*, *::before, *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

/* Screen reader only — visually hidden but accessible */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

:root {
  --cell-size: 40px;
  --border-radius: 6px;
  --grid-gap: 2px;
  --font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
  --font-display: 'Segoe UI', system-ui, sans-serif;

  --color-bg: #e8e0d4;
  --color-app-bg: #d4ccc0;
  --color-cell-hidden: #d4cabb;
  --color-cell-hidden-hover: #e0d6c8;
  --color-cell-hidden-gradient: linear-gradient(145deg, #ddd3c5, #c8bead);
  --color-cell-revealed: #f5f0e8;
  --color-cell-border-light: #ede5d8;
  --color-cell-border-dark: #b8ae9e;
  --color-mine: #d32f2f;
  --color-mine-hit: #ff1744;
  --color-flag: #d32f2f;
  --color-text: #2d2416;
  --color-text-secondary: #7a6e5d;

  --color-num-1: #1565c0;
  --color-num-2: #2e7d32;
  --color-num-3: #c62828;
  --color-num-4: #4527a0;
  --color-num-5: #ad1457;
  --color-num-6: #007884;
  --color-num-7: #37474f;
  --color-num-8: #5a6f7a;
  /* 9-18 for wormhole combined counts (dark values for light base theme) */
  --color-num-9: #b33d00;
  --color-num-10: #006570;
  --color-num-11: #5c1299;
  --color-num-12: #7a7a00;
  --color-num-13: #a83000;
  --color-num-14: #00524a;
  --color-num-15: #3a0f6e;
  --color-num-16: #962a00;
  --color-num-17: #0d1a6e;
  --color-num-18: #6e0a40;

  --color-header-bg: #d4cabb;
  --color-header-gradient: linear-gradient(180deg, #ddd3c5, #c8bead);
  --color-lcd-bg: #1a1a1a;
  --color-lcd-text: #ff3333;
  --color-modal-bg: #faf7f2;
  --color-modal-overlay: rgba(0, 0, 0, 0.55);
  --color-btn-bg: #e0d6c8;
  --color-btn-hover: #ede5d8;
  --color-btn-gradient: linear-gradient(180deg, #ede5d8, #d4cabb);
  --color-border: #b8ae9e;
  --color-fog: rgba(45, 36, 22, 0.88);
  --color-scan-highlight: rgba(255, 193, 7, 0.35);
  --color-golden: #f9a825;
  --color-accent: #5c6bc0;

  /* Wordmark gradient — the "GregSweeper" title on the title screen, in-game
     header, and share card all read these, so the wordmark picks up each
     theme's identity. Default derives from the theme accent (accent → a lighter
     accent); a theme may override either stop for a bespoke treatment. */
  --wordmark-from: var(--color-accent, #5c6bc0);
  --wordmark-to: color-mix(in srgb, var(--color-accent, #5c6bc0), #ffffff 32%);
  --color-accent-hover: #3f51b5;
  --color-accent-glow: rgba(92, 107, 192, 0.3);
  --color-win: #43a047;
  --color-loss: #e53935;
  --color-surface: rgba(255, 255, 255, 0.5);

  --shadow-sm: 0 1px 3px rgba(0,0,0,0.1);
  --shadow-md: 0 4px 12px rgba(0,0,0,0.12);
  --shadow-lg: 0 8px 32px rgba(0,0,0,0.18);
  --shadow-glow: none;

  /* ── Structural shadows & effects (theme-overridable) ── */
  --shadow-app: var(--shadow-lg);
  --border-app: none;
  --bg-app: var(--color-bg);

  --shadow-cell-unrevealed: var(--shadow-sm);
  --shadow-cell-hover: var(--shadow-md);
  --border-cell-revealed: 1px solid rgba(0,0,0,0.06);

  --text-shadow-title: none;
  --text-shadow-lcd: none;
  --text-shadow-subtitle: none;
  --text-shadow-mine: none;
  --text-shadow-num-1: none;
  --text-shadow-num-2: none;
  --text-shadow-num-3: none;
  --text-shadow-num-4: none;
  --text-shadow-num-5: none;

  --shadow-board: var(--shadow-md);
  --border-board: 2px solid var(--color-border);
  --border-radius-board: 8px;

  --shadow-lcd: inset 0 2px 6px rgba(0,0,0,0.4);
  --border-lcd: 1px solid rgba(0,0,0,0.3);

  --shadow-smiley: var(--shadow-sm), 0 2px 0 var(--color-border);
  --border-smiley: none;

  --border-nav-btn: 1px solid var(--color-border);
  --shadow-nav-btn-hover: var(--shadow-md);

  --border-powerup-btn: 1px solid var(--color-border);

  --shadow-modal: var(--shadow-lg);
  --border-modal: 1px solid rgba(255,255,255,0.1);
  --bg-modal-content: var(--color-modal-bg);

  --bg-modal-close-hover: rgba(0,0,0,0.05);

  --border-achievement-unlocked: var(--color-accent);
  --shadow-achievement-unlocked: 0 0 8px var(--color-accent-glow);

  --transition-fast: 0.15s ease;
  --transition-normal: 0.25s ease;
  --transition-slow: 0.4s ease;

  /* ════════════════════════════════════════════════════════════════
     THEME EXPRESSION TOKENS
     Every token below defaults to the exact value that used to be
     hardcoded, so all themes render identically until one deliberately
     overrides a token. This is what lets a theme diverge in motion,
     type, texture, and cell treatment without a code change.
     ════════════════════════════════════════════════════════════════ */

  /* ── Motion character (only the animation shorthand is tokenized —
     @keyframes interiors cannot read vars). A theme changes feel by
     overriding duration/easing; it changes choreography with its own
     @keyframes. ── */
  --anim-reveal-dur: 0.25s;
  --anim-reveal-ease: ease-out;
  /* Flag/mine defaults are byte-for-byte the literals .cell.flag-pop /
     .cell.mine-chain used to hardcode (the tokens were declared with
     aspirational values, 0.3s / 0.35s, but never consumed — wired up
     2026-06-10, so a theme that overrides nothing animates exactly as
     before). */
  --anim-flag-dur: 0.35s;
  --anim-flag-ease: cubic-bezier(0.34, 1.56, 0.64, 1);
  --anim-mine-dur: 0.4s;
  --anim-mine-ease: cubic-bezier(0.34, 1.56, 0.64, 1);
  --ease-bounce: cubic-bezier(0.34, 1.56, 0.64, 1);
  --ease-standard: ease;

  /* ── Typography scale (defaults = current fixed px) ── */
  --fs-title: 28px;
  --fs-lcd: 28px;
  /* --fs-cell-number is superseded: the cell number now scales with --cell-size
     (see .cell font-size) so big cells use the room. Kept for back-compat only. */
  --fs-cell-number: 19px;
  --fs-mine: 20px;
  --fs-flag: 18px;

  /* ── Cell treatment + sizing hooks. --cell-min/max-size are read by
     boardRenderer.js (JS owns --cell-size at runtime). ── */
  --cell-shape-radius: var(--border-radius);
  --cell-min-size: 18px;
  --cell-max-size: 50px;      /* responsive cap (resizeCells) */
  --cell-fit-max-size: 40px;  /* fit-to-screen cap (adjustCellSize) */
  /* Color painted into the gap *ring* between revealed cells when an ambient
     effect is active (see `#board.fx-on .cell.revealed::before`). Defaults to
     the revealed surface so dark "void" themes (matrix/neon/galaxy) read as one
     continuous cleared area. Themes whose grid color contrasts with the cell
     (forest sage, candy pink) override this to their opaque grid color so the
     revealed cells stay separated as individual tiles instead of merging. */
  --cell-gap-seal: var(--color-cell-revealed);

  /* ── Background / texture hooks (vector only: gradients, CSS patterns,
     SVG data-URIs — no raster assets, so no service-worker coupling).
     Defaults paint nothing new. Animated / board ambiance routes through
     src/ui/themeEffects.js, not CSS. ── */
  --bg-page-image: none;
  --bg-page-blend: normal;
  --bg-board: transparent;

  /* ── Special-cell / modifier markers — LEGIBILITY FLOOR.
     A theme may re-hue these slightly to avoid clashing with its own
     background, but must keep every marker (a) unmistakable, (b) mutually
     distinct, (c) high-contrast against the cell bg, and (d) never below
     these alpha floors (tints >= 0.12, borders >= 0.6). Identity is
     anchored in a non-color channel (glyph / italic+underline / dashed
     border / outline) so meaning never rests on hue alone. ── */
  --marker-liar-outline: rgba(231, 76, 60, 0.9);
  --marker-liar-outline-width: 2px;
  --marker-sonar-tint: rgba(0, 200, 220, 0.15);
  --marker-compass-tint: rgba(230, 180, 0, 0.16);
  --marker-wormhole-0: rgba(255, 140, 0, 0.18);
  --marker-wormhole-1: rgba(220, 80, 220, 0.18);
  --marker-wormhole-2: rgba(100, 220, 100, 0.18);
  --marker-mirror-0: rgba(52, 152, 219, 0.85);
  --marker-mirror-1: rgba(155, 89, 182, 0.85);
  --marker-mirror-2: rgba(46, 204, 113, 0.85);
  --marker-mirror-width: 2.5px;
  --marker-plate-timer: #ff4444;
  --marker-plate-border: rgba(255, 80, 80, 0.6);
  --marker-plate-glow: rgba(255, 50, 50, 0.4);

  /* ── Greg's Gym mode-card dumbbell. The plate (weight) color is themeable;
     the inlined gym SVG in index.html fills its plates from these tokens so a
     theme can recolor the weights. Default is brand green; the bar stays
     steel. A theme overrides by setting --color-gym-weight (and optionally the
     -dark / -hi companions) in its own stylesheet. ── */
  --color-gym-weight: #2e8b57;
  --color-gym-weight-dark: #3a6a3a;
  --color-gym-weight-hi: #5ad07a;

  /* ── Post-death analysis overlays ── */
  --overlay-wrong-flag: #ff1744;
  --overlay-wrong-flag-fill: rgba(255, 23, 68, 0.15);
  --overlay-correct-flag: #00c853;
  --overlay-correct-flag-fill: rgba(0, 230, 118, 0.2);
  --overlay-suggest-move: #0091ea;
  --overlay-suggest-move-glow: rgba(0, 145, 234, 0.4);
  --overlay-suggest-start: #4caf50;
  --overlay-suggest-start-fill: rgba(76, 175, 80, 0.35);
  --overlay-suggest-start-glow: rgba(76, 175, 80, 0.4);
  --overlay-mine-hit-glow: rgba(255, 23, 68, 0.5);
  /* Red behind any revealed mine / strike cell — a theme-independent, ALL-MODES
     "this is a mine" cue (the themed sprite alone, e.g. nest's fried egg, didn't
     register). The struck/EXPLODED cell additionally gets a ring
     (--overlay-strike-ring) so it reads as a CONFIRMED found-mine — a flag + an
     exploded mine next to a 2 means it's satisfied (chord it). The hit mine
     keeps its stronger --color-mine-hit glow on top. */
  --overlay-mine-tint: rgba(206, 40, 40, 0.42);
  --overlay-strike-ring: rgba(220, 30, 30, 0.9);

  /* ── Timer urgency. Defaults are the EFFECTIVE colors, which the
     .timer-warning / .timer-critical rules set with !important (those mask
     the .lcd-display.timer-* color). --timer-critical-glow is the LCD
     critical box-shadow tint. ── */
  --timer-warning: #ff9800;
  --timer-critical: #f44336;
  --timer-critical-glow: rgba(255, 51, 51, 0.3);

  /* ── Victory overlay ── */
  --victory-color: #ffd54f;
  --victory-duration: 3600ms;

  /* ── Receipt moments (reserved) ──
     Tokens for the deduction-receipt surfaces (proof-region pulse,
     verdict chip, crux highlight) that the receipts/lens work renders.
     Reserved in the theme contract NOW so each world can voice these
     moments in its own idiom from the day they ship, instead of the
     moments being retrofitted across the catalog later. Defaults are
     theme-neutral; a world overrides them like any other token. */
  --receipt-pulse-color: rgba(80, 160, 255, 0.45);
  --receipt-verdict-bg: rgba(40, 44, 52, 0.92);
  --receipt-verdict-border: rgba(80, 160, 255, 0.6);
  --receipt-crux-outline: rgba(255, 200, 60, 0.85);

  /* ── Power-up feedback (solid/usage colors tokenized; deep glow alphas
     inside keyframes stay literal — partial by design). ── */
  --pu-shield: #43a047;
  --pu-shield-fill: rgba(67, 160, 71, 0.15);
  --pu-shield-glow: rgba(67, 160, 71, 0.6);
  --pu-xray-area: rgba(100, 149, 237, 0.15);
  --pu-xray-mine: rgba(255, 50, 50, 0.3);
  --pu-xray-accent: rgba(100, 149, 237, 0.9);
  --pu-lifeline: rgba(80, 200, 120, 0.9);
  --pu-magnet: rgba(180, 130, 255, 0.6);
}

/* ── Greg's Gym dumbbell: per-theme weight (plate) color ───────────────
   The mode-card dumbbell (inlined in index.html) fills its plates from
   --color-gym-weight. classic/dark keep the brand green set in :root; every
   other theme sets its signature color in ONE place here, and the outer-plate
   (-dark) and highlight (-hi) shades auto-derive from it via color-mix, so each
   theme is a single deliberate choice. Understated "print" worlds use their ink
   color (black on light paper, the light ink on dark grounds); vibrant worlds
   use their accent. The steel bar and dark outline stay constant across themes.
   Loaded via <img> (e.g. the gallery) the vars are undefined and the SVG's own
   green fallbacks render. */
[data-theme]:not([data-theme="classic"]):not([data-theme="dark"]) {
  --color-gym-weight-dark: color-mix(in srgb, var(--color-gym-weight) 70%, #000);
  --color-gym-weight-hi:   color-mix(in srgb, var(--color-gym-weight) 55%, #fff);
}
[data-theme="editorial"]    { --color-gym-weight: #1a1714; } /* ink */
[data-theme="sumie"]        { --color-gym-weight: #1c1814; } /* ink wash */
[data-theme="cartography"]  { --color-gym-weight: #4a3420; } /* map sepia */
[data-theme="origami"]      { --color-gym-weight: #d14a4a; } /* fold red */
[data-theme="nest"]         { --color-gym-weight: #d2492f; } /* robin red */
[data-theme="candy"]        { --color-gym-weight: #ff4081; } /* candy pink */
[data-theme="apothecary"]   { --color-gym-weight: #c89030; } /* amber glass */
[data-theme="stainedglass"] { --color-gym-weight: #e0b040; } /* leaded gold */
[data-theme="blueprint"]    { --color-gym-weight: #cfe4ff; } /* drafting white */
[data-theme="chalkboard"]   { --color-gym-weight: #ebe6da; } /* chalk */
[data-theme="noir"]         { --color-gym-weight: #d6a44a; } /* the one amber */
[data-theme="splitflap"]    { --color-gym-weight: #e8b84a; } /* board amber */
[data-theme="forest"]       { --color-gym-weight: #6abf6a; } /* leaf green */
[data-theme="ocean"]        { --color-gym-weight: #00b4d8; } /* sea cyan */
[data-theme="sakura"]       { --color-gym-weight: #e87090; } /* blossom pink */
[data-theme="aurora"]       { --color-gym-weight: #00bfa5; } /* aurora teal */
[data-theme="galaxy"]       { --color-gym-weight: #d050ff; } /* nebula violet */
[data-theme="circuitboard"] { --color-gym-weight: #40f090; } /* trace green */
[data-theme="matrix"]       { --color-gym-weight: #00ff00; } /* code green */
[data-theme="neon"]         { --color-gym-weight: #ff0066; } /* neon pink */
[data-theme="synthwave"]    { --color-gym-weight: #ff2090; } /* magenta */
[data-theme="inferno"]      { --color-gym-weight: #ff4400; } /* flame */
[data-theme="supernova"]    { --color-gym-weight: #ff6600; } /* blaze orange */
[data-theme="legendary"]    { --color-gym-weight: #ffc830; } /* gold */

html, body {
  height: 100%;
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: none;
}

html {
  background: var(--color-app-bg);
  background-color: var(--color-app-bg);
}

/* Form controls don't inherit font-family in CSS — without this reset
   every button, tab strip, and input across the app fell back to the
   UA's Arial and sat as an off-brand island inside fully-themed
   screens (63 controls measured on chalkboard, 2026-06-11: nav
   buttons, all five tab strips, settings, the smiley). Element-level
   specificity, so any rule that sets an explicit face still wins. */
button, input, select, textarea {
  font-family: inherit;
}

body {
  font-family: var(--font-family);
  background: var(--color-app-bg);
  background-color: var(--color-app-bg);
  color: var(--color-text);
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
  min-height: 100dvh;
  padding-top: env(safe-area-inset-top);
  padding-left: env(safe-area-inset-left);
  padding-right: env(safe-area-inset-right);
  padding-bottom: env(safe-area-inset-bottom);
  -webkit-user-select: none;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
}

/* Theme page-texture layer. Sits behind all content; paints nothing by
   default (--bg-page-image: none). A theme overrides --bg-page-image with
   a gradient, CSS pattern, or SVG data-URI for ambient page texture. */
body::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: var(--bg-page-image, none);
  background-size: cover;
  background-position: center;
  mix-blend-mode: var(--bg-page-blend, normal);
}

#app {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  padding: 20px 16px 16px;
  background: var(--bg-app);
  border-radius: 16px;
  box-shadow: var(--shadow-app);
  border: var(--border-app);
  position: relative;
  max-width: 560px;
  width: 95%;
}

/* ── Title ──────────────────────────────────── */

#title-bar {
  text-align: center;
  margin-bottom: 2px;
  cursor: pointer;
}

#game-title {
  font-family: var(--font-display);
  font-size: var(--fs-title, 28px);
  font-weight: 800;
  letter-spacing: 3px;
  text-align: center;
  /* Themed wordmark gradient, matching the title screen + share card. */
  background: linear-gradient(135deg, var(--wordmark-from), var(--wordmark-to));
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
  color: var(--color-accent);
  margin: 0;
}

#game-title:hover {
  color: var(--color-accent);
}

#title-subtitle {
  font-size: 10px;
  letter-spacing: 4px;
  text-transform: uppercase;
  color: var(--color-text-secondary);
  text-shadow: var(--text-shadow-subtitle);
  opacity: 0.7;
}

/* ── Header ─────────────────────────────────── */

#game-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  padding: 10px 14px;
  background: var(--color-header-gradient);
  border-radius: 10px;
  border: 1px solid var(--color-border);
  box-shadow: var(--shadow-sm), inset 0 1px 0 var(--color-cell-border-light);
}

.lcd-display {
  font-family: 'Courier New', 'Orbitron', monospace;
  font-size: var(--fs-lcd, 28px);
  font-weight: bold;
  color: var(--color-lcd-text);
  background: var(--color-lcd-bg);
  padding: 6px 10px;
  border-radius: 6px;
  min-width: 64px;
  text-align: center;
  letter-spacing: 3px;
  border: var(--border-lcd);
  box-shadow: var(--shadow-lcd);
  text-shadow: var(--text-shadow-lcd);
}

/* Timer urgency for countdown */
.lcd-display.timer-warning {
  color: var(--timer-warning, #ff9800);
  animation: timerPulse 1s ease-in-out infinite;
}

.lcd-display.timer-critical {
  color: var(--timer-critical, #f44336);
  animation: timerPulse 0.4s ease-in-out infinite;
  box-shadow: inset 0 2px 6px rgba(0,0,0,0.4), 0 0 8px var(--timer-critical-glow, rgba(255, 51, 51, 0.3));
}

@keyframes timerPulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.5; }
}

.smiley-btn {
  font-size: 32px;
  width: 50px;
  height: 50px;
  border: var(--border-smiley);
  background: var(--color-btn-gradient);
  border-radius: 50%;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
  box-shadow: var(--shadow-smiley);
  transition: transform var(--transition-fast), box-shadow var(--transition-fast);
}

.smiley-btn:not(:disabled):hover {
  transform: scale(1.08);
}

.smiley-btn:not(:disabled):active {
  transform: scale(0.95);
  box-shadow: none;
}

/* Daily/Weekly: smiley stays a fully-visible status face (no opacity
   dimming, unlike .powerup-btn:disabled) but reads as non-interactive. */
.smiley-btn:disabled {
  cursor: default;
}

/* ── Info Bar ───────────────────────────────── */

#game-info-bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
  padding: 4px 14px;
  font-size: 12px;
  font-weight: 600;
  color: var(--color-text-secondary);
  letter-spacing: 0.5px;
}

/* ── Lives Display ────────────────────────────── */

#lives-display {
  font-size: 11px;
  color: var(--color-loss, #ff4444);
  font-weight: 700;
  letter-spacing: 0.5px;
  white-space: nowrap;
}

#lives-display.life-pulse {
  animation: lifePulse 0.6s ease-out;
}

@keyframes lifePulse {
  0% { transform: scale(1); }
  30% { transform: scale(1.4); }
  100% { transform: scale(1); }
}

#lives-display.life-used {
  animation: lifeUsed 0.5s ease-out;
}

@keyframes lifeUsed {
  0% { transform: scale(1); opacity: 1; }
  50% { transform: scale(0.7); opacity: 0.4; }
  100% { transform: scale(1); opacity: 1; }
}

/* ── Mode Switcher Pills ──────────────────────── */

#mode-switcher {
  display: flex;
  gap: 4px;
}

.mode-pill {
  font-size: 13px;
  width: 30px;
  height: 24px;
  border: 1px solid var(--color-border);
  border-radius: 6px;
  background: var(--color-btn-bg);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0.45;
  transition: all 0.2s;
  padding: 0;
}

.mode-pill.active {
  opacity: 1;
  border-color: var(--color-accent);
  box-shadow: 0 0 6px var(--color-accent-glow);
}

.mode-pill:hover {
  opacity: 0.8;
}

/* ── Power-Up Bar ───────────────────────────── */

#powerup-bar {
  display: flex;
  justify-content: center;
  gap: 8px;
  padding: 4px 0;
  flex-wrap: wrap;
}

#powerup-bar.hidden {
  display: none;
}

.powerup-btn {
  display: flex;
  align-items: center;
  gap: 5px;
  padding: 8px 14px;
  min-height: 44px;
  border: var(--border-powerup-btn);
  background: var(--color-btn-gradient);
  border-radius: 10px;
  cursor: pointer;
  font-size: 14px;
  transition: all var(--transition-fast);
  box-shadow: var(--shadow-sm);
}

.powerup-btn:disabled {
  opacity: 0.35;
  cursor: default;
  box-shadow: none;
}
/* Passive powerups (lifeline) show full opacity even when disabled */
.powerup-btn.powerup-passive:disabled {
  opacity: 1;
}

.powerup-btn:not(:disabled):hover {
  background: var(--color-btn-hover);
  transform: translateY(-1px);
  box-shadow: var(--shadow-md);
}

.powerup-btn:not(:disabled):active {
  transform: translateY(0);
  box-shadow: none;
}

.powerup-btn.active-powerup {
  background: rgba(67, 160, 71, 0.15);
  border-color: var(--color-win);
  box-shadow: 0 0 8px rgba(67, 160, 71, 0.25);
}

.powerup-btn.scan-active {
  background: rgba(249, 168, 37, 0.15);
  border-color: var(--color-golden);
  box-shadow: 0 0 8px rgba(249, 168, 37, 0.25);
}

.powerup-icon {
  font-size: 18px;
}

/* Drawn sprite variants track their container's font-size, so every
   existing breakpoint (mode cards 32/28/24/22px, power-ups 18/14px)
   keeps working — a 1.25em square sits where the emoji glyph sat. */
.powerup-img,
.mode-card-img {
  width: 1.25em;
  height: 1.25em;
  display: inline-block;
  vertical-align: -0.2em;
}

.powerup-count {
  font-weight: 700;
  font-size: 13px;
  min-width: 16px;
  text-align: center;
}

/* ── Board ──────────────────────────────────── */

#screen-shake-wrapper {
  width: 100%;
}

#board-container {
  position: relative;
  width: 100%;
  background: var(--bg-board, transparent);
}

/* Scroll wrapper for zoom on large boards */
#board-scroll-wrapper {
  overflow: auto;
  max-height: 70vh;
  border-radius: 8px;
}

#board-scroll-wrapper.zoomed {
  overflow: auto;
  -webkit-overflow-scrolling: touch;
}

/* Zoom controls ride the bottom nav (Expert/Extreme Quick Play only).
   display:contents makes the two buttons direct flex items of the nav;
   the wrapper exists so updateZoom can show/hide the pair at once
   (the global .hidden !important wins over display:contents). The
   buttons themselves are .nav-btn — .zoom-btn only bolds the glyphs. */
#zoom-controls {
  display: contents;
}

.zoom-btn {
  font-weight: bold;
}

#streak-border {
  position: absolute;
  inset: -4px;
  border-radius: 12px;
  pointer-events: none;
  z-index: 1;
  opacity: 0;
  transition: opacity var(--transition-normal);
}

#streak-border.active {
  opacity: 1;
}

#streak-border.streak-1 { box-shadow: 0 0 6px 1px var(--color-accent-glow); }
#streak-border.streak-2 { box-shadow: 0 0 10px 2px var(--color-accent-glow); }
#streak-border.streak-3 {
  box-shadow: 0 0 12px 3px var(--color-accent-glow);
  animation: accentGlow 2.5s ease-in-out infinite;
}

@keyframes accentGlow {
  0%, 100% { box-shadow: 0 0 12px 3px var(--color-accent-glow); }
  50% { box-shadow: 0 0 18px 5px var(--color-accent-glow); }
}

#board {
  display: grid;
  gap: var(--grid-gap);
  /* Holistic fog art: a theme may set --bg-fog-art to ONE large vector
     drawing (data-URI SVG / gradient) that spans the whole grid — the
     crane crease pattern, the worn chart, the open sky. Themes that
     use it switch their unrevealed cells to TRANSLUCENT tints so the
     drawing reads through the fog as one continuous image; revealed
     cells stay opaque (revealing = unfolding the paper / tearing away
     the chart). Default none = byte-identical to the old shorthand. */
  background-color: var(--color-border);
  background-image: var(--bg-fog-art, none);
  background-size: 100% 100%;
  border: var(--border-board);
  border-radius: var(--border-radius-board);
  padding: 2px;
  box-shadow: var(--shadow-board);
  transition: transform 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
  touch-action: none;
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
  margin: 0 auto;
  width: fit-content;
  position: relative;
  overflow: hidden;
}

#board.board-transition {
  animation: boardPop 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
}

@keyframes boardPop {
  0% { transform: scale(0.85); opacity: 0.5; }
  60% { transform: scale(1.03); }
  100% { transform: scale(1); opacity: 1; }
}

#particle-canvas {
  position: absolute;
  top: 0;
  left: 0;
  pointer-events: none;
  z-index: 10;
  display: none;
}

#particle-canvas.active {
  display: block;
}

/* ── Cells ──────────────────────────────────── */

.cell {
  width: var(--cell-size);
  height: var(--cell-size);
  display: flex;
  align-items: center;
  justify-content: center;
  /* Scale the number with the cell so big cells use the room and small cells
     stay proportional (was a fixed --fs-cell-number that left big cells empty). */
  font-size: calc(var(--cell-size, 40px) * 0.56);
  font-weight: 800;
  cursor: pointer;
  transition: background-color var(--transition-fast), transform var(--transition-fast);
  border-radius: var(--cell-shape-radius, var(--border-radius));
  position: relative;
}

.cell.unrevealed {
  background: var(--color-cell-hidden-gradient);
  border: 1px solid var(--color-cell-border-light);
  box-shadow: var(--shadow-cell-unrevealed);
}

/* Guard hover styles behind (hover: hover) so iOS doesn't keep the
   :hover state stuck after a tap. Touch devices skip these rules
   entirely and rely on :active for press feedback. */
@media (hover: hover) and (pointer: fine) {
  .cell.unrevealed:hover {
    background: var(--color-cell-hidden-hover);
    transform: scale(1.04);
    box-shadow: var(--shadow-cell-hover);
    z-index: 2;
  }
}

.cell.unrevealed:active {
  transform: scale(0.95);
  box-shadow: none;
}

/* Keyboard focus indicator */
.cell:focus-visible {
  outline: 3px solid #1976d2;
  outline-offset: -1px;
  z-index: 3;
  box-shadow: 0 0 0 2px rgba(25, 118, 210, 0.3);
}

.cell.touch-holding {
  transform: scale(0.92);
  opacity: 0.75;
  transition: transform 0.15s ease, opacity 0.15s ease;
}

.cell.revealed {
  background: var(--color-cell-revealed);
  border: var(--border-cell-revealed);
  border-radius: var(--cell-shape-radius, var(--border-radius));
  cursor: default;
}

/* ── Effect-occlusion system (engages only when an ambient effect is on) ──────
   themeEffects.js adds `.fx-on` to #board whenever a theme registers a particle
   effect. These rules then (1) lift revealed cells + flags above the .theme-fx
   layer (z-index 1) so animations never wash over numbers/markers, and (2) seal
   the inter-cell gaps around revealed cells so the effect can't show as slivers
   between two already-revealed cells. Scoped to `.fx-on` so the effect-less
   themes render byte-for-byte as before — no stacking contexts, no gap fill. */
#board.fx-on .cell.revealed,
#board.fx-on .cell.flagged {
  z-index: 2;
}

/* Two stacked layers so cleared cells read as separate rounded tiles set in a
   colored grout, while the ambient effect is FULLY blocked — including the
   4-cell junctions a rounded ring/shadow leaves open (that diamond is inherent
   to rounded corners; only a SQUARE fill tiles it shut).

   ::before — a SQUARE solid fill of the gap color over cell + surrounding gap.
   Square (no radius) so four neighbors' fills tile every junction with no
   diamond. z-index -2: back of the cell's stacking context, still above the fx
   layer (a lower sibling).
   ::after  — the rounded revealed body on top (z-index -1): each tile shows its
   own surface, grout reads only in the gaps + corner notches.

   Special-cell markers whose cue lives on the cell FACE are excluded so the
   seal never buries them: the background tints (sonar/compass/wormhole), the
   cells whose ::after is a status glyph (locked/pressure-plate/defused), and
   MIRROR - its cue is the dashed border, and because the fx-on z-lift makes
   each revealed cell a stacking context, negative-z pseudos paint ABOVE the
   element's own background and borders (CSS painting order: backgrounds and
   borders first, then negative-z children) - the seal would bury the dashes
   (2026-06-11 mirror-daily-on-chalkboard bug). Liar (outline; outlines paint
   last) and mystery (text) genuinely survive and keep the full seal. An
   excluded cell's gaps are still covered by the solid fill of any plain
   neighbor; a mirror PAIR is adjacent, so the seam between the two excluded
   cells can show a 1px effect sliver - accepted, same as two adjacent tint
   markers. */
#board.fx-on .cell.revealed:not(.sonar-cell):not(.compass-cell):not(.wormhole-cell):not(.locked-cell):not(.pressure-plate):not(.defused):not(.mirror-cell)::before {
  content: '';
  position: absolute;
  pointer-events: none;
  /* Extend by the gap PLUS 1px. `inset` is measured from the cell's padding
     box, but the cell carries a ~1px revealed border that would otherwise eat
     the whole reach — so a bare `-gap` only touches the border-box edge and
     never enters the gap (matrix's 1px gap leaked the CSS #board::before rain
     for exactly this reason). The extra 1px pushes the fill the gap's full
     width past the border so it meets the neighbor's edge; two neighbors
     double-cover every seam with no hi-DPI sliver. */
  inset: calc(-1 * var(--grid-gap, 2px) - 1px);
  background: var(--cell-gap-seal, var(--color-cell-revealed));
  z-index: -2;
}
html:not([data-colorblind="true"]) #board.fx-on .cell.revealed:not(.sonar-cell):not(.compass-cell):not(.wormhole-cell):not(.locked-cell):not(.pressure-plate):not(.defused):not(.mirror-cell)::after {
  content: '';
  position: absolute;
  pointer-events: none;
  inset: 0;
  background: var(--color-cell-revealed);
  border-radius: var(--cell-shape-radius, var(--border-radius));
  z-index: -1;
}
/* In colorblind mode ::after is a shape glyph, so there's no body layer — paint
   the seal in the revealed color so the cell reads as one cleared surface under
   the glyph instead of bleeding the grout color across the whole tile. */
[data-colorblind="true"] #board.fx-on .cell.revealed {
  --cell-gap-seal: var(--color-cell-revealed);
}

/* The tint markers (sonar/compass/wormhole) are excluded from the seal so their
   color stays visible — but their fill is translucent, which on an effect theme
   would let the ambient animation bleed THROUGH the marker face and break the
   "markers never blend into the background" rule. Composite the same tint over
   an opaque revealed base so the marker keeps its exact hue while fully blocking
   the effect behind it. (Higher specificity + !important beats the base marker
   rules; identical hue, just no longer see-through.) */
#board.fx-on .cell.revealed.sonar-cell {
  background: linear-gradient(var(--marker-sonar-tint, rgba(0, 200, 220, 0.15)), var(--marker-sonar-tint, rgba(0, 200, 220, 0.15))), var(--color-cell-revealed) !important;
}
#board.fx-on .cell.revealed.compass-cell {
  background: linear-gradient(var(--marker-compass-tint, rgba(230, 180, 0, 0.16)), var(--marker-compass-tint, rgba(230, 180, 0, 0.16))), var(--color-cell-revealed) !important;
}
#board.fx-on .cell.revealed.wormhole-cell,
#board.fx-on .cell.revealed.wormhole-cell.wormhole-pair-0 {
  background: linear-gradient(var(--marker-wormhole-0, rgba(255, 140, 0, 0.18)), var(--marker-wormhole-0, rgba(255, 140, 0, 0.18))), var(--color-cell-revealed) !important;
}
#board.fx-on .cell.revealed.wormhole-cell.wormhole-pair-1 {
  background: linear-gradient(var(--marker-wormhole-1, rgba(220, 80, 220, 0.18)), var(--marker-wormhole-1, rgba(220, 80, 220, 0.18))), var(--color-cell-revealed) !important;
}
#board.fx-on .cell.revealed.wormhole-cell.wormhole-pair-2 {
  background: linear-gradient(var(--marker-wormhole-2, rgba(100, 220, 100, 0.18)), var(--marker-wormhole-2, rgba(100, 220, 100, 0.18))), var(--color-cell-revealed) !important;
}

