/* The game hub (v0.160): the board, keyboard and hub chrome for Generic Guess.
   Tokens, base type, .card, .btn, the focus ring and the colour-scheme rules
   come from /public.css; this file holds only what the hub adds. Served as
   /games/games.css?v=<release stamp> (immutable for a year), so never write a
   ?v= by hand. */

main{max-width:720px;margin:0 auto;padding:max(24px,env(safe-area-inset-top)) max(16px,env(safe-area-inset-right)) 56px max(16px,env(safe-area-inset-left))}
.brand{display:flex;align-items:center;gap:10px;font-weight:600;font-size:15px;color:var(--label);text-decoration:none;margin-bottom:20px;width:max-content}
.dot{width:22px;height:22px;border-radius:7px;display:block;box-shadow:0 1px 2px rgba(0,0,0,.12)}
.app-back{display:inline-flex;align-items:center;min-height:44px;margin-bottom:12px;color:var(--blue);font-size:15px}
h1{font-size:30px;line-height:1.15;letter-spacing:-.02em;margin:0 0 10px}
h2{font-size:22px;letter-spacing:-.01em;margin:0 0 4px}
h3{font-size:17px;margin:18px 0 6px}
.lede{color:var(--label2);margin:0 0 6px}
.tile-line{margin:0 0 10px}
.run{font-size:14px;font-weight:600;color:var(--label);margin:10px 0 4px}
.score{font-size:14px;color:var(--label2);margin:0 0 6px}
.score:last-child{margin-bottom:12px}
.card{padding:18px 16px 16px}

/* the board: one grid row per guess, --len columns, square tiles. At 375px
   with 16px gutters a 12-letter row is 12 tiles of about 25px plus 3px gaps */
.board{display:grid;gap:4px;margin:0 auto 14px;width:100%;max-width:calc(var(--len,8) * 58px + (var(--len,8) - 1) * 4px)}
.row{display:grid;grid-template-columns:repeat(var(--len,8),minmax(0,1fr));gap:3px}
/* a tile's colours live in three custom properties so the flip (v0.162) can
   hold the neutral face until halfway and then snap to the scored one */
.tile{position:relative;aspect-ratio:1/1;min-width:0;display:flex;align-items:center;justify-content:center;
  --tbg:var(--bg2);--tbd:var(--sep);--tink:var(--label);
  border:2px solid var(--tbd);border-radius:6px;background:var(--tbg);color:var(--tink);
  font-weight:700;font-size:clamp(13px,5.2vw,26px);text-transform:uppercase;line-height:1;user-select:none}
