/* 2026 Sustainability Forum — page content styles.
   Forked from page-content.css (the 2025 page) on 2026-08-06.
   Only the loader root id differs; the design language is unchanged. */

/* 引入Google Fonts - Montserrat */
@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@300;400;500;600;700&display=swap');

/* 全局字体设置 */
* {
    font-family: 'Montserrat', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif !important;
}

/* 让页面内容突破主题容器，占满整个视口宽度
   Full-bleed the page content.

   🚨 2026-08-04. This used to hang off `.elementor-widget-html` /
   `.elementor-html-widget` — the wrappers Elementor put around the HTML widget
   this page used to live in. The page was migrated to Variant C on 2026-07-27
   (MIGRATION.md, page 14883), so those wrappers no longer exist in the DOM and
   the rule stopped matching ANYTHING. Nothing errors; `.forum-content` simply
   fell back to filling the theme's boxed container, and the whole forum
   rendered in a narrow centred column with white gutters either side.

   The full-bleed therefore moves to `#forum-2026-root`, the div the loader
   injects the fragment into. Not `.forum-content`: the green nav and the mobile
   white header are SIBLINGS of it in the fragment, so bleeding only
   `.forum-content` leaves the nav bar boxed at 1200px with white either side —
   which is what shipped for half an hour on 2026-08-04 before this was caught.
   The Elementor selectors are kept so the page still renders correctly if it is
   ever previewed inside the builder; they are inert on the live page. This is
   the exact trap WEB_WORKFLOW.md warns about under "CSS pitfalls when a page
   stops being an Elementor full-width canvas". */
#forum-2026-root,
.forum-content,
.elementor-html-widget,
.elementor-widget-html .elementor-widget-container,
.elementor-widget-html {
    width: 100vw !important;
    max-width: 100vw !important;
    padding: 0 !important;
    /* margin-based, NOT `position:relative; left:50%`. Two reasons: the green
       nav inside is `position: sticky`, where `left` is an inset threshold and
       would stick it horizontally; and this form is idempotent — applied to a
       child whose parent is already 100vw, `50% - 50vw` evaluates to 0, so
       nesting #forum-2026-root and .forum-content costs nothing. */
    margin-left: calc(50% - 50vw) !important;
    margin-right: calc(50% - 50vw) !important;
    margin-top: 0 !important;
    margin-bottom: 0 !important;
}

.container {
    max-width: 1600px;
    margin: 0 auto;
    padding: 0 20px;
}

/* Key Visual Section */
/* ---------------------------------------------------------------------------
   HERO HEIGHT — stays at 95vh.

   🚨 THE COMP'S HERO IS 808px TALL AT 1920 WIDE — 2.38:1, not the 4:1 band an
   earlier pass here claimed. That 4:1 came from scanning column x=10 downward
   for the first dark pixel and taking y=509 as the stats band; x=10 at that
   height is dark HARBOUR WATER, not the band, which actually starts at y=863.
   Find a boundary by the row being uniform across the full width, never by one
   column going dark.

   On the strength of the wrong number this was shipped as `height: 25vw`
   (480px at 1920, a strip) and Chase reverted it the same day. 95vh on a
   1080-tall window is 1026px against the comp's 808 — the same order, which is
   why the comp needs no change here at all.

   The costs of 95vh, for the record: the copy block is 311px tall at 1920, so
   it fills under a third of the frame, and `object-fit: cover` scales the
   1920x796 master UP by 29% and throws away 555px of its width. Accepted.
   --------------------------------------------------------------------------- */
.key-visual-section {
    height: 95vh;
    min-height: 500px;
    position: relative;
    overflow: hidden;

    /* WeChat's in-app browser refuses to autoplay the film and paints nothing,
       leaving a white box — and the lockup over it is white type, so the whole
       key visual vanished (Ivan, 2026-09-18). A still frame of the same film
       sits underneath: invisible wherever the video does play, and the design
       wherever it does not. */
    background: #0b1b33 url('https://hkujcesgri.hku.hk/wp-content/uploads/forum-2026-kv-poster.webp') center center / cover no-repeat;
}

.key-visual-video {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    z-index: 1;
}

/* ---------------------------------------------------------------------------
   NO SCRIM OVER THE KEY VISUAL — the dark layer is in the film.
                                                            (2026-08-10)

   A `.key-visual-section` ::after gradient used to sit here, copied from the
   front page's hero and then lightened twice at Bunny's request. It is gone:
   she re-cut the film with the darkening baked in — "然後不加overlay，因為我加
   在video裡面了" — and two layers of dark would double up.

   The film does the job far better than the CSS ever did. Mean luminance of
   the top 45% of the frame at t=6s, where the copy sits:

       old film, no gradient         .423   white text at 2.22:1
       old film + .28/.12/.42        —      white text at 2.29:1
       old film + .18/.02/.32        —      white text at 1.83:1  ⚠
       NEW film, no gradient         .139   white text at 5.56:1  ✓

   So the legibility problem flagged three times running — the hero title under
   WCAG's 3:1 for large text, worst on mobile — is fixed by the film, not by a
   text-shadow. Nothing more is needed.

   ⚠️ IF THE FILM IS EVER SWAPPED BACK to an ungraded master, the gradient has
   to come back with it or the title lands at 2.2:1 again. Check the frame, not
   the filename.

   `.key-visual-content` keeps z-index 3: the video is 1, and 3 is simply above
   it now that nothing sits at 2.
   --------------------------------------------------------------------------- */

/* ---------------------------------------------------------------------------
   VERTICAL PLACEMENT — high, not centred.                         (2026-08-10)

   Chase: "垂直上应该是要偏上一些". Measured off the comp with the hero taken
   between the nav's bottom edge and the stats band's top edge, both found as
   full-width runs of #0E142C rather than by eye:

       hero          y  55 .. 863     808 tall
       copy block    y 151 .. 462     311 tall
       above  96      below  401      1 : 4.18

   The free space is split roughly one-fifth above, four-fifths below — the
   block sits in the upper third with the harbour open beneath it. It was
   centred here first, which put it 354px down at 1920; that was wrong.

   Two flex spacers rather than a padding or a translate, because it has to
   hold at any hero height and neither of those scales: `padding: %` resolves
   against the WIDTH, and a translate would need the free space, which CSS
   cannot name. `flex-grow: 96` and `401` divide whatever is left over in
   exactly the comp's ratio.

   It also fails safe. Both spacers have `flex-basis: 0`, so on a hero too
   short to hold the block they collapse and `justify-content: flex-start`
   leaves the copy starting at the top edge and overflowing the bottom — the
   logo stays whole.

   🚨 THESE TWO RULES ARE LOAD-BEARING AND EASY TO DELETE BY ACCIDENT. They sat
   immediately above `.key-visual-content` next to the old scrim block, and
   removing the scrim on 2026-08-10 took them with it — the whole hero snapped
   to the top edge (head 0 against the intended 137 at 1920) and shipped that
   way for one deploy. If you cut anything out of this region, re-measure the
   head/foot ratio afterwards; a missing spacer looks like a design choice.
   --------------------------------------------------------------------------- */
.key-visual-content::before,
.key-visual-content::after {
    content: "" !important;
    display: block !important;
    flex-basis: 0 !important;
    flex-shrink: 1 !important;
}
.key-visual-content::before { flex-grow: 96 !important; }
.key-visual-content::after  { flex-grow: 401 !important; }

.key-visual-content {
    /* one number drives the whole block; everything else is a multiple of it */
    --kv-title: min(3.83vw, 9.5vh);

    position: absolute !important;
    top: 0 !important;       /* 2025 had -50px here, which un-did the centring */
    left: 0 !important;
    width: 100% !important;
    height: 100% !important;
    z-index: 3 !important;   /* above the scrim — see the block above */
    display: flex !important;
    flex-direction: column !important;
    justify-content: flex-start !important;   /* the spacers above do the work */
    align-items: center !important;      /* was flex-start */
    text-align: center !important;
    padding: 0 5% !important;
    box-sizing: border-box !important;
    color: white !important;
}

/* Logo */
/* The gaps below are tuned against RENDERED INK, not against the boxes: a line
   box carries leading above the capitals, so a margin set to the comp's gap
   paints a visibly larger one. Expressed as a fraction of the title's own
   width, which is the ratio that survives the comp's unknown scale:

     comp gap / comp title width      ours / our title width (1920)
       logo → title  58/1153 = .050     58/1137 = .051

   The logo multiplier looks small next to the other two because this PNG has
   14.3% of its height as empty canvas BELOW the ink (rows 442–517 of 517).
   That padding is part of the gap already; the margin only supplies the rest.
   2025's file was trimmed flush, so its margin was 0.60 for the same result.
       title → date  46/1153 = .040     45/1137 = .040
       date → venue  28/1153 = .024     27/1137 = .024

   ⚠️ MEASURE THE LOGO GAP FROM ITS BOX, NOT FROM ITS INK. The anniversary mark
   is drawn in hairlines that fall under any sane white-pixel threshold when a
   pale frame of the video is behind them, so an ink scan puts the logo's
   bottom edge ~45px too high and invites exactly the wrong correction — which
   is what happened on the first pass here, cutting this margin to 0.253 and
   closing the gap to 16px.

   0.514 since 2026-08-20, when the ESGRI mark alone became the four-logo strip:
   0.419 left a 43px gap where Bunny's APEC_website_mockv3 has 50 (strip ink
   bottom 208, title cap top 258, at a 1920 mock). 0.514 measures 51. Both files
   are trimmed flush, so box bottom IS ink bottom and the two are comparable. */
.kv-logo {
    margin-bottom: calc(var(--kv-title) * 0.514) !important;
    position: relative !important;   /* anchors .kv-logo__home */
}
/* Covers the ESGRI lockup at the left of the shared strip and nothing else —
   see the comment on the anchor in forum-2026-content.html for why it is a
   zone and where 34% comes from. The strip is centred, so percentages of the
   box track the artwork at every width. */
.kv-logo__home {
    position: absolute !important;
    left: 0; top: 0;
    width: 34%; height: 100%;
    display: block !important;
    cursor: pointer;
}

/* 2026-forum-kv-logos.webp — Bunny's supplied APEC_website_top logo.png, trimmed
   to its ink (the source carried 310px of transparent margin each side and ~180
   top and bottom). Trimming is not cosmetic: the height rule below and the
   margin rule above both assume box == ink, and the source's padding would have
   eaten a fifth of the height and thrown the gap out.

   No horizontal nudge needed — after the trim the ink is flush to both edges, so
   the box centre IS the ink centre; measured live at 504–1416 in a 1920 window,
   centre 960.0. 2025's Ann-ver-logo.webp was NOT trimmed symmetrically: ink
   flush to x=0 with 148px of empty pixels on the right put the drawing 22px left
   of centre against type centred to 0.0px. If the file is ever swapped again,
   check the ink bbox before assuming it is centred.

   v6 (2026-09-04) swaps in Bunny's APEC_website_v4_CGTN artwork — CGTN is now
   labelled "Exclusive Media Partner" and sits over two lines, so the strip's
   ink aspect drops from 12.02:1 to 10.04:1. The height multiplier is raised
   from 1.201 to 1.236 to hold the rendered WIDTH at the previous 912px, which
   is what keeps the ESGRI lockup at the scale the mock sets; matching height
   instead would have shrunk everything by a fifth.

   1.201, down from the 1.270 the ESGRI-only lockup used. Derived from the mock,
   not chosen: the strip's ink is 88.3px tall there against --kv-title's 73.5px
   at 1920. Renders 912x88 live where the mock has 909.7x88.3. */
.kv-logo img {
    /* 🚨 2.126, AND IT TRACKS THE ARTWORK'S ASPECT, NOT A TASTE. The strip is
       sized by height so it scales with the hero; v6 was 2560x255 (10.04:1) and
       rendered 760px wide at a 1600 viewport. v7 is 2560x352 (7.27:1), so the
       same height would have made it NARROWER — 552px — and the taglines
       smaller, which is the opposite of what was asked. 2.126 puts it at 950px
       wide there, a deliberate step up from 760: the Jockey Club asked to
       "enlarge and align the size of the taglines for readability"
       (Amy Wong, via Sophie, 2026-09-10). Change this one number to resize it. */
    height: calc(var(--kv-title) * 2.126) !important;
    width: auto !important;
    object-fit: contain !important;
    display: block !important;
}

/* Title Section */
.kv-title-section {
    text-align: center !important;
}

/* Title — ONE line. `nowrap` is what guarantees it stays one line: the size is
   derived to fit 60% of the viewport, but a stray narrow window would
   otherwise break it after "SUSTAINABILITY" and quietly reinstate the 2025
   two-line shape. Below 768px it is allowed to wrap again — see that query. */
.kv-title-main {
    line-height: 1.05 !important;
    /* 0.20, down from 0.331, because the subtitle now sits between the title and
       the date. Measured: title cap-bottom to subtitle cap-top is 33px at 1920,
       which is what Bunny's APEC_website_mockv3 has (315 -> 348). */
    margin-bottom: calc(var(--kv-title) * 0.20) !important;
}

/* GLOBAL LEADERSHIP DIALOGUE — the forum's subtitle. It is in the 0818 rundown's
   header and in Bunny's APEC_website_mockv3; the page had never carried it.

   Same face as the title (Montserrat 800, loaded just below) with the comp's
   tracking. Both numbers are derived from the comp, not chosen:

     size    subtitle cap / title cap = 35/58 in the mock -> 0.609 of --kv-title,
             after correcting for the mock being a JPEG whose soft edges read
             ~9% taller and ~1.5% wider than a crisp render of the same type.
             Renders 815px wide against the comp's 824.
     track   solved, not eyeballed. At 0.609 * 73.536 = 44.8px the string sets
             775px flat; the comp wants 815. CSS adds the spacing after every
             character INCLUDING the last, so that is 26 increments over 26
             glyphs, i.e. 40/44.8/26 = 0.035em.
     gap     margin 0.409 puts subtitle cap-bottom to date cap-top at 47px,
             the comp's 382 -> 429, on the nose.

   ⚠️ If the string ever changes, the tracking has to be re-solved — it is
   width-matched to these 26 characters, not a style choice. */
