/* ==========================================================
   HALF-LIFE HAVOC — namespaced "hlh-" per EC per-app CSS convention.
   Chrome (surfaces, borders, text) pulls from base.css tokens so the game
   tracks theme + scheme changes. Game-object colours deliberately do NOT
   — see the note below. Font sizes use the canonical 8-step rem scale
   (EC_Design_System.md §3.2).
   ========================================================== */

/* ── Canonical button classes ──────────────────────────────
   .btn-primary and .btn-outline-sm are NOT defined in base.css or
   layout.css — per EC convention each app duplicates them in its own
   stylesheet. Verbatim from EC_Design_System.md §6.1.
   ------------------------------------------------------------------ */
.btn-primary {
  background: var(--primary);
  color: white;
  border: none;
  border-radius: var(--radius-sm);
  padding: 0.5rem 1.1rem;
  cursor: pointer;
  font-size: 0.85rem;
  font-weight: 600;
  font-family: var(--font);
  transition: all var(--transition);
  white-space: nowrap;
  box-shadow: var(--shadow-primary);
}
.btn-primary:hover { background: var(--primary-hover); }
.btn-primary:disabled { opacity: 0.5; cursor: not-allowed; }
.btn-primary:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }

.btn-outline-sm {
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text-muted);
  border-radius: var(--radius-sm);
  padding: 0.4rem 0.8rem;
  cursor: pointer;
  font-size: 0.80rem;
  font-weight: 600;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  transition: all var(--transition);
  font-family: var(--font);
}
.btn-outline-sm:hover { color: var(--primary); border-color: var(--primary); }
.btn-outline-sm:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }

/* ══════════════════════════════════════════════════════════
   GAME PALETTE — SCHEME-NEUTRAL ON PURPOSE
   ══════════════════════════════════════════════════════════
   In this game colour IS the answer: alpha/beta/positron and the two
   terrain types are told apart by hue and nothing else. Binding any of
   them to var(--primary) breaks that, because --primary is byte-identical
   to another game colour in every non-default scheme:

     amber  --primary #F0C840  ==  alpha (highlight)
     purple --primary #9B8DD4  ==  positron (tertiary)
     teal   --primary #3FC9A0  ==  stable daughter (secondary)
     orange --primary #F08C4A  ==  stray isotope (alert)

   A student on the teal scheme would see the beta blaster and the stable
   daughters render the same colour — a wrong-answer generator, not a
   cosmetic wobble. Per §4.2 these are semantic roles, so they take fixed
   values and shift only with light/dark. The scheme picker still drives
   all the chrome (buttons, selection states, focus rings) as usual.

   The values are the DEFAULT (cobalt-scheme) semantic hexes from base.css,
   so on the default scheme nothing looks different from the artboard. */

:root,
[data-theme="light"] {
  --hlh-alpha:    #C49200;   /* highlight  — alpha particle, He-4 */
  --hlh-beta:     #2C5CC5;   /* cobalt     — beta-minus, the electron */
  --hlh-positron: #6B5CA5;   /* tertiary   — beta-plus, the positron */
  --hlh-stable:   #1B9E77;   /* secondary  — daughter terrain */
  --hlh-stray:    #D95F02;   /* alert      — stray isotope hazard */

  --hlh-alpha-soft:    rgba(196,146,0,0.12);
  --hlh-beta-soft:     rgba(44,92,197,0.10);
  --hlh-positron-soft: rgba(107,92,165,0.12);
  --hlh-stray-soft:    rgba(253,240,230,0.96);

  --hlh-board: #EDF1F8;
  --hlh-grid:  rgba(44,92,197,0.18);
  --hlh-band:  rgba(44,92,197,0.06);
  --hlh-node:  rgba(255,255,255,0.98);
}

