/* ============================================================================
   Shared stylesheet - originally built for learn/, copied here (per the
   brief: eLines inherits the trio's color scheme, styles and font, with
   one deliberate exception - the game grid/balls get their own visual
   treatment, not the dark card-based phonics look) so this app matches
   learn/'s and study/'s chrome, logo treatment, and copyright footer
   exactly. Structural variables, fonts, colors and the card-based layout
   are lifted directly from read_guide.html's own premium dark-mode
   design (via learn/assets/style.css). The bottom of this file adds
   eLines-only components (mode picker, split game layout, the grid/ball
   renderer, control panel, dynamic input zone) not used by learn/study.
   ============================================================================ */

:root {
  /* -- read_guide.html's own palette, verbatim (shared app chrome) -- */
  --bg-color: #232323;
  --card-color: #1d1d1d;
  --exception-bg: #161616;
  --electric-yellow: #e6c27a;
  --hot-pink: #FF2E88;
  --light-gray: #D8D8D8;
  --darker-gray: #888888;

  --ease: cubic-bezier(0.4, 0, 0.2, 1);

  /* -- borrowed from learn/'s functional palette: the board is the same
     off-black "stage" tone, and the mic accent reuses the same connector
     blue learn/'s engine uses - one shared accent language, not a
     separate eLines-only one. -- */
  --stage-bg: #0A0A0A;
  --connector: #80D8FF;
}

* { box-sizing: border-box; margin: 0; padding: 0; }

body {
  background-color: var(--bg-color);
  color: var(--light-gray);
  font-family: Verdana, Geneva, sans-serif;
  line-height: 1.6;
  min-height: 100vh;
}

/* game.html's header is compact on purpose (no logo, tighter padding
   than index.html's) - matching study/'s own in-game pages, which drop
   the logo from the header entirely (it only reappears in their pause
   overlay) - and because vertical space here is genuinely scarce, going
   straight to the fixed-height game-shell below. */
.game-body header.app-header {
  padding: 10px 20px;
}

/* game.html only: a real fixed-viewport flex column (header, then the
   game-shell filling everything left over), instead of a scrolling page
   with .game-shell's height guessed via calc(100vh - <header px>). That
   guess broke the moment the header's actual height changed (e.g. when
   the back-link moved under the title, making it taller) - this doesn't
   need to know the header's height at all, so it can't drift out of
   sync with it again. */
