/* ============================================================
   Closing catchphrase band — home, below #start, above the footer.
   Reference: the closing marquee on monday.com. Contract:
   bar-closing-marquee.md. The band carries no background, no
   gradient, no card and no button of its own (client, 2026-10-10).
   ============================================================ */

/* One size drives the band: the phrase and its pictures both read it, so when
   the still layout caps the type (below) the pictures shrink with it.

   §5.3: a plain, un-filled section is 4rem top and bottom, measured to the
   line. The mask below adds its own headroom for the descenders, so the
   section's padding gives that back — the panel-to-line distance stays 4rem
   instead of growing to ~5.2rem. */
.closing {
  /* The type size. At least the jumbo row; above ~1250px it grows with the
     band so that ONE sentence is always 1.32x the band's width — the way
     monday's line overflows the screen (its type is 128px at 1440 and 144px at
     1920). A pause between sentences was tried first and read as a missing item
     (brief critic, round 6: monday keeps one even gap all the way along). The
     growth is a recorded exception in design-system.md §4.1. */
  /* The type size, from two limits and the jumbo row between them:
     - FLOOR: one sentence must be 1.32x the band, so it never sits whole on
       screen (mechanism 1). Above ~1280px this binds and the type grows past
       jumbo — the way monday's does (128px at 1440, 144px at 1920).
     - CEILING: one phrase must fit 80% of the band, so a phone reader can see
       a whole phrase as it passes (brief critic, round 7). Below ~860px this
       binds and the type shrinks — the way monday's does (32px at 390).
     Between them, jumbo. Recorded in design-system.md §4.1. */
  --closing-fs: max(
    calc(1.32 * 100cqi / var(--closing-k)),
    min(var(--fs-jumbo), calc(0.8 * 100cqi / var(--closing-p)))
  );
  --closing-room: calc(var(--closing-fs) * 0.18);
  /* One sentence (phrase, picture, phrase, picture, four gaps) measures exactly
     this many times the type size, at every width — the copy and the pictures
     both scale with --closing-fs. Measured 2026-10-11 on fresh loads at 390,
     1100 and 1440: EN 14.891, KO 14.5816. */
  --closing-k: 14.891;
  /* The longest phrase, in type sizes: EN "A new language." 6.596, KO
     "배우는 언어도," 5.441 (measured 2026-10-11). */
  --closing-p: 6.596;
  /* The disc is 0.68 of the type (mechanism 5), but never smaller than this.
     monday's pictures hardly change size across devices (76px on a phone, 88px
     at 700, 1000 and 1440) while its type runs 32-128px. Ours shrank with the
     type below ~860px — ~32px dots on a phone (brief critic, round 8), and a step
     from 113px to 53px across 640/641 (craft + system, round 9). The floor binds
     only where the phrase ceiling has shrunk the type: 4.3rem sits just under
     0.68 x jumbo (4.352rem), so from ~860px up the disc is 0.68 exactly. ~64px
     at 390, ~67px at 640, ~70px at 860 — one smooth curve, no breakpoint. */
  --closing-disc-min: 4.3rem;
  container-type: inline-size;              /* 100cqi = the band's own width */
  padding-block: calc(var(--sp-40) - var(--closing-room));
}
:lang(ko) .closing { --closing-k: 14.5816; --closing-p: 5.441; }

/* The mask is the full page width and clips the track, so the line is cut by
   the viewport rather than fitted to it (mechanism 1).

   The padding is load-bearing. The §4.1 jumbo row sets line-height 0.9, which
   makes the line box SHORTER than the glyph ink — at 115.5px the ink runs
   105.3px in a 103.96px box. Overflow clips at the padding edge, so without
   this the mask sheared 11.5px off every descender and "language." ended in a
   flat cut instead of a curve (craft critic, 2026-10-10). This buys headroom
   without touching the type row. */
.closing__mask {
  overflow: hidden;
  width: 100%;
  padding-block: var(--closing-room);
}

/* One flex row: phrase, picture, phrase, picture — then the same group again,
   so translating by -50% lands on an identical frame and the loop has no seam
   (mechanism 2). */
/* No `gap` here on purpose. A flex gap sits BETWEEN children, so with an even
   number of children the two halves are not equal and a -50% loop lands half a
   gap out — it measured a 21.76px backward hop every cycle. Each child carries
   its own trailing margin instead, so every repeat is exactly the same width
   and -50% is seamless. */