[data-theme="dark"] {
  --hlh-alpha:    #F0C840;
  --hlh-beta:     #6B93DB;
  --hlh-positron: #9B8DD4;
  --hlh-stable:   #3FC9A0;
  --hlh-stray:    #F08C4A;

  --hlh-alpha-soft:    rgba(240,200,64,0.14);
  --hlh-beta-soft:     rgba(107,147,219,0.14);
  --hlh-positron-soft: rgba(155,141,212,0.14);
  --hlh-stray-soft:    rgba(46,30,16,0.94);

  --hlh-board: #0C1220;
  --hlh-grid:  rgba(107,147,219,0.10);
  --hlh-band:  rgba(107,147,219,0.05);
  --hlh-node:  rgba(30,38,54,0.98);
}

/* ── Shell ── */
.hlh-wrap {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.1rem;
}

/* The app name already lives in the CoreUI header, so the visible <h1> is
   redundant. Keep a screen-reader-only one so the page still has a proper
   top-level heading for assistive tech and search indexing. */
.hlh-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;
}

.hlh-head { width: 100%; display: flex; flex-wrap: wrap; align-items: flex-end; gap: 0.75rem; }
.hlh-head-copy { flex: 1; min-width: 240px; }
.hlh-subtitle { margin: 0; font-size: 0.85rem; color: var(--text-muted); line-height: 1.5; }
.hlh-best {
  display: flex; align-items: center; gap: 0.5rem;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  font-size: 0.80rem;
  color: var(--text-muted);
}
.hlh-best strong { color: var(--text); font-size: 0.95rem; }

.hlh-section-label {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: 0.55rem;
}

/* ══════════════════════════════════════════════════════════
   MENU
   ══════════════════════════════════════════════════════════ */
.hlh-panel {
  width: 100%;
  max-width: 660px;
  padding: 1.35rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
  box-shadow: var(--shadow-md);
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  animation: fadeInUp .3s ease-out forwards;
}

.hlh-opt-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 0.6rem; }
.hlh-opt {
  text-align: left;
  padding: 0.75rem 0.8rem;
  border-radius: var(--radius-sm);
  cursor: pointer;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  font-family: var(--font);
  transition: all var(--transition);
}
.hlh-opt:hover { border-color: var(--primary); }
.hlh-opt:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.hlh-opt[data-selected="true"] { border-color: var(--primary); background: var(--primary-light); }
/* Flex so the count badge always pins to the right edge instead of
   wrapping under a long label. */
.hlh-opt-title { display: flex; align-items: center; justify-content: space-between; gap: 0.35rem; font-size: 0.85rem; font-weight: 700; margin-bottom: 0.2rem; }
.hlh-opt-desc { font-size: 0.72rem; color: var(--text-muted); line-height: 1.4; }
.hlh-opt-count {
  flex: none; white-space: nowrap;
  font-size: 0.72rem; font-weight: 600; color: var(--text-muted);
  border: 1px solid var(--border); border-radius: 999px; padding: 0 0.4rem;
}

.hlh-toggle-row {
  display: flex; align-items: center; gap: 0.8rem;
  padding: 0.75rem 0.8rem;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--surface);
  cursor: pointer;
  text-align: left;
  color: var(--text);
  font-family: var(--font);
  width: 100%;
  transition: all var(--transition);
}
.hlh-toggle-row[data-on="true"] { border-color: var(--primary); background: var(--primary-light); }
.hlh-toggle-row:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.hlh-switch {
  position: relative; flex: none;
  width: 2.6rem; height: 1.5rem;
  border-radius: 999px;
  background: var(--border);
  transition: background var(--transition);
}
.hlh-switch[data-on="true"] { background: var(--primary); }
.hlh-switch-knob {
  position: absolute; top: 0.18rem; left: 0.18rem;
  width: 1.1rem; height: 1.1rem;
  border-radius: 999px;
  background: #fff;
  box-shadow: var(--shadow-sm);
  transition: left var(--transition);
}
.hlh-switch[data-on="true"] .hlh-switch-knob { left: 1.3rem; }
.hlh-toggle-copy { flex: 1; }
/* These are <span>s, so they MUST be blockified — as inline elements they
   run together on one line and margin-top is silently ignored. */
.hlh-toggle-title { display: block; font-size: 0.85rem; font-weight: 700; }
.hlh-toggle-hint { display: block; font-size: 0.72rem; color: var(--text-muted); line-height: 1.4; margin-top: 0.25rem; }