body.game-body {
  min-height: 0;
  height: 100vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

a { color: inherit; }

/* ---------------------------------------------------------------------------
   Header (shared: mode-select screen, guide pages)
   ------------------------------------------------------------------------- */
header.app-header {
  position: sticky;
  top: 0;
  background-color: rgba(18, 18, 18, 0.95);
  backdrop-filter: blur(5px);
  border-bottom: 2px solid var(--card-color);
  padding: 15px 20px;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 10px;
}

header.app-header h1 {
  color: var(--electric-yellow);
  font-size: 1.4rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.back-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background-color: var(--card-color);
  color: var(--light-gray);
  padding: 7px 16px;
  border-radius: 20px;
  text-decoration: none;
  font-size: 0.85rem;
  font-weight: 700;
  border: 1px solid #333;
  transition: background 0.2s, color 0.2s;
}
.back-link:hover { background-color: var(--electric-yellow); color: #121212; }

.header-title {
  display: flex;
  align-items: center;
  gap: 12px;
}

.logo-link {
  display: inline-flex;
  border-radius: 50%;
  line-height: 0;
  flex-shrink: 0;
  transition: transform 0.2s var(--ease);
}
.logo-link:hover { transform: scale(1.06); }

.logo-img {
  width: 56px; /* matches study/index.html - learn/'s base logo-img is 38px */
  height: 56px;
  border-radius: 50%;
  display: block;
  object-fit: cover;
}

.site-footer {
  text-align: center;
  color: var(--darker-gray);
  font-size: 0.8rem;
  padding: 20px 20px 20px;
  letter-spacing: 0.02em;
}

main {
  max-width: 900px;
  margin: 30px auto;
  padding: 0 20px;
}

.page-intro {
  color: var(--darker-gray);
  font-size: 0.95rem;
  margin-bottom: 24px;
}

/* ---------------------------------------------------------------------------
   Mode-select screen (index.html) - modeled on learn/study's start-screen
   card grid, since it's the same "pick one, then Go" shape.
   ------------------------------------------------------------------------- */

/* Copied from learn/'s base (was missing here entirely - index.html's
   "Resume Session" button had no styling at all until now, a real gap
   caught while doubling font sizes across this page). */
.resume-btn {
  margin: 16px auto 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  background-color: var(--electric-yellow);
  color: #121212;
  font-family: inherit;
  font-weight: 800;
  font-size: 1rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 8px 18px;
  border: none;
  border-radius: 24px;
  cursor: pointer;
  transition: transform 0.2s var(--ease), box-shadow 0.2s var(--ease);
  box-shadow: 0 0 0 rgba(247, 240, 0, 0);
}
.resume-btn:hover:not(:disabled) {
  transform: translateY(-2px);
  box-shadow: 0 6px 24px rgba(247, 240, 0, 0.25);
}
.resume-btn:disabled {
  background-color: var(--card-color);
  color: var(--darker-gray);
  cursor: default;
}

.mode-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 18px;
  margin-top: 12px;
}

.mode-card {
  background-color: var(--card-color);
  border: 1px solid #252525;
  border-radius: 10px;
  padding: 22px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  transition: border-color 0.25s var(--ease), transform 0.25s var(--ease);
}
.mode-card:hover { border-color: #3a3a3a; transform: translateY(-2px); }

.mode-card .mode-title {
  color: white;
  font-size: 1.3rem;
  font-weight: 800;
  letter-spacing: 0.01em;
}

.mode-card .mode-desc {
  color: var(--darker-gray);
  font-size: 1.15rem;
  line-height: 1.5;
  flex-grow: 1;
}

.mode-card .go-btn {
  font-family: inherit;
  font-weight: 800;
  font-size: 1rem;
  border-radius: 20px;
  border: none;
  cursor: pointer;
  padding: 10px 0;
  text-decoration: none;
  text-align: center;
  background-color: var(--electric-yellow);
  color: #121212;
  transition: transform 0.15s var(--ease), opacity 0.15s var(--ease);
}
.mode-card .go-btn:hover { transform: translateY(-1px); opacity: 0.92; }

/* ---------------------------------------------------------------------------
   Rule cards (guide/reference pages) - copied verbatim from learn/, so the
   guide/ pages this app shares with learn/study render identically.
   ------------------------------------------------------------------------- */
.section-title {
  color: white;
  font-size: 1.4rem;
  margin: 35px 0 15px 0;
  border-left: 4px solid var(--electric-yellow);
  padding-left: 10px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}
.section-title:first-child { margin-top: 0; }

.rule-card {
  background-color: var(--card-color);
  border-radius: 8px;
  margin-bottom: 16px;
  overflow: hidden;
  border: 1px solid #252525;
}

.card-header {
  padding: 18px 20px;
  cursor: pointer;
  display: flex;
  justify-content: space-between;
  align-items: center;
  user-select: none;
  background-color: #222222;
}

.pattern-visual {
  font-size: 1.25rem;
  font-weight: 800;
  color: var(--electric-yellow);
  letter-spacing: 0.05em;
}

.header-meta { display: flex; align-items: center; gap: 12px; }

.badge {
  font-size: 0.75rem;
  font-weight: 800;
  padding: 3px 8px;
  border-radius: 4px;
  text-transform: uppercase;
}
.badge-5 { background-color: #2b7a3e; color: #e2f7e6; }
.badge-4 { background-color: #3b6b8c; color: #e6f2fc; }
.badge-3 { background-color: #8c763b; color: #fcf6e6; }
.badge-2 { background-color: #8c4f3b; color: #fcebe6; }
.badge-1 { background-color: #7d2c2c; color: #fce8e8; }

.arrow { font-size: 0.8rem; transition: transform 0.3s; color: var(--darker-gray); }
.rule-card.active .arrow { transform: rotate(180deg); }

.card-body { padding: 20px; display: none; border-top: 1px solid #2a2a2a; }
.rule-card.active .card-body { display: block; }

.explanation { font-size: 0.95rem; margin-bottom: 15px; color: #c8c8c8; }

.chip-group-title {
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--darker-gray);
  margin-bottom: 6px;
  font-weight: 600;
}

.chips-container { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 18px; }

.word-chip {
  background-color: #2a2a2a;
  color: white;
  padding: 6px 14px;
  border-radius: 20px;
  font-size: 0.95rem;
  font-weight: 600;
  border: 1px solid #3a3a3a;
}

.exception-panel {
  background-color: var(--exception-bg);
  border-left: 4px solid var(--hot-pink);
  border-top: 1px solid #25121a;
  border-right: 1px solid #25121a;
  border-bottom: 1px solid #25121a;
  padding: 12px 16px;
  border-radius: 0 6px 6px 0;
  font-style: italic;
}

.exception-title {
  color: var(--hot-pink);
  font-size: 0.8rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-bottom: 6px;
  font-style: normal;
}

.exception-words { color: #e0b3c5; }

.global-controls { display: flex; justify-content: flex-end; gap: 10px; margin-bottom: 10px; }

.control-btn {
  background: none;
  border: 1px solid #444;
  color: var(--darker-gray);
  padding: 4px 10px;
  border-radius: 4px;
  cursor: pointer;
  font-size: 0.75rem;
  font-family: inherit;
}
.control-btn:hover { color: white; border-color: #666; }

.icon-btn {
  width: 42px;
  height: 42px;
  border-radius: 50%;
  border: 1px solid #333;
  background-color: rgba(29, 29, 29, 0.9);
  backdrop-filter: blur(4px);
  color: var(--light-gray);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: border-color 0.2s var(--ease), color 0.2s var(--ease), transform 0.15s var(--ease);
}
.icon-btn:hover { border-color: var(--electric-yellow); color: var(--electric-yellow); transform: translateY(-1px); }
.icon-btn:active { transform: scale(0.94); }
.icon-btn svg { width: 18px; height: 18px; fill: currentColor; }

.no-results { display: none; text-align: center; padding: 40px; color: var(--darker-gray); }

/* Score block: 4 icon-first controls in a row - the score itself styled
   like a digital clock/counter display (no "Score" label anymore - the
   other 3 are icon-only buttons, per instruction, so the label would be
   the odd one out), then Rules / Pause-Resume / Close. */
.score-block {
  display: flex;
  align-items: center;
  gap: 8px;
}
.digital-score {
  flex: 1 1 auto;
  display: flex;
  justify-content: center;
  gap: 4px;
  background: #0d0d0d;
  border: 1px solid #262626;
  border-radius: 8px;
  padding: 6px 8px;
}
/* Each digit its own square tile - separate LED-style cells, like a
   real electronic clock/calculator display, rather than one flowing
   string of characters. */
.score-digit {
  display: flex;
  align-items: center;
  justify-content: center;
  aspect-ratio: 1 / 1;
  height: 100%;
  min-width: 1.1em;
  font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', monospace;
  font-variant-numeric: tabular-nums;
  font-weight: 800;
  font-size: 3.24rem;
  color: #ffffff;
  background: #1a1a1a;
  border-radius: 4px;
  text-shadow: 0 0 6px rgba(255, 255, 255, 0.4);
}
.score-block .icon-btn { flex-shrink: 0; }

#pause-btn.paused-state { border-color: var(--electric-yellow); color: var(--electric-yellow); }

/* ============================================================================
   eLines-only from here down: the fixed split game layout, the grid/ball
   renderer, control panel and dynamic input zone. The grid is now the
   SAME off-black theme as the rest of the app (not the light contrast
   panel an earlier pass used) - only the balls carry color, everything
   else stays in the shared dark palette. Cell borders are dashed light
   lines - "chalk on a blackboard" - rather than solid hairlines.
   ============================================================================ */

/* Section 5 of eLines_specs.html: fixed, non-scrolling split layout.
   flex:1 fills whatever space body.game-body's column has left after
   the header - no hardcoded header height to keep in sync. min-height:0
   overrides the flex default (min-height:auto), which would otherwise
   let this grow taller than its share to fit its children's content
   instead of respecting the fixed allocation - exactly what caused the
   sidebar/grid height mismatch this replaces. max-width/margin reset
   the generic `main` selector above (900px, centered - meant for
   index.html/guide pages) that was otherwise still winning for any
   property .game-shell didn't explicitly set of its own, since a class
   selector only overrides an element selector for the properties it
   actually declares - this silently caged the whole game-shell into a
   narrow centered column and was the real cause of "too much empty
   space everywhere. */
.game-shell {
  max-width: none;
  margin: 0;
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  gap: 16px;
  padding: 16px;
  overflow: hidden;
}
.game-shell.menu-hidden .control-panel { display: none; }
.game-shell.menu-hidden .board-wrap { flex: 1 1 100%; }

.board-wrap {
  flex: 0 0 70%;
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 0;
  min-height: 0;
}

/* The frame (background/border/radius) lives on .board itself, not
   .board-wrap - the wrap is only sized 70% of the shell's width, but the
   square board is capped at 78vh, so on most viewports width is the
   binding constraint and the board's rendered height is shorter than
   the wrap's full height. A border on the wrap would then float away
   from the grid's actual top/bottom edges (looking present on the
   left/right, where the grid does reach the wrap's edge, but missing on
   top/bottom, where it doesn't) - putting the frame on .board instead
   means it always hugs the grid tightly on all four sides. */
.board {
  display: grid;
  grid-template-columns: repeat(9, 1fr);
  grid-template-rows: repeat(9, 1fr);
  gap: 4px;
  width: min(100%, 78vh);
  aspect-ratio: 1 / 1;
  position: relative; /* anchors the traveling-ball animation layer */
  background: var(--stage-bg);
  border: 1px solid var(--card-color);
  border-radius: 12px;
  padding: 12px;
}

.cell {
  background: #161616;
  border: 1px dashed rgba(255, 255, 255, 0.22);
  border-radius: 4px;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  cursor: pointer;
}

.ball {
  width: 78%;
  height: 78%;
  border-radius: 50%;
  background: var(--ball-color);
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
  pointer-events: none;
}
.ball.selected { animation: ball-bounce 0.6s var(--ease) infinite; }
.ball.spawning { animation: ball-drop 0.5s cubic-bezier(0.34, 1.56, 0.64, 1); }
.ball.arriving { animation: ball-settle 0.4s var(--ease); }
.ball.clearing { animation: ball-clear 0.32s var(--ease) forwards; }

.traveling-ball {
  position: absolute;
  border-radius: 50%;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
  pointer-events: none;
  z-index: 50;
}

@keyframes ball-bounce {
  0%, 100% { transform: translateY(0) scale(1); }
  50% { transform: translateY(-18%) scale(0.94); }
}
/* A dropped-in ball, not a scale-fade pop: falls from above, overshoots
   on landing, and settles - "drops like it has weight" rather than
   materializing instantly. */
@keyframes ball-drop {
  0% { transform: translateY(-140%) scale(0.9); opacity: 0; }
  55% { transform: translateY(0) scale(1); opacity: 1; }
  72% { transform: translateY(-14%) scale(0.97); }
  86% { transform: translateY(4%) scale(1.02); }
  100% { transform: translateY(0) scale(1); }
}
/* A moved ball landing in its new tile after traveling there - a quick
   squash-and-stretch, distinct from the drop-in above. */
@keyframes ball-settle {
  0% { transform: scale(1.15, 0.85); }
  50% { transform: scale(0.92, 1.08); }
  100% { transform: scale(1, 1); }
}
@keyframes ball-clear {
  to { transform: scale(1.5); opacity: 0; }
}

/* -- Control panel (30% width) -- */
.control-panel {
  flex: 0 0 30%;
  display: flex;
  flex-direction: column;
  gap: 12px;
  min-width: 0;
  min-height: 0; /* without this, .pattern-key's flex:1 has no real ceiling to grow against */
  overflow-y: auto;
}

.panel-box {
  background: var(--card-color);
  border: 1px solid #252525;
  color: var(--light-gray);
  border-radius: 12px;
  padding: 10px 14px;
}

/* Outer panel-box: holds the scrollable rows list plus a fixed
   copyright footer that survives renderPatternKey()'s re-population of
   #pattern-key-list (a static sibling, not wiped by innerHTML resets). */
.pattern-key-panel {
  display: flex;
  flex-direction: column;
  gap: 4px;
  flex: 1 1 auto; /* fills remaining panel height, matching the grid's height */
  max-height: 80%; /* cut 15%, then another 5%, per instructions */
  min-height: 0;
}
.pattern-key {
  display: flex;
  flex-direction: column;
  gap: 3px;
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  justify-content: center; /* compact rows center nicely if there's any leftover slack */
}
.legend-copyright {
  flex-shrink: 0;
  text-align: center;
  color: var(--darker-gray);
  font-size: 1.05rem;
  padding-top: 4px;
  border-top: 1px solid #252525;
}
.pattern-key-row {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 1.368rem;
  line-height: 1.3;
  opacity: 1;
}
.pattern-key-row.inactive { opacity: 0.35; }
.pattern-key-row .key-dot {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  flex-shrink: 0;
  background: var(--ball-color);
}
.pattern-key-row .key-label { flex-grow: 1; }
.pattern-key-row .key-help {
  width: 25px;
  height: 25px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  border: 1px solid #444;
  background: none;
  color: var(--darker-gray);
  font-size: 1.08rem;
  font-weight: 800;
  text-decoration: none;
  cursor: pointer;
  flex-shrink: 0;
}
.pattern-key-row .key-help:hover { border-color: var(--electric-yellow); color: var(--electric-yellow); }

.input-zone { display: flex; flex-direction: column; gap: 10px; }
.input-zone .prompt { font-size: 1.53rem; color: var(--light-gray); min-height: 2.6em; }
.input-zone .prompt .prompt-pattern { font-weight: 800; color: var(--electric-yellow); }
.input-widget { display: none; }
.input-widget.visible { display: block; }
.input-zone input[type="text"] {
  font-family: inherit;
  font-size: 1.8rem;
  padding: 10px 12px;
  border-radius: 8px;
  border: 1px solid #333;
  background: #0d0d0d;
  color: var(--light-gray);
  width: 100%;
}
.input-zone input[type="text"]:disabled { background: #1a1a1a; color: var(--darker-gray); }

.mic-btn {
  font-family: inherit;
  font-weight: 800;
  font-size: 1.62rem;
  padding: 10px 0;
  border-radius: 20px;
  border: none;
  background: var(--connector);
  color: #0d0d0d;
  cursor: pointer;
  width: 100%;
}
.mic-btn.listening { background: var(--hot-pink); color: white; animation: mic-pulse 1s var(--ease) infinite; }
@keyframes mic-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(255, 46, 136, 0.5); }
  50% { box-shadow: 0 0 0 8px rgba(255, 46, 136, 0); }
}

/* The armed-ball prompt ("MOVE!") - replaces a reachable-tile board
   highlight entirely; a punchy flashing label is the only cue. */
.move-flash {
  text-align: center;
  font-size: 2.88rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--electric-yellow);
  animation: move-flash-pulse 0.9s var(--ease) infinite;
}
@keyframes move-flash-pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: 0.55; transform: scale(1.06); }
}

.input-warning {
  font-size: 1.404rem;
  color: var(--hot-pink);
  min-height: 1.2em;
}

/* Session-locked overlay (Brain Melt hard timer, board full, manual stop) */
#session-lock-overlay {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(10, 10, 10, 0.9);
  backdrop-filter: blur(6px);
  z-index: 1050;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 12px;
  text-align: center;
}
#session-lock-overlay.visible { display: flex; }
#session-lock-overlay .locked-label {
  color: var(--electric-yellow);
  font-size: 2.88rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
#session-lock-overlay .locked-summary { color: var(--darker-gray); font-size: 1.71rem; max-width: 420px; }

/* Pause overlay - a genuine pause, not just navigating away: blocks
   board interaction and stops the (invisible) session clock from
   ticking while shown. */
#pause-overlay {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(10, 10, 10, 0.9);
  backdrop-filter: blur(6px);
  z-index: 1060;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 18px;
}
#pause-overlay.visible { display: flex; }
.pause-logo-img {
  width: 64px;
  height: 64px;
  box-shadow: 0 3px 16px rgba(0, 0, 0, 0.4);
  transition: transform 0.2s var(--ease);
}
#pause-logo-link:hover .pause-logo-img { transform: scale(1.06); }
#pause-overlay .paused-label {
  color: var(--electric-yellow);
  font-size: 2.88rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
.resume-btn-overlay {
  width: 64px;
  height: 64px;
  border-color: var(--electric-yellow);
  color: var(--electric-yellow);
}
.resume-btn-overlay svg { width: 26px; height: 26px; }

/* Rules overlay - the Color Lines game rules (how selection/movement/
   scoring work), distinct from the per-pattern phonics guide the "?"
   buttons open. Plain in-page content, not an <iframe> - no risk of the
   mobile-breakpoint bug the guide modal had, since there's no embedded
   page here to squeeze. */
#rules-overlay {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(10, 10, 10, 0.85);
  backdrop-filter: blur(4px);
  z-index: 1060;
  align-items: center;
  justify-content: center;
  padding: 40px;
}
#rules-overlay.visible { display: flex; }
.rules-box {
  position: relative;
  background: var(--bg-color);
  border: 1px solid var(--card-color);
  border-radius: 12px;
  padding: 32px;
  max-width: 560px;
  max-height: 100%;
  overflow-y: auto;
}
.rules-box h2 {
  color: var(--electric-yellow);
  font-size: 2.07rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin-bottom: 16px;
}
.rules-box ol {
  padding-left: 22px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.rules-box li { font-size: 1.53rem; line-height: 1.5; }
.rules-close {
  position: absolute;
  top: 16px;
  right: 16px;
}

/* Guide "?" lookup: a plain same-tab link to guide/<id>.html, exactly
   like learn/'s and study/'s own "?" buttons - not a modal (an earlier
   pass tried an <iframe> overlay; it rendered the guide page cramped
   into mobile breakpoints and wasn't what "should work like in study and
   learn" meant). Navigating away triggers the existing beforeunload
   persist handler, so the game state is saved (not lost) - functionally
   a pause. The guide page's own Back link goes to index.html (its
   own "Back" always did, even in learn/study - that's what its shared
   template does), and Resume Session picks the same game back up from
   there - see README's "Sessions vs. the game" section. */

@media (max-width: 900px) {
  .game-shell { flex-direction: column; height: auto; overflow: visible; }
  .board-wrap, .control-panel { flex: 1 1 auto; }
  .mode-grid { grid-template-columns: 1fr; }
}
