/*
 * Gloss homepage.
 * Palette and type mirror the app's editorial theme (components/review/theme.ts):
 * Newsreader for display, Inter for body, Space Grotesk for letterspaced kickers.
 */

:root {
  --bg: #121212;
  --paper: #1a1a1a;
  --paper-2: #1e1e1e;
  --paper-3: #202020;
  --rule: #3f3f3f;
  --rule-faint: #2a2a2a;
  --ink: #ece9e4;
  --ink-dim: #b9b4ad;
  --ink-faint: #9f988f;
  /* Reader unit states, taken from the app's dark reader palette in
     app/reader/[bookId].tsx: a unit is plain until it is selected, saved, or
     currently being spoken during sentence playback. */
  --unit-selected: #3c3c3c;
  --unit-selected-fg: #f0ece7;
  --unit-saved: #353434;
  --unit-speaking: #544327;
  --unit-speaking-selected: #3f3d39;
  --ok: #c9d6b8;
  --bad: #d7a29a;

  --serif: 'Newsreader', Georgia, 'Times New Roman', serif;
  --sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --grotesk: 'Space Grotesk', 'Inter', sans-serif;

  --shell: 1200px;
  --gutter: clamp(20px, 5vw, 64px);
  --section-y: clamp(72px, 11vw, 148px);
}

*,
*::before,
*::after { box-sizing: border-box; }

html {
  scroll-padding-top: 72px;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

img { display: block; max-width: 100%; }

a { color: inherit; text-decoration: none; }

button {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  cursor: pointer;
}

:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
}

.shell {
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  padding: 12px 18px;
  background: var(--ink);
  color: var(--bg);
  font-family: var(--grotesk);
  font-size: 11px;
  letter-spacing: 2px;
  text-transform: uppercase;
}
.skip:focus { left: 12px; top: 12px; }

/* ── Shared type ──────────────────────────────────────────── */

.kicker {
  margin: 0;
  font-family: var(--grotesk);
  font-weight: 700;
  font-size: 10px;
  letter-spacing: 3.2px;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.tiny {
  margin: 0;
  font-family: var(--grotesk);
  font-weight: 700;
  font-size: 9px;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.display {
  margin: 0;
  font-family: var(--serif);
  font-weight: 300;
  font-size: clamp(46px, 7.4vw, 92px);
  line-height: 1.03;
  letter-spacing: -0.03em;
}
.display em {
  font-style: italic;
  color: var(--ink-dim);
}
.display--2 { font-size: clamp(36px, 5.4vw, 66px); }

.lede {
  margin: 24px 0 0;
  max-width: 52ch;
  font-size: clamp(16px, 1.5vw, 19px);
  line-height: 1.62;
  color: var(--ink-dim);
}
.lede em { font-style: italic; color: var(--ink); }

/* ── Buttons ──────────────────────────────────────────────── */

.btn {
  display: inline-flex;
  align-items: center;
  gap: 11px;
  padding: 13px 22px;
  border: 1px solid var(--rule);
  font-family: var(--grotesk);
  font-weight: 700;
  transition: background-color .2s ease, color .2s ease, border-color .2s ease;
}

.btn__apple {
  width: 19px;
  height: 22px;
  flex: none;
  fill: currentColor;
}

.btn__stack {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  line-height: 1.15;
  font-size: 16px;
  letter-spacing: 0.2px;
}
.btn__stack small {
  font-family: var(--sans);
  font-weight: 400;
  font-size: 10px;
  letter-spacing: 0.6px;
  opacity: .72;
}

.btn--filled {
  background: var(--ink);
  color: var(--bg);
  border-color: var(--ink);
}
.btn--filled:hover { background: #fff; border-color: #fff; }

.btn--small {
  padding: 9px 16px;
  font-size: 10px;
  letter-spacing: 2.2px;
  text-transform: uppercase;
  white-space: nowrap;
  flex-shrink: 0;
}
.btn--small .btn__apple { width: 13px; height: 15px; }
.btn--small:hover { background: var(--ink); color: var(--bg); border-color: var(--ink); }

/* ── Nav ──────────────────────────────────────────────────── */

.nav {
  position: sticky;
  top: 0;
  z-index: 50;
  border-bottom: 1px solid transparent;
  transition: background-color .3s ease, border-color .3s ease;
}
.nav.is-stuck {
  background: rgba(18, 18, 18, .86);
  backdrop-filter: blur(14px);
  border-bottom-color: var(--rule-faint);
}

.nav__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  min-height: 72px;
}

.nav__brand {
  display: flex;
  align-items: center;
  gap: 11px;
}
.nav__mark {
  width: 30px;
  height: 30px;
  border: 1px solid var(--rule-faint);
}
.nav__word {
  margin: 0;
  font-family: var(--grotesk);
  font-weight: 700;
  font-size: 15px;
  letter-spacing: 5px;
}

.nav__links {
  display: none;
  gap: 32px;
  font-family: var(--grotesk);
  font-size: 12px;
  letter-spacing: 1.4px;
  color: var(--ink-dim);
}
@media (min-width: 900px) {
  .nav__links { display: flex; }
}
.nav__links a { padding-block: 6px; }
.nav__links a:hover { color: var(--ink); }

/* ── Language switcher ────────────────────────────────────────
   Two words rather than a flag: a language is not a country, and Spanish
   here is the reader's own language, not a region. */
.lang {
  display: flex;
  align-items: center;
  gap: 1px;
  font-family: var(--grotesk);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 1.6px;
}
.lang__opt {
  padding: 5px 9px;
  color: var(--ink-faint);
  border: 1px solid transparent;
  transition: color .18s ease, border-color .18s ease;
}
.lang__opt:hover { color: var(--ink); }
.lang__opt.is-on {
  color: var(--ink);
  border-color: var(--rule);
  cursor: default;
}

/* ── Hero ─────────────────────────────────────────────────── */

.hero {
  padding-block: clamp(48px, 8vw, 104px) var(--section-y);
}

.hero__grid {
  display: grid;
  grid-template-columns: minmax(0, 1.18fr) minmax(0, .82fr);
  gap: clamp(40px, 6vw, 88px);
  align-items: center;
}

/* Sized so "Learn Spanish by" holds one line at every width. */
.hero__title {
  margin-top: 22px;
  font-size: clamp(42px, 5.6vw, 76px);
}

.hero__actions {
  display: flex;
  align-items: center;
  gap: 20px;
  flex-wrap: wrap;
  margin-top: 38px;
}
.hero__note {
  margin: 0;
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--ink-faint);
}

.slashes {
  list-style: none;
  margin: 46px 0 0;
  padding: 0;
  border-top: 1px solid var(--rule-faint);
}
.slashes li {
  position: relative;
  padding: 14px 0 14px 30px;
  border-bottom: 1px solid var(--rule-faint);
  font-size: 14.5px;
  color: var(--ink-dim);
}
.slashes li::before {
  content: '/';
  position: absolute;
  left: 0;
  font-family: var(--grotesk);
  color: var(--ink-faint);
}

/* ── Phone + reader demo ──────────────────────────────────── */

.hero__demo {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
}
.hero__demo-note {
  margin: 0;
  max-width: 34ch;
  text-align: center;
  font-size: 12px;
  line-height: 1.6;
  color: var(--ink-faint);
}
.hero__demo-note em { font-style: italic; }

.phone {
  position: relative;
  width: min(100%, 372px);
  border: 1px solid var(--rule);
  background: var(--paper);
  box-shadow: 0 40px 90px -50px rgba(0, 0, 0, .9);
}

.phone__screen {
  position: relative;
  padding: 26px 24px 24px;
  /* Tall enough that all three sentences still clear the tallest word sheet
     (363px, on the units with the most alternatives) with room to spare. */
  min-height: 700px;
  overflow: hidden;
}

.reader__bar {
  display: flex;
  justify-content: space-between;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--rule-faint);
}