.kv-subtitle {
    font-family: Montserrat, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important;
    /* 0.609 * 1.1 — the comp-derived share, with Bunny's 10% (see the block by
       .kv-title-line). ⚠️ The tracking below was width-solved against the comp
       at weight 800 and that match no longer holds: 500 sets narrower glyphs and
       the line is 10% bigger, so the string is no longer 815px at 1920. The
       spacing is kept as the look Bunny signed off; it is not a measurement any
       more, and re-solving it would need a new comp. */
    font-size: calc(var(--kv-title) * 0.67) !important;
    font-weight: 500 !important;   /* was 800; measured off the EDM header */
    color: #fff !important;
    text-transform: uppercase !important;
    letter-spacing: 0.035em !important;
    line-height: 1 !important;
    white-space: nowrap !important;
    margin: 0 0 calc(var(--kv-title) * 0.409) !important;
}

/* 🚨 THE SITE ONLY SHIPS MONTSERRAT 300-700. Checked against document.fonts:
   no 800 face and no 900 face, so the `font-weight: 900` that stood here was
   rendering as plain Bold 700 — "2026 SUSTAINABILITY FORUM" measures 1567px at
   100px in 700, 800 and 900 alike, which is the giveaway. Asking for Extra
   Bold by changing the number alone would have changed nothing at all.

   So the face is loaded, once, here. Latin subset only: the title is
   "2026 SUSTAINABILITY FORUM" and nothing else on the page uses weight 800, so
   the other subsets Google serves would download for nothing. `font-display:
   swap` keeps the title visible in Bold while it arrives.

   Bunny, 2026-08-10: "2026 SUSTAINABILITY FORUM這個字款要 Extra Bold". */
@font-face {
  font-family: 'Montserrat';
  font-style: normal;
  font-weight: 800;
  font-display: swap;
  src: url(https://fonts.gstatic.com/s/montserrat/v31/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCvr73w5aXo.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ── +10% AND TWO STEPS LIGHTER — Bunny, 2026-08-27 ──────────────────────────
   "可以把 2026 SUSTAINABILITY FORUM 跟 GLOBAL LEADERSHIP DIALOGUE 調大10%左右嗎？
   然後他們的字要幼一格，現在太粗了 … 粗幼效果要跟這個 [APEC_invitation EDM
   header_v3.jpg]".

   🚨 THE 10% GOES ON THE TWO TYPE SIZES, NOT ON --kv-title. That token drives
   the ENTIRE hero — date, venue, the register button and every gap between them
   are multiples of it — so raising it 10% would have grown the whole block and
   moved the head/foot ratio that the spacers above are measured against. Only
   these two lines were asked for.

   THE WEIGHT IS MEASURED OFF THE EDM, not guessed at. Stroke width over cap
   height, on the reference and on a Montserrat ladder rendered at the SAME cap
   height and re-encoded at the same JPEG quality (the reference is a JPEG, and
   soft edges read fatter — the note above already had to correct for that on
   size):

       weight   300    400    500    600    700    800
       ratio   .079   .111   .138   .185   .231   .277
       EDM title .200 -> 600 is nearest (.185); 700 is .231
       EDM subtitle .159 -> 500 is nearest (.140); 600 is .186
       live before .272 -> 800, which is what it was set to. Method checks out.

   So the reference is SemiBold over Medium, not one weight for both. "幼一格"
   read literally would be 700/700; the picture Bunny pointed at is 600/500, and
   the picture is the spec. One number each if that turns out to be a step too
   far.

   ⚠️ The 800 @font-face above is now unreferenced. It is left in place — a
   @font-face nothing asks for is never downloaded, so it costs nothing, and it
   is what a revert would need. */
.kv-title-line {
    font-size: calc(var(--kv-title) * 1.1) !important;
    /* 700, not the 600 the EDM measures at: Bunny looked at it live and asked for
       it back a step — "還是粗一格吧" (2026-08-27, same day). The subtitle stays at
       500, which is what she asked to keep. */
    font-weight: 700 !important;
    color: white !important;
    text-transform: uppercase !important;
    letter-spacing: 0 !important;
    white-space: nowrap !important;
}

/* Date — plain white type. The gold chip was 2025's; the comp has no chip. */
.kv-date {
    font-size: calc(var(--kv-title) * 0.507) !important;
    font-weight: 700 !important;
    color: white !important;
    text-transform: uppercase !important;
    letter-spacing: .02em !important;
    line-height: 1.2 !important;
    margin-bottom: calc(var(--kv-title) * 0.201) !important;
}

/* Venue.
   NOT sized from the comp's width ratio: the comp's venue reads "MUSEUM PLUS,
   WEST KOWLOON" and ours is "M+, West Kowloon Cultural District", 36% longer,
   so matching widths would have set it in the same size as the date and broken
   the step down the block. Sized instead to land clearly narrower than the
   date line above it — 532px against 596 at 1920, the same descending order
   the comp has. */
.kv-location {
    color: white !important;
    font-size: calc(var(--kv-title) * 0.32) !important;
    font-weight: 500 !important;
    text-transform: uppercase !important;
    letter-spacing: .02em !important;
    line-height: 1.35 !important;
    display: block !important;
    margin-top: 0 !important;
}

/* REGISTER NOW, Bunny's 2026-08-12 comp. Sized off --kv-title like everything
   else in this block, so the button scales with the hero instead of becoming a
   postage stamp at 2560 and swallowing the venue line at 1280.
   Measured off the comp at its own 1990px width: the plate is 418x40 with the
   label at 15px — 0.55 and 0.21 of the 74px title, and 10.4x the label's height
   wide.

   🚨 EVERY NUMBER BELOW CARRIES A x1.40. The comp's ratios were 0.21 / 0.135 /
   1.05; they are 0.294 / 0.189 / 1.47 here. Both axes have to be scaled or the
   plate only grows in one: width is 2*padding-x + label, height is 2*padding-y +
   line-height, and the label itself scales with font-size — multiplying all
   three by the same number is what makes the plate bigger rather than wider. If
   it is ever re-measured against a comp, divide these by 1.40 first.

   It went x1.10 on 2026-08-20 (Chase: "整個 button 可以再大10%") and x1.40 on
   2026-08-21 (Sophie, via Chase: "那個黃色 register now 可以再大點哦"). At 1440
   that is 239x29 -> 299x37 with the label at 12.7px -> 16.2px. The 12.7px was
   the real complaint: it is BELOW this page's body copy, on the only primary
   action in the key visual.

   🚨 THE TWO STATES SWAPPED ON 2026-08-20 (Chase: "金底黑字變成default，然後
   mouse over再是黑底白字"). Gold #C9A227 with a #14171F label is the RESTING
   state; #14171F with white is the hover. Read the pair together before changing
   either — an inversion only reads as one gesture if both halves move.

   #14171F is the site's --evh-ink, which is what Bunny's comp samples to, and
   #C9A227 is the gold the sticky Register Now card already uses
   (.popup-card__cta), so the page's two Register affordances answer to the same
   colour. Both states carry their own contrast: black on gold is 7.41:1, white
   on ink is 15.6:1. ⚠️ White on the gold is 2.42:1 — it was that way for an hour
   earlier the same day. Do not put white back on the gold in either state.

   ⚠️ The old note here said "no hover lift and no pointer: it is disabled until
   registration opens". Registration DID open — the span became a Qualtrics link
   on 2026-08-20 — and `cursor: default` was left behind, so a live link was
   telling the cursor it was inert. Hence pointer below. */
.kv-cta {
    display: block !important;
    margin-top: calc(var(--kv-title) * 0.30) !important;
}

.kv-btn {
    display: inline-block !important;
    background: #C9A227 !important;
    color: #14171F !important;
    font-family: "Poppins", "Noto Sans", sans-serif !important;
    font-size: calc(var(--kv-title) * 0.294) !important;
    font-weight: 700 !important;
    letter-spacing: .06em !important;
    text-transform: uppercase !important;
    line-height: 1 !important;
    padding: calc(var(--kv-title) * 0.189) calc(var(--kv-title) * 1.47) !important;
    border-radius: 0 !important;
    cursor: pointer !important;
    user-select: none !important;
    transition: background-color .2s ease, color .2s ease !important;
}

/* :focus-visible rides along so the keyboard gets the same signal the mouse
   does. Both are needed — :hover alone leaves a tab-user with no feedback at
   all, and this is the page's only primary action. */
.kv-btn:hover,
.kv-btn:focus-visible {
    background: #14171F !important;
    color: #fff !important;
}

.kv-location .location-icon {
    width: calc(var(--kv-title) * 0.36) !important;
    height: calc(var(--kv-title) * 0.36) !important;
    margin-right: .35em !important;
    vertical-align: -0.12em !important;
    display: inline-block !important;
}


/* Stats Highlight Section */
/* 80px, the same figure .partners-section pays, because Chase asked for this
   band to breathe like that one (2026-08-20: "上下藍色的gap可以多一點嗎，仿照
   那些logo那段的距离"). It was 8px, which put the Anniversary line 34px under
   the band's top edge and "Media Reach" 24px above its bottom — measured as
   ink, not boxes. At 80 those become 106 and 96, against the logo section's
   96 and 123.

   Symmetric on purpose even though the reference section reads 96/123: its
   extra 27px at the foot is not padding, it is the empty half of the 150px
   .partner-logo box under a 66px logo. Chasing that with asymmetric padding
   here would break the moment the stats content changes.

   No mobile override — this is the only rule for the band, and 80px on a phone
   is the same air the partners section already takes there. */
.stats-highlight-section {
    background: #0E142C;
    padding: 80px 0;
    color: white;
}

.anniversary-text {
    text-align: center;
    color: white;
    font-size: 2rem;
    font-weight: 700;
    margin: 1rem;
}

.stats-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 3rem;
    text-align: center;
}

.stat-item {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.75rem;
    padding: 0.5rem;
    text-align: center;
}

.stat-icon {
    color: rgba(255, 255, 255, 0.9);
}

.stat-icon svg {
    width: 120px;
    height: 120px;
}

.stat-icon img {
    width: 120px;
    height: 120px;
}

.stat-content {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.5rem;
    text-align: center;
    justify-content: center;
}

.stat-number {
    font-size: 2.5rem;
    font-weight: 700;
    color: white;
    line-height: 1;
}

.stat-label {
    font-size: 1rem;
    font-weight: 500;
    color: rgba(255, 255, 255, 0.9);
    letter-spacing: 0.5px;
}


.highlights-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
    gap: 2rem;
    margin-bottom: 3rem;
}

.highlight-card {
    text-align: center;
    padding: 2rem;
    border-radius: 10px;
    box-shadow: 0 4px 15px rgba(0,0,0,0.1);
    transition: transform 0.3s ease;
}

.highlight-card:hover {
    transform: translateY(-5px);
}

.highlight-icon {
    width: 80px;
    height: 80px;
    margin: 0 auto 1.5rem;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #f8f9fa;
    border-radius: 50%;
}

.highlight-icon img {
    width: 40px;
    height: 40px;
}

.register-section {
    text-align: center;
}

.btn-register {
    background: #FFA726;
    color: white;
    font-size: 1.2rem;
    padding: 15px 40px;
}

/* Background Info Section */
.background-info-section {
    padding: 60px 0;
    background: #f8f9fa;
    text-align: center;
}

/* Featured Programs Section */
.programs-section {
    padding: 100px 0;
    background: #0E142C;
    color: white;
}

.programs-layout {
    display: flex;
    align-items: center;
    gap: 4rem;
}

.programs-title {
    flex: 0 0 auto;
    min-width: 250px;
}

.programs-title h2 {
    font-size: 3rem;
    font-weight: 700;
    color: white;
    margin: 0;
    line-height: 1.1;
    text-transform: capitalize;
}

.programs-carousel {
    flex: 1;
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    min-height: 0;
    /* 🚨 min-width: 0 IS THE FIX FOR THE RIGHT-HAND CARD BEING EATEN (Chase,
       2026-09-04, at ~1600px). A flex item's default min-width is auto, i.e.
       its content's minimum, and the content here is a 1080px scroll box —
       so below ~1450px this item refused to shrink, the layout overflowed the
       .container to the right, and the viewport edge cut the second card
       (measured: carousel right = 1414 in a 1000, 1200 AND 1400 window). */
    min-width: 0;
}

/* 1100, not 1080: two 540 cards plus the 20px gap between them. At 1080 the
   second card lost its last 20px even on a wide screen (card2 right 1517 vs
   box right 1497 at 1600). The trailing margin of card 2 is allowed to hang
   outside; it is empty. */
.programs-scroll-container {
    width: 100%;
    max-width: 1100px;
    overflow: hidden;
    position: relative;
    margin: 0 auto;
    height: auto;
    transition: height 0.3s ease;
}

/* Below 1460px the title and the 1100px strip no longer fit side by side
   (250 + 4rem + 1100 + 40 padding = 1454), so the title moves above the
   carousel and the strip gets the full container width. Below 1140 even that
   is too narrow for two 540 cards, and the cards cannot be made fluid — the
   carousel JS (navigation.js, shared with 2025) steps a fixed 560px per index —
   so the strip is ZOOMED instead: zoom scales the layout, the JS's translateX
   and the heights it measures all together, which a transform would not.
   Stepped rather than calc()'d because length÷length in calc() is still not
   safe to rely on. The 768px query below takes over from there (one card per
   view, 100% wide). */
@media (max-width: 1460px) {
    .programs-layout {
        flex-direction: column;
        align-items: stretch;
        gap: 2rem;
    }
    .programs-title {
        min-width: auto;
    }
}
@media (max-width: 1140px) { .programs-scroll-container { zoom: 0.9; } }
@media (max-width: 1030px) { .programs-scroll-container { zoom: 0.8; } }
@media (max-width: 920px)  { .programs-scroll-container { zoom: 0.7; } }
@media (max-width: 810px)  { .programs-scroll-container { zoom: 0.62; } }
@media (max-width: 768px)  { .programs-scroll-container { zoom: 1; } }

.programs-scroll-content {
    display: flex;
    gap: 0;
    transition: transform 0.3s ease;
    padding: 1rem 0;
    align-items: flex-start;
}

.program-card {
    flex: 0 0 540px;
    background: transparent;
    border-radius: 0;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
    overflow: hidden;
    margin-right: 20px;
}

/* Program Carousel Navigation Buttons */
.program-carousel-btn {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    z-index: 10;
    width: 50px;
    height: 50px;
    background: rgba(255, 255, 255, 0.3);
    border: none;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: all 0.3s ease;
    font-size: 1.8rem;
    color: rgba(255, 255, 255, 0.9);
    font-weight: 400;
    outline: none;
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
    padding: 0;
    margin: 0;
    box-sizing: border-box;
    overflow: hidden;
}

#programsCarouselPrev {
    position: absolute;
    top: 50%;
    left: -25px;
    transform: translateY(-50%);
}

