img{
    height: auto;
}

/* ---------------------------------------------------------------------------
   Traditional Chinese navigation

   The design sizes every nav item at a fixed 16.6667% — one sixth of the row —
   which fits the English labels but not the Chinese ones: 我們的活動 and
   我們的伙伴 are wide enough to wrap onto a second line.

   Above the mobile breakpoint, let each item size to its own text instead and
   give the row more room between items. Only zh-hant is touched, so the English
   nav keeps the designer's even six-column rhythm.

   Below 992px the nav collapses into the full-width dropdown, where the labels
   already have a whole row each — that layout is left alone.
   --------------------------------------------------------------------------- */
@media screen and (min-width: 992px) {
    html[lang="zh-hant"] .nav-wrap {
        grid-column-gap: 20px;
        grid-row-gap: 20px;
    }

    html[lang="zh-hant"] .nav-link {
        width: auto;
        flex: 0 0 auto;
        white-space: nowrap;
    }
}

@media screen and (min-width: 1280px) {
    html[lang="zh-hant"] .nav-wrap {
        grid-column-gap: 30px;
        grid-row-gap: 30px;
    }
}

/* ---------------------------------------------------------------------------
   The Programme Details pillar cards flip on hover

   The export gave each `.recognize-area-card-container` a data-w-id and two IX2
   events — MOUSE_OVER runs a-7 (rotateY -180deg over 500ms), MOUSE_OUT runs a-8
   (back to 0). Both are `useEventTarget: true`, so **the element IX2 rotates is
   the element it takes the hover from**, and that is the whole bug: a rotated
   box is hit-tested on its projected quad, which is only `cos θ` as wide.

   Half a card is 270px, so a pointer 20px inside the edge is 250px off centre
   and falls outside the card as soon as it has turned 22° — about 60ms in. That
   fires MOUSE_OUT, a-8 rotates it back under the pointer, MOUSE_OVER fires
   again, and the card sits there juddering a few degrees off true. Dead centre
   it never happens, which is why it looks like it works.

   So the trigger and the transform are split onto two elements. The container
   is a plain, untransformed box the pointer can never fall out of — its rect is
   exactly the card's, the two faces being `inset: 0` and `position: relative`
   inside it — and the rotation moves to `-flip`, which nothing hit-tests.
   Hovering the very edge now flips the card once, all the way, every time.

   `transform-style: preserve-3d` is what makes the two `backface-visibility:
   hidden` faces swap over at 90°. IX2 rotated a `flat` container, which
   flattens its children into one plane before turning it, and a flattened face
   has no backface to hide — the front simply came round mirrored. No
   `perspective`: the designer's flip has none, so it stays an orthographic
   turn rather than gaining a depth cue that was never drawn.

   The 500ms and the ease are a-7's own. As a CSS transition it also runs on the
   compositor instead of a per-frame rAF write, so it is smoother than what it
   replaces — and it cannot be interrupted halfway by its own geometry.
   --------------------------------------------------------------------------- */
.recognize-area-card-flip {
    height: 100%;
    position: relative;
    transform-style: preserve-3d;
    transition: transform 500ms ease-in-out;
}

.recognize-area-card-container:hover .recognize-area-card-flip {
    transform: rotateX(0) rotateY(-180deg) rotateZ(0);
}

/* ---------------------------------------------------------------------------
   Lists on the back of the Programme Details pillar cards

   In the export the card backs are hand-written markup: a `.common-list.bullet`
   holding `.common-list-item.bullet` (disc) on card 1 and `.common-list-item.num`
   (decimal) on card 2. That text is a CMS editor field now, so the admin's
   rich-text output is a plain <ul>/<ol> with none of those classes — and the
   editor has no way to add them.

   Match the design's spacing here instead: the tighter 15px indent and 5px row
   gap the designer used, and real disc / decimal markers, so a numbered list
   entered in the admin still reads as one. The 10px bottom margin lines the
   block up with `.recognize-area-card-back-b`, which is what separates the
   hand-written blocks in the export.
   --------------------------------------------------------------------------- */
.recognize-area-card-back ul,
.recognize-area-card-back ol {
    margin-top: 0;
    margin-bottom: 10px;
    padding-left: 15px;
}

.recognize-area-card-back ul {
    list-style-type: disc;
}

.recognize-area-card-back ol {
    list-style-type: decimal;
}

.recognize-area-card-back li + li {
    margin-top: 5px;
}

/* ---------------------------------------------------------------------------
   Our Activities — Load More

   Every card is in the page from the start; the ones past the first batch are
   marked here and revealed by the button. Hidden server-side rather than by
   script so the list never flashes at full length, and so the page still reads
   as the designed four with JavaScript off.
   --------------------------------------------------------------------------- */
.activities-list-col.is-hidden {
    display: none;
}

/* The export's featured media is always a YouTube embed, which brings its own
   16:9 box. An uploaded image has to be told to fill the same width. */
.detail-big-video-b img {
    width: 100%;
    display: block;
}