.reader__hint {
  margin: 16px 0 0;
  font-family: var(--grotesk);
  font-size: 9px;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--ink-faint);
  transition: opacity .3s ease;
}
/* Fades out but keeps its space, so opening the sheet doesn't jolt the text. */
.reader__hint.is-gone { opacity: 0; visibility: hidden; }

.reader__text {
  margin: 14px 0 0;
  font-family: var(--serif);
  font-weight: 400;
  font-size: 19px;
  line-height: 1.66;
  color: var(--ink);
}
/* Every word is a tap target, as in the reader, where only punctuation and
   the spaces between units are left untappable. Nothing is pre-highlighted:
   a word stays plain until it is selected, saved or spoken. Padding would
   widen words and break the line's rhythm, so highlights are drawn with a
   box-shadow spread instead. */
.kw {
  padding: 0;
  font: inherit;
  color: inherit;
  transition: background-color .18s ease, box-shadow .18s ease, color .18s ease;
}
.kw:hover {
  background: var(--paper-3);
  box-shadow: 0 0 0 3px var(--paper-3);
}
/* Source order sets the precedence the reader uses: spoken beats selected,
   and selected beats saved. */
.kw.is-saved {
  background: var(--unit-saved);
  box-shadow: 0 0 0 2.5px var(--unit-saved);
}
.kw.is-selected {
  background: var(--unit-selected);
  color: var(--unit-selected-fg);
  box-shadow: 0 0 0 2.5px var(--unit-selected);
}
.kw.is-speaking {
  background: var(--unit-speaking);
  box-shadow: 0 0 0 2.5px var(--unit-speaking);
}
.kw.is-speaking.is-selected {
  background: var(--unit-speaking-selected);
  color: var(--unit-selected-fg);
  box-shadow: 0 0 0 2.5px var(--unit-speaking-selected);
}

/* The sentence the sheet is describing picks up a faint underline. Buttons
   don't inherit text-decoration, so the rule is drawn twice at the same
   offset — once for the spaces and punctuation, once for the words — which
   reads as one continuous line. */
.reader__text.is-reading,
.reader__text.is-reading .kw {
  text-decoration: underline;
  text-decoration-color: var(--unit-selected);
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
}
.reader__text.is-reading .kw.is-speaking { text-decoration-color: var(--unit-speaking); }

/* Word sheet: slides up over the page, as it does in the app. */
.sheet {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 14px 18px 16px;
  background: var(--paper-2);
  border-top: 1px solid var(--rule);
  animation: sheet-up .34s cubic-bezier(.16, 1, .3, 1);
}
.sheet[hidden] { display: none; }
/* Softens the cut between the page and the sheet sitting over it. */
.sheet::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 100%;
  height: 44px;
  background: linear-gradient(to top, var(--paper), rgba(26, 26, 26, 0));
  pointer-events: none;
}

@keyframes sheet-up {
  from { transform: translateY(18px); opacity: 0; }
  to { transform: none; opacity: 1; }
}

.sheet__grip {
  width: 34px;
  height: 3px;
  margin: 0 auto 14px;
  background: var(--rule);
}

.sheet__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 14px;
  padding-bottom: 13px;
  border-bottom: 1px solid var(--rule-faint);
}
.sheet__span {
  margin: 6px 0 0;
  font-family: var(--serif);
  font-size: 25px;
  line-height: 1.15;
}
.sheet__ipa {
  margin: 3px 0 0;
  font-size: 12px;
  color: var(--ink-faint);
}

.sheet__tools { display: flex; gap: 8px; flex: none; }

.icon {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border: 1px solid var(--rule);
  transition: background-color .18s ease, color .18s ease;
}
.icon svg { width: 16px; height: 16px; fill: currentColor; }
.icon:hover:not(:disabled) { background: var(--paper-3); }
.icon[aria-pressed='true'] { background: var(--ok); border-color: var(--ok); color: var(--bg); }
.icon.is-playing { background: var(--ink); border-color: var(--ink); color: var(--bg); }
.icon:disabled { opacity: .35; cursor: not-allowed; }

/* ── Audio nudge ──────────────────────────────────────────────
   A ring breathes out of whichever audio control comes next, until both have
   been used once. The app draws its own play buttons with a halo, so this
   borrows that idea rather than inventing a badge. */
.icon.is-nudge,
.linky.is-nudge { position: relative; }
.icon.is-nudge::after,
.linky.is-nudge::after {
  content: '';
  position: absolute;
  inset: -4px;
  border: 1px solid var(--ink);
  opacity: 0;
  pointer-events: none;
  animation: nudge 2s ease-out infinite;
}
.linky.is-nudge { color: var(--ink); }

/* The same ring around a phrase in the text, so the first tap has a target.
   Drawn on a pseudo-element rather than the word, which would shift the line. */
.kw.is-nudge { position: relative; }
.kw.is-nudge::after {
  content: '';
  position: absolute;
  inset: -2px -4px;
  border: 1px solid var(--ink);
  opacity: 0;
  pointer-events: none;
  animation: nudge 2s ease-out infinite;
}

@keyframes nudge {
  0% { opacity: .55; transform: scale(1); }
  65%, 100% { opacity: 0; transform: scale(1.32); }
}

.sheet__rows { margin: 0; }
.sheet__row {
  display: grid;
  grid-template-columns: 74px minmax(0, 1fr);
  gap: 12px;
  align-items: baseline;
  padding: 10px 0;
  border-bottom: 1px solid var(--rule-faint);
}
.sheet__row:last-child { border-bottom: 0; }
.sheet__row dd { margin: 0; font-size: 14.5px; }
.sheet__row dt { padding-top: 3px; }