.program-carousel-btn-next {
    right: -25px;
}

.program-carousel-btn:hover:not(:disabled) {
    background: rgba(255, 255, 255, 0.5);
    color: white;
    transform: translateY(-50%) scale(1.05);
}

.program-carousel-btn:active:not(:disabled) {
    background: rgba(255, 255, 255, 0.3);
}

.program-carousel-btn:disabled {
    display: none;
}

.program-carousel-btn span {
    user-select: none;
    line-height: 1;
    pointer-events: none;
    margin: 0;
    padding: 0;
}

.program-image {
    width: 100%;
    aspect-ratio: 1.55;
    background: #f8f9fa;
    display: flex;
    align-items: center;
    justify-content: center;
}

.program-image img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.program-content {
    padding: 1.5rem;
}

.program-content h3 {
    color: white;
    margin-bottom: 1rem;
    font-size: 1.3rem;
}

.program-content p {
    color: rgba(255, 255, 255, 0.9);
    line-height: 1.6;
    margin-bottom: 1.5rem;
}

/* The speaker line, between the title and the blurb. Marketing's
   "Blurbs for webpage.docx" names one for five of the eight cards; the other
   three carry none and the element is simply absent, not empty.

   ⚠️ Scoped as `.program-content p.program-speaker` — (0,2,1) — because the
   rule above is `.program-content p` at (0,1,1) and would otherwise win the
   margin outright. */
.program-content p.program-speaker {
    color: rgba(255, 255, 255, 0.72);
    font-size: 0.95rem;
    font-style: italic;
    line-height: 1.4;
    margin-top: -0.5rem;
    margin-bottom: 0.9rem;
}

.btn-program {
    background: #367F54;
    color: white;
    padding: 8px 20px;
    font-size: 0.9rem;
}

/* Agenda Section */
.agenda-section {
    padding: 80px 0;
    background: #0E142C;
}

.agenda-item.agenda-title-row {
    border-bottom: none;
}

.agenda-item.agenda-title-row .title {
    font-size: 3rem;
    font-weight: 700;
    margin-bottom: 0;
}

.agenda-content {
    max-width: 1200px;
    margin: 0 auto;
}

.agenda-table {
    display: flex;
    flex-direction: column;
}

.agenda-separator-only {
    padding: 0;
    height: 1px;
}

.agenda-item {
    background: transparent;
    border-bottom: 1px solid white;
    padding: 1rem 0;
}

.agenda-item:last-child {
    border-bottom: none;
}

.agenda-header {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    padding: 0;
}

.agenda-item .time {
    font-weight: 700;
    color: white;
    font-size: 2rem;
    margin-bottom: 0.5rem;
}

.agenda-item .title {
    color: white;
    font-weight: 400;
    font-size: 2rem;
    line-height: 1.4;
    margin-bottom: 0.5rem;
}


.agenda-details {
    padding: 0;
    margin-top: 0.5rem;
}

.agenda-details .subtitle {
    color: #ffffff;
    font-size: 0.9rem;
    font-style: italic;
    margin: 0.5rem 0;
}

.agenda-details h4 {
    color: white;
    font-size: 0.9rem;
    margin-bottom: 0.25rem;
    font-weight: 600;
}

.agenda-details h5 {
    color: white;
    font-size: 0.9rem;
    margin: 1rem 0 0.5rem 0;
    font-weight: 600;
}

/* The 4:55 showcase strands. Three of them in the 0818 rundown, and only the
   third (Bio-resources) has a named speaker — the EPD and Kadoorie seats are
   still "XX is [Title]" in Marketing's Speakers sheet — so the strands are
   listed as text above Jeanne Ng's card rather than as three cards with two
   TBC faces.

   🚨 `list-style: disc` is restated. Phlox sets `ul { list-style: none }` site
   wide, so without it the padding-left reserves room for bullets that never
   draw and the lines read as a stray indent. Same trap as the research-blog
   Key Takeaways list. */
.agenda-showcase {
    list-style: disc !important;
    color: white;
    font-size: 0.9rem;
    line-height: 1.5;
    margin: 0 0 1.25rem 0;
    padding-left: 1.15rem;
}

.agenda-showcase li {
    list-style: disc !important;
    margin-bottom: 0.35rem;
}

.agenda-showcase li:last-child {
    margin-bottom: 0;
}

/* 5:05 p.m. — the Ruby Yang film row's one line of lead-in copy. Same white,
   same size and the same 1.25rem gap to the cards as .agenda-showcase, because
   it does the same job in the same slot; it is a <p> rather than a <ul> only
   because there is nothing to bullet. Added 2026-09-04 with the 0903 rundown. */
.agenda-showcase-note {
    color: white;
    font-size: 0.9rem;
    line-height: 1.5;
    margin: 0 0 1.25rem 0;
}

/* 5:00 Showcase, 2026-09-29 (Bunny): the strand line and the talk title at the
   same size as .roundtable-role-label ("Panellists:") — 1.2rem, 1.1rem on the
   breakpoint where that label shrinks (the rule sits in that media block). */
.agenda-showcase-note--lg { font-size: 1.2rem; line-height: 1.45; }
.agenda-showcase-note--first { margin-bottom: 0.8rem; }

.speaker-list {
    list-style: none;
    padding: 0;
    margin: 0;
}

.speaker-list li {
    padding: 0.5rem 0;
    border-bottom: 1px solid #f5f5f5;
    color: #555;
    line-height: 1.4;
}

.speaker-list li:last-child {
    border-bottom: none;
}

.speaker-list li:before {
    content: '•';
    color: #367F54;
    margin-right: 0.75rem;
    font-weight: bold;
}

/* Agenda Speakers Grid */
.agenda-speakers-grid {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
    margin-top: 1rem;
}

.agenda-speaker-card {
    width: 180px;
    flex-shrink: 0;
}

.agenda-speakers-grid.single-speaker {
    max-width: none;
}

/* Closing Remarks - single speaker card styling */
.agenda-details > .agenda-speaker-card {
    max-width: 180px;
}

/* Single Row Layout (Zhang Xiang, Cai Hongbin, Gabriel Leung in one row) */
.agenda-speakers-grid.agenda-speakers-single-row {
    display: flex;
    justify-content: flex-start;
    gap: 1rem;
    max-width: none;
    margin-top: 1rem;
    margin-bottom: 1rem;
}

/* 2x2 Layout (He Guojun & Roni in first row, Jeffrey & Uta in second row) */
.agenda-speakers-grid.agenda-speakers-2x2 {
    display: flex;
    flex-direction: column;
    gap: 1rem;
    max-width: none;
}

.agenda-speakers-grid.agenda-speakers-2x2 .agenda-speaker-row {
    display: flex;
    justify-content: flex-start;
    gap: 1rem;
}

/* Four Even Layout (Research Presentations) - REMOVED SPACE-BETWEEN, NOW USES NORMAL FLEX-START LAYOUT */
.agenda-item .agenda-details .agenda-speakers-grid.agenda-speakers-four-even {
    display: flex !important;
    justify-content: flex-start !important;
    align-items: flex-start !important;
    gap: 1rem !important;
    max-width: none !important;
    width: 100% !important;
    flex-wrap: wrap !important;
    margin-top: 1rem !important;
}

/* Backup selector: target agenda-speakers-grid that has exactly 3 speaker cards (Research Presentations) */
.agenda-speakers-grid:has(.agenda-speaker-card:nth-child(3):last-child) {
    display: flex !important;
    justify-content: flex-start !important;
    align-items: flex-start !important;
    gap: 1rem !important;
    max-width: none !important;
    width: 100% !important;
    flex-wrap: wrap !important;
    margin-top: 1rem !important;
}

.agenda-speaker-card {
    width: 180px;
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    background: transparent;
    border: none;
    border-radius: 0;
    overflow: hidden;
    transition: transform 0.3s ease;
}

/* Override width for special layouts to maintain consistent size */
.agenda-speakers-grid.agenda-speakers-single-row .agenda-speaker-card {
    width: 180px !important;
    max-width: 180px !important;
    flex: 0 0 180px !important;
}

.agenda-speakers-grid.agenda-speakers-2x2 .agenda-speaker-card {
    width: 180px !important;
    max-width: 180px !important;
    flex: 0 0 180px !important;
}

.agenda-item .agenda-details .agenda-speakers-grid.agenda-speakers-four-even .agenda-speaker-card,
.agenda-speakers-grid:has(.agenda-speaker-card:nth-child(3):last-child) .agenda-speaker-card {
    width: 180px !important;
    max-width: 180px !important;
    flex: 0 0 180px !important;
}

.agenda-speaker-card:hover {
    transform: translateY(-3px);
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
}

.agenda-speaker-photo {
    width: 100%;
    aspect-ratio: 1;
    margin: 0;
    border-radius: 0;
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}

.agenda-speaker-photo img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.agenda-speaker-info {
    padding: 0.75rem 0.5rem;
    text-align: center;
    flex-grow: 1;
    display: flex;
    flex-direction: column;
    justify-content: flex-start;
}

.agenda-speaker-info h4 {
    color: white;
    font-size: 0.85rem;
    font-weight: 600;
    margin-bottom: 0.25rem;
    line-height: 1.2;
}

.agenda-speaker-info p {
    color: rgba(255, 255, 255, 0.8);
    font-size: 0.7rem;
    line-height: 1.1;
    margin-bottom: 0.1rem;
}

.agenda-cta {
    margin-top: 3rem;
}

/* Keynote Layout — both keynote-style rows (10:25 Keynote, 3:15 Leadership
   Spotlight). Bunny, 2026-08-21: the topic block hugged the top-right corner
   of the row; she wants it vertically centred on the portrait and starting
   further left. align-items centres the shorter text column against the
   taller speaker card; the flex split 0.25/0.75 -> 0.2/0.8 moves the text's
   left edge in by ~60px at 1200px. The phone breakpoint stacks the columns
   and resets align-items to flex-start, so this is desktop-only. */
.keynote-layout {
    display: flex;
    align-items: center;
    gap: 2rem;
    margin-top: 1rem;
}

.keynote-speaker {
    flex: 0.2;
}

.keynote-content {
    flex: 0.8;
}

.keynote-content h3 {
    color: white;
    font-size: 2rem;
    font-weight: 600;
    margin-bottom: 1rem;
    line-height: 1.3;
}

.keynote-content p {
    color: rgba(255, 255, 255, 0.9);
    font-size: 1rem;
    line-height: 1.6;
    margin: 0;
}

/* Horizontal Layout for Simple Items */
.agenda-item.horizontal .agenda-header {
    flex-direction: row;
    align-items: center;
    gap: 2rem;
}

.agenda-item.horizontal .time {
    margin-bottom: 0;
    min-width: 140px;
    flex-shrink: 0;
}

.agenda-item.horizontal .title {
    margin-bottom: 0;
}

/* Agenda Note */
.agenda-item.agenda-note {
    border-bottom: none !important;
    padding: 1.5rem 0 0.5rem 0 !important;
    text-align: center;
}

.agenda-note-text {
    font-size: 0.9rem !important;
    color: #cccccc !important;
    line-height: 1.4 !important;
    font-style: italic;
    max-width: 800px;
    margin: 0 auto;
}

/* Roundtable Single Row Layout */
.roundtable-single-row {
    flex-wrap: nowrap;
    overflow-x: auto;
}

/* New Roundtable Structure with Labels */
.roundtable-speakers-container {
    display: flex;
    gap: 30px;
    width: 100%;
}

.roundtable-moderator-section {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    min-width: 200px;
}

.roundtable-panellists-section {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    flex: 1;
}

.roundtable-role-label {
    color: white;
    font-size: 1.2rem;
    font-weight: normal;
    margin-bottom: 15px;
    text-align: left;
}

.roundtable-panellists-grid {
    display: flex;
    gap: 20px;
    flex-wrap: nowrap;
    overflow-x: auto;
    width: 100%;
}

.roundtable-moderator-section .agenda-speaker-card,
.roundtable-panellists-grid .agenda-speaker-card {
    flex: 0 0 auto;
    min-width: 180px;
}

.agenda-separator {
    height: 1px;
    background: white;
    width: 100%;
}

.moderator-card .agenda-speaker-info p:first-of-type {
    font-weight: 600;
    color: rgba(255, 255, 255, 1);
}

/* Morning Sessions Layout */
.morning-layout {
    display: flex;
    gap: 2rem;
    align-items: stretch;
}

.morning-left {
    flex: 0.55;
    display: flex;
    flex-direction: column;
    gap: 1rem;
    padding-right: 2rem;
    border-right: 1px solid white;
    min-height: 100%;
    justify-content: flex-start;
}

.morning-right {
    flex: 0.45;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
}

.ceremony-top {
    align-self: flex-start;
}

.ceremony-top .time {
    font-weight: 700;
    color: white;
    font-size: 2rem;
    margin-bottom: 0.5rem;
}

.ceremony-top .title {
    color: white;
    font-weight: 400;
    font-size: 2rem;
    line-height: 1.4;
    margin-bottom: 0.5rem;
}

.ceremony-top .subtitle {
    color: #ffffff;
    font-size: 1rem;
    margin: 0.5rem 0;
}

.ceremony-bottom {
    align-self: flex-start;
    margin-top: auto;
}

.morning-session {
    display: flex;
    flex-direction: column;
    gap: 0.8rem;
    padding: 1.5rem 0;
    border-bottom: 1px solid white;
}

.morning-session:last-child {
    border-bottom: none;
}

.morning-session .time {
    font-weight: 700;
    color: white;
    font-size: 2rem;
}

.morning-session .title {
    color: white;
    font-weight: 400;
    font-size: 2rem;
    line-height: 1.4;
}

.morning-session .subtitle {
    color: rgba(255, 255, 255, 0.8);
    font-size: 0.9rem;
    font-style: italic;
    margin: 0.5rem 0;
}

.btn-outline-green {
    background: transparent;
    color: #367F54;
    border: 2px solid #367F54;
    font-size: 1.1rem;
    font-weight: 500;
    padding: 12px 30px;
    border-radius: 5px;
    text-decoration: none;
    display: inline-block;
    transition: all 0.3s ease;
}

.btn-outline-green:hover {
    background: #367F54;
    color: white;
    text-decoration: none;
}

/* Section Separator */
.section-separator {
    background: #0E142C;
    padding: 0;
}

.separator-line {
    height: 1px;
    background: white;
    margin: 0 10px;
}