.hlh-start-row { display: flex; flex-wrap: wrap; align-items: center; gap: 0.75rem; }
.hlh-start-row .btn-primary { flex: 1; min-width: 190px; padding: 0.8rem 1.1rem; font-size: 0.95rem; }
.hlh-start-hint { font-size: 0.72rem; color: var(--text-muted); }

/* ══════════════════════════════════════════════════════════
   ISOTOPE NOTATION
   Mass number stacked ABOVE atomic number, both right-aligned, to the left
   of the symbol. A <sup>/<sub> pair can't express this — they sit side by
   side — so the numbers are a right-aligned flex column instead. No
   Unicode super/subscript glyphs are used anywhere (§3.4).
   ══════════════════════════════════════════════════════════ */
.hlh-iso {
  display: inline-flex;
  align-items: center;
  font-family: var(--font);
  line-height: 1;
}
.hlh-iso-nums {
  display: flex; flex-direction: column; align-items: flex-end;
  font-size: 0.72rem; font-weight: 700; line-height: 1.08;
  padding-right: 2px;
}
.hlh-iso-sym { font-size: 1.50rem; font-weight: 700; }

/* ══════════════════════════════════════════════════════════
   PLAY SCREEN
   ══════════════════════════════════════════════════════════ */
.hlh-play {
  width: 100%;
  max-width: 720px;
  display: flex;
  flex-direction: column;
  gap: 0.7rem;
  /* Vertical space the non-board chrome needs (sticky header + stats +
     controls + fire row + legend + gaps). The default is a safe first-paint
     estimate; hlhMeasureChrome() overwrites it with the real number. */
  --hlh-chrome: 15rem;
}

.hlh-stats { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.hlh-stat {
  flex: 1; min-width: 5.5rem;
  padding: 0.45rem 0.65rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
}
.hlh-stat-label { font-size: 0.72rem; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--text-muted); }
.hlh-stat-value { font-size: 1.05rem; font-weight: 700; color: var(--text); line-height: 1.3; min-height: 1.5rem; display: flex; align-items: center; }
.hlh-stat-value .hlh-iso-sym { font-size: 1.05rem; }
.hlh-stat-value .hlh-iso-nums { font-size: 0.72rem; }
.hlh-equip-empty {
  font-size: 0.95rem; font-weight: 700; color: var(--text-light);
  border: 1px dashed var(--border); border-radius: var(--radius-sm); padding: 0 0.6rem;
}

.hlh-pips { gap: 0.3rem; }
.hlh-pip {
  width: 0.75rem; height: 0.75rem;
  border-radius: 50%;
  border: 1.5px solid var(--border);
  background: transparent;
  transition: all var(--transition);
}
.hlh-pip[data-on="true"] { background: var(--hlh-stable); border-color: var(--hlh-stable); }

/* The board is 3:2, so capping its width caps its height too. 100dvh (not
   100vh) so mobile browser toolbars don't push it under the fold. */
.hlh-board {
  position: relative;
  width: 100%;
  width: min(100%, calc((100dvh - var(--hlh-chrome)) * 1.5));
  max-width: 720px;
  margin: 0 auto;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--hlh-board);
  overflow: hidden;
  touch-action: none;
}
.hlh-board canvas { display: block; width: 100%; aspect-ratio: 3 / 2; touch-action: none; }

/* ── In-play callout ── */
.hlh-callout {
  position: absolute; left: 50%; top: 8%;
  transform: translateX(-50%);
  width: min(85%, 30rem);
  display: flex; flex-direction: column; gap: 0.15rem;
  padding: 0.6rem 0.85rem;
  border-radius: var(--radius-sm);
  border: 1px solid var(--hlh-stray);
  background: var(--surface);
  box-shadow: var(--shadow-lg);
  text-align: left;
  pointer-events: none;
  /* MUST stay 0. The animation ends at opacity 0 with fill-mode forwards,
     but the moment .hlh-callout-show is removed the element reverts to
     THIS rule — without opacity:0 the message stays painted over the
     board permanently. */
  opacity: 0;
}
.hlh-callout strong { font-size: 0.80rem; font-weight: 700; color: var(--hlh-stray); }
.hlh-callout span { font-size: 0.72rem; line-height: 1.45; color: var(--text-muted); }
.hlh-callout.hlh-callout-show { animation: hlhCallout 5.2s ease forwards; }
@keyframes hlhCallout {
  0%   { transform: translate(-50%, -8px); opacity: 0; }
  5%   { transform: translate(-50%, 0);    opacity: 1; }
  88%  { transform: translate(-50%, 0);    opacity: 1; }
  100% { transform: translate(-50%, -8px); opacity: 0; }
}