.sheet__sentence {
  font-family: var(--serif);
  font-style: italic;
  font-size: 14px;
  line-height: 1.5;
  color: var(--ink-dim);
}

.chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.chips span {
  padding: 3px 9px;
  border: 1px solid var(--rule);
  border-radius: 999px;
  font-size: 11.5px;
  color: var(--ink-dim);
}

/* Translation note: the app's own grammar explanation for the unit, collapsed
   by default so opening a new unit doesn't change the sheet's height. The
   notes run to a couple of hundred words, so main.js trims the text to an
   excerpt. Cutting the text rather than clipping the box means no line is
   ever sliced in half, at any width. */
.sheet__note {
  margin-top: 11px;
  padding: 11px 12px;
  background: var(--paper-3);
  border: 1px solid var(--rule-faint);
  font-size: 13px;
  line-height: 1.62;
  color: var(--ink-dim);
}
.sheet__note strong { font-weight: 600; color: var(--ink); }

.sheet__foot {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px 18px;
  margin-top: 10px;
  padding-top: 11px;
  border-top: 1px solid var(--rule-faint);
}

.linky {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 3px 0;
  font-family: var(--grotesk);
  font-weight: 700;
  font-size: 9px;
  letter-spacing: 1.8px;
  text-transform: uppercase;
  color: var(--ink-dim);
  transition: color .18s ease;
}
.linky svg { width: 11px; height: 11px; fill: currentColor; }
.linky:hover:not(:disabled),
.linky.is-playing { color: var(--ink); }
.linky:disabled { opacity: .35; cursor: not-allowed; }

.sheet__saved {
  margin: 0 0 0 auto;
  font-family: var(--grotesk);
  font-size: 9px;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--ok);
}

/* ── Stats band ───────────────────────────────────────────── */

.band {
  padding-block: clamp(52px, 7vw, 88px);
  border-top: 1px solid var(--rule-faint);
  border-bottom: 1px solid var(--rule-faint);
  background: var(--paper);
}

.band__kicker {
  text-align: center;
  margin-bottom: 44px;
}

.band__grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 1px;
  background: var(--rule-faint);
  border: 1px solid var(--rule-faint);
}

.stat {
  padding: 34px 26px;
  background: var(--paper);
  text-align: center;
}
.stat__num {
  margin: 0;
  font-family: var(--serif);
  font-weight: 300;
  font-size: clamp(52px, 6vw, 78px);
  line-height: 1;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
}
.stat__label {
  margin: 14px auto 0;
  max-width: 18ch;
  font-family: var(--grotesk);
  font-size: 10px;
  letter-spacing: 1.8px;
  text-transform: uppercase;
  line-height: 1.7;
  color: var(--ink-faint);
}

/* ── Sections ─────────────────────────────────────────────── */

.section { padding-block: var(--section-y); }
.section--rule { border-top: 1px solid var(--rule-faint); }

.section__head { margin-bottom: clamp(44px, 6vw, 76px); }
.section__head .display { margin-top: 20px; }

/* ── Review games ─────────────────────────────────────────────
   A self-advancing showcase. The track slides one card at a time; the live
   card is lit and its mock animates, the rest sit back dimmed. Nothing is
   clickable, so there is no focus or keyboard handling here — under reduced
   motion the whole thing becomes a static grid (see the media query below).
*/

.games__viewport {
  overflow: hidden;
  /* Let the card shadows and lit edges breathe without being clipped. */
  margin: 0 -4px;
  padding: 4px;
}

.games__track {
  display: flex;
  gap: 22px;
  margin: 0;
  padding: 0;
  list-style: none;
  transition: transform .72s cubic-bezier(.16, 1, .3, 1);
}

.gcard {
  /* Sized so three cards sit in the frame with a clear slice of the fourth
     showing, rather than a sliver — the 66px is the three gaps. */
  flex: 0 0 clamp(280px, calc((100% - 66px) / 3.4), 380px);
  display: flex;
  flex-direction: column;
  background: var(--paper);
  border: 1px solid var(--rule-faint);
  opacity: .34;
  transition: opacity .5s ease, border-color .5s ease;
}
.gcard.is-live {
  opacity: 1;
  border-color: var(--rule);
}

