/* Lifted from tools/playtest.py, which was verified in Chromium. The token
   structure is deliberate: the light palette is defined on a bare :root, and dark
   is redefined BOTH under prefers-color-scheme and under [data-theme="dark"], so
   a colour never has its only definition inside a media query. */
*,*::before,*::after{box-sizing:border-box}
/* The UA's [hidden] rule loses to any class that sets display, and .controls sets
   display:flex - so hiding the control row by attribute silently does nothing
   without this. */
[hidden]{display:none!important}
:root{
  color-scheme:light dark;
  --ground:#F3F4F6; --surface:#FFF; --raised:#FAFAFB; --tile:#FFF;
  --ink:#14161A; --muted:#5A6070; --line:#DFE2E8;
  --accent:#8A6100; --sel:#14161A; --sel-ink:#FFF;
  --d1:#E3B23C; --d2:#C97B2E; --d3:#9C4A24; --d4:#6B2D1F;
  --bad:#B4432B; --ok:#1F7A45;
  --f-display:ui-sans-serif,system-ui,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  --f-body:ui-sans-serif,system-ui,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
}
@media (prefers-color-scheme:dark){:root:not([data-theme="light"]){
  --ground:#101216; --surface:#191C22; --raised:#1F232B; --tile:#232830;
  --ink:#E8EAED; --muted:#969DAD; --line:#2A2F3A;
  --accent:#F5C518; --sel:#E8EAED; --sel-ink:#14161A;
  --bad:#E4694B; --ok:#4ADE80;
}}
:root[data-theme="dark"]{
  --ground:#101216; --surface:#191C22; --raised:#1F232B; --tile:#232830;
  --ink:#E8EAED; --muted:#969DAD; --line:#2A2F3A;
  --accent:#F5C518; --sel:#E8EAED; --sel-ink:#14161A;
  --bad:#E4694B; --ok:#4ADE80;
}
body{margin:0;background:var(--ground);color:var(--ink);font-family:var(--f-body);
  font-size:15px;line-height:1.5;-webkit-font-smoothing:antialiased}
.wrap{max-width:560px;margin:0 auto;padding:20px 14px 48px}

header{display:flex;flex-direction:column;gap:3px;margin-bottom:14px}
.hrow{display:flex;align-items:flex-start;justify-content:space-between;gap:10px}
.eyebrow{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.14em;color:var(--accent)}
h1{font-family:var(--f-display);font-size:26px;font-weight:800;letter-spacing:-.025em;
  text-transform:uppercase;margin:0}
.sub{color:var(--muted);font-size:13px;margin:2px 0 0}

.tools{display:flex;gap:5px;flex-shrink:0}
.icon{width:31px;height:31px;padding:0;border-radius:8px;border:1px solid var(--line);
  background:var(--surface);color:var(--muted);font:inherit;font-size:14px;line-height:1;
  cursor:pointer;display:flex;align-items:center;justify-content:center}
.icon:hover{border-color:var(--accent);color:var(--ink)}
.icon:focus-visible{outline:2px solid var(--accent);outline-offset:2px}

/* Tooltips. Shown on hover AND on keyboard focus - a `title` attribute does only
   the first, which is why this is CSS rather than markup. Colours are --ink on
   --surface, which inverts by itself in dark mode. pointer-events:none matters:
   without it the tip sits over the button it describes and eats the click. */
.tip{position:relative}
.tip::after{content:attr(data-tip);position:absolute;top:calc(100% + 6px);right:0;
  white-space:nowrap;font-size:11px;font-weight:650;line-height:1;padding:5px 7px;
  border-radius:6px;background:var(--ink);color:var(--surface);
  opacity:0;pointer-events:none;transition:opacity .12s ease;z-index:20}
.tip:hover::after,.tip:focus-visible::after{opacity:1}
/* The mode tips sit at the LEFT of the row and say more than one word, so they
   anchor left and are allowed to wrap - right:0 + nowrap would run the Easy tip
   off the left edge of a phone. */
.modes .tip::after{left:0;right:auto;white-space:normal;width:max-content;max-width:200px}
/* A disabled button explains nothing by being hovered, but the archive button is
   disabled only while the manifest loads, so the tip still earns its place. */
.tip:disabled::after{opacity:0}
.tip:disabled:hover::after{opacity:1}