/* ── Overlays ── */
/* ── Overlays: fixed to the VIEWPORT, not to the board ────────────────
   These were absolutely positioned inside .hlh-board, which capped their
   height at the board's height — and the board and the cards move in
   OPPOSITE directions as the font-scale control is used: bigger text grows
   the chrome rows, which shrinks the board's height budget, while the cards
   themselves grow. At 1280x800 with A+ at maximum the board was 392px and
   the game-over card 453px, so "Play again" fell outside a box that had no
   overflow-y at all — clipped and unreachable, exactly for the students
   most likely to have raised the text size.

   Fixed to the viewport, the height budget is the window. At ordinary sizes
   nothing scrolls and the card's sticky action bar never even engages.

   z-index clears the CoreUI header (50). These are modal gates — you must
   answer the card, and the run really is over — so dimming the whole page
   rather than a rectangle inside it is also the more honest reading.

   "safe center" centres the card while it fits and falls back to
   top-aligned once it doesn't. Plain `center` overflows in BOTH directions
   when the content is taller than the box, which puts the top of the card
   above the scroll origin where it can never be scrolled back into view.
   The unprefixed value is listed first as the fallback for older engines.
   -------------------------------------------------------------------- */
.hlh-overlay {
  position: fixed; inset: 0;
  z-index: 90;
  display: none;
  place-items: center;
  align-content: center;
  align-content: safe center;
  overflow-y: auto;
  background: var(--overlay);
  backdrop-filter: blur(3px);
  padding: 1rem;
}
.hlh-overlay.hlh-overlay-show { display: grid; }

/* ── The problem card ── */
.hlh-card {
  width: 100%;
  max-width: 30rem;
  margin: auto;
  padding: 0.85rem 1rem 0;
  border-radius: var(--radius-lg);
  background: var(--surface);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-lg);
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  animation: scaleIn .25s ease-out forwards;
}
.hlh-card-head { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; flex-wrap: wrap; }
.hlh-card-kicker { font-size: 0.72rem; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-muted); }
.hlh-card-badge {
  font-size: 0.72rem; font-weight: 700;
  padding: 0.15rem 0.55rem; border-radius: 999px;
  border: 1px solid var(--border); color: var(--text-muted);
}
.hlh-card-badge[data-chained="true"] {
  color: var(--hlh-positron);
  border-color: var(--hlh-positron);
  background: var(--hlh-positron-soft);
}

.hlh-equation {
  display: flex; align-items: center; justify-content: center;
  flex-wrap: wrap; gap: 0.5rem 0.75rem;
  padding: 0.6rem 0.5rem;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
}
.hlh-eq-side { display: flex; flex-direction: column; align-items: center; gap: 0.15rem; }
.hlh-eq-op { font-size: 1.20rem; font-weight: 700; color: var(--text-muted); }
.hlh-eq-name { font-size: 0.72rem; color: var(--text-muted); }
.hlh-eq-meta { font-size: 0.72rem; color: var(--text-light); }
.hlh-eq-unknown {
  font-size: 1.50rem; font-weight: 700; line-height: 1;
  color: var(--hlh-beta);
  border: 1px dashed var(--hlh-beta);
  border-radius: var(--radius-sm);
  padding: 0.1rem 0.7rem;
  animation: hlhPulse 1.6s ease-in-out infinite;
}
@keyframes hlhPulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.45; } }