/* Speakers Section */
.speakers-section {
    padding: 80px 0;
    background: #0E142C;
}

/* Speakers Layout */
.speakers-layout {
    display: flex;
    align-items: flex-start;
    gap: 4rem;
}

.speakers-title-container {
    min-width: 250px;
    text-align: left;
}

.speakers-main-title {
    font-size: 3rem;
    font-weight: 700;
    color: white;
    margin: 0;
    line-height: 1.1;
}

/* Marketing, 2026-09-02: "Speaker 下面加一行小字 'In the order of speaking'".
   Sits under the 3rem title in the same white, at the weight the rest of the
   page uses for a caption. */
.speakers-note {
    margin: 0.5rem 0 0;
    font-size: 0.95rem;
    font-weight: 400;
    line-height: 1.4;
    color: rgba(255, 255, 255, 0.75);
}

.speakers-line {
    display: block;
}

.speakers-content-container {
    flex: 1;
    max-width: 1200px;
    /* Same fix as .programs-carousel (Chase, 2026-09-04): without min-width: 0
       this flex item's floor is its content, and the content was five 227px
       cards that could not shrink — so between 768 and ~1600px the grid ran
       past the .container and the viewport cut the fifth column. */
    min-width: 0;
}

/* auto-fill, not repeat(5): the number of columns follows the width, so a
   column drops out whole instead of being sliced. At the 1200px cap this is
   still five ((1200 - 4rem) / 5 = 227, the card's old fixed width); at 1000 it
   is four, at 800 three. The 1024 and 768 queries below still override. */
.speakers-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: 1rem;
}

.speaker-card {
    width: 100%;          /* was a fixed 227px — the cell sets the width now */
    max-width: 227px;
    justify-self: center;
    display: flex;
    flex-direction: column;
    border-radius: 0;
    overflow: hidden;
    transition: transform 0.3s ease;
    background: transparent;
    box-shadow: none;
    border: 1px solid rgba(255, 255, 255, 0.2);
}

.speaker-card:hover {
    transform: translateY(-3px);
    box-shadow: 0 4px 8px rgba(255, 255, 255, 0.1);
}

.speaker-photo {
    width: 100%;
    aspect-ratio: 1;
    margin: 0;
    border-radius: 0;
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}

.speaker-photo img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.speaker-info {
    padding: 0.75rem 0.5rem;
    text-align: center;
    flex-grow: 1;
    display: flex;
    flex-direction: column;
    justify-content: flex-start;
}

.speaker-info h3 {
    color: white;
    font-size: 0.85rem;
    margin-bottom: 0.25rem;
    font-weight: 600;
    line-height: 1.2;
}

.speaker-info .title,
.speaker-info .company {
    color: rgba(255, 255, 255, 0.8);
    font-size: 0.7rem;
    margin-bottom: 0.1rem;
    line-height: 1.1;
}

/* Partners Section */
.partners-section {
    padding: 80px 0;
    background: #ffffff;
}

.partners-grid {
    display: grid !important;
    grid-template-columns: repeat(20, 1fr) !important;
    gap: 2rem !important;
    max-width: 1600px !important;
    margin: 0 auto !important;
}

/* 🚨 THE LOGO ROWS ARE NOT LAID OUT BY THIS GRID ANY MORE — see
   `.partner-logo-row` further down. This block is now only the shared title and
   the divider, which still span all 20 tracks.

   The history is worth keeping because it is four attempts at the same wrong
   idea. Every version placed nine logos as flat children of `repeat(20, 1fr)`
   and encoded the layout in span arithmetic: hand-placed spans, one selector
   per child number (4+10, 3+13, 3+4+5, 3+4+4 — four round trips, and each time
   one was missed the leftovers fell into bare 30px columns; Chase, 2026-08-20:
   "合作方的logo有些对不上"); then a single uniform span; then two spans with
   nth-child boundaries. The last of those put the right number of logos on each
   row and still looked wrong, because equal cells cannot produce equal GAPS
   when the logos in them are different widths.

   Bunny, 2026-08-20 (APEC_website_mockv3): "only keep supporting organization
   part in the middle" — ESTABLISHED BY / FUNDED BY / CO-HOST left this section
   for the KV logo strip, so the grid's children are the shared title and the
   two logo rows. */

/* Shared title, spanning full width */
.partner-row-title-top {
    grid-column: 1 / 21;
    text-align: center;
    /* 0, not the 3rem it carried while three titled logos sat above it: this is
       the first thing in the section now and .partners-section already pays
       80px of padding. */
    margin-top: 0;
    margin-bottom: 1rem;
}

/* 34px, not the 15px the departed top-row titles used: this rule spans the whole
   page, so its line reads as a section break rather than a column head and needs
   the air (Chase, 2026-08-10: "距離下面的橫線的空間也可以大一些"). Measured
   ink-bottom to line-top: 28px before, 47px now — the gap is bigger than the
   margin because .partner-title is a 44px flex box and the glyphs do not fill it. */
.partner-row-title-top .partner-title {
    margin: 0 0 34px 0 !important;
}

.partner-row-title-top .partner-divider {
    width: 100% !important;
}

/* 🚨 EACH ROW IS ITS OWN FLEX CONTAINER — no spans, no nth-child, no counting.
   Chase, 2026-08-28: "你这个unitar的位置不太对啊".

   The three attempts before this all failed the same way, and the reason is
   worth keeping. The logos were nine flat children of a 20-column grid:
     - uniform `span 5` gave 4 per row, and nine logos left 学说 alone on a third
     - uniform `span 4` gave 5 + 4, and he wanted 4 + 5
     - two spans plus nth-child gave 4 + 5, but every logo was centred in an
       EQUAL cell, so where a row started and ended depended on how wide that
       particular logo happened to be — measured at 1920, row 1 began 94px
       inside the section and row 2 began 3px inside
     - flushing just the two ends fixed the outer edges and broke the inner
       ones: BEC moved left, UNITAR did not, and the gap between them opened up
       while the others stayed put. That is the "unitar的位置不太对".

   Equal cells cannot give equal GAPS when the things in them are different
   widths. space-between can, and does it without knowing how many there are:
   the ends land on the section edges and every gap in the row is identical by
   construction. The row split is now in the markup, where it is legible, and
   nothing in this file counts children any more. */
.partner-logo-row {
    grid-column: 1 / 21;
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 2rem;
}

.partner-item-no-title {
    gap: 0;
}

/* A row with only two logos in it. space-between puts one at each section edge
   and makes the whole width a single gap, which under a four-logo row reads as
   a mistake rather than as a shorter row; centring keeps the block visually
   under the one above. Added 2026-09-08 with Sophie's 4 + 2 split. */
/* 🚨 ITS GAP IS ROW 1's GAP, COMPUTED (Bunny, 2026-10-05: "can the spacing
   between the logos in 2nd row same as 1st row"). Row 1 is space-between, so
   its gap is (row width - its four logos) / 3, and the four logos' total width
   is a fixed multiple of the height cap below them: every image is sized by
   max-height, so 187+196+187+177 = 747px at the 66px cap = 11.32 x the cap,
   and the same 11.32 at 54/44/36 (measured 611/497/408). --plogo-h mirrors that
   cap at each breakpoint. Swap a row-1 logo for one of a different width and
   11.32 must be re-measured (sum the four img widths at 1440, divide by 66).
   Below 769 the rows stack and this does not apply. Was a fixed 6rem/4rem/3rem,
   which left row 2 at 96px against row 1's 218px at 1440. */
.partner-logo-row.partner-logo-row-short {
    justify-content: center;
    --plogo-h: 66px;
    gap: max(2rem, calc((100% - 11.32 * var(--plogo-h)) / 3));
}
@media (max-width: 1200px) { .partner-logo-row.partner-logo-row-short { --plogo-h: 54px; } }
@media (max-width: 1024px) { .partner-logo-row.partner-logo-row-short { --plogo-h: 44px; } }
@media (max-width: 900px)  { .partner-logo-row.partner-logo-row-short { --plogo-h: 36px; } }

/* A logo is as wide as it needs to be and space-between shares out the rest —
   but it MUST be allowed to shrink, or the row overflows.

   🚨 `flex: 0 0 auto` was the first version and it broke between 769 and about
   1100: five logos at their natural widths plus four 2rem gaps are wider than
   the section there, space-between has no slack left to remove, and the row
   simply ran off the right. Measured at 1024: row 2 ended 170px past the
   section's right edge and row 1 85px past. Below 769 the rows stack, so the
   band is narrow and easy to miss — it does not show at 1920 or at 390.

   `1` on flex-shrink plus `min-width: 0` lets the item give way, and
   `max-width: 100%` on the image lets the logo follow it down past the 220px
   cap .partner-logo sets. The gap tightens below 1200 as well, so the logos
   stay as large as they can for as long as they can. */
.partner-logo-row .partner-item-no-title {
    flex: 0 1 auto;
    min-width: 0;
}
/* 🚨 `.partner-logo-row .partner-item-no-title …`, NOT `.partner-logo-row
   .partner-logo …`. The shorter form is (0,3,1) — exactly the same weight as
   `.partner-item-no-title .partner-logo img` further down this file, which sets
   66px/280px — and that one is written LATER, so it wins the tie and none of
   this applied. Cost a full deploy-and-measure round trip: the computed values
   came back 66px/280px, neither the base rule's nor mine. Four classes beats
   three; keep it that way. */
/* 🚨 THE 280px CEILING GOES ON THE ITEM, NOT ON THE IMAGE. Both were tried and
   measured; this is the third arrangement and the reason is subtle.

     max-width: 100% on the img   — drops the ceiling entirely. Alumni is
       662x139, which at the 66px height cap wants 314px, so it grew past 280
       and row 1's gaps went 196 -> 176.
     max-width: min(280px,100%)   — keeps the ceiling but leaves SLACK. A flex
       item is sized from its content's max-content width, which is the 314 the
       image wants before max-width clips it; the picture then renders 280 wide
       inside a 314-wide item, centred, so row 2 started 17px inside the section
       and the gaps came out 142/125/125/125.

   Capping the ITEM removes the slack: the box is at most 280, the image fills
   it, and there is nothing left over to centre. 280 itself is deliberate — see
   the note further down about 上海中心 and 学说 doubling when the cap was 140. */
.partner-logo-row .partner-item-no-title {
    max-width: 280px;
}
.partner-logo-row .partner-item-no-title .partner-logo img {
    max-width: 100%;
}
/* 🚨 max-HEIGHT is what actually shrinks these, not max-width. `.partner-logo
   img` is `width: auto` with an intrinsic ratio, so its rendered width follows
   its HEIGHT — capping the width alone let the flex item narrow while the
   picture inside stayed exactly as wide, and the row still overflowed. Measured
   after the width-only fix: 1920 down to 1200 were exact, but at 1100 the gaps
   had collapsed to 8px and by 900 the logos were overlapping by 40px.
   Two steps, and the row is back inside the section at every width down to
   where it stacks (769). */
@media (max-width: 1200px) {
    .partner-logo-row { gap: 1.25rem; }
    .partner-logo-row .partner-item-no-title .partner-logo img { max-height: calc(54px * var(--logo-scale, 1)); }
    .partner-logo-row .partner-item-no-title .partner-logo { min-height: 110px; }
}
@media (max-width: 1024px) {
    .partner-logo-row { gap: 0.9rem; }
    .partner-logo-row .partner-item-no-title .partner-logo img { max-height: calc(44px * var(--logo-scale, 1)); }
    .partner-logo-row .partner-item-no-title .partner-logo { min-height: 92px; }
}
@media (max-width: 900px) {
    .partner-logo-row { gap: 0.7rem; }
    .partner-logo-row .partner-item-no-title .partner-logo img { max-height: calc(36px * var(--logo-scale, 1)); }
    .partner-logo-row .partner-item-no-title .partner-logo { min-height: 78px; }
}