.gcard__tags {
  margin: 18px 18px 0;
  font-family: var(--grotesk);
  font-weight: 700;
  font-size: 9px;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.gcard__title {
  margin: 9px 18px 0;
  font-family: var(--serif);
  font-weight: 300;
  font-size: 25px;
  line-height: 1.14;
  letter-spacing: -0.01em;
}
.gcard__note {
  margin: 9px 18px 20px;
  font-size: 14px;
  line-height: 1.58;
  color: var(--ink-dim);
}

/* The mock sits on the app's page colour so it reads as a screen. The stage
   is a fixed height so every card matches, and the contents are centred
   because each game fills a different amount of it. */
.gstage {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: center;
  height: 232px;
  padding: 15px 16px;
  overflow: hidden;
  background: var(--bg);
  border-bottom: 1px solid var(--rule-faint);
}
.gstage__head {
  margin: 0 0 9px;
  font-family: var(--grotesk);
  font-weight: 700;
  font-size: 8px;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.gstage__meta {
  margin: 0;
  font-family: var(--grotesk);
  font-size: 8.5px;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--ink-faint);
}

/* Shared mock primitives, matching the games' own chrome. */
.gbox {
  display: block;
  padding: 7px 9px;
  background: var(--paper);
  border: 1px solid var(--rule-faint);
  font-size: 12.5px;
  color: var(--ink);
}
.gbox--es,
.gopts--es li,
.bank__line,
.scan__chips span,
.mcard__face--es,
.mm__es { font-family: var(--serif); font-style: italic; }

.gslots,
.gtiles {
  display: flex;
  gap: 5px;
}
.gslots { margin-bottom: 14px; }
.gslots span {
  flex: 1 1 0;
  min-width: 0;
  padding-bottom: 4px;
  border-bottom: 1px solid var(--rule);
  font-family: var(--serif);
  font-size: 17px;
  text-align: center;
  color: var(--ink);
}
.gtiles { flex-wrap: wrap; }
.gtiles span {
  display: grid;
  place-items: center;
  width: 27px;
  height: 30px;
  background: var(--paper-2);
  border: 1px solid var(--rule);
  font-family: var(--serif);
  font-size: 15px;
}
.gtiles--words span {
  width: auto;
  height: auto;
  padding: 5px 8px;
  font-style: italic;
  font-size: 13px;
}

.gspeaker {
  position: relative;
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: 28px;
  height: 28px;
  border: 1px solid var(--rule);
  color: var(--ink);
}
.gspeaker svg { width: 13px; height: 13px; fill: currentColor; }
/* Ring that pulses out while the clip plays. */
.gspeaker::after {
  content: '';
  position: absolute;
  inset: -1px;
  border: 1px solid var(--ink);
  opacity: 0;
}

.gopts {
  margin: 0;
  padding: 0;
  list-style: none;
}
.gopts li {
  display: flex;
  gap: 7px;
  padding: 6px 0;
  border-bottom: 1px solid var(--rule-faint);
  font-size: 12.5px;
  color: var(--ink);
}
.gopts li:last-child { border-bottom: 0; }
.gopts b {
  font-family: var(--grotesk);
  font-weight: 400;
  font-size: 10px;
  color: var(--ink-faint);
}

/* ── 1 · Pair the boxes ── */
.gstage--pair {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  align-content: center;
  gap: 10px;
}
.pair__col { display: grid; gap: 8px; align-content: start; }

/* The three pairs share one timeline and resolve in turn, so the board fills
   up over the cycle instead of solving all at once. Each pair lights up as
   it is picked, then locks into the solved state and holds it.
   The percentages are the only difference between these three. */
.gcard.is-live .pair--a { animation: pair-a 5s infinite; }
.gcard.is-live .pair--b { animation: pair-b 5s infinite; }
.gcard.is-live .pair--c { animation: pair-c 5s infinite; }
@keyframes pair-a {
  0%, 10% { border-color: var(--rule-faint); color: var(--ink); }
  15%, 19% { border-color: var(--ink); background: var(--paper-2); color: var(--ink); }
  24%, 100% { border-color: var(--ok); color: var(--ink-faint); text-decoration: line-through; opacity: .55; }
}
@keyframes pair-b {
  0%, 38% { border-color: var(--rule-faint); color: var(--ink); }
  43%, 47% { border-color: var(--ink); background: var(--paper-2); color: var(--ink); }
  52%, 100% { border-color: var(--ok); color: var(--ink-faint); text-decoration: line-through; opacity: .55; }
}
@keyframes pair-c {
  0%, 66% { border-color: var(--rule-faint); color: var(--ink); }
  71%, 75% { border-color: var(--ink); background: var(--paper-2); color: var(--ink); }
  80%, 100% { border-color: var(--ok); color: var(--ink-faint); text-decoration: line-through; opacity: .55; }
}

/* ── 2 · Memory, flipped ── */
.mem__grid {
  flex: 1;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 7px;
}
.mcard {
  position: relative;
  transform-style: preserve-3d;
}
.mcard__back,
.mcard__face {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  padding: 3px;
  background: var(--paper);
  border: 1px solid var(--rule);
  backface-visibility: hidden;
  font-size: 11px;
  font-style: normal;
  line-height: 1.2;
  text-align: center;
  color: var(--ink);
}
.mcard__back {
  font-family: var(--serif);
  font-style: italic;
  font-size: 15px;
  color: var(--ink-faint);
}
.mcard__face { transform: rotateY(180deg); }
/* Re-stated here because `.mcard__face` above resets font-style at the same
   specificity as the shared italic rule. */
.mcard__face--es { font-family: var(--serif); font-style: italic; }

/* Two pairs turn over during the cycle; the rest stay face down. */
.gcard.is-live .mcard--a { animation: mem-flip 5s infinite; }
.gcard.is-live .mcard--b { animation: mem-flip 5s infinite; animation-delay: -2.5s; }
@keyframes mem-flip {
  0%, 6% { transform: rotateY(0deg); }
  20%, 42% { transform: rotateY(180deg); }
  48%, 100% { transform: rotateY(0deg); }
}
.gcard.is-live .mcard--a .mcard__face { animation: mem-ok 5s infinite; }
.gcard.is-live .mcard--b .mcard__face { animation: mem-ok 5s infinite; animation-delay: -2.5s; }
@keyframes mem-ok {
  0%, 26% { border-color: var(--rule); color: var(--ink); }
  32%, 100% { border-color: var(--ok); color: var(--ok); }
}

/* ── 3 · Word bank ── */
.bank__line {
  margin: 0 0 16px;
  font-size: 16px;
  line-height: 1.72;
  color: var(--ink);
}
.bank__gap {
  display: inline-block;
  min-width: 74px;
  border-bottom: 1px solid var(--rule);
  text-align: center;
}
.bank__gap i { font-style: italic; opacity: 0; }

.gcard.is-live .bank__gap i { animation: bank-fill 5s infinite; }
@keyframes bank-fill {
  0%, 26% { opacity: 0; }
  34%, 100% { opacity: 1; }
}
.gcard.is-live .bank__gap { animation: bank-ok 5s infinite; }
@keyframes bank-ok {
  0%, 58% { border-color: var(--rule); color: var(--ink); }
  66%, 100% { border-color: var(--ok); color: var(--ok); }
}
.gcard.is-live .gtiles--words .is-target { animation: bank-used 5s infinite; }
@keyframes bank-used {
  0%, 26% { opacity: 1; }
  34%, 100% { opacity: .22; }
}

/* ── 4 · Letter scramble, 8 · Listen · scramble ── */
.scr__gloss {
  margin: 0 0 16px;
  font-family: var(--serif);
  font-weight: 300;
  font-style: italic;
  font-size: 26px;
  color: var(--ink);
}
.gstage--listen .aud__play { margin-bottom: 16px; }

/* Letters land one after another, then the whole answer confirms. The two
   animations touch different properties, so they can share the element.
   Scoped to the scramble stages: the word bank reuses `.gtiles`. */
.gcard.is-live .gstage--scramble .gslots span {
  animation:
    slot-land 5s calc(var(--i) * .18s) infinite,
    slot-ok 5s infinite;
}
@keyframes slot-land {
  0%, 10% { color: transparent; }
  18%, 100% { color: var(--ink); }
}
@keyframes slot-ok {
  0%, 62% { border-bottom-color: var(--rule); }
  70%, 100% { border-bottom-color: var(--ok); }
}
.gcard.is-live .gstage--scramble .gtiles span {
  animation: tile-used 5s infinite;
  animation-delay: calc(var(--i) * .18s);
}
@keyframes tile-used {
  0%, 10% { opacity: 1; }
  18%, 100% { opacity: .25; }
}

/* ── 5 · Sentence scan ── */
.scan__hint {
  margin: 0 0 14px;
  font-family: var(--serif);
  font-style: italic;
  font-size: 18px;
  color: var(--ink);
}
.scan__chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 7px;
}
.scan__chips span {
  padding-bottom: 2px;
  border-bottom: 1px solid transparent;
  font-size: 14px;
  color: var(--ink-dim);
}
.gcard.is-live .scan__chips .is-answer {
  animation: scan-pick 5s infinite;
  animation-delay: calc(var(--i) * .2s);
}
@keyframes scan-pick {
  0%, 16% { border-bottom-color: transparent; color: var(--ink-dim); }
  24%, 54% { border-bottom-color: var(--ink); color: var(--ink); }
  62%, 100% { border-bottom-color: var(--ok); color: var(--ok); }
}