.modes{display:flex;align-items:center;gap:5px;margin-top:11px;flex-wrap:wrap}
.modes button{font:inherit;font-size:12px;font-weight:650;padding:5px 10px;border-radius:999px;
  border:1px solid var(--line);background:var(--surface);color:var(--muted);cursor:pointer}
.modes button[aria-pressed="true"]{background:var(--sel);color:var(--sel-ink);border-color:var(--sel)}
.modes button:disabled{cursor:default;opacity:.55}
.modes button:disabled[aria-pressed="true"]{opacity:1}
.modes button:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.modelock{font-size:10.5px;color:var(--muted);text-transform:uppercase;letter-spacing:.09em}

.hints{margin:0 0 8px;display:flex;flex-wrap:wrap;gap:5px}
.hintlabel{width:100%;font-size:10.5px;font-weight:700;text-transform:uppercase;
  letter-spacing:.1em;color:var(--muted);margin:0 0 2px}
.chip{font-size:11.5px;font-weight:650;padding:4px 9px;border-radius:999px;
  border:1px dashed var(--line);color:var(--ink);background:var(--raised)}
.reveal{font:inherit;font-size:12px;font-weight:650;padding:6px 12px;border-radius:999px;
  border:1px dashed var(--accent);background:var(--raised);color:var(--accent);cursor:pointer}
.reveal:hover{background:var(--surface)}
.reveal:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.hintnote{width:100%;font-size:11px;color:var(--muted);margin:5px 0 0}
.date{font-size:12px;font-weight:650;color:var(--muted);margin:0 0 10px;
  text-transform:uppercase;letter-spacing:.09em}