.closing__track {
  display: flex;
  align-items: center;
  width: max-content;
  will-change: transform;
  /* One sentence every K / 0.84 seconds (~17.7s EN, ~17.4s KO) from ~860px up —
     monday's model, which holds a fixed 20s cycle and lets its speed follow its
     type. Since a sentence there is exactly K type-sizes long, the speed works
     out to 0.84 type-heights per second: 106 px/s at 1440 (monday's own measured
     speed there). Below ~860 see the note after this rule. The track holds
     six sentences and travels three. Pure CSS — nothing to recompute on resize. */
  animation: closing-slide calc(var(--closing-k) * 3s / 0.84) linear infinite;
}
/* 1.6rem against 6.4rem type = 0.25em, the reference's own picture-to-word
   gap. At 2.4rem the clusters started reading as objects set between the words
   rather than as words in the line. */
.closing__track > * { margin-inline-end: calc(var(--closing-fs) * 0.25); }


/* Where the picture floor binds (below ~860px EN, ~690px KO) a sentence is
   longer than K type sizes, so at this one duration the line runs a little
   faster there in type-heights: ~1.0/s on a 390 phone (49 px/s EN, 56 KO)
   against 0.84 on desktop — still under monday's phone band (1.3/s). Stepping
   the duration in bands to hold 0.84 was tried (round 11) and rejected: any
   change of duration keeps the animation's time, so a live resize across a band
   edge threw the line sideways by up to half a sentence (system critic). One
   duration, no bands: speed and position both change smoothly with width. */

@keyframes closing-slide {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}

/* §4.1 jumbo row, as the site sets it (6.4rem / 500 / 0.9 / --kern-headline).
   The reference runs 128px / 1.3 / −0.04em; the size lands inside the bar's
   110–140px band either way, and the house row wins on weight and tracking. */
.closing__phrase {
  font-size: var(--closing-fs);
  font-weight: 500;
  line-height: 0.9;
  letter-spacing: var(--kern-headline);
  color: var(--color--grey-1000);
  white-space: nowrap;
  /* DM Sans's optical-size axis tops out at 40, so at every size this band
     normally sets (40px and up) `auto` already means opsz 40. Below 40px —
     a phone under ~345px — auto switches to the wider text cut and the phrase
     outgrew the 80% ceiling (80.5% at 320; system critic, round 15). Pinning
     40 changes nothing at 40px+ and keeps p constant below it. */
  font-variation-settings: "opsz" 40;
}

/* §4.1.2: Hangul keeps 1.2 / −0.016em at every heading rank. This is the
   largest Hangul on the site, and −0.024em visibly crowds it at that size. */
:lang(ko) .closing__phrase {
  line-height: var(--lh-heading);
  letter-spacing: var(--kern-heading);
}

/* The pictures are words in the sentence: same row, same baseline run, height
   a fixed share of the type so they stay small against it (mechanisms 4, 5). */
/* Both clusters share one canvas: 686x291, a 264px disc with 27px of headroom
   above it, so the characters can stand in front of their circles and still
   line up with the photo circles on one rule. 0.68 of the type is the DISC
   (mechanism 5); the canvas is 291/264 = 1.1023x that. */
.closing__pic {
  display: block;
  height: calc(max(var(--closing-fs) * 0.68, var(--closing-disc-min)) * 1.1023);
  width: auto;
  flex: none;
  /* The canvas carries its headroom above the disc, so centring the BOX leaves
     the disc 4.6% of its own height low against the text. Lift it so the disc's
     centre, not the file's, sits on the line-box centre (mechanism 4). */
  transform: translateY(-4.64%);
}

/* §8 / §10.4: the band is decorative motion, so it stops outright when the
   reader asks for less. Stopping the track alone left a still frame that cut
   "A new language." mid-word at every width (630px of phrase in a 390px mask).
   So the still state is its own layout: the repeats go, and the one live group
   wraps and centres inside the page, the sentence whole. */