/* ── 6 · Audio → meaning, 7 · Audio → spelling ── */
.aud__prompt {
  margin: 0 0 13px;
  font-family: var(--serif);
  font-style: italic;
  font-size: 15px;
  line-height: 1.4;
  color: var(--ink-dim);
}
.aud__play {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 13px;
}
/* Hidden until answered, exactly as the game hides it: drawn in the page
   colour rather than removed, so the line never reflows. */
.aud__hidden {
  font-family: var(--serif);
  font-style: italic;
  font-size: 15px;
  color: var(--bg);
}
.gcard.is-live .aud__hidden { animation: aud-reveal 5s infinite; }
@keyframes aud-reveal {
  0%, 50% { color: var(--bg); }
  58%, 100% { color: var(--ink-dim); }
}
.gcard.is-live .gspeaker::after { animation: aud-pulse 5s infinite; }
@keyframes aud-pulse {
  0% { opacity: .55; transform: scale(1); }
  22% { opacity: 0; transform: scale(1.5); }
  100% { opacity: 0; transform: scale(1.5); }
}
.gcard.is-live .gopts .is-answer { animation: opt-right 5s infinite; }
@keyframes opt-right {
  0%, 50% { color: var(--ink); }
  58%, 100% { color: var(--ok); font-style: italic; }
}
.gcard.is-live .gopts li:not(.is-answer) { animation: opt-fade 5s infinite; }
@keyframes opt-fade {
  0%, 50% { opacity: 1; }
  58%, 100% { opacity: .35; }
}

/* ── 9 · Memorize & match ── */
.mm__rows {
  margin: 0 0 12px;
  padding: 0;
  list-style: none;
}
.mm__rows li {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  padding: 5px 0;
  border-bottom: 1px solid var(--rule-faint);
  font-size: 12.5px;
}
.mm__es { color: var(--ink); }
.mm__en { color: var(--ink-faint); }
/* The pairs are studied, then taken away — the point of the game. Only the
   text goes; the rules stay, so it reads as covered rather than faded out. */
.gcard.is-live .mm__rows span { animation: mm-hide 5s infinite; }
@keyframes mm-hide {
  0%, 46% { opacity: 1; }
  60%, 100% { opacity: .12; }
}
.mm__step {
  margin: 0;
  font-family: var(--grotesk);
  font-weight: 700;
  font-size: 9px;
  letter-spacing: 1.8px;
  text-transform: uppercase;
  color: var(--ink);
  opacity: 0;
}
.gcard.is-live .mm__step { animation: mm-step 5s infinite; }
@keyframes mm-step {
  0%, 52% { opacity: 0; }
  66%, 100% { opacity: 1; }
}

/* ── 10 · Mixed review ── */
.mix__rounds {
  display: flex;
  gap: 6px;
  margin: 0 0 20px;
  padding: 0;
  list-style: none;
}
.mix__rounds li {
  display: grid;
  place-items: center;
  flex: 1 1 0;
  height: 34px;
  background: var(--paper);
  border: 1px solid var(--rule-faint);
  font-family: var(--grotesk);
  font-size: 10px;
  letter-spacing: 1px;
  color: var(--ink-faint);
}
.gcard.is-live .mix__rounds li {
  animation: mix-step 5s infinite;
  animation-delay: calc(var(--i) * 1s);
}
@keyframes mix-step {
  0%, 14% { border-color: var(--ink); background: var(--paper-2); color: var(--ink); }
  20%, 100% { border-color: var(--rule-faint); background: var(--paper); color: var(--ink-faint); }
}

/* The round labels cross-fade in the same rhythm, stacked so the block
   keeps one line's height. */
.mix__now {
  position: relative;
  margin: 0 0 16px;
  height: 34px;
}
.mix__now span {
  position: absolute;
  inset: 0;
  font-family: var(--serif);
  font-weight: 300;
  font-size: 23px;
  color: var(--ink);
  opacity: 0;
}
.gcard.is-live .mix__now span {
  animation: mix-label 5s infinite;
  animation-delay: calc(var(--i) * 1s);
}
@keyframes mix-label {
  0% { opacity: 0; }
  4%, 16% { opacity: 1; }
  20%, 100% { opacity: 0; }
}

/* ── Position readout and ticks ── */
.games__meta {
  display: flex;
  align-items: center;
  gap: 18px;
  margin-top: 26px;
}
.games__count {
  margin: 0;
  font-family: var(--grotesk);
  font-size: 10px;
  letter-spacing: 2px;
  white-space: nowrap;
  color: var(--ink-faint);
}
.games__count b { font-weight: 700; color: var(--ink); }
/* A rail of ten segments that shares out the width, so it holds together on
   a phone instead of pushing the readout onto a second line. */