/* ---------------------------------------------------------------------------
   The icon rows on an activity's highlight block

   In the export the "Details" block is hand-written markup: an
   `.assembly-detail-list` of `.assembly-detail-list-wrap` rows, each with its own
   `.assembly-detail-list-icon` — a calendar, a clock, then a pin. That text is a
   CMS editor field now, so the admin's rich-text output is a plain <ul> with no
   icons available to it.

   A list typed into that field is restyled here to match: the design's 5px row
   gap, and the three icons by position, cycling if a fourth row is added. The
   25px indent is the export's 15px icon plus its 10px gap. Ordinary paragraphs
   in the same field are untouched, so a block that is only prose still reads as
   the designer drew it.
   --------------------------------------------------------------------------- */
.assembly-detail-b .subtitle-content ul {
    grid-row-gap: 5px;
    flex-flow: column;
    margin: 0;
    padding: 0;
    list-style: none;
    display: flex;
}

.assembly-detail-b .subtitle-content ul li {
    min-height: 17px;
    padding-left: 25px;
    background-position: 0 2px;
    background-repeat: no-repeat;
    background-size: 15px;
}

.assembly-detail-b .subtitle-content ul li:nth-child(3n + 1) {
    background-image: url('../images/assembly-detail-list-icon01.svg');
}

.assembly-detail-b .subtitle-content ul li:nth-child(3n + 2) {
    background-image: url('../images/assembly-detail-list-icon02.svg');
}

.assembly-detail-b .subtitle-content ul li:nth-child(3n + 3) {
    background-image: url('../images/assembly-detail-list-icon03.svg');
}

/* The right-hand image sits in a 5px frame, so it has to fill it exactly. */
.assembly-detail-img-b > img {
    width: 100%;
    display: block;
}

/* ---------------------------------------------------------------------------
   An activity's video grid on a phone

   `.detail-video-wrap` and `.activities-list-wrap` are the same grid — two 50%
   columns of identical cards — but the export only ever narrows the listing one:
   `.activities-list-col` goes to 80% centred at 767px and 100% at 479px, while
   `.detail-video-col` is left at 50% at every width and only its font size is
   touched. Two 16:9 players side by side on a phone are too small to watch, so
   the same two steps are applied here.

   Kept identical to the designer's own values rather than picked fresh, so the
   two grids break at the same points and read as one component.
   --------------------------------------------------------------------------- */
@media screen and (max-width: 767px) {
    .detail-video-wrap {
        justify-content: center;
    }

    .detail-video-col {
        width: 80%;
    }
}

@media screen and (max-width: 479px) {
    .detail-video-col {
        width: 100%;
    }
}

/* ---------------------------------------------------------------------------
   One video on its own fills the row

   `.detail-video-col` is a fixed 50% — the designed pair — so a section with a
   single video would leave half the notebook empty beside it. The blade marks a
   one-row grid `is-single` and it takes the whole width. Higher specificity than
   the two steps above, so it stays full width at every size, which is where
   those steps were heading anyway.
   --------------------------------------------------------------------------- */
.detail-video-wrap.is-single .detail-video-col {
    width: 100%;
}

/* ---------------------------------------------------------------------------
   The video card hover

   IX2's img-hover (a-5 / a-6) scaled a card's `.img-cover` to 1.1 over 300ms on
   easeInOut. Its events belong to activities-detail-01, and IX2 events are
   page-scoped — the merged activity page declares activities-detail-02 instead,
   so the button hover survives and these cannot fire. See the note at the top of
   frontend/activity_detail.blade.php.

   The same scale on the same curve, in CSS. `.detail-video-list-img` clips it,
   exactly as it did when IX2 wrote the transform.
   --------------------------------------------------------------------------- */
.detail-video-list-b .img-cover {
    transition: transform 300ms ease-in-out;
}

.detail-video-list-b:hover .img-cover {
    transform: scale(1.1);
}

/* ---------------------------------------------------------------------------
   A partner with no photos yet

   `.partners-col` is a fixed `calc(50% - 20px)`, so a partner whose slider is
   empty — the blade drops the binder and the slider column with it — would
   leave the text stranded in half a notebook. Widen the one remaining column
   to fill it. The designed two-column case is untouched: `:only-child` cannot
   match while the slider is there, and below 992px the export already sets
   every column to 100%.
   --------------------------------------------------------------------------- */
.partners-wrap > .partners-col:only-child {
    width: 100%;
}

/* ---------------------------------------------------------------------------
   Descenders in a split heading

   IX3 splits a heading into letters through GSAP SplitText with `mask`, which
   wraps every letter in a clone of itself — `.gsap_split_letter-mask` — and
   sets `overflow: clip` on it *inline*. The wrapper is only as tall as the
   letter's line box, and every heading on the site is `line-height: 110%`, so
   anything hanging below the baseline is cut off: the g of "Participating
   Schools" in the banner, and the same in every other split heading.

   The mask exists to hide the letters while they slide down into place, so
   dropping it means a letter is faintly visible above its slot mid-reveal —
   it fades in as it travels, so the worst-positioned frame is also the most
   transparent one. `!important` is needed because SplitText writes the
   property onto the element itself.
   --------------------------------------------------------------------------- */
.gsap_split_letter-mask {
    overflow: visible !important;
}