.solved{display:flex;flex-direction:column;gap:6px;margin-bottom:6px}
.band{border-radius:9px;padding:9px 12px;color:#fff}
.band.t1{background:var(--d1);color:#2A1F06} .band.t2{background:var(--d2)}
.band.t3{background:var(--d3)} .band.t4{background:var(--d4)}
.band .bl{font-weight:750;font-size:13px;letter-spacing:-.005em}
.band .bm{font-size:12px;opacity:.92}

.board{display:grid;grid-template-columns:repeat(4,1fr);gap:6px}
.tile{background:var(--tile);border:1px solid var(--line);border-radius:9px;
  min-height:62px;padding:5px 3px;display:flex;align-items:center;justify-content:center;
  text-align:center;font-size:11.5px;font-weight:600;line-height:1.2;cursor:pointer;
  color:var(--ink);font-family:inherit;
  user-select:none;transition:transform .08s ease,background .12s ease}
.tile:hover{border-color:var(--accent)}
.tile:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.tile[aria-pressed="true"]{background:var(--sel);color:var(--sel-ink);border-color:var(--sel)}
.tile.shake{animation:shake .4s}
@keyframes shake{0%,100%{transform:translateX(0)}20%{transform:translateX(-5px)}
  40%{transform:translateX(5px)}60%{transform:translateX(-3px)}80%{transform:translateX(3px)}}

.msg{min-height:22px;text-align:center;font-size:13px;font-weight:600;margin:10px 0 4px}
.msg.bad{color:var(--bad)} .msg.good{color:var(--ok)}

.controls{display:flex;gap:8px;margin-top:6px}
.controls button{flex:1;font:inherit;font-size:14px;font-weight:650;padding:11px;
  border-radius:10px;border:1px solid var(--line);background:var(--surface);
  color:var(--ink);cursor:pointer}
.controls button.primary{background:var(--sel);color:var(--sel-ink);border-color:var(--sel)}
.controls button:disabled{opacity:.4;cursor:default}
.controls button:focus-visible{outline:2px solid var(--accent);outline-offset:2px}

.lives{display:flex;align-items:center;justify-content:center;gap:6px;margin:12px 0 0;
  font-size:12px;color:var(--muted)}
.dot{width:9px;height:9px;border-radius:50%;background:var(--ink);opacity:.85}
.dot.gone{background:var(--line);opacity:1}

/* A finished sample offers up to four buttons in one row, which at flex:1 (basis
   0) would shrink past their own text rather than wrap. A real basis makes them
   wrap onto a second row instead of clipping. */
.result .controls{flex-wrap:wrap}
.result .controls button{flex:1 1 140px}

.result,.notice{margin-top:18px;border:1px solid var(--line);border-radius:12px;
  background:var(--surface);padding:15px 16px}
.result h2,.notice h2{font-family:var(--f-display);font-size:13px;font-weight:750;
  text-transform:uppercase;letter-spacing:.1em;margin:0 0 10px;color:var(--accent)}
.notice p{margin:0 0 8px;font-size:14px}
.notice p:last-child{margin-bottom:0}
.grid{font-family:ui-monospace,Menlo,Consolas,monospace;font-size:20px;line-height:1.28;
  margin:0;letter-spacing:.06em}
.rate{display:flex;flex-wrap:wrap;gap:6px;align-items:center;margin:13px 0 0;
  padding-top:12px;border-top:1px solid var(--line)}
.ratelabel{width:100%;font-size:10.5px;font-weight:700;text-transform:uppercase;
  letter-spacing:.1em;color:var(--muted);margin:0 0 3px}
.ratethumb{font:inherit;font-size:18px;line-height:1;padding:6px 15px;border-radius:10px;
  border:1px solid var(--line);background:var(--raised);cursor:pointer}
.ratethumb:hover{border-color:var(--accent)}
.ratethumb:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.ratechip{font:inherit;font-size:11.5px;font-weight:650;padding:5px 10px;border-radius:999px;
  border:1px solid var(--line);background:var(--surface);color:var(--ink);cursor:pointer}
.ratechip:hover{border-color:var(--accent);color:var(--accent)}
.ratechip:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.ratechip.skip{color:var(--muted)}
.ratethanks{font-size:12.5px;color:var(--muted);margin:0}

.streakline{font-size:13px;color:var(--muted);margin:11px 0 0}
.streakline b{color:var(--ink);font-weight:700;font-variant-numeric:tabular-nums}
.hint{font-size:12px;color:var(--muted);margin:9px 0 0}
.hint a{color:var(--accent)}
/* Announced, never shown. clip-path rather than display:none, which removes it
   from the accessibility tree along with everything else. */
.sr{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;
  clip-path:inset(50%);white-space:nowrap;border:0}

/* Dialogs. showModal() supplies focus trapping, Esc and the backdrop; all this
   has to do is not fight the token palette. */
dialog{max-width:420px;width:calc(100% - 28px);border:1px solid var(--line);border-radius:14px;
  background:var(--surface);color:var(--ink);padding:17px 18px;font-family:var(--f-body);
  font-size:14px;line-height:1.5}
dialog::backdrop{background:rgba(0,0,0,.55)}
dialog h2{font-family:var(--f-display);font-size:13px;font-weight:750;text-transform:uppercase;
  letter-spacing:.1em;margin:0 0 11px;color:var(--accent)}
dialog p{margin:0 0 9px}
.modelist{margin:0 0 9px;padding-left:18px}
.modelist li{margin-bottom:5px}

.figs{display:grid;grid-template-columns:repeat(4,1fr);gap:7px;margin-bottom:14px}
.fig{background:var(--raised);border-radius:9px;padding:9px 4px;text-align:center}
.fig b{display:block;font-size:19px;font-weight:800;font-variant-numeric:tabular-nums}
.fig span{font-size:9.5px;text-transform:uppercase;letter-spacing:.08em;color:var(--muted)}

.dist{display:flex;flex-direction:column;gap:3px;margin-bottom:11px}
.brow{display:flex;align-items:center;gap:7px;font-size:12px}
.bn{width:11px;color:var(--muted);font-variant-numeric:tabular-nums}
.bbar{height:14px;min-width:3px;border-radius:3px;background:var(--d1)}
.bv{color:var(--muted);font-variant-numeric:tabular-nums}

#archivelist{max-height:47vh;overflow-y:auto;margin-bottom:4px}
.arow{display:flex;justify-content:space-between;gap:10px;padding:9px 2px;
  border-bottom:1px solid var(--line);text-decoration:none;color:var(--ink);font-size:13px}
.arow:last-child{border-bottom:0}
.arow:hover{color:var(--accent)}
.arow .ok{color:var(--ok);font-weight:650}
.arow .bad{color:var(--bad);font-weight:650}
.arow .muted{color:var(--muted)}
.empty{color:var(--muted);font-size:13px}

footer{margin-top:34px;padding-top:16px;border-top:1px solid var(--line);
  font-size:11.5px;line-height:1.55;color:var(--muted)}
footer p{margin:0 0 8px}
footer p:last-child{margin-bottom:0}
footer strong{color:var(--ink)}
footer a{color:var(--accent)}

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