/* Tapit Daily. Same Bold Utility system as site.css (ink outlines, hard offset shadows, cobalt),
   with three speed colours for the Keyprint. Light only, like the rest of the site. */

:root {
  --fast: #1E9E5A; --fast-tint: #E4F5EC; --fast-text: #145F38;
  --steady: #E7A400; --steady-tint: #FFF4D6; --steady-text: #7A5600;
  --slow: #D7372B; --slow-tint: #FCE5E3; --slow-text: #8E1F17;
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
}

/* Browser surfaces that would otherwise keep their defaults. */
html { scrollbar-color: var(--ink) var(--panel); }
::selection { background: var(--accent); color: var(--on-accent); }
input { caret-color: var(--accent); }
input::placeholder { color: var(--muted); opacity: 1; }
.rounds-table, .headline, .logbook, .round-clock, .placement-rank { font-variant-numeric: tabular-nums; }

.wordmark { min-height: 44px; }
.daily-page .topbar-mac { min-height: 44px; }
/* Badges, theme and sound live in the nav on every screen; theme and badges step aside during a run. */
.topbar-tools { position: relative; display: flex; align-items: center; gap: 10px; margin-left: auto; }
.topbar-tools .sound-icon { position: static; }
.daily-page:has(.round:not([hidden]), .between:not([hidden])) :is(#pack-toggle, #badge-toggle) { display: none; }
.game { position: relative; padding-top: 40px; padding-bottom: 72px; min-height: calc(100svh - 65px - 40px); }
.game-screen { max-width: 760px; margin-inline: auto; }

/* Backdrops (generated with Codex, design/backgrounds/codex/): a busier one behind the start
   screen, a near-plain paper behind the rounds. Two fixed layers crossfade as screens change.
   ?bg=keycaps, ?bg=halftone or ?bg=ripples swaps the start one back to an older look, for comparing. */
/* The desk drawing is busy at the edges, so a glow of its own paper colour keeps the middle clear for the text. */
.daily-page {
  --desk-wash: radial-gradient(ellipse 34% 44% at 50% 55%, rgb(249 246 238) 58%, rgb(249 246 238 / 0) 100%);
  --bg-start: var(--desk-wash), url("../img/bg/start-desk.webp"); --bg-play: url("../img/bg/play-paper.webp");
}
:root[data-bg="keycaps"] .daily-page { --bg-start: url("../img/bg/start-keycaps.webp"); }
:root[data-bg="halftone"] .daily-page { --bg-start: url("../img/bg/start-halftone.webp"); }
:root[data-bg="ripples"] .daily-page { --bg-start: url("../img/bg/start-ripples.webp"); }
.daily-page::before, .daily-page::after {
  /* Sits between the top bar and the footer (the start screen fits one screen, so both stay put). */
  content: ""; position: fixed; inset: 66px 0 var(--footer-h, 40px); z-index: -1; pointer-events: none;
  background: center / cover no-repeat; opacity: 0; transition: opacity 600ms var(--ease-out);
}
.daily-page::before { background-image: var(--bg-start); background-position: var(--bg-start-position, center); }
.daily-page::after { background-image: var(--bg-play); }
.daily-page:has(.start:not([hidden]))::before,
.daily-page:has(.round:not([hidden]), .between:not([hidden]))::after { opacity: 1; }
/* Tall screens get portrait versions, so the detail stays at the edges instead of cropping off. */
@media (max-aspect-ratio: 4/5) {
  .daily-page::before, .daily-page::after { top: 60px; --footer-h: 40px; }
  /* The desk drawing is landscape only; on a phone, show its keyboard corner and coiled cable. */
  .daily-page {
    --desk-wash: radial-gradient(ellipse 75% 46% at 50% 58%, rgb(249 246 238) 68%, rgb(249 246 238 / 0) 100%);
    --bg-start: var(--desk-wash), url("../img/bg/start-desk.webp"); --bg-start-position: 14% 100%; --bg-play: url("../img/bg/play-paper-tall.webp");
  }
  :root[data-bg] .daily-page { --bg-start-position: center; }
  :root[data-bg="keycaps"] .daily-page { --bg-start: url("../img/bg/start-keycaps-tall.webp"); }
  :root[data-bg="halftone"] .daily-page { --bg-start: url("../img/bg/start-halftone-tall.webp"); }
  :root[data-bg="ripples"] .daily-page { --bg-start: url("../img/bg/start-ripples-tall.webp"); }
}
/* The rounds can scroll past one screen, so their quiet paper runs to the bottom under the footer. */
.daily-page::after { bottom: 0; }
/* The footer sits on paper so a keycap in the backdrop never runs under its text. */
.daily-page .footer { background: var(--paper); }
[hidden] { display: none !important; }
/* site.css rules sections apart with a line; screens here replace each other instead. */
.game > .game-screen { border-top: 0; }
.button.big { min-height: 54px; padding: 14px 28px; font-size: 18px; }
.button.big.pro { box-shadow: 4px 4px 0 var(--ink); }
.button.big.pro:hover { box-shadow: 3px 3px 0 var(--ink); }
.button:disabled { opacity: 0.5; cursor: default; }

/* ---------- Tappy ---------- */
/* Two stacked copies of the mascot: a pose change swaps the hidden one and crossfades, so poses
   ease over --pose-ms instead of snapping. */
.tappy { position: relative; display: inline-block; flex-shrink: 0; width: 52px; aspect-ratio: 1; pointer-events: none; }
.tappy.big { width: 88px; }
.tappy svg {
  position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible;
  opacity: 0; transform: translateY(5px) scale(0.94); transform-origin: 50% 90%;
  transition: opacity var(--pose-ms, 400ms) var(--ease-out), transform var(--pose-ms, 400ms) var(--ease-out);
}
.tappy svg.is-shown { opacity: 1; transform: none; }

.tappy-line { display: flex; align-items: center; gap: 20px; }
.bubble {
  position: relative; padding: 12px 16px; max-width: 34ch; border: var(--rule) solid var(--ink); border-radius: 12px;
  background: var(--paper); box-shadow: 3px 3px 0 var(--ink);
  font-weight: 700; font-size: 17px; line-height: 1.3; text-wrap: balance;
}
.bubble::before {
  content: ""; position: absolute; left: -8px; top: 50%; width: 14px; height: 14px; background: var(--paper);
  border-left: var(--rule) solid var(--ink); border-bottom: var(--rule) solid var(--ink); transform: translateY(-50%) rotate(45deg);
}
.bubble:empty { display: none; }

/* ---------- Start ---------- */
/* One screen, no scroll: TAPIT as five keycaps, a line of pitch, the call to begin, one meta line. */
.game:has(.start:not([hidden])) { padding-bottom: 24px; min-height: 0; }
.game-screen.start:not([hidden]) {
  display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center;
  /* The top bar, the slim footer and the game's padding: the start screen fills the rest exactly. */
  min-height: calc(100svh - 170px);
}
.daily-title { margin-top: 0; font-size: clamp(34px, 6vw, 60px); line-height: 1.02; text-wrap: balance; }
.game-rules { margin-top: 14px; font-size: 19px; color: var(--body); max-width: 56ch; }
.wordmark-row { position: relative; display: flex; align-items: flex-end; gap: 20px; margin-top: 64px; }
.wordmark-keys { display: flex; gap: 12px; margin: 0; --cap: clamp(52px, 8vw, 112px); }
.wordmark-cap {
  display: grid; place-items: center; width: var(--cap); height: calc(var(--cap) * 1.12);
  border: var(--rule) solid var(--ink); border-radius: calc(var(--cap) * 0.14); background: var(--paper);
  box-shadow: 6px 6px 0 var(--ink);
  font-weight: 800; font-stretch: 125%; font-size: calc(var(--cap) * 0.55); line-height: 1; color: var(--ink);
  /* T-A-P-I-T typed out one key at a time: each key goes down, lights cobalt, hops back up,
     then the word rests for about three seconds before it's typed again. */
  animation: cap-press 4.4s linear calc(var(--i, 0) * 180ms + 400ms) infinite both;
}
.wordmark-cap:nth-child(2) { --i: 1; }
.wordmark-cap:nth-child(3) { --i: 2; }
.wordmark-cap:nth-child(4) { --i: 3; }
.wordmark-cap:nth-child(5) { --i: 4; }
/* One 4.4s cycle; 1% is 44ms. The press, hop and settle take the first ~700ms. */
@keyframes cap-press {
  0% { transform: none; box-shadow: 6px 6px 0 var(--ink); background: var(--paper); color: var(--ink); animation-timing-function: cubic-bezier(0.4, 0, 1, 1); }
  3%, 6.5% { transform: translate(6px, 6px); box-shadow: 0 0 0 var(--ink); background: var(--accent); color: var(--on-accent); }
  6.5% { animation-timing-function: var(--ease-out); }
  10% { transform: translate(-1px, -9px); box-shadow: 7px 15px 0 var(--ink); background: var(--accent); color: var(--on-accent); animation-timing-function: ease-in-out; }
  13% { transform: translate(0, 1px); box-shadow: 6px 5px 0 var(--ink); }
  16%, 100% { transform: none; box-shadow: 6px 6px 0 var(--ink); background: var(--paper); color: var(--ink); }
}
.start-tappy { display: flex; flex-shrink: 0; align-self: flex-start; transform: translateY(-34px); }
.start-tappy .tappy.big { width: 100px; }
.bubble.above { position: absolute; right: 0; bottom: calc(100% + 4px); width: max-content; max-width: 340px; font-size: 16px; text-align: left; white-space: nowrap; }
.bubble.above::before { left: auto; right: 28px; top: auto; bottom: -8px; transform: rotate(-45deg); border-left: 0; border-bottom: var(--rule) solid var(--ink); border-right: var(--rule) solid var(--ink); }
.start-tappy .bubble.above::before { right: 42px; }
.wordmark-sub { margin-top: 22px; font-weight: 800; font-stretch: 125%; font-size: 16px; letter-spacing: 0.5em; padding-left: 0.5em; color: var(--ink); }
.start-pitch { margin-top: 18px; font-size: clamp(18px, 2.2vw, 22px); color: var(--body); max-width: 34ch; text-wrap: balance; }
.start-cta { margin-top: 36px; min-height: 54px; padding: 8px 12px; border: 0; background: none; font: inherit; color: var(--ink); font-weight: 700; font-size: 18px; cursor: pointer; }
.start-cta kbd {
  display: inline-block; margin: 0 2px; padding: 2px 10px 4px; border: var(--rule) solid var(--ink); border-radius: 8px; background: var(--paper);
  box-shadow: 3px 3px 0 var(--ink); font: inherit; font-weight: 800; animation: hint-pulse 1.6s ease-in-out 1.4s infinite;
}
.start-cta kbd + kbd { animation-delay: 1.55s; }
.start-cta:hover kbd { background: var(--accent-tint); }
@keyframes hint-pulse {
  0%, 60%, 100% { transform: none; box-shadow: 3px 3px 0 var(--ink); }
  30% { transform: translate(2px, 2px); box-shadow: 1px 1px 0 var(--ink); }
}
.cta-tap { display: none; }
@media (hover: none) and (pointer: coarse) {
  .cta-keys { display: none; }
  .cta-tap {
    display: inline-block; padding: 14px 32px; border: var(--rule) solid var(--ink); border-radius: 12px; background: var(--accent); color: var(--on-accent);
    box-shadow: 4px 4px 0 var(--ink); font-weight: 800; font-size: 20px;
  }
}
.start-counts { margin-top: 10px; font-weight: 600; }
.start-counts:empty { display: none; }
.start-meta { margin-top: 18px; font-weight: 600; font-size: 15px; color: var(--muted); }
.start-meta:empty { display: none; }
/* Once the Daily is in, its result stands where the pitch was, so the screen reads as "done". */
.start-result {
  display: grid; justify-items: center; gap: 6px; margin-top: 18px; padding: 16px 28px 18px;
  border: var(--rule) solid var(--ink); border-radius: 14px; background: var(--paper); box-shadow: 5px 5px 0 var(--accent);
}
.start-result-score { font-weight: 800; font-stretch: 125%; font-size: clamp(36px, 5vw, 48px); line-height: 1; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; }
.start-result-line { font-weight: 700; font-size: 16px; color: var(--body); }
.start-result-links { display: flex; flex-wrap: wrap; justify-content: center; gap: 10px 12px; margin-top: 12px; }
.start-result-open {
  min-height: 40px; padding: 8px 14px; border: var(--rule) solid var(--ink); border-radius: 9px; background: var(--paper); color: var(--ink);
  font: inherit; font-weight: 800; font-size: 14px; box-shadow: 3px 3px 0 var(--ink); cursor: pointer;
  transition: transform 80ms ease, box-shadow 80ms ease, background 80ms ease;
}
.start-result-open:hover { background: var(--accent-tint); }
.start-result-open:active { transform: translate(3px, 3px); box-shadow: 0 0 0 var(--ink); }
@media (prefers-reduced-motion: reduce) { .start-result-open { transition: none; } }
/* Daily or practice: on the start result, in the round header, and the colour of a finished round. */
.run-chip { padding: 4px 9px; border: var(--rule) solid var(--ink); background: var(--paper); color: var(--ink); text-transform: uppercase; line-height: 1.2; }
.run-chip.is-daily { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
.run-chip:empty { display: none; }
body[data-run="practice"] .round-progress li.is-done { background: var(--ink); }
body[data-run="practice"] .round-progress li.is-current { border-color: var(--ink); color: var(--ink); }
body[data-run="practice"] .round-stage:focus-within { outline-color: var(--ink); }
body[data-run="practice"] .kb.mini .kb-key.is-lit { background: var(--ink); }
.sound-icon {
  position: absolute; top: 4px; right: var(--gutter); display: grid; place-items: center; width: 44px; height: 44px;
  border: var(--rule) solid var(--ink); border-radius: 10px; background: var(--paper); cursor: pointer;
}
.sound-icon svg { width: 22px; height: 22px; fill: none; stroke: var(--ink); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.sound-icon .icon-on { display: none; }
.sound-icon[data-on="true"] { background: var(--accent); }
.sound-icon[data-on="true"] svg { stroke: var(--on-accent); }
.sound-icon[data-on="true"] .icon-on { display: block; }
.sound-icon[data-on="true"] .icon-off { display: none; }
.sound-icon:hover { background: var(--accent-tint); }
.sound-icon[data-on="true"]:hover { background: var(--accent); }

/* ---------- Theme packs ---------- */
.pack-icon[aria-expanded="true"] { background: var(--accent-tint); }
.pack-panel {
  position: absolute; z-index: 5; top: calc(100% + 12px); right: 0; display: grid; gap: 4px; width: min(360px, calc(100vw - 2 * var(--gutter)));
  padding: 8px; border: var(--rule) solid var(--ink); border-radius: 14px; background: var(--paper); box-shadow: 4px 4px 0 var(--ink); text-align: left;
}
.pack-option {
  display: grid; grid-template-columns: 96px 1fr 22px; align-items: center; gap: 12px; min-height: 64px; padding: 6px; border: 0; border-radius: 10px;
  background: none; color: var(--ink); font: inherit; text-align: left; cursor: pointer;
}
.pack-option:hover { background: var(--accent-tint); }
.pack-option img { display: block; width: 96px; height: 64px; object-fit: cover; border: var(--rule) solid var(--ink); border-radius: 8px; }
.pack-option strong { display: block; font-weight: 800; font-size: 17px; }
.pack-blurb { display: block; margin-top: 2px; font-size: 14px; line-height: 1.3; color: var(--body); }
.pack-option svg { width: 22px; height: 22px; fill: none; stroke: var(--accent); stroke-width: 3; stroke-linecap: round; stroke-linejoin: round; opacity: 0; }
.pack-option[aria-checked="true"] { background: var(--accent-tint); box-shadow: inset 0 0 0 2px var(--accent); }
.pack-option[aria-checked="true"] svg { opacity: 1; }
.pack-option:focus-visible, .pack-icon:focus-visible { outline: 2.5px solid var(--accent); outline-offset: 2px; }

/* Ink paints its own paper full-screen behind the rounds, so the Codex paper backdrop steps aside. */
.ink-stage { position: fixed; inset: 0; z-index: -1; pointer-events: none; }
.ink-stage canvas { position: absolute; inset: 0; width: 100%; height: 100%; }
.ink-quiet { transition: opacity 500ms var(--ease-out); }
body.pack-ink::after { opacity: 0 !important; }
/* Between rounds the bloom fills the page, so Tappy and the coach sit on a paper card above it. */
body.pack-ink .game-screen.between:not([hidden]) {
  width: fit-content; max-width: 100%; margin-top: 24px; padding: 28px 32px;
  border: var(--rule) solid var(--ink); border-radius: 16px; background: rgb(255 255 255 / 0.92); box-shadow: 6px 6px 0 var(--ink);
}

/* The Long Page: a full typewriter skin. The sheet and typewriter are a fixed stage behind
   the game; the round's own header and race stay on top of it, and the sentence card steps aside. */
.lp-stage {
  --lp-mono: ui-monospace, "SF Mono", "Courier New", monospace; --lp-cream: #FAF4E2; --lp-pencil: #6F6C5C; --lp-ribbon: #D6322B;
  --lp-fs: 18px; --lp-lh: 34px; --lp-cw: 10.8px; --lp-left: 100px; --lp-text-w: 540px; --lp-key: 26px; --lp-key-gap: 5px; --lp-knob: 40px; --lp-tappy: 76px;
  position: fixed; left: 0; top: 0; width: 100%; z-index: -1; overflow: hidden; pointer-events: none;
}
html:has(body.pack-long-page) { overflow: hidden; overscroll-behavior: none; }
body.pack-long-page::after { opacity: 0 !important; }
body.pack-long-page .footer { display: none; }
body.pack-long-page .game { padding: 0; min-height: 0; }
.lp-stage canvas { position: absolute; left: 0; top: 0; width: 100%; height: 100%; }
.lp-env { z-index: 0; }
.lp-fx { z-index: 3; }
.lp-clip {
  position: absolute; inset: 0; z-index: 1;
  mask-image: linear-gradient(to bottom, transparent var(--lp-clear, 0px), #000 calc(var(--lp-clear, 0px) + 36px));
}
.lp-world {
  position: absolute; left: 0; top: 0; transform-origin: 0 0; will-change: transform;
  background-color: var(--lp-cream); box-shadow: 0 0 0 1.5px var(--ink), 6px 6px 0 var(--ink); transition: opacity 400ms var(--ease-out);
}
.lp-row { position: absolute; left: var(--lp-left); height: var(--lp-lh); font: var(--lp-fs)/var(--lp-lh) var(--lp-mono); white-space: pre; }
.lp-row.pending { visibility: hidden; }
.lp-c { display: inline-block; width: var(--lp-cw); text-align: center; color: var(--lp-pencil); }
.lp-row.head { font-weight: 700; }
.lp-row.head .lp-c { color: var(--ink); opacity: var(--o, 1); transform: translate(var(--dx, 0), var(--dy, 0)) rotate(var(--r, 0deg)); }
.lp-c.in {
  color: var(--ink); font-weight: 700; text-shadow: 0 0 0.5px rgb(14 14 16 / 0.6);
  opacity: var(--o); transform: translate(var(--dx), var(--dy)) rotate(var(--r)); transition: color 120ms ease-out, opacity 120ms ease-out;
}
/* The Ticker's chaser: a ribbon-red underline through the letters it has passed, a bar at its
   leading edge, and the letter it caught struck through. */
.lp-c.chased { box-shadow: inset 0 -2px 0 var(--lp-ribbon); }
.lp-c.caught { color: var(--lp-ribbon); font-weight: 700; text-decoration: line-through; text-decoration-thickness: 2px; }
.lp-chaser { position: absolute; left: 0; top: 0; z-index: 2; width: 3px; height: calc(var(--lp-lh) * 0.82); border-radius: 2px; background: var(--lp-ribbon); will-change: transform; }
.lp-chaser[hidden] { display: none; }
.lp-c.wrong { color: var(--lp-ribbon); font-weight: 700; text-shadow: 0.6px 0.4px 0 var(--lp-ribbon); opacity: var(--o); transform: translate(var(--dx), var(--dy)) rotate(var(--r)); }
.lp-cursor {
  position: absolute; width: 2.5px; border-radius: 1px; background: var(--accent); z-index: 2;
  transition: transform 70ms ease-out; animation: lp-pulse 1.1s ease-in-out infinite;
}
.lp-cursor.carriage { transition-duration: 380ms; transition-timing-function: cubic-bezier(0.2, 0.8, 0.2, 1); }
.lp-cursor::after { content: ""; position: absolute; left: -2px; right: -2px; bottom: -4px; height: 3px; border-radius: 2px; background: var(--lp-ribbon); opacity: 0; }
.lp-cursor.miss::after { animation: lp-miss 400ms ease-out; }
@keyframes lp-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }
@keyframes lp-miss { 0% { opacity: 1; transform: scaleX(2.6); } 100% { opacity: 0; transform: scaleX(1); } }
/* Each finished round's WPM, typed in the right margin beside its last row. */
.lp-wpm { position: absolute; height: var(--lp-lh); font: 700 12px/var(--lp-lh) var(--lp-mono); color: var(--ink); white-space: pre; }
/* The red marker: a ribbon-red tab on the paper's left edge, level with the line being typed. */
.lp-marker { position: absolute; left: 0; top: 0; z-index: 2; width: 0; height: 0; will-change: transform; transition: transform 260ms var(--ease-out); }
.lp-marker::before {
  content: ""; position: absolute; left: 7px; top: -8px; width: 16px; height: 16px; background: var(--lp-ribbon);
  clip-path: polygon(0 0, 62% 0, 100% 50%, 62% 100%, 0 100%); border-radius: 2px;
}
/* The typewriter, fixed at the bottom of the visible screen: the platen roller where the paper feeds in,
   a dark enamel body with a hint of ribbon, and rows of round ringed keys. */
.lp-machine { position: absolute; left: 0; right: 0; bottom: 0; height: var(--lp-machine-h, 200px); z-index: 4; }
.lp-platen {
  position: absolute; top: 0; left: 50%; width: var(--lp-bail-w, 900px); height: var(--lp-platen-h, 24px); transform: translateX(-50%);
  background: linear-gradient(to bottom, #4a4c55 0, #1b1c21 28%, var(--ink) 60%, #26272d 100%); border: 1.5px solid var(--ink); border-bottom: 0; border-radius: 12px 12px 0 0;
}
.lp-bail {
  position: absolute; top: -12px; left: 50%; width: var(--lp-bail-w, 900px); height: 10px; transform: translateX(-50%);
  background: var(--paper); border: 1.5px solid var(--ink); border-radius: 6px; box-shadow: 0 3px 0 var(--ink); z-index: 2;
}
.lp-knob {
  position: absolute; top: 50%; width: var(--lp-knob); height: var(--lp-knob); margin-top: calc(var(--lp-knob) / -2); border-radius: 50%;
  background: radial-gradient(circle at 36% 30%, rgb(255 255 255 / 0.45) 0 14%, transparent 15%), repeating-conic-gradient(rgb(0 0 0 / 0.14) 0 8deg, transparent 8deg 24deg), var(--accent);
  border: 2px solid var(--ink); box-shadow: 0 3px 0 var(--ink);
}
.lp-knob.left { left: calc(var(--lp-knob) / -1 - 8px); }
.lp-knob.right { right: calc(var(--lp-knob) / -1 - 8px); }
.lp-body {
  position: absolute; left: 0; right: 0; top: var(--lp-platen-h, 24px); bottom: 0; display: flex; align-items: flex-end; justify-content: center;
  background: linear-gradient(to bottom, #2c2d35 0, #1a1b20 40%, #0f1013 100%); border-top: 2px solid var(--ink);
  box-shadow: inset 0 2px 0 rgb(255 255 255 / 0.13), inset 0 -5px 0 var(--accent);
}
.lp-body::before { /* the ribbon: red over black, running behind the type bars */
  content: ""; position: absolute; left: 12%; right: 12%; top: 7px; height: 7px; border-radius: 4px; border: 1px solid #000;
  background: linear-gradient(to bottom, var(--lp-ribbon) 0 50%, #050506 50%);
}
.lp-keys { display: flex; flex-direction: column; align-items: center; gap: calc(var(--lp-key-gap) + 4px); padding-bottom: 12px; }
.lp-krow { display: flex; gap: calc(var(--lp-key-gap) + 8px); }
.lp-key {
  width: var(--lp-key); height: var(--lp-key); display: grid; place-items: center; border-radius: 50%; color: var(--ink);
  background: radial-gradient(circle at 36% 28%, #fff 0, var(--paper) 50%, #d9d3c0 100%);
  box-shadow: 0 0 0 2.5px #c9ccd3, 0 0 0 4px #000, 0 3px 0 4px #000; font: 700 11px/1 var(--lp-mono); text-transform: uppercase;
  transition: transform 90ms ease-out, box-shadow 90ms ease-out;
}
.lp-key.space { width: calc(var(--lp-key) * 5); height: calc(var(--lp-key) * 0.5); border-radius: 999px; }
.lp-key.down { transform: translateY(3px); box-shadow: 0 0 0 2.5px #c9ccd3, 0 0 0 4px #000, 0 0 0 4px #000; background: #d9d3c0; }
/* Tappy sits on the bail and bobs; the round screen's racers stay, the big Tappy is this one. */
.lp-tappy { position: absolute; z-index: 5; width: var(--lp-tappy); height: var(--lp-tappy); }
.lp-tappy .tappy { width: 100%; animation: lp-bob 2.8s ease-in-out infinite; }
@keyframes lp-bob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-4px); } }

/* The round's own header stays above the sheet, readable on its pieces of paper. */
body.pack-long-page .game-screen:not([hidden]) { position: fixed; left: 0; right: 0; top: calc(var(--lp-top, 0px) + 78px); z-index: 2; padding-inline: var(--gutter); }
body.pack-long-page .game-screen.round:not([hidden]) { display: block; min-height: 0; pointer-events: none; }
body.pack-long-page .game-screen.round .race-lane .racer, body.pack-long-page .round-input { pointer-events: auto; }
body.pack-long-page .game-screen.round > .label, body.pack-long-page .round-skill, body.pack-long-page .round-hint {
  width: fit-content; max-width: 100%; padding: 2px 8px; border-radius: 6px; background: var(--paper);
}
body.pack-long-page .game-screen.round > .label { margin-top: 10px; }
body.pack-long-page .round-stage { margin-top: 10px; padding: 0; min-height: 0; border: 0; border-radius: 0; box-shadow: none; background: none; }
body.pack-long-page .round-stage:focus-within { outline: 0; }
body.pack-long-page .race { margin: 0; padding: 10px 16px; border: var(--rule) solid var(--ink); border-radius: 12px; box-shadow: 4px 4px 0 var(--ink); background: var(--paper); }
body.pack-long-page .round-text { display: none; }
body.pack-long-page .round-hint { margin-top: 10px; text-align: left; }
/* Between rounds the sheet stays, dimmed, and the coach sits on a paper card above it. */
body.pack-long-page .game-screen.between:not([hidden]) {
  left: 50%; right: auto; width: fit-content; max-width: calc(100% - 2 * var(--gutter)); transform: translateX(-50%); padding: 28px 32px;
  border: var(--rule) solid var(--ink); border-radius: 16px; background: rgb(255 255 255 / 0.92); box-shadow: 6px 6px 0 var(--ink);
}
body.pack-long-page:has(.between:not([hidden])) .lp-world { opacity: 0.45; }
body.pack-long-page:has(.between:not([hidden])) .lp-tappy { display: none; }
@media (max-width: 599px) {
  .lp-key { font-size: 10px; box-shadow: 0 0 0 2px #c9ccd3, 0 0 0 3.5px #000, 0 2px 0 3.5px #000; }
  .lp-key.down { box-shadow: 0 0 0 2px #c9ccd3, 0 0 0 3.5px #000; transform: translateY(2px); }
  .lp-wpm { font-size: 10px; }
  .lp-marker::before { left: 3px; width: 13px; height: 13px; top: -6.5px; }
  body.pack-long-page .topbar { display: none; }
  body.pack-long-page .game-screen:not([hidden]) { top: calc(var(--lp-top, 0px) + 10px); }
  body.pack-long-page .game-screen.between:not([hidden]) { padding: 18px 16px; }
  body.pack-long-page .race { padding: 6px 12px; }
  body.pack-long-page .round-hint { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .lp-tappy .tappy, .lp-cursor { animation: none; }
  .lp-marker { transition: none; }
  .lp-stage * { transition-duration: 0s !important; transition-delay: 0s !important; }
}

/* ---------- Badges ---------- */
.badge-icon[aria-expanded="true"] { background: var(--accent-tint); }
.badge-icon:focus-visible, .badge-panel-close:focus-visible { outline: 2.5px solid var(--accent); outline-offset: 2px; }
.badge-panel {
  position: absolute; z-index: 5; top: calc(100% + 12px); right: 0; width: min(640px, calc(100vw - 2 * var(--gutter)));
  max-height: calc(100svh - 120px); overflow-y: auto; overscroll-behavior: contain; padding: 14px 16px 18px;
  border: var(--rule) solid var(--ink); border-radius: 14px; background: var(--paper); box-shadow: 4px 4px 0 var(--ink); text-align: left;
}
.badge-panel:focus { outline: none; }
.badge-panel-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 4px; }
.badge-panel-title { font-size: 22px; line-height: 1.1; }
.badge-panel-title span { margin-left: 6px; font-size: 16px; color: var(--muted); font-weight: 700; }
.badge-panel-close {
  min-height: 44px; padding: 0 14px; border: var(--rule) solid var(--ink); border-radius: 10px; background: var(--paper);
  font: inherit; font-weight: 700; cursor: pointer;
}
.badge-panel-close:hover { background: var(--accent-tint); }

/* Sound: key sounds on or off, and the wrong-key sound (mistake-sounds.js), like LocalFlow's cue pickers. */
.sound-panel { width: min(360px, calc(100vw - 2 * var(--gutter))); }
.sound-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-top: 12px; font-weight: 700; }
.mistake-sounds { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; margin: 8px 0 10px; }
.mistake-sounds button {
  min-height: 44px; padding: 0 12px; border: var(--rule) solid var(--ink); border-radius: 10px; background: var(--paper);
  font: inherit; font-weight: 700; text-align: left; cursor: pointer;
}
.mistake-sounds button:hover { background: var(--accent-tint); }
.mistake-sounds button[aria-checked="true"] { background: var(--ink); color: var(--paper); }
.sound-panel.is-off .mistake-sounds { opacity: .55; }

/* How to play: the rules, then one line per round from ROUND_PLAN (game.js). */
.help-panel { width: min(520px, calc(100vw - 2 * var(--gutter))); }
.help-rules { margin: 10px 0 0; padding-left: 20px; }
.help-rules li { margin-top: 8px; line-height: 1.45; }
.help-rules li::marker { color: var(--accent); }
.help-rounds-title { margin-top: 18px; font-size: 13px; font-weight: 800; letter-spacing: 0.08em; text-transform: uppercase; }
.help-rounds { display: grid; gap: 8px; margin: 8px 0 14px; padding: 0; list-style: none; counter-reset: help-round; }
.help-rounds li {
  display: grid; grid-template-columns: 30px 1fr; column-gap: 12px; align-items: start; padding: 8px 10px;
  border: var(--rule) solid var(--ink); border-radius: 10px; counter-increment: help-round;
}
.help-rounds li::before {
  content: counter(help-round); grid-row: span 2; display: grid; place-items: center; width: 30px; height: 30px;
  border-radius: 8px; background: var(--ink); color: var(--paper); font-weight: 800;
}
.help-rounds strong { line-height: 1.3; }
.help-rounds span { color: var(--muted); font-size: 14.5px; line-height: 1.35; }

.badge-family { margin-top: 16px; }
.badge-family-title { display: flex; align-items: baseline; gap: 10px; margin-bottom: 8px; font-size: 13px; font-weight: 800; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink); }
.badge-family-count { font-weight: 700; letter-spacing: 0; color: var(--muted); font-variant-numeric: tabular-nums; }
.badge-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; margin: 0; padding: 0; list-style: none; }
.badge-tile {
  --fam: var(--accent); --fam-tint: var(--accent-tint); --fam-ink: var(--on-accent);
  display: flex; align-items: flex-start; gap: 12px; padding: 10px 12px 10px 10px;
  border: var(--rule) solid var(--ink); border-radius: 12px; background: var(--paper);
}
.badge-tile[data-family="habit"] { --fam: var(--fast); --fam-tint: var(--fast-tint); }
.badge-tile[data-family="placement"] { --fam: var(--steady); --fam-tint: var(--steady-tint); --fam-ink: var(--ink); }
.badge-tile[data-family="accuracy"] { --fam: var(--ink); --fam-tint: var(--panel); --fam-ink: var(--paper); }
.badge-tile[data-family="early"] { --fam: var(--slow); --fam-tint: var(--slow-tint); }
.badge-tile[data-family="keyprint"] { --fam: var(--accent-deep); --fam-tint: var(--accent-tint); }
.badge-key {
  flex-shrink: 0; display: grid; place-items: center; width: 48px; height: 48px;
  border: var(--rule) solid var(--ink); border-radius: 10px; background: var(--fam); box-shadow: 2px 2px 0 var(--ink);
}
.badge-key svg { width: 26px; height: 26px; fill: none; stroke: var(--fam-ink); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.badge-tile[data-tier="1"] .badge-key, .badge-tile[data-tier="2"] .badge-key { background: var(--fam-tint); }
.badge-tile[data-tier="1"] .badge-key svg, .badge-tile[data-tier="2"] .badge-key svg { stroke: var(--ink); }
.badge-text { display: grid; gap: 2px; min-width: 0; }
.badge-name { font-weight: 800; font-size: 16px; line-height: 1.2; }
.badge-line { font-size: 13px; line-height: 1.35; color: var(--body); }
.badge-meta { font-size: 13px; font-weight: 700; color: var(--accent); font-variant-numeric: tabular-nums; }
.badge-pips { display: flex; gap: 4px; margin-top: 4px; }
.badge-pips i { width: 9px; height: 9px; border: 1.5px solid var(--ink); border-radius: 3px; background: var(--paper); }
.badge-pips i.on { background: var(--fam); }
/* Locked: outline only, dimmed. */
.badge-tile.is-locked { border-color: var(--quiet); background: none; }
.badge-tile.is-locked .badge-key { background: none; border-color: var(--quiet); box-shadow: none; }
.badge-tile.is-locked .badge-key svg { stroke: var(--quiet); }
.badge-tile.is-locked .badge-name { color: var(--muted); }
.badge-tile.is-locked .badge-line, .badge-tile.is-locked .badge-meta { color: var(--muted); }
.badge-tile.is-locked .badge-pips i { border-color: var(--quiet); background: none; }

/* The board: badges as keycaps, staggered like the Keyprint. Earned caps are solid in the family
   colour with the glyph; locked caps are blank outlines, so the gaps show what's left to earn. */
.badge-views { margin: 10px 0 14px; }
.badge-board { display: grid; gap: 8px; justify-content: center; padding: 16px 8px 10px; }
.badge-board-row { display: flex; gap: 8px; justify-content: center; }
.badge-board-row:nth-child(2) { padding-left: 22px; }
.badge-board-row:nth-child(3) { padding-left: 52px; }
.badge-board-row:nth-child(4) { padding-left: 0; }
.badge-cap {
  --fam: var(--accent); --fam-tint: var(--accent-tint); --fam-ink: var(--on-accent);
  display: grid; place-items: center; width: 50px; height: 50px; padding: 0; border: var(--rule) solid var(--ink); border-radius: 10px;
  background: var(--fam); color: var(--fam-ink); box-shadow: 3px 3px 0 var(--ink); cursor: pointer;
  transition: transform 80ms ease, box-shadow 80ms ease;
}
.badge-cap[data-family="habit"] { --fam: var(--fast); --fam-tint: var(--fast-tint); }
.badge-cap[data-family="placement"] { --fam: var(--steady); --fam-tint: var(--steady-tint); --fam-ink: var(--ink); }
.badge-cap[data-family="accuracy"] { --fam: var(--ink); --fam-tint: var(--panel); --fam-ink: var(--paper); }
.badge-cap[data-family="early"] { --fam: var(--slow); --fam-tint: var(--slow-tint); }
.badge-cap[data-family="keyprint"] { --fam: var(--accent-deep); --fam-tint: var(--accent-tint); }
.badge-cap[data-tier="1"], .badge-cap[data-tier="2"] { background: var(--fam-tint); --fam-ink: var(--ink); }
.badge-cap svg { width: 26px; height: 26px; fill: none; stroke: var(--fam-ink); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.badge-cap:hover, .badge-cap:focus-visible { transform: translate(1px, 1px); box-shadow: 2px 2px 0 var(--ink); }
.badge-cap:active { transform: translate(3px, 3px); box-shadow: 0 0 0 var(--ink); }
.badge-cap.is-locked { background: var(--paper); border-color: var(--quiet); box-shadow: 3px 3px 0 var(--quiet); }
.badge-cap.is-locked svg { stroke: var(--quiet); }
.badge-board-caption { min-height: 2.6em; margin-top: 6px; padding: 0 4px; text-align: center; font-size: 14px; font-weight: 600; color: var(--body); text-wrap: balance; }
@media (max-width: 600px) {
  .badge-board { gap: 6px; padding: 10px 0 6px; }
  .badge-board-row { gap: 5px; }
  .badge-board-row:nth-child(2) { padding-left: 16px; }
  .badge-board-row:nth-child(3) { padding-left: 36px; }
  .badge-cap { width: 30px; height: 36px; border-radius: 7px; box-shadow: 2px 2px 0 var(--ink); }
  .badge-cap.is-locked { box-shadow: 2px 2px 0 var(--quiet); }
  .badge-cap svg { width: 18px; height: 18px; }
}
@media (prefers-reduced-motion: reduce) { .badge-cap { transition: none; } }

/* The unlock beat, at the top of the stats page. */
.badge-beat {
  margin-top: 18px; padding: 22px 24px; border: var(--rule) solid var(--ink); border-radius: 16px; background: var(--accent-tint);
  box-shadow: 6px 6px 0 var(--ink); animation: beat-in 420ms var(--ease-out) both;
}
.badge-beat-title { font-size: clamp(24px, 4vw, 34px); line-height: 1.05; }
.badge-beat-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 12px; margin: 16px 0 0; padding: 0; list-style: none; }
.badge-beat .badge-tile { animation: badge-pop 520ms var(--ease-out) calc(var(--i, 0) * 110ms + 140ms) both; }
.badge-beat-tappy { margin-top: 18px; }
.badge-beat .button { margin-top: 18px; }
.badge-beat.is-settled .button { display: none; }
.placement.is-held { visibility: hidden; }
@keyframes beat-in { from { opacity: 0; transform: translateY(-10px); } }
@keyframes badge-pop { from { opacity: 0; transform: translateY(16px) scale(0.92); } }

@media (max-width: 600px) {
  .badge-panel {
    position: fixed; z-index: 20; top: auto; right: 0; bottom: 0; left: 0; width: auto; max-height: 78svh; padding: 14px var(--gutter) 24px;
    border-width: var(--rule) 0 0; border-radius: 16px 16px 0 0; box-shadow: 0 0 0 100vmax rgb(14 14 16 / 0.4);
  }
  .badge-grid { grid-template-columns: 1fr; }
  .badge-beat { padding: 18px 16px; }
}

/* ---------- Round ---------- */
.game-screen.round { max-width: 860px; }
.game-screen.round:not([hidden]) { display: flex; flex-direction: column; justify-content: center; min-height: calc(100svh - 300px); }
.round-head { display: flex; align-items: center; gap: 20px; }
.round-progress { display: flex; gap: 8px; margin: 0; padding: 0; list-style: none; }
.round-progress li {
  display: grid; place-items: center; width: 34px; height: 34px; border: var(--rule) solid var(--ink); border-radius: 8px;
  background: var(--paper); font-weight: 800; font-size: 14px; color: var(--muted);
}
.round-progress li.is-done { background: var(--accent); border-color: var(--ink); color: var(--on-accent); box-shadow: 2px 2px 0 var(--ink); }
.round-progress li.is-current { border-color: var(--accent); border-width: 2.5px; color: var(--accent); }
.round-clock {
  min-width: 3.2ch; padding: 2px 12px; border: var(--rule) solid var(--ink); border-radius: 10px; text-align: center;
  font-weight: 800; font-stretch: 125%; font-size: 26px; line-height: 1.3;
}
.round-stage .label, .game-screen.round > .label { margin-top: 18px; }
.round-skill { margin-top: 4px; color: var(--muted); font-weight: 600; }
.round-stage {
  position: relative; margin-top: 24px; padding: 28px 36px 40px; min-height: 280px;
  border: var(--rule) solid var(--ink); border-radius: 14px; box-shadow: 5px 5px 0 var(--ink); background: var(--paper);
}
.round-stage:focus-within { outline: 2.5px solid var(--accent); outline-offset: 4px; }
/* The race above the sentence: you and today's typical typist (a grey ghost), moved by script. */
.race { display: grid; gap: 6px; margin-bottom: 26px; }
.race-lane { display: flex; align-items: center; gap: 12px; }
.race-label { width: 4.6em; flex-shrink: 0; font-size: 12px; font-weight: 800; letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted); }
.race-track { position: relative; flex: 1; height: 26px; border-bottom: var(--rule) solid var(--ink); }
.racer { position: absolute; bottom: 2px; left: calc(var(--p, 0) * (100% - 26px)); width: 26px; height: 26px; }
.racer svg { display: block; width: 100%; height: 100%; overflow: visible; }
.racer .tappy { width: 100%; }
.race-lane:not(.is-ghost) .racer { transition: left 140ms var(--ease-out); }
.race-lane.is-ghost .racer { opacity: 0.45; filter: grayscale(1); }
.race-lane.is-ghost .race-track { border-bottom-color: var(--quiet); border-bottom-style: dashed; }
.race-lane[hidden] { display: none; }
.round-text { font-size: clamp(22px, 3vw, 38px); line-height: 1.55; font-weight: 600; color: var(--muted); overflow-wrap: anywhere; }
.round-text .done { color: var(--accent); }
/* Round 4, the Ticker: one line that slides left and speeds up (game.js stepTicker, ticker.js). */
.ticker[hidden], .race[hidden], .round-text[hidden] { display: none; }
.ticker-speed { display: flex; align-items: center; gap: 10px; margin: 0 0 14px; font-weight: 800; font-variant-numeric: tabular-nums; }
.ticker-speed b { font-size: 26px; transition: color 300ms; }
.ticker-speed.is-bumped b { color: var(--call); }
.ticker-bar { flex: 1; height: 8px; border-radius: 4px; background: var(--panel); overflow: hidden; }
.ticker-bar > span { display: block; width: 0; height: 100%; background: var(--accent); transition: width 300ms var(--ease-out); }
.ticker-track { position: relative; height: 84px; overflow: hidden; border-block: var(--rule) dashed var(--quiet); }
.ticker-strip {
  position: absolute; top: 50%; left: 0; margin: 0; white-space: pre; translate: 0 -50%; will-change: transform;
  font-size: clamp(20px, 2.6vw, 32px); font-weight: 600; color: var(--muted);
}
.ticker-strip .done { color: var(--accent); }
.ticker-strip .current { color: var(--ink); background: var(--accent-tint); box-shadow: inset 0 -3px 0 var(--accent); }
.ticker-strip .current.wrong { background: var(--warn-fill); box-shadow: inset 0 -3px 0 var(--warn-text); }
/* TICKER.deadline in ticker.js: keep the two at 12%. */
.ticker-deadline { position: absolute; inset-block: 0; left: 12%; width: 3px; background: var(--warn-text); opacity: 0.5; }
/* The Long Page draws its own sheet; for round 4 it steps aside and the Ticker gets the usual card. */
/* One line, not a paragraph: the card fits it, and goes as wide as the page so more of it shows. */
body[data-round="ticker"] .round-stage { min-height: 0; }
body[data-round="ticker"] .game-screen.round { max-width: 1180px; }
@media (max-width: 600px) { body[data-round="ticker"] .round-stage { padding: 18px 12px; } }
/* On a theme that types the Ticker onto its own page (the Long Page), only the speed readout shows
   here: the page draws the text and the chaser (packs/long-page.js chase). */
body[data-round="ticker-page"] .ticker-track { display: none; }
body.pack-long-page .ticker-speed {
  margin: 0; padding: 10px 16px; border: var(--rule) solid var(--ink); border-radius: 12px; box-shadow: 4px 4px 0 var(--ink); background: var(--paper);
}
.round-text .current { color: var(--ink); background: var(--accent-tint); box-shadow: inset 0 -3px 0 var(--accent); }
.round-text .wrong { color: var(--slow-text); }
.round-text .missed { color: var(--slow-text); text-decoration: line-through; text-decoration-thickness: 2px; }
/* Covers the stage so a tap anywhere focuses it and opens a phone's keyboard; invisible on top. */
.round-input {
  position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; border: 0; padding: 0;
  font-size: 16px; /* stops iOS zooming in on focus */ caret-color: transparent; cursor: text;
}
/* The hint keeps one fixed-height slot whatever it says, so a hint appearing never moves the
   (vertically centred) round screen under the typist. */
.round-hint {
  box-sizing: border-box; width: fit-content; max-width: 100%; height: 28px; margin: 14px auto 0; padding: 0 10px;
  border-radius: 7px; line-height: 28px; text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  transition: opacity 300ms var(--ease-out), background-color 200ms;
}
.round-hint.is-quiet { opacity: 0; }
/* Why the cursor won't move (hint.js), e.g. "Capital letter: hold Shift and press T". */
.round-hint.is-stuck { background: var(--warn-fill); color: var(--warn-text); font-size: 14px; font-weight: 700; }

/* ---------- Keyboards (between rounds and the Keyprint) ---------- */
.kb { display: grid; gap: 6px; justify-content: center; }
.kb-row { display: flex; gap: 6px; justify-content: center; }
/* Five rows: numbers, then the three letter rows stepping right as on a real board, then Space. */
.kb-row:nth-child(2) { padding-left: 22px; }
.kb-row:nth-child(3) { padding-left: 40px; }
.kb-row:nth-child(4) { padding-left: 68px; }
.kb-key {
  display: grid; place-items: center; width: 44px; height: 44px; border: var(--rule) solid var(--ink); border-radius: 8px;
  font-weight: 800; font-size: 15px; background: var(--paper); box-shadow: 2px 2px 0 var(--ink);
}
.kb-key.is-space { width: 296px; font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase; }
/* A key with a shifted character shows both, the shifted one small on top. */
.kb-key.is-pair { grid-template-rows: auto auto; align-content: center; gap: 1px; line-height: 1; }
.kb-key.is-pair i { font-style: normal; font-size: 10px; font-weight: 700; opacity: 0.75; }
.kb-key.is-pair b { font-size: 14px; }
.kb.mini .kb-row:nth-child(1), .kb.mini .kb-row:nth-child(5) { display: none; } /* between rounds: letters only, as before */
.kb.mini .kb-row:nth-child(2) { padding-left: 0; }
.kb.mini .kb-row:nth-child(3) { padding-left: 18px; }
.kb.mini .kb-row:nth-child(4) { padding-left: 46px; }
.kb.mini .kb-key:is([data-key=";"], [data-key="'"], [data-key=","], [data-key="."], [data-key="/"]) { display: none; }
.kb.mini .kb-key { color: var(--muted); border-color: var(--quiet); box-shadow: none; transition: background 300ms ease, color 300ms ease, border-color 300ms ease; transition-delay: calc(var(--key) * 18ms); }
.kb.mini .kb-key.is-lit { background: var(--accent); color: var(--on-accent); border-color: var(--ink); }
.kb-key.is-green { background: var(--fast-tint); border-color: var(--fast); color: var(--fast-text); }
.kb-key.is-amber { background: var(--steady-tint); border-color: var(--steady); color: var(--steady-text); }
.kb-key.is-red { background: var(--slow-tint); border-color: var(--slow); color: var(--slow-text); }
.kb-key.is-grey { background: var(--panel); border-color: var(--quiet); color: var(--muted); box-shadow: none; }
.between { display: grid; justify-items: center; gap: 36px; padding-top: 40px; }
.between-row { display: flex; align-items: center; gap: 20px; max-width: 640px; }
.between-talk { display: grid; gap: 14px; justify-items: start; }
.between-talk .bubble { max-width: 44ch; }
.between-line { font-weight: 800; font-stretch: 125%; font-size: clamp(24px, 4vw, 34px); line-height: 1.1; }
.between-next-row { display: flex; align-items: center; gap: 14px; }
.between-keys { font-size: 14px; color: var(--muted); }
@media (hover: none) and (pointer: coarse) { .between-keys { display: none; } }

/* ---------- Missing day ---------- */
.missing .tappy-line { margin-bottom: 28px; }
.mac-link { display: inline-flex; align-items: center; min-height: 44px; margin-top: 12px; font-weight: 700; }

/* ---------- Stats ---------- */
.stats-title #stats-title { color: var(--ink); }
.stats-title { font-size: clamp(22px, 3.4vw, 30px); line-height: 1.1; letter-spacing: -0.01em; display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; }
.practice-chip { background: var(--ink); color: var(--paper); align-self: center; }
.placement { margin-top: 18px; padding: 28px 24px 22px; border: var(--rule) solid var(--ink); border-radius: 16px; box-shadow: 6px 6px 0 var(--accent); }
.placement-rank { font-weight: 800; font-stretch: 125%; font-size: clamp(52px, 11vw, 104px); line-height: 0.95; letter-spacing: -0.03em; }
.placement-of { margin-top: 10px; font-size: 20px; font-weight: 700; }
.placement.is-unavailable .placement-of { margin-top: 0; font-weight: 800; font-stretch: 125%; font-size: clamp(24px, 4vw, 34px); line-height: 1.1; }
.placement-top { margin-top: 8px; display: inline-block; padding: 4px 12px; border-radius: 999px; background: var(--accent); color: var(--on-accent); font-weight: 800; }
.placement-top:empty { display: none; }
.placement-curve { display: block; width: 100%; height: auto; margin-top: 18px; overflow: visible; }
.placement-curve .curve-area { fill: var(--accent-tint); }
.placement-curve .curve-line { fill: none; stroke: var(--accent); stroke-width: 2.5; stroke-dasharray: 2000; stroke-dashoffset: 0; animation: draw-curve 1.2s ease-out 0.4s both; }
.placement-curve .curve-axis { stroke: var(--ink); stroke-width: 1.5; }
.placement-curve .curve-marker line { stroke: var(--ink); stroke-width: 1.5; stroke-dasharray: 4 4; }
.placement-curve .curve-marker circle { fill: var(--accent); stroke: var(--ink); stroke-width: 2; }
.placement-curve .curve-marker { animation: drop-marker 500ms cubic-bezier(.3, 1.4, .5, 1) 1.4s both; }
.curve-wrap { position: relative; margin-top: 18px; padding-top: 24px; }
.curve-wrap .placement-curve { margin-top: 0; }
.curve-you { position: absolute; top: 0; font-weight: 800; font-size: 13px; letter-spacing: 0.08em; line-height: 1; animation: fade-in 400ms ease-out 1.5s both; }
.curve-captions { display: flex; justify-content: space-between; margin-top: 8px; font-size: 13px; font-weight: 600; color: var(--muted); }
.placement-note { margin-top: 12px; font-size: 14px; }
.placement-note:empty { display: none; }
.placement-tappy { margin-top: 18px; padding-top: 18px; border-top: 1px solid var(--hairline); }
@keyframes draw-curve { from { stroke-dashoffset: 2000; } }
@keyframes fade-in { from { opacity: 0; } }
@keyframes drop-marker { from { transform: translateY(-24px); opacity: 0; } }

.headline-wrap { position: relative; margin-top: 28px; }
.headline { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); border: var(--rule) solid var(--ink); border-radius: 12px; overflow: hidden; }
.headline > div { position: relative; padding: 14px 16px; }
.headline > div + div { border-left: 1px solid var(--hairline); }
.headline > div.is-score { background: var(--accent-tint); }
.headline dt { font-size: 12px; font-weight: 800; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); }
.headline dd { margin: 4px 0 0; font-weight: 800; font-stretch: 125%; font-size: 26px; line-height: 1.1; overflow-wrap: anywhere; }
/* ---------- Rhythm and the pace chart ---------- */
.rhythm-headline { grid-template-columns: repeat(2, minmax(0, 1fr)); max-width: 420px; }
.pace { margin-top: 18px; }
.pace-plot { padding-top: 22px; }
.pace-bar { fill: var(--accent-tint); stroke: var(--accent); stroke-width: 1; }
.pace-bar.has-slip { fill: var(--slow-tint); stroke: var(--slow); }
.pace-slip { fill: var(--slow); }
.pace-line { fill: none; stroke: var(--ink); stroke-width: 2; stroke-linejoin: round; }
.pace-divider { stroke: var(--muted); stroke-width: 1; stroke-dasharray: 3 4; }
.pace-rounds { position: absolute; top: 0; left: 0; right: 0; height: 20px; }
.pace-rounds span {
  position: absolute; top: 0; min-width: 18px; padding: 1px 5px; border: var(--rule) solid var(--ink); border-radius: 5px; background: var(--paper);
  font-size: 11px; font-weight: 800; line-height: 1.2; text-align: center;
}
.pace-scale { position: absolute; top: 24px; right: 0; font-size: 11px; font-weight: 700; color: var(--muted); }
.pace-plot .progress-callout { top: 26px; } /* under the round numbers, so hovering never hides them */
.pace-legend i.is-bar { width: 12px; height: 12px; border-radius: 3px; border: 1.5px solid var(--accent); background: var(--accent-tint); }
.pace-legend i.is-line { width: 16px; height: 0; border-radius: 0; border: 0; border-top: 2px solid var(--ink); background: none; }
.pace-legend i.is-slip { width: 10px; height: 10px; border: 0; background: var(--slow); }
.score-note { margin-top: 12px; font-size: 14px; line-height: 1.5; color: var(--muted); text-wrap: pretty; }
.score-note:empty { display: none; }
.new-best {
  display: inline-block; margin-left: 8px; padding: 2px 7px; vertical-align: 0.4em; border-radius: 6px; background: var(--ink); color: var(--paper);
  font-weight: 800; font-stretch: 125%; font-size: 11px; letter-spacing: 0.08em; line-height: 1.3;
}
.burst-key {
  position: absolute; z-index: 3; width: 14px; height: 14px; border: var(--rule) solid var(--ink); border-radius: 4px;
  background: var(--accent); pointer-events: none;
}
.burst-key.paper { background: var(--paper); }

.keepsake-card { display: grid; gap: 16px; justify-items: start; margin: 0; }
.keepsake-art { width: 100%; }
.keepsake-art canvas { display: block; width: 100%; height: auto; border: 1px solid var(--hairline); border-radius: 4px; box-shadow: 6px 6px 0 var(--ink); }

.stats-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 16px; margin-top: 28px; }
.retain { flex-basis: 100%; display: flex; align-items: center; gap: 8px; font-weight: 700; }
.retain svg { width: 24px; height: 24px; flex-shrink: 0; }
.retain [data-next-daily] { font-variant-numeric: tabular-nums; font-weight: 800; color: var(--accent); }
.share-status { flex-basis: 100%; white-space: pre-line; }
.share-status:empty { display: none; }

.stats-block { margin-top: 52px; }
.stats-heading { font-size: 26px; line-height: 1; margin-bottom: 18px; }
.narrator { margin-bottom: 20px; gap: 14px; }
.narrator .tappy { width: 56px; }
.narrator h2.bubble { margin: 0; font-stretch: 100%; }
.stats-block .headline-wrap { margin-top: 0; }
.stats-block .keyprint { margin-top: 26px; }
.stats-block .rounds-table { margin-top: 26px; }
.keyprint-legend { display: flex; flex-wrap: nowrap; justify-content: center; gap: 6px 16px; margin-top: 16px; font-size: 13px; color: var(--body); }
.keyprint-legend li { display: inline-flex; align-items: center; gap: 6px; }
.swatch { width: 14px; height: 14px; border-radius: 4px; border: var(--rule) solid; }
.swatch.is-green { background: var(--fast-tint); border-color: var(--fast); }
.swatch.is-amber { background: var(--steady-tint); border-color: var(--steady); }
.swatch.is-red { background: var(--slow-tint); border-color: var(--slow); }
.swatch.is-grey { background: var(--panel); border-color: var(--quiet); }

.fix-three { margin: 0; padding: 0; list-style: none; border-top: var(--rule) solid var(--ink); }
.fix-three li { display: grid; grid-template-columns: auto 1fr; gap: 2px 16px; align-items: start; padding: 14px 4px; border-bottom: 1px solid var(--hairline); }
.fix-three .fix-label { grid-row: span 2; min-width: 56px; padding: 8px 10px; text-align: center; border: var(--rule) solid var(--slow); border-radius: 8px; background: var(--slow-tint); color: var(--slow-text); font-weight: 800; font-size: 18px; }
.fix-three .fix-numbers { font-weight: 700; }
.fix-three .fix-tip { color: var(--body); font-size: 15px; }
.fix-three:empty { display: none; }
.fix-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 16px; margin-top: 18px; }
.fix-actions .fineprint { flex: 1 1 260px; }
/* The drill's end: the three lines against the run they came from. */
.drill-end .stats-title { margin-bottom: 18px; }
.drill-tappy { margin-bottom: 22px; }
.drill-results { margin: 0; padding: 0; list-style: none; border-top: var(--rule) solid var(--ink); }
.drill-results li { display: grid; grid-template-columns: auto 1fr; gap: 2px 16px; align-items: start; padding: 14px 4px; border-bottom: 1px solid var(--hairline); }
.drill-results .fix-label { grid-row: span 2; min-width: 56px; padding: 8px 10px; text-align: center; border: var(--rule) solid var(--ink); border-radius: 8px; background: var(--accent-tint); font-weight: 800; font-size: 18px; }
.drill-results .fix-numbers { font-weight: 700; }
.drill-results .fix-tip { color: var(--body); font-size: 15px; }
body[data-run="drill"] .round-progress li.is-done { background: var(--ink); }
body[data-run="drill"] .round-progress li.is-current { border-color: var(--ink); color: var(--ink); }
body[data-run="drill"] .round-stage:focus-within { outline-color: var(--ink); }
body[data-run="drill"] .kb.mini { display: none; }