.games__ticks {
  flex: 1 1 auto;
  display: flex;
  gap: 6px;
  max-width: 320px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.games__ticks li {
  flex: 1 1 0;
  min-width: 0;
  height: 2px;
  background: var(--rule-faint);
  transition: background-color .4s ease;
}
.games__ticks li.is-live { background: var(--ink); }

/* ── Why reading works ────────────────────────────────────── */

.why {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1px;
  background: var(--rule-faint);
  border: 1px solid var(--rule-faint);
}

.why__item {
  padding: clamp(26px, 2.6vw, 38px);
  background: var(--bg);
}
.why__item h3 {
  margin: 0 0 14px;
  font-family: var(--serif);
  font-weight: 400;
  font-size: 24px;
  line-height: 1.24;
  letter-spacing: -0.01em;
}
.why__item p {
  margin: 0;
  font-size: 14.5px;
  line-height: 1.68;
  color: var(--ink-dim);
}
.why__item p em { font-style: italic; color: var(--ink); }
.why__item .why__num {
  margin: 0 0 20px;
  font-family: var(--grotesk);
  font-weight: 700;
  font-size: 10px;
  letter-spacing: 2.4px;
  color: var(--ink-faint);
}

.why__turn {
  display: grid;
  grid-template-columns: minmax(0, 190px) minmax(0, 1fr);
  gap: clamp(18px, 4vw, 56px);
  margin-top: clamp(40px, 5vw, 66px);
  padding-top: clamp(26px, 3vw, 40px);
  border-top: 1px solid var(--rule-faint);
}
.why__turn-label {
  margin: 0;
  padding-top: 9px;
  font-family: var(--grotesk);
  font-weight: 700;
  font-size: 10px;
  letter-spacing: 2.6px;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.why__turn-body {
  margin: 0;
  max-width: 60ch;
  font-family: var(--serif);
  font-size: clamp(18px, 1.9vw, 23px);
  line-height: 1.55;
  color: var(--ink-dim);
}

/* ── How it works ─────────────────────────────────────────── */

.steps {
  display: grid;
  grid-template-columns: minmax(0, .92fr) minmax(0, 1.08fr);
  gap: clamp(32px, 5vw, 72px);
  align-items: start;
}

.steps__list {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--rule-faint);
}
.steps__list li { border-bottom: 1px solid var(--rule-faint); }
/* Desktop: the JS track wrapper is transparent and the loop clones stay out. */
.steps__track { display: contents; }
.step-clone { display: none; }

.step {
  position: relative;
  display: grid;
  grid-template-columns: 46px minmax(0, 1fr);
  gap: 16px;
  width: 100%;
  padding: 22px 4px;
  text-align: left;
  transition: opacity .3s ease;
  opacity: .48;
}
.step:hover { opacity: .78; }
.step[aria-selected='true'] { opacity: 1; }

.step__num {
  font-family: var(--grotesk);
  font-weight: 700;
  font-size: 11px;
  letter-spacing: 2px;
  color: var(--ink-faint);
  padding-top: 5px;
}
.step[aria-selected='true'] .step__num { color: var(--ink); }

.step__body { display: block; }
.step__title {
  display: block;
  font-family: var(--serif);
  font-size: clamp(20px, 2vw, 25px);
  line-height: 1.28;
  letter-spacing: -0.01em;
}
.step__note {
  display: block;
  margin-top: 7px;
  font-size: 13.5px;
  line-height: 1.6;
  color: var(--ink-dim);
  max-width: 42ch;
}

.step__bar {
  position: absolute;
  left: 0;
  bottom: -1px;
  width: 100%;
  height: 1px;
  overflow: hidden;
}
.step__bar i {
  display: block;
  height: 100%;
  width: 100%;
  background: var(--ink);
  transform: scaleX(0);
  transform-origin: left;
}
.step[aria-selected='true'] .step__bar i {
  animation: step-fill var(--step-duration, 5s) linear forwards;
}
@keyframes step-fill {
  from { transform: scaleX(0); }
  to { transform: scaleX(1); }
}

/* Panels */
.steps__stage {
  position: relative;
  border: 1px solid var(--rule);
  background: var(--paper);
  padding: clamp(24px, 3vw, 38px);
  min-height: 440px;
  /* Every panel sits in the same cell, so the stage is always as tall as the
     tallest one. Hiding a panel with `display: none` would resize the stage on
     each step and shove the rest of the page up and down. */
  display: grid;
  align-items: start;
}

.panel {
  grid-area: 1 / 1;
  width: 100%;
}
.panel:not([hidden]) { animation: panel-in .4s cubic-bezier(.16, 1, .3, 1); }
/* Keeps its space but stays out of the page and the accessibility tree. */
.panel[hidden] {
  display: block;
  visibility: hidden;
  animation: none;
}

@keyframes panel-in {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: none; }
}

.panel__kicker {
  margin: 0;
  font-family: var(--grotesk);
  font-weight: 700;
  font-size: 9px;
  letter-spacing: 2.6px;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.panel__title {
  margin: 10px 0 24px;
  font-family: var(--serif);
  font-size: 27px;
  line-height: 1.2;
}
.panel__word {
  margin: 10px 0 2px;
  font-family: var(--serif);
  font-size: clamp(30px, 3.4vw, 40px);
  line-height: 1.1;
}
.panel__ipa {
  margin: 0 0 24px;
  font-size: 13px;
  color: var(--ink-faint);
}

.panel__shelf {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 18px;
}
.panel__shelf img {
  width: 100%;
  /* Without this the height="300" attribute wins and the ratio below is
     ignored, squeezing the square art into a 0.47 box and cropping half its
     width away. */
  height: auto;
  aspect-ratio: 2 / 3;
  object-fit: cover;
  border: 1px solid var(--rule-faint);
}
.panel__shelf figure { margin: 0; }
.panel__shelf figcaption {
  margin-top: 12px;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--ink-dim);
}
.panel__shelf figcaption b {
  display: block;
  font-family: var(--grotesk);
  font-size: 9px;
  letter-spacing: 2px;
  color: var(--ink-faint);
  margin-bottom: 4px;
}

.panel__prose {
  margin: 0;
  font-family: var(--serif);
  font-size: 19px;
  line-height: 1.7;
  color: var(--ink-dim);
}
.panel__prose em {
  font-style: normal;
  color: var(--ink);
  border-bottom: 1px solid var(--rule);
  padding-bottom: 1px;
}

.panel__foot {
  display: flex;
  justify-content: space-between;
  margin-top: 30px;
  padding-top: 16px;
  border-top: 1px solid var(--rule-faint);
  font-family: var(--grotesk);
  font-size: 9px;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.panel__rows { margin: 0; }
.panel__rows > div {
  display: grid;
  grid-template-columns: 96px minmax(0, 1fr);
  gap: 14px;
  padding: 14px 0;
  border-top: 1px solid var(--rule-faint);
}
.panel__rows dt {
  font-family: var(--grotesk);
  font-weight: 700;
  font-size: 9px;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--ink-faint);
  padding-top: 4px;
}
.panel__rows dd { margin: 0; font-size: 15px; color: var(--ink-dim); }
.panel__rows > div:first-child dd { color: var(--ink); font-size: 17px; }

.panel__units {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--rule-faint);
}
.panel__units li {
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr) auto;
  gap: 14px;
  align-items: center;
  padding: 15px 0;
  border-bottom: 1px solid var(--rule-faint);
}
.u-span { font-family: var(--serif); font-size: 17px; }
.u-gloss { font-size: 13.5px; color: var(--ink-dim); }

.tag {
  font-family: var(--grotesk);
  font-weight: 700;
  font-size: 8.5px;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  padding: 4px 9px;
  border: 1px solid var(--rule);
  color: var(--ink-dim);
  white-space: nowrap;
}
.tag--struggling { color: var(--bad); border-color: var(--bad); }
.tag--mastered { color: var(--ok); border-color: var(--ok); }
.tag--solid { color: var(--ink); border-color: var(--ink-faint); }

.tiles {
  display: flex;
  flex-wrap: wrap;
  gap: 9px;
  margin-top: 8px;
}
.tiles--bank { margin-top: 26px; opacity: .7; }
.tile {
  display: grid;
  place-items: center;
  width: 46px;
  height: 52px;
  border: 1px solid var(--rule);
  font-family: var(--serif);
  font-size: 22px;
}
.tile--set { background: var(--ink); color: var(--bg); border-color: var(--ink); }
.tile--open { border-style: dashed; border-color: var(--rule-faint); }

.panel__games {
  margin: 32px 0 0;
  padding-top: 16px;
  border-top: 1px solid var(--rule-faint);
  font-size: 12.5px;
  color: var(--ink-faint);
}