.partner-item {
    text-align: center;
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

/* Navy, not the institute green (Bunny, 2026-08-07 mockup): "字跟線的顏色轉做
   深藍色, 跟上面的底色一樣" — the same #0E142C the stats band directly above
   this section is painted in, so the white partner strip reads as a continuation
   of it rather than as a third colour. The rule below on hr.partner-divider is
   the "線" half of the same instruction; change one and change both. */
h4.partner-title {
    font-size: 1rem;
    font-weight: 600;
    color: #0E142C;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    margin: 0 0 15px 0 !important;
    padding: 0 !important;
    min-height: 44px;
    display: flex;
    align-items: center;
    justify-content: center;
}

/* 多行标题样式 */
.partner-title-multiline {
    line-height: 1.3;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
}

.partner-subtitle {
    font-size: 1rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    display: block;
    margin-top: 2px;
}

hr.partner-divider {
    width: 100% !important;
    height: 1px !important;
    border: none !important;
    background: #0E142C !important;   /* see h4.partner-title above */
    margin: 0 !important;
}

.partner-logo {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 120px;
}

.partner-logo img {
    max-height: 100px;
    max-width: 220px;
    width: auto;
    object-fit: contain;
}

/* HKJC logo special sizing */
.partner-logo img[alt="HKJCCT Logo"] {
    max-width: 300px;
}

/* HKUBS is height-capped, not width-capped. The plain lockup (no 25th-anniversary
   mark) is 2.26:1 where the anniversary one was 3.80:1, so the shared
   max-width: 220px would render it 97px tall against HKJC's 61px and it would
   dominate the row. At 80px the wordmark matches "The Hong Kong Jockey Club
   Charities Trust" beside it. See build_2026.py for why the mark went. */
.partner-logo img[alt="HKUBS Logo"] {
    max-height: 80px !important;
    max-width: 300px !important;
}

/* Supporting Organization logos - larger sizing.
   Keyed to the class, not to a child range. It was written as a child range
   twice, and both times the count moved underneath it: logos outside the stale
   range fell back to the 220x100 default and rendered visibly smaller than
   their own row — OASES first, then the last two. A ninth logo now inherits
   this without anyone editing a number. */
.partner-item-no-title .partner-logo {
    min-height: 150px;
}

.partner-item-no-title .partner-logo img {
    /* 🚨 Capped by HEIGHT first, and 66px not 140. Measured off Bunny's mockup:
       the eight supporting logos run 45-79px tall and 142-289px wide — they are
       aligned on their height, not stretched to a common width. With the cap at
       140 every logo hit max-width instead, which doubled the compact ones:
       上海中心 rendered 280x111 against the comp's 142x57, 学说 280x108 against
       160x61 (Chase, 2026-08-20: "logo有些对不上"). 66px lands every one of the
       eight within ~15% of the comp, and it is a RULE — a ninth logo inherits
       it instead of needing its own number.

       The px is multiplied by --logo-scale so a single logo can be nudged off
       the shared cap without leaving the rule — see the per-logo block below. */
    max-height: calc(66px * var(--logo-scale, 1));
    max-width: 280px;
    /* 🚨 The six 2025 files these replaced were 1090x590 canvases whose artwork
       filled 12-27% of the frame, so max-height cropped them to a logo a third
       the size of BEC's and UNITAR's, which are cut to their content. All eight
       are now trimmed to the alpha box at an 800px long edge, which is what
       makes them read at one size (Chase, 2026-08-20). Re-export the same way
       or the row goes ragged again. */
    object-fit: contain;
}

/* 🚨 PER-LOGO NUDGES OFF THE SHARED 66px CAP. Bunny, 2026-08-31: "OHKF need to
   enlarge around 5% and 學說 10% smaller". Every other supporting logo is
   deliberately aligned on one height (see above) — this is the exception, not a
   new pattern, so keep the list short and keep the numbers as ratios.

   Keyed to the FILENAME, not to alt text. Alt text is copy: 學說 has already
   been written 学说 and 學說 in the same file, and OHKF's carries a bilingual
   tail. The src is the logo's identity and survives a rewording.

   --logo-scale multiplies the cap rather than replacing it, so these follow the
   row down through the 1200/1024/900 steps and into the phone layout at the same
   relative size, instead of overtaking their neighbours on small screens.

   UNITAR at 0.95 is Chase, 2026-09-01. It is the widest mark of the four — 3.6:1
   against BEC's 2.7 — so at a shared height it reads as the biggest logo in the
   row and it is the first one in Bunny's order. */
.partner-logo-row .partner-logo img[src*="2026-forum-logo-unitar"]  { --logo-scale: 0.95; }
.partner-logo-row .partner-logo img[src*="2026-forum-logo-ohkf"]    { --logo-scale: 1.05; }
.partner-logo-row .partner-logo img[src*="2026-forum-logo-xueshuo"] { --logo-scale: 0.9;  }

/* Carousel Navigation Buttons */
.carousel-btn {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    z-index: 10;
    width: 50px;
    height: 50px;
    background: rgba(255, 255, 255, 0.3);
    border: none;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: all 0.3s ease;
    font-size: 1.8rem;
    color: #666;
    font-weight: 400;
    outline: none;
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
    padding: 0;
    margin: 0;
    box-sizing: border-box;
    overflow: hidden;
}

.carousel-btn-prev {
    left: -25px;
}

.carousel-btn-next {
    right: -25px;
}


/* Floating next button within Programs section */
.programs-section {
    position: relative;
}

/* 🚨 -25px TO MIRROR #programsCarouselPrev, WHICH SITS AT left: -25px. It was
   50px, so the right-hand button sat 75px further in than the left one and the
   pair was visibly off-axis about the carousel (Chase, 2026-08-10).

   The asymmetry hid behind three layers, which is worth knowing before editing
   these buttons again:
     * `.program-carousel-btn-next { right: -25px }` above IS correct and has
       always been dead — this ID rule outranks it and carries !important, so
       even an inline style with !important does not move the button;
     * both buttons are `position: absolute` inside a `display: flex` parent, so
       with left/right auto they park at their flex static position — which is
       what the computed `right: 50px` was reporting, not a specified value;
     * `:disabled { display: none }` hides prev on the first slide, so a
       measurement taken on page load finds it at 0x0 and reports no problem.
   Measure with the carousel advanced one slide and the pointer parked away from
   the buttons — hovering inflates one of them by scale(1.05). */
#programsCarouselNext {
    position: absolute !important;
    right: -25px !important;
    top: 50% !important;
    transform: translateY(-50%) !important;
    z-index: 10 !important;
}

#programsCarouselNext:hover:not(:disabled) {
    transform: translateY(-50%) scale(1.05) !important;
}

/* Programs Indicators */
.programs-indicators {
    display: flex;
    justify-content: center;
    gap: 12px;
    margin-top: 20px;
    margin-bottom: 20px;
}

.programs-indicators .indicator {
    width: 40px;
    height: 4px;
    background-color: rgba(255, 255, 255, 0.3);
    border-radius: 2px;
    cursor: pointer;
    transition: background-color 0.3s ease;
}

.programs-indicators .indicator.active {
    background-color: #ffffff;
}

.programs-indicators .indicator:hover {
    background-color: rgba(255, 255, 255, 0.6);
}

.carousel-btn:hover:not(:disabled) {
    background: rgba(255, 255, 255, 0.5);
    transform: translateY(-50%) scale(1.05);
}

.carousel-btn:active:not(:disabled) {
    background: rgba(0, 0, 0, 0.3);
}

.carousel-btn:disabled {
    display: none;
}

.carousel-btn span {
    user-select: none;
    line-height: 1;
    pointer-events: none;
    margin: 0;
    padding: 0;
}



/* Endowed Professorship Section */
.endowed-section {
    padding: 80px 0;
    background: #f8f9fa;
}

.endowed-content {
    max-width: 800px;
    margin: 0 auto;
    text-align: center;
}

/* Register Section */
.register-section {
    padding: 80px 0;
    background: linear-gradient(135deg, #367F54 0%, #2d6843 100%);
    text-align: center;
}

.register-section .section-title {
    color: #ffffff;
    margin-bottom: 2rem;
}

.register-info h3 {
    color: #ffffff;
    font-size: 2rem;
    margin-bottom: 1rem;
}

.register-info p {
    color: #ffffff;
    font-size: 1.2rem;
    margin-bottom: 2rem;
}

.register-cta {
    display: flex;
    justify-content: center;
    gap: 1rem;
    flex-wrap: wrap;
}

.btn-register-main {
    background: #ffffff;
    color: #367F54;
    padding: 15px 30px;
    border-radius: 5px;
    font-weight: 600;
    text-decoration: none;
    display: inline-block;
    transition: all 0.3s ease;
}

.btn-register-main:hover {
    background: #f5f5f5;
    color: #367F54;
    text-decoration: none;
}

/* Register Badge - same style as date badge */
.kv-register-badge {
    text-decoration: none !important;
    transition: opacity 0.3s ease !important;
}

.kv-register-badge:hover {
    opacity: 0.8 !important;
    text-decoration: none !important;
}

.btn-register-secondary {
    background: transparent;
    color: #ffffff;
    border: 2px solid #ffffff;
    padding: 13px 30px;
    border-radius: 5px;
}


/* 响应式设计 */
@media (max-width: 1024px) {
    .speakers-layout {
        gap: 2rem;
    }
    
    .speakers-title-container {
        min-width: 200px;
    }
    
    .speakers-main-title {
        font-size: 3rem;
    }
    
    .speakers-content-container {
        max-width: calc(100% - 200px - 2rem);
    }
    
    .speakers-grid {
        grid-template-columns: repeat(4, 1fr);
        gap: 0.8rem;
    }
    
    .supporting-logos {
        grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
    }
}

@media (max-width: 768px) {
    /* ---- KV on phones -------------------------------------------------
       Centred like the desktop, but the title is ALLOWED TO WRAP: 60% of a
       390px screen is 234px, which no legible size fits, so the one-line rule
       is dropped here and only here.

       The ceilings are the other half of it. Every unit in this block used to
       be a share of the WIDTH, but the hero's height is pinned — `height:
       30vh` never beats `min-height: 500px`, so the box is 500px tall on a
       phone and on a portrait tablet alike. At 390 wide that is fine; at 768
       the type kept growing while the box did not, the block measured 558px
       inside 500, and the venue line fell off the bottom edge. Each ceiling
       sits above what its vw term yields at 390, so a phone is untouched and
       they only engage past ~510px wide. */
    .kv-title-line {
        white-space: normal !important;
    }

    /* The subtitle wraps here for the same reason the title does, and it drops
       the desktop tracking: that value is width-matched to ONE line at 1920 and
       only pushes the wrap point earlier on a phone.

       🚨 The hero below 768px is a pinned 500px box — `height: 30vh` never beats
       `min-height: 500px` — and this block adds a FOURTH line to copy that
       already measured 558px inside 500 once, at 768. Hence the smaller share
       and the tighter gap; measured at 375, 390 and 768 after. */
    .kv-subtitle {
        white-space: normal !important;
        letter-spacing: 0.02em !important;
        font-size: calc(var(--kv-title) * 0.572) !important;   /* 0.52 * 1.1 */
        margin-bottom: calc(var(--kv-title) * 0.30) !important;
    }

    /* Equal spacers, i.e. centred: the comp has no mobile view, so the 1:4.18
       top bias it specifies for the desktop hero is not carried down here on a
       guess. The phone hero is a 500px box and the copy sits in the middle of
       it, as it does today. */
    .key-visual-content::before,
    .key-visual-content::after {
        flex-grow: 1 !important;
    }

    .key-visual-content {
        --kv-title: min(9.5vw, 46px);

        top: 0 !important;
        align-items: center !important;
        padding: min(12%, 48px) 6% !important;
    }

    /* Hidden since 2025: at this size the lockup's three lines of institute
       name are unreadable, and the site header two inches above already
       carries the same logo in colour. */
    /* The strip is ON the phone now (Bunny's APEC_website_v4-10 mock, 2026-08-24).
       It had been display:none since the lockup moved into the key visual, which
       is why the earlier "fix the logo on the top" note was ambiguous — the only
       logo a phone showed was the white header's.

       Sized off the mock rather than guessed: its ink runs x440-5156 of a 5870
       wide artboard, so 80vw, and the height follows the artwork. `width` has to
       be set explicitly because the desktop rule drives this image from `height`
       and leaves width auto — set only display, and a 10.8:1 strip at the
       desktop height overflows a 393px screen by a factor of three. */
    .kv-logo {
        display: block !important;
    }

    .kv-logo img {
        width: 80vw !important;
        height: auto !important;
        margin: 0 auto !important;
    }

    /* `30vh` never wins against the 500px min-height on the base rule, so this
       is a 500px hero on every handset — which is what the copy below is
       spaced for. */
    .key-visual-section {
        height: 30vh !important;
    }

    /* Mobile video - using dedicated mobile video source, no position adjustment needed */

    .kv-title-section {
        display: flex !important;
        flex-direction: column !important;
        align-items: center !important;
        text-align: center !important;
    }

    .kv-location .location-icon {
        vertical-align: -0.14em !important;
    }

    .anniversary-text {
        font-size: 1.2rem;
    }
    
    /* One logo per row on a phone, so `gap` is pure vertical rhythm — and at
       2rem the marks ran together, several of them being wordmarks with their
       own tight ink. Bunny, 2026-08-21: "logos間的gap也要闊一點" -> 3.5rem, then
       Chase the same day: "提升到現在的兩倍" -> 7rem. Only the single-column
       phone layout; the desktop grid keeps its 2rem.

       Measured ink-to-ink on a 393px screen, because box-to-box is misleading
       here: .partner-logo has min-height 120px around marks capped at 100px, so
       the item boxes overlap into each other's gap and read as tighter than the
       logos actually are. What a visitor sees scales 1:1 with the gap anyway —
       2rem gives ~40px between marks, 3.5rem ~64px, 7rem ~120px. Now every logo
       has more space around it than it occupies.

       Also checked while here: `.partner-item-no-title { grid-column: span 5 }`
       is written for the desktop 20-column grid and still applies in this
       one-column layout, which is why the row track reports 70px against 150px
       items. It changes nothing visible — overriding it to `1 / -1` produced
       byte-identical geometry at every gap tested — so it is left alone rather
       than "fixed" into a no-op that the next person has to re-derive. */
    .partners-grid {
        grid-template-columns: 1fr !important;
        gap: 7rem !important;
    }
    
    .main-title {
        font-size: 2.5rem;
    }
    
    .programs-layout {
        flex-direction: column;
        gap: 2rem;
        align-items: stretch;
    }

    .programs-carousel {
        flex: 0 0 auto;
        align-self: stretch;
    }

    .programs-scroll-container {
        width: 100%;
    }
    
    .programs-title {
        min-width: auto;
        text-align: center;
    }
    
    .programs-title h2 {
        font-size: 2.5rem;
    }
    
    .programs-scroll-container {
        max-width: 100%;
    }
    
    .program-card {
        flex: 0 0 100%;
        margin-right: 0 !important;
    }
    
    .programs-grid {
        grid-template-columns: 1fr;
        gap: 0;
    }
    
    /* 移动端Programs轮播按钮对称布局 */
    .programs-scroll-container {
        position: relative;
    }
    
    /* 🚨 `top: 50%` IS THE WRONG HALF ON A PHONE. The base rule centres the
       arrows on the whole card, and a phone card is image + title + speaker +
       a paragraph — so 50% lands in the title, which is what Bunny circled on
       2026-08-21: two buttons sitting on top of "Who Will Do This Work?".
       On a wide screen the card is mostly image and 50% happens to be fine.

       So aim at the image instead of at the card. .program-image is `width:
       100%; aspect-ratio: 1.55` at the top of the card, and the card sits 16px
       below the positioning ancestor, so its centre is a function of WIDTH, not
       of height: 16px + (container / 1.55) / 2. The container is the viewport
       less the section's 20px side padding at every phone width (measured 353
       at 393, 390 at 430, 728 at 768), which makes the whole thing exact and
       self-adjusting instead of a magic pixel number per handset.

       translateY(-50%) still comes from the base rule, so `top` is the centre.

       🚨 IT HAS TO BE SET ON THE IDs TOO. #programsCarouselNext carries
       `top: 50% !important` at line ~1619 — an ID beats a class even when both
       are !important, so a rule on .program-carousel-btn alone moved Prev and
       left Next behind, one on the image and one still over the paragraph.
       Hence the shared custom property: one number, three selectors, no way
       for the two arrows to drift apart again. */
    .programs-carousel {
        --prog-btn-top: calc(16px + (100vw - 40px) / 3.1);
    }

    .program-carousel-btn {
        width: 45px !important;
        height: 45px !important;
        font-size: 1.5rem !important;
        background: rgba(255, 255, 255, 0.8) !important;
        border: none !important;
        color: #333 !important;
        top: var(--prog-btn-top) !important;
    }

    #programsCarouselPrev,
    #programsCarouselNext {
        top: var(--prog-btn-top) !important;
    }
    
    #programsCarouselPrev {
        left: 15px !important;
    }
    
    #programsCarouselNext {
        right: 15px !important;
    }
    
    .program-carousel-btn:hover:not(:disabled) {
        background: rgba(255, 255, 255, 0.95) !important;
        color: #333 !important;
        transform: translateY(-50%) scale(1.05) !important;
    }
    
    .highlights-grid {
        grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    }
    
    .speakers-layout {
        flex-direction: column;
        gap: 2rem;
        text-align: center;
        align-items: stretch;
    }
    
    .speakers-title-container {
        min-width: auto;
        text-align: center;
    }
    
    .speakers-main-title {
        font-size: 2.5rem;
    }
    
    .speakers-content-container {
        max-width: 100%;
    }
    
    .speakers-grid {
        grid-template-columns: repeat(2, 1fr);
        gap: 0.6rem;
    }
    
    .speaker-card {
        width: 100%;
        max-width: none;
    }
    
    .speaker-photo {
        width: 80%;
        margin: 0 auto;
    }
    
    
    .cta-buttons {
        flex-direction: column;
        align-items: center;
    }
    
    .key-visual-section {
        padding: 100px 0 60px;
    }
    
    .stats-grid {
        grid-template-columns: repeat(2, 1fr);
        gap: 1.5rem;
    }
    
    .stat-item {
        padding: 1rem 0.5rem;
    }
    
    .stat-number {
        font-size: 1.1rem;
    }
    
    
    .partners-container {
        flex-direction: column;
        gap: 1.5rem;
    }
    
    .partner-separator {
        margin: 3rem 0;
    }
    
}