.hlh-card-read { margin: 0; font-size: 0.80rem; line-height: 1.5; color: var(--text-muted); }
.hlh-card-read strong { color: var(--text); }

.hlh-conserve {
  display: flex; flex-direction: column; gap: 0.3rem;
  padding: 0.6rem 0.75rem;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
}
.hlh-conserve span { font-size: 0.72rem; line-height: 1.45; color: var(--text-muted); }
.hlh-conserve strong { color: var(--text); }

.hlh-pick-block { display: flex; flex-direction: column; }
.hlh-pick-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.5rem; }
.hlh-pick {
  display: flex; flex-direction: column; align-items: center; gap: 0.2rem;
  padding: 0.55rem 0.35rem;
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-family: var(--font);
  color: var(--text);
  background: var(--surface);
  border: 1.5px solid var(--border);
  transition: all var(--transition);
}
.hlh-pick:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.hlh-pick-name { font-size: 0.72rem; font-weight: 700; }
.hlh-pick-delta { font-size: 0.72rem; color: var(--text-light); }
.hlh-pick sup { font-size: 0.7em; }

.hlh-pick[data-mode="alpha"]:hover,
.hlh-pick[data-mode="alpha"][data-selected="true"]      { border-color: var(--hlh-alpha); }
.hlh-pick[data-mode="alpha"][data-selected="true"]      { background: var(--hlh-alpha-soft); }
.hlh-pick[data-mode="beta-minus"]:hover,
.hlh-pick[data-mode="beta-minus"][data-selected="true"] { border-color: var(--hlh-beta); }
.hlh-pick[data-mode="beta-minus"][data-selected="true"] { background: var(--hlh-beta-soft); }
.hlh-pick[data-mode="beta-plus"]:hover,
.hlh-pick[data-mode="beta-plus"][data-selected="true"]  { border-color: var(--hlh-positron); }
.hlh-pick[data-mode="beta-plus"][data-selected="true"]  { background: var(--hlh-positron-soft); }

.hlh-card-note { margin: 0; font-size: 0.72rem; line-height: 1.45; color: var(--text-light); }
.hlh-card-note em { font-style: italic; }
/* Pinned to the bottom of the scrolling overlay. On a short board the card
   is taller than the viewport it sits in, and the primary action must never
   be the thing that ends up below the fold. */
.hlh-card-actions {
  position: sticky;
  bottom: 0;
  padding: 0.55rem 0 0.85rem;
  background: var(--surface);
  /* A short fade above the bar so content scrolling underneath reads as
     "there is more up there", not as a clipped element. */
  box-shadow: 0 -0.6rem 0.6rem -0.6rem rgba(0,0,0,0.16);
}
.hlh-card-actions .btn-primary { width: 100%; padding: 0.7rem; font-size: 0.95rem; }
.hlh-begin-empty {
  width: 100%; text-align: center;
  font-size: 0.85rem; font-weight: 500; color: var(--text-light);
  border: 1px dashed var(--border); border-radius: var(--radius-sm);
  padding: 0.7rem;
}

/* ── Pause / game over ── */
.hlh-pause-card, .hlh-over-card {
  width: 100%; max-width: 24rem;
  padding: 1.35rem 1.5rem;
  border-radius: var(--radius-lg);
  background: var(--surface);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-lg);
  text-align: center;
  animation: scaleIn .25s ease-out forwards;
}
.hlh-pause-title { font-size: 1.05rem; font-weight: 700; margin-bottom: 0.6rem; color: var(--text); }
.hlh-rules { list-style: none; text-align: left; display: flex; flex-direction: column; gap: 0.4rem; margin-bottom: 1rem; }
.hlh-rules li { font-size: 0.72rem; line-height: 1.5; color: var(--text-muted); }
.hlh-rules strong { color: var(--text); }
.hlh-pause-actions, .hlh-over-actions { display: flex; gap: 0.5rem; }
.hlh-pause-actions .btn-primary, .hlh-over-actions .btn-primary { flex: 1; }