.rounds-table { width: 100%; border-collapse: collapse; }
.rounds-table th, .rounds-table td { padding: 11px 8px; text-align: left; border-bottom: 1px solid var(--hairline); }
.rounds-table th { font-size: 12px; font-weight: 800; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); border-bottom: var(--rule) solid var(--ink); }
.rounds-table td:not(:first-child), .rounds-table th:not(:first-child) { text-align: right; }

.logbook { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; }
.logbook dt { font-size: 12px; font-weight: 800; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); }
.logbook dd { margin: 2px 0 0; font-weight: 800; font-size: 24px; }
.logbook .is-streak dd { color: var(--accent); }
/* ---------- Progress chart ---------- */
.progress { margin-top: 20px; }
.progress-metrics { margin-bottom: 14px; }
.progress-plot { position: relative; }
.progress-svg { display: block; width: 100%; height: auto; overflow: visible; }
.progress-grid { stroke: var(--hairline); stroke-width: 1; }
.progress-axis { stroke: var(--ink); stroke-width: 1.5; }
.progress-best { stroke: var(--accent); stroke-width: 1.5; stroke-dasharray: 4 5; opacity: 0.7; }
.progress-best-label { position: absolute; right: 0; transform: translateY(-110%); font-size: 12px; font-weight: 800; letter-spacing: 0.04em; color: var(--accent); }
.progress-line { fill: none; stroke: var(--ink); stroke-width: 2; stroke-linejoin: round; }
.progress-dot { fill: var(--ink); stroke: var(--paper); stroke-width: 1.5; }
.progress-dot.is-today { fill: var(--accent); }
.progress-practice { fill: var(--paper); stroke: var(--ink); stroke-width: 1.5; }
.progress-guide { stroke: var(--ink); stroke-width: 1; stroke-dasharray: 3 3; opacity: 0.6; }
.progress-guide[hidden] { display: none; }
.progress-callout {
  position: absolute; top: -8px; z-index: 2; padding: 4px 8px; border: var(--rule) solid var(--ink); border-radius: 6px; background: var(--paper);
  box-shadow: 2px 2px 0 var(--ink); font-size: 12.5px; font-weight: 700; white-space: nowrap; pointer-events: none;
}
.progress-captions { display: flex; justify-content: space-between; gap: 12px; margin-top: 8px; font-size: 12.5px; font-weight: 600; color: var(--muted); }
.progress-legend { display: flex; flex-wrap: wrap; gap: 6px 16px; margin-top: 10px; font-size: 13px; color: var(--body); }
.progress-legend li { display: inline-flex; align-items: center; gap: 6px; }
.progress-legend i { display: inline-block; width: 12px; height: 12px; border-radius: 50%; border: 1.5px solid var(--ink); background: var(--ink); }
.progress-legend i.is-practice { background: var(--paper); }
.progress-legend i.is-best { width: 16px; height: 0; border-radius: 0; border: 0; border-top: 2px dashed var(--accent); background: none; }
.progress-empty { margin-top: 12px; font-size: 14px; color: var(--muted); }
.progress-panel .logbook { margin-top: 12px; }
.progress-save { margin-top: 20px; padding-top: 16px; border-top: 1px solid var(--hairline); display: grid; gap: 10px; }
.progress-save .fineprint:empty { display: none; }

.mac-card { margin-top: 48px; padding: 24px; border: var(--rule) solid var(--ink); border-radius: 16px; background: var(--accent-tint); box-shadow: 6px 6px 0 var(--ink); }
.mac-card p { margin-top: 8px; color: var(--body); }
.mac-card p.fineprint { color: var(--muted); }
.mac-card .stats-heading { margin-bottom: 0; }
.mac-card-art { display: flex; align-items: flex-end; gap: 14px; margin-bottom: 18px; }
.mac-card-art .tappy { margin-bottom: -2px; }
.menubar {
  flex: 1; display: flex; align-items: center; gap: 10px; min-width: 0; height: 30px; padding: 0 10px;
  border: var(--rule) solid var(--ink); border-radius: 8px; background: var(--paper);
}
.menubar-item { width: 34px; height: 8px; border-radius: 4px; background: var(--hairline); }
.menubar-item.short { width: 20px; }
.menubar-spacer { flex: 1; }
.menubar-cap { width: 22px; height: 22px; padding: 1px; border-radius: 6px; background: var(--accent-tint); box-shadow: 0 0 0 1.5px var(--accent); }
.mac-card .waitlist { margin-top: 16px; }

.daily-footer .footer-base::before { display: none; }
.daily-footer .footer-base { padding-top: 10px; padding-bottom: 10px; font-size: 12.5px; }