@media (max-width: 480px) {
    .stats-grid {
        /* minmax(0, 1fr): plain 1fr is minmax(auto, 1fr), so the widest stat
           widens its own column instead of being held to half the row. */
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 1rem;
    }

    /* 🚨 THE CAP IS WHAT STOPS "3,000,000+" RUNNING OFF THE SCREEN.
       Rick, 2026-08-27: "Alignment for 3,000,000+ Media Reach". Measured on the
       live page before this: at 390 the number ran x=210 to x=396 in a 390px
       viewport — 6px past the right edge — and at 360 it was 36px past. It is
       the longest string of the four and it has no break opportunity, so no
       amount of grid tuning helps; the type has to come down.
       7.2vw gives 28.1px at 390 against a 167px column, and the 2rem ceiling
       keeps 480 looking exactly as it did. */
    .stat-number {
        font-size: clamp(1.35rem, 7.2vw, 2rem);
    }
    
    .stat-label {
        font-size: 0.9rem;
    }
    
    .speakers-grid {
        grid-template-columns: repeat(2, 1fr);
        gap: 0.5rem;
    }
    
    
    .speaker-info {
        padding: 0.5rem 0.4rem;
    }
    
    .speaker-info h3 {
        font-size: 0.75rem;
    }
    
    .speaker-info .title,
    .speaker-info .company {
        font-size: 0.65rem;
    }
    
    
    .agenda-item {
        flex-direction: column;
        text-align: left !important;
    }
    
    .agenda-item .time {
        min-width: auto;
        margin-right: 0;
        margin-bottom: 0.5rem;
        text-align: left !important;
    }
    
    .agenda-item .title {
        text-align: left !important;
    }
    
    .agenda-header {
        text-align: left !important;
    }
    
    .agenda-details {
        text-align: left !important;
    }
    
    .agenda-details .subtitle {
        text-align: left !important;
    }
    
    .morning-session .time,
    .morning-session .title {
        text-align: left !important;
    }
    
    .ceremony-top .time,
    .ceremony-top .title,
    .ceremony-top .subtitle {
        text-align: left !important;
    }
    
    .keynote-content {
        text-align: left !important;
    }
    
    .keynote-content h3,
    .keynote-content p {
        text-align: left !important;
    }
    
    /* Agenda移动端适配 */
    .agenda-section {
        padding: 60px 0;
    }
    
    /* Agenda标题格式 - 参考Speaker样式 */
    .agenda-content {
        max-width: 100%;
        margin: 0 auto;
    }
    
    .agenda-item.agenda-title-row {
        text-align: center !important;
        margin-bottom: 2rem;
    }
    
    .agenda-item.agenda-title-row .agenda-header {
        display: flex !important;
        justify-content: center !important;
        align-items: center !important;
    }
    
    .agenda-item.agenda-title-row .title {
        font-size: 2.5rem !important;
        margin-bottom: 0;
        text-align: center;
    }
    
    /* 禁用Morning Layout特殊布局，改为顺序垂直排列 */
    .morning-layout {
        display: block !important;
        flex-direction: unset !important;
        gap: unset !important;
        align-items: unset !important;
    }
    
    .morning-left, .morning-right {
        display: block !important;
        flex: unset !important;
        width: 100% !important;
        padding: 0 !important;
        border: none !important;
        margin-bottom: 2rem;
    }

    .morning-left {
        border-right: none !important;
        padding-right: 0 !important;
        border-bottom: 1px solid white !important;
        padding-bottom: 2rem !important;
    }
    
    .morning-session {
        margin-bottom: 2rem;
    }
    
    .ceremony-top, .ceremony-bottom {
        margin-bottom: 2rem;
    }
    
    /* Agenda Speaker Cards移动端调整 - 统一使用2列网格布局 */
    .agenda-speakers-grid {
        display: grid !important;
        grid-template-columns: repeat(2, 1fr) !important;
        gap: 0.6rem !important;
        margin-top: 1rem !important;
    }

    /* Single Row Layout Mobile Adaptation - 改为2列网格 */
    .agenda-speakers-grid.agenda-speakers-single-row {
        display: grid !important;
        grid-template-columns: repeat(2, 1fr) !important;
        gap: 0.6rem !important;
        margin-top: 1rem !important;
    }

    .agenda-speakers-grid.agenda-speakers-single-row .agenda-speaker-card {
        width: 100% !important;
        max-width: none !important;
        flex: unset !important;
    }

    /* Research Presentations (3 professors) - 改为2列网格 */
    .agenda-speakers-grid:has(.agenda-speaker-card:nth-child(3):last-child) {
        display: grid !important;
        grid-template-columns: repeat(2, 1fr) !important;
        gap: 0.6rem !important;
        margin-top: 1rem !important;
    }

    .agenda-speakers-grid:has(.agenda-speaker-card:nth-child(3):last-child) .agenda-speaker-card {
        width: 100% !important;
        max-width: none !important;
        flex: unset !important;
    }

    /* 2x2 Layout Mobile Adaptation */
    .agenda-speakers-grid.agenda-speakers-2x2 {
        display: flex !important;
        flex-direction: column;
        gap: 0.8rem;
    }

    .agenda-speakers-grid.agenda-speakers-2x2 .agenda-speaker-row {
        display: flex;
        justify-content: space-evenly;
        gap: 0.6rem;
    }

    .agenda-speakers-grid.agenda-speakers-2x2 .agenda-speaker-row .agenda-speaker-card {
        flex: 1;
        max-width: 45%;
    }
    
    .agenda-speaker-card {
        width: 100%;
        max-width: none;
        min-width: auto;
    }
    
    .agenda-speaker-photo {
        width: 80%;
        margin: 0 auto;
    }
    
    .agenda-speaker-info h4 {
        font-size: 0.75rem;
        line-height: 1.1;
    }
    
    .agenda-speaker-info p {
        font-size: 0.65rem;
        line-height: 1.1;
    }
    
    /* Keynote Layout移动端调整 - 上下布局 */
    .keynote-layout {
        display: flex !important;
        flex-direction: column !important;
        gap: 1rem !important;
        align-items: flex-start !important;
    }

    .keynote-speaker {
        width: 100% !important;
        flex: none !important;
        display: block !important;
    }

    /* Speaker卡片内部左右布局 */
    .keynote-speaker .agenda-speaker-card {
        width: 100% !important;
        max-width: none !important;
        display: flex !important;
        flex-direction: row !important;
        align-items: center !important;
        gap: 1rem !important;
    }

    .keynote-speaker .agenda-speaker-photo {
        width: 40% !important;
        flex: 0 0 40% !important;
        margin: 0 !important;
    }

    .keynote-speaker .agenda-speaker-info {
        width: 60% !important;
        flex: 0 0 60% !important;
        padding-left: 0 !important;
        display: flex !important;
        flex-direction: column !important;
        justify-content: center !important;
        align-items: flex-start !important;
        margin-left: -0.5rem !important;
        text-align: left !important;
    }

    .keynote-speaker .agenda-speaker-info h4,
    .keynote-speaker .agenda-speaker-info p {
        text-align: left !important;
        margin-left: 0 !important;
    }

    .keynote-content {
        width: 100% !important;
        flex: none !important;
        margin-top: 0 !important;
        padding-left: 0 !important;
    }
    
    .keynote-content h3 {
        font-size: 1.2rem;
    }
    
    .keynote-content p {
        font-size: 0.9rem;
        line-height: 1.4;
    }
    
    /* Agenda时间和标题调整 */
    .agenda-item .time {
        font-size: 1.4rem;
    }
    
    .agenda-item .title {
        font-size: 1.2rem;
        line-height: 1.3;
    }

    /* Mobile agenda note */
    .agenda-note-text {
        font-size: 0.8rem !important;
        padding: 0 1rem;
    }
    
    /* Roundtable移动端调整 - 统一网格布局 */
    .roundtable-speakers-container {
        display: block !important;
        gap: unset !important;
    }
    
    .roundtable-moderator-section,
    .roundtable-panellists-section {
        width: 100% !important;
        display: block !important;
        flex-direction: unset !important;
        align-items: unset !important;
        min-width: unset !important;
        flex: unset !important;
    }
    
    .roundtable-role-label {
        font-size: 1.1rem;
        margin-bottom: 1rem;
        text-align: left;
    }
    .agenda-showcase-note--lg { font-size: 1.1rem; }
    
    /* 将所有speaker卡片放在一个统一的网格中 */
    .roundtable-moderator-section .agenda-speaker-card {
        display: inline-block;
        width: calc(50% - 0.3rem);
        margin-right: 0.6rem;
        margin-bottom: 0.6rem;
        vertical-align: top;
    }
    
    .roundtable-panellists-grid {
        display: grid !important;
        grid-template-columns: repeat(2, 1fr) !important;
        gap: 0.6rem !important;
        flex-wrap: unset !important;
        overflow-x: visible !important;
        width: 100% !important;
        margin-top: 0;
    }
    
    .roundtable-panellists-grid .agenda-speaker-card {
        width: 100% !important;
        max-width: none !important;
        min-width: auto !important;
        flex: unset !important;
    }
    
}

/* Floating Registration Popup */
.floating-register-popup {
    position: fixed;
    bottom: 20px;
    right: 20px;
    width: 320px;
    height: 139px;
    z-index: 9999;
    border-radius: 12px;
    overflow: hidden;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
    transition: all 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94);
    cursor: pointer;
    opacity: 0;
    transition: all 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94), opacity 0.5s ease;
}

.floating-register-popup.minimized {
    width: 320px;
    height: 50px;
    border-radius: 25px;
}

.popup-toggle {
    position: absolute;
    top: 10px;
    right: 15px;
    width: 30px;
    height: 30px;
    background: rgba(0, 0, 0, 0.4);
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    z-index: 10001;
    transition: all 0.3s ease;
}

.popup-toggle:hover {
    background: rgba(0, 0, 0, 0.6);
    transform: scale(1.1);
}

.toggle-icon {
    color: white;
    font-size: 20px;
    font-weight: bold;
    line-height: 1;
}

.popup-full-content {
    width: 100%;
    height: 100%;
    opacity: 1;
    transition: opacity 0.3s ease;
}

.floating-register-popup.minimized .popup-full-content {
    opacity: 0;
    pointer-events: none;
}

.popup-full-content a {
    display: block !important;
    width: 100% !important;
    height: 100% !important;
    z-index: 10 !important;
    cursor: pointer !important;
}

.popup-full-content img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: 12px;
}

.popup-minimized-content {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: linear-gradient(135deg, #1a2240, #2c4a68);
    display: flex;
    align-items: center;
    justify-content: flex-start;
    padding: 0 20px 0 15px;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.3s ease;
    border-radius: 25px;
}

.floating-register-popup.minimized .popup-minimized-content {
    opacity: 1;
    pointer-events: auto;
}

.minimized-text {
    color: white;
    font-size: 13px;
    font-weight: 500;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    text-align: left;
}

.floating-register-popup:hover {
    transform: translateY(-3px);
    box-shadow: 0 12px 40px rgba(0, 0, 0, 0.4);
}

/* 隐藏回到顶部按钮 */
.aux-goto-top-btn {
    display: none !important;
}

/* 移动端适配 */
@media (max-width: 768px) {
    .floating-register-popup {
        width: 280px;
        height: 122px;
        bottom: 15px;
        right: 15px;
    }
    
    .floating-register-popup.minimized {
        width: 280px;
        height: 45px;
    }
    
    .minimized-text {
        font-size: 12px;
    }
}

@media (max-width: 480px) {
    .floating-register-popup {
        width: 250px;
        height: 109px;
        bottom: 10px;
        left: 10px;
    }
    
    .floating-register-popup.minimized {
        width: 250px;
        height: 40px;
    }
    
    .minimized-text {
        font-size: 11px;
        padding: 0 40px 0 10px;
    }
    
    .popup-toggle {
        top: 5px;
        right: 10px;
        width: 25px;
        height: 25px;
    }
    
    .toggle-icon {
        font-size: 16px;
    }
}

/* ===== SPEAKER BIO MODAL STYLES ===== */

/* Modal Container */
.speaker-bio-modal {
    display: none;
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    z-index: 10000;
    opacity: 0;
    transition: opacity 0.3s ease;
}

.speaker-bio-modal.active {
    display: block;
    opacity: 1;
}

/* Modal Overlay */
.bio-modal-overlay {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.7);
    cursor: pointer;
}

/* Modal Content Container */
.bio-modal-content {
    position: relative;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    background: #ffffff;
    width: 90%;
    max-width: 1000px;
    max-height: 85vh;
    border-radius: 0;
    box-shadow: 0 10px 50px rgba(0, 0, 0, 0.3);
    overflow: hidden;
}

/* Close Button */
.bio-modal-close {
    position: absolute;
    top: 20px;
    right: 20px;
    width: 40px;
    height: 40px;
    background: transparent;
    border: none;
    font-size: 2.5rem;
    color: #666;
    cursor: pointer;
    z-index: 10;
    transition: all 0.3s ease;
    line-height: 1;
    display: flex;
    align-items: center;
    justify-content: center;
}