@media (prefers-reduced-motion: reduce) {
  /* The growth above exists to keep a MOVING line overflowing; a still layout
     wraps instead, so it keeps the plain jumbo row. */
  .closing { --closing-fs: var(--fs-jumbo); }
  /* The still layout was tuned at the plain 0.68 disc; the picture floor above
     is for a moving line. */
  .closing { --closing-disc-min: 0px; }
  .closing__track {
    animation: none;
    transform: none;
    width: auto;
    flex-wrap: wrap;
    justify-content: center;
    row-gap: var(--sp-16);
    padding-inline: var(--sp-16);
  }
  .closing__track > [aria-hidden="true"] { display: none; }
  /* The marquee's trailing margins only exist to keep the loop seamless; in the
     still layout they would narrow the column, so the row spaces with a gap. */
  .closing__track > * { margin-inline-end: 0; }
  .closing__track { column-gap: var(--sp-16); }
  .closing__phrase { white-space: normal; text-align: center; overflow-wrap: break-word; }

  /* Two composed states, never a free wrap. A plain flex wrap reflowed into
     ragged rows at ~630-880px — the people cluster sat beside "Your way." and
     the characters fell to a row of their own (craft critic, round 13).
     - Narrow: one centred column — phrase, its picture, phrase, its picture.
     - Wide, once "A new language. [people]" fits on one row: two centred
       rows, each phrase with its own picture. A zero-height ::before ordered
       between the pairs forces the break; each of its two row gaps is half a
       step, so the rows sit one --sp-16 apart.
     The width is the band's own (container query), so a scrollbar cannot tip
     it: EN needs ~956px of band at jumbo, KO ~812 — set at 1000 / 860. */
  .closing__track { flex-direction: column; align-items: center; row-gap: var(--sp-8); }
  /* In the column, pairing is carried by distance, not just order: a phrase
     sits 0.8rem over its own picture and 3.2rem clear of the next phrase
     (craft critic, round 14: one even gap read as four separate items). */
  .closing__track > :nth-child(2) { margin-block-end: var(--sp-24); }
  /* The lift that centres a disc on a moving line has no line to centre on
     in the column; left on, it pulled each picture ~3px toward its phrase and
     off the --sp-8 / --sp-24 rhythm (system critic, round 15). */
  .closing__pic { transform: none; }
  @container (min-width: 1000px) {
    :lang(en) .closing__track { flex-direction: row; row-gap: calc(var(--sp-16) / 2); }
    :lang(en) .closing__track::before { content: ""; order: 2; flex-basis: 100%; height: 0; }
    :lang(en) .closing__track > :nth-child(-n+2) { order: 1; }
    :lang(en) .closing__track > :nth-child(2) { margin-block-end: 0; }
    :lang(en) .closing__pic { transform: translateY(-4.64%); }
    :lang(en) .closing__track > :nth-child(n+3) { order: 3; }
  }
  @container (min-width: 860px) {
    :lang(ko) .closing__track { flex-direction: row; row-gap: calc(var(--sp-16) / 2); }
    :lang(ko) .closing__track::before { content: ""; order: 2; flex-basis: 100%; height: 0; }
    :lang(ko) .closing__track > :nth-child(-n+2) { order: 1; }
    :lang(ko) .closing__track > :nth-child(2) { margin-block-end: 0; }
    :lang(ko) .closing__pic { transform: translateY(-4.64%); }
    :lang(ko) .closing__track > :nth-child(n+3) { order: 3; }
  }
}

/* "language." is 3.86em wide, and at 6.4rem it outgrows the still layout's
   column on every phone (374px in ~342px at 390; clipped to "anguage." at 360).
   Hyphenating it per §4.2.1 kept it on screen but still split the word, which a
   critic called the same defect (round 3). So on narrow screens the still
   layout caps the size until the longest word fits, on the terms of §9.3.2's
   width-fit clamp (binds only where jumbo itself would not fit, below ~428px).
   Recorded as an exception under §4.2.1. The pictures read the same size, so
   they shrink with the type rather than outgrowing it. 3.95em leaves a hair of
   room over the measured 3.86em; hyphens: auto stays as §4.2.1's fallback and
   does not fire on this copy. */
@media (prefers-reduced-motion: reduce) and (max-width: 640px) {
  .closing:lang(en) {
    /* 100cqi, not 100vw: the column is the band minus its gutters, and a
       desktop scrollbar takes 15px of the viewport but none of the band. At
       100vw "language." split as "lang- / uage." at 320-440 whenever a
       scrollbar showed (system critic, round 12). */
    --closing-fs: min(var(--fs-jumbo), calc((100cqi - 2 * var(--sp-16)) / 3.95));
  }
  :lang(en) .closing__phrase { hyphens: auto; }
  /* Korean never splits a word (keep-all), but at jumbo each phrase broke onto
     two lines and the still column ran 793px on a 390 phone — taller than the
     screen (craft critic, round 14). The same width-fit cap, sized to the
     longer phrase (5.441em, with a hair of room), keeps each on one line. */
  .closing:lang(ko) {
    --closing-fs: min(var(--fs-jumbo), calc((100cqi - 2 * var(--sp-16)) / 5.5));
  }
}
