/* ===========================================================================
   Lingo Chess — interface
   Mobile-first. Light is the default theme; dark is designed, not inverted.
   Three accessibility axes ride on the same tokens: text scale (--fs),
   contrast ([data-contrast]) and motion ([data-motion]).
   =========================================================================== */

/* ---------- Tokens: light (the default a first-time visitor gets) ---------- */
:root {
  color-scheme: light;
  --fs: 1;                       /* text scale, set by the accessibility panel */

  --bg: #f4f6fb;
  --bg-grad: radial-gradient(1100px 700px at 85% -15%, #e5e9ff 0%, transparent 60%);
  --surface: #ffffff;
  --surface-2: #f1f3f9;
  --surface-3: #e7eaf3;
  --text: #14192a;
  --text-dim: #5b6478;
  --border: #dde1ec;
  --border-strong: #c3c9da;

  --primary: #4f46e5;
  --primary-2: #6d5ef8;
  --primary-soft: #eceafe;
  --accent: #0f9d76;
  --accent-soft: #e2f6f0;
  --danger: #dc2743;
  --warn: #b45309;
  --focus: #1d4ed8;

  --sq-light: #eef1e2;
  --sq-dark: #7d9b63;
  --pc-white: #ffffff;
  --pc-white-line: #2a3242;
  --pc-black: #2b3242;
  --pc-black-line: #0d1220;
  --pc-detail-light: #2a3242;
  --pc-detail-dark: #d7dfef;

  --sel: #f2d35b;
  --target: rgba(20, 30, 20, .30);
  --target-cap: rgba(220, 39, 67, .70);
  --last: rgba(242, 211, 91, .55);
  --check: rgba(220, 39, 67, .60);

  /* Scrollbar: a thin rail that is present without asking for attention. The track is a
     whisper rather than nothing, so a scrollable area reads as scrollable even while the
     thumb sits at one end; the thumb itself is a rounded capsule inset from the edge. */
  --sb-thumb: #c3cade;
  --sb-thumb-hover: #a0a9c4;
  --sb-thumb-active: #838da9;
  --sb-track: rgba(20, 25, 42, .045);
  --sb-size: 11px;

  --radius: 18px;
  --radius-sm: 12px;
  --radius-xs: 9px;
  --shadow: 0 12px 32px rgba(24, 39, 75, .10);
  --shadow-sm: 0 4px 14px rgba(24, 39, 75, .07);
  --font: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --tap: 44px;                   /* minimum comfortable touch target */
}

[data-theme="dark"] {
  color-scheme: dark;
  --bg: #0d1220;
  --bg-grad: radial-gradient(1100px 700px at 85% -15%, #1b2450 0%, transparent 60%);
  --surface: #161d31;
  --surface-2: #1e2739;
  --surface-3: #273148;
  --text: #e9edf7;
  --text-dim: #9aa5bd;
  --border: #2a3550;
  --border-strong: #3b486a;

  --primary: #7c73ff;
  --primary-2: #9a91ff;
  --primary-soft: #232a55;
  --accent: #35c79a;
  --accent-soft: #14342c;
  --danger: #ff5c78;
  --warn: #f0a13a;
  --focus: #8ab4ff;

  --sq-light: #dfe6cf;
  --sq-dark: #5f7d4a;
  --pc-black: #333e52;
  --pc-black-line: #0a0f1a;
  --shadow: 0 14px 36px rgba(0, 0, 0, .45);
  --shadow-sm: 0 4px 16px rgba(0, 0, 0, .35);
  --sb-thumb: #3a4665;
  --sb-thumb-hover: #4f5d83;
  --sb-thumb-active: #6675a0;
  --sb-track: rgba(255, 255, 255, .04);
}

/* High contrast: stronger separation everywhere, not just darker text. */
[data-contrast="high"] {
  --text: #000000;
  --text-dim: #22262f;
  --border: #4a5164;
  --border-strong: #14192a;
  --surface-2: #ffffff;
  --sq-light: #ffffff;
  --sq-dark: #58708f;
  --target: rgba(0, 0, 0, .55);
  --sb-thumb: #14192a;
  --sb-thumb-hover: #000000;
  --sb-thumb-active: #000000;
  --sb-track: rgba(20, 25, 42, .12);
  --sel: #ffd400;
  --last: rgba(255, 212, 0, .75);
  --shadow: none;
  --shadow-sm: none;
}
[data-theme="dark"][data-contrast="high"] {
  --text: #ffffff;
  --text-dim: #e2e8f5;
  --surface: #000814;
  --surface-2: #0b1526;
  --border: #7e8aa6;
  --border-strong: #ffffff;
  --sq-light: #e9eef7;
  --sq-dark: #3d5a80;
  --sb-thumb: #d8e0f0;
  --sb-thumb-hover: #ffffff;
  --sb-thumb-active: #ffffff;
  --sb-track: rgba(255, 255, 255, .14);
}

/* ---------- Scrollbars ----------
   Thin, rounded, track almost invisible, thumb clearly there. Firefox gets the standard
   properties, WebKit the pseudo-elements; neither is used alone. The thumb is never
   hidden on a long area — you should be able to see that there is more below. */
*, html, body { scrollbar-width: thin; scrollbar-color: var(--sb-thumb) var(--sb-track); }
::-webkit-scrollbar { width: var(--sb-size); height: var(--sb-size); background: transparent; }
::-webkit-scrollbar-track { background: var(--sb-track); border-radius: 999px; }
/* The 3px transparent border is what makes the thumb a slim capsule floating in the rail
   rather than a block filling it — `background-clip: padding-box` keeps the colour inside
   that border. It is the difference between this and a default browser scrollbar. */
::-webkit-scrollbar-thumb {
  background: var(--sb-thumb); border-radius: 999px;
  border: 3px solid transparent; background-clip: padding-box;
  min-height: 32px;                     /* never a dot on a very long list */
}
::-webkit-scrollbar-thumb:hover { background: var(--sb-thumb-hover); background-clip: padding-box; }
::-webkit-scrollbar-thumb:active { background: var(--sb-thumb-active); background-clip: padding-box; }
/* THE reason the scrollbars still looked native: styling `::-webkit-scrollbar` without
   also declaring the buttons leaves WebKit drawing the end arrows with the system theme.
   The rail came out custom and the two little arrows stayed grey and square, which is
   what "still looks like a default scrollbar" was. Every button variant is zeroed here,
   because some builds draw a pair at each end rather than one.
   `track-piece` goes the same way: left undeclared it keeps the native track painting
   above and below the thumb, which is the other half of the old look. */
::-webkit-scrollbar-button,
::-webkit-scrollbar-button:start,
::-webkit-scrollbar-button:end,
::-webkit-scrollbar-button:vertical:start:decrement,
::-webkit-scrollbar-button:vertical:end:increment,
::-webkit-scrollbar-button:horizontal:start:decrement,
::-webkit-scrollbar-button:horizontal:end:increment {
  display: none; width: 0; height: 0; background: transparent;
}
::-webkit-scrollbar-track-piece { background: transparent; }
::-webkit-scrollbar-corner, ::-webkit-resizer { background: transparent; border: 0; }
/* Reserve the rail so content does not shift sideways the moment a list gets long
   enough to scroll. Only where scrolling is expected, never on the page itself. */
.tab-panel, .modal, .diag-list, .menu-items, .vocab-list, .settings-form { scrollbar-gutter: stable; }
/* An inner scroller keeps its overscroll to itself instead of dragging the page along. */
.tab-panel, .modal, .diag-list, .menu-items, .vocab-list { overscroll-behavior: contain; }

/* While a dialog is open the page behind it must not scroll — and must get its scroll
   back the moment the dialog closes. The lock is derived from what is open, never counted. */
html.scroll-locked { overflow: hidden; padding-right: var(--sbw, 0px); }

/* ---------- Base ---------- */
* { box-sizing: border-box; }
html { font-size: calc(100% * var(--fs)); -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; }
html, body { margin: 0; padding: 0; }
body {
  font-family: var(--font);
  background: var(--bg-grad), var(--bg);
  background-attachment: fixed;
  color: var(--text);
  min-height: 100vh;
  min-height: 100svh;
  line-height: 1.45;
  -webkit-text-size-adjust: 100%;
  overscroll-behavior-y: auto;
}
h1, h2, h3 { margin: 0; line-height: 1.2; }
p { margin: 0; }
button, input, select { font-family: inherit; }
button { cursor: pointer; }
.hidden { display: none !important; }
[hidden] { display: none !important; }

:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
  border-radius: 6px;
}
.skip-link {
  position: absolute; left: -999px; top: 0; z-index: 100;
  background: var(--primary); color: #fff; padding: .6rem 1rem; border-radius: 0 0 10px 0; font-weight: 700;
}
.skip-link:focus { left: 0; }

/* Motion: the OS preference is honoured, and the explicit switch overrides it either way. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .001ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; }
}
[data-motion="reduced"] *, [data-motion="reduced"] *::before, [data-motion="reduced"] *::after {
  animation: none !important; transition: none !important; scroll-behavior: auto !important;
}

/* ---------- Controls ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
  min-height: var(--tap);
  background: var(--surface); color: var(--text);
  border: 1.5px solid var(--border); border-radius: var(--radius-sm);
  padding: .55rem 1rem; font-size: .95rem; font-weight: 650;
  transition: background .15s ease, border-color .15s ease, transform .08s ease;
}
.btn:hover { background: var(--surface-2); border-color: var(--border-strong); }
.btn:active { transform: translateY(1px); }
.btn:disabled { opacity: .45; cursor: not-allowed; }
.btn-primary {
  background: linear-gradient(135deg, var(--primary), var(--primary-2));
  color: #fff; border-color: transparent; box-shadow: var(--shadow-sm);
}
.btn-primary:hover { filter: brightness(1.07); background: linear-gradient(135deg, var(--primary), var(--primary-2)); }
.btn-ghost { background: transparent; border-color: transparent; }
.btn-ghost:hover { background: var(--surface-2); }
.btn-danger { background: var(--danger); color: #fff; border-color: transparent; }
.btn-xl { width: 100%; padding: 1rem 1.4rem; font-size: 1.1rem; font-weight: 750; margin-top: .4rem; }

.icon-btn {
  background: transparent; border: 1.5px solid transparent; color: var(--text);
  width: var(--tap); height: var(--tap); min-width: var(--tap);
  border-radius: var(--radius-xs); display: grid; place-items: center; padding: 0;
}
.icon-btn:hover { background: var(--surface-2); }

/* Theme control in the header: sun · switch · moon. It replaced a single icon button,
   which could not say which state you were in — only which one you would get. The lit
   side is the theme you are in now. The whole pill is at least one tap target tall, and
   the switch's own hit area is stretched to match it (::after), so a thumb cannot miss. */
.theme-toggle {
  display: inline-flex; align-items: center; gap: .4rem;
  min-height: var(--tap); padding: 0 .5rem;
  border: 1.5px solid transparent; border-radius: 999px;
}
.theme-toggle:hover { background: var(--surface-2); }
.tt-icon { display: grid; place-items: center; color: var(--text-dim); transition: color .18s ease; }
.tt-icon svg { width: 17px; height: 17px; }
.tt-icon.on { color: var(--text); }
.switch.sm { width: 40px; height: 22px; }
.switch.sm .slider::before { width: 16px; height: 16px; left: 2px; top: 2px; }
.switch.sm input:checked + .slider::before { transform: translateX(18px); }
/* Reaches the full 44px tap target without making the drawn switch bigger. */
.switch.sm::after { content: ""; position: absolute; inset: -11px -4px; border-radius: 999px; }
.icon-btn svg { width: 21px; height: 21px; }
.icon-btn.off { opacity: .5; }

.mini-btn {
  background: var(--surface-2); border: 1.5px solid var(--border); color: var(--text);
  border-radius: 999px; padding: .4rem .8rem; font-size: .82rem; font-weight: 650;
  display: inline-flex; align-items: center; gap: .35rem; min-height: 36px;
}
.mini-btn:hover { border-color: var(--primary); }
.mini-btn.done { background: var(--accent-soft); border-color: var(--accent); }

.pill {
  background: var(--surface); border: 1.5px solid var(--border); color: var(--text-dim);
  border-radius: 999px; padding: .5rem 1rem; font-weight: 650; font-size: .9rem;
  min-height: 40px; transition: background .15s ease, color .15s ease, border-color .15s ease;
}
.pill:hover { border-color: var(--border-strong); color: var(--text); }
.pill.active { background: var(--primary); border-color: var(--primary); color: #fff; }
/* An option this device cannot honour: visibly out of reach, and said in words under the
   row as well, never by colour alone. */
.pill.unavailable { opacity: .45; cursor: not-allowed; text-decoration: line-through; }
.pill.unavailable:hover { border-color: var(--border); color: var(--text-dim); }
.pill-note { flex-basis: 100%; color: var(--text-dim); font-size: .78rem; line-height: 1.4; }
.pill-row { display: flex; flex-wrap: wrap; gap: .45rem; }

/* Segmented control — used for the two language choices */
.seg { display: flex; background: var(--surface-2); border: 1.5px solid var(--border); border-radius: var(--radius-sm); padding: .25rem; gap: .25rem; }
.seg button {
  flex: 1; background: transparent; border: 0; color: var(--text-dim);
  border-radius: var(--radius-xs); padding: .55rem .5rem; font-weight: 700; font-size: .92rem;
  min-height: 40px; white-space: nowrap;
}
.seg button:hover { color: var(--text); }
.seg button.active { background: var(--surface); color: var(--text); box-shadow: var(--shadow-sm); }
[data-theme="dark"] .seg button.active { background: var(--surface-3); }

/* Switch */
.switch { position: relative; display: inline-block; width: 50px; height: 30px; flex: 0 0 auto; cursor: pointer; }
/* The input is invisible but still the thing being clicked: it covers the whole track and
   sits above the slider painted on top of it. A zero-sized input (what this was) can only
   ever be reached by keyboard, which is how a switch ends up looking wired and doing
   nothing. `.switch` being a <label> makes the click work even before this rule applies. */
.switch input { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; margin: 0; cursor: pointer; z-index: 1; }
.switch .slider { position: absolute; inset: 0; background: var(--surface-3); border: 1.5px solid var(--border); border-radius: 999px; transition: background .18s ease; }
.switch .slider::before { content: ""; position: absolute; width: 22px; height: 22px; left: 2px; top: 2px; background: #fff; border-radius: 50%; box-shadow: 0 1px 3px rgba(0,0,0,.3); transition: transform .18s ease; }
.switch input:checked + .slider { background: var(--primary); border-color: var(--primary); }
.switch input:checked + .slider::before { transform: translateX(20px); }
.switch input:focus-visible + .slider { outline: 3px solid var(--focus); outline-offset: 2px; }

input[type="range"] { width: 100%; accent-color: var(--primary); height: 28px; }
select, .type-input {
  background: var(--surface); color: var(--text); border: 1.5px solid var(--border);
  border-radius: var(--radius-xs); padding: .6rem .7rem; font-size: .95rem; min-height: var(--tap); width: 100%;
}

/* ===========================================================================
   Setup screen
   =========================================================================== */
.setup { min-height: 100vh; min-height: 100svh; display: flex; justify-content: center; padding: clamp(.8rem, 3vw, 2rem) clamp(.7rem, 3vw, 1.5rem) 3rem; }
.setup-shell { width: min(880px, 100%); display: grid; gap: clamp(.7rem, 2vw, 1rem); align-content: start; }
.setup-head { display: flex; align-items: center; gap: 1rem; padding: .2rem .2rem .4rem; }
.setup-head-actions { margin-left: auto; display: flex; gap: .2rem; }
.brand { display: flex; align-items: center; gap: .85rem; min-width: 0; }
.brand-mark { width: 3rem; height: 3rem; display: grid; place-items: center; flex: 0 0 auto; }
.brand-mark svg { width: 100%; height: 100%; }
.brand-mark.sm { width: 1.9rem; height: 1.9rem; }
.brand h1 { font-size: clamp(1.5rem, 4vw, 2.1rem); font-weight: 800; letter-spacing: -.02em; }
.tagline { color: var(--text-dim); font-size: .95rem; margin-top: .15rem; }

.card {
  background: var(--surface); border: 1.5px solid var(--border); border-radius: var(--radius);
  padding: clamp(.9rem, 2.4vw, 1.3rem); box-shadow: var(--shadow-sm);
}
.card-title { display: flex; align-items: center; gap: .55rem; font-size: .82rem; font-weight: 750; text-transform: uppercase; letter-spacing: .07em; color: var(--text-dim); margin-bottom: .85rem; }
.card-ico { display: inline-grid; place-items: center; color: var(--primary); }
.card-ico svg { width: 18px; height: 18px; }
.card-note { color: var(--text-dim); font-size: .88rem; margin-top: .7rem; }
.sub-group { margin-top: 1rem; border-top: 1.5px dashed var(--border); padding-top: .9rem; }
.sub-title { font-size: .9rem; font-weight: 700; color: var(--text-dim); margin-bottom: .6rem; }

/* Languages: two roles, one arrow, no flags anywhere */
.lang-pair { display: grid; grid-template-columns: 1fr auto 1fr; align-items: end; gap: .7rem; }
.lang-side { min-width: 0; }
.lang-role { display: block; font-size: .78rem; font-weight: 750; text-transform: uppercase; letter-spacing: .05em; color: var(--text-dim); margin-bottom: .35rem; }
.lang-arrow { color: var(--primary); display: grid; place-items: center; padding-bottom: .5rem; }
.lang-arrow svg { width: 22px; height: 22px; }
.lang-summary { margin-top: .8rem; font-weight: 700; font-size: 1.05rem; text-align: center; color: var(--text); }
.lang-summary .ls-arrow { color: var(--primary); margin: 0 .5rem; }
@media (max-width: 620px) {
  .lang-pair { grid-template-columns: 1fr; }
  .lang-arrow { transform: rotate(90deg); justify-self: center; padding: 0; }
}

/* CEFR: three bands, two levels each */
.cefr-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: .6rem; }
@media (max-width: 620px) { .cefr-grid { grid-template-columns: 1fr; } }
.cefr-band { background: var(--surface-2); border: 1.5px solid var(--border); border-radius: var(--radius-sm); padding: .7rem; display: grid; gap: .5rem; }
.cefr-band.on { border-color: var(--primary); background: var(--primary-soft); }
.cefr-band-name { font-weight: 750; font-size: .9rem; }
.cefr-levels { display: flex; gap: .4rem; }
.cefr-level {
  flex: 1; background: var(--surface); border: 1.5px solid var(--border); color: var(--text);
  border-radius: var(--radius-xs); padding: .5rem .2rem; font-weight: 750; font-size: 1rem; min-height: var(--tap);
}
.cefr-level:hover { border-color: var(--primary); }
.cefr-level.active { background: var(--primary); border-color: var(--primary); color: #fff; }
.cefr-band-desc { font-size: .78rem; color: var(--text-dim); line-height: 1.3; }

/* Choice cards (how to learn / how to play) */
.choice-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: .6rem; }
.choice {
  background: var(--surface-2); border: 1.5px solid var(--border); border-radius: var(--radius-sm);
  padding: .85rem; text-align: left; color: var(--text); display: grid; gap: .25rem;
  grid-template-columns: auto 1fr; grid-template-areas: "ico label" "ico desc";
  align-items: center; min-height: 74px; transition: border-color .15s ease, background .15s ease;
}
.choice:hover { border-color: var(--primary-2); }
.choice.active { border-color: var(--primary); background: var(--primary-soft); box-shadow: inset 0 0 0 1.5px var(--primary); }
.choice-ico { grid-area: ico; display: grid; place-items: center; width: 2.4rem; height: 2.4rem; margin-right: .6rem; color: var(--primary); background: var(--surface); border-radius: 10px; }
.choice.active .choice-ico { background: var(--surface); }
.choice-ico svg { width: 22px; height: 22px; }
.choice-label { grid-area: label; font-weight: 700; font-size: .98rem; }
.choice-desc { grid-area: desc; font-size: .8rem; color: var(--text-dim); line-height: 1.3; }

/* Tactic picker (study mode) */
.theme-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: .5rem; }
.theme-choice { display: grid; gap: .3rem; padding: .7rem; background: var(--surface-2); border: 1.5px solid var(--border); border-radius: var(--radius-sm); text-align: left; color: var(--text); min-height: 72px; }
.theme-choice:hover { border-color: var(--primary-2); }
.theme-choice.active { border-color: var(--primary); background: var(--primary-soft); }
.theme-head { display: flex; align-items: center; gap: .4rem; font-weight: 700; font-size: .92rem; }
.theme-head .t-ico { font-size: 1.1rem; }
.theme-meta { display: flex; align-items: center; gap: .4rem; font-size: .75rem; color: var(--text-dim); }
.theme-meter { flex: 1; height: 5px; border-radius: 3px; background: var(--surface-3); overflow: hidden; }
.theme-meter span { display: block; height: 100%; background: var(--accent); }
.theme-done { color: var(--accent); font-weight: 700; }
.cefr-tag { font-size: .68rem; font-weight: 800; letter-spacing: .04em; padding: .1rem .35rem; border-radius: 5px; background: var(--surface-3); color: var(--text-dim); }

/* Match options */
.opt-row { display: grid; grid-template-columns: 8.5rem 1fr; gap: .6rem; align-items: center; padding: .45rem 0; }
.opt-row + .opt-row { border-top: 1.5px dashed var(--border); }
.opt-label { font-weight: 650; font-size: .9rem; color: var(--text-dim); }
@media (max-width: 620px) { .opt-row { grid-template-columns: 1fr; gap: .35rem; } }

/* ===========================================================================
   App shell
   =========================================================================== */
.app { min-height: 100vh; min-height: 100svh; display: flex; flex-direction: column; }
.topbar {
  display: flex; align-items: center; gap: .4rem;
  padding: .45rem clamp(.5rem, 2vw, 1rem);
  background: var(--surface);
  background: color-mix(in srgb, var(--surface) 88%, transparent);
  backdrop-filter: blur(12px);
  border-bottom: 1.5px solid var(--border);
  position: sticky; top: 0; z-index: 20;
}
.topbar-title { display: flex; align-items: center; gap: .45rem; font-size: 1rem; font-weight: 750; }
.topbar-meta { display: flex; gap: .35rem; margin-left: auto; align-items: center; overflow: hidden; }
.topbar-actions { display: flex; gap: .1rem; }
.chip {
  background: var(--surface-2); border: 1.5px solid var(--border); border-radius: 999px;
  padding: .28rem .6rem; font-size: .78rem; font-weight: 750; white-space: nowrap; color: var(--text);
  display: inline-flex; align-items: center; gap: .25rem;
}
.chip-btn { min-height: 32px; }
.chip-btn:hover { border-color: var(--primary); }
.chip.streak { color: #e8720c; }
[data-theme="dark"] .chip.streak { color: #ffa24d; }
#lang-chip .lc-arrow { color: var(--primary); }
@media (max-width: 860px) { .topbar-title strong { display: none; } #level-chip { display: none; } }
@media (max-width: 560px) { #cefr-chip { display: none; } }

.layout {
  flex: 1; display: grid; gap: clamp(.6rem, 1.6vw, 1.1rem);
  grid-template-columns: minmax(0, 1fr) clamp(290px, 25vw, 370px);
  padding: clamp(.6rem, 1.8vw, 1.2rem); width: 100%; max-width: 1500px; margin: 0 auto;
  align-items: start;
}
/* Collapsed panel: a slim rail keeps the affordance and gives the board the room. */
.layout.side-collapsed { grid-template-columns: minmax(0, 1fr) 3.4rem; }
.layout.side-collapsed .tabs, .layout.side-collapsed .tab-panels { display: none; }
.layout.side-collapsed .side-head { justify-content: center; padding: .4rem; }
.layout.side-collapsed .side-collapse svg { transform: rotate(180deg); }

/* ---------- Board column ---------- */
.board-col { display: flex; flex-direction: column; gap: .55rem; min-width: 0; }

.hud {
  display: flex; align-items: center; justify-content: space-between; gap: .6rem;
  background: var(--surface); border: 1.5px solid var(--border); border-radius: var(--radius-sm);
  padding: .5rem .75rem; min-height: 48px;
}
.hud-turn { display: flex; align-items: center; gap: .5rem; min-width: 0; }
.turn-dot { width: 15px; height: 15px; border-radius: 50%; background: var(--pc-white); border: 2px solid var(--pc-white-line); flex: 0 0 auto; }
.turn-dot.black { background: var(--pc-black); border-color: var(--pc-black-line); }
.status-text { font-weight: 700; font-size: .98rem; }
.status-text.check { color: var(--danger); }
.hud-flag { display: inline-flex; align-items: center; gap: .3rem; font-size: .74rem; font-weight: 700; color: var(--accent); background: var(--accent-soft); border-radius: 999px; padding: .2rem .5rem; }
.hud-flag svg { width: 14px; height: 14px; }
.hud-clocks { display: flex; gap: .4rem; }
.clock { display: inline-flex; align-items: center; gap: .35rem; font-variant-numeric: tabular-nums; font-weight: 750; padding: .25rem .5rem; border-radius: 8px; border: 1.5px solid transparent; background: var(--surface-2); }
.clock.active { border-color: var(--primary); background: var(--primary-soft); }
.clock.low .clock-time { color: var(--danger); }
.clock-dot { width: 10px; height: 10px; border-radius: 50%; border: 1.5px solid var(--pc-white-line); background: var(--pc-black); }
.clock-dot.light { background: var(--pc-white); }
.clock-time { font-size: .95rem; }

/* The lesson strip — the word being taught lives above the board, once. */
.lesson {
  display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: .6rem;
  background: var(--surface); border: 1.5px solid var(--border); border-left: 4px solid var(--primary);
  border-radius: var(--radius-sm); padding: .5rem .75rem;
}
.lesson.solved { border-left-color: var(--accent); }
.lesson.failed { border-left-color: var(--danger); }
.lesson-term { display: inline-flex; align-items: baseline; gap: .4rem; background: transparent; border: 0; color: var(--text); padding: .2rem .3rem; border-radius: 8px; min-height: 36px; }
.lesson-term:hover { background: var(--surface-2); }
.lesson-ico { font-size: 1.1rem; }
.lesson-word { font-weight: 800; font-size: 1.02rem; }
.lesson-ipa { color: var(--text-dim); font-size: .8rem; }
.lesson-say { color: var(--primary); align-self: center; display: inline-grid; }
.lesson-say svg { width: 15px; height: 15px; }
.lesson-task { font-size: .92rem; font-weight: 600; }
.lesson-count { font-size: .78rem; color: var(--text-dim); font-weight: 700; white-space: nowrap; }
@media (max-width: 560px) {
  .lesson { grid-template-columns: 1fr auto; }
  .lesson-task { grid-column: 1 / -1; }
}

/* ---------- Board ---------- */
.board-wrap { position: relative; display: grid; place-items: center; }
.board {
  width: min(100%, calc(100vh - 15.5rem));
  width: min(100%, calc(100svh - 15.5rem));
  aspect-ratio: 1 / 1; max-width: 100%;
  display: grid; grid-template-columns: repeat(8, 1fr); grid-template-rows: repeat(8, 1fr);
  border-radius: var(--radius-sm); overflow: hidden;
  box-shadow: var(--shadow); position: relative;
  /* pan-y: a vertical swipe over the board still scrolls the page. Only a square with a
     piece on it takes the gesture (see .sq.occupied), because only that can be a drag. */
  touch-action: pan-y;
  border: 3px solid var(--surface-3); outline-offset: 4px;
}
@media (min-width: 901px) { .board { width: min(100%, calc(100vh - 12rem), 760px); width: min(100%, calc(100svh - 12rem), 760px); } }
.sq { position: relative; display: grid; place-items: center; user-select: none; }
.sq.occupied { touch-action: none; }
.sq.light { background: var(--sq-light); }
.sq.dark { background: var(--sq-dark); }

/* State is never colour alone: selection gets a ring, the last move gets corner
   marks, a capture target gets a ring, a quiet target gets a dot, check gets a halo. */
.sq.sel::after { content: ""; position: absolute; inset: 0; box-shadow: inset 0 0 0 4px var(--sel); }
.sq.last::before { content: ""; position: absolute; inset: 0; background: var(--last); }
.sq.last::after {
  content: ""; position: absolute; inset: 0;
  background:
    linear-gradient(135deg, var(--text) 0 6px, transparent 6px) top left / 12px 12px no-repeat,
    linear-gradient(-135deg, var(--text) 0 6px, transparent 6px) top right / 12px 12px no-repeat,
    linear-gradient(45deg, var(--text) 0 6px, transparent 6px) bottom left / 12px 12px no-repeat,
    linear-gradient(-45deg, var(--text) 0 6px, transparent 6px) bottom right / 12px 12px no-repeat;
  opacity: .32;
}
.sq.last-from::before { opacity: .55; }
.sq.check::before { content: ""; position: absolute; inset: 0; background: radial-gradient(circle, var(--check), transparent 72%); }
.sq.target::after { content: ""; position: absolute; width: 30%; height: 30%; border-radius: 50%; background: var(--target); z-index: 1; }
.sq.target-cap::after { content: ""; position: absolute; inset: 7%; border-radius: 50%; border: 5px solid var(--target-cap); z-index: 1; }
.sq.cursor { box-shadow: inset 0 0 0 3px var(--focus); }
.board:focus-visible { outline: 3px solid var(--focus); }

/* The piece is positioned against the square itself, not sized by percentages inside a
   grid item: a percentage height in a grid cell whose row comes from `aspect-ratio` can
   resolve to zero on older WebKit, and that is exactly how pieces end up microscopic.
   `inset` ties the drawing to the padding box of .sq, which always has a size. */
.sq .piece { position: absolute; top: 6%; right: 6%; bottom: 6%; left: 6%; inset: 6%; display: block; z-index: 2; transition: transform .1s ease; }
.sq .piece svg { display: block; width: 100%; height: 100%; overflow: visible; }
.pc { stroke-width: 1.5; stroke-linejoin: round; stroke-linecap: round; }
[data-contrast="high"] .pc { stroke-width: 2.4; }
[data-contrast="high"] .pc .det { stroke-width: 2; }
.pc-w { fill: var(--pc-white); stroke: var(--pc-white-line); }
.pc-b { fill: var(--pc-black); stroke: var(--pc-black-line); }
.pc .det { fill: none; stroke-width: 1.4; }
.pc-w .det { stroke: var(--pc-detail-light); }
.pc-b .det { stroke: var(--pc-detail-dark); }
.pc-w .eye { fill: var(--pc-detail-light); stroke: none; }
.pc-b .eye { fill: var(--pc-detail-dark); stroke: none; }
.piece.dragging { transition: none; filter: drop-shadow(0 6px 10px rgba(0,0,0,.35)); }

.coord { position: absolute; font-size: .6rem; font-weight: 800; color: color-mix(in srgb, var(--text) 55%, transparent); z-index: 3; pointer-events: none; }
.coord.rank { top: 2px; left: 4px; }
.coord.file { bottom: 1px; right: 4px; }
.board.no-coords .coord { display: none; }

/* Move-quality badge floats over the board corner instead of taking a row. */
.eval-badge {
  position: absolute; top: .5rem; left: 50%; transform: translate(-50%, -8px);
  display: inline-flex; align-items: center; gap: .4rem; z-index: 6;
  background: var(--surface); border: 1.5px solid var(--eval-color, var(--border));
  border-radius: 999px; padding: .3rem .75rem; font-weight: 750; font-size: .85rem;
  box-shadow: var(--shadow-sm); opacity: 0; transition: opacity .18s ease, transform .18s ease;
}
.eval-badge.show { opacity: 1; transform: translate(-50%, 0); }
.eval-dot { width: 10px; height: 10px; border-radius: 50%; }

/* Caption — what the voice is saying, tap to repeat */
.caption {
  display: flex; align-items: center; gap: .55rem; width: 100%;
  background: var(--surface); border: 1.5px solid var(--border); border-left: 4px solid var(--primary);
  border-radius: var(--radius-sm); padding: .55rem .75rem; text-align: left; color: var(--text);
  font-size: .95rem; font-weight: 600; min-height: var(--tap);
  opacity: 0; transform: translateY(4px); transition: opacity .18s ease, transform .18s ease;
}
.caption.show { opacity: 1; transform: none; }
.caption-text { flex: 1; }
.caption.coach { border-left-color: var(--accent); }
.caption.danger { border-left-color: var(--danger); background: var(--surface); background: color-mix(in srgb, var(--surface) 88%, var(--danger) 12%); }

/* Type-the-move bar */
.type-bar { display: grid; grid-template-columns: 1fr auto auto; gap: .4rem; }
.type-input { font-weight: 650; }
.type-input.bad { border-color: var(--danger); }

/* Contextual actions: at most three plus overflow */
.actions { display: flex; gap: .45rem; flex-wrap: wrap; }
.actions .btn { flex: 1 1 auto; min-width: 0; }
.actions .btn .ico { display: inline-grid; }
.actions .btn .ico svg { width: 18px; height: 18px; }
.actions .btn-more { flex: 0 0 auto; width: var(--tap); padding: 0; }
@media (max-width: 420px) { .actions .btn { font-size: .88rem; padding: .55rem .6rem; } }

/* ---------- Side panel ---------- */
.side { background: var(--surface); border: 1.5px solid var(--border); border-radius: var(--radius); display: flex; flex-direction: column; overflow: hidden; position: sticky; top: 4.2rem; }
.side-head { display: flex; align-items: center; border-bottom: 1.5px solid var(--border); }
/* The tab strip scrolls sideways when the panel is too narrow for every tab. The strip
   itself has no visible scrollbar (it would sit across the tab labels), so the fact that
   there is more to the right has to be said some other way: an arrow button at each end,
   shown only when there is something in that direction, plus a fade over the edge. The
   arrows are what a mouse without a trackpad has — swiping and shift+wheel already work. */
.tabs-wrap { position: relative; display: flex; align-items: stretch; flex: 1; min-width: 0; }
.tabs {
  display: flex; flex: 1; min-width: 0; overflow-x: auto; scrollbar-width: none;
  scroll-behavior: smooth; scroll-snap-type: x proximity;
}
.tabs::-webkit-scrollbar { display: none; }
.tab { flex: 0 0 auto; scroll-snap-align: end; background: transparent; border: 0; color: var(--text-dim); padding: .8rem .6rem; font-weight: 700; font-size: .82rem; white-space: nowrap; border-bottom: 3px solid transparent; min-height: var(--tap); }
/* Scroll arrows. Deliberately flat and inside the strip, so they never read as the
   panel-collapse button sitting next to them behind its own dividing line. */
.tabs-arrow {
  position: absolute; top: 0; bottom: 0; z-index: 2;
  display: none; place-items: center; width: 28px; padding: 0;
  border: 0; cursor: pointer; color: var(--text);
  background: var(--surface);
}
.tabs-arrow.show { display: grid; }
.tabs-arrow:hover { color: var(--primary); }
.tabs-arrow svg { width: 17px; height: 17px; }
.tabs-arrow.left { left: 0; box-shadow: 10px 0 10px -6px var(--surface); }
.tabs-arrow.right { right: 0; box-shadow: -10px 0 10px -6px var(--surface); }
.tabs-arrow.left svg { transform: rotate(180deg); }
@media (max-width: 900px) { .tabs-arrow { width: 34px; } }
.tab:hover { color: var(--text); }
.tab.active { color: var(--primary); border-bottom-color: var(--primary); }
/* The collapse button keeps its own dividing line, and its chevron turns to face the
   way the panel will go — so it never reads as "next tab" beside the scroll arrows. */
.side-collapse { border-left: 1.5px solid var(--border); border-radius: 0; flex: 0 0 auto; }
.side-collapse svg { transition: transform .18s ease; }
.layout.side-collapsed .side-collapse svg { transform: rotate(180deg); }
.tab-panel { display: none; max-height: min(62vh, 620px); overflow-y: auto; padding: .8rem; }
.tab-panel.active { display: block; }
@media (max-width: 900px) {
  .layout { grid-template-columns: 1fr; }
  .layout.side-collapsed { grid-template-columns: 1fr; }
  .layout.side-collapsed .tabs { display: flex; }
  .side { position: static; }
  .tab-panel { max-height: 55vh; }
}

/* ===========================================================================
   Panel content — move list, word cards, review, progress
   =========================================================================== */
.movelist { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .1rem; font-variant-numeric: tabular-nums; }
.movelist li { display: grid; grid-template-columns: 2.2rem 1fr 1fr; gap: .3rem; align-items: center; padding: .1rem .2rem; border-radius: 8px; }
.movelist li:nth-child(odd) { background: var(--surface-2); }
/* The empty state is a sentence, not a move. Left in the list's three-column grid it fell
   into the 2.2rem number column and broke one word per line, which is what made it look
   unfinished. It spans the whole width instead, and balances its own line breaks. */
.movelist li.empty {
  display: block; background: none; padding: .9rem .7rem;
  color: var(--text-dim); text-align: center; line-height: 1.55; text-wrap: balance;
}
.mv-num { color: var(--text-dim); font-size: .8rem; }
.mv { background: transparent; border: 1.5px solid transparent; color: var(--text); text-align: left; padding: .3rem .45rem; border-radius: 7px; font-weight: 650; font-size: .9rem; min-height: 34px; display: flex; align-items: center; gap: .35rem; }
.mv:hover { background: var(--surface); border-color: var(--border); }
.mv-q { width: 9px; height: 9px; border-radius: 50%; display: inline-block; }
.empty { color: var(--text-dim); text-align: center; padding: 1.6rem .6rem; font-size: .92rem; }

.vocab-filter { display: flex; gap: .35rem; flex-wrap: wrap; margin-bottom: .7rem; }
.filter-pill { background: var(--surface-2); border: 1.5px solid var(--border); color: var(--text-dim); border-radius: 999px; padding: .35rem .7rem; font-size: .78rem; font-weight: 700; min-height: 34px; }
.filter-pill.active { background: var(--primary); border-color: var(--primary); color: #fff; }

.word-card { background: var(--surface-2); border: 1.5px solid var(--border); border-radius: var(--radius-sm); padding: .8rem; margin-bottom: .6rem; }
.word-card.is-new { border-color: var(--accent); }
.word-card.locked { opacity: .55; }
.wc-head { display: flex; align-items: center; gap: .6rem; }
.wc-icon { font-size: 1.4rem; width: 1.8rem; text-align: center; }
.wc-term-wrap { flex: 1; min-width: 0; }
.wc-term { font-size: 1.02rem; font-weight: 750; display: flex; align-items: center; gap: .4rem; flex-wrap: wrap; }
.wc-ipa { color: var(--text-dim); font-size: .8rem; }
.wc-trans { color: var(--text-dim); font-size: .85rem; margin-top: .1rem; }
.wc-trans b { color: var(--text); font-weight: 650; }
/* Article + gender. The tag is a word, not a colour: nothing here is carried by hue. */
.wc-gender { display: flex; align-items: baseline; gap: .4rem; flex-wrap: wrap; margin-top: .15rem; font-size: .85rem; }
.wc-gender b { color: var(--text); font-weight: 650; }
.wc-gender-tag {
  color: var(--text-dim); font-size: .72rem; letter-spacing: .02em;
  border: 1px solid var(--border); border-radius: 999px; padding: .05rem .4rem; white-space: nowrap;
}
.wc-diff { color: var(--text-dim); font-size: .7rem; letter-spacing: .1em; }
.wc-body { margin: .55rem 0; display: grid; gap: .25rem; }
.wc-def, .wc-ex { font-size: .87rem; line-height: 1.4; }
.wc-ex em { color: var(--text-dim); }
.wc-actions { display: flex; gap: .35rem; flex-wrap: wrap; }
.badge { font-size: .7rem; padding: .1rem .4rem; border-radius: 6px; background: var(--surface-3); }
.badge.ok { background: var(--accent-soft); color: var(--accent); font-weight: 800; }

.review-head { margin-bottom: .8rem; font-size: .92rem; color: var(--text-dim); }
.review-q { display: grid; gap: .6rem; }
.review-prompt { font-weight: 700; }
.listen-q { text-align: left; }
.review-options { display: grid; gap: .45rem; }
.review-opt { background: var(--surface-2); border: 1.5px solid var(--border); color: var(--text); border-radius: var(--radius-xs); padding: .7rem .8rem; font-weight: 650; text-align: left; min-height: var(--tap); }
.review-opt:hover { border-color: var(--primary); }
.review-opt.right { background: var(--accent-soft); border-color: var(--accent); }
.review-opt.wrong { background: var(--surface-2); background: color-mix(in srgb, var(--surface-2) 80%, var(--danger) 20%); border-color: var(--danger); }
.review-feedback { font-weight: 700; min-height: 1.2rem; }

.prog-level { display: flex; align-items: center; gap: 1rem; margin-bottom: 1rem; }
.prog-ring { width: 74px; height: 74px; border-radius: 50%; display: grid; place-items: center; font-weight: 800; font-size: 1.4rem; flex: 0 0 auto;
  background: conic-gradient(var(--primary) calc(var(--pct) * 1%), var(--surface-3) 0); position: relative; }
.prog-ring::before { content: ""; position: absolute; inset: 7px; border-radius: 50%; background: var(--surface); }
.prog-ring span { position: relative; }
.prog-level-info { flex: 1; min-width: 0; }
.xp-bar { height: 8px; background: var(--surface-3); border-radius: 4px; overflow: hidden; margin: .35rem 0 .2rem; }
.xp-bar span { display: block; height: 100%; background: linear-gradient(90deg, var(--primary), var(--primary-2)); }
.xp-bar.goal span { background: var(--accent); }
.stat-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: .5rem; margin-bottom: 1rem; }
.stat { background: var(--surface-2); border: 1.5px solid var(--border); border-radius: var(--radius-sm); padding: .6rem; display: grid; gap: .1rem; }
.stat-num { font-weight: 800; font-size: 1.15rem; }
.stat-lbl { font-size: .74rem; color: var(--text-dim); }
.goal-box { background: var(--surface-2); border: 1.5px solid var(--border); border-radius: var(--radius-sm); padding: .7rem; margin-bottom: 1rem; }
.goal-head { display: flex; justify-content: space-between; font-size: .88rem; margin-bottom: .3rem; }
.go-review { margin-top: .5rem; }
.ach-title { font-size: .82rem; text-transform: uppercase; letter-spacing: .06em; color: var(--text-dim); margin-bottom: .5rem; }
.ach-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(96px, 1fr)); gap: .45rem; }
.ach { background: var(--surface-2); border: 1.5px solid var(--border); border-radius: var(--radius-sm); padding: .55rem .4rem; display: grid; gap: .2rem; justify-items: center; text-align: center; }
.ach.earned { border-color: var(--accent); background: var(--accent-soft); }
.ach-medal { font-size: 1.2rem; }
.ach-name { font-size: .7rem; font-weight: 650; line-height: 1.2; }
.vocab-meter { margin-top: .8rem; text-align: center; font-size: .8rem; color: var(--text-dim); }

/* ===========================================================================
   Modals, sheets, toast
   =========================================================================== */
.modal-root { position: fixed; inset: 0; z-index: 60; display: grid; place-items: center; padding: 1rem; }
.modal-backdrop, .menu-backdrop { position: absolute; inset: 0; background: rgba(8, 12, 24, .55); backdrop-filter: blur(3px); }
.modal {
  position: relative; background: var(--surface); border: 1.5px solid var(--border); border-radius: var(--radius);
  width: min(620px, 100%); max-height: 88svh; overflow-y: auto; padding: clamp(1rem, 3vw, 1.6rem);
  box-shadow: var(--shadow);
}
.modal-close { position: absolute; top: .6rem; right: .6rem; background: var(--surface-2); border: 1.5px solid var(--border); border-radius: 10px; width: 38px; height: 38px; display: grid; place-items: center; color: var(--text); }
.modal-close svg { width: 18px; height: 18px; }

.menu-sheet { position: fixed; inset: 0; z-index: 70; display: grid; align-items: end; justify-items: center; padding: 1rem; }
.menu-card { position: relative; background: var(--surface); border: 1.5px solid var(--border); border-radius: var(--radius); width: min(460px, 100%); padding: .7rem; box-shadow: var(--shadow); display: grid; gap: .4rem; }
.menu-items { display: grid; gap: .3rem; }
.menu-item { display: flex; align-items: center; gap: .7rem; background: transparent; border: 0; color: var(--text); padding: .75rem .8rem; border-radius: var(--radius-xs); font-weight: 650; font-size: .98rem; text-align: left; min-height: var(--tap); }
.menu-item:hover { background: var(--surface-2); }
.menu-item .ico { display: inline-grid; color: var(--text-dim); }
.menu-item .ico svg { width: 20px; height: 20px; }
.menu-item.danger { color: var(--danger); }
.menu-cancel { width: 100%; }
@media (min-width: 700px) { .menu-sheet { align-items: center; } }

.toast {
  position: fixed; left: 50%; bottom: 1.2rem; transform: translate(-50%, 1rem);
  background: var(--surface); color: var(--text); border: 1.5px solid var(--border);
  border-radius: 999px; padding: .6rem 1.1rem; font-weight: 650; font-size: .9rem;
  box-shadow: var(--shadow); opacity: 0; pointer-events: none; z-index: 80; max-width: 90vw; text-align: center;
  transition: opacity .2s ease, transform .2s ease;
}
.toast.show { opacity: 1; transform: translate(-50%, 0); }
.toast.warn { border-color: var(--danger); }

/* Settings */
.settings-form { display: grid; gap: .9rem; }
.settings-form h2 { font-size: 1.25rem; font-weight: 800; }
/* Four short pills. They hide their scrollbar, so on a very narrow phone they wrap onto a
   second line instead of scrolling out of reach behind an invisible rail. */
.set-tabs { display: flex; gap: .3rem; background: var(--surface-2); border-radius: var(--radius-sm); padding: .25rem; overflow-x: auto; scrollbar-width: none; }
@media (max-width: 430px) { .set-tabs { flex-wrap: wrap; overflow-x: visible; } }
.set-tabs::-webkit-scrollbar { display: none; }
.set-tab { flex: 1; background: transparent; border: 0; color: var(--text-dim); border-radius: var(--radius-xs); padding: .55rem .4rem; font-weight: 700; font-size: .84rem; white-space: nowrap; min-height: 40px; display: inline-flex; align-items: center; justify-content: center; gap: .35rem; }
.set-tab svg { width: 17px; height: 17px; }
.set-tab.active { background: var(--surface); color: var(--text); box-shadow: var(--shadow-sm); }
[data-theme="dark"] .set-tab.active { background: var(--surface-3); }
.set-page { display: none; gap: .2rem; }
.set-page.active { display: grid; }
.set-row { display: flex; align-items: center; justify-content: space-between; gap: .8rem; padding: .7rem .1rem; border-bottom: 1.5px dashed var(--border); }
.set-row:last-child { border-bottom: 0; }
.set-row.col { display: grid; justify-items: stretch; }
.set-label { font-weight: 650; font-size: .95rem; display: grid; gap: .1rem; }
.set-label small { font-weight: 500; font-size: .78rem; color: var(--text-dim); }
.set-value { color: var(--text-dim); font-weight: 700; font-size: .85rem; }
/* The voice warning: present and readable, but not an alarm. Carried by a bar and by
   words, never by colour alone. */
.set-warn {
  display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
  margin: .2rem 0 .1rem; padding: .5rem .7rem;
  font-size: .82rem; line-height: 1.45; color: var(--text);
  background: var(--surface-2); border-left: 3px solid var(--warn);
  border-radius: var(--radius-xs);
}
.set-hint { font-size: .8rem; color: var(--text-dim); padding: .2rem 0 .6rem; }
.diag-table { width: 100%; border-collapse: collapse; font-size: .82rem; table-layout: fixed; word-break: break-word; }
.diag-table th, .diag-table td { text-align: left; padding: .35rem .4rem; border-bottom: 1px solid var(--border); }
.diag-table th { color: var(--text-dim); font-weight: 700; }
.diag-ok { color: var(--accent); font-weight: 800; }
.diag-warn { color: var(--warn); font-weight: 800; }
/* A fallback that ended on the wrong gender is not a result, it is a failure to meet the
   request, and the diagnosis has to read that way. */
.diag-bad { color: var(--danger); font-weight: 800; }
.diag-list { max-height: 200px; overflow: auto; border: 1.5px solid var(--border); border-radius: var(--radius-xs); }

/* Report / confirm / promotion */
.report { display: grid; gap: .9rem; }
.report-outcome { font-size: 1.4rem; font-weight: 800; }
.report-xp { color: var(--text-dim); font-weight: 700; }
.report-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: .5rem; }
@media (max-width: 520px) { .report-grid { grid-template-columns: repeat(2, 1fr); } }
.rg { background: var(--surface-2); border: 1.5px solid var(--border); border-radius: var(--radius-sm); padding: .6rem; display: grid; gap: .1rem; }
.rg-num { font-weight: 800; font-size: 1.2rem; }
.rg-lbl { font-size: .72rem; color: var(--text-dim); }
.report-sec h3 { font-size: .9rem; margin-bottom: .35rem; }
.report-sec ul { margin: 0; padding-left: 1.1rem; font-size: .9rem; }
.report-cols { display: grid; grid-template-columns: 1fr 1fr; gap: .8rem; }
@media (max-width: 520px) { .report-cols { grid-template-columns: 1fr; } }
.report-sec.tip { background: var(--primary-soft); border-radius: var(--radius-sm); padding: .8rem; }
.rw-chips { display: flex; flex-wrap: wrap; gap: .35rem; }
.rw-chip { background: var(--surface-2); border: 1.5px solid var(--border); border-radius: 999px; padding: .3rem .7rem; font-size: .84rem; font-weight: 650; cursor: pointer; }
.report-ach { background: var(--accent-soft); border-radius: var(--radius-sm); padding: .6rem .8rem; font-weight: 700; }
.report-actions { display: flex; gap: .5rem; }
.report-actions .btn { flex: 1; }
.confirm { display: grid; gap: 1rem; }
.confirm h2 { font-size: 1.15rem; }
.confirm-row { display: flex; gap: .5rem; }
.confirm-row .btn { flex: 1; }
.promo-chooser { display: grid; gap: .8rem; justify-items: center; }
.promo-row { display: flex; gap: .5rem; }
.promo-piece { width: 68px; height: 68px; background: var(--surface-2); border: 1.5px solid var(--border); border-radius: var(--radius-sm); display: grid; place-items: center; padding: .4rem; }
.promo-piece:hover { border-color: var(--primary); }
.promo-piece svg { width: 100%; height: 100%; }
.study-intro { display: grid; gap: .9rem; }
.study-intro h2 { font-size: 1rem; color: var(--text-dim); font-weight: 650; }
.type-help { display: grid; gap: .6rem; font-size: .92rem; }
.type-help code { background: var(--surface-2); border-radius: 6px; padding: .1rem .35rem; font-weight: 700; }

/* ===========================================================================
   Pause — only offered where stopping the clock is not a question
   =========================================================================== */
.hud-pause { flex: 0 0 auto; }
/* Opaque on purpose: a paused game must not be a free analysis board. */
.pause-overlay {
  position: absolute; inset: 0; z-index: 12; display: grid; place-items: center;
  background: var(--surface); border-radius: var(--radius-sm);
}
.pause-card {
  display: grid; gap: .55rem; justify-items: center; text-align: center;
  background: var(--surface); border: 1.5px solid var(--border); border-radius: var(--radius);
  padding: 1.1rem 1.2rem; box-shadow: var(--shadow); width: min(300px, 84%);
}
.pause-card strong { font-size: 1.25rem; }
.pause-ico { color: var(--primary); display: grid; }
.pause-ico svg { width: 34px; height: 34px; }
.pause-note { color: var(--text-dim); font-size: .85rem; }
.pause-card .btn { width: 100%; }
/* Everything that shows the position goes away while paused — the board itself, the
   move-quality badge, the caption of what was just said, the lesson strip and any open
   question. A blur is not enough: the pieces would still be readable. */
.board-wrap.paused .board { visibility: hidden; }
/* The pause hides the position, and the captures are part of what is on the board. */
.board-wrap.paused .cap-strip { visibility: hidden; }

/* ---- Captured pieces -------------------------------------------------------------
   One row above the board and one below it, each showing what that side has taken.
   A row, not a column: a side panel would either take width from the board or wrap
   underneath it on a phone, and the board has to stay the biggest thing on screen.
   Each strip collapses to nothing while there is nothing in it (hidden by the script),
   so an empty game looks exactly as it did before. */
/* The strips and the tool bar line up with the BOARD, not with the column the board sits
   in — the column is wider, and a full-width strip starts out to the left of the board.
   The expression is the board's own, repeated here on purpose; check-layout compares the
   two and fails if they ever drift apart. */
.board-wrap, .board-tools { --board-w: min(100%, max(15rem, calc(100svh - 15.5rem))); }
@media (min-width: 901px) {
  .board-wrap, .board-tools { --board-w: min(100%, max(18rem, calc(100svh - 12rem)), 760px); }
}
.cap-strip {
  display: flex; align-items: center; gap: .12rem; flex-wrap: wrap;
  width: var(--board-w); max-width: 100%; min-height: 32px; padding: .1rem 0;
}
.cap-strip[hidden] { display: none; }
/* Big enough to be read across a room, which is the point: someone who cannot make out a
   16px silhouette gets nothing from a row of them. */
.cap-piece { position: relative; display: inline-flex; width: 30px; height: 30px; }
.cap-piece svg { width: 100%; height: 100%; display: block; }
/* A new kind of piece opens a little air, so equal pieces read as a group and the eye
   counts them without a number to decode. */
.cap-piece.cap-group { margin-left: .34rem; }
.cap-piece.cap-group:first-child { margin-left: 0; }
/* Taken pieces are a record, not the game: they sit back a little so the board leads. */
.cap-strip .cap-piece { opacity: .78; }
.cap-strip:hover .cap-piece { opacity: 1; }
@media (max-width: 480px) {
  .cap-piece { width: 26px; height: 26px; }
  .cap-strip { min-height: 28px; gap: .08rem; }
  .cap-piece.cap-group { margin-left: .26rem; }
}

/* ---- Tools under the board: sound and captions ----------------------------------
   Moved down here from the top bar so that everything belonging to the game in progress
   sits next to the game. Each one is a real switch with its name and its state written
   out, so "on" and "off" are words and a knob position, never a colour. */
.board-tools {
  display: flex; align-items: center; justify-content: flex-end; gap: .5rem; flex-wrap: wrap;
  width: var(--board-w); max-width: 100%; margin: 0 auto; padding-top: .1rem;
}
.tool-toggle {
  display: inline-flex; align-items: center; gap: .4rem;
  min-height: var(--tap); padding: .15rem .6rem;
  border: 1.5px solid var(--border); border-radius: 999px;
  background: var(--surface); color: var(--text);
}
.tool-toggle:hover { border-color: var(--border-strong); }
.tool-toggle.off { color: var(--text-dim); }
.tool-ico { display: grid; place-items: center; }
.tool-ico svg { width: 18px; height: 18px; display: block; }
.tool-name { font-size: .86rem; font-weight: 650; cursor: pointer; white-space: nowrap; }
.tool-state { font-size: .78rem; font-weight: 700; color: var(--text-dim); min-width: 4.6em; }
.tool-toggle:focus-within { outline: 3px solid var(--focus); outline-offset: 2px; }
@media (max-width: 560px) {
  .board-tools { justify-content: space-between; gap: .35rem; }
  .tool-toggle { padding: .15rem .45rem; gap: .3rem; flex: 1 1 0; justify-content: center; }
  .tool-state { display: none; }          /* the struck-through icon and the knob remain */
}


body.is-paused #caption,
body.is-paused #eval-badge,
body.is-paused #lesson,
body.is-paused #quiz { visibility: hidden; }

/* ===========================================================================
   Responsive pass — phones, tablets, and the landscape phone that used to
   squeeze the board down to a postage stamp.
   =========================================================================== */

/* The board never depends on a single dimension: 100% keeps it inside the column,
   the height budget keeps it on screen, and the floor keeps it playable. */
.board { width: min(100%, max(15rem, calc(100vh - 15.5rem))); width: min(100%, max(15rem, calc(100svh - 15.5rem))); }
@media (min-width: 901px) { .board { width: min(100%, max(18rem, calc(100vh - 12rem)), 760px); width: min(100%, max(18rem, calc(100svh - 12rem)), 760px); } }

/* --- Phone, portrait --- */
@media (max-width: 560px) {
  .layout { padding: .5rem; gap: .5rem; }
  .hud { padding: .45rem .55rem; }
  .status-text { font-size: .9rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .hud-turn { min-width: 0; flex: 1; }
  .card { padding: .85rem; }
  .card-title { margin-bottom: .7rem; }
  .setup-shell { gap: .6rem; }
  .brand h1 { font-size: 1.35rem; }
  .tagline { font-size: .88rem; }
  .seg button { font-size: .84rem; padding: .55rem .25rem; letter-spacing: -.01em; }
  .choice { min-height: 68px; padding: .75rem; }
  .choice-ico { width: 2.1rem; height: 2.1rem; margin-right: .5rem; }
  .theme-grid { grid-template-columns: repeat(auto-fit, minmax(132px, 1fr)); }
  .lesson { padding: .45rem .6rem; gap: .4rem; }
  .lesson-word { font-size: .96rem; }
  .actions .btn { flex: 1 1 40%; }
  .tab { font-size: .78rem; padding: .7rem .35rem; }
  /* On a phone the page itself is the scroller: a panel that scrolls inside a page that
     scrolls inside a card is how a thumb ends up fighting the layout. */
  .tab-panel { max-height: none; overflow-y: visible; }
}

/* --- Phone, landscape: the board takes the height, everything else the width --- */
@media (orientation: landscape) and (max-height: 620px) {
  .layout { grid-template-columns: 1fr; padding: .4rem; gap: .5rem; }
  .board-col {
    display: grid; grid-template-columns: auto minmax(11rem, 1fr);
    gap: .5rem; align-items: start;
  }
  .board-wrap { grid-column: 1; grid-row: 1 / span 6; align-self: start; }
  .hud, .lesson, .caption, .type-bar, .actions, .board-tools { grid-column: 2; }
  .board { width: min(100%, max(12rem, calc(100vh - 4.6rem))); width: min(100%, max(12rem, calc(100svh - 4.6rem))); }
  /* The strips stay with the board; the tools move to the side column and fill it. */
  .board-wrap { --board-w: min(100%, max(12rem, calc(100svh - 4.6rem))); }
  /* The side column is ~11rem: the two controls stack and drop the written state, so the
     name and the switch still fit without crowding. The struck-through icon carries it. */
  .board-tools { width: 100%; flex-direction: column; align-items: stretch; gap: .3rem; }
  .board-tools .tool-toggle { justify-content: space-between; padding: .1rem .5rem; min-height: 38px; }
  .board-tools .tool-state { display: none; }
  .cap-piece { width: 24px; height: 24px; }
  .cap-strip { min-height: 26px; }
  .hud { min-height: 40px; padding: .35rem .5rem; flex-wrap: wrap; }
  .actions { flex-direction: column; }
  .actions .btn { width: 100%; flex: 0 0 auto; }
  .actions .btn-more { width: 100%; }
  .lesson { grid-template-columns: 1fr; }
  .lesson-count { justify-self: start; }
  .side { margin-top: .3rem; }
  .tab-panel { max-height: 40vh; }
}

/* --- Tablet portrait: the panel is worth showing, the board still leads --- */
@media (min-width: 601px) and (max-width: 900px) {
  .board { width: min(100%, max(20rem, calc(100vh - 17rem))); width: min(100%, max(20rem, calc(100svh - 17rem))); }
  .board-wrap, .board-tools { --board-w: min(100%, max(20rem, calc(100svh - 17rem))); }
  .choice-grid { grid-template-columns: repeat(2, 1fr); }
  .theme-grid { grid-template-columns: repeat(3, 1fr); }
}

/* Nothing may ever scroll sideways. */
html, body { max-width: 100%; }
html, body { overflow-x: hidden; }
@supports (overflow: clip) { html, body { overflow-x: clip; } }
.layout, .board-col, .setup-shell, .card { min-width: 0; }

/* ===========================================================================
   Micro-questions — a card, not a quiz screen: it must never feel like leaving
   the game. Big targets, one clearly correct answer, an escape hatch.
   =========================================================================== */
.quiz {
  background: var(--surface); border: 1.5px solid var(--primary);
  border-radius: var(--radius-sm); padding: .7rem .8rem; display: grid; gap: .55rem;
  box-shadow: var(--shadow-sm);
}
.quiz-head { display: flex; align-items: center; justify-content: space-between; gap: .5rem; }
.quiz-tag {
  font-size: .7rem; font-weight: 800; letter-spacing: .07em; text-transform: uppercase;
  color: var(--primary); background: var(--primary-soft); border-radius: 999px; padding: .2rem .55rem;
}
.quiz-skip { width: 34px; height: 34px; min-width: 34px; }
.quiz-skip svg { width: 16px; height: 16px; }
.quiz-prompt { font-weight: 700; font-size: 1rem; line-height: 1.35; }
.quiz-help { color: var(--text-dim); font-size: .85rem; }
/* The exercise text itself — a sentence or a word to READ. It is deliberately not
   spoken (see learn.js): the prompt above is the instruction and carries the voice,
   this is the thing being worked on, so it is set as content rather than as a label. */
.quiz-sentence {
  font-size: 1.05rem; line-height: 1.45; font-weight: 600;
  background: var(--surface-2); border-left: 3px solid var(--primary);
  border-radius: var(--radius-xs); padding: .5rem .65rem;
}
.quiz-options { display: grid; gap: .4rem; }
.quiz-opt {
  background: var(--surface-2); border: 1.5px solid var(--border); color: var(--text);
  border-radius: var(--radius-xs); padding: .7rem .8rem; font-weight: 650; font-size: .95rem;
  text-align: left; min-height: var(--tap); font-family: inherit;
}
.quiz-opt:hover { border-color: var(--primary); }
.quiz-opt.right { background: var(--accent-soft); border-color: var(--accent); }
.quiz-opt.wrong { background: var(--surface-2); border-color: var(--danger); }
.quiz-opt:disabled { opacity: 1; cursor: default; }
.quiz-feedback { font-size: .9rem; font-weight: 600; }
.quiz-feedback.right { color: var(--accent); }
.quiz-feedback.wrong { color: var(--danger); }
@media (max-width: 560px) { .quiz-prompt { font-size: .95rem; } .quiz-sentence { font-size: 1rem; } .quiz-opt { padding: .65rem .7rem; } }

/* ===========================================================================
   Switches — the state is written, not only coloured
   =========================================================================== */
.switch-wrap { display: inline-flex; align-items: center; gap: .55rem; flex: 0 0 auto; }
.switch-state { font-size: .82rem; font-weight: 700; color: var(--text-dim); min-width: 5.5em; text-align: right; }
.switch input:checked ~ .slider ~ .switch-state, .switch-wrap:has(input:checked) .switch-state { color: var(--primary); }
/* The pointer belongs on what actually takes the click — the words and the switch — not
   on the whole row, which would promise a target that is not there. */
.switch-row .set-label, .set-row label.set-label { cursor: pointer; }
.switch-row .set-label { min-width: 0; }

/* Light | switch | Dark — both names always readable, the active one marked */
.theme-switch { display: inline-flex; align-items: center; gap: .6rem; flex-wrap: wrap; justify-content: flex-end; }
.ts-side {
  display: inline-flex; align-items: center; gap: .35rem; font-size: .88rem; font-weight: 650;
  color: var(--text-dim); padding: .25rem .5rem; border-radius: 999px; border: 1.5px solid transparent;
}
.ts-side svg { width: 17px; height: 17px; }
.ts-side.on { color: var(--text); border-color: var(--border-strong); background: var(--surface-2); font-weight: 750; }
@media (max-width: 480px) {
  .set-row { flex-wrap: wrap; }
  .switch-state { min-width: 0; }
  .theme-switch { width: 100%; justify-content: space-between; }
}