.bio-modal-close:hover {
    color: #000;
    transform: rotate(90deg);
}

/* Modal Inner Container */
.bio-modal-inner {
    display: flex;
    height: 100%;
    max-height: 85vh;
}

/* Left Side - Speaker Info */
.bio-modal-left {
    flex: 0 0 320px;
    background: #f8f9fa;
    padding: 40px 30px;
    display: flex;
    flex-direction: column;
    align-items: center;
    border-right: 1px solid #e0e0e0;
}

.bio-speaker-photo {
    width: 200px;
    height: 200px;
    border-radius: 0;
    overflow: hidden;
    margin-bottom: 25px;
    box-shadow: 0 4px 15px rgba(0, 0, 0, 0.15);
}

.bio-speaker-photo img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.bio-speaker-basic {
    text-align: left;
    width: 100%;
}

.bio-speaker-basic h3 {
    font-size: 1.6rem;
    font-weight: 700;
    color: #000;
    margin-bottom: 15px;
    line-height: 1.3;
}

.bio-speaker-title {
    font-size: 0.85rem;
    color: #000;
    margin-bottom: 6px;
    line-height: 1.4;
    font-weight: 400;
}

.bio-speaker-company {
    font-size: 0.85rem;
    color: #000;
    font-weight: 400;
    margin-bottom: 15px;
}

/* Speaker Social Links */
.bio-speaker-links {
    display: flex;
    gap: 12px;
    justify-content: flex-start;
    align-items: center;
    margin-top: 15px;
}

.bio-social-link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border-radius: 0;
    background: transparent;
    transition: all 0.3s ease;
    text-decoration: none;
}

.bio-social-link:hover {
    opacity: 0.7;
}

.bio-social-link svg {
    display: block;
    transition: all 0.3s ease;
}

.bio-social-link:hover svg {
    transform: scale(1.1);
}

/* Hide links if no URL is set - TEMPORARILY DISABLED FOR TESTING */
/* .bio-social-link[href="#"],
.bio-social-link[href=""] {
    display: none;
} */

/* Right Side - Biography Content */
.bio-modal-right {
    flex: 1;
    padding: 50px 40px;
    overflow-y: auto;
}

.bio-section-title {
    display: none;
}

.bio-content {
    color: #333;
    font-size: 0.9rem;
    line-height: 1.7;
}

.bio-content p {
    margin-bottom: 1rem;
}

.bio-content p:last-child {
    margin-bottom: 0;
}

/* Clickable Speaker Cards */
/* 🚨 `cursor: pointer` moved to the --has-bio classes 2026-09-04. The blanket
   rule made every card LOOK clickable, including Ms. Alpha Lau's, whose bio is
   missing (see speaker-bio-2026.js) — clicking her did nothing, which is the
   exact broken-promise this file's own note below warns about for agenda faces.
   speaker-bio-2026.js adds .speaker-card--has-bio / .agenda-speaker-card--has-bio
   only where a profile exists, so the pointer now follows the modal. */
.speaker-card,
.agenda-speaker-card {
    transition: all 0.3s ease;
}

.speaker-card--has-bio,
.agenda-speaker-card--has-bio {
    cursor: pointer;
}

/* 🚨 THE POINTER IS A PROMISE. This rule gave every agenda face a pointer and a
   hover lift from the day the modal shipped, while speaker-bio-2026.js wired
   only the grid — so twenty faces invited a click that did nothing, which is
   what Bunny reported on 2026-08-24. The script wires them now, and this rule
   makes the affordance follow the wiring rather than run ahead of it: a card
   the script could not resolve to a bio stops advertising one. Both facts then
   come from the same place, so they cannot disagree again. */
.agenda-speaker-card:not(.agenda-speaker-card--has-bio) {
    cursor: default;
}
.agenda-speaker-card:not(.agenda-speaker-card--has-bio):hover {
    transform: none !important;
}

/* Same gold ring, and the same Mac-only suppression, as the grid cards —
   see the .speaker-card--has-bio pair further down. */
.agenda-speaker-card--has-bio:focus-visible {
    outline: 2px solid #b89642;
    outline-offset: 4px;
}
.agenda-speaker-card--has-bio.bio-refocus-quiet:focus-visible {
    outline: none;
}

.speaker-card:hover,
.agenda-speaker-card:hover {
    transform: translateY(-5px);
}

/* Responsive Design for Bio Modal */
@media (max-width: 768px) {
    .bio-modal-content {
        width: 95%;
        max-width: 600px;
        max-height: 80vh;
        border-radius: 0;
    }

    .bio-modal-inner {
        flex-direction: column;
    }

    .bio-modal-left {
        flex: 0 0 auto;
        padding: 30px 20px;
        border-right: none;
        border-bottom: 1px solid #e0e0e0;
    }

    .bio-speaker-photo {
        width: 150px;
        height: 150px;
        margin-bottom: 20px;
        border-radius: 0;
    }

    .bio-speaker-basic h3 {
        font-size: 1.4rem;
    }

    .bio-modal-right {
        padding: 30px 25px;
        max-height: 45vh;
        overflow-y: auto;
        -webkit-overflow-scrolling: touch;
    }

    .bio-section-title {
        font-size: 1.5rem;
    }

    .bio-modal-close {
        top: 15px;
        right: 15px;
        width: 35px;
        height: 35px;
        font-size: 2rem;
    }
}

@media (max-width: 480px) {
    .bio-modal-content {
        width: 95%;
        max-width: 450px;
        max-height: 75vh;
        border-radius: 0;
    }

    .bio-modal-left {
        padding: 25px 15px;
    }

    .bio-speaker-photo {
        width: 120px;
        height: 120px;
        border-radius: 0;
    }

    .bio-speaker-basic h3 {
        font-size: 1.3rem;
    }

    .bio-speaker-title,
    .bio-speaker-company {
        font-size: 0.8rem;
    }

    .bio-modal-right {
        padding: 25px 20px;
        max-height: 35vh;
        overflow-y: auto;
        -webkit-overflow-scrolling: touch;
    }

    .bio-section-title {
        font-size: 1.3rem;
    }

    .bio-content {
        font-size: 0.85rem;
        padding-bottom: 20px;
    }
}

/* ===== CUSTOM FOOTER STYLES ===== */

/* 主要容器样式 */
.custom-footer-section {
    background: #1a1a1a !important;
    color: #ffffff !important;
    padding: 60px 0 30px !important;
    margin-top: 0 !important;
    width: 100% !important;
}

/* Logo区域 - 两列布局.
   🚨 The count is load-bearing: these are hand-placed tracks, not auto-flow, so
   the number of columns must equal the number of .footer-logo-item children.
   It was `1fr 1.5fr 1fr 1.5fr` for four; both 第一财经 blocks came out on
   2026-08-11 and the survivors would otherwise have sat in columns 1-2 with two
   empty tracks to their right, i.e. the pair shunted hard left.

   EQUAL tracks now, not the old 1:1.5. The 1.5 was there to give the wide HKJC
   lockup room among four items; with two, equal columns are what puts the pair
   symmetrically about the page centre — measured 326/489/326 → 585/585, HKUBS
   centred 308px left of centre and HKJC 307 right.

   build_2026.py asserts the child count is 2. Change both, or neither. */
.footer-logos {
    display: grid !important;
    grid-template-columns: 1fr 1fr !important;
    gap: 30px !important;
    margin-bottom: 50px !important;
    text-align: center !important;
    max-width: 1200px !important;
    margin-left: auto !important;
    margin-right: auto !important;
}

.footer-logo-item {
    display: flex !important;
    flex-direction: column !important;
    align-items: center !important;
    justify-content: flex-start !important;
    min-height: 140px !important;
}

.footer-logo-item a {
    text-decoration: none !important;
    display: flex !important;
    align-items: flex-start !important;
    justify-content: center !important;
}

.footer-logo-item img {
    width: auto !important;
    margin: 15px auto 0 !important;
    display: block !important;
    transition: opacity 0.3s ease !important;
    vertical-align: top !important;
}

/* Direct img without a tag - for Media Partner */
.footer-logo-item > img {
    margin: 15px auto 0 !important;
    align-self: flex-start !important;
}

/* Individual logo sizing for visual balance */
.footer-logo-item img[alt="HKU Business School"] {
    height: 95px !important;
}

/* 🚨 67px, NOT the 120px this rule carried, and that is not a shrink.
   The Jockey Club's new artwork (2026-08-24) is trimmed to its ink; the file it
   replaces was not — its lockup occupied only 52%% of the box height, the rest
   transparent margin. Measured on both files: the old asset at 120px rendered a
   62.1px text block and a 54.0px roundel, and the new one reaches 62.1px text at
   66.7px and 54.0px roundel at 65.9px. So 67px reproduces the mark at exactly
   the size it has been, and the two independent measurements agreeing is the
   check that it is the right number.

   Height, not width, because the artwork also gained the divider and the 2026
   mark to the right of the lockup: 6.10:1 against the old 3.18:1. At the old
   120px it would have been 733px wide in a 585px grid track and simply
   overflowed; at 67px it is 409px, near the 381px the lockup occupied before.

   The top margin replaces the padding the old file carried inside itself, so
   the mark keeps its optical line against HKU Business School beside it. */
.footer-logo-item img[alt="HKJC"] {
    height: 67px !important;
    margin-top: 29px !important;
}

/* Dead since 2026-08-11 — no img[alt="Media Partner"] is printed any more.
   Kept, not deleted: this logo has come and gone once already and putting it
   back should not also mean re-deriving its size. */
.footer-logo-item img[alt="Media Partner"] {
    height: 60px !important;
    margin-top: 30px !important;
}

.footer-logo-item img[alt="Content Partner"] {
    height: 60px !important;
    margin-top: 30px !important;
}

.footer-logo-item a:hover img {
    opacity: 0.8 !important;
}

.footer-logo-title {
    font-size: 14px !important;
    font-weight: 400 !important;
    margin: 0 0 15px 0 !important;
    color: #ffffff !important;
    font-family: 'Montserrat', sans-serif !important;
    text-align: center !important;
}

/* 社交媒体图标 */
.footer-social {
    display: flex !important;
    justify-content: center !important;
    gap: 12px !important;
    margin-bottom: 40px !important;
    padding: 30px 0 !important;
    border-top: 1px solid rgba(255,255,255,0.1) !important;
    border-bottom: 1px solid rgba(255,255,255,0.1) !important;
}

.footer-social a {
    display: flex !important;
    align-items: center !important;
    justify-content: center !important;
    color: #ffffff !important;
    text-decoration: none !important;
    transition: all 0.3s ease !important;
}

.footer-social a:hover {
    transform: translateY(-3px) !important;
}

.footer-social a img {
    width: 32px !important;
    height: 32px !important;
    object-fit: contain !important;
    transition: opacity 0.3s ease !important;
}

.footer-social a:hover img {
    opacity: 0.8 !important;
}

/* 底部区域 */
.footer-bottom {
    text-align: center !important;
    padding-top: 20px !important;
    width: 100% !important;
    margin: 0 !important;
    display: flex !important;
    flex-direction: column !important;
    align-items: center !important;
    justify-content: center !important;
}

.footer-links {
    margin-bottom: 20px !important;
    font-size: 14px !important;
}

.footer-links a {
    color: rgba(255,255,255,0.8) !important;
    text-decoration: none !important;
    margin: 0 10px !important;
    transition: color 0.3s ease !important;
    font-family: 'Montserrat', sans-serif !important;
}

.footer-links a:hover {
    color: #ffffff !important;
}

.footer-links span {
    color: rgba(255,255,255,0.4) !important;
    margin: 0 5px !important;
}

.footer-copyright {
    font-size: 12px !important;
    color: rgba(255,255,255,0.6) !important;
    margin: 15px 0 !important;
    font-family: 'Montserrat', sans-serif !important;
    line-height: 1.5 !important;
}

.footer-disclaimer {
    font-size: 10px !important;
    color: rgba(255,255,255,0.4) !important;
    margin: 15px 0 0 0 !important;
    font-family: 'Montserrat', sans-serif !important;
    line-height: 1.4 !important;
    white-space: nowrap !important;
    text-align: center !important;
    width: 100% !important;
}

.footer-disclaimer small {
    font-size: inherit !important;
}

/* 响应式设计 */
@media (max-width: 992px) {
    .footer-logos {
        grid-template-columns: repeat(2, 1fr) !important;
        gap: 30px !important;
    }

    /* 🚨 The `.footer-logo-item:last-child { grid-column: 1 / -1 }` rule that
       used to live here is GONE, deliberately. It existed to centre the
       orphaned FOURTH item on a two-column grid. There are two items now, so
       it made the second one span the whole row while the first sat in a half
       — a rule that was correct for a count that no longer exists. */
}

