/* Name the Dot. A daily game in the newspaper-games manner: a white
   page and a white masthead with a hairline under it, a slab serif for titles
   and Franklin for everything else. The game itself is broadcast hardware
   (black scorebug, turf, control bar) and a guess sheet ruled in ink, coded with
   highlighter: yellow = the guess you're making (and "close" on a comparison
   tile), pink = a miss, green = got it (and "match"). */

:root {
  --page: #ffffff;
  --masthead: #ffffff;
  --masthead-ink: #121212;
  --masthead-muted: #121212;
  --hairline: 1px solid #dcdcdc;
  --card: #ffffff;
  --ink: #0e0f10;
  --ink-2: #4b4f55;
  --rule: 1.5px solid var(--ink);
  --hl-now: #ffe135;
  --hl-miss: #ff5a52;
  --hl-hit: #5fd06e;
  --slab: #0e0f10;          /* scorebug + control bar */
  --slab-ink: #f4f5f5;
  --slab-muted: #b9bcc0;
  /* One family, Libre Franklin: heavy tight caps for every label and row, like
     a newspaper sports section; regular weights for sentences. */
  --caps: "Libre Franklin", "Franklin Gothic Medium", Arial, sans-serif;
  --text: "Libre Franklin", "Franklin Gothic Book", Arial, sans-serif;
  /* Titles: a slab serif, the way the newspaper games name themselves. */
  --serif: "Zilla Slab", "Rockwell", Georgia, serif;
  --ease-out: cubic-bezier(.16, 1, .3, 1);
  --fa: 1.6; /* field height ÷ width, set per play from its crop */
  --col: 560px; /* content column; the masthead lines up with it */
}
/* The field always fills the card's width; its height comes from the play's
   crop (see FieldView.crop), which is kept tight so long plays stay short. */
.field-wrap { position: relative; display: flex; justify-content: center; background: #1f4426; border-radius: 0 0 10px 10px; overflow: hidden; }
/* Rive moments (flag, GOT IT!, INCOMPLETE) play over the field, never catching taps. */
.field-wrap .moments { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }

* { box-sizing: border-box; }
html { background: var(--page); }
body { margin: 0; min-height: 100dvh; color: var(--ink); background: var(--page);
  font: 16px/1.5 var(--text); -webkit-font-smoothing: antialiased; }
::selection { background: var(--hl-now); color: var(--ink); }
:focus-visible { outline: 2.5px solid var(--ink); outline-offset: 2px; border-radius: 4px; }
a { color: inherit; text-underline-offset: 3px; }
button, input { font: inherit; color: inherit; }
[hidden] { display: none !important; }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }

/* ---------- masthead ---------- */
.masthead { position: sticky; top: 0; z-index: 5; display: flex; align-items: center; justify-content: space-between;
  gap: 12px; padding: max(6px, env(safe-area-inset-top)) 8px 6px 16px; color: var(--masthead-ink);
  background: var(--masthead); border-bottom: var(--hairline); }
.wordmark { font: 700 22px/1 var(--serif); letter-spacing: -.01em; text-decoration: none; white-space: nowrap; }
.masthead-nav { display: flex; }
.masthead-nav a, .masthead-nav button { display: grid; place-items: center; width: 44px; height: 44px; padding: 0; border: 0;
  border-radius: 50%; background: transparent; color: var(--masthead-muted); cursor: pointer;
  transition: background-color .15s ease-out; }