/* ── Features ─────────────────────────────────────────────── */

/* Cover marquee. It sits straight under the section header, which supplies
   the space above it. */
.marquee__label {
  margin: 0 0 28px;
  text-align: center;
  font-family: var(--grotesk);
  font-size: 10px;
  letter-spacing: 2.6px;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.marquee__viewport {
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 9%, #000 91%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 9%, #000 91%, transparent);
}

.marquee__track {
  display: flex;
  gap: 20px;
  width: max-content;
  animation: marquee 52s linear infinite;
}
.marquee.is-held .marquee__track { animation-play-state: paused; }
.marquee__track figure {
  flex: 0 0 auto;
  width: 118px;
  margin: 0;
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
}
.marquee__track img {
  display: block;
  width: 100%;
  aspect-ratio: 2 / 3;
  object-fit: cover;
  border: 1px solid var(--rule-faint);
  filter: grayscale(1);
  opacity: .62;
  transition: filter .3s ease, opacity .3s ease;
  /* Hits go to the figure. Safari otherwise treats a long-press as
     “save / enlarge this image” and steals the hold. */
  pointer-events: none;
  -webkit-touch-callout: none;
  -webkit-user-drag: none;
}
/* Two lines are reserved so every cover sits on the same baseline whatever
   the title length. */
.marquee__track figcaption {
  min-height: 2.9em;
  margin-top: 11px;
  font-size: 11px;
  line-height: 1.45;
  color: var(--ink-faint);
  transition: color .3s ease;
}
/* A press lifts the cover; hover does the same, but only on devices that
   can hover. A tap would otherwise stick :hover and freeze the strip. */
.marquee__track figure.is-held img { filter: none; opacity: 1; }
.marquee__track figure.is-held figcaption { color: var(--ink); }
@media (hover: hover) {
  .marquee:hover .marquee__track { animation-play-state: paused; }
  .marquee__track figure:hover img { filter: none; opacity: 1; }
  .marquee__track figure:hover figcaption { color: var(--ink); }
}

@keyframes marquee {
  from { transform: translateX(0); }
  to { transform: translateX(calc(-50% - 10px)); }
}

/* ── Closing call to action ───────────────────────────────── */

.closer {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 20px;
  margin-top: clamp(46px, 5vw, 68px);
  padding-top: clamp(32px, 4vw, 46px);
  border-top: 1px solid var(--rule-faint);
}
.closer__note {
  margin: 0;
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--ink-faint);
}

/* ── Footer ───────────────────────────────────────────────── */

.footer {
  border-top: 1px solid var(--rule-faint);
  background: var(--paper);
  padding-top: 56px;
}

.footer__inner {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 32px;
  flex-wrap: wrap;
  padding-bottom: 40px;
}

.footer__brand {
  display: flex;
  gap: 14px;
  align-items: center;
}
.footer__brand img { border: 1px solid var(--rule-faint); }
.footer__tag {
  margin: 6px 0 0;
  font-size: 13px;
  color: var(--ink-dim);
}

.footer__links {
  display: flex;
  gap: 28px;
  flex-wrap: wrap;
  font-family: var(--grotesk);
  font-size: 11px;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  color: var(--ink-dim);
}
.footer__links a:hover { color: var(--ink); }

.footer__legal {
  border-top: 1px solid var(--rule-faint);
  padding-block: 22px 30px;
}
.footer__legal p {
  margin: 0;
  font-size: 11.5px;
  color: var(--ink-faint);
}

.footer__links a[aria-current='page'] { color: var(--ink); }

/* ── Legal / support pages ────────────────────────────────── */

.page--legal .reveal {
  opacity: 1;
  transform: none;
}

.legal {
  padding-block: clamp(48px, 8vw, 96px) var(--section-y);
}

.legal__shell {
  max-width: 760px;
}

.legal__title {
  margin-top: 18px;
}

.legal__effective {
  margin: 18px 0 0;
  font-size: 14px;
  color: var(--ink-faint);
}

.legal__lead {
  margin-top: 22px;
  max-width: 62ch;
  color: var(--ink-dim);
  font-size: 17px;
  line-height: 1.55;
}
.legal__lead p { margin: 0 0 0.85em; }
.legal__lead p:last-child { margin-bottom: 0; }
.legal__lead a {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: var(--rule);
}
.legal__lead a:hover { text-decoration-color: var(--ink); }

.page--support .legal {
  padding-top: 20px;
}
.page--support .legal__lead {
  margin-top: 16px;
}
.page--support .legal__pages {
  margin-top: 20px;
  padding-top: 16px;
}