@media (max-width: 600px) {
  :root { --gutter: 20px; }
  .game { padding-top: 24px; min-height: calc(100svh - 59px - 40px); }
  .tappy.big { width: 72px; }
  .tappy-line { gap: 14px; }
  .wordmark-row { gap: 8px; margin-top: 108px; }
  .start-tappy { transform: translateY(-26px); }
  .game-screen.start:not([hidden]) { min-height: calc(100svh - 148px); }
  .wordmark-keys { gap: 6px; --cap: min(64px, calc((100vw - 2 * var(--gutter) - 92px) / 5)); }
  .wordmark-cap { box-shadow: 4px 4px 0 var(--ink); }
  .start-tappy .tappy.big { width: 62px; }
  .start-tappy .bubble.above::before { right: 24px; }
  /* Phones can't install the Mac app, so the nav keeps just the icons, closer together so all five fit at 390px. */
  .daily-page .topbar-mac { display: none; }
  .topbar-tools { gap: 6px; }
  .footer-promise { display: none; }
  .bubble.above { max-width: 250px; font-size: 15px; white-space: normal; }
  .keyprint-legend { gap: 6px 12px; font-size: 12px; }
  .race-label { width: 4.2em; }
  .sound-icon { top: 0; }
  .pack-panel { top: 52px; }
  .pack-option { grid-template-columns: 72px 1fr 22px; }
  .pack-option img { width: 72px; height: 48px; }
  body.pack-ink .game-screen.between:not([hidden]) { width: 100%; padding: 18px 10px; gap: 24px; }
  body.pack-ink .between .kb-key { width: 28px; }
  body.pack-ink .between-row { gap: 12px; }
  .between-line { font-size: 22px; }
  .bubble { font-size: 16px; padding: 10px 14px; }
  .headline { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .headline > div:nth-child(odd) { border-left: 0; }
  .headline > div:nth-child(n + 3) { border-top: 1px solid var(--hairline); }
  .headline dd { font-size: 22px; }
  .logbook { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .kb-key { width: 25px; height: 36px; font-size: 12px; border-radius: 5px; }
  .kb-key.is-space { width: 170px; font-size: 9px; }
  .kb-key.is-pair i { font-size: 8px; }
  .kb-key.is-pair b { font-size: 11px; }
  .kb, .kb-row { gap: 3px; }
  .kb-row:nth-child(2) { padding-left: 14px; }
  .kb-row:nth-child(3) { padding-left: 26px; }
  .kb-row:nth-child(4) { padding-left: 44px; }
  .kb.mini .kb-key { width: 30px; height: 40px; font-size: 13px; }
  .kb.mini .kb-row:nth-child(2) { padding-left: 0; }
  .kb.mini .kb-row:nth-child(3) { padding-left: 12px; }
  .kb.mini .kb-row:nth-child(4) { padding-left: 30px; }
  .round-stage { padding: 22px 18px; min-height: 200px; }
  .game-screen.round:not([hidden]) { justify-content: flex-start; min-height: 0; }
  .round-progress li { width: 30px; height: 30px; }
  .placement { padding: 22px 16px 16px; }
  .button.big { width: 100%; }
  .stats-actions .button { flex: 1 1 100%; }
  .mac-card { padding: 20px 16px; }
}

@media (prefers-reduced-motion: reduce) {
  .placement-curve .curve-line, .placement-curve .curve-marker, .curve-you { animation: none; }
  .badge-beat, .badge-beat .badge-tile { animation: none; }
  .kb.mini .kb-key { transition: none; transition-delay: 0s; }
  .tappy svg { transition: none; }
  .wordmark-cap, .start-cta kbd { animation: none; }
  .racer { transition: none !important; }
  .button { transition: none; }
}