.cell.mine {
  font-size: var(--fs-mine, 20px);
  text-shadow: var(--text-shadow-mine);
  background-color: var(--overlay-mine-tint, rgba(206, 40, 40, 0.3)) !important;
}

.cell.mine-hit {
  background: var(--color-mine-hit) !important;
  box-shadow: 0 0 12px var(--overlay-mine-hit-glow, rgba(255, 23, 68, 0.5));
}

.cell.flagged {
  font-size: var(--fs-flag, 18px);
}

/* Post-death analysis overlays */
.cell.wrong-flag {
  border: 2px solid var(--overlay-wrong-flag, #ff1744) !important;
  background: var(--overlay-wrong-flag-fill, rgba(255, 23, 68, 0.15)) !important;
}

.cell.correct-flag {
  background: var(--overlay-correct-flag-fill, rgba(0, 230, 118, 0.2)) !important;
  border: 2px solid var(--overlay-correct-flag, #00c853) !important;
}

.cell.suggested-move {
  border: 2px solid var(--overlay-suggest-move, #0091ea) !important;
  box-shadow: 0 0 8px var(--overlay-suggest-move-glow, rgba(0, 145, 234, 0.4));
  animation: pulse-suggest 1.5s ease-in-out infinite;
}

@keyframes pulse-suggest {
  0%, 100% { box-shadow: 0 0 8px rgba(0, 145, 234, 0.3); }
  50% { box-shadow: 0 0 16px rgba(0, 145, 234, 0.7); }
}

/* ── Receipt surfaces ──────────────────────────────────
   The loss receipt paints the FULL provably-safe frontier (quiet
   outlines — the one suggested-move cell keeps its louder pulse), and
   tap-to-interrogate pulses the constraint region that proves a cell.
   Colors come from the reserved receipt tokens so each theme world can
   voice these moments in its own idiom. */
.cell.frontier-safe {
  outline: 2px dashed var(--receipt-pulse-color, rgba(80, 160, 255, 0.45));
  outline-offset: -2px;
}
.cell.receipt-source-pulse {
  animation: receiptSourcePulse 0.9s ease-in-out 3;
}
/* The crux square during the win-receipt "show me" jump */
.cell.receipt-crux {
  outline: 3px solid var(--receipt-crux-outline, #f9a825);
  outline-offset: -3px;
  animation: receiptSourcePulse 0.9s ease-in-out 3;
  z-index: 4;
}
.gameover-receipt-tappable {
  cursor: pointer;
  text-decoration: underline;
  text-decoration-style: dotted;
  text-underline-offset: 3px;
}
@keyframes receiptSourcePulse {
  0%, 100% { box-shadow: inset 0 0 0 2px var(--receipt-pulse-color, rgba(80, 160, 255, 0.45)); }
  50% { box-shadow: inset 0 0 0 4px var(--receipt-pulse-color, rgba(80, 160, 255, 0.85)), 0 0 12px var(--receipt-pulse-color, rgba(80, 160, 255, 0.6)); }
}
.daily-bomb-verdict {
  margin-top: 6px;
  font-size: 0.82em;
  opacity: 0.92;
  color: var(--color-text, #eee);
}
.bombhit-verdict {
  font-weight: 600;
  border-left: 3px solid var(--receipt-verdict-border, rgba(80, 160, 255, 0.6));
  padding-left: 8px;
}
.gameover-receipt {
  font-size: 0.85em;
  color: var(--color-text-secondary, #999);
  margin: 4px 0;
}

/* ── The Lexicon overlay ───────────────────────────────
   Generated single-technique lessons behind the deducibility
   click-gate: unproven clicks bounce, the proving region pulses. */
#lexicon-overlay {
  position: fixed; inset: 0; z-index: 1200;
  background: rgba(0, 0, 0, 0.75);
  display: flex; align-items: center; justify-content: center;
  padding: 16px;
}
.lexicon-card {
  background: var(--color-modal-bg, #2a2a2a);
  color: var(--color-text, #eee);
  border-radius: 12px;
  padding: 18px;
  max-width: 420px;
  width: 100%;
}
.lexicon-header { display: flex; justify-content: space-between; align-items: center; }
.lexicon-title { font-weight: 700; font-size: 1.1em; }
.lexicon-close {
  background: none; border: none; color: inherit;
  font-size: 1.6em; line-height: 1; cursor: pointer; padding: 2px 8px;
}
.lexicon-instruction {
  font-size: 0.85em;
  color: var(--color-text-secondary, #999);
  margin: 8px 0 12px;
}
/* Mines-left counter + board number, aligned to the grid edges — the
   same anchor the main game's LCD provides. */
.lexicon-status {
  display: flex; justify-content: space-between; align-items: center;
  max-width: 320px;
  margin: 0 auto 8px;
  font-size: 0.9em;
}
.lexicon-mines-left { font-weight: 700; color: var(--color-text, #eee); }
.lexicon-board-count { font-size: 0.85em; color: var(--color-text-secondary, #999); }
/* Flag-mode toggle: the reliable touch path for flagging. Active state is
   high-contrast (inverted) so the player always knows a tap will flag. */
.lexicon-flag-toggle {
  font: inherit;
  font-size: 0.85em;
  font-weight: 700;
  padding: 4px 14px;
  border-radius: 999px;
  border: 1.5px solid var(--color-border, #555);
  background: var(--color-cell-revealed, #333);
  color: var(--color-text, #eee);
  cursor: pointer;
  touch-action: manipulation;
  user-select: none;
  -webkit-touch-callout: none;
}
.lexicon-flag-toggle.active {
  background: var(--color-text, #eee);
  color: var(--color-cell-revealed, #333);
  border-color: var(--color-text, #eee);
}
.lexicon-grid {
  display: grid;
  gap: 3px;
  max-width: 320px;
  margin: 0 auto;
}
.lexicon-cell {
  aspect-ratio: 1;
  display: flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: 1.05em;
  border-radius: var(--cell-shape-radius, 4px);
  cursor: pointer;
  user-select: none;
  touch-action: manipulation;
  -webkit-touch-callout: none;
}
.lexicon-cell.unrevealed { background: var(--color-cell-hidden, #555); }
.lexicon-cell.revealed { background: var(--color-cell-revealed, #333); cursor: default; }
.lexicon-cell.flagged { font-size: 0.9em; }
.lexicon-cell[data-num="1"] { color: var(--color-num-1, #6baed6); }
.lexicon-cell[data-num="2"] { color: var(--color-num-2, #66bb6a); }
.lexicon-cell[data-num="3"] { color: var(--color-num-3, #ff6b6b); }
.lexicon-cell[data-num="4"] { color: var(--color-num-4, #ce93d8); }
.lexicon-cell[data-num="5"] { color: var(--color-num-5, #f48fb1); }
.lexicon-cell.lexicon-bounce { animation: lexiconBounce 0.3s ease-out; }
@keyframes lexiconBounce {
  0%, 100% { transform: translateX(0); }
  30% { transform: translateX(-4px); }
  60% { transform: translateX(4px); }
}
.lexicon-cell.lexicon-pulse {
  animation: receiptSourcePulse 0.9s ease-in-out 2;
}
/* The coach line: one slot under the board, updated in place (never
   queued like toasts, so the note lands the instant the move does).
   Reserved height keeps the card from jumping as notes come and go. */
.lexicon-coach, .board-coach {
  font-size: 0.88em;
  line-height: 1.35;
  color: var(--color-text, #eee);
}
.lexicon-coach {
  min-height: 3.4em;
  margin: 10px 0 0;
}
/* The board coach line: the Lens answers here, under the live board.
   Hidden (display:none via [hidden]) when empty so it costs no height
   until a hint is actually showing. */
.board-coach {
  margin: 8px auto 0;
  max-width: 520px;
  padding: 0 10px;
  text-align: center;
}
.lexicon-coach.coach-pop, .board-coach.coach-pop { animation: lexCoachPop 0.25s ease-out; }
@keyframes lexCoachPop {
  0% { transform: translateY(4px); opacity: 0.3; }
  100% { transform: translateY(0); opacity: 1; }
}

/* ── Crux teaser (?crux= share route) ──────────────────
   A standalone "find the safe square" view of a past daily's hardest
   step. Mirrors the Gym mini-board's visual language so the two practice
   surfaces feel like one game. */
.crux-teaser {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  overflow-y: auto;
  background: var(--color-bg, #1a1a1a);
  z-index: 50;
}
.crux-teaser.hidden { display: none; }
.crux-teaser-card {
  background: var(--color-modal-bg, #2a2a2a);
  color: var(--color-text, #eee);
  border-radius: 16px;
  padding: 22px;
  max-width: 380px;
  width: 100%;
  text-align: center;
  box-shadow: 0 8px 40px rgba(0, 0, 0, 0.4);
}
.crux-teaser-brand {
  display: flex;
  align-items: center;
  gap: 10px;
  justify-content: center;
  margin-bottom: 4px;
}
.crux-greg { width: 44px; height: 44px; object-fit: contain; flex: none; }
.crux-teaser-logo { font-weight: 800; font-size: 1.3em; line-height: 1.1; text-align: left; }
.crux-teaser-tagline { font-size: 0.85em; color: var(--color-text-secondary, #999); text-align: left; }
.crux-teaser-date { font-size: 0.8em; color: var(--color-text-secondary, #999); margin: 12px 0 2px; }
.crux-teaser-prompt { font-size: 0.98em; margin: 4px 0 14px; line-height: 1.35; }
.crux-board {
  display: grid;
  gap: 3px;
  max-width: 280px;
  margin: 0 auto;
}
.crux-cell {
  aspect-ratio: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  font-size: 1.05em;
  border-radius: var(--cell-shape-radius, 4px);
  user-select: none;
}
.crux-cell.crux-fog { background: var(--color-cell-hidden, #555); cursor: pointer; }
.crux-cell.crux-fog:hover { background: var(--color-cell-hidden-hover, #666); }
.crux-cell.revealed { background: var(--color-cell-revealed, #333); cursor: default; }
.crux-cell.crux-found { background: var(--overlay-suggest-start, #2e7d32); color: #fff; }
/* A flagged mine reads like the game's flagged cell: the hidden-cell ground
   with the drawn flag sprite on top (not an emoji). */
.crux-cell.crux-mine { background: var(--color-cell-hidden, #555); }
.crux-cell .crux-marker-img { width: 72%; height: 72%; object-fit: contain; }
.crux-cell[data-num="1"] { color: var(--color-num-1, #6baed6); }
.crux-cell[data-num="2"] { color: var(--color-num-2, #66bb6a); }
.crux-cell[data-num="3"] { color: var(--color-num-3, #ff6b6b); }
.crux-cell[data-num="4"] { color: var(--color-num-4, #ce93d8); }
.crux-cell[data-num="5"] { color: var(--color-num-5, #f48fb1); }
.crux-cell[data-num="6"] { color: var(--color-num-6, #4dd0e1); }
.crux-cell[data-num="7"] { color: var(--color-num-7, #cfd8dc); }
.crux-cell[data-num="8"] { color: var(--color-num-8, #b0bec5); }
.crux-cell.crux-bounce { animation: lexiconBounce 0.3s ease-out; }
.crux-cell.crux-pulse { animation: receiptSourcePulse 0.9s ease-in-out 2; }
.crux-progress { font-size: 0.85em; font-weight: 700; color: var(--color-text-secondary, #999); margin: 8px 0 2px; }
.crux-coach { min-height: 3em; margin: 8px 0 6px; font-size: 0.9em; line-height: 1.4; }
.crux-teaser-actions { display: flex; flex-direction: column; align-items: center; gap: 8px; }
.crux-reveal-all {
  background: none; border: none; cursor: pointer; padding: 2px 6px;
  color: var(--color-accent, #6cf); font-size: 0.85em; text-decoration: underline;
}
.crux-cta { display: inline-block; text-decoration: none; }
/* Walls drawn over the mini grid (positioned by cruxTeaser._renderMiniWalls).
   pointer-events:none so a wall over a gap never eats a tap. */
.crux-wall {
  position: absolute;
  background: var(--color-wall, #6b5a3e);
  border-radius: 1px;
  z-index: 2;
  pointer-events: none;
}
.lexicon-naming {
  margin: 12px 0 4px;
  font-size: 0.92em;
  font-style: italic;
  color: var(--color-accent, #6cf);
}
.lexicon-actions { display: flex; gap: 8px; justify-content: center; margin-top: 10px; }

/* ── Lesson-select + Field Notebook views ───────────────── */
.lexicon-back {
  background: none; border: none; color: var(--color-text-secondary, #999);
  font-size: 0.95em; cursor: pointer; padding: 2px 6px; font-weight: 600;
}
.lexicon-back:hover { color: var(--color-text, #eee); }
.lexicon-view[hidden] { display: none; }
.lexicon-select-intro, .lexicon-notebook-intro {
  font-size: 0.85em; color: var(--color-text-secondary, #999); margin: 10px 0 12px;
}
.lexicon-lesson-list { display: flex; flex-direction: column; gap: 8px; }
.lexicon-lesson-card {
  display: flex; flex-direction: column; gap: 2px; text-align: left;
  background: var(--color-cell-revealed, #333); color: inherit;
  border: 1px solid transparent; border-radius: 10px;
  padding: 12px 14px; cursor: pointer; transition: border-color 0.15s, transform 0.1s;
}
.lexicon-lesson-card:hover { border-color: var(--color-accent, #4caf50); }
.lexicon-lesson-card:active { transform: scale(0.99); }
.lexicon-lesson-name { font-weight: 700; font-size: 1.02em; }
.lexicon-lesson-blurb { font-size: 0.82em; color: var(--color-text-secondary, #999); }
.lexicon-adv {
  font-size: 0.68em; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--color-accent, #4caf50); border: 1px solid currentColor;
  border-radius: 6px; padding: 0 5px; margin-left: 6px; vertical-align: middle;
}
.lexicon-notebook-btn { width: 100%; margin-top: 14px; }

.lexicon-note {
  display: flex; gap: 12px; align-items: flex-start;
  padding: 12px 0; border-top: 1px solid var(--color-border, #444);
}
.lexicon-note:first-of-type { border-top: none; }
.lexicon-note-body { flex: 1; min-width: 0; }
.lexicon-note-head { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; }
.lexicon-note-name { font-weight: 700; }
.lexicon-note-count { font-size: 0.78em; color: var(--color-text-secondary, #999); white-space: nowrap; }
.lexicon-note-rule { font-size: 0.82em; color: var(--color-text-secondary, #bbb); margin: 4px 0 0; line-height: 1.4; }
.lexicon-note-sketch { flex-shrink: 0; }
.lexicon-sketch { display: grid; gap: 2px; width: 72px; }
.lexicon-sketch .sk {
  aspect-ratio: 1; display: flex; align-items: center; justify-content: center;
  font-size: 0.7em; font-weight: 700; border-radius: 3px;
  background: var(--color-cell-revealed, #333);
}
.lexicon-sketch .sk-hidden { background: var(--color-cell-hidden, #555); }
.lexicon-sketch .sk-mine { font-size: 0.6em; }
.lexicon-sketch .sk-safe { color: var(--color-accent, #4caf50); }
.lexicon-sketch .sk-num[data-num="1"] { color: var(--color-num-1, #6baed6); }
.lexicon-sketch .sk-num[data-num="2"] { color: var(--color-num-2, #66bb6a); }
.lexicon-sketch .sk-num[data-num="3"] { color: var(--color-num-3, #ff6b6b); }

.cell.suggested-start {
  background: var(--overlay-suggest-start-fill, rgba(76, 175, 80, 0.35));
  border: 2px solid var(--overlay-suggest-start, #4caf50) !important;
  box-shadow: 0 0 8px var(--overlay-suggest-start-glow, rgba(76, 175, 80, 0.4));
  animation: pulse-start 2s ease-in-out infinite;
}

@keyframes pulse-start {
  0%, 100% { box-shadow: 0 0 6px rgba(76, 175, 80, 0.3); }
  50% { box-shadow: 0 0 14px rgba(76, 175, 80, 0.6); }
}

.start-here-label {
  position: fixed;
  transform: translate(-50%, -100%);
  color: var(--color-text, #333);
  font-size: 11px;
  font-weight: 600;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0.85;
  /* Below .modal (z-index 1001) so the gameover overlay covers the
     label cleanly. Still well above board cells. */
  z-index: 900;
  animation: fade-in-start 0.5s ease-out;
}

/* VICTORY! overlay — large gold bouncing text on every win. Sits over
   the board, fades out before the gameover modal slides in. */
.victory-overlay {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  z-index: 1500;
  font-size: clamp(48px, 14vw, 96px);
  font-weight: 900;
  letter-spacing: 4px;
  color: var(--victory-color, #ffd54f);
  text-shadow:
    0 4px 14px rgba(0, 0, 0, 0.7),
    0 0 30px rgba(255, 215, 79, 0.55),
    0 0 6px rgba(0, 0, 0, 0.9);
  font-family: var(--font-display, var(--font-family, system-ui));
  animation: victoryPop var(--victory-duration, 3600ms) var(--ease-bounce, cubic-bezier(0.34, 1.56, 0.64, 1)) forwards;
}
@keyframes victoryPop {
  0%   { transform: scale(0.4) rotate(-6deg); opacity: 0; }
  9%   { transform: scale(1.4) rotate(2deg);  opacity: 1; }
  14%  { transform: scale(1.0) rotate(0deg);  opacity: 1; }
  90%  { transform: scale(1.0) rotate(0deg);  opacity: 1; }
  100% { transform: scale(1.05) rotate(0deg); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .victory-overlay {
    animation: victoryFade var(--victory-duration, 3600ms) ease-out forwards;
  }
  @keyframes victoryFade {
    0% { opacity: 0; } 20% { opacity: 1; } 80% { opacity: 1; } 100% { opacity: 0; }
  }
}

/* Post-loss NEXT MOVE label — blue chip anchored to the
   solver-suggested safe cell. Default layout matches .start-here-label
   (floats above the cell); .label-on-cell overrides to center it
   directly on top of the cell so it visually belongs to the square. */
.next-move-label {
  position: fixed;
  transform: translate(-50%, -100%);
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.5px;
  white-space: nowrap;
  pointer-events: none;
  color: #fff;
  background: var(--overlay-suggest-move, #0091ea);
  padding: 2px 6px;
  border-radius: 4px;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.35);
  /* Below .modal (z-index 1001) so the gameover overlay covers the
     label cleanly when it slides in after the cascade. */
  z-index: 900;
  animation: fade-in-start 0.4s ease-out;
}
.next-move-label.label-on-cell {
  transform: translate(-50%, -50%);
}

@keyframes fade-in-start {
  from { opacity: 0; transform: translate(-50%, -80%); }
  to { opacity: 0.85; transform: translate(-50%, -100%); }
}

.daily-bomb-popup {
  position: fixed;
  top: 0; left: 0; right: 0; bottom: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 2000;
  pointer-events: none;
  animation: bomb-popup-in 0.3s ease-out;
}

.daily-bomb-popup-content {
  background: var(--color-cell-hidden, #2a2a4a);
  color: var(--color-text, #eee);
  padding: 24px 32px;
  border-radius: 16px;
  font-size: 18px;
  font-weight: 700;
  text-align: center;
  line-height: 1.6;
  box-shadow: 0 8px 32px rgba(0,0,0,0.4);
}

.daily-bomb-sub {
  font-size: 13px;
  font-weight: 400;
  opacity: 0.8;
}

@keyframes bomb-popup-in {
  from { opacity: 0; transform: scale(0.8); }
  to { opacity: 1; transform: scale(1); }
}

.cell.fogged {
  background: var(--color-fog);
  border: 1px solid rgba(0,0,0,0.3);
  cursor: default;
}

.cell.num-1 { color: var(--color-num-1); text-shadow: var(--text-shadow-num-1); }
.cell.num-2 { color: var(--color-num-2); text-shadow: var(--text-shadow-num-2); }
.cell.num-3 { color: var(--color-num-3); text-shadow: var(--text-shadow-num-3); }
.cell.num-4 { color: var(--color-num-4); text-shadow: var(--text-shadow-num-4); }
.cell.num-5 { color: var(--color-num-5); text-shadow: var(--text-shadow-num-5); }
.cell.num-6 { color: var(--color-num-6); }
.cell.num-7 { color: var(--color-num-7); }
.cell.num-8 { color: var(--color-num-8); }
/* 9-18 for wormhole combined counts */
.cell.num-9  { color: var(--color-num-9); }
.cell.num-10 { color: var(--color-num-10); }
.cell.num-11 { color: var(--color-num-11); }
.cell.num-12 { color: var(--color-num-12); }
.cell.num-13 { color: var(--color-num-13); }
.cell.num-14 { color: var(--color-num-14); }
.cell.num-15 { color: var(--color-num-15); }
.cell.num-16 { color: var(--color-num-16); }
.cell.num-17 { color: var(--color-num-17); }
.cell.num-18 { color: var(--color-num-18); }

/* ── Reveal Safe Animation ─────────────────── */
.cell.golden-reveal {
  animation: goldenPulse 0.6s ease;
}

@keyframes goldenPulse {
  0% { box-shadow: 0 0 0 0 rgba(249, 168, 37, 0.9); transform: scale(0.5); opacity: 0; }
  30% { box-shadow: 0 0 30px 15px rgba(249, 168, 37, 0.5); transform: scale(1.15); opacity: 1; }
  60% { box-shadow: 0 0 15px 5px rgba(249, 168, 37, 0.3); transform: scale(0.95); }
  100% { box-shadow: 0 0 0 0 rgba(249, 168, 37, 0); transform: scale(1); }
}

.golden-ripple {
  position: absolute;
  border-radius: 50%;
  border: 3px solid rgba(249, 168, 37, 0.8);
  pointer-events: none;
  z-index: 55;
  transform: translate(-50%, -50%);
  animation: goldenRippleExpand 0.7s ease-out forwards;
}

@keyframes goldenRippleExpand {
  0% { width: 0; height: 0; opacity: 1; }
  100% { width: 100px; height: 100px; opacity: 0; }
}

/* ── Scan Animation ────────────────────────── */
.cell.scan-highlight {
  background: var(--color-scan-highlight) !important;
  box-shadow: inset 0 0 8px var(--color-scan-highlight);
  animation: scanCellPop 0.3s ease-out both;
}

@keyframes scanCellPop {
  0% { transform: scale(0.9); opacity: 0.5; }
  50% { transform: scale(1.05); }
  100% { transform: scale(1); opacity: 1; }
}

.scan-sweep-h, .scan-sweep-v {
  position: absolute;
  pointer-events: none;
  z-index: 60;
}

.scan-sweep-h {
  left: 0; right: 0;
  height: 2px;
  background: linear-gradient(90deg, transparent, var(--color-golden), transparent);
  box-shadow: 0 0 8px var(--color-golden);
  animation: scanSweepH 0.5s ease-out forwards;
}

.scan-sweep-v {
  top: 0; bottom: 0;
  width: 2px;
  background: linear-gradient(180deg, transparent, var(--color-golden), transparent);
  box-shadow: 0 0 8px var(--color-golden);
  animation: scanSweepV 0.5s ease-out forwards;
}

@keyframes scanSweepH {
  0% { opacity: 0; transform: scaleX(0); }
  50% { opacity: 1; transform: scaleX(1); }
  100% { opacity: 0; }
}

@keyframes scanSweepV {
  0% { opacity: 0; transform: scaleY(0); }
  50% { opacity: 1; transform: scaleY(1); }
  100% { opacity: 0; }
}

/* Scan mode crosshair cursor */
#board.scan-mode .cell.unrevealed {
  cursor: crosshair;
}

/* ── Shield Active + Defuse Animation ──────── */
#board.shield-active {
  box-shadow: var(--shadow-md), inset 0 0 20px rgba(67, 160, 71, 0.15);
  animation: shieldPulse 1.5s ease-in-out infinite;
}

@keyframes shieldPulse {
  0%, 100% { box-shadow: var(--shadow-md), inset 0 0 20px rgba(67, 160, 71, 0.15); }
  50% { box-shadow: var(--shadow-md), inset 0 0 30px rgba(67, 160, 71, 0.25); }
}

#board.shield-active .cell.unrevealed {
  border-color: rgba(67, 160, 71, 0.3);
}

.cell.defused {
  position: relative;
  background: var(--pu-shield-fill, rgba(67, 160, 71, 0.15)) !important;
  font-size: calc(var(--cell-size) * 0.6);
  animation: shieldDefusePop 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.cell.defused::after {
  content: '✕';
  position: absolute;
  font-size: calc(var(--cell-size) * 0.7);
  font-weight: 900;
  color: var(--pu-shield, #43a047);
  text-shadow: 0 0 6px var(--pu-shield-glow, rgba(67, 160, 71, 0.6));
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  animation: defusedXAppear 0.4s ease-out 0.2s both;
}

@keyframes shieldDefusePop {
  0% { transform: scale(0.5); opacity: 0; }
  50% { transform: scale(1.2); box-shadow: 0 0 20px rgba(67, 160, 71, 0.6); }
  100% { transform: scale(1); }
}

@keyframes defusedXAppear {
  0% { opacity: 0; transform: translate(-50%, -50%) scale(2) rotate(45deg); }
  100% { opacity: 1; transform: translate(-50%, -50%) scale(1) rotate(0deg); }
}

.shield-break-flash {
  position: fixed;
  top: 0; left: 0; right: 0; bottom: 0;
  background: radial-gradient(circle, rgba(67, 160, 71, 0.3), transparent 70%);
  pointer-events: none;
  z-index: 200;
  animation: shieldFlash 0.6s ease-out forwards;
}

@keyframes shieldFlash {
  0% { opacity: 1; }
  100% { opacity: 0; }
}

.shield-defused-cell {
  animation: shieldDefusePop 0.6s cubic-bezier(0.34, 1.56, 0.64, 1) !important;
}

/* ── Scan Toast ─────────────────────────────── */

#scan-toast {
  position: absolute;
  bottom: -40px;
  left: 50%;
  transform: translateX(-50%);
  background: var(--color-modal-bg);
  color: var(--color-text);
  padding: 10px 24px;
  border-radius: 10px;
  font-size: 13px;
  font-weight: bold;
  box-shadow: var(--shadow-lg);
  z-index: 100;
  animation: scanToastSlideUp 0.25s ease-out;
  pointer-events: none;
  border: 1px solid var(--color-border);
  white-space: nowrap;
}

@keyframes scanToastSlideUp {
  from { opacity: 0; transform: translateX(-50%) translateY(8px); }
  to { opacity: 1; transform: translateX(-50%) translateY(0); }
}

#scan-toast.hidden {
  display: none;
}

/* X-Ray: styled variant for x-ray scan results */
#scan-toast.xray-toast-top {
  background: rgba(100, 149, 237, 0.95);
  border-color: rgba(100, 149, 237, 0.5);
}

/* ── X-Ray Power-Up ────────────────────────── */
.cell.xray-area {
  background: var(--pu-xray-area, rgba(100, 149, 237, 0.15)) !important;
  transition: background 0.3s ease;
}

.cell.xray-mine {
  background: var(--pu-xray-mine, rgba(255, 50, 50, 0.3)) !important;
  box-shadow: 0 0 10px rgba(255, 50, 50, 0.6), inset 0 0 6px rgba(255, 50, 50, 0.4);
  animation: xrayPulse 0.5s ease infinite alternate;
}

@keyframes xrayPulse {
  from { box-shadow: 0 0 6px rgba(255, 50, 50, 0.4); }
  to { box-shadow: 0 0 14px rgba(255, 50, 50, 0.8), inset 0 0 8px rgba(255, 50, 50, 0.5); }
}

/* Scan-line sweep across X-Ray area */
.xray-scan-line {
  position: absolute;
  left: 0; right: 0;
  height: 3px;
  background: linear-gradient(90deg, transparent, var(--pu-xray-accent, rgba(100, 149, 237, 0.9)), transparent);
  box-shadow: 0 0 8px rgba(100, 149, 237, 0.6);
  pointer-events: none;
  z-index: 60;
  animation: xraySweep 0.6s ease-out forwards;
}

@keyframes xraySweep {
  0% { top: 0; opacity: 1; }
  100% { top: 100%; opacity: 0.3; }
}

#board.xray-mode .cell.unrevealed {
  cursor: crosshair;
}

.powerup-btn.xray-active {
  background: rgba(100, 149, 237, 0.3) !important;
  box-shadow: 0 0 8px rgba(100, 149, 237, 0.5);
}

/* ── Lifeline Power-Up ─────────────────────── */
.cell.lifeline-save {
  animation: lifelinePulse 1.4s ease-out;
  box-shadow: 0 0 16px var(--pu-lifeline, rgba(80, 200, 120, 0.9)), inset 0 0 8px rgba(80, 200, 120, 0.5);
}

@keyframes lifelinePulse {
  0% { box-shadow: 0 0 24px rgba(80, 200, 120, 1), inset 0 0 12px rgba(80, 200, 120, 0.7); transform: scale(1.2); }
  30% { box-shadow: 0 0 18px rgba(80, 200, 120, 0.7); transform: scale(1.08); }
  60% { box-shadow: 0 0 10px rgba(80, 200, 120, 0.4); transform: scale(1.02); }
  100% { box-shadow: none; transform: scale(1); }
}

.lifeline-flash {
  position: fixed;
  top: 0; left: 0; right: 0; bottom: 0;
  background: radial-gradient(circle, rgba(80, 200, 120, 0.35), transparent 70%);
  pointer-events: none;
  z-index: 200;
  animation: lifelineFlashAnim 0.8s ease-out forwards;
}

@keyframes lifelineFlashAnim {
  0% { opacity: 1; }
  50% { opacity: 0.7; }
  100% { opacity: 0; }
}

.lifeline-indicator {
  cursor: default !important;
}

/* ── Magnet Power-Up ──────────────────────── */
.cell.magnet-area {
  animation: magnetPulse 1.5s ease-out;
  box-shadow: 0 0 10px var(--pu-magnet, rgba(180, 130, 255, 0.6));
}

@keyframes magnetPulse {
  0% { box-shadow: 0 0 16px rgba(180, 130, 255, 0.9); background: rgba(180, 130, 255, 0.25) !important; }
  50% { box-shadow: 0 0 8px rgba(180, 130, 255, 0.4); background: rgba(180, 130, 255, 0.1) !important; }
  100% { box-shadow: none; background: inherit !important; }
}

#board.magnet-mode .cell.unrevealed {
  cursor: crosshair;
}

.powerup-btn.magnet-active {
  background: rgba(180, 130, 255, 0.3) !important;
  box-shadow: 0 0 8px rgba(180, 130, 255, 0.5);
}

/* ── Gimmick Cells ─────────────────────────── */

/* Wall overlay lines — continuous between cells, no gaps */
.wall-overlay-container {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 3;
}
.wall-line {
  position: absolute;
  background: var(--color-wall, #c9a96e);
  border-radius: 1px;
  /* Two-tone wall support: themes whose revealed and hidden cell bgs sit
     at OPPOSITE luminance extremes (light panes + dark fog — stained
     glass, apothecary, split-flap) cannot clear the 3.5:1 wall floor
     against both with any single color. The body covers one side, this
     outline covers the other. Default transparent so every other theme
     renders exactly as before. */
  box-shadow: 0 0 0 1.5px var(--color-wall-outline, transparent);
}
.wall-line-h {
  height: 5px;
  transform: translateY(-50%);
  /* Extend 1px past cell edges to overlap with adjacent wall segments */
  margin-left: -1px;
  padding-right: 2px;
  box-sizing: content-box;
}
.wall-line-v {
  width: 5px;
  transform: translateX(-50%);
  margin-top: -1px;
  padding-bottom: 2px;
  box-sizing: content-box;
}

/* Mystery cells — revealed but showing '?' */
.cell.mystery-cell {
  color: var(--color-text-secondary);
  font-weight: 900;
  font-style: italic;
  text-shadow: 0 0 4px rgba(255, 200, 50, 0.4);
}

/* Liar cells — display is off by ±1.
   2px solid rose-pink outline for the strong "watch this number" cue,
   plus italic + underline as typographic reinforcement. Outline (not
   border) so mirror's dashed border can still wrap the same cell when
   both gimmicks land on one cell. Tested across all 30+ themes — the
   outline reads clearly against every cell-bg color. Color chosen to
   avoid sonar cyan, compass gold, wormhole amber/magenta/green, and
   mirror blue/purple/green. */
.cell.liar-cell {
  font-style: italic;
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 2px;
  /* Keep the underline CONTINUOUS. The browser default skip-ink erases the line
     where the glyph crosses it; on large-font themes (editorial 0.67, the 0.72
     serif themes) the number is big enough that almost the whole underline gets
     eaten, leaving only a stub — so the liar cue read as "no underline". */
  text-decoration-skip-ink: none;
  outline: var(--marker-liar-outline-width, 2px) solid var(--marker-liar-outline, rgba(231, 76, 60, 0.9));
  outline-offset: -2px;
}

/* Locked cells — padlock indicator */
.cell.locked-cell::after {
  content: '🔒';
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  font-size: calc(var(--cell-size) * 0.45);
  opacity: 0.85;
  pointer-events: none;
}

.cell.locked-cell {
  position: relative;
}

/* Pressure Plate cells — countdown timer ring */
.cell.pressure-plate {
  position: relative;
  box-shadow: inset 0 0 8px var(--marker-plate-glow, rgba(255, 50, 50, 0.4));
  border: 2px solid var(--marker-plate-border, rgba(255, 80, 80, 0.6)) !important;
}
.cell.pressure-plate.plate-active {
  animation: platePulse 1s ease-in-out infinite;
}
@keyframes platePulse {
  0%, 100% { box-shadow: inset 0 0 8px rgba(255, 50, 50, 0.4); }
  50% { box-shadow: inset 0 0 14px rgba(255, 50, 50, 0.7), 0 0 6px rgba(255, 50, 50, 0.3); }
}
.plate-timer {
  position: absolute;
  bottom: 1px;
  left: 1px;
  right: 1px;
  height: 3px;
  background: var(--marker-plate-timer, #ff4444);
  border-radius: 1px;
  transform-origin: left;
  transition: transform 1s linear;
}

/* Sonar cells — 📡 prefix is the identifier, plus a faint cyan tint
   so the cell reads as "different" even before the player parses the
   range glyph. Subtle alpha so the underlying number color stays
   legible. */
.cell.sonar-cell {
  font-size: calc(var(--cell-size) * 0.4) !important;
  letter-spacing: -1px;
  background-color: var(--marker-sonar-tint, rgba(0, 200, 220, 0.15)) !important;
}

/* Compass cells — arrow suffix is the identifier, plus a faint gold
   tint mirroring the sonar pattern. Different hue so the player can
   distinguish a sonar tile from a compass tile at peripheral glance. */
.cell.compass-cell {
  font-size: calc(var(--cell-size) * 0.4) !important;
  letter-spacing: -1px;
  background-color: var(--marker-compass-tint, rgba(230, 180, 0, 0.16)) !important;
}

/* Wormhole cells — paired background tints (no border, avoids conflict with number colors).
   Colors chosen to avoid sonar cyan, compass gold, and liar pink.
   Base rule is a fallback for old saved games missing wormholePairIndex. */
.cell.wormhole-cell { background: var(--marker-wormhole-0, rgba(255, 140, 0, 0.18)) !important; }                   /* fallback amber */
.cell.wormhole-cell.wormhole-pair-0 { background: var(--marker-wormhole-0, rgba(255, 140, 0, 0.18)) !important; }   /* amber */
.cell.wormhole-cell.wormhole-pair-1 { background: var(--marker-wormhole-1, rgba(220, 80, 220, 0.18)) !important; }  /* magenta */
.cell.wormhole-cell.wormhole-pair-2 { background: var(--marker-wormhole-2, rgba(100, 220, 100, 0.18)) !important; } /* green */

/* Mirror pair color-coding — dashed border (not fill) so they're distinct from wormholes */
.cell.mirror-cell.mirror-pair-0 { border: var(--marker-mirror-width, 2.5px) dashed var(--marker-mirror-0, rgba(52, 152, 219, 0.85)) !important; }
.cell.mirror-cell.mirror-pair-1 { border: var(--marker-mirror-width, 2.5px) dashed var(--marker-mirror-1, rgba(155, 89, 182, 0.85)) !important; }
.cell.mirror-cell.mirror-pair-2 { border: var(--marker-mirror-width, 2.5px) dashed var(--marker-mirror-2, rgba(46, 204, 113, 0.85)) !important; }

/* Mine shift shimmer */
.mine-shift-shimmer {
  animation: mineShiftFlash 0.6s ease-out;
}

@keyframes mineShiftFlash {
  0% { box-shadow: 0 0 12px rgba(255, 200, 50, 0.6); }
  100% { box-shadow: none; }
}

/* ── Bottom Nav ─────────────────────────────── */

#bottom-nav {
  display: flex;
  gap: 14px;
  flex-wrap: wrap;
  justify-content: center;
}

/* Four targets only since the 2026-06-10 declutter: roomier thumb
   targets, no wrap pressure on a phone. */
.nav-btn {
  font-size: 22px;
  width: 52px;
  height: 48px;
  border: var(--border-nav-btn);
  background: var(--color-btn-gradient);
  border-radius: 12px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all var(--transition-fast);
  box-shadow: var(--shadow-sm);
}

.nav-btn:hover {
  background: var(--color-btn-hover);
  transform: translateY(-2px);
  box-shadow: var(--shadow-nav-btn-hover);
}

.nav-btn:active {
  transform: translateY(0);
  box-shadow: none;
}

/* ── Modals ──────────────────────────────────── */

.modal {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: var(--color-modal-overlay);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1001; /* above title screen (z-index: 1000) */
  animation: fadeIn 0.2s ease-out;
  /* No backdrop-filter blur. A full-viewport blur re-rasterizes the whole
     title/board behind the modal, and the fadeIn re-runs that every frame. When
     Chrome composites in software (integrated graphics, or a GPU-driver
     fallback that can hit even a strong card), it runs on the CPU and stalls
     every modal open. The dim overlay alone reads as a modal at no blur cost. */
}

@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes slideUp {
  from { opacity: 0; transform: translateY(24px) scale(0.96); }
  to { opacity: 1; transform: translateY(0) scale(1); }
}

.modal.hidden {
  display: none;
}

.modal-content {
  background: var(--bg-modal-content);
  color: var(--color-text);
  border-radius: 20px;
  padding: 28px;
  max-width: 420px;
  width: 92%;
  max-height: 85vh;
  overflow-y: auto;
  box-shadow: var(--shadow-modal);
  animation: slideUp 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
  border: var(--border-modal);
}

.modal-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20px;
}

.modal-header h2 {
  font-family: var(--font-display);
  font-size: 22px;
  font-weight: 700;
  letter-spacing: 1px;
}

.modal-close {
  background: none;
  border: none;
  font-size: 28px;
  cursor: pointer;
  color: var(--color-text-secondary);
  line-height: 1;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all var(--transition-fast);
}

.modal-close:hover {
  color: var(--color-text);
  background: var(--bg-modal-close-hover);
}

/* ── Settings ───────────────────────────────── */

.setting-group {
  margin-bottom: 24px;
}

.setting-group h3 {
  font-size: 11px;
  margin-bottom: 12px;
  color: var(--color-text-secondary);
  text-transform: uppercase;
  letter-spacing: 2px;
  font-weight: 700;
}

/* Theme picker: each theme is a CARD with a live mini-board preview —
   real cell classes inside a [data-theme] wrapper, so the theme's own
   fog, numbers, objects, and fog-art render. Replaced the old
   circle-swatch look (a gradient dot said nothing about the world). */
.theme-swatches {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(118px, 1fr));
  gap: 10px;
}

.theme-swatch {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 8px 8px 9px;
  border: 2px solid transparent;
  background: var(--color-btn-bg);
  border-radius: 12px;
  cursor: pointer;
  font-size: 11px;
  font-weight: 600;
  color: var(--color-text);
  transition: all var(--transition-fast);
  /* 26 cards x 8 themed cells + fog-art rasters is a heavy first
     paint; skip layout/paint for offscreen cards so opening the tab
     does not jank. */
  content-visibility: auto;
  contain-intrinsic-size: 130px 118px;
}

.theme-swatch:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-md);
}

.theme-swatch.active {
  border-color: var(--color-accent);
  box-shadow: 0 0 0 2px var(--color-accent-glow);
}

/* The mini-board: 4x2 of real .cell elements. Sized locally (the
   global .cell reads --cell-size, which JS owns on the live #board). */
.swatch-board {
  display: grid;
  grid-template-columns: repeat(4, 21px);
  gap: 2px;
  padding: 4px;
  border-radius: 6px;
  background-color: var(--color-border, #555);
  background-image: var(--bg-fog-art, none);
  background-size: 100% 100%;
  pointer-events: none;
}

.swatch-board .cell {
  width: 21px;
  height: 21px;
  min-width: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  line-height: 1;
  /* Inherit the theme's own face: its cell radius, its bevel shadow,
     its number font - that is what makes the preview accurate. */
  font-family: var(--font-family);
  border-radius: var(--cell-shape-radius, 3px);
}

.swatch-name {
  display: block;
}

.swatch-lock {
  display: block;
  font-size: 9px;
  color: var(--color-text-secondary);
  font-weight: 600;
  letter-spacing: 0.3px;
  white-space: nowrap;
}

.swatch-lock.hidden,
.swatch-name.hidden {
  display: none !important;
}

/* ── Locked Theme Swatch ─────────────────── */

.theme-swatch.locked {
  opacity: 0.4;
  filter: grayscale(0.7);
  cursor: not-allowed;
}

.theme-swatch.locked:hover {
  transform: none;
  box-shadow: none;
}

.theme-swatch.locked .swatch-board {
  filter: grayscale(0.8) brightness(0.7);
}

.theme-swatch.swatch-shake {
  animation: swatchShake 0.4s ease-out;
}

@keyframes swatchShake {
  0%, 100% { transform: translateX(0); }
  20% { transform: translateX(-3px); }
  40% { transform: translateX(3px); }
  60% { transform: translateX(-2px); }
  80% { transform: translateX(2px); }
}

/* ── Theme Collapse Toggle ─────────────────── */

.toggle-locked-btn {
  display: block;
  width: 100%;
  margin-top: 8px;
  padding: 8px 0;
  background: none;
  border: 1px dashed var(--color-border);
  border-radius: 8px;
  color: var(--color-text-secondary);
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.2s;
  letter-spacing: 0.5px;
}

.toggle-locked-btn:hover {
  color: var(--color-text);
  border-color: var(--color-accent);
}

.toggle-locked-btn.expanded {
  border-style: solid;
}

.theme-swatch.locked-collapsed {
  display: none;
}

.mode-buttons {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.mode-btn {
  padding: 10px 16px;
  min-height: 44px;
  border: 2px solid var(--color-border);
  background: var(--color-btn-bg);
  border-radius: 10px;
  cursor: pointer;
  font-size: 13px;
  font-weight: 600;
  color: var(--color-text);
  transition: all var(--transition-fast);
}

.mode-btn.active {
  background: var(--color-accent);
  border-color: var(--color-accent);
  color: #fff;
  box-shadow: 0 2px 8px var(--color-accent-glow);
}

.mode-btn:hover:not(.active) {
  background: var(--color-btn-hover);
  transform: translateY(-1px);
}

/* ── Timed Difficulty Picker ───────────────── */

.timed-difficulty {
  margin-top: 8px;
}

.timed-difficulty h4 {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 1.5px;
  color: var(--color-muted);
  margin: 0 0 6px 0;
}

.timed-diff-buttons {
  display: flex;
  gap: 6px;
}

.timed-diff-btn {
  flex: 1;
  padding: 8px 6px;
  border: 2px solid var(--color-border);
  background: var(--color-btn-bg);
  border-radius: 8px;
  cursor: pointer;
  font-size: 12px;
  font-weight: 600;
  color: var(--color-text);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  transition: all 0.15s ease;
}

.timed-diff-btn span {
  font-size: 10px;
  font-weight: 400;
  opacity: 0.6;
}

.timed-diff-btn.active {
  background: var(--color-accent);
  border-color: var(--color-accent);
  color: #fff;
  box-shadow: 0 2px 8px var(--color-accent-glow);
}

.timed-diff-btn.active span {
  opacity: 0.85;
}

.timed-diff-btn:hover:not(.active) {
  background: var(--color-btn-hover);
  transform: translateY(-1px);
}

/* ── Reset Profile ─────────────────────────── */

.reset-group {
  border-top: 1px solid rgba(0,0,0,0.08);
  padding-top: 20px;
  margin-top: 8px;
}

.clear-cache-btn {
  width: 100%;
  padding: 10px 20px;
  border: 2px solid var(--color-border, #555);
  background: transparent;
  color: var(--color-text, #ccc);
  border-radius: 10px;
  cursor: pointer;
  font-size: 13px;
  font-weight: 700;
  transition: all 0.2s ease;
}
.clear-cache-btn:hover {
  background: var(--color-border, #555);
  color: #fff;
  transform: translateY(-1px);
}
.clear-cache-btn:active {
  background: var(--color-border, #555);
  color: #fff;
}

.reset-profile-btn {
  width: 100%;
  margin-top: 16px;
  padding: 10px 20px;
  border: 2px solid #d32f2f;
  background: transparent;
  color: #d32f2f;
  border-radius: 10px;
  cursor: pointer;
  font-size: 13px;
  font-weight: 700;
  transition: all 0.2s ease;
}

.reset-profile-btn:hover {
  background: #d32f2f;
  color: #fff;
  transform: translateY(-1px);
  box-shadow: 0 2px 8px rgba(211, 47, 47, 0.3);
}
.reset-profile-btn:active {
  background: #d32f2f;
  color: #fff;
}

.reset-hint {
  font-size: 11px;
  color: var(--color-text-secondary);
  margin-top: 8px;
  opacity: 0.7;
}

/* Account section in Settings — two stacked buttons with hint above,
   plus the optional email-link form that slides in when "Sign in with
   email link" is tapped. */
.account-section {
  display: block;
}
.account-btn {
  margin-top: 10px;
}
.account-btn:first-of-type {
  margin-top: 8px;
}
.account-status {
  margin: 0 0 4px;
  font-size: 14px;
  color: var(--color-text, #eee);
}
.account-status strong {
  font-weight: 700;
}
.email-link-form {
  margin-top: 10px;
}
.email-link-form input {
  width: 100%;
  margin-bottom: 8px;
}
.email-link-row {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 10px;
}
.text-btn {
  background: transparent;
  border: none;
  color: var(--color-text-secondary);
  font-size: 13px;
  font-weight: 600;
  padding: 8px 12px;
  cursor: pointer;
  border-radius: 6px;
}
.text-btn:hover {
  color: var(--color-text, #eee);
}
.account-btn-inline {
  width: auto;
  padding: 8px 18px;
  font-size: 13px;
}
.account-confirm-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 10px;
  margin-top: 16px;
}

/* Reminder time: a themed control instead of the bare OS dropdown,
   so the Alerts tab matches the rest of Settings. */
.reminder-hour-select {
  font: inherit;
  font-size: 14px;
  color: var(--color-text, #eee);
  background: transparent;
  border: 2px solid var(--color-border, #555);
  border-radius: 10px;
  padding: 8px 12px;
  cursor: pointer;
}
.reminder-hour-select:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}
/* "Reminder time" is dependent on the Daily-reminders toggle above it:
   indent + space it so Alerts reads with the same rhythm as the
   other tabs instead of one cramped block. */
.setting-subrow {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 12px 0 0 28px;
  font-size: 14px;
  color: var(--color-text, #eee);
}
.setting-subrow label {
  color: var(--color-text-secondary);
}

/* About tab: the sponsor / privacy / par links and their explanations
   must be readable, not the faint muted hint style used elsewhere. */
#settings-panel-about .reset-hint {
  color: var(--color-text, #eee);
  opacity: 1;
  font-size: 12px;
}
#settings-panel-about a {
  color: var(--color-text, #eee);
  opacity: 1;
  font-weight: 600;
  text-decoration: underline;
}

/* ── Help ───────────────────────────────────── */

.help-body {
  font-size: 14px;
}

.help-section {
  margin-bottom: 14px;
  padding-bottom: 12px;
  border-bottom: 1px solid rgba(0,0,0,0.06);
}

.help-section:last-child {
  border-bottom: none;
  margin-bottom: 0;
  padding-bottom: 0;
}

.help-section h3 {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 2px;
  color: var(--color-accent);
  margin-bottom: 6px;
  font-weight: 700;
}

.help-section p {
  margin-bottom: 4px;
  line-height: 1.5;
}

.help-note {
  font-size: 12px;
  color: var(--color-text-secondary, #888);
  font-style: italic;
  margin-top: 4px;
}

/* Hide keyboard shortcuts on touch / mobile devices */
@media (hover: none), (max-width: 768px) {
  .help-keyboard-only { display: none; }
}

/* ── Stats ──────────────────────────────────── */






.recent-games h3 {
  font-size: 14px;
  margin-bottom: 10px;
  color: var(--color-text-secondary);
}

#recent-games-chart {
  display: flex;
  gap: 3px;
  align-items: flex-end;
  height: 70px;
  padding: 6px;
  background: var(--color-surface);
  border-radius: 10px;
  border: 1px solid rgba(0,0,0,0.04);
}

.game-bar {
  flex: 1;
  min-width: 4px;
  max-width: 14px;
  border-radius: 3px 3px 0 0;
  transition: height 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.game-bar.win {
  background: linear-gradient(180deg, var(--color-win), #2e7d32);
}

.game-bar.loss {
  background: linear-gradient(180deg, var(--color-loss), #c62828);
}

/* ── Stats modal v2 — tabbed, mode-specific charts ───── */

.stats-modal-content {
  /* Matches leaderboard-modal-content: the two modals read as one design. */
  max-width: 600px;
}
.stats-body {
  max-height: min(80vh, 900px);
  overflow-y: auto;
}

.stats-tabs, .help-tabs, .settings-tabs {
  display: flex;
  gap: 2px;
  margin-bottom: 16px;
  border-bottom: 1px solid var(--color-border, rgba(255, 255, 255, 0.1));
}
.stats-tab, .help-tab, .settings-tab {
  flex: 1;
  background: transparent;
  color: var(--color-text-secondary);
  border: none;
  padding: 9px 6px;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  border-bottom: 2px solid transparent;
  transition: color 0.2s, border-color 0.2s;
}
.stats-tab:hover, .help-tab:hover, .settings-tab:hover { color: var(--color-text); }
.stats-tab.active, .help-tab.active, .settings-tab.active {
  color: var(--color-accent, #4c8dff);
  border-bottom-color: var(--color-accent, #4c8dff);
}
.stats-panel.hidden, .help-panel.hidden, .settings-panel.hidden { display: none; }

/* Leaderboard modal tabs (Daily / Weekly). Reuses the stats-tab
   visual pattern but scoped to the leaderboard modal so tab styles stay
   independent if either set changes. */
/* Leaderboard modal: roomier than the default 420px so the three-view
   layout and the friends panel can breathe (stats-modal precedent). */
.leaderboard-modal-content {
  max-width: 600px;
}

/* Scope toggle (Daily/Weekly): compact pills, sits above the view tabs. */
.leaderboard-tabs.lb-scope-toggle {
  display: inline-flex;
  gap: 3px;
  margin-bottom: 10px;
  padding: 3px;
  border-radius: 9px;
  background: var(--color-surface, rgba(255, 255, 255, 0.05));
  border-bottom: none;
}
.lb-scope-toggle .leaderboard-tab {
  flex: none;
  background: transparent;
  color: var(--color-text-secondary);
  border: none;
  border-radius: 6px;
  padding: 6px 18px;
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
  transition: color 0.2s, background-color 0.2s;
}
.lb-scope-toggle .leaderboard-tab:hover { color: var(--color-text); }
.lb-scope-toggle .leaderboard-tab.active {
  background: var(--color-accent, #4c8dff);
  color: #fff;
}

/* View tabs (Scores / Adjusted / Friends): the proven underline style. */
.lb-view-tabs {
  display: flex;
  gap: 2px;
  margin-bottom: 12px;
  border-bottom: 1px solid var(--color-border, rgba(255, 255, 255, 0.1));
}
.lb-view-tab {
  flex: 1;
  background: transparent;
  color: var(--color-text-secondary);
  border: none;
  padding: 9px 6px;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  border-bottom: 2px solid transparent;
  transition: color 0.2s, border-color 0.2s;
}
.lb-view-tab:hover:not(:disabled) { color: var(--color-text); }
.lb-view-tab.active {
  color: var(--color-accent, #4c8dff);
  border-bottom-color: var(--color-accent, #4c8dff);
}

/* Mini tables inside Stats (past weeks): the leaderboard's row language. */
.lb-mini-table {
  width: 100%;
  border-collapse: collapse;
  margin-top: 8px;
}
.lb-mini-table th,
.lb-mini-table td {
  padding: 8px 10px;
  text-align: left;
  border-bottom: 1px solid rgba(0, 0, 0, 0.06);
  font-size: 12.5px;
}
.lb-mini-table th {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.6px;
  color: var(--color-text-secondary);
  font-weight: 700;
}

/* Medal sprites mark the four top ranks (diamond/gold/silver/bronze). */
.sprite-rank {
  width: 21px;
  height: 21px;
  vertical-align: middle;
}
/* Modifier (gimmick) icon sprites — inline with text in bars, popups, help. */
.sprite-gimmick {
  width: 1.2em;
  height: 1.2em;
  vertical-align: -0.15em;
}
.lb-rank-cell { line-height: 1; }
.sprite-medal {
  width: 26px;
  height: 26px;
  vertical-align: middle;
}

/* Wave C chrome icon sprites. Theme-agnostic affordances drawn in the
   house style; sizing varies by host (icon-only nav button vs inline
   label vs modal close). */
.ui-icon {
  width: 22px;
  height: 22px;
  vertical-align: middle;
}
.ui-icon-nav {
  width: 28px;
  height: 28px;
  vertical-align: middle;
}
.ui-icon-label {
  width: 22px;
  height: 22px;
  vertical-align: -5px;
  margin-right: 7px;
}
.modal-close .ui-icon-close {
  width: 24px;
  height: 24px;
  display: block;
}

/* Long names scroll horizontally (hidden scrollbar) instead of
   truncating, so the full name is always reachable by swipe/trackpad. */
.lb-name {
  display: inline-block;
  vertical-align: middle;
  max-width: 220px;
  white-space: nowrap;
  overflow-x: auto;
  scrollbar-width: none;
}
.lb-name::-webkit-scrollbar { display: none; }

/* Handicap chips on the Adjusted view. */
.lb-hc-chip {
  display: inline-block;
  padding: 1px 7px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 700;
  background: var(--color-surface, rgba(255, 255, 255, 0.07));
  color: var(--color-text-secondary);
}
.lb-hc-chip.lb-hc-unrated {
  font-style: italic;
  font-weight: 600;
  opacity: 0.7;
}
.lb-adjusted { font-weight: 700; }
.lb-footnote {
  margin: 10px 0 0;
  font-size: 11px;
  color: var(--color-text-secondary);
  opacity: 0.85;
}

/* ── Friends panel ───────────────────────────── */
.friends-code-block {
  margin: 4px 0 14px;
  padding: 14px;
  border-radius: 12px;
  background: var(--color-surface, rgba(255, 255, 255, 0.05));
  text-align: center;
}
.friends-code-label {
  margin: 0 0 6px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--color-text-secondary);
}
.friends-code-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
}
.friends-code {
  font-family: var(--font-display, monospace);
  font-size: 28px;
  font-weight: 800;
  letter-spacing: 6px;
  color: var(--color-accent, #4c8dff);
  user-select: all;
}
.friends-code-expiry {
  margin: 6px 0 0;
  font-size: 11.5px;
  color: var(--color-text-secondary);
  min-height: 1em;
}
.friends-code-hint {
  margin: 8px 0 0;
  font-size: 11.5px;
  line-height: 1.4;
  color: var(--color-text-secondary);
  opacity: 0.85;
}
.friends-add-block {
  display: flex;
  gap: 8px;
  margin-bottom: 10px;
}
.friends-input {
  flex: 1;
  min-width: 0;
  padding: 9px 12px;
  border-radius: 8px;
  border: 1px solid var(--color-border, rgba(255, 255, 255, 0.15));
  background: var(--color-surface, rgba(255, 255, 255, 0.05));
  color: var(--color-text);
  font-size: 14px;
  letter-spacing: 2px;
  text-transform: uppercase;
}
.friends-btn {
  padding: 8px 14px;
  border-radius: 8px;
  border: 1px solid var(--color-border, rgba(255, 255, 255, 0.15));
  background: var(--color-btn-bg);
  color: var(--color-text);
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
}
.friends-btn:hover { background: var(--color-btn-hover); }
.friends-btn-primary {
  background: var(--color-accent, #4c8dff);
  border-color: transparent;
  color: #fff;
}
.friends-status {
  margin: 0 0 10px;
  font-size: 12.5px;
  color: var(--color-win, #6abf69);
}
.friends-status-error { color: var(--color-loss, #e57373); }
.friends-empty {
  font-size: 12.5px;
  color: var(--color-text-secondary);
  margin: 8px 0 12px;
}
.friends-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 7px 4px;
  border-bottom: 1px solid var(--color-border, rgba(255, 255, 255, 0.08));
}
.friends-row-name { font-size: 13.5px; font-weight: 600; }
.friends-remove {
  background: transparent;
  border: none;
  color: var(--color-text-secondary);
  font-size: 13px;
  cursor: pointer;
  padding: 4px 8px;
  border-radius: 6px;
}
.friends-remove:hover {
  color: var(--color-loss, #e57373);
  background: var(--color-surface, rgba(255, 255, 255, 0.06));
}
#friends-list { margin-bottom: 14px; }

@media (max-width: 520px) {
  .friends-code { font-size: 22px; letter-spacing: 4px; }
  .lb-scope-toggle .leaderboard-tab { padding: 6px 14px; }
  .lb-hc-chip { font-size: 10px; padding: 1px 5px; }
}

.stats-section {
  margin-top: 20px;
  padding-top: 14px;
  border-top: 1px solid var(--color-border, rgba(255, 255, 255, 0.08));
}
.stats-section:first-child {
  margin-top: 0;
  padding-top: 0;
  border-top: none;
}
.stats-section h3 {
  margin: 0 0 4px;
  font-size: 14px;
  font-weight: 700;
}
.stats-blurb {
  margin: 0 0 10px !important;
  font-size: 11px;
  color: var(--color-text-secondary);
  opacity: 0.85;
  line-height: 1.4;
}

.stat-headline {
  font-size: 32px;
  font-weight: 800;
  font-family: var(--font-display);
  margin: 4px 0 8px;
  color: var(--color-accent, #4c8dff);
}

.stat-row {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 10px;
}
.stat-mini {
  flex: 1 1 0;
  min-width: 80px;
  padding: 9px 12px;
  background: var(--color-surface);
  border-radius: 12px;
  border: 1px solid rgba(0, 0, 0, 0.04);
  text-align: center;
}
.stat-mini-label {
  font-size: 9.5px;
  text-transform: uppercase;
  letter-spacing: 0.6px;
  color: var(--color-text-secondary);
  font-weight: 600;
}
.stat-mini-value {
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 800;
  margin-top: 2px;
}

.stat-chart {
  background: var(--color-surface);
  border-radius: 10px;
  padding: 8px;
  margin-top: 4px;
}
.chart-empty {
  display: block;
  padding: 24px 12px;
  text-align: center;
  font-size: 12px;
  color: var(--color-text-secondary);
  opacity: 0.65;
}
.recent-games-inline {
  display: flex;
  gap: 3px;
  align-items: flex-end;
  height: 70px;
  padding: 6px;
}

.stats-chart {
  display: block;
  width: 100%;
  height: auto;
  max-height: 320px;
}

/* Chart styling — SVG user units. Same viewBox as dailyHistoryChart. */
.chart-axis-grid {
  stroke: var(--color-text-secondary);
  stroke-opacity: 0.12;
  stroke-width: 1;
}
.chart-axis-zero {
  stroke: var(--color-text-secondary);
  stroke-opacity: 0.5;
  stroke-width: 2;
}
.chart-threshold {
  stroke: var(--color-text-secondary);
  stroke-opacity: 0.4;
  stroke-width: 1;
  stroke-dasharray: 4 4;
}
.chart-axis-label {
  font-size: 20px;
  font-family: inherit;
  fill: var(--color-text-secondary);
  opacity: 0.75;
}
.chart-axis-label-zero { opacity: 0.95; font-weight: 600; }
.chart-x-label { font-size: 18px; }
.chart-legend {
  font-size: 18px;
  font-family: inherit;
  opacity: 0.9;
}
.chart-value-label { font-weight: 600; }

.chart-line {
  stroke: var(--color-accent, #4c8dff);
  stroke-width: 3;
  fill: none;
  stroke-linejoin: round;
}
.chart-line-handicap { stroke: #7b61ff; }
.chart-line-strike   { stroke: #ef5350; }
.chart-line-rank     { stroke: #f9a825; }
/* Secondary series: thinner, dashed, muted neutral so the primary
   line reads as the headline signal and the secondary reads as
   supporting context. Used by the handicap-trajectory chart to
   overlay a 10-play rolling mean on top of the cumulative average. */
.chart-line-secondary {
  stroke: var(--color-text-secondary, #888);
  stroke-width: 2;
  stroke-dasharray: 6 4;
  opacity: 0.75;
  fill: none;
}
.chart-dot-secondary {
  fill: var(--color-text-secondary, #888);
  opacity: 0.85;
}
.chart-dot {
  stroke: none;
  fill: var(--color-accent, #4c8dff);
}
.chart-dot-good { fill: #4caf50; }
.chart-dot-bad  { fill: #ef5350; }
.chart-dot-even { fill: var(--color-text-secondary); opacity: 0.7; }

.chart-area { fill-opacity: 0.85; stroke: none; }
.chart-area-easy   { fill: #4caf50; }
.chart-area-medium { fill: #fbc02d; }
.chart-area-hard   { fill: #ef5350; }
.chart-legend.chart-area-easy   { fill: #4caf50; }
.chart-legend.chart-area-medium { fill: #fbc02d; }
.chart-legend.chart-area-hard   { fill: #ef5350; }

.chart-bar { stroke: none; }
.chart-bar-a      { fill: var(--color-accent, #4c8dff); }
.chart-bar-b      { fill: var(--color-text-secondary); opacity: 0.5; }
.chart-bar-recent { fill: var(--color-accent, #4c8dff); }
.chart-bar-prior  { fill: var(--color-text-secondary); opacity: 0.5; }
.chart-bar-freq   { fill: #7b61ff; }
.chart-legend.chart-bar-recent { fill: var(--color-accent, #4c8dff); }
.chart-legend.chart-bar-prior  { fill: var(--color-text-secondary); opacity: 0.8; }

.chart-density-fill {
  fill: #7b61ff;
  fill-opacity: 0.35;
  stroke: none;
}
.chart-density-line {
  stroke: #7b61ff;
  stroke-width: 3;
  fill: none;
  stroke-linejoin: round;
}
.chart-meanline {
  stroke: #f9a825;
  stroke-width: 2;
  stroke-dasharray: 6 6;
  opacity: 0.9;
}

.chart-whisker { stroke: var(--color-text-secondary); stroke-width: 1.5; opacity: 0.6; }
.chart-box     { fill: var(--color-accent, #4c8dff); fill-opacity: 0.35; stroke: var(--color-accent, #4c8dff); stroke-width: 1.5; }
.chart-median  { stroke: #fff; stroke-width: 3; }

.chart-heat-bar { stroke: none; }
.chart-heat-good { fill: #4caf50; }
.chart-heat-bad  { fill: #ef5350; }
.chart-heat-even { fill: var(--color-text-secondary); opacity: 0.5; }

@media (max-width: 520px) {
  .stats-modal-content { max-width: 100%; }
  .stat-headline { font-size: 26px; }
  .stats-section h3 { font-size: 13px; }
  .stat-mini-label { font-size: 9px; }
  .stat-mini-value { font-size: 15px; }
  .stats-chart { max-height: 260px; }
  .chart-axis-label { font-size: 22px; }
  .chart-x-label { font-size: 20px; }
}

/* ── Achievements / Ranks ──────────────────── */

.achievements-content {
  max-width: 440px;
}

.achievement-progress-bar {
  height: 28px;
  background: var(--color-surface);
  border-radius: 14px;
  margin-bottom: 20px;
  position: relative;
  overflow: hidden;
  border: 1px solid rgba(0,0,0,0.06);
}

.achievement-progress-fill {
  height: 100%;
  background: linear-gradient(90deg, var(--color-accent), var(--color-golden));
  border-radius: 14px;
  transition: width 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
  min-width: 0;
}

.achievement-progress-text {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 1px;
  color: var(--color-text);
  text-shadow: 0 1px 2px rgba(255,255,255,0.5);
}

/* ── Achievements: sectioned list rows (2026-06-10 redesign) ──
   The earned medal opens each row; the name carries the weight; the
   next step reads as one sentence; a six-dot track shows the tier
   ladder; a hairline progress bar underlines rows still in motion.
   No boxes — the rows breathe against the modal surface. */
.achievements-grid {
  display: flex;
  flex-direction: column;
}

.ach-section-title {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-text-secondary);
  margin: 18px 0 4px;
}
.ach-section-title:first-child {
  margin-top: 6px;
}

.ach-row {
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 2px 12px;
  border-bottom: 1px solid rgba(128, 128, 128, 0.12);
}

.ach-medal {
  font-size: 24px;
  flex-shrink: 0;
  width: 32px;
  height: 32px;
  text-align: center;
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
/* Locked: the category icon shows greyed — the technique you're chasing.
   Earned: it lifts to full colour and a corner medal marks the tier. */
.ach-medal.none {
  opacity: 0.45;
  filter: grayscale(1);
}
.ach-tier-badge {
  position: absolute;
  right: -5px;
  bottom: -5px;
  display: inline-flex;
  line-height: 0;
  filter: drop-shadow(0 1px 1.5px rgba(0, 0, 0, 0.35));
}
.sprite-tier-badge {
  width: 15px;
  height: 15px;
}

.ach-main {
  flex: 1;
  min-width: 0;
}

.ach-name-line {
  display: flex;
  align-items: center;
  gap: 10px;
}

.ach-name {
  font-weight: 700;
  font-size: 14px;
}

.ach-track {
  display: inline-flex;
  gap: 4px;
  align-items: center;
}
.ach-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: rgba(128, 128, 128, 0.25);
}
.ach-dot.earned {
  box-shadow: 0 0 4px rgba(0, 0, 0, 0.15);
}

.ach-sub {
  font-size: 11.5px;
  color: var(--color-text-secondary);
  margin-top: 2px;
}

.ach-next {
  font-weight: 600;
  color: var(--color-text);
}
.ach-next.ach-maxed {
  color: var(--color-golden);
}

/* Hairline progress underline for rows still in motion */
.ach-rowbar {
  position: absolute;
  left: 44px;
  right: 2px;
  bottom: 0;
  height: 2px;
  background: transparent;
}
.ach-rowbar > div {
  height: 100%;
  background: var(--color-accent);
  opacity: 0.55;
  border-radius: 1px;
  transition: width 0.5s var(--ease-standard, ease-out);
}

/* kept for the win-modal tier-up chips */
.ach-maxed {
  color: var(--color-golden);
  font-weight: 700;
  font-size: 11px;
}

/* Tier-up badge in game over */
.tier-up-badge {
  background: linear-gradient(135deg, rgba(249, 168, 37, 0.2), rgba(255, 215, 0, 0.15));
  border-color: var(--color-golden);
  animation: tierBadgePulse 1.5s ease-in-out infinite;
}

@keyframes tierBadgePulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(249, 168, 37, 0.3); }
  50% { box-shadow: 0 0 16px 4px rgba(249, 168, 37, 0.2); }
}

/* ── Achievement Toast ─────────────────────── */

.achievement-toast {
  position: fixed;
  top: 16px;
  left: 50%;
  transform: translateX(-50%) translateY(-100%);
  background: var(--color-modal-bg);
  color: var(--color-text);
  padding: 14px 24px;
  border-radius: 14px;
  display: flex;
  align-items: center;
  gap: 12px;
  z-index: 300;
  box-shadow: var(--shadow-lg), 0 0 0 2px var(--color-golden);
  animation: achievementSlideIn 0.5s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
  border: 1px solid var(--color-golden);
}

.achievement-toast.hidden {
  display: none;
}

.achievement-toast.hiding {
  animation: achievementSlideOut 0.3s ease-in forwards;
}

@keyframes achievementSlideIn {
  from { transform: translateX(-50%) translateY(-100%); }
  to { transform: translateX(-50%) translateY(0); }
}

@keyframes achievementSlideOut {
  from { transform: translateX(-50%) translateY(0); opacity: 1; }
  to { transform: translateX(-50%) translateY(-100%); opacity: 0; }
}

.achievement-toast-icon {
  font-size: 32px;
}

.achievement-toast-title {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 2px;
  color: var(--color-golden);
  font-weight: 700;
}

.achievement-toast-name {
  font-size: 15px;
  font-weight: 700;
}

/* ── Theme Unlock Toast ──────────────────── */

.theme-unlock-toast {
  position: fixed;
  bottom: 16px;
  left: 50%;
  transform: translateX(-50%) translateY(100%);
  background: var(--color-modal-bg);
  color: var(--color-text);
  padding: 14px 24px;
  border-radius: 14px;
  display: flex;
  align-items: center;
  gap: 12px;
  z-index: 300;
  box-shadow: var(--shadow-lg), 0 0 0 2px var(--color-accent);
  animation: themeUnlockSlideIn 0.5s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
  border: 1px solid var(--color-accent);
}

.theme-unlock-toast.hidden {
  display: none;
}

.theme-unlock-toast.hiding {
  animation: themeUnlockSlideOut 0.3s ease-in forwards;
}

@keyframes themeUnlockSlideIn {
  from { transform: translateX(-50%) translateY(100%); }
  to { transform: translateX(-50%) translateY(0); }
}

@keyframes themeUnlockSlideOut {
  from { transform: translateX(-50%) translateY(0); opacity: 1; }
  to { transform: translateX(-50%) translateY(100%); opacity: 0; }
}

.theme-unlock-toast-icon {
  font-size: 32px;
}

.theme-unlock-toast-title {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 2px;
  color: var(--color-accent);
  font-weight: 700;
}

.theme-unlock-toast-name {
  font-size: 15px;
  font-weight: 700;
}

/* ── Gameover Achievements ─────────────────── */

.gameover-achievements {
  margin: 12px 0;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  justify-content: center;
}

.gameover-achievement-badge {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  background: rgba(249, 168, 37, 0.1);
  border: 1px solid var(--color-golden);
  border-radius: 20px;
  font-size: 12px;
  font-weight: 600;
}

/* ── Leaderboard ────────────────────────────── */

#leaderboard-table {
  width: 100%;
  border-collapse: collapse;
  margin-top: 12px;
}

#leaderboard-table th,
#leaderboard-table td {
  padding: 10px 14px;
  text-align: left;
  border-bottom: 1px solid rgba(0,0,0,0.06);
}

/* Narrow screens: tighten padding and shrink fonts so the table fits
   at 390px. Long names SCROLL (see .lb-name) rather than truncate. */
@media (max-width: 520px) {
  #leaderboard-table th,
  #leaderboard-table td {
    padding: 6px 3px;
    font-size: 11.5px;
  }
  #leaderboard-table th {
    font-size: 9px;
    letter-spacing: 0.5px;
  }
  .lb-name { max-width: 110px; }
  .sprite-rank { width: 18px; height: 18px; }
  #leaderboard-table td:first-child,
  #leaderboard-table th:first-child {
    padding-left: 4px;
  }
  #leaderboard-table td:last-child,
  #leaderboard-table th:last-child {
    padding-right: 4px;
  }
}

#leaderboard-table th {
  font-size: 10px;
  text-transform: uppercase;
  color: var(--color-text-secondary);
  letter-spacing: 1.5px;
  font-weight: 700;
}

#leaderboard-empty {
  text-align: center;
  color: var(--color-text-secondary);
  padding: 24px;
  font-size: 14px;
}

.lb-status {
  display: inline-block;
  font-size: 10px;
  padding: 2px 8px;
  border-radius: 10px;
  vertical-align: middle;
  margin-left: 6px;
  font-weight: 600;
  letter-spacing: 0.5px;
}

.lb-status.online {
  background: rgba(67, 160, 71, 0.2);
  color: #43a047;
}

.lb-status.offline {
  background: rgba(128, 128, 128, 0.2);
  color: #999;
}

/* ── Game Over ──────────────────────────────── */

.gameover-content {
  text-align: center;
}

.gameover-content h2 {
  font-family: var(--font-display);
  font-size: 32px;
  font-weight: 800;
  margin-bottom: 8px;
  letter-spacing: 1px;
}

.gameover-content p {
  margin-bottom: 6px;
  color: var(--color-text-secondary);
}

#gameover-par {
  font-size: 15px;
  font-weight: 600;
}
.par-under { color: #4caf50 !important; }
.par-over { color: #ef5350 !important; }
.par-even { color: var(--color-text-secondary) !important; }

/* Highlight the signed-in player's own row on the daily / weekly
   leaderboard. Themes can override --color-mine-row, but the default
   accent-tinted background works against every shipped theme. */
.lb-row-mine td {
  background: var(--color-mine-row, rgba(76, 141, 255, 0.18));
  font-weight: 700;
}

/* Greg's ghost row: the par rendered as a competitor at its sorted
   position. Dashed and muted so it reads as a benchmark, not a player;
   the crab sprite sits where a rank number would (he holds no rank,
   humans keep theirs). */
.greg-row td {
  border-top: 1px dashed var(--color-text-secondary, #888);
  border-bottom: 1px dashed var(--color-text-secondary, #888);
  background: var(--color-surface, rgba(255, 255, 255, 0.04));
  color: var(--color-text-secondary);
  font-style: italic;
}
.greg-row .lb-name { font-weight: 700; }
.sprite-greg-row {
  width: 20px;
  height: 20px;
  vertical-align: middle;
}

/* Greg avatar beside his Time line on the win modal, and beside the
   field note on the Daily card. Small, inline, text-anchored. */
.sprite-greg-par {
  width: 19px;
  height: 19px;
  vertical-align: -4px;
  margin-right: 3px;
}
.sprite-greg-note {
  width: 15px;
  height: 15px;
  vertical-align: -3px;
  margin-right: 4px;
}

/* Meet-Greg one-time introduction card. */
.meet-greg-content { max-width: 340px; }
.meet-greg-body { text-align: center; }
.meet-greg-img {
  width: 120px;
  height: 120px;
  margin: 4px auto 10px;
  display: block;
}
.meet-greg-body p {
  margin: 8px 0;
  line-height: 1.45;
}

/* 7-dot history strip on the daily-win modal. Compact glance at the
   player's recent trajectory. Today's just-completed play is the
   rightmost dot, scaled up so it reads as "this play vs. recent
   pattern." Missed days render as faint outlines. */
.gameover-history-dots {
  display: flex;
  gap: 6px;
  justify-content: center;
  align-items: center;
  margin: 8px 0;
}
.gameover-history-dot {
  width: 14px; height: 14px; border-radius: 50%;
  background: var(--color-text-secondary, #999);
  opacity: 0.85;
}
.gameover-history-dot.under { background: #4caf50; }
.gameover-history-dot.over { background: #ef5350; }
.gameover-history-dot.even { background: var(--color-text-secondary, #888); }
.gameover-history-dot.missed {
  background: transparent;
  border: 1.5px solid var(--color-text-secondary, #888);
  opacity: 0.35;
}
.gameover-history-dot.today {
  width: 20px; height: 20px;
  box-shadow: 0 0 0 2px var(--color-accent, #4c8dff);
}
.par-hint {
  color: var(--color-text-secondary);
  font-size: 0.85em;
  opacity: 0.8;
}

/* Molt-day moment in the win modal: a banked cover earned, or a covered gap
   that saved the streak. A quiet positive beat above Greg's Time. */
.molt-note {
  display: inline-block;
  font-size: 0.9em;
  color: var(--color-accent, #4c8dff);
  margin-bottom: 4px;
}

.par-breakdown {
  font-size: 11.5px;
  color: var(--color-text-secondary);
  opacity: 0.75;
  line-height: 1.5;
  margin-top: -2px;
  margin-bottom: 10px;
  /* Allow natural wrapping across multiple lines on narrow screens rather
     than overflowing or truncating. */
  word-spacing: 0;
}
.par-breakdown .par-term {
  display: inline-block;
  white-space: nowrap;
}
.par-breakdown .par-term-sep {
  opacity: 0.5;
}

/* ── Weekly end-of-game summary ──────────────────────── */
.weekly-summary-row {
  margin: 6px 0;
  font-size: 14px;
}
.weekly-day-dots {
  font-size: 22px;
  letter-spacing: 4px;
  text-align: center;
  margin: 8px 0 12px;
  color: var(--color-text-primary);
}
.weekly-leaderboard {
  margin-top: 12px;
  padding-top: 10px;
  border-top: 1px solid var(--color-border, rgba(255,255,255,0.15));
  font-size: 13px;
  text-align: left;
  max-width: 320px;
  margin-left: auto;
  margin-right: auto;
}
.weekly-leaderboard-header {
  font-weight: 600;
  margin-bottom: 6px;
  text-align: center;
  color: var(--color-text-secondary);
}
.weekly-leaderboard-loading,
.weekly-leaderboard-empty {
  text-align: center;
  color: var(--color-text-secondary);
  opacity: 0.7;
  font-style: italic;
}
.weekly-lb-row {
  display: grid;
  grid-template-columns: 30px 1fr auto auto;
  gap: 8px;
  padding: 3px 6px;
  border-radius: 4px;
}
.weekly-lb-row-mine {
  background: rgba(108, 92, 231, 0.18);
  font-weight: 600;
}
.weekly-lb-rank { color: var(--color-text-secondary); }
.weekly-lb-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.weekly-lb-time { font-variant-numeric: tabular-nums; }
.weekly-lb-attempts { color: var(--color-text-secondary); font-size: 11px; align-self: center; }

/* ── Daily history chart (leaderboard modal) ───────────── */
.daily-history-section {
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid var(--color-border, rgba(255, 255, 255, 0.1));
}
.daily-history-section h4 {
  margin: 0 0 6px;
  font-size: 13px;
  font-weight: 600;
  color: var(--color-text-secondary);
  letter-spacing: 0.02em;
}
.daily-history-chart {
  display: block;
  width: 100%;
  height: auto;
  max-height: 340px;
}
.daily-history-empty {
  font-size: 13px;
  color: var(--color-text-secondary);
  opacity: 0.7;
  padding: 16px 0;
  text-align: center;
}
/* Stroke widths and font sizes are in viewBox user units (the viewBox is
   600x400). At a typical mobile rendered width of ~340px, one user unit
   equals roughly 0.57 CSS px, so 22 user units ≈ 12.5 CSS px — large
   enough to read without a zoom. */
.dhc-axis-grid {
  stroke: var(--color-text-secondary);
  stroke-opacity: 0.15;
}
.dhc-axis-zero {
  stroke: var(--color-text-secondary);
  stroke-opacity: 0.5;
}
.dhc-axis-label {
  font-size: 22px;
  font-family: inherit;
  fill: var(--color-text-secondary);
  opacity: 0.75;
}
.dhc-axis-label-zero { opacity: 0.95; font-weight: 600; }
.dhc-date-label { font-size: 20px; }
.dhc-dot { stroke: none; }
.dhc-dot-under { fill: #4caf50; }
.dhc-dot-over  { fill: #ef5350; }
.dhc-dot-even  { fill: var(--color-text-secondary); opacity: 0.7; }

#gameover-record {
  color: var(--color-golden) !important;
  font-weight: 800;
  font-size: 18px;
  text-shadow: 0 0 12px rgba(249, 168, 37, 0.3);
}

#gameover-powerup-earned {
  color: var(--color-accent) !important;
  font-size: 14px;
  font-weight: 600;
}

#gameover-life-earned {
  color: var(--color-loss, #ff4444) !important;
  font-size: 14px;
  font-weight: 700;
}

.action-btn.life-btn {
  background: linear-gradient(180deg, #e53935, #c62828);
  border-color: #e53935;
  color: #fff;
  box-shadow: var(--shadow-sm), 0 2px 8px rgba(229, 57, 53, 0.3);
  order: -1;
}

.action-btn.life-btn:hover {
  background: linear-gradient(180deg, #ef5350, #e53935);
}

@keyframes heartBeat {
  0%, 100% { transform: scale(1); }
  14% { transform: scale(1.2); }
  28% { transform: scale(1); }
  42% { transform: scale(1.15); }
  56% { transform: scale(1); }
}

.gameover-analysis {
  margin: 10px 0 4px;
  padding: 8px 14px;
  background: rgba(255, 255, 255, 0.06);
  border-radius: 8px;
  font-size: 13px;
  color: var(--color-text-secondary);
  text-align: center;
}

.gameover-actions {
  display: flex;
  gap: 10px;
  justify-content: center;
  margin-top: 20px;
  flex-wrap: wrap;
}

/* Post-death floating replay bar — sits above bottom nav */
.post-death-bar {
  position: fixed;
  bottom: 56px;
  left: 0;
  right: 0;
  display: flex;
  justify-content: center;
  padding: 12px 16px;
  background: var(--color-bg, #0f0f23);
  z-index: 100;
}
.post-death-bar .action-btn {
  min-width: 200px;
  font-size: 15px;
}

.action-btn {
  padding: 12px 24px;
  min-height: 44px;
  border: 1px solid var(--color-border);
  background: var(--color-btn-gradient);
  border-radius: 12px;
  cursor: pointer;
  font-size: 14px;
  font-weight: 700;
  color: var(--color-text);
  transition: all var(--transition-fast);
  box-shadow: var(--shadow-sm);
}

.action-btn:hover {
  transform: translateY(-1px);
  box-shadow: var(--shadow-md);
}

.action-btn:active {
  transform: translateY(0);
}

.action-btn.primary {
  background: linear-gradient(180deg, var(--color-accent), var(--color-accent-hover));
  border-color: var(--color-accent);
  color: #fff;
  box-shadow: var(--shadow-sm), 0 2px 8px var(--color-accent-glow);
}

.action-btn.share-btn {
  background: linear-gradient(180deg, var(--color-win), #2e7d32);
  border-color: var(--color-win);
  color: #fff;
}

/* ── About Modal ────────────────────────────── */

.about-content {
  max-width: 360px;
}

.about-body {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}
.about-greg {
  width: 96px;
  height: 96px;
  object-fit: contain;
  margin-bottom: 6px;
}

.about-photo-wrapper {
  width: 120px;
  height: 120px;
  border-radius: 50%;
  overflow: hidden;
  margin-bottom: 16px;
  border: 3px solid var(--color-accent);
  box-shadow: 0 4px 20px var(--color-accent-glow);
}

#about-photo {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.about-photo-fallback {
  width: 100%;
  height: 100%;
  display: none;
  align-items: center;
  justify-content: center;
  background: linear-gradient(135deg, var(--color-accent), var(--color-accent-hover));
  color: #fff;
  font-size: 36px;
  font-weight: 800;
  letter-spacing: 3px;
}

.about-name {
  font-family: var(--font-display);
  font-size: 24px;
  font-weight: 800;
  margin-bottom: 2px;
}

.about-role {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 3px;
  color: var(--color-accent);
  font-weight: 700;
  margin-bottom: 14px;
}

.about-tagline {
  font-size: 14px;
  color: var(--color-text-secondary);
  line-height: 1.6;
  max-width: 260px;
  margin-bottom: 18px;
}

.about-divider {
  width: 40px;
  height: 2px;
  background: var(--color-border);
  margin-bottom: 14px;
  border-radius: 1px;
}

.about-credits {
  font-size: 12px;
  color: var(--color-text-secondary);
}

/* ── Best Time Display ──────────────────────── */

#best-time-display {
  font-size: 11px;
  color: var(--color-golden);
  font-weight: 700;
  letter-spacing: 0.5px;
}

#max-level-display {
  font-size: 11px;
  color: var(--color-text-secondary);
  font-weight: 600;
  opacity: 0.7;
  letter-spacing: 0.5px;
}

/* ── Level Up Toast ────────────────────────── */

.level-up-toast {
  position: fixed;
  top: 20%;
  left: 50%;
  transform: translateX(-50%);
  background: linear-gradient(135deg, var(--color-golden), #ff8f00);
  color: #000;
  padding: 18px 36px;
  border-radius: 16px;
  font-family: var(--font-display);
  font-size: 26px;
  font-weight: 800;
  z-index: 200;
  animation: levelUpAnim 2s ease-out forwards;
  pointer-events: none;
  box-shadow: 0 4px 24px rgba(249, 168, 37, 0.5);
  letter-spacing: 2px;
}

@keyframes levelUpAnim {
  0% { opacity: 0; transform: translateX(-50%) scale(0.5); }
  15% { opacity: 1; transform: translateX(-50%) scale(1.2); }
  30% { transform: translateX(-50%) scale(1); }
  80% { opacity: 1; }
  100% { opacity: 0; transform: translateX(-50%) translateY(-30px); }
}

/* ── Level Info Toast ──────────────────────── */

.level-info-toast {
  position: fixed;
  top: 15%;
  left: 50%;
  transform: translateX(-50%);
  background: var(--color-modal-bg);
  color: var(--color-text);
  padding: 14px 28px;
  border-radius: 14px;
  font-size: 16px;
  text-align: center;
  z-index: 200;
  animation: levelInfoAnim 2.5s ease-out forwards;
  pointer-events: none;
  box-shadow: var(--shadow-lg);
  border: 2px solid var(--color-accent);
}

.level-info-details {
  font-size: 12px;
  color: var(--color-text-secondary);
}

@keyframes levelInfoAnim {
  0% { opacity: 0; transform: translateX(-50%) translateY(10px); }
  12% { opacity: 1; transform: translateX(-50%) translateY(0); }
  80% { opacity: 1; }
  100% { opacity: 0; transform: translateX(-50%) translateY(-10px); }
}

/* ── Share Copied Toast ────────────────────── */

.share-copied-toast {
  position: fixed;
  bottom: 20%;
  left: 50%;
  transform: translateX(-50%);
  background: var(--color-win);
  color: #fff;
  padding: 12px 24px;
  border-radius: 12px;
  font-size: 14px;
  font-weight: 700;
  z-index: 300;
  animation: fadeInOut 2s ease forwards;
  pointer-events: none;
  box-shadow: var(--shadow-md);
}

@keyframes fadeInOut {
  0% { opacity: 0; transform: translateX(-50%) translateY(10px); }
  15% { opacity: 1; transform: translateX(-50%) translateY(0); }
  75% { opacity: 1; }
  100% { opacity: 0; }
}

/* ── Chart Empty State ─────────────────────── */

.chart-empty {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  font-size: 12px;
  color: var(--color-text-secondary);
  font-style: italic;
}

/* ── Explosion / Celebration Effects ─────── */

.red-flash {
  position: absolute;
  inset: 0;
  background: radial-gradient(circle, rgba(255, 23, 68, 0.35), rgba(255, 0, 0, 0.15));
  border-radius: 16px;
  z-index: 30;
  pointer-events: none;
  animation: flashFade 0.6s ease-out forwards;
}

.green-flash {
  position: absolute;
  inset: 0;
  background: radial-gradient(circle, rgba(67, 160, 71, 0.25), rgba(0, 200, 83, 0.1));
  border-radius: 16px;
  z-index: 30;
  pointer-events: none;
  animation: flashFade 0.5s ease-out forwards;
}

@keyframes flashFade {
  0% { opacity: 1; }
  100% { opacity: 0; }
}

/* Heavy screen shake for explosions */
.heavy-shaking {
  animation: heavyShake 0.7s ease-out;
}

@keyframes heavyShake {
  0%, 100% { transform: translate(0, 0) rotate(0deg); }
  8% { transform: translate(-8px, -5px) rotate(-1deg); }
  16% { transform: translate(8px, 5px) rotate(1deg); }
  24% { transform: translate(-7px, 6px) rotate(-0.5deg); }
  32% { transform: translate(7px, -6px) rotate(0.5deg); }
  40% { transform: translate(-5px, 4px) rotate(-0.3deg); }
  48% { transform: translate(5px, -4px) rotate(0.3deg); }
  56% { transform: translate(-4px, 3px); }
  64% { transform: translate(4px, -3px); }
  72% { transform: translate(-3px, 2px); }
  80% { transform: translate(2px, -1px); }
  90% { transform: translate(-1px, 0px); }
}

/* Chain mine reveal explosion */
.cell.mine-chain {
  animation: mineChainExplode var(--anim-mine-dur, 0.4s) var(--anim-mine-ease, cubic-bezier(0.34, 1.56, 0.64, 1)) both;
}

@keyframes mineChainExplode {
  0% { transform: scale(0); opacity: 0; }
  40% { transform: scale(1.5); opacity: 1; }
  60% { transform: scale(0.9); }
  100% { transform: scale(1); opacity: 1; }

}

/* ── Flag Pop Animation ────────────────────── */
.cell.flag-pop {
  animation: flagPop var(--anim-flag-dur, 0.35s) var(--anim-flag-ease, cubic-bezier(0.34, 1.56, 0.64, 1));
}

@keyframes flagPop {
  0% { transform: scale(0.3); opacity: 0; }
  50% { transform: scale(1.25); }
  75% { transform: scale(0.9); }
  100% { transform: scale(1); opacity: 1; }
}

.cell.unflag-shrink {
  animation: unflagShrink 0.2s ease-out;
}

@keyframes unflagShrink {
  0% { transform: scale(1); opacity: 1; }
  100% { transform: scale(0.5); opacity: 0; }
}

/* ── Smiley Bounce (win celebration) ──────── */
.smiley-btn.smiley-win-bounce {
  animation: smileyWinBounce 0.8s cubic-bezier(0.34, 1.56, 0.64, 1);
}

@keyframes smileyWinBounce {
  0% { transform: scale(1); }
  15% { transform: scale(1.4) rotate(-10deg); }
  30% { transform: scale(0.85) rotate(5deg); }
  45% { transform: scale(1.2) rotate(-3deg); }
  60% { transform: scale(0.95); }
  75% { transform: scale(1.1); }
  100% { transform: scale(1); }
}

.smiley-btn.smiley-loss-shake {
  animation: smileyLossShake 0.5s ease-out;
}

@keyframes smileyLossShake {
  0%, 100% { transform: rotate(0deg); }
  15% { transform: rotate(-12deg) scale(1.1); }
  30% { transform: rotate(10deg); }
  45% { transform: rotate(-8deg); }
  60% { transform: rotate(6deg); }
  75% { transform: rotate(-3deg); }
}

/* ── LCD Counter Bump ──────────────────────── */
.lcd-display.counter-bump {
  animation: counterBump 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
}

@keyframes counterBump {
  0% { transform: scale(1); }
  50% { transform: scale(1.15); }
  100% { transform: scale(1); }
}

/* ── Number Cell Pop-In ────────────────────── */
.cell.num-pop {
  animation: numPop 0.3s cubic-bezier(0.34, 1.56, 0.64, 1) both;
}

@keyframes numPop {
  0% { transform: scale(0); opacity: 0; }
  60% { transform: scale(1.15); opacity: 1; }
  100% { transform: scale(1); }
}

/* ── Theme Crossfade ──────────────────────── */
#app {
  transition: background 0.4s ease, border-color 0.4s ease, box-shadow 0.4s ease;
}

.game-header {
  transition: background 0.4s ease, border-color 0.4s ease;
}

.lcd-display {
  transition: color 0.3s ease, background 0.3s ease, border-color 0.3s ease,
              transform var(--transition-fast), box-shadow var(--transition-fast);
}

.nav-btn {
  transition: background 0.3s ease, border-color 0.3s ease, color 0.3s ease;
}

/* ── Power-Up Active Glow Pulse ──────────── */
.powerup-btn.active-powerup {
  animation: powerupGlow 1.5s ease-in-out infinite;
}

.powerup-btn.scan-active {
  animation: scanGlow 1.5s ease-in-out infinite;
}

@keyframes powerupGlow {
  0%, 100% { box-shadow: 0 0 8px rgba(67, 160, 71, 0.25); }
  50% { box-shadow: 0 0 16px rgba(67, 160, 71, 0.5), 0 0 4px rgba(67, 160, 71, 0.3); }
}

@keyframes scanGlow {
  0%, 100% { box-shadow: 0 0 8px rgba(249, 168, 37, 0.25); }
  50% { box-shadow: 0 0 16px rgba(249, 168, 37, 0.5), 0 0 4px rgba(249, 168, 37, 0.3); }
}

/* ── New Game Board Cascade ──────────────── */
.cell.cascade-in {
  animation: cascadeIn 0.3s cubic-bezier(0.34, 1.56, 0.64, 1) both;
}

@keyframes cascadeIn {
  0% { transform: scale(0) rotateZ(15deg); opacity: 0; }
  100% { transform: scale(1) rotateZ(0deg); opacity: 1; }
}

/* ── Smiley Press Feedback ───────────────── */
.smiley-btn.smiley-pressed {
  animation: smileyPress 0.15s ease-out;
}

@keyframes smileyPress {
  0% { transform: scale(1); }
  50% { transform: scale(0.8); }
  100% { transform: scale(1); }
}

/* ── Win Title Bounce ─────────────────────── */
.gameover-content h2.win-title-bounce {
  animation: winTitleBounce 0.7s cubic-bezier(0.34, 1.56, 0.64, 1);
}

@keyframes winTitleBounce {
  0% { transform: translateY(-30px) scale(0.5); opacity: 0; }
  40% { transform: translateY(5px) scale(1.15); opacity: 1; }
  60% { transform: translateY(-3px) scale(0.95); }
  80% { transform: translateY(1px) scale(1.02); }
  100% { transform: translateY(0) scale(1); }
}

/* ── Stats Cascade ───────────────────────── */
.gameover-content p.stats-cascade {
  animation: statsCascade 0.4s ease-out both;
}

@keyframes statsCascade {
  0% { transform: translateX(30px); opacity: 0; }
  100% { transform: translateX(0); opacity: 1; }
}

/* ── Timer Tick Pulse ────────────────────── */
.lcd-display.timer-tick {
  animation: timerTick 0.3s ease-out;
}

@keyframes timerTick {
  0% { transform: scale(1); }
  30% { transform: scale(1.06); }
  100% { transform: scale(1); }
}

/* ── Power-Up Earned Bounce ──────────────── */
.powerup-btn.powerup-earned {
  animation: powerupEarned 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
}

@keyframes powerupEarned {
  0% { transform: scale(1); box-shadow: 0 0 0 0 var(--color-accent-glow); }
  30% { transform: scale(1.3); box-shadow: 0 0 16px 6px var(--color-accent-glow); }
  60% { transform: scale(0.9); }
  100% { transform: scale(1); box-shadow: none; }
}

/* ── Daily Streak Shake ──────────────────── */
.streak-shake {
  animation: streakShake 0.5s ease-out;
}

@keyframes streakShake {
  0%, 100% { transform: translateX(0); }
  10% { transform: translateX(-4px) rotate(-2deg); }
  20% { transform: translateX(4px) rotate(2deg); }
  30% { transform: translateX(-3px) rotate(-1deg); }
  40% { transform: translateX(3px) rotate(1deg); }
  50% { transform: translateX(-2px); }
  60% { transform: translateX(2px); }
  70% { transform: translateX(-1px); }
}

/* ── Chord Ripple ────────────────────────── */
.cell.chord-ripple {
  animation: chordRipple 0.35s cubic-bezier(0.34, 1.56, 0.64, 1) both;
}

@keyframes chordRipple {
  0% { transform: scale(0.8); opacity: 0.5; box-shadow: 0 0 0 0 var(--color-accent-glow); }
  50% { transform: scale(1.1); opacity: 1; box-shadow: 0 0 8px 2px var(--color-accent-glow); }
  100% { transform: scale(1); opacity: 1; box-shadow: none; }
}

/* ── Number Glow ─────────────────────────── */
.cell.number-glow {
  animation: numberGlow 0.8s ease-out both;
}

@keyframes numberGlow {
  0% { text-shadow: none; }
  40% { text-shadow: 0 0 8px currentColor, 0 0 16px currentColor; }
  100% { text-shadow: none; }
}

.hidden {
  display: none !important;
}

/* ── Responsive ─────────────────────────────── */

@media (max-width: 480px) {
  :root {
    --cell-size: 28px;
  }

  #app {
    padding: 12px 10px 10px;
    border-radius: 12px;
    gap: 6px;
  }

  /* In-game, on a phone, every row above the board is rent. The
     wordmark block is the one purely decorative tenant: the title
     screen owns the brand, the Certified chip carries the contract,
     and About is reachable from Settings. Desktop keeps the wordmark
     (and its tap-for-About) — space is free there. */
  #app #title-bar {
    display: none;
  }

  #game-header {
    padding: 6px 10px;
  }

  #game-info-bar {
    padding: 2px 12px;
  }

  .header-icon-btn {
    width: 36px;
    height: 36px;
    font-size: 15px;
  }

  .active-gimmick-bar {
    margin: 2px auto;
    padding: 3px 10px;
  }

  #game-title {
    font-size: 20px;
  }

  .lcd-display {
    font-size: 20px;
    min-width: 50px;
    padding: 4px 8px;
  }

  .smiley-btn {
    font-size: 26px;
    width: 42px;
    height: 42px;
  }

  #powerup-bar {
    gap: 4px;
  }

  .powerup-btn {
    padding: 5px 7px;
    font-size: 11px;
    gap: 3px;
  }

  .powerup-icon {
    font-size: 14px;
  }

  .modal-content {
    padding: 20px;
    border-radius: 16px;
  }

  .nav-btn {
    width: 38px;
    height: 38px;
    font-size: 18px;
  }

  /* Seven buttons when the zoom pair is visible (Expert/Extreme Quick
     Play) must fit a 360px row without wrapping. */
  #bottom-nav {
    gap: 8px;
  }

  .timed-size-tabs {
    gap: 4px;
  }

  .timed-tab {
    padding: 8px 10px;
    font-size: 11px;
    min-height: 38px;
  }
}

@media (min-width: 481px) and (max-width: 768px) {
  :root {
    --cell-size: 34px;
  }
}

/* ── Progress Bar ───────────────────────────────────── */
#progress-bar-container {
  width: 100%;
  height: 6px;
  background: var(--color-surface, rgba(0,0,0,0.1));
  border-radius: 3px;
  position: relative;
  overflow: hidden;
}
#progress-bar-fill {
  height: 100%;
  background: linear-gradient(90deg, var(--color-accent), var(--color-accent-hover, #d63851));
  border-radius: 3px;
  transition: width 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
  width: 0%;
}
#progress-bar-markers {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}
.checkpoint-marker {
  position: absolute;
  top: -2px;
  width: 2px;
  height: 10px;
  background: var(--color-text-secondary, #888);
  border-radius: 1px;
  opacity: 0.6;
}
.checkpoint-marker.reached {
  background: var(--color-accent);
  opacity: 1;
}

/* ── Checkpoint Display ─────────────────────────────── */
#checkpoint-display {
  font-size: 10px;
  color: var(--color-text-secondary);
  letter-spacing: 0.5px;
}

/* ── Cells Remaining ────────────────────────────────── */
#cells-remaining {
  font-size: 10px;
  color: var(--color-text-secondary);
  opacity: 0.7;
  letter-spacing: 0.5px;
}

/* ── Daily Streak Display ───────────────────────────── */
#streak-display {
  font-size: 11px;
  font-weight: 600;
  color: var(--color-accent);
}

/* ── Header icon buttons (flag toggle + Stuck?) ─────────
   They flank the smiley in the LCD row. The Stuck? button is quieter
   than the toggle (the toggle is the every-few-seconds control;
   Stuck? is the once-in-a-while ask), distinguished by tone. */
.header-icon-btn {
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 2px solid var(--color-border);
  background: var(--color-btn-gradient);
  border-radius: 12px;
  cursor: pointer;
  font-size: 17px;
  color: var(--color-text);
  transition: all 0.2s;
  flex-shrink: 0;
}
.header-icon-btn:hover {
  border-color: var(--color-accent);
}
.header-icon-btn.flag-active {
  border-color: #e53935;
  background: linear-gradient(135deg, rgba(229,57,53,0.15), rgba(229,57,53,0.05));
  box-shadow: 0 0 8px rgba(229,57,53,0.2);
}
.stuck-btn {
  opacity: 0.85;
}
.stuck-btn:active {
  transform: scale(0.97);
}
#flag-mode-icon {
  font-size: 17px;
}

/* ── Mode Pill Sizing ───────────────────────────────── */
.mode-pill {
  font-size: 16px;
  width: 36px;
  height: 30px;
}

/* ── Timer Urgency ──────────────────────────────────── */
.timer-warning {
  color: var(--timer-warning, #ff9800) !important;
  text-shadow: 0 0 4px rgba(255, 152, 0, 0.4);
}
.timer-critical {
  color: var(--timer-critical, #f44336) !important;
  text-shadow: 0 0 6px rgba(244, 67, 54, 0.5);
  animation: timer-pulse 0.5s ease-in-out infinite;
}
@keyframes timer-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.6; }
}

/* ── Toast Queue Container ──────────────────────────── */
.toast-container {
  position: fixed;
  top: 12px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  gap: 8px;
  z-index: 9999;
  pointer-events: none;
}
.queued-toast {
  background: var(--color-bg, #fff);
  color: var(--color-text, #333);
  padding: 10px 18px;
  border-radius: 10px;
  box-shadow: 0 4px 16px rgba(0,0,0,0.2);
  font-size: 13px;
  font-weight: 600;
  pointer-events: auto;
  animation: toast-slide-in 0.3s ease-out;
  white-space: nowrap;
}
.queued-toast.toast-exit {
  animation: toast-slide-out 0.25s ease-in forwards;
}
@keyframes toast-slide-in {
  from { opacity: 0; transform: translateY(-20px); }
  to { opacity: 1; transform: translateY(0); }
}
@keyframes toast-slide-out {
  from { opacity: 1; transform: translateY(0); }
  to { opacity: 0; transform: translateY(-20px); }
}

/* ── Checkpoint Selector ────────────────────────────── */
.checkpoint-modal-content {
  max-width: 480px;
}

.checkpoint-resume {
  margin-bottom: 16px;
}

.checkpoint-resume-btn {
  width: 100%;
  padding: 14px 18px;
  border: 2px solid var(--color-accent);
  background: var(--color-accent);
  color: #fff;
  border-radius: 12px;
  font-size: 15px;
  font-weight: 700;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 10px;
  transition: all 0.2s;
  box-shadow: 0 2px 8px var(--color-accent-glow);
}
.checkpoint-resume-btn:hover {
  transform: translateY(-1px);
  box-shadow: 0 4px 16px var(--color-accent-glow);
}
.checkpoint-resume-btn:active { transform: translateY(0); }

.checkpoint-resume-btn .resume-icon { font-size: 20px; }
.checkpoint-resume-btn .resume-label { flex: 1; text-align: left; }
.checkpoint-resume-btn .resume-level {
  font-size: 12px;
  opacity: 0.85;
  font-weight: 400;
}

.checkpoint-list {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 6px;
}

.checkpoint-btn {
  padding: 8px 6px;
  border: 2px solid var(--color-border);
  background: var(--color-surface);
  color: var(--color-text);
  border-radius: 8px;
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1px;
  transition: all 0.2s;
  min-height: 38px;
}
.checkpoint-btn:hover:not(.checkpoint-locked) {
  border-color: var(--color-accent);
  transform: translateY(-1px);
  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.checkpoint-btn:active:not(.checkpoint-locked) { transform: translateY(0); }

.checkpoint-btn .cp-level { font-size: 12px; font-weight: 700; }
.checkpoint-btn .cp-modifier {
  font-size: 10px;
  color: var(--color-text-secondary);
  display: flex;
  align-items: center;
  gap: 2px;
}
.checkpoint-btn .cp-modifier-icon { font-size: 12px; }

.checkpoint-locked {
  opacity: 0.4;
  cursor: not-allowed;
}
.checkpoint-locked .cp-modifier {
  font-style: italic;
}

/* ── Chaos Mode UI ────────────────────────────────── */
.mode-card-chaos {
  position: relative;
  animation: chaos-glitch 3s infinite;
}
.mode-card-chaos .mode-card-name {
  animation: chaos-text-glitch 3s infinite;
  display: inline-block;
}
@keyframes chaos-glitch {
  0%, 90%, 100% { transform: none; }
  91% { transform: translate(-2px, 1px) skewX(-1deg); }
  92% { transform: translate(2px, -1px) skewX(1deg); }
  93% { transform: translate(-1px, 0) skewX(0); }
  94% { transform: none; }
}
@keyframes chaos-text-glitch {
  0%, 90%, 95%, 100% { transform: none; letter-spacing: normal; font-style: normal; }
  91% { transform: skewX(-4deg); letter-spacing: 2px; }
  92% { transform: skewX(3deg) translateX(1px); letter-spacing: -1px; font-style: italic; }
  93% { transform: skewX(-2deg) translateX(-1px); letter-spacing: 1px; }
  94% { transform: none; font-style: italic; }
}

.chaos-modifier-bar {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 6px 12px;
  margin: 4px auto;
  background: linear-gradient(90deg, rgba(150,0,255,0.12), rgba(255,0,85,0.12));
  border-radius: 8px;
  border: 1px solid rgba(150,0,255,0.2);
  max-width: fit-content;
}

.chaos-round-label {
  font-weight: 700;
  font-size: 14px;
  color: var(--color-text, #e0d8f0);
  letter-spacing: 0.5px;
  text-transform: uppercase;
}

.chaos-modifier-icons {
  display: flex;
  gap: 4px;
  font-size: 18px;
}

.chaos-mod-icon {
  display: inline-block;
  transition: transform 0.2s;
}
.chaos-mod-icon:hover {
  transform: scale(1.3);
}

/* Persistent active-gimmick bar for daily / weekly / challenge.
   Theme-neutral so it doesn't fight the chaos bar's purple/red palette. */
.active-gimmick-bar {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 4px 12px;
  margin: 4px auto;
  background: var(--color-cell-revealed, rgba(255,255,255,0.06));
  border-radius: 8px;
  border: 1px solid var(--color-cell-border, rgba(0,0,0,0.15));
  max-width: fit-content;
  font-size: 13px;
}
.active-gimmick-label {
  font-weight: 600;
  color: var(--color-text, #333);
  letter-spacing: 0.3px;
  text-transform: uppercase;
  font-size: 11px;
  opacity: 0.8;
}
.active-gimmick-icons {
  display: flex;
  gap: 6px;
  font-size: 18px;
}
.active-gimmick-icon {
  display: inline-block;
  cursor: help;
  transition: transform 0.15s;
}
.active-gimmick-icon:hover, .active-gimmick-icon:active {
  transform: scale(1.25);
}
/* The no-guess certificate chip (and its Chaos inverse). A real button
   so keyboard and screen-reader users get activation for free; styled
   as a quiet pill that invites a tap without shouting. */
.cert-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 9px;
  border-radius: 999px;
  border: 1px solid rgba(76, 175, 80, 0.55);
  background: rgba(76, 175, 80, 0.14);
  color: var(--color-text, #333);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.3px;
  line-height: 1.6;
  cursor: pointer;
  font-family: inherit;
}
.cert-chip:hover, .cert-chip:focus-visible { filter: brightness(1.12); }
.cert-chip-none {
  border-color: var(--timer-warning, #ff9800);
  background: rgba(255, 152, 0, 0.12);
}
.cert-modal-content { max-width: 420px; }
.cert-recheck { font-size: 0.85em; opacity: 0.75; }

.chaos-run-summary {
  display: flex;
  gap: 16px;
  justify-content: center;
  padding: 10px 0;
  margin: 8px 0;
  border-top: 1px solid rgba(150,0,255,0.2);
  border-bottom: 1px solid rgba(150,0,255,0.2);
}

.chaos-summary-stat {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
}

.chaos-stat-label {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  opacity: 0.7;
}

.chaos-stat-value {
  font-size: 22px;
  font-weight: 700;
  color: var(--color-accent, #ff0055);
}

/* ── Modal Exit Animation ───────────────────────────── */
.modal.modal-closing .modal-content {
  animation: modal-slide-down 0.25s ease-in forwards;
}
@keyframes modal-slide-down {
  from { opacity: 1; transform: translateY(0); }
  to { opacity: 0; transform: translateY(30px); }
}

/* ── Focus Trapping / Keyboard Nav ──────────────────── */
.cell:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: -1px;
  z-index: 3;
}
.modal-content:focus-visible {
  outline: none;
}
.cell.keyboard-cursor {
  outline: 2px solid var(--color-accent);
  outline-offset: -1px;
  z-index: 3;
}

/* ── Encouragement Line ─────────────────────────────── */
.gameover-encouragement {
  font-size: 13px;
  color: var(--color-text-secondary);
  font-style: italic;
  margin: 4px 0 0;
}

/* ── Share Card Preview ─────────────────────────────── */
.share-card-preview {
  margin: 12px auto;
  display: block;
  text-align: center;
}
/* Wave D: the rendered share-card PNG shown in the win modal. */
.share-card-img {
  display: block;
  width: 100%;
  max-width: 300px;
  margin: 0 auto;
  border-radius: 12px;
  box-shadow: 0 3px 14px rgba(0, 0, 0, 0.28);
}
.share-card-grid {
  display: grid;
  gap: 2px;
  justify-content: center;
}
.share-card-cell {
  width: 10px;
  height: 10px;
  border-radius: 2px;
}
.share-card-cell.safe { background: #4caf50; }
.share-card-cell.mine { background: #f44336; }
.share-card-cell.empty { background: var(--color-border, #ccc); }

/* ── Daily Submit Form ──────────────────────────────── */
.daily-submit-form {
  display: flex;
  gap: 8px;
  align-items: center;
  justify-content: center;
  margin-top: 8px;
}
.daily-name-input {
  padding: 8px 12px;
  border: 2px solid var(--color-border);
  border-radius: 8px;
  background: var(--color-surface, rgba(0,0,0,0.05));
  color: var(--color-text);
  font-size: 14px;
  font-family: inherit;
  width: 160px;
  outline: none;
  transition: border-color 0.2s;
}
.daily-name-input:focus {
  border-color: var(--color-accent);
}
.daily-name-input::placeholder {
  color: var(--color-text-secondary);
  opacity: 0.6;
}

/* ── Onboarding ─────────────────────────────────────── */
.onboarding-content {
  text-align: center;
  max-width: 320px;
}
.onboarding-content h2 {
  font-size: 20px;
  margin-bottom: 12px;
}
.onboarding-content p {
  font-size: 14px;
  line-height: 1.6;
  margin: 6px 0;
  color: var(--color-text-secondary);
}
.onboarding-actions {
  margin-top: 16px;
}

/* ── Checkpoint Toast ───────────────────────────────── */
.checkpoint-toast {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background: var(--color-bg);
  color: var(--color-text);
  padding: 16px 28px;
  border-radius: 12px;
  box-shadow: 0 8px 32px rgba(0,0,0,0.3);
  font-size: 16px;
  font-weight: 700;
  z-index: 10000;
  animation: checkpoint-pop 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
  text-align: center;
}
@keyframes checkpoint-pop {
  from { opacity: 0; transform: translate(-50%, -50%) scale(0.7); }
  to { opacity: 1; transform: translate(-50%, -50%) scale(1); }
}

/* ── Power-up Choice Modal ──────────────────────────── */
.powerup-choice-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
  margin: 12px 0;
}
.powerup-choice-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 12px 8px;
  border: 2px solid var(--color-border);
  border-radius: 10px;
  background: var(--color-btn-gradient);
  cursor: pointer;
  transition: all 0.2s;
  color: var(--color-text);
}
.powerup-choice-btn:hover {
  border-color: var(--color-accent);
  transform: scale(1.05);
}
.powerup-choice-icon { font-size: 24px; }
.powerup-choice-name { font-size: 11px; font-weight: 600; }

/* ── Title Screen ──────────────────────────────────── */

.title-screen {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: linear-gradient(135deg, var(--color-bg, #1a1a2e), var(--color-app-bg, #0f0f23));
  padding: 20px;
  gap: 32px;
}
.title-screen.hidden { display: none; }

.title-screen-header {
  text-align: center;
}
.title-screen-logo {
  font-family: var(--font-display, 'Orbitron'), sans-serif;
  font-size: clamp(28px, 8vw, 48px);
  font-weight: 900;
  background: linear-gradient(135deg, var(--wordmark-from), var(--wordmark-to));
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
  letter-spacing: 2px;
}
.title-screen-subtitle {
  font-size: 14px;
  color: var(--color-text-secondary, #888);
  margin-top: 4px;
  letter-spacing: 3px;
  text-transform: uppercase;
}
/* The proof line: substantiates the headline claim directly under it. */
.title-screen-proof {
  font-size: 13px;
  color: var(--color-text-secondary, #888);
  margin-top: 6px;
  max-width: 34ch;
  margin-left: auto;
  margin-right: auto;
  line-height: 1.4;
}
.title-screen-modes {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 12px;
  width: 100%;
  max-width: 360px;
}

.mode-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 20px 12px;
  border-radius: 14px;
  background: var(--color-cell-hidden, #2a2a4a);
  border: 2px solid var(--color-border, #333);
  cursor: pointer;
  transition: all 0.2s;
  /* Reset native <button> appearance — mode-cards are buttons now so keyboard
     users can tab through them and Enter/Space starts a mode. */
  font: inherit;
  color: inherit;
  text-align: center;
  -webkit-appearance: none;
  appearance: none;
}
@media (hover: hover) and (pointer: fine) {
  .mode-card:hover {
    border-color: var(--color-accent, #e94560);
    transform: scale(1.03);
    box-shadow: 0 4px 20px rgba(0,0,0,0.3);
  }
}
.mode-card:active {
  border-color: var(--color-accent, #e94560);
  transform: scale(1.03);
  box-shadow: 0 4px 20px rgba(0,0,0,0.3);
}

/* Global focus-visible rule — keyboard users now get a clear focus ring on
   every button, including mode-cards, footer buttons, modal close X,
   power-up buttons, tab buttons, smiley, zoom. One rule replaces ~12
   per-selector definitions that didn't exist. */
button:focus-visible {
  outline: 3px solid var(--color-accent, #5c6bc0);
  outline-offset: 2px;
  border-radius: 6px;
}

/* One-time pulsing glow on the Daily card immediately after the tutorial,
   so first-time users see where to go next. Class is added by
   spotlightDailyCard() in main.js and auto-removed after ~5s or on first
   click. Animation runs three times for a total of ~4.5s of attention. */
.mode-card.spotlight {
  animation: dailyCardSpotlight 1.5s ease-in-out 0s 3;
  position: relative;
}
@keyframes dailyCardSpotlight {
  0%, 100% {
    box-shadow: 0 0 0 0 rgba(92, 107, 192, 0.7), 0 4px 20px rgba(0, 0, 0, 0.3);
    transform: scale(1);
  }
  50% {
    box-shadow: 0 0 0 14px rgba(92, 107, 192, 0), 0 4px 20px rgba(0, 0, 0, 0.3);
    transform: scale(1.04);
  }
}
.mode-card-icon { font-size: 32px; }

/* ── Title-screen background occlusion (generic, theme-agnostic) ────────────
   When a theme's ambient effect plays behind the title cards, themeEffects.js
   adds .has-title-sky to #title-screen. The cards must then be SOLID so the
   effect drifts only in the open background and cleanly vanishes behind them.
   Each theme's --title-card-solid sets the panel color (falls back to its
   opaque button bg); content lifts above the z-index-0 background layer. */
#title-screen.has-title-sky { position: relative; }
#title-screen.has-title-sky > *:not(.theme-fx-titlescene) { position: relative; z-index: 1; }
#title-screen.has-title-sky .mode-card,
#title-screen.has-title-sky .title-footer-btn {
  background: var(--title-card-solid, var(--color-btn-bg));
}
#title-screen.has-title-sky .mode-card:hover,
#title-screen.has-title-sky .title-footer-btn:hover {
  background: var(--title-card-solid-hover, var(--color-btn-hover));
}
.mode-card-name {
  font-weight: 700;
  font-size: 14px;
  color: var(--color-text, #eee);
}
.mode-card-progress {
  font-size: 11px;
  color: var(--color-text-secondary, #888);
}
/* Par sits on its own line beneath the Daily card's descriptor. */
.mode-card-par {
  display: block;
  margin-top: 2px;
  opacity: 0.8;
  font-variant-numeric: tabular-nums;
}

/* Greg's Field Note — now the daily card's single center descriptor (why
   today's board exists, in one true sentence). Italic keeps it Greg's voice;
   sized to read as the primary line, not a secondary afterthought. */
.mode-card-fieldnote {
  display: block;
  font-size: 1em;
  font-style: italic;
  opacity: 0.8;
  line-height: 1.3;
}

/* ── Past Dailies calendar ─────────────────────────────── */
/* The Daily card is the positioning context for its four corner stats, and
   reserves a bottom band so the absolute streak/par clear Greg's note. The
   padding-bottom outranks the responsive `.mode-card` shorthand by specificity,
   so the band survives every breakpoint. */
.mode-card[data-mode="daily"] { position: relative; padding-bottom: 24px; }
/* ── Daily card: corner-anchored stats ──────────────────────────────────
   Four corners frame Greg's note: molt tokens top-left, Past chip top-right,
   streak bottom-left, par bottom-right. The streak + par are plain text in
   Greg's note color (NOT pills, NOT italic), so the Past chip stays the one
   pill that pops. */
.daily-corner-molt {
  position: absolute;
  top: 6px;
  left: 7px;
  font-size: 0.78rem;
  line-height: 1;
  letter-spacing: -2px;
  cursor: default;
}
.daily-corner-stat {
  position: absolute;
  bottom: 7px;
  font-size: 0.72rem;
  color: var(--color-text-secondary, #7a6e5d);
  opacity: 0.85;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.daily-corner-streak { left: 11px; }
.daily-corner-par { right: 11px; }
/* The crab dropping into the card corner when a molt day is earned (replayed
   when the earned popup is dismissed). Same drop used for the popup crab. */
@keyframes moltPlace {
  0%   { transform: translateY(-14px) scale(0.55); opacity: 0; }
  60%  { transform: translateY(1px) scale(1.1); opacity: 1; }
  100% { transform: translateY(0) scale(1); opacity: 1; }
}
.daily-corner-molt.molt-placing {
  animation: moltPlace 0.5s cubic-bezier(0.22, 1, 0.36, 1) both;
}
/* Earned-molt-day popup: a big crab that drops in, and a primary action. */
.molt-earned-crab {
  font-size: 56px;
  line-height: 1;
  margin: 6px auto 12px;
  animation: moltPlace 0.5s cubic-bezier(0.22, 1, 0.36, 1) both;
}
.molt-earned-done {
  margin-top: 14px;
  padding: 9px 24px;
  font: inherit;
  font-weight: 600;
  color: #fff;
  background: var(--color-accent, #5c6bc0);
  border: none;
  border-radius: 999px;
  cursor: pointer;
}
.molt-earned-done:hover { filter: brightness(1.05); }
/* "Past dailies" affordance: a small chip in the card corner, OUT of the
   content stack so it never adds a row. The card is a <button>, so this is a
   role=button span; a capture-phase handler routes its taps to the calendar
   instead of launching today's board. */
.card-archive-btn {
  position: absolute;
  top: 6px;
  right: 6px;
  padding: 2px 7px;
  font-size: 0.7rem;
  font-weight: 600;
  line-height: 1.3;
  color: var(--color-accent, #4a90d9);
  background: color-mix(in srgb, var(--color-accent, #4a90d9) 12%, transparent);
  border-radius: 999px;
  cursor: pointer;
  opacity: 0.9;
  white-space: nowrap;
}
.card-archive-btn:hover { opacity: 1; filter: brightness(1.05); }
.card-archive-btn:focus-visible {
  outline: 2px solid var(--color-accent, #4a90d9);
  outline-offset: 2px;
}

.archive-modal-content { max-width: 440px; }
.archive-intro {
  font-size: 0.82rem;
  opacity: 0.8;
  line-height: 1.4;
  margin: 0 0 14px;
}
.archive-nav {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  margin-bottom: 10px;
}
.archive-nav-btn {
  background: var(--color-cell-hidden, #cfd8e3);
  color: var(--color-text, #222);
  border: none;
  border-radius: 8px;
  width: 36px;
  height: 36px;
  font-size: 1.25rem;
  line-height: 1;
  cursor: pointer;
}
.archive-nav-btn:disabled { opacity: 0.3; cursor: default; }
.archive-month-label {
  font-weight: 700;
  font-size: 0.98rem;
  min-width: 150px;
  text-align: center;
  font-variant-numeric: tabular-nums;
}
.archive-weekdays,
.archive-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 5px;
}
.archive-weekdays { margin-bottom: 5px; }
.archive-weekdays span {
  text-align: center;
  font-size: 0.7rem;
  font-weight: 700;
  opacity: 0.5;
}
.archive-day {
  aspect-ratio: 1 / 1;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  font-size: 0.85rem;
  border: none;
  border-radius: 8px;
  background: transparent;
  color: var(--color-text, #222);
  font-variant-numeric: tabular-nums;
}
.archive-day.empty { visibility: hidden; }
.archive-day.blocked { opacity: 0.22; }
.archive-day.today {
  opacity: 0.55;
  font-weight: 700;
  outline: 1px dashed var(--color-accent, #4a90d9);
}
.archive-day.playable {
  background: var(--color-cell-hidden, #cfd8e3);
  cursor: pointer;
  font-weight: 600;
  transition: transform 0.08s ease, filter 0.08s ease;
}
.archive-day.playable:hover { filter: brightness(1.08); transform: translateY(-1px); }
.archive-day.playable:focus-visible {
  outline: 2px solid var(--color-accent, #4a90d9);
  outline-offset: 1px;
}
.archive-day.completed {
  background: var(--color-accent, #4a90d9);
  color: #fff;
}
.archive-day.loading { opacity: 0.6; cursor: progress; }
.archive-check {
  position: absolute;
  top: 2px;
  right: 4px;
  font-size: 0.58rem;
  line-height: 1;
}
.archive-empty-note {
  text-align: center;
  opacity: 0.6;
  font-size: 0.8rem;
  margin-top: 12px;
}
/* In-app entry to the crux teaser, below the calendar. */
.archive-crux-btn {
  display: block;
  margin: 16px auto 0;
  padding: 8px 14px;
  background: none;
  border: 1px solid var(--color-border, #555);
  border-radius: 8px;
  color: var(--color-text, #eee);
  font-size: 0.85rem;
  cursor: pointer;
}
.archive-crux-btn:hover { background: var(--color-cell-hidden, #555); }

/* Greg's yesterday note in the leaderboard modal — the closed loop of
   the daily experiment, rendered once per session. */
.greg-yesterday-note {
  font-size: 0.85em;
  font-style: italic;
  color: var(--color-text-secondary, #999);
  margin: 4px 0 8px;
}

.mode-card.daily-completed {
  opacity: 0.6;
  position: relative;
}
.mode-card.daily-completed .mode-card-progress {
  color: var(--color-accent, #4caf50);
}

.title-screen-footer {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
}
.title-footer-btn {
  padding: 10px 20px;
  border-radius: 8px;
  border: 1px solid var(--color-border, #333);
  background: transparent;
  color: var(--color-text-secondary, #888);
  font-size: 13px;
  cursor: pointer;
  transition: all 0.2s;
}
.title-footer-btn:hover {
  border-color: var(--color-accent, #e94560);
  color: var(--color-text, #eee);
}

/* What's New badge */
.title-footer-btn { position: relative; }
.whatsnew-badge {
  position: absolute;
  top: -6px;
  right: -6px;
  background: #e94560;
  color: #fff;
  font-size: 9px;
  font-weight: 700;
  padding: 2px 5px;
  border-radius: 8px;
  line-height: 1;
  pointer-events: none;
}

/* ── Title-screen sheets (Progress / More) ──────────────
   Small action sheets behind the grouped footer: a short list of
   rows, each opening an existing modal. */
.sheet-content {
  max-width: 300px;
}
.sheet-rows {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.sheet-row {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 13px 16px;
  border: 1px solid var(--color-border, #333);
  border-radius: 10px;
  background: var(--color-btn-gradient);
  color: var(--color-text, #eee);
  font-size: 15px;
  cursor: pointer;
  transition: all 0.2s;
  text-align: left;
}
.sheet-row:hover {
  border-color: var(--color-accent, #e94560);
}
/* On a sheet row the NEW badge sits inline at the row's end, not
   floated off a corner. */
.sheet-row .whatsnew-badge {
  position: static;
  margin-left: auto;
}
/* News dot on the More button: the What's New badge lives behind the
   sheet now, so the button itself has to carry the signal. */
.more-dot {
  position: absolute;
  top: -3px;
  right: -3px;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: #e94560;
  pointer-events: none;
}

/* An odd card count (chaos hidden until L50) leaves an orphan cell in
   the 2-column grid; let the last card span the row instead. */
.title-screen-modes .mode-card:last-child:nth-child(odd) {
  grid-column: 1 / -1;
}

/* What's New modal body */
.whatsnew-body h3 {
  margin: 0 0 8px;
  font-size: 15px;
  color: var(--color-accent, #e94560);
}
.whatsnew-body ul {
  margin: 0 0 16px;
  padding-left: 20px;
}
.whatsnew-body li {
  margin-bottom: 6px;
  font-size: 13px;
  line-height: 1.4;
  color: var(--color-text, #eee);
}
.whatsnew-body li strong {
  color: var(--color-text, #fff);
}

/* Player name input in settings */
.player-name-input {
  display: block;
  width: 100%;
  margin-top: 6px;
  padding: 8px 12px;
  border: 2px solid var(--color-border);
  border-radius: 8px;
  background: var(--color-surface, #1a1a2e);
  color: var(--color-text, #eee);
  font-size: 14px;
  box-sizing: border-box;
}
.player-name-input:focus {
  border-color: var(--color-accent);
  outline: none;
}
.setting-label {
  display: block;
  font-size: 14px;
  color: var(--color-text, #eee);
}

/* ── Timed Size Tabs ───────────────────────────────── */

.timed-size-tabs {
  display: flex;
  justify-content: center;
  gap: 6px;
  padding: 8px 0;
}
.timed-size-tabs.hidden { display: none; }

.timed-tab {
  padding: 10px 16px;
  min-height: 44px;
  border-radius: 20px;
  border: 2px solid var(--color-border, #333);
  background: transparent;
  color: var(--color-text-secondary, #888);
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.2s;
}
.timed-tab.active {
  border-color: var(--color-accent, #e94560);
  color: var(--color-text, #eee);
  background: var(--color-cell-hidden, #2a2a4a);
  box-shadow: 0 0 8px var(--color-accent-glow, rgba(233,69,96,0.3));
}
.timed-tab:hover:not(.active) {
  border-color: var(--color-text-secondary, #666);
}

/* ── Skill Trainer ─────────────────────────────────── */

.skill-trainer-container {
  width: 100%;
  max-width: 500px;
  margin: 0 auto;
  padding: 12px;
}
.skill-trainer-container.hidden { display: none; }

.skill-categories {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.skill-category-cards {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.skill-category-card {
  display: flex;
  align-items: center;
  gap: 16px;
  width: 100%;
  padding: 18px 16px;
  border-radius: 12px;
  border: 1px solid var(--color-border, #333);
  background: var(--color-cell-hidden, #2a2a4a);
  color: var(--color-text, #eee);
  cursor: pointer;
  transition: all 0.2s;
  text-align: left;
}
.skill-category-card:hover, .skill-category-card:active {
  border-color: var(--color-accent, #e94560);
  background: var(--color-cell-hover, rgba(255,255,255,0.05));
}
.skill-category-card.all-complete {
  border-color: #4caf50;
}
.skill-category-card-icon {
  font-size: 28px;
  flex-shrink: 0;
}
.skill-category-card-info {
  flex: 1;
}
.skill-category-card-name {
  font-size: 16px;
  font-weight: 700;
}
.skill-category-card-progress {
  font-size: 12px;
  color: var(--color-text-secondary, #888);
  margin-top: 2px;
}
.skill-category-card-arrow {
  font-size: 24px;
  color: var(--color-text-secondary, #888);
  flex-shrink: 0;
}

.skill-lesson-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.skill-lesson-card {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 10px;
  border: none;
  background: transparent;
  color: var(--color-text, #eee);
  cursor: pointer;
  border-radius: 8px;
  transition: background 0.15s;
  text-align: left;
}
.skill-lesson-card:hover {
  background: var(--color-cell-hover, rgba(255,255,255,0.05));
}
.skill-lesson-card.completed {
  opacity: 0.85;
}
.skill-lesson-card.coming-soon {
  opacity: 0.45;
  cursor: default;
  pointer-events: none;
}
.coming-soon-label {
  color: var(--color-text-secondary, #888);
  font-style: italic;
  font-size: 11px;
}

.skill-lesson-info {
  flex: 1;
}
.skill-lesson-name {
  font-weight: 600;
  font-size: 13px;
}
.skill-lesson-desc {
  font-size: 11px;
  color: var(--color-text-secondary, #888);
  margin-top: 2px;
}
.skill-lesson-stars {
  font-size: 14px;
  white-space: nowrap;
}

.skill-back-btn {
  background: none;
  border: none;
  color: var(--color-text-secondary, #888);
  cursor: pointer;
  font-size: 13px;
  padding: 6px 0;
  margin-bottom: 8px;
}
.skill-back-btn:hover { color: var(--color-text, #eee); }

.skill-lesson-header {
  margin-bottom: 12px;
}
.skill-lesson-header h3 {
  font-size: 16px;
  color: var(--color-text, #eee);
}
.skill-explanation {
  font-size: 13px;
  color: var(--color-text-secondary, #aaa);
  margin-top: 4px;
  line-height: 1.4;
}

.skill-progress-dots {
  display: flex;
  justify-content: center;
  gap: 6px;
  margin: 8px 0;
}
.skill-progress-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--color-border, #333);
  transition: background 0.2s;
}
.skill-progress-dot.completed {
  background: var(--color-accent, #e94560);
}
.skill-progress-dot.active {
  background: var(--color-text, #eee);
  box-shadow: 0 0 6px var(--color-text, #eee);
}

.skill-progress-label {
  text-align: center;
  font-size: 11px;
  color: var(--color-text-secondary, #888);
  margin-bottom: 8px;
}

.skill-puzzle-board {
  display: grid;
  gap: 2px;
  margin: 0 auto;
  max-width: 300px;
}

.skill-cell {
  width: 100%;
  aspect-ratio: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 4px;
  font-size: 16px;
  font-weight: 700;
  cursor: pointer;
  user-select: none;
  transition: transform 0.1s;
}
.skill-cell:active { transform: scale(0.92); }
.skill-cell.unrevealed {
  background: var(--color-cell-hidden, #2a2a4a);
  border: 1px solid var(--color-border, #444);
}
.skill-cell.revealed {
  background: var(--color-cell-revealed, #3a3a5a);
  border: 1px solid transparent;
}
.skill-cell.flagged {
  background: var(--color-cell-hidden, #2a2a4a);
  border: 1px solid #e94560;
}
.skill-cell.mine {
  background: #c0392b;
}
.skill-cell.correct-move {
  animation: correctPulse 0.5s ease;
  background: #27ae60;
}

@keyframes correctPulse {
  0% { transform: scale(1); }
  50% { transform: scale(1.15); }
  100% { transform: scale(1); }
}

/* ── Skill Trainer: Modifier Cell Styles ─────────── */
.skill-cell.wall {
  background: #5a4a3a;
  border: 1px solid #7a6a5a;
  cursor: default;
  font-size: 18px;
}
.skill-cell.skill-mystery {
  background: var(--color-cell-revealed, #3a3a5a);
  border: 1px solid #9b59b6;
  color: #9b59b6 !important;
  font-size: 18px;
  font-style: italic;
}
.skill-cell.skill-locked {
  background: var(--color-cell-hidden, #2a2a4a);
  border: 1px solid #95a5a6;
  cursor: not-allowed;
  font-size: 14px;
}
.skill-cell.skill-liar {
  border: 2px solid #e67e22 !important;
  box-shadow: 0 0 4px rgba(230, 126, 34, 0.4);
}
.skill-cell.skill-wormhole {
  border: 2px solid #3498db !important;
  box-shadow: 0 0 4px rgba(52, 152, 219, 0.4);
  position: relative;
}
.skill-cell.skill-wormhole::after {
  content: '\1F300';
  position: absolute;
  top: -2px;
  right: -2px;
  font-size: 8px;
  line-height: 1;
}
.skill-cell.skill-wormhole-0 { border-color: #3498db !important; }
.skill-cell.skill-wormhole-1 { border-color: #e74c3c !important; }
.skill-cell.skill-mirror {
  border: 2px solid #1abc9c !important;
  box-shadow: 0 0 4px rgba(26, 188, 156, 0.3);
  position: relative;
}
.skill-cell.skill-mirror::after {
  content: '\1FA9E';
  position: absolute;
  top: -2px;
  right: -2px;
  font-size: 8px;
  line-height: 1;
}

.skill-hint-btn {
  display: block;
  margin: 8px auto;
  padding: 6px 16px;
  border: 1px solid var(--color-border, #333);
  border-radius: 6px;
  background: transparent;
  color: var(--color-text-secondary, #888);
  font-size: 12px;
  cursor: pointer;
}
.skill-hint-btn:hover {
  border-color: var(--color-accent, #e94560);
  color: var(--color-text, #eee);
}

.skill-hint {
  text-align: center;
  font-size: 12px;
  color: var(--color-accent, #e94560);
  margin-top: 6px;
  font-style: italic;
}

.skill-feedback {
  display: inline-block;
  padding: 6px 16px;
  border-radius: 20px;
  font-size: 13px;
  font-weight: 700;
  text-align: center;
  margin: 8px auto;
  pointer-events: none;
  animation: feedbackPop 0.25s ease-out;
}
.skill-feedback.hidden { display: none; }
.skill-feedback.correct {
  color: #27ae60;
  background: rgba(39, 174, 96, 0.15);
}
.skill-feedback.wrong {
  color: #e74c3c;
  background: rgba(231, 76, 60, 0.15);
}
@keyframes feedbackPop {
  from { transform: scale(0.8); opacity: 0; }
  to { transform: scale(1); opacity: 1; }
}

.skill-complete-card {
  text-align: center;
  padding: 32px 20px;
  background: var(--color-surface, #f5f0e8);
  border-radius: 16px;
  border: 1px solid var(--color-border, rgba(0,0,0,0.08));
  box-shadow: 0 4px 20px rgba(0,0,0,0.08);
  max-width: 340px;
  margin: 20px auto;
}
.skill-complete-title {
  font-size: 20px;
  font-weight: 700;
  color: var(--color-text, #333);
  margin: 0 0 4px;
}
.skill-complete-lesson-name {
  font-size: 14px;
  color: var(--color-text-secondary, #888);
  margin-bottom: 12px;
}
.skill-complete-stars {
  font-size: 32px;
  margin: 8px 0;
  color: #f4b400;
}
.skill-complete-rating {
  font-size: 13px;
  color: var(--color-text-secondary, #888);
  margin-bottom: 20px;
}
.skill-complete-actions {
  display: flex;
  gap: 10px;
  justify-content: center;
}

/* ── Audio Settings ────────────────────────────────── */

.audio-setting {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 6px 0;
}
.audio-setting label {
  font-size: 13px;
  min-width: 60px;
  color: var(--color-text-secondary, #aaa);
}
.audio-setting input[type="range"] {
  flex: 1;
  accent-color: var(--color-accent, #e94560);
}

/* ── Volume Sliders (Settings) ────────────────────── */
.volume-label {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 13px;
  color: var(--color-text-secondary, #aaa);
  margin: 6px 0;
}
.volume-slider {
  flex: 1;
  accent-color: var(--color-accent, #e94560);
}

/* ── Collection Modal (themes only) ───────────────── */
.collection-content {
  max-height: 80vh;
}
.collection-panel {
  max-height: 55vh;
  overflow-y: auto;
}

/* ══════════════════════════════════════════════════════ */
/* ── Fix #8: Skill Trainer Neutral Theme Override ──── */
/* ══════════════════════════════════════════════════════ */

.skill-trainer-container {
  --color-cell-hidden: #d4d4d4;
  --color-cell-hidden-hover: #c8c8c8;
  --color-cell-revealed: #f0f0f0;
  --color-cell-border-light: #bbb;
  --color-cell-border-dark: #999;
  --color-text: #333;
  --color-text-secondary: #666;
  --color-surface: #fff;
  --color-surface-alt: #f5f5f5;
  --color-accent: #2196f3;
  --color-mine-bg: #ff5252;
  --board-bg: #e8e8e8;
  --board-border: #ccc;
  background: #f8f8f8;
  border-radius: 12px;
  padding: 16px;
  border: 1px solid #ddd;
}

.skill-trainer-container .cell {
  background: #d4d4d4 !important;
  border-color: #bbb #999 #999 #bbb !important;
  color: #333 !important;
}
.skill-trainer-container .cell.revealed {
  background: #f0f0f0 !important;
  border-color: #ddd !important;
}
.skill-trainer-container .cell.revealed.num-1 { color: #1976d2 !important; }
.skill-trainer-container .cell.revealed.num-2 { color: #388e3c !important; }
.skill-trainer-container .cell.revealed.num-3 { color: #d32f2f !important; }
.skill-trainer-container .cell.revealed.num-4 { color: #7b1fa2 !important; }
.skill-trainer-container .cell.revealed.num-5 { color: #ff6f00 !important; }

/* ══════════════════════════════════════════════════════ */
/* ── Fix #10: Visual Polish & Unification ────────────  */
/* ══════════════════════════════════════════════════════ */

/* Bottom nav — compact, icon-only */
#bottom-nav {
  display: flex;
  justify-content: center;
  gap: 2px;
  padding: 6px 8px;
  background: var(--color-bg, #0f0f23);
  border-top: 1px solid var(--color-border, #333);
}
.nav-btn {
  background: none;
  border: none;
  font-size: 18px;
  padding: 6px 10px;
  cursor: pointer;
  border-radius: 8px;
  transition: background 0.2s, transform 0.1s;
  opacity: 0.7;
}
.nav-btn:hover {
  background: var(--color-surface, #1a1a2e);
  opacity: 1;
  transform: scale(1.05);
}
.nav-btn:active {
  transform: scale(0.95);
}

/* Title screen polish */
.title-screen {
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  align-items: center;
  /* `safe center` centers when the content fits but falls back to start
     alignment (no clipping) when it doesn't, instead of overflowing equally
     off both ends. Paired with overflow-y:auto so that on the rare device
     where even the compact layout is taller than the visible area (mobile
     browser address bar eating height), the footer is still reachable by a
     small scroll rather than silently cut off. */
  justify-content: safe center;
  overflow-y: auto;
  gap: 16px;
  /* Use max() so the iPhone notch / Dynamic Island doesn't overlap the logo
     when the PWA is installed and runs full-screen. Falls back to 16px on
     viewports without safe-area-inset support. */
  padding: max(16px, env(safe-area-inset-top)) 16px max(16px, env(safe-area-inset-bottom));
  background: var(--color-bg, #0f0f23);
  color: var(--color-text, #eee);
}
.title-screen-header {
  /* Greg + the wordmark sit as one centered group (the 2026-06-25 front-door
     rebuild). The flex gap already separates header / modes / footer. */
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  margin-bottom: 4px;
}
.title-greg-mascot {
  width: 100px;
  height: 100px;
  flex: none;
  line-height: 0;
}
.title-greg-mascot svg { display: block; }
.title-screen-wordmark {
  text-align: left;
}
/* In the left-aligned wordmark the proof drops its auto-centering margins. */
.title-screen-wordmark .title-screen-proof {
  margin-left: 0;
  margin-right: 0;
  max-width: 30ch;
}
.title-screen-logo {
  font-family: var(--font-display, 'Fredoka'), sans-serif;
  font-size: clamp(28px, 7vw, 44px);
  font-weight: 700;
  background: linear-gradient(135deg, var(--wordmark-from), var(--wordmark-to));
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
  margin: 0 0 4px;
  letter-spacing: -0.5px;
  /* Comfortable line-height + a hair of padding so the gradient-clipped
     descenders (the g and p) aren't cut at the bottom of the line box. */
  line-height: 1.15;
  padding-bottom: 2px;
}
.title-screen-subtitle {
  font-size: 14px;
  color: var(--color-text-secondary, #888);
  letter-spacing: 1px;
  text-transform: uppercase;
}
.title-screen-modes {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 12px;
  width: 100%;
  max-width: 360px;
  margin-bottom: 4px;
}
.mode-card {
  background: var(--color-surface, #1a1a2e);
  border: 2px solid var(--color-border, #333);
  border-radius: 14px;
  padding: 18px 14px;
  text-align: center;
  cursor: pointer;
  transition: all 0.25s ease;
}
@media (hover: hover) and (pointer: fine) {
  .mode-card:hover {
    border-color: var(--color-accent, #e94560);
    transform: translateY(-2px);
    box-shadow: 0 6px 20px rgba(0,0,0,0.3);
  }
}
.mode-card:active {
  transform: translateY(0) scale(0.97);
}
.mode-card-icon {
  font-size: 28px;
  margin-bottom: 6px;
}
.mode-card-name {
  font-family: var(--font-display, 'Fredoka'), sans-serif;
  font-weight: 600;
  font-size: 15px;
  margin-bottom: 4px;
  color: var(--color-text, #eee);
}
.mode-card-progress {
  font-size: 11px;
  color: var(--color-text-secondary, #888);
}
.title-screen-footer {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  justify-content: center;
}
.title-footer-btn {
  background: var(--color-surface, #1a1a2e);
  border: 1px solid var(--color-border, #333);
  color: var(--color-text, #eee);
  padding: 8px 16px;
  border-radius: 10px;
  font-size: 13px;
  cursor: pointer;
  transition: all 0.2s;
}
.title-footer-btn:hover {
  border-color: var(--color-accent, #e94560);
  background: var(--color-accent, #e94560)15;
}

/* Phone compaction. Keyed on WIDTH, not height: a phone is a phone whether
   it reports 740px or 930px tall, and its real visible height is unknowable
   (the mobile browser address bar eats a variable, dynamic slice that the
   media query never sees). A height breakpoint missed tall Androids/iPhones
   entirely. Every phone is <=480px wide, so this reliably catches all of
   them. Combined with the base overflow-y:auto + safe-center, the title
   screen now fits the visible area on phones and can never hard-clip the
   footer even on the shortest devices. The slightly shorter `(max-height)`
   query layers on extra trimming for very short / landscape cases. */
@media (max-width: 480px) {
  .title-screen {
    gap: 12px;
    padding-top: max(12px, env(safe-area-inset-top));
    padding-bottom: max(12px, env(safe-area-inset-bottom));
  }
  .title-screen-header { margin-bottom: 0; gap: 9px; }
  .title-greg-mascot { width: 80px; height: 80px; }
  .title-screen-logo { font-size: clamp(24px, 6vw, 34px); }
  .title-screen-subtitle { font-size: 12px; }
  .title-screen-proof { margin-top: 4px; font-size: 12px; }
  .title-screen-modes { margin-bottom: 0; }
  .mode-card { padding: 11px 10px; }
  .mode-card-icon { font-size: 24px; margin-bottom: 2px; }
  .mode-card-name { font-size: 14px; margin-bottom: 2px; }
  .title-footer-btn { padding: 7px 13px; }
}
/* Extra squeeze for genuinely short viewports (small Androids, landscape,
   browser UI showing on top of an already-short device). */
@media (max-height: 680px) {
  .title-screen { gap: 9px; }
  .title-greg-mascot { width: 68px; height: 68px; }
  .title-screen-logo { font-size: clamp(22px, 6vw, 30px); }
  .mode-card { padding: 9px 8px; }
  .mode-card-icon { font-size: 22px; }
  .title-footer-btn { padding: 6px 12px; }
}

/* Modifier dismiss button in intro popup */
.modifier-dismiss-btn {
  display: block;
  margin: 8px auto 0;
  font-size: 12px;
  opacity: 0.7;
  background: transparent;
  border: 1px solid var(--color-border, #444);
  color: var(--color-text-secondary, #999);
  padding: 6px 14px;
  border-radius: 6px;
  cursor: pointer;
}
.modifier-dismiss-btn:hover {
  opacity: 1;
}

/* Gimmick intro example grid */
#gimmick-intro-example {
  margin: 12px auto 8px;
  text-align: center;
}
.gimmick-example-grid {
  display: inline-grid;
  gap: 2px;
  margin: 0 auto;
}
.ge-cell {
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 14px;
  font-weight: 700;
  border-radius: 4px;
  border: 1px solid var(--color-border, #444);
}
.ge-cell.unrevealed {
  background: var(--color-cell-hidden, #2a2a4a);
}
.ge-cell.revealed {
  background: var(--color-cell-revealed, #1a1a2e);
  color: var(--color-text, #eee);
}
.ge-mystery {
  color: #a855f7;
  font-size: 18px;
}
.ge-locked {
  font-size: 16px;
}
.ge-liar {
  border: 2px solid #f59e0b !important;
  color: #f59e0b;
}
.ge-wall {
  background: #555 !important;
  font-size: 16px;
}
.ge-wormhole {
  color: #38bdf8;
  font-size: 12px;
}
.ge-mirror {
  color: #c084fc;
  font-size: 12px;
}
.ge-mine-shift {
  font-size: 11px;
  color: #fb923c;
}
.ge-mine-dest {
  background: var(--color-cell-hidden, #2a2a4a);
  border: 1px dashed #fb923c !important;
}
.ge-caption {
  margin-top: 8px;
  font-size: 12px;
  color: var(--color-text-secondary, #999);
  font-style: italic;
}

/* Gimmick intro content sizing */
.gimmick-intro-content {
  text-align: center;
  max-width: 340px;
}
.gimmick-intro-content p {
  font-size: 14px;
  line-height: 1.5;
  color: var(--color-text-secondary, #ccc);
  margin-bottom: 4px;
}

/* Settings toggle label */
.toggle-label {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 14px;
  color: var(--color-text, #eee);
  cursor: pointer;
}
.toggle-label input[type="checkbox"] {
  width: 18px;
  height: 18px;
  accent-color: var(--color-accent, #e94560);
}

/* Modal headers — unified */
.modal-header h2 {
  font-family: var(--font-display, 'Fredoka'), sans-serif;
  font-size: 20px;
  font-weight: 700;
  letter-spacing: -0.3px;
  color: var(--color-text, #eee);
}


/* Action buttons — unified */
.action-btn {
  padding: 10px 20px;
  border: none;
  border-radius: 10px;
  font-family: var(--font-display, 'Fredoka'), sans-serif;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.2s;
  background: var(--color-surface, #1a1a2e);
  color: var(--color-text, #eee);
  border: 1px solid var(--color-border, #333);
}
.action-btn:hover {
  transform: translateY(-1px);
  box-shadow: 0 3px 10px rgba(0,0,0,0.2);
}
.action-btn:active {
  transform: translateY(0) scale(0.97);
}
.action-btn.primary {
  background: var(--color-accent, #e94560);
  color: #fff;
  border-color: transparent;
}
.action-btn.primary:hover {
  background: var(--color-accent-hover, #d63a55);
}

/* Toast — slide-in animation. z-index must beat .modal (1001) so
   toasts triggered while a modal is open (eg from the Settings
   notification toggle) actually surface to the user instead of
   rendering invisibly behind the modal backdrop. */
.toast-container {
  position: fixed;
  bottom: 80px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 10000;
  pointer-events: none;
}

/* Settings theme grid — better collapse UX */
.theme-swatches {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  max-height: 200px;
  overflow-y: auto;
  padding: 4px 0;
}
.theme-swatch.locked-collapsed {
  display: none;
}

/* Game over modal polish */
.gameover-content {
  text-align: center;
  padding: 20px;
}
.gameover-content h2 {
  font-family: var(--font-display, 'Fredoka'), sans-serif;
  font-size: 24px;
  margin: 0 0 8px;
}
.gameover-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  justify-content: center;
  margin-top: 16px;
}

/* Post-death bar (override above — sits above bottom nav) */

/* Share card */
.share-card-preview {
  margin: 10px auto;
  padding: 8px;
  background: var(--color-surface, #1a1a2e);
  border-radius: 8px;
  display: inline-block;
}

/* ── Colorblind Mode ──────────────────────────────────── */
/* Overrides number colors with a palette safe for deuteranopia/protanopia.
   Also adds distinct shape markers (::after) so numbers are identifiable
   by shape alone, not just color. */

[data-colorblind="true"] {
  --color-num-1: #0072b2;  /* blue (unchanged, safe) */
  --color-num-2: #009e73;  /* bluish green */
  --color-num-3: #d55e00;  /* vermillion */
  --color-num-4: #cc79a7;  /* reddish purple */
  --color-num-5: #e69f00;  /* orange */
  --color-num-6: #56b4e9;  /* sky blue */
  --color-num-7: #333333;  /* dark gray */
  --color-num-8: #999999;  /* light gray */
  --color-num-9: #f5793a;  /* warm orange */
  --color-num-10: #85c0f9; /* light blue */
  --color-num-11: #a95aa1; /* muted purple */
  --color-num-12: #c5b731; /* gold */
  --color-num-13: #fc6955; /* salmon */
  --color-num-14: #4eb89a; /* sea green */
  --color-num-15: #8080cc; /* periwinkle */
  --color-num-16: #d4885e; /* clay */
  --color-num-17: #6897bb; /* steel blue */
  --color-num-18: #c97aa4; /* mauve */
}

/* Shape markers: small symbols in top-right corner of each numbered cell */
[data-colorblind="true"] .cell.revealed[class*="num-"]::after {
  position: absolute;
  top: 1px;
  right: 2px;
  font-size: 0.45em;
  line-height: 1;
  opacity: 0.7;
  pointer-events: none;
}

[data-colorblind="true"] .cell.num-1::after { content: "●"; color: var(--color-num-1); }
[data-colorblind="true"] .cell.num-2::after { content: "■"; color: var(--color-num-2); }
[data-colorblind="true"] .cell.num-3::after { content: "▲"; color: var(--color-num-3); }
[data-colorblind="true"] .cell.num-4::after { content: "◆"; color: var(--color-num-4); }
[data-colorblind="true"] .cell.num-5::after { content: "★"; color: var(--color-num-5); }
[data-colorblind="true"] .cell.num-6::after { content: "▼"; color: var(--color-num-6); }
[data-colorblind="true"] .cell.num-7::after { content: "◀"; color: var(--color-num-7); }
[data-colorblind="true"] .cell.num-8::after { content: "▶"; color: var(--color-num-8); }

/* ── Interactive Tutorial ──────────────────────────────── */
.tutorial-overlay {
  position: fixed;
  inset: 0;
  z-index: 10000;
  background: var(--color-bg, #1a1a2e);
  display: flex;
  align-items: center;
  justify-content: center;
  animation: tutorialFadeIn 0.3s ease;
}
.tutorial-overlay.tutorial-exit {
  animation: tutorialFadeOut 0.3s ease forwards;
}
@keyframes tutorialFadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}
@keyframes tutorialFadeOut {
  from { opacity: 1; }
  to { opacity: 0; }
}

.tutorial-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 20px;
  padding: 24px;
  max-width: 400px;
  width: 100%;
}

.tutorial-instruction {
  text-align: center;
  padding: 16px 20px;
  background: var(--color-card-bg, rgba(255,255,255,0.05));
  border-radius: 12px;
  border: 1px solid var(--color-border, rgba(255,255,255,0.1));
  width: 100%;
}
.tutorial-instruction h3 {
  font-size: 18px;
  margin: 0 0 8px;
  color: var(--color-text, #e0e0e0);
}
.tutorial-instruction p {
  font-size: 14px;
  line-height: 1.5;
  margin: 0 0 12px;
  color: var(--color-text-secondary, #aaa);
}

.tutorial-board-wrapper {
  display: flex;
  justify-content: center;
}

.tutorial-board {
  --tutorial-cell-size: 48px;
  display: grid;
  gap: 2px;
  background: var(--color-board-bg, #2a2a4a);
  border: 2px solid var(--color-border, rgba(255,255,255,0.15));
  border-radius: 8px;
  padding: 4px;
}

.tutorial-cell {
  width: var(--tutorial-cell-size, 48px);
  height: var(--tutorial-cell-size, 48px);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 20px;
  font-weight: 700;
  border-radius: 4px;
  cursor: pointer;
  transition: transform 0.15s, background 0.2s;
  user-select: none;
  -webkit-user-select: none;
  position: relative;
}
.tutorial-cell:active {
  transform: scale(0.92);
}

.tutorial-cell.unrevealed {
  background: var(--color-cell-unrevealed, #3a3a5c);
  border: 1px solid rgba(255,255,255,0.12);
}
.tutorial-cell.revealed {
  background: var(--color-cell-revealed, #1e1e38);
  border: 1px solid rgba(255,255,255,0.06);
}
.tutorial-cell.revealed.empty {
  background: var(--color-cell-revealed, #1e1e38);
}
.tutorial-cell.flagged {
  background: var(--color-cell-unrevealed, #3a3a5c);
  border: 1px solid rgba(255,255,255,0.12);
  font-size: 22px;
}
.tutorial-cell.mine {
  background: #c62828;
  font-size: 22px;
}

/* Number colors */
.tutorial-cell.num-1 { color: var(--color-num-1, #42a5f5); }
.tutorial-cell.num-2 { color: var(--color-num-2, #66bb6a); }
.tutorial-cell.num-3 { color: var(--color-num-3, #ef5350); }
.tutorial-cell.num-4 { color: var(--color-num-4, #ab47bc); }
.tutorial-cell.num-5 { color: var(--color-num-5, #ff7043); }

/* Highlighted target cell — pulsing glow */
.tutorial-cell.tutorial-highlight {
  box-shadow: 0 0 0 3px rgba(255, 193, 7, 0.7), 0 0 16px rgba(255, 193, 7, 0.4);
  animation: tutorialPulse 1.2s ease-in-out infinite;
  z-index: 1;
}
@keyframes tutorialPulse {
  0%, 100% { box-shadow: 0 0 0 3px rgba(255, 193, 7, 0.7), 0 0 16px rgba(255, 193, 7, 0.4); }
  50% { box-shadow: 0 0 0 5px rgba(255, 193, 7, 0.9), 0 0 24px rgba(255, 193, 7, 0.6); }
}

.tutorial-footer {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  width: 100%;
}

.tutorial-skip-btn {
  background: none;
  border: none;
  color: var(--color-text-secondary, #888);
  font-size: 13px;
  cursor: pointer;
  padding: 6px 12px;
  text-decoration: underline;
  opacity: 0.7;
  transition: opacity 0.2s;
}
.tutorial-skip-btn:hover {
  opacity: 1;
}

.tutorial-progress {
  display: flex;
  gap: 6px;
  align-items: center;
}
.tutorial-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--color-text-secondary, #555);
  opacity: 0.3;
  transition: all 0.3s;
}
.tutorial-dot.active {
  background: var(--color-accent, #ffc107);
  opacity: 1;
  transform: scale(1.3);
}
.tutorial-dot.completed {
  background: var(--color-accent, #ffc107);
  opacity: 0.6;
}

/* Responsive: smaller cells on small screens */
@media (max-width: 360px) {
  .tutorial-board {
    --tutorial-cell-size: 40px;
  }
  .tutorial-cell {
    font-size: 17px;
  }
}

/* ── Diagnostics Modal ────────────────────────── */

#diagnostics-modal .modal-body {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.diagnostics-loading {
  color: var(--color-text-secondary);
  font-size: 13px;
  text-align: center;
  padding: 24px 0;
}

.diagnostics-row {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding-left: 10px;
  border-left: 3px solid transparent;
}

.diagnostics-row.diagnostics-warn {
  border-left-color: #ff6b6b;
}

.diagnostics-label {
  font-size: 10px;
  color: var(--color-text-secondary);
  text-transform: uppercase;
  letter-spacing: 1.5px;
  font-weight: 700;
}

.diagnostics-warn .diagnostics-label {
  color: #ff6b6b;
}

.diagnostics-value {
  font-family: ui-monospace, Menlo, Consolas, monospace;
  font-size: 13px;
  color: var(--color-text, #ccc);
  word-break: break-all;
  user-select: text;
  -webkit-user-select: text;
}

.diagnostics-value.diagnostics-uid {
  font-size: 15px;
  font-weight: 600;
  color: var(--color-accent, #ffc107);
}

.diagnostics-small .diagnostics-value,
.diagnostics-row.diagnostics-small .diagnostics-value {
  font-size: 11px;
  opacity: 0.85;
}

pre.diagnostics-value,
pre.diagnostics-pre {
  font-family: ui-monospace, Menlo, Consolas, monospace;
  font-size: 12px;
  color: var(--color-text, #ccc);
  background: rgba(0, 0, 0, 0.18);
  border: 1px solid var(--color-border, #555);
  border-radius: 6px;
  padding: 8px 10px;
  margin: 0;
  white-space: pre;
  overflow-x: auto;
  max-height: 280px;
  overflow-y: auto;
}

.diagnostics-note {
  font-size: 12px;
  color: #ffb84d;
  margin: -6px 0 0 10px;
  padding: 8px 10px;
  background: rgba(255, 184, 77, 0.08);
  border-left: 3px solid #ffb84d;
  border-radius: 0 4px 4px 0;
}

.diagnostics-actions {
  margin-top: 10px;
}

.daily-name-hint {
  font-size: 11px;
  color: var(--color-text-secondary, #888);
  margin: 4px 0 8px 0;
}

/* ── Forced-colors (Windows High Contrast / accessibility) ────────
   When the OS forces a high-contrast palette, theme colors get
   stripped and replaced with system colors (ButtonText, ButtonFace,
   Highlight, etc.). Without explicit forced-colors rules, decorative
   elements like cell borders and button outlines can vanish entirely.
   These rules restore the bare-minimum visual structure so the game
   stays playable. */
@media (forced-colors: active) {
  .cell {
    border: 1px solid ButtonText;
    forced-color-adjust: none;
  }
  .cell.revealed {
    background: ButtonFace;
    color: ButtonText;
  }
  .cell.unrevealed {
    background: Canvas;
  }
  .cell.mine,
  .cell.mine-hit {
    background: Mark;
    color: MarkText;
  }
  .cell.flagged {
    background: Highlight;
    color: HighlightText;
  }
  .mode-card,
  .action-btn,
  .title-footer-btn,
  .modal-close {
    border: 1px solid ButtonText;
    forced-color-adjust: none;
  }
  /* Win/loss color cues fall back to text-decoration since color is
     unreliable under forced-colors. */
  .par-under { text-decoration: underline solid; }
  .par-over { text-decoration: overline solid; }
  /* Liar outline survives — outline color uses system Highlight. */
  .cell.liar-cell {
    outline: 2px solid Highlight;
  }
}

/* ── Game sprites (mine, flag, smileys, strike) ───────── */
.game-sprite {
  pointer-events: none;
  user-select: none;
  -webkit-user-drag: none;
}
/* Strike cell: a defused bomb spot in daily/weekly mode (player hit the
   mine, +10s penalty, mine removed, but the explosion mark stays so
   they can see where it was). Soft red tint differentiates it from
   regular revealed cells without screaming. */
.cell.strike-cell {
  background-color: var(--overlay-mine-tint, rgba(206, 40, 40, 0.42)) !important;
  outline: 2px solid var(--overlay-strike-ring, rgba(220, 30, 30, 0.9));
  outline-offset: -2px;
}
/* Use max-width/max-height + width:auto/height:auto so the sprite stays
   inside the cell on every browser, including ones where percentage
   height on a flex item resolves to 0 or leaks intrinsic dimensions.
   margin:auto centers the image when its natural size is smaller than
   the cap (it never is here — natural is 768×768 — but keeps the
   rule robust under future sprite resizes). object-fit:contain is a
   no-op when the cap matches aspect, useful insurance otherwise. */
.cell > .game-sprite.sprite-cell,
.tutorial-cell > .game-sprite.sprite-cell {
  display: block;
  width: auto;
  height: auto;
  max-width: 88%;
  max-height: 88%;
  margin: auto;
  object-fit: contain;
}
.smiley-btn > .game-sprite.sprite-smiley {
  display: block;
  width: auto;
  height: auto;
  max-width: 78%;
  max-height: 78%;
  margin: auto;
  object-fit: contain;
}
.game-sprite.sprite-header {
  display: inline-block;
  width: 1em;
  height: 1em;
  vertical-align: -0.15em;
}
.game-sprite.sprite-popup {
  display: inline-block;
  width: 1.2em;
  height: 1.2em;
  vertical-align: -0.2em;
  margin-right: 0.25em;
}

/* ── Wave E: inline chrome + toast / coach sprites ────────────────────
   The last plain-emoji surfaces, drawn. Sizes mirror sprite-header /
   ui-icon-label so each icon sits on the baseline of its message. */
.toast-icon {
  display: inline-block;
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  vertical-align: -4px;
  pointer-events: none;
}
.queued-toast.has-icon {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.coach-icon {
  display: inline-block;
  width: 1.2em;
  height: 1.2em;
  vertical-align: -0.25em;
  margin-right: 0.4em;
  pointer-events: none;
}
.game-sprite.btn-icon {
  width: 20px;
  height: 20px;
  vertical-align: -5px;
  margin-right: 7px;
}
.game-sprite.record-icon {
  display: inline-block;
  width: 1.35em;
  height: 1.35em;
  vertical-align: -0.28em;
  margin-right: 0.25em;
}
.game-sprite.molt-inline {
  display: inline-block;
  width: 1.15em;
  height: 1.15em;
  vertical-align: -0.22em;
  margin-right: 0.15em;
}
.game-sprite.molt-token {
  display: inline-block;
  width: 15px;
  height: 15px;
  vertical-align: middle;
}
.game-sprite.gimmick-intro-icon {
  display: block;
  width: 46px;
  height: 46px;
  margin: 0 auto;
}
.header-btn-icon {
  display: block;
  width: 1.5em;
  height: 1.5em;
  margin: auto;
  pointer-events: none;
}
.molt-earned-crab img {
  display: block;
  width: 56px;
  height: 56px;
  margin: 0 auto;
}
/* Wave E pass 2: LCD header, power-up text, gym board, modal titles. */
.game-sprite.lcd-icon { display: inline-block; width: 1.05em; height: 1.05em; vertical-align: -0.14em; }
.game-sprite.inline-pu { display: inline-block; width: 1.1em; height: 1.1em; vertical-align: -0.18em; margin-right: 0.12em; }
.game-sprite.inline-mine { display: inline-block; width: 1.05em; height: 1.05em; vertical-align: -0.16em; margin-right: 0.18em; }
.game-sprite.inline-strike { display: inline-block; width: 1.05em; height: 1.05em; vertical-align: -0.15em; margin: 0 0.08em; }
.game-sprite.gym-piece { display: inline-block; width: 1.2em; height: 1.2em; vertical-align: -0.2em; }
.game-sprite.gym-sketch { display: block; width: 100%; height: 100%; }
.game-sprite.lexicon-title-icon { display: inline-block; width: 1.3em; height: 1.3em; vertical-align: -0.25em; margin-right: 0.2em; }
.modal-title-icon { width: 1.05em; height: 1.05em; vertical-align: -0.1em; margin-right: 0.15em; }
.inline-medal { width: 1.2em; height: 1.2em; vertical-align: -0.22em; margin: 0 1px; }
.ge-cell img.ge-piece { width: 22px; height: 22px; vertical-align: middle; object-fit: contain; }
.game-sprite.inline-lock { display: inline-block; width: 1em; height: 1em; vertical-align: -0.12em; margin-right: 0.15em; }
.cell .game-sprite.sonar-marker { display: inline-block; width: 0.8em; height: 0.8em; vertical-align: -0.05em; margin-right: 1px; }

/* ── Live theme carousel ──────────────────────────────────────────────────────
   A slim bar that floats over the bottom of the screen so the real board stays
   visible and re-themes live as you flip. Theme-NEUTRAL (its own fixed dark
   glass look) so it reads on every theme, light or dark. */
.theme-carousel {
  position: fixed;
  left: 50%;
  bottom: 18px;
  transform: translateX(-50%);
  z-index: 4000;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border-radius: 16px;
  background: rgba(18, 18, 24, 0.86);
  border: 1px solid rgba(255, 255, 255, 0.14);
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  color: #f4f4f6;
  font-family: system-ui, -apple-system, 'Segoe UI', sans-serif;
  max-width: calc(100vw - 24px);
  animation: tcRise 0.22s cubic-bezier(0.34, 1.4, 0.5, 1);
}
.theme-carousel.hidden { display: none; }

@keyframes tcRise {
  from { opacity: 0; transform: translate(-50%, 14px); }
  to   { opacity: 1; transform: translate(-50%, 0); }
}

.tc-arrow {
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  border-radius: 12px;
  border: none;
  background: rgba(255, 255, 255, 0.1);
  color: #fff;
  font-size: 26px;
  line-height: 1;
  cursor: pointer;
  transition: background 0.15s, transform 0.1s;
}
.tc-arrow:hover { background: rgba(255, 255, 255, 0.2); }
.tc-arrow:active { transform: scale(0.92); }

.tc-info {
  flex: 1 1 auto;
  min-width: 116px;
  text-align: center;
  user-select: none;
}
.tc-name {
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.3px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.tc-pos {
  font-size: 11px;
  opacity: 0.6;
  margin-top: 1px;
  letter-spacing: 0.5px;
}
.tc-name .tc-lock { opacity: 0.7; font-size: 12px; margin-left: 4px; }

.tc-done {
  flex: 0 0 auto;
  height: 44px;
  padding: 0 16px;
  border-radius: 12px;
  border: none;
  background: #4a8af0;
  color: #fff;
  font-size: 14px;
  font-weight: 700;
  cursor: pointer;
  transition: background 0.15s, transform 0.1s;
}
.tc-done:hover { background: #5a97f5; }
.tc-done:active { transform: scale(0.95); }

/* While the carousel is open, hint that the board is swipeable. */
#board.tc-swipe-target { cursor: grab; }