.feedback {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-top: 18px;
  max-width: 62ch;
}
.feedback__label {
  display: block;
  margin-bottom: 6px;
  font-family: var(--grotesk);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.feedback__label em {
  font-style: normal;
  font-weight: 400;
  letter-spacing: 0.4px;
  text-transform: none;
}
.feedback textarea,
.feedback input[type="text"] {
  width: 100%;
  padding: 12px 14px;
  border: 1px solid var(--rule);
  background: var(--paper);
  color: var(--ink);
  font: inherit;
  font-size: 16px;
  line-height: 1.45;
}
.feedback textarea {
  min-height: 96px;
  resize: vertical;
}
.feedback__hint,
.feedback__error {
  margin: 0;
  font-size: 15px;
  line-height: 1.5;
  color: var(--ink-dim);
}
.feedback__error a {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 3px;
}
.feedback .btn { align-self: flex-start; }
.feedback__hp {
  position: absolute;
  left: -10000px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}
.sent {
  margin-top: 22px;
  max-width: 62ch;
  padding: 24px 26px;
  border: 1px solid var(--rule-faint);
  border-left: 2px solid var(--ok);
  background: var(--paper);
}
.sent__badge {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 14px;
  font-family: var(--grotesk);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 2.2px;
  text-transform: uppercase;
  color: var(--ok);
}
.sent__badge svg {
  width: 15px;
  height: 15px;
  flex: none;
}
.sent__heading {
  margin: 0 0 10px;
  font-family: var(--serif);
  font-size: clamp(21px, 2.6vw, 26px);
  font-weight: 400;
  letter-spacing: -0.02em;
  line-height: 1.25;
  color: var(--ink);
}
.sent__text,
.sent__more {
  margin: 0;
  font-size: 16px;
  line-height: 1.6;
  color: var(--ink-dim);
}
.sent__more {
  margin-top: 16px;
  padding-top: 16px;
  border-top: 1px solid var(--rule-faint);
  font-size: 15px;
  color: var(--ink-faint);
}
.sent__more a {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: var(--rule);
}
.sent__more a:hover { text-decoration-color: var(--ink); }

@media (max-width: 360px) {
  .sent { padding: 20px; }
}

.legal__pages {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 22px;
  margin-top: 28px;
  padding-top: 22px;
  border-top: 1px solid var(--rule-faint);
  font-family: var(--grotesk);
  font-size: 11px;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.legal__pages a:hover { color: var(--ink); }
.legal__pages a.is-on {
  color: var(--ink);
  cursor: default;
}

.legal__body {
  margin-top: 42px;
  color: var(--ink-dim);
  font-size: 16.5px;
  line-height: 1.65;
  overflow-wrap: break-word;
}

.legal__body h2 {
  margin: 2.4em 0 0.7em;
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(24px, 3vw, 30px);
  letter-spacing: -0.02em;
  color: var(--ink);
  line-height: 1.2;
}

.legal__body h2:first-child { margin-top: 0; }

.legal__body h3 {
  margin: 1.6em 0 0.5em;
  font-family: var(--grotesk);
  font-weight: 700;
  font-size: 12px;
  letter-spacing: 1.8px;
  text-transform: uppercase;
  color: var(--ink);
}

.legal__body p { margin: 0 0 1em; }

.legal__body ul {
  margin: 0 0 1.2em;
  padding-left: 1.2em;
}

.legal__body li { margin: 0.35em 0; }

.legal__body a {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: var(--rule);
}

.legal__body a:hover { text-decoration-color: var(--ink); }

.legal__body code {
  font-size: 0.9em;
  color: var(--ink);
}

.legal__body table {
  width: 100%;
  margin: 0 0 1.4em;
  border-collapse: collapse;
  font-size: 15px;
}

.legal__body th,
.legal__body td {
  border: 1px solid var(--rule-faint);
  padding: 10px 14px;
  text-align: left;
  vertical-align: top;
}

.legal__body th {
  font-family: var(--grotesk);
  font-weight: 700;
  font-size: 10px;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  color: var(--ink-faint);
  background: var(--paper);
}

.legal__body td { color: var(--ink-dim); }

@media (max-width: 700px) {
  .legal__body table { display: block; overflow-x: auto; }
}

/* ── Reveal on scroll ─────────────────────────────────────── */

.reveal {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity .7s cubic-bezier(.16, 1, .3, 1), transform .7s cubic-bezier(.16, 1, .3, 1);
}
.reveal.is-in {
  opacity: 1;
  transform: none;
}

/* ── Responsive ───────────────────────────────────────────── */

@media (max-width: 1000px) {
  .hero__grid { grid-template-columns: minmax(0, 1fr); }
  .hero__copy { order: -1; }
  .hero__demo { margin-top: 8px; }
  .steps { grid-template-columns: minmax(0, 1fr); }
  .steps__stage { min-height: 400px; }
  /* One step at a time. The track is translated in JS so 05 can slide
     straight into 01; native overflow-scroll can't wrap. */
  .steps__list {
    border-top: none;
    overflow: hidden;
    touch-action: pan-y;
  }
  .steps__track {
    display: flex;
    width: 100%;
    will-change: transform;
  }
  .steps__track > li {
    flex: 0 0 100%;
    min-width: 100%;
    border-bottom: none;
  }
  .step-clone { display: block; }
  .step { opacity: 1; padding: 4px 0 18px; }
  /* Clear of the clipped edge, so the progress line still shows. */
  .step__bar { bottom: 0; }
  .band__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .why { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 359px) {
  .nav .btn--small { display: none; }
}

@media (max-width: 640px) {
  .nav__inner { gap: 12px; }
  .btn--small { padding: 9px 12px; letter-spacing: 1.6px; }
  /* One card fills the frame, so the dimmed neighbour isn't worth the width. */
  .gcard { flex-basis: 100%; }
  .gstage { height: 250px; }
  .steps__stage { padding: 22px 18px; min-height: 0; }
  .panel__shelf { gap: 12px; }
  /* Five two-line rows made this the tallest panel by a wide margin, and the
     tallest panel sets the height of the stage. */
  .panel__units li {
    grid-template-columns: minmax(0, 1fr) auto;
    row-gap: 1px;
    padding: 9px 0;
  }
  .panel__units .u-span { font-size: 16px; }
  .panel__units .u-gloss { grid-column: 1; grid-row: 2; font-size: 12.5px; }
  .panel__units .tag { grid-row: 1 / span 2; }
  .panel__rows > div { grid-template-columns: minmax(0, 1fr); gap: 6px; }
  .panel__prose { font-size: 17px; }
  .panel__title { margin-bottom: 18px; }
  .phone__screen {
    padding: 22px 18px 0;
    /* The sheet is pinned to the bottom; this is just enough that the last
       line still clears it, without the empty band the 700px frame left. */
    min-height: 665px;
  }
  .reader__text { font-size: 17.5px; }
  .sheet::before { height: 20px; }
  .why__turn { grid-template-columns: minmax(0, 1fr); }
  .why__turn-label { padding-top: 0; }
  .footer__inner { flex-direction: column; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .reveal { opacity: 1; transform: none; transition: none; }
  .marquee__track { animation: none; }
  .panel:not([hidden]),
  .sheet { animation: none; }
  /* The nudge ring can't breathe, so it just sits there instead. */
  .icon.is-nudge::after,
  .linky.is-nudge::after,
  .kw.is-nudge::after { opacity: 1; }
  .step[aria-selected='true'] .step__bar i { animation: none; transform: scaleX(1); }

  /* The games showcase stops being a carousel and becomes a plain grid. */
  .games__viewport { overflow: visible; margin: 0; padding: 0; }
  .games__track {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(270px, 1fr));
    transform: none !important;
  }
  .gcard { opacity: 1; border-color: var(--rule); }
  .games__meta { display: none; }

  /* Each mock needs a resting frame, since several elements are only
     revealed by the animation that no longer runs. Show the solved state. */
  .bank__gap i,
  .mm__step { opacity: 1; }
  .bank__gap { border-bottom-color: var(--ok); color: var(--ok); }
  .gtiles--words .is-target { opacity: .22; }
  .aud__hidden { color: var(--ink-dim); }
  .gopts .is-answer { color: var(--ok); font-style: italic; }
  .gopts li:not(.is-answer) { opacity: .35; }
  .gslots span { border-bottom-color: var(--ok); }
  .gtiles span { opacity: .25; }
  .scan__chips .is-answer { border-bottom-color: var(--ok); color: var(--ok); }
  .pair--a { border-color: var(--ok); color: var(--ink-faint); text-decoration: line-through; opacity: .55; }
  .mcard--a, .mcard--b { transform: rotateY(180deg); }
  .mcard--a .mcard__face, .mcard--b .mcard__face { border-color: var(--ok); color: var(--ok); }
  .mm__rows span { opacity: .12; }
  .mix__rounds li:first-child { border-color: var(--ink); background: var(--paper-2); color: var(--ink); }
  .mix__now span:first-child { opacity: 1; }

  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
}