.masthead-nav a:hover, .masthead-nav a[aria-current="page"], .masthead-nav button:hover { background: #f0f0f0; }
#soundBtn .off, #soundBtn[aria-pressed="false"] .on { display: none; }
/* Four icons and the wordmark have to share a 375px phone. */
@media (max-width: 400px) {
  .masthead { padding-left: 12px; padding-right: 4px; gap: 6px; }
  .wordmark { font-size: 19px; }
  .masthead-nav a, .masthead-nav button { width: 40px; }
  .masthead-nav svg { width: 22px; height: 22px; }
}
#soundBtn[aria-pressed="false"] .off { display: block; }
.masthead-nav svg { width: 24px; height: 24px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.masthead-nav .dot { fill: currentColor; }

/* ---------- the page column ---------- */
.card { position: relative; width: min(100% - 16px, var(--col)); min-width: min(100% - 16px, 300px); margin: 0 auto 24px;
  padding: 14px 14px 28px; outline: none; background: var(--page); }

.meta { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; margin: 0 2px 10px;
  font: 800 12px/1.2 var(--caps); text-transform: uppercase; letter-spacing: .04em; color: var(--ink-2); }
.meta b { color: var(--ink); font-weight: 900; }
.meta > span:first-child { white-space: nowrap; flex-shrink: 0; }

/* ---------- broadcast frame: scorebug, field, controls ---------- */
.bug { position: relative; display: grid; grid-template-columns: 1fr auto; align-items: center; gap: 12px;
  background: var(--slab); color: var(--slab-ink); border-radius: 10px 10px 0 0; padding: 10px 12px 10px 10px; }
.teams { display: grid; gap: 4px; }
.team { display: grid; grid-template-columns: 6px 1fr auto 28px; align-items: center; gap: 8px;
  font: 800 16px/1.2 var(--caps); letter-spacing: -.005em; }
.team i { width: 6px; height: 22px; border-radius: 2px; background: var(--c); }
.team .score { font-variant-numeric: tabular-nums; text-align: right; }
.team .poss { width: 12px; height: 8px; border-radius: 50%; background: #8a5426; justify-self: center; visibility: hidden; }
.team.has-ball .poss { visibility: visible; }
/* Two 22px rows 4px apart, level with the two team lines. */
.sit { display: grid; grid-template-rows: 22px 22px; gap: 4px; align-items: center; justify-items: end;
  text-align: right; border-left: 1px solid #34373b; padding-left: 12px;
  font: 500 13px/1.3 var(--caps); color: var(--slab-muted); letter-spacing: 0; }
.sit b { display: flex; justify-content: flex-end; align-items: center; gap: 6px; font-weight: 800; font-size: 17px; color: var(--slab-ink); }
.sit .clock { min-width: 50px; text-align: right; font-variant-numeric: tabular-nums; }
/* The live Rive scorebug sits over the HTML one, which stays underneath as the
   fallback until the file loads (and as the screen-reader text). */
.bug-live { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
.bug.is-live > :not(.bug-live) { opacity: 0; } /* not visibility: screen readers still read it */

canvas { display: block; width: 100%; }
.field { width: 100%; aspect-ratio: 1 / var(--fa); background: #1f4426; }
/* Its own block under the field, never touching or covering it. */
canvas.field { cursor: pointer; -webkit-tap-highlight-color: transparent; }
.controls { aspect-ratio: 440 / 40; margin-top: 6px; background: var(--slab); border-radius: 8px; touch-action: none; }

.meta .game { font-variant-numeric: tabular-nums; text-align: right; text-wrap: balance; }
.panel > .sheet { margin-top: 14px; }


/* ---------- the guess sheet ---------- */
.sheet { list-style: none; margin: 0; padding: 0; border-top: var(--rule); }
.call { display: grid; grid-template-columns: 46px minmax(0, 1fr) auto; align-items: stretch; min-height: 52px; border-bottom: var(--rule);
  font: 800 16px/1.15 var(--caps); text-transform: uppercase; letter-spacing: -.005em; transition: background-color .3s ease-out; }
.call .num { display: grid; place-items: center; border-right: var(--rule); font-weight: 900; font-size: 20px; font-variant-numeric: tabular-nums; }
.call .name { display: flex; align-items: center; padding: 0 12px; min-width: 0; overflow-wrap: anywhere; }
.call.is-empty { min-height: 44px; }
.call.is-now .num { align-content: center; gap: 1px; }
.call.is-now .num small { font: 700 10px/1 var(--caps); letter-spacing: .02em; }

/* A missed guess: the name, then four tiles comparing it with the answer.
   Green = match, yellow = close, white = off; arrows point toward the answer. */
.call .guess { grid-column: 2 / -1; display: grid; gap: 6px; padding: 8px 10px 9px 12px; min-width: 0; }
.call .guess .name { padding: 0; }
.cmp { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 5px; }
.cmp-cell { display: grid; justify-items: center; gap: 1px; padding: 4px 2px 5px; border: var(--rule); border-radius: 6px;
  background: var(--card); text-decoration: none; }
.cmp-cell small { font: 700 10px/1 var(--caps); letter-spacing: .04em; opacity: .75; }
.cmp-cell b { display: flex; align-items: center; gap: 2px; font: 900 14px/1.1 var(--caps); font-variant-numeric: tabular-nums; }
.cmp-cell svg { width: 9px; height: 9px; fill: currentColor; }
.cmp-cell.is-hit { background: var(--hl-hit); }
.cmp-cell.is-near { background: var(--hl-now); }
.call .got { display: flex; align-items: center; padding: 0 12px; font-size: 13px; letter-spacing: .04em; }

/* Highlighter: a filled row is a stroke of colour; the row that just
   changed gets the stroke swiped in left to right, then its tiles flip in
   one at a time. */
.call.is-miss, .call.is-hit { background: linear-gradient(var(--hl), var(--hl)) left / 100% 100% no-repeat; }
.call.is-miss { --hl: var(--hl-miss); }
.call.is-hit { --hl: var(--hl-hit); }
.call.is-fresh { animation: swipe .6s var(--ease-out) both; }
.call.is-fresh .cmp-cell { animation: flip .5s var(--ease-out) both; animation-delay: calc(.3s + var(--i) * .12s); }
@keyframes swipe { from { background-size: 0% 100%; } }
@keyframes flip { from { transform: perspective(300px) rotateX(-90deg); opacity: 0; } }
.call.is-miss .guess > .name { text-decoration: line-through; text-decoration-thickness: 2px; }
.call.is-hit { background: var(--hl-hit); }
.call.is-now { background: var(--hl-now); }
.call form, .composer form { position: relative; display: flex; align-items: center; gap: 8px; padding: 6px 6px 6px 10px; grid-column: 2 / -1; min-width: 0; }
/* Matches open below the guess box (.is-below), or above it when a phone keyboard leaves no room. */
.picks { position: absolute; left: 10px; right: 6px; bottom: calc(100% - 2px); z-index: 4; margin: 0; padding: 4px; list-style: none;
  border: var(--rule); border-radius: 10px; background: var(--card); box-shadow: 0 -10px 30px rgba(14,15,16,.22);
  animation: rise .18s var(--ease-out); }
.picks.is-below { bottom: auto; top: calc(100% - 2px); box-shadow: 0 10px 30px rgba(14,15,16,.22); }
.picks li { display: flex; align-items: center; min-height: 44px; padding: 0 12px; border-radius: 7px; cursor: pointer;
  font: 800 16px/1.15 var(--caps); text-transform: uppercase; letter-spacing: -.005em; }
.picks li[aria-selected="true"] { background: var(--hl-now); }
.picks li:hover { background: #eef0f0; }
.picks li[aria-selected="true"]:hover { background: var(--hl-now); }
.call input, .composer input { flex: 1; min-width: 0; height: 44px; padding: 0 12px; border: var(--rule); border-radius: 8px; background: var(--card);
  font: 500 16px var(--text); text-transform: none; letter-spacing: 0; caret-color: var(--ink); }
.call input::placeholder, .composer input::placeholder { color: #6a6e74; }
.call input[aria-invalid="true"], .composer input[aria-invalid="true"] { border-color: #b3123f; box-shadow: 0 0 0 2px rgba(179,18,63,.18); }
.btn { display: inline-flex; align-items: center; justify-content: center; gap: 8px; min-height: 44px; padding: 0 18px;
  border: 0; border-radius: 999px; background: var(--ink); color: var(--card); cursor: pointer; text-decoration: none;
  font: 800 15px/1 var(--caps); text-transform: uppercase; letter-spacing: .02em; transition: background-color .15s ease-out, transform .15s var(--ease-out); }
.btn:hover { background: #2a2d31; }
.btn:active { transform: scale(.97); }
.btn.ghost { background: transparent; color: var(--ink); box-shadow: inset 0 0 0 1.5px var(--ink); }
.btn.ghost:hover { background: #eef0f0; }
:is(.call, .composer) .btn { min-height: 44px; padding: 0 14px; border-radius: 8px; } /* squared to match the box beside it */
.form-error { margin: 6px 2px 0; min-height: 1.4em; font-size: 14px; font-weight: 500; color: #b3123f; }

/* Phones: the guess box in the page is a button (composer.js) that opens a
   bar pinned above the keyboard, with the matches stacked upward over the
   play, best match nearest the box. */
.guess-open { grid-column: 2 / -1; align-self: center; min-width: 0; height: 44px; margin: 6px 6px 6px 10px; padding: 0 12px;
  border: var(--rule); border-radius: 8px; background: var(--card); color: #6a6e74; text-align: left; cursor: text;
  font: 500 16px var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.composer { position: fixed; inset: 0; z-index: 60; }
.composer-backdrop { position: absolute; inset: 0; background: rgba(14,15,16,.5); animation: fade .15s ease-out; }
.composer-panel { position: absolute; left: 0; right: 0; bottom: 0; padding: 4px 4px calc(4px + env(safe-area-inset-bottom));
  background: var(--hl-now); box-shadow: 0 -6px 24px rgba(14,15,16,.25); }
.composer-panel form { padding: 6px; }
.composer-panel .form-error { margin: 4px 10px 0; }
.composer-panel .form-error:empty { display: none; }
.composer .picks, .composer .picks.is-below { top: auto; bottom: calc(100% + 8px); left: 6px; right: 6px;
  display: flex; flex-direction: column-reverse; box-shadow: 0 -10px 30px rgba(14,15,16,.3); }
@keyframes fade { from { opacity: 0; } }

/* The sheet folds shut when the game ends; the reveal opens in its place. */
.sheet.is-folding { overflow: hidden; transition: height .45s var(--ease-out) .25s, opacity .3s ease-out .25s; opacity: 0; }

/* ---------- reveal ---------- */
.reveal { margin-top: 22px; }
/* A fresh finish brings each part in on its own beat (--d); a revisit, or
   anyone who prefers less motion, gets the finished page at once. */
.reveal.is-fresh :is(.answer-meta, .scorecard, .box-row, .share-row, .next-row, .the-play) { animation: rise .5s var(--ease-out) both; animation-delay: var(--d); }
.reveal.is-fresh .answer { animation: land .8s var(--ease-out) both; animation-delay: var(--d); }
.reveal.is-fresh .share-row .share { animation: pop .45s var(--ease-out) both; animation-delay: calc(var(--d) + .05s); }
.dist.is-growing { animation: rise .4s var(--ease-out) both; animation-delay: var(--d); }
.dist.is-growing .fill { animation: grow .7s var(--ease-out) both; animation-delay: calc(var(--d) + var(--i) * .07s); }
@keyframes rise { from { opacity: 0; transform: translateY(10px); } }
@keyframes pop { 0% { opacity: 0; transform: scale(.6); } 70% { opacity: 1; transform: scale(1.06); } 100% { transform: none; } }
@keyframes grow { from { clip-path: inset(0 100% 0 0 round 4px); } to { clip-path: inset(0 0 0 0 round 4px); } }
.answer { margin: 0; font: 700 clamp(34px, 9vw, 46px)/1.05 var(--serif); letter-spacing: -.01em; text-wrap: balance; overflow-wrap: anywhere; }
@keyframes land { from { clip-path: inset(0 100% 0 0); transform: translateX(-6px); } to { clip-path: inset(0 0 0 0); transform: none; } }
.answer-meta { margin: 6px 0 0; font: 500 15px var(--text); color: var(--ink-2); }
.scorecard { display: block; width: 100%; aspect-ratio: 440 / 110; margin: 18px 0 16px; }
/* The play's call, under the name like a photo caption. */
.the-play { margin: 10px 0 0; font: 400 15px/1.45 var(--text); color: var(--ink); text-wrap: pretty; }

/* Box score: each guess on one line, its number then the name. */
.box { list-style: none; margin: 0; padding: 0; border-top: var(--rule); }
.box-row { display: grid; grid-template-columns: 26px minmax(0, 1fr) auto; align-items: center; gap: 10px; min-height: 34px;
  border-bottom: var(--rule); font: 800 14px/1.15 var(--caps); text-transform: uppercase; }
.box-row .n { font-weight: 900; text-align: center; font-variant-numeric: tabular-nums; }


.dist { margin-top: 22px; }
.dist h3, .section-title { margin: 0 0 8px; font: 800 12px var(--caps); text-transform: uppercase; letter-spacing: .04em; color: var(--ink-2); }
.bar { display: grid; grid-template-columns: 30px 1fr; align-items: center; gap: 8px; margin: 5px 0; font: 700 14px var(--caps); }
.bar span:first-child { text-align: center; }
.bar .fill { min-width: 34px; width: var(--w); padding: 3px 8px; border-radius: 4px; background: #e2e4e6; text-align: right;
  font-variant-numeric: tabular-nums; transition: width .6s var(--ease-out); }
.bar.is-you .fill { background: var(--hl-hit); }
.dist p { margin: 8px 0 0; font-size: 14px; color: var(--ink-2); }

/* Like the newspaper games' results: the countdown on the left, a thin rule,
   and the Share button on the right. */
.share-row { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 0 20px; margin-top: 20px; }
.share-row::before { content: ""; grid-column: 2; grid-row: 1; width: 1px; height: 52px; background: var(--ink); }
.share { grid-column: 3; grid-row: 1; justify-self: start; min-width: 150px; min-height: 52px; font-size: 17px; }
.share .morph-in { display: inline-block; animation: label-in .28s var(--ease-out) both; }
@keyframes label-in { from { opacity: 0; transform: translateY(8px); filter: blur(3px); } }
.share-row .next { grid-column: 1; grid-row: 1; justify-self: end; display: grid; text-align: center; }
.share-row .next small { font: 800 12px var(--caps); text-transform: uppercase; letter-spacing: .04em; }
.share-row .next b { font: 400 30px/1.15 var(--text); font-variant-numeric: tabular-nums; }
.toast { margin: 8px 0 0; font-size: 14px; font-weight: 500; }
.toast:empty { display: none; }

/* ---------- pages ---------- */
.page-title { margin: 12px 0 16px; font: 700 34px/1.05 var(--serif); letter-spacing: -.01em; text-wrap: balance; }
.lede { margin: 0 0 20px; font-size: 17px; color: var(--ink-2); max-width: 46ch; }

.page-actions { margin-top: 22px; }

/* Rules: a dialog over today's play, dismissed to start it. */
dialog#rules { width: min(100% - 32px, 400px); max-height: calc(100dvh - 32px); padding: 22px 20px 20px; border: 0;
  border-radius: 8px; background: var(--card); color: var(--ink); box-shadow: 0 4px 23px rgba(0, 0, 0, .2); }
dialog#rules::backdrop { background: rgba(255, 255, 255, .7); }
dialog#rules[open] { animation: deal .32s var(--ease-out); }
@keyframes deal { from { opacity: 0; transform: translateY(14px) scale(.98); } }
dialog#rules .x { position: absolute; top: 10px; right: 10px; margin: 0; }
dialog#rules .x button { display: grid; place-items: center; width: 44px; height: 44px; border: 0; border-radius: 10px; background: transparent; color: var(--ink); cursor: pointer; }
dialog#rules .x button:hover { background: #eef0f0; }
dialog#rules .x svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; }
.call.is-now { scroll-margin-bottom: 12px; }
dialog#rules h2 { margin: 0 0 14px; font: 700 30px/1 var(--serif); letter-spacing: -.01em; }
.rules { list-style: none; margin: 0; padding: 0; border-top: var(--rule); }
.rules li { display: grid; grid-template-columns: 34px 1fr; align-items: start; gap: 0 12px; padding: 12px 0; border-bottom: var(--rule); }
.rules .num { font: 900 18px/1.4 var(--caps); text-align: center; }
.rules p { margin: 0; font-size: 15px; line-height: 1.45; color: var(--ink-2); }
.rules p b { color: var(--ink); font-weight: 700; }
/* The playmaker's dot, sized to the text and centred on its middle. */
.rules .q { display: inline-grid; place-items: center; width: 18px; height: 18px; border-radius: 50%; background: var(--hl-now);
  color: var(--ink); font: 900 11px/1 var(--caps); vertical-align: middle; position: relative; top: -1px; }
.rules .nowrap { white-space: nowrap; }
.rules .cmp { grid-column: 2; margin-top: 10px; }
.rules-note { margin: 14px 0 16px; font-size: 14px; color: var(--ink-2); }
dialog#rules .btn { width: 100%; }

.stat-grid { display: flex; gap: 28px; margin: 0 0 28px; border: 0; }
.stat-grid .call { display: flex; flex-direction: column-reverse; align-items: flex-start; min-height: 0; border: 0; text-transform: none; }
.stat-grid .call .name { padding: 0; font: 500 13px/1.3 var(--text); }
.stat-grid .call .val { font: 400 40px/1.1 var(--text); font-variant-numeric: tabular-nums; letter-spacing: -.01em; }

/* Each cell carries its own rule (centred on its edge), so a launch-day
   archive of one cell still reads as a closed box. */
.archive { display: grid; grid-template-columns: repeat(auto-fill, minmax(84px, 1fr)); padding: 1px; }
.cell { position: relative; display: grid; place-items: center; gap: 2px; aspect-ratio: 1; padding: 6px; text-decoration: none;
  outline: 1.5px solid var(--ink); outline-offset: -0.75px; transition: background-color .15s ease-out; }
.cell:hover { background: #eef0f0; }
.cell b { position: relative; font: 900 30px/1 var(--caps); font-variant-numeric: tabular-nums; }
.cell small { font: 800 11px var(--caps); text-transform: uppercase; letter-spacing: .04em; color: var(--ink-2); }
.cell.is-open { background: var(--hl-now); }
.cell.is-today b::after { content: ""; display: block; height: 3px; margin-top: 3px; background: var(--ink); border-radius: 2px; }
.legend { display: flex; flex-wrap: wrap; gap: 6px 16px; margin: 14px 0 0; font-size: 14px; color: var(--ink-2); }

.empty { padding: 28px 0; }
.empty p { color: var(--ink-2); max-width: 44ch; }

@media (min-width: 720px) {
  /* A narrower column keeps the control bar in proportion to the field. On a tablet the field must not push the guess box off the screen: the
     column narrows until field, bar and the guess row fit the window. */
  :root { --col: clamp(380px, calc((100dvh - 330px) / var(--fa, 1.4) + 44px), 480px); }
  .card { margin-top: 12px; padding: 20px 22px 32px; }
  /* The masthead's wordmark and icons line up with the column's edges. */
  .masthead { padding-inline: max(16px, calc((100% - var(--col)) / 2)); }
  .masthead-nav { margin-right: -10px; }
}

/* Wide screens: two cards side by side. The play card (date line, scorebug,
   field, bar) stays in view on the left; the guesses card sits beside it and
   is only as tall as what's in it. The field's width follows the window's
   height, so a long play fits and a tall screen gets a bigger field. */
@media (min-width: 900px) {
  :root { --stage: clamp(320px, calc((100dvh - 330px) / var(--fa, 1.4)), 560px); --side: 420px; --gap: 40px;
    --col: calc(var(--stage) + 32px + var(--gap) + var(--side)); }
  .card:has(.play-grid) { padding: 0; margin-top: 20px; }
  .play-grid { display: grid; grid-template-columns: calc(var(--stage) + 32px) minmax(280px, var(--side)); gap: var(--gap); align-items: start; }
  .side { display: grid; gap: var(--gap); }
  /* No boxes on the white page: the play and the guesses sit side by side. */
  .stage, .panel { padding: 0; }
  .stage { position: sticky; top: 64px; }
  .panel > .sheet { margin-top: 0; }
  .call { min-height: 60px; }
  .call.is-empty { min-height: 52px; }
  .form-error:empty { display: none; }
  .reveal { margin-top: 0; }
  .answer { font-size: clamp(38px, 4vw, 52px); }
}

/* Local test mode only (see testBar in app.js). */
.test-bar { position: fixed; left: 50%; bottom: 12px; z-index: 20; transform: translateX(-50%); display: flex; align-items: center; gap: 6px;
  padding: 6px 8px 6px 12px; border-radius: 12px; background: #ff6fab; color: var(--ink); box-shadow: 0 8px 24px rgba(0,0,0,.35);
  font: 800 12px var(--caps); text-transform: uppercase; letter-spacing: .03em; white-space: nowrap; }
.test-bar button { min-width: 36px; height: 36px; padding: 0 10px; border: 0; border-radius: 8px; background: var(--ink); color: #fff;
  font: inherit; font-size: 16px; cursor: pointer; }
.test-bar button[data-reset] { font-size: 11px; }
.test-bar button:disabled { opacity: .35; cursor: default; }
body:has(.test-bar) { padding-bottom: 64px; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
}

/* ---------- five-play sets ---------- */
/* One box per play, ruled like the sheet: yellow is the play on screen, then
   green or pink once it's called. The closer's star is the typed-in bonus. */
/* The day and its five boxes share a line; the game line sits under them,
   right over the scorebug it belongs to. */
.set-bar { display: flex; align-items: center; gap: 12px; margin: 0 2px 14px;
  font: 800 12px/1.2 var(--caps); text-transform: uppercase; letter-spacing: .04em; color: var(--ink-2); }
.set-bar .day { white-space: nowrap; }
.set-bar b { color: var(--ink); font-weight: 900; }
.meta.game { display: block; margin-bottom: 8px; text-align: left; }
.pips { list-style: none; flex: 1; display: grid; grid-template-columns: repeat(5, 1fr); gap: 6px; margin: 0; padding: 0; }
.pip { display: grid; place-items: center; height: 28px; border: var(--rule); border-radius: 6px;
  font: 900 13px/1 var(--caps); font-variant-numeric: tabular-nums; color: var(--ink-2); }
.pip:last-child { border-style: dashed; }
.pip.is-now { background: var(--hl-now); color: var(--ink); }
.pip.is-right, .pip.is-star { background: var(--hl-hit); color: var(--ink); border-style: solid; }
.pip.is-star { font-size: 16px; }
.pip.is-wrong { background: var(--hl-miss); color: var(--ink); border-style: solid; }
.pip > * { display: grid; place-items: center; width: 100%; height: 100%; }
.pip button { padding: 0; border: 0; border-radius: 4px; background: none; font: inherit; color: inherit; cursor: pointer; }
.pip.is-now:is(.is-right, .is-wrong, .is-star) { box-shadow: 0 0 0 2px var(--page), 0 0 0 4px var(--ink); }
.pip.is-link { transition: transform .12s ease-out, filter .12s ease-out; }
.pip.is-link:hover { filter: brightness(.93); transform: translateY(-1px); }

.prompt { display: grid; gap: 2px; margin: 14px 2px 10px; }
.prompt .kind { font: 800 12px/1.2 var(--caps); text-transform: uppercase; letter-spacing: .04em; color: var(--ink-2); }
.prompt b { font: 700 24px/1.15 var(--serif); }

/* The four names: rows of the sheet, each a button. */
.choices { margin-top: 0; }
.choice { width: 100%; padding: 0; border: 0; border-bottom: var(--rule); border-radius: 0; background: var(--card);
  text-align: left; font: 700 17px/1.2 var(--text); cursor: pointer; }
.choices li:last-child .choice { border-bottom: 0; }
.choice:hover:not(:disabled) { background: #fff4b8; }
.choice:disabled { cursor: default; color: var(--ink); }
.choice .pos { display: flex; align-items: center; padding: 0 12px; font: 800 12px var(--caps); letter-spacing: .04em; color: var(--ink-2); }
.choice.is-selected { background: var(--hl-now); box-shadow: inset 4px 0 0 var(--ink); }
.lock { margin-top: 12px; width: 100%; min-height: 52px; font-size: 17px; animation: rise .25s var(--ease-out) both; }
.choice.is-hit { background: var(--hl-hit); }
.choice.is-miss { background: var(--hl-miss); }
.choice.is-miss .name { text-decoration: line-through; text-decoration-thickness: 2px; }
.choice.is-out { color: var(--ink-2); }
.choices.is-fresh li { animation: rise .4s var(--ease-out) both; animation-delay: calc(var(--i, 0) * .06s); }
.typed + .choices { margin-top: 14px; }

.show-options { margin-top: 12px; width: 100%; }
.show-options small { font-weight: 500; color: var(--ink-2); }

.verdict { display: inline-block; margin: 0 0 8px; padding: 3px 8px; border-radius: 4px;
  font: 800 12px/1.4 var(--caps); text-transform: uppercase; letter-spacing: .04em; }
.verdict.is-right, .verdict.is-star { background: var(--hl-hit); }
.verdict.is-wrong { background: var(--hl-miss); }
.next-row { margin-top: 20px; }
.next-play { min-width: 180px; min-height: 52px; font-size: 17px; white-space: nowrap; }
.reveal.is-fresh .verdict { animation: rise .4s var(--ease-out) both; animation-delay: var(--d); }

/* Results: each play's line opens it again. */
.results { margin-top: 6px; }
.box-row .nm { min-width: 0; overflow-wrap: anywhere; padding: 0; border: 0; background: none; text-align: left; font: inherit; cursor: pointer;
  text-decoration: underline; text-decoration-color: #c4c7ca; text-underline-offset: 3px; }
.box-row .nm small { margin-left: 4px; font: 700 11px var(--caps); text-transform: uppercase; letter-spacing: .04em; color: var(--ink-2); text-decoration: none; }
.box-row .mark { display: grid; place-items: center; width: 26px; height: 26px; border-radius: 50%;
  font: 900 15px/1 var(--caps); color: var(--ink); }
.box-row .mark.is-right, .box-row .mark.is-star { background: var(--hl-hit); }
.box-row .mark.is-wrong { background: var(--hl-miss); }

.cell .tally { font: 800 12px var(--caps); font-variant-numeric: tabular-nums; }
.cell.is-done { background: #e6f6e9; }

/* Results, stats and the archive: one wide column whose edges line up with
   the masthead's wordmark and icons (so no side padding of its own). */
@media (min-width: 720px) {
  body:not(:has(.play-grid)) { --col: 640px; }
  .card:not(:has(.play-grid)) { padding-inline: 0; }
}

/* From one play to the next (View Transitions, where the browser has them):
   the play boxes and the scorebug stay put and change in place, the old field
   slides off to the left as the new one comes in from the right, and the names
   fade over. Everything else cross-fades. */
.set-bar { view-transition-name: set-bar; }
.bug { view-transition-name: bug; }
.field-wrap { view-transition-name: field; }
.panel { view-transition-name: panel; }
::view-transition-group(*) { animation-duration: .4s; animation-timing-function: var(--ease-out); }
::view-transition-group(field) { overflow: clip; border-radius: 0 0 10px 10px; }
::view-transition-old(field) { animation: .4s var(--ease-out) both field-out; }
::view-transition-new(field) { animation: .4s var(--ease-out) both field-in; }
::view-transition-old(panel) { animation: .2s ease-out both fade-out; }
::view-transition-new(panel) { animation: .35s var(--ease-out) .1s both rise; }
@keyframes field-out { to { transform: translateX(-30%); opacity: 0; } }
@keyframes field-in { from { transform: translateX(30%); opacity: 0; } }
@keyframes fade-out { to { opacity: 0; } }

/* Phones: the guess panel is pinned to the bottom (names in a 2 x 2 grid,
   then Lock it in; after the pick, the result and Next play in the same
   spot), so the next play is never a scroll away. The field above keeps its
   natural size, up to about 70% of the screen (app.js turns a longer play
   into a camera that follows the ball), and the page scrolls to see it all.
   app.js keeps --panel-h up to date. */
@media (max-width: 719px) {
  .card.is-play { margin-bottom: 0; padding-bottom: calc(var(--panel-h, 220px) + 12px); }
  .card.is-play .set-bar { margin-bottom: 8px; }
  .card.is-play .meta.game { margin-bottom: 6px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

  .card.is-play .panel { position: fixed; left: 0; right: 0; bottom: 0; z-index: 4; max-height: 72dvh; overflow-y: auto;
    padding: 10px 12px calc(10px + env(safe-area-inset-bottom)); background: var(--page);
    border-top: var(--hairline); box-shadow: 0 -8px 20px rgba(0, 0, 0, .08); }
  .card.is-play .prompt { margin: 0 2px 8px; grid-template-columns: 1fr; }
  .card.is-play .prompt b { font-size: 19px; }
  /* Once the play is called the question gives way to the answer. */
  .card.is-play .panel:has(.reveal:not([hidden])) .prompt { display: none; }

  .choices { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; border: 0; }
  .choice { grid-template-columns: auto minmax(0, 1fr); grid-template-rows: auto auto; align-content: center; column-gap: 8px;
    min-height: 52px; padding: 5px 8px; border: var(--rule); border-radius: 8px; font-size: 14px; line-height: 1.15; }
  .choices li:last-child .choice { border-bottom: var(--rule); }
  .choice .num { grid-row: 1 / 3; border: 0; font-size: 14px; }
  .choice .name { padding: 0; }
  .choice .pos { padding: 0; font-size: 10px; }
  .choice.is-selected { box-shadow: inset 0 0 0 2px var(--ink); }
  .lock, .show-options { margin-top: 8px; min-height: 48px; }

  /* The result: verdict and name on one line, then Next play. The details
     (number, team, the play's text) stay on the big screen. */
  .card.is-play .reveal { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 10px; margin-top: 10px; }
  .card.is-play .reveal .verdict { margin: 0; }
  .card.is-play .reveal .answer { font-size: 24px; }
  .card.is-play .reveal :is(.answer-meta, .the-play) { display: none; }
  .card.is-play .next-row { flex-basis: 100%; margin-top: 6px; }
  .card.is-play .next-play { width: 100%; min-height: 48px; }
  .card.is-play .form-error:empty { display: none; }

  /* The local test bar moves to the top, off the panel. */
  .test-bar { top: 6px; bottom: auto; transform: translateX(-50%) scale(.85); }
  body:has(.test-bar) { padding-bottom: 0; }
}