@media (min-width:560px){.tile{font-size:clamp(16px,3vw,26px)}}
.tile.filled{--tbd:var(--label2)}
.tile.hit{--tbg:var(--gg-hit);--tbd:var(--gg-hit);--tink:#fff}
.tile.near{--tbg:var(--gg-near);--tbd:var(--gg-near);--tink:#fff}
.tile.miss{--tbg:var(--gg-miss);--tbd:var(--gg-miss);--tink:var(--gg-miss-ink)}
.tile .glyph{position:absolute;top:1px;right:3px;font-size:.42em;font-weight:700;line-height:1;opacity:.95}
:root{--gg-hit:var(--green);--gg-near:#D4A017;--gg-miss:#A1A1A6;--gg-miss-ink:#fff}
@media (prefers-color-scheme:dark){:root:not([data-theme="light"]){--gg-near:#B8900F;--gg-miss:#4A4A4E}}
:root[data-theme="dark"]{--gg-near:#B8900F;--gg-miss:#4A4A4E}
/* the colour-blind palette: orange for a hit, blue for near, on the board and the keys */
.cb .tile.hit{--tbg:#F5793A;--tbd:#F5793A;--tink:#fff}
.cb .tile.near{--tbg:#1F77D0;--tbd:#1F77D0;--tink:#fff}
.cb .key.hit{background:#F5793A;border-color:#F5793A;color:#fff}
.cb .key.near{background:#1F77D0;border-color:#1F77D0;color:#fff}

/* the live region: visible, short, never empty enough to collapse the layout */
.status{min-height:24px;text-align:center;font-weight:600;margin:0 0 12px;color:var(--label)}
.status.bad{color:#C62828}
@media (prefers-color-scheme:dark){:root:not([data-theme="light"]) .status.bad{color:#FF6B6B}}
:root[data-theme="dark"] .status.bad{color:#FF6B6B}

/* the on-screen keyboard: <button>s, 44px tall, three rows */
.keys{display:flex;flex-direction:column;gap:6px;margin:0 0 16px}
.krow{display:flex;gap:4px;justify-content:center}
.key{flex:1 1 0;min-width:0;max-width:44px;height:44px;padding:0;border:0;border-radius:7px;background:var(--fill2);color:var(--label);
  font:inherit;font-weight:600;font-size:15px;text-transform:uppercase;cursor:pointer;touch-action:manipulation;transition:background .12s}
.key.wide{flex:1.6 1 0;max-width:72px;font-size:12px;text-transform:none}
.key:hover{background:var(--fill3)}
.key.hit{background:var(--gg-hit);color:#fff}
.key.near{background:var(--gg-near);color:#fff}
.key.miss{background:var(--gg-miss);color:var(--gg-miss-ink)}

/* the clues (v0.171): the opened ones as a list, one 44px button for the next */
.clues{margin:0 0 12px}
.clue-list{list-style:none;margin:0 0 8px;padding:0}
.clue{padding:9px 12px;margin:0 0 6px;border-left:3px solid var(--gg-near);border-radius:8px;background:var(--fill);color:var(--label);font-size:15px;line-height:1.4;overflow-wrap:anywhere}
.clue .k{font-weight:600;color:var(--label2)}
.clue:focus{outline:none}
.cb .clue{border-left-color:#1F77D0}

/* controls under the board */
.controls{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin:0 0 6px}
.toggle{display:inline-flex;align-items:center;gap:8px;min-height:44px;padding:8px 12px;border:0;border-radius:11px;background:var(--fill);color:var(--label);font:inherit;font-size:15px;cursor:pointer}
.toggle .sw{width:34px;height:20px;border-radius:10px;background:var(--fill3);position:relative;flex:0 0 34px;transition:background .15s}
.toggle .sw::after{content:"";position:absolute;top:2px;left:2px;width:16px;height:16px;border-radius:8px;background:#fff;box-shadow:0 1px 2px rgba(0,0,0,.3);transition:transform .15s}
.toggle[aria-pressed="true"] .sw{background:var(--green)}
.toggle[aria-pressed="true"] .sw::after{transform:translateX(14px)}
.btn.small{min-height:44px;padding:9px 16px;font-size:15px}
.after{display:none;margin:12px 0 0}
.after.show{display:block}
.copybox{width:100%;min-height:150px;margin:8px 0 0;font:inherit;font-size:15px;border:1px solid var(--sep);border-radius:10px;padding:10px;background:var(--bg);color:var(--label)}
.hub-foot{font-size:14px;color:var(--label2);margin-top:28px}
.hub-foot a{color:var(--blue)}
.reset{margin-top:14px}

/* Stemmed (v0.161): the round line, the drug name with its stem marked after
   the answer, four full-width option <button>s, and the day's recap list.
   The hidden attribute must beat .btn's display:inline-flex from /public.css,
   or the Next round and Copy result buttons show while hidden */
[hidden]{display:none!important}
#st{margin-top:18px}
.round{font-size:14px;font-weight:600;color:var(--label2);margin:4px 0 2px}
.drug{font-size:clamp(24px,7vw,32px);font-weight:700;letter-spacing:-.01em;margin:0 0 12px;overflow-wrap:anywhere;color:var(--label)}
.drug .stem{color:var(--gg-hit);text-decoration:underline;text-decoration-thickness:3px;text-underline-offset:4px}
.cb .drug .stem{color:#F5793A}
.opts{display:grid;grid-template-columns:1fr;gap:8px;margin:0 0 12px}
@media (min-width:560px){.opts{grid-template-columns:1fr 1fr}}
.opt{min-height:44px;padding:10px 14px;border:2px solid var(--sep);border-radius:11px;background:var(--bg2);color:var(--label);
  font:inherit;font-size:15px;font-weight:600;text-align:left;cursor:pointer;transition:background .12s,border-color .12s}
.opt:hover:not(:disabled){background:var(--fill)}
.opt:disabled{cursor:default;opacity:.85}
.opt.hit{background:var(--gg-hit);border-color:var(--gg-hit);color:#fff;opacity:1}
.opt.miss{background:var(--gg-miss);border-color:var(--gg-miss);color:var(--gg-miss-ink);opacity:1}
.cb .opt.hit{background:#F5793A;border-color:#F5793A;color:#fff}
.recap{list-style:none;margin:0 0 12px;padding:0}
.recap li{display:flex;align-items:baseline;gap:8px;padding:6px 0;border-bottom:1px solid var(--sep);font-size:15px;overflow-wrap:anywhere}
.recap li .glyph{flex:0 0 18px;font-weight:700}
.recap li.hit .glyph{color:var(--gg-hit)}
.recap li.miss .glyph{color:var(--gg-miss)}
.cb .recap li.hit .glyph{color:#F5793A}
.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}

/* motion (v0.162), all written here, all CSS: games.js only adds a class and,
   for the staggered ones, --i (the tile's index) and --stagger on the row. The
   scored classes, glyphs and text are in the DOM before any animation starts,
   so nothing below is needed to read the state. One ease-out curve throughout;
   nothing moves more than 6px. Every animation is zeroed by the
   reduced-motion block at the end, and by the html.reduce-motion test class,
   which the manual check uses because the pane cannot emulate the setting. */
:root{--ease:cubic-bezier(.2,.7,.2,1)}
/* a letter typed: a short pop; backspace: a shrink back to size */
@keyframes gg-pop{0%{transform:scale(1)}40%{transform:scale(1.08)}100%{transform:scale(1)}}
@keyframes gg-unpop{0%{transform:scale(.94)}100%{transform:scale(1)}}
.tile.pop{animation:gg-pop .12s var(--ease)}
.tile.unpop{animation:gg-unpop .1s var(--ease)}
/* the reveal: each tile flips on its X axis, 250ms, starting --i * --stagger
   after the first; the neutral face is held to just before halfway, then the
   scored colours and glyph appear as the tile turns back */
@keyframes gg-flip{0%{transform:perspective(400px) rotateX(0);background:var(--bg2);border-color:var(--label2);color:var(--label)}
  49.9%{background:var(--bg2);border-color:var(--label2);color:var(--label)}
  50%{transform:perspective(400px) rotateX(90deg);background:var(--tbg);border-color:var(--tbd);color:var(--tink)}
  100%{transform:perspective(400px) rotateX(0)}}
@keyframes gg-glyph{0%,49.9%{opacity:0}50%,100%{opacity:.95}}
.tile.flip{animation:gg-flip .25s var(--ease) calc(var(--i,0) * var(--stagger,80ms)) both}
.tile.flip .glyph{animation:gg-glyph .25s linear calc(var(--i,0) * var(--stagger,80ms)) both}
/* a refused guess: the row shakes, 4px; a wrong Stemmed pick: the button, 3px */
@keyframes gg-shake{10%,90%{transform:translateX(calc(var(--amp,4px) * -.5))}20%,80%{transform:translateX(calc(var(--amp,4px) * .75))}30%,50%,70%{transform:translateX(calc(var(--amp,4px) * -1))}40%,60%{transform:translateX(var(--amp,4px))}}
.row.shake{animation:gg-shake .4s var(--ease)}
/* a win: the row's tiles rise 6px in turn after the reveal */
@keyframes gg-wave{0%,100%{transform:translateY(0)}50%{transform:translateY(-6px)}}
.tile.wave{animation:gg-wave .3s var(--ease) calc(var(--i,0) * 25ms)}
/* the scorecard: the streak line nudges up when the streak grows */
@keyframes gg-tick{0%,100%{transform:translateY(0)}40%{transform:translateY(-3px)}}
.run.tick{animation:gg-tick .3s var(--ease)}
/* Stemmed: the right pick settles with a glow; a wrong pick shakes and the
   right one colours in after it; a score dot fills per round; the next round
   and the recap slide in */
@keyframes st-glow{0%{box-shadow:0 0 0 0 var(--glow)}40%{box-shadow:0 0 0 6px var(--glow)}100%{box-shadow:0 0 0 0 transparent}}
.opt.hit{--glow:rgba(52,199,89,.45)}
.cb .opt.hit{--glow:rgba(245,121,58,.45)}
.opt.glow{animation:st-glow .5s var(--ease)}
.opt.shake{--amp:3px;animation:gg-shake .4s var(--ease)}
@keyframes st-late{0%{background:var(--bg2);border-color:var(--sep);color:var(--label)}}
.opt.late{animation:st-late .3s var(--ease) .35s backwards}
.dots{display:flex;gap:6px;margin:0 0 10px}
.dots span{width:10px;height:10px;border-radius:5px;background:var(--fill3);display:block}
.dots span.hit{background:var(--gg-hit)}
.dots span.miss{background:var(--gg-miss)}
.cb .dots span.hit{background:#F5793A}
@keyframes st-dot{0%{transform:scale(.5)}60%{transform:scale(1.2)}100%{transform:scale(1)}}
.dots span.fill{animation:st-dot .3s var(--ease)}
@keyframes st-enter{0%{opacity:0;transform:translateY(6px)}100%{opacity:1;transform:translateY(0)}}
#st-play.enter,.after.enter,.clue.enter{animation:st-enter .25s var(--ease)}
/* reduced motion: every animation and transition off, so each state change is
   instant with the same final appearance. html.reduce-motion is the same rule
   for the manual check (add the class, then read animationName from
   getComputedStyle); games.js reads both and adds no motion class under either */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation:none!important;transition:none!important}
}
.reduce-motion *,.reduce-motion *::before,.reduce-motion *::after{animation:none!important;transition:none!important}
/* Practice never presents a scorecard or a share control, including rerenders. */
.archive-play #gg-head, .archive-play #st-head,
.archive-play #gg-copy, .archive-play #st-copy { display: none; }
#archive-signin a { display: inline-block; min-height: 44px; align-content: center; }

/* v0.185: hub rhythm and typography; board/option geometry unchanged. */
main{padding-bottom:64px}.brand{margin-bottom:28px}h1,h2,h3,.drug{font-weight:500}.run,.score,.round{font-family:"JetBrains Mono",Consolas,monospace}.hub-foot{color:var(--label);line-height:1.65}.card{border:1px solid var(--sep);border-radius:10px}
.tile.hit,.key.hit,.opt.hit{color:var(--on-accent)}

/* v0.187: landing-style hub chrome; puzzle states and board geometry retained. */
main{max-width:960px;padding-top:40px}
.brand{font-size:18px;font-weight:500;padding-bottom:24px;border-bottom:1px solid var(--sep)}
h1{font-size:clamp(36px,5vw,56px);font-weight:400;letter-spacing:-.04em;margin:30px 0 24px}
h2{font-size:30px;font-weight:400;letter-spacing:-.03em}
.lede{line-height:1.7;max-width:680px}
section.card{margin-block:36px;padding:28px;border:10px solid transparent;border-radius:4px;
  background:linear-gradient(var(--bg2),var(--bg2)) padding-box,linear-gradient(125deg,#d9e7d0,#c6e1d9,#ded3e5) border-box;box-shadow:none}
.tile-line{font-family:"JetBrains Mono",Consolas,monospace;font-size:13px;line-height:1.7;margin:16px 0 24px}
.controls{padding-block:16px;border-top:1px solid var(--sep)}
.btn{border-radius:40px;min-height:44px}
.btn:not(.sec){background:var(--label);color:var(--bg)}
.hub-foot{border-top:1px solid var(--sep);padding-top:24px;font-size:14px;line-height:1.75}
:focus-visible{outline:3px solid var(--blue);outline-offset:4px}
:root[data-theme="dark"] section.card{background:linear-gradient(var(--bg2),var(--bg2)) padding-box,linear-gradient(125deg,#425749,#354e4c,#514656) border-box}
@media(prefers-color-scheme:dark){:root:not([data-theme="light"]) section.card{background:linear-gradient(var(--bg2),var(--bg2)) padding-box,linear-gradient(125deg,#425749,#354e4c,#514656) border-box}}
@media(max-width:600px){main{padding-top:24px}section.card{padding:18px 12px;border-width:8px}h1{font-size:36px}}
/* Every key keeps a 44px hit area on narrow phones; DOM/key order is unchanged. */
/* v0.212 (CEO: "The keyboard on mobile is flawed re render so maintains the shape we have
   on desktop view"): phones keep the three QWERTY rows. Keys share the row width (about
   30px each at 375px, above the 24px target minimum) and are taller for thumbs; the v0.187
   grid reflowed the letters into a block and lost the rows */
@media(max-width:600px){.keys{gap:8px}.krow{gap:5px}.key{max-width:none;height:54px;border-radius:6px;font-size:16px}.key.wide{flex:1.5 1 0;max-width:none;font-size:12px}}
/* v1.5: Enter in the brand green so it is found at a glance (light and dark: --green from public.css) */
.key.go{background:var(--green,#0f6e56);color:var(--on-accent,#fff)}
.key.go:hover{background:var(--green,#0f6e56);opacity:.9}