.hlh-over-reason { font-size: 0.72rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--hlh-stray); }
.hlh-over-score { font-size: 2.00rem; font-weight: 700; letter-spacing: -0.03em; margin: 0.3rem 0 0.1rem; color: var(--text); }
.hlh-over-note { font-size: 0.80rem; color: var(--text-muted); margin-bottom: 1rem; }
.hlh-over-stats { display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem; margin-bottom: 1.1rem; }
.hlh-over-stat { padding: 0.5rem; border: 1px solid var(--border); border-radius: var(--radius-sm); }
.hlh-over-stat-label { font-size: 0.72rem; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--text-muted); }
.hlh-over-stat-value { font-size: 1.05rem; font-weight: 700; color: var(--text); }

/* ── Controls row ── */
.hlh-controls { display: flex; flex-wrap: wrap; align-items: center; gap: 0.55rem; }
.hlh-controls .btn-outline-sm { font-weight: 500; }
.hlh-hint { flex: 1; min-width: 160px; text-align: right; font-size: 0.72rem; color: var(--text-muted); }

/* ── Optional fire button (touch, auto-fire off) ── */
.hlh-fire-row { display: flex; justify-content: center; }
.hlh-fire-btn {
  min-width: 12rem; min-height: 3.25rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text-muted);
  font-family: var(--font);
  font-size: 0.95rem;
  font-weight: 700;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: none;
  user-select: none;
  transition: background var(--transition), color var(--transition), border-color var(--transition);
}
.hlh-fire-btn:active { background: var(--primary-light); border-color: var(--primary); color: var(--primary); }

/* ── Legend ── */
.hlh-legend { display: flex; flex-wrap: wrap; gap: 0.4rem 1rem; justify-content: center; font-size: 0.72rem; color: var(--text-muted); }
.hlh-legend-item { display: inline-flex; align-items: center; gap: 0.4rem; }
/* Drawn as inline SVG rather than a clip-path box, so the legend swatch is
   the same shape the canvas actually paints — including the inner ring that
   distinguishes a chaining daughter from a stable one. */
.hlh-legend svg { flex: none; display: block; }
.hlh-legend-diamond { width: 0.6rem; height: 0.6rem; transform: rotate(45deg); background: var(--hlh-stray); border-radius: 1px; }

/* ══════════════════════════════════════════════════════════
   IMMERSIVE PLAY (touch devices)
   Gated on a .hlh-touch class set by pointer/maxTouchPoints detection, NOT
   a width breakpoint — an iPad is 768x1024 portrait and matches no phone
   breakpoint, which is why it would otherwise keep the scrollable desktop
   layout. The play screen becomes a fixed full-viewport layer during a
   run: stronger than locking body overflow, which is famously leaky on
   iOS Safari, because there is simply no scrollable page underneath.
   ══════════════════════════════════════════════════════════ */
html.hlh-touch body.hlh-playing #core-header,
html.hlh-touch body.hlh-playing #core-footer { display: none; }

html.hlh-touch body.hlh-playing {
  overflow: hidden;
  overscroll-behavior: none;   /* kills pull-to-refresh and rubber-banding */
}

html.hlh-touch body.hlh-playing .hlh-play {
  position: fixed;
  inset: 0;
  max-width: none;
  z-index: 60;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  padding: 0.4rem;
  background: var(--bg);
  touch-action: none;
}
/* In immersive play the 720px desktop cap is dropped: the layer already
   fills the viewport, and on a tablet in portrait that cap left the board
   at 720x480 inside an 820x1180 screen — most of the height unused, and a
   problem card that had to scroll for no reason. Off the cap, the board
   grows to the full width and the card fits without scrolling. */
html.hlh-touch body.hlh-playing .hlh-board { max-width: none; }
html.hlh-touch body.hlh-playing .hlh-stats,
html.hlh-touch body.hlh-playing .hlh-controls,
html.hlh-touch body.hlh-playing .hlh-fire-row,
html.hlh-touch body.hlh-playing .hlh-legend { width: 100%; max-width: none; }

@media (max-width: 480px) {
  .hlh-hint { text-align: left; width: 100%; }
  .hlh-legend { font-size: 0.72rem; gap: 0.3rem 0.7rem; }
}