@media (max-width: 768px) {
    /* Partners Section - Mobile: One logo per row.
       Written as a child selector rather than fifteen hand-counted nth-childs,
       which stopped at 15 and so left children 16 and 17 carrying their desktop
       column spans on phones once the block grew to seventeen. */
    .partners-grid > * {
        grid-column: auto !important;
    }

    /* 🚨 THE DEAD BAND UNDER THE DIVIDER IS THIS GAP, NOT A MARGIN. .partners-grid
       is itself a grid and carries a 7rem row-gap, which put 112px between the
       rule and the first logo — with only two children left (the title row and
       the one logo row) that gap is the whole space Bunny saw as empty in her
       2026-08-31 screenshot. Nothing on .partner-row-title-top or on the row
       explains it; both measured 0/15px. */
    .partners-grid {
        gap: 24px !important;
    }

    /* 🚨 ONE COLUMN, BUT NOT THE OLD ONE. Chase, 2026-09-01: "改成一列".
       It was briefly 2x2 (2026-08-31) and before that a column with a 7rem gap
       and a -5rem margin clawing it back — arithmetic from when there were nine
       logos and stacking was the only thing that fit. Bunny's four made that
       shape wrong: measured at 390 it ran 328px to show four logos 36px high,
       so the section was mostly gap and every mark read as small.

       Back to one per row, but keeping what the 2x2 pass was actually for —
       a 24px gap instead of 7rem-minus-5rem, and a 46px cap instead of 36.
       Section height lands near the 2x2's rather than the original's.

       Still a grid, not the base flex: justify-items does the centring in one
       declaration, and there is no negative margin left to reason about. */
    /* 🚨 58px, measured off the same mockup as the 72px cap. Chase,
       2026-09-01: "logo之间再分开一些". It started at 24, which left 53px of white
       between one logo's ink and the next; Bunny's screenshot has 87px at the
       same scale. 58 closes that. Re-measure off the INK if you change it —
       .partner-logo is a 100px box around a mark 65-76px tall, so ~15px of the
       run between two logos is box and the rest is this gap. */
    .partner-logo-row {
        display: grid !important;
        grid-template-columns: 1fr !important;
        flex-direction: row !important;
        gap: 58px !important;
        align-items: center !important;
        justify-items: center !important;
    }
    .partners-grid .partner-logo {
        justify-content: center !important;
    }
    /* The 280px item cap is narrower than the track now, so the item has to be
       told to fill it or the logos stop centring on the screen. */
    .partner-logo-row .partner-item-no-title {
        max-width: 100% !important;
        width: 100% !important;
    }
    /* 🚨 72px, AND THE NUMBER CAME OFF BUNNY'S MOCKUP — do not round it down
       to look tidier. She sent a screenshot on 2026-09-01: "在mobile可以全部都
       一起大嗎？像這樣". Measuring the ink in it against the section title —
       the one element whose size does not change between her phone and a 390
       render — every logo was ~1.6x what the 46px cap gave, and all four by the
       SAME factor, which is what "全部都一起大" asks for.

       72 reproduces that to within a percent of her image, at 390:
         UNITAR  248px wide, 63.5%   (hers 64.7%)
         OHKF    197px,      50.6%   (51.5%)
         BEC     194px,      49.8%   (50.8%)
         xueshuo 168px,      43.1%   (44.3%)
       --logo-scale still rides on top, so the three per-logo nudges survive the
       enlargement instead of being flattened by it.

       max-width: 100% is the guard at 320, where 248px would overrun the
       container. */
    .partner-logo-row .partner-item-no-title .partner-logo img {
        max-height: calc(72px * var(--logo-scale, 1)) !important;
        max-width: 100% !important;
    }

    /* The <=900 step leaves .partner-logo at 78px, which a 75.6px OHKF fills to
       the pixel. 100 gives every mark room to sit in. */
    .partner-logo-row .partner-item-no-title .partner-logo {
        min-height: 100px !important;
    }

    /* 移动端共同标题行样式 */
    .partner-row-title-top {
        margin: 15px 0 !important;
    }

    .partner-row-title-top .partner-title {
        font-size: 0.9rem !important;
    }

    /* Supporting Organization间距调整 - 移动端.
       Was -5rem, clawing back the 7rem gap of the old one-per-row column.
       The grid above sets its own 30px row gap, so a negative margin here just
       overlaps the two rows. */
    .partners-grid .partner-item-no-title {
        margin-bottom: 0 !important;
    }

    .custom-footer-section {
        padding: 40px 0 20px !important;
        margin-top: 0 !important;
    }

    .footer-logos {
        grid-template-columns: 1fr !important;
        gap: 25px !important;
        margin-bottom: 30px !important;
    }

    .footer-logo-item {
        min-height: auto !important;
    }

    .footer-logo-item img {
        max-height: 60px !important;
    }

    /* HKUBS和HKJC logo在移动端可以更大 */
    .footer-logo-item img[alt="HKU Business School"] {
        max-height: 80px !important;
    }

    /* 🚨 WIDTH-DRIVEN HERE, OR THE MARK IS STRETCHED. The desktop rule pins
       `height: 67px` and leaves width auto, which at 6.10:1 wants 409px — wider
       than the 323px column a 393px phone gives it. The theme's `img
       { max-width: 100% }` then clamps the width while the height stays pinned,
       and the browser honours both: the roundel came out an egg and the type
       came out condensed (measured 323x67 = 4.82:1 against the artwork's 6.10).
       `max-height` alone does not save it — it was already 100px here and never
       binds. Only releasing the height does.

       This is the third outing for one bug: the squeezed JC logo in 33fc3db and
       the 275px mobile header in acabe89 were both a fixed dimension meeting a
       cap. Whenever an aspect-ratio-bearing image is given a hard height, ask
       what happens when its natural width will not fit. */
    .footer-logo-item img[alt="HKJC"] {
        width: 100% !important;
        height: auto !important;
        /* The ceiling is a max-WIDTH, never a max-height: with the width fixed
           at 100%, a max-height clamp would squash the mark exactly as the
           desktop height rule did. 409px is what the mark renders at on a wide
           screen, so a 768px tablet — one column, a 728px track — stops there
           instead of drawing it larger than the desktop does. */
        max-width: 409px !important;
        max-height: none !important;
    }

    .footer-social {
        gap: 10px !important;
        padding: 20px 0 !important;
        flex-wrap: wrap !important;
    }


    .footer-social a img {
        width: 28px !important;
        height: 28px !important;
    }

    .footer-links a {
        display: inline-block !important;
        margin: 5px 10px !important;
    }
}

@media (max-width: 480px) {
    .custom-footer-section {
        padding: 30px 15px 15px !important;
        margin-top: 0 !important;
    }
    
    .footer-logo-title {
        font-size: 12px !important;
    }
    
    .footer-logo-item img {
        max-height: 50px !important;
    }

    /* HKUBS和HKJC logo在小屏移动端也可以更大 */
    .footer-logo-item img[alt="HKU Business School"] {
        max-height: 70px !important;
    }

    /* the 768 block already releases the height; keep this one from re-pinning it */
    .footer-logo-item img[alt="HKJC"] {
        max-height: none !important;
    }


    .footer-social a img {
        width: 24px !important;
        height: 24px !important;
    }
}

/* ===== VENUE SECTION STYLES ===== */

/* Venue Section */
.venue-section {
    padding: 80px 0;
    background: #ffffff;
    color: #000000;
}

.venue-section .container {
    max-width: 1200px;
}

.venue-title {
    font-size: 3rem;
    font-weight: 700;
    color: #000000;
    margin-bottom: 1rem;
    text-align: left;
}

.venue-info {
    font-size: 1.2rem;
    font-weight: 700;
    color: #000000;
    margin-bottom: 0;
    padding-bottom: 2rem;
    text-align: left;
}

.venue-pin {
    width: 24px !important;
    height: 24px !important;
    margin-right: 8px !important;
    vertical-align: middle !important;
    display: inline-block !important;
}

/* Google Map Container */
.venue-map-container {
    width: 100%;
    margin: 0;
    border: 1px solid #000000;
}

/* 🚨 margin: 0 is what closes the white strip under the map (Chase, 2026-08-11:
   "地图最下面为什么有个白边"). The theme gives every iframe `margin-bottom: 1rem`,
   and this rule never mentioned margin, so it inherited 16px — which sat INSIDE
   the container's 1px black border and read as a white band along the bottom
   edge of the map. Measured: iframe 500px, container 518 = 1 + 500 + 16 + 1.

   Not the usual inline-descender gap — `display: block` was already here and
   already working. Anything with a border wrapped tightly around an iframe on
   this site wants this line; /2025-sustainability-forum/ has the same strip. */
.venue-map-container iframe {
    display: block !important;
    width: 100% !important;
    margin: 0 !important;
}

/* Responsive Design */
@media (max-width: 768px) {
    .venue-section {
        padding: 60px 0;
    }

    .venue-title {
        font-size: 2.5rem;
        margin-bottom: 0.8rem;
    }

    .venue-info {
        font-size: 1.1rem;
        margin-bottom: 1.5rem;
    }

    .venue-pin {
        width: 20px !important;
        height: 20px !important;
        margin-right: 6px !important;
    }

    .venue-map-container iframe {
        height: 350px !important;
    }
}

@media (max-width: 480px) {
    .venue-title {
        font-size: 2rem;
    }

    .venue-info {
        font-size: 1rem;
    }

    .venue-pin {
        width: 18px !important;
        height: 18px !important;
        margin-right: 5px !important;
    }

    .venue-map-container iframe {
        height: 300px !important;
    }
}
/* ---------------------------------------------------------------------------
   The white strip above the footer.

   The theme keeps a bottom margin below the content — .entry-main 70px and
   .entry-content 50px — so the page's own dark ground stops and the white body
   background shows through between the last section and the footer. Zeroed
   rather than painted dark: a background would leave 120px of dead page still
   sitting there. Same rule and same reason as insights.css and about.css.
   --------------------------------------------------------------------------- */
.entry-main,
.entry-content {
  margin-bottom: 0 !important;
}

/* ---------------------------------------------------------------------------
   Hide the site-wide theme header on this page (Chase, 2026-08-06).

   This is what `hide-default.css` was written for in 2025 and never did: every
   selector in that file is still `body.page-id-[PAGE_ID]`, the literal
   placeholder, so it matches nothing and the whole sheet is inert. It is not
   loaded here — these rules replace it, scoped to the real page id.

   Both the header and its sticky clone have to go; the theme swaps in
   `.aux-sticky-header` on scroll, so hiding only the first one puts the bar
   back the moment the visitor moves. The page's own green nav is
   `position: sticky` and rises to y=0 on its own once the 157px header is out
   of the flow — nothing needs repositioning.
   --------------------------------------------------------------------------- */
body.page-id-22031 #site-elementor-header,
body.page-id-22031 .aux-elementor-header,
body.page-id-22031 #sticky-header,
body.page-id-22031 .aux-sticky-header,
body.page-id-22031 .aux-header {
  display: none !important;
}

body.page-id-22031 #main.aux-main {
  margin-top: 0 !important;
  padding-top: 0 !important;
}

/* ---------------------------------------------------------------------------
   Hide the site-wide theme footer (Chase, 2026-08-06).

   The page carries its own footer — #custom-footer, with the four partner
   logos — so the theme's adds a second, contradictory one underneath.

   2025 does the same thing, but from an inline <style> inside its content HTML
   and via `.elementor-element-a20af26`, the Elementor element id of the footer
   template's one section. That id is generated: edit the footer template in
   Elementor and it can change, at which point the rule silently stops matching
   and a second footer reappears on a page nobody is looking at any more.
   `footer.aux-elementor-footer` is the theme's own wrapper and survives that.
   --------------------------------------------------------------------------- */
body.page-id-22031 footer.aux-elementor-footer {
  display: none !important;
}

/* ---------------------------------------------------------------------------
   The Register button is deliberately dead until EventX is set up
   (Chase, 2026-08-06). The markup is a <span>, not a disabled <a>, so there is
   no href to follow and nothing in the tab order; these rules stop it from
   still *looking* clickable — a button that lifts under the cursor and then
   does nothing reads as a broken form, not as "registration has not opened".
   --------------------------------------------------------------------------- */
.btn-register-main.btn-inactive {
  cursor: default !important;
  opacity: 0.75 !important;
}

.btn-register-main.btn-inactive:hover {
  background: #ffffff !important;
  transform: none !important;
}

/* ---------------------------------------------------------------------------
   Sticky nav bar — navy, not green    (Bunny, 2026-08-07 mockup)

   "最頂bar轉深藍色, 跟下面的底色一樣", the arrow pointing down at the stats
   band. #0E142C is that band's own background, so the bar and the block it
   scrolls over are one colour.

   🚨 The green lives in `assets/code/navigation.css`, which **2025 fetches
   too** — recolouring it there would repaint last year's page as a side
   effect. The override therefore sits here, in the sheet only /2026-
   sustainability-forum/ loads, and is scoped to the page id as well:
   `body.page-id-22031 #green-navigation` is (1,1,1) against the original's
   (1,0,0), so it wins on specificity and does not depend on which of the two
   fetched stylesheets the loader happens to append last.
   --------------------------------------------------------------------------- */
body.page-id-22031 #green-navigation {
  background: #0E142C !important;
}

/* ── Clickable speaker cards ──────────────────────────────────────────────
   Chase, 2026-08-19: 像2025年的那样，打开人的头像，就有一个profile出来.

   Only cursor + focus ring here. The lift on hover is NOT mine — line ~2575
   already gives `.speaker-card:hover` a translateY(-5px), and it applies to
   every card whether or not it has a bio. Two of the sixteen (Yun Fan, Richard
   Wong) are absent from Marketing's sheet and open nothing; if that mismatch
   ever matters, narrow THAT rule to .speaker-card--has-bio rather than adding
   a competing one here. */
.speaker-card--has-bio { cursor: pointer; }
.speaker-card--has-bio:focus-visible {
  outline: 2px solid #b89642;
  outline-offset: 4px;
}
/* Closing the modal focuses the card again for keyboard users. Safari counts
   that programmatic focus() as :focus-visible, Chrome does not — so mouse
   users on a Mac saw the gold ring after every profile (Bunny, 2026-08-21).
   speaker-bio-2026.js adds this class on mouse-opened closes only, and
   removes it on blur; keyboard users keep the ring above. */
.speaker-card--has-bio.bio-refocus-quiet:focus-visible {
  outline: none;
}

/* 🚨 On a phone the bio must scroll as ONE thing. The 2025 rules give
   .bio-modal-right its own overflow-y:auto, which on a 664px viewport left the
   biography a 232px window with no visible affordance — text simply stopped
   mid-sentence. It never showed up in 2025 because that year's speakerData
   shipped `bio: loremIpsum` where loremIpsum = '' — the modal had no body text
   at all. Ours run 484-1878 characters. */
@media (max-width: 768px) {
  .bio-modal-inner {
    max-height: 80vh;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
  }
  .bio-modal-right {
    max-height: none;
    overflow-y: visible;
  }
}
@media (max-width: 480px) {
  .bio-modal-inner { max-height: 75vh; }
}

/* Floating popup panel — stands in for the poster image the 2025 popup used,
   until design supplies a 2026 one. Sized to the .floating-register-popup box
   already declared above (320x139), so swapping an <img> back in needs no
   change here. */
.popup-card {
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 6px;
    height: 100%;
    padding: 18px 22px;
    background: linear-gradient(135deg, #0E142C 0%, #1b2650 100%);
    color: #fff;
    text-decoration: none;
}
/* 🚨 Each line is its own block. As inline spans in a 320px box they reflowed
   into each other — "2026" ended up on the kicker's line and "Register Now"
   wrapped onto the title's (measured 2026-08-20). */
.popup-card > * { display: block; }
.popup-card__kicker {
    font-size: 0.72rem;
    white-space: nowrap;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    opacity: 0.75;
}
.popup-card__title {
    font-size: 1.02rem;
    font-weight: 700;
    line-height: 1.2;
    white-space: nowrap;
}
.popup-card__cta {
    font-size: 0.82rem;
    font-weight: 600;
    color: #C9A227;
}
.popup-card:hover .popup-card__cta { text-decoration: underline; }

