:root {
  --cell: 30px;
  --rowclue: 66px;
  --colclue: 66px;
  --clue-font: 13px;
  --cell-gap: 3px;         /* space between rounded cells */

  --bg: #ffffff;
  --ink: #33404f;          /* dark text */
  --title: #2a2550;
  --blue: #5a49d6;         /* accent: icons, toggles, filled cells, brand (darker purple) */
  --blue-hi: #1fa8ff;      /* gradient start (matches the app icon) */
  --blue-lo: #6f5af0;      /* gradient end */
  --page-bg: linear-gradient(180deg, #ffffff 0%, #eef0fb 100%);
  --cell-empty: #e7edf9;   /* empty rounded cell */
  --sep: #b0b6c2; /* dashed group divider, light gray */
  --group-gap: 6px; /* padding between blocks of cells (holds the dashed divider) */
  --clue-ink: #9aa0b2;     /* clue numbers (soft, light gray) */
  --clue-done: #c9c9d6;
  --cross: #48506a;        /* X mark */
  --hl: rgba(106, 92, 240, 0.13);
  --heart: #f5333f;
  --heart-lost: #dbd8ec;
  --panel: #eeecf8;
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }

html, body {
  margin: 0;
  min-height: 100%;
  /* Same full-screen backdrop as the menu, so the menu and game screens match. */
  background: var(--page-bg);
  background-attachment: fixed;
  color: var(--ink);
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
}

/* Text is selectable everywhere by default; only the board and controls opt out,
   where a drag/tap must not begin a text selection. */
.board, .toolbar, .endbar, .diff-select, .avatar, button {
  -webkit-user-select: none;
  user-select: none;
}

/* --- Main menu page --- */
.menu-page {
  position: fixed;
  inset: 0;
  z-index: 15;
  display: flex;
  padding: 24px;
  overflow-y: auto; /* the signed-in stats panel can make the menu taller than the viewport */
  background: var(--page-bg);
}
.menu-page.hidden { display: none; }
#appPage.hidden { display: none; }
/* First-paint view, set by the inline head script (removed once game.js boots). */
.boot-menu #appPage { display: none; }
.boot-puzzle #mainMenu { display: none; }

/* One-shot loading splash over the first paint (see game.js hideSplash). Covers the
   menu/app until the home is assembled, then fades out and is never shown again. */
.splash {
  position: fixed; inset: 0; z-index: 1000;
  display: flex; align-items: center; justify-content: center;
  background: var(--bg);
  transition: opacity 0.25s ease;
}
.splash.gone { opacity: 0; pointer-events: none; }
.splash-spin {
  width: 44px; height: 44px; border-radius: 50%;
  border: 4px solid var(--panel);
  border-top-color: var(--blue);
  animation: splash-spin 0.8s linear infinite;
}
@keyframes splash-spin { to { transform: rotate(360deg); } }
.menu-inner {
  margin: auto; /* centers, but degrades to top-aligned + scrollable when taller than the page */
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
  max-width: 360px;
  text-align: center;
}
.hero-logo {
  width: 128px;
  height: auto;
  filter: drop-shadow(0 12px 24px rgba(106, 92, 240, 0.32));
}
.brand {
  font-size: 30px;
  font-weight: 800;
  letter-spacing: 0.5px;
  color: var(--blue);
  margin: 12px 0 40px;
}

/* Signed-in home: a 3-column grid of personal stat tiles. */
.menu-stats { width: 100%; margin-top: 24px; }
.menu-stats.hidden { display: none; }
.ms-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.ms-tile { background: var(--panel); border-radius: 12px; padding: 11px 6px; }
.ms-val { font-size: 20px; font-weight: 800; color: var(--blue); font-variant-numeric: tabular-nums; line-height: 1.1; }
.ms-label { font-size: 11px; font-weight: 600; color: #8a90a2; margin-top: 3px; }
.btn.big-blue {
  width: 100%;
  font-size: 17px;
  font-weight: 800;
  padding: 15px;
  border-radius: 13px;
  /* Wide 3-stop gradient so shifting its position reads as a moving gradient. */
  background-image: linear-gradient(120deg, var(--blue-hi), var(--blue-lo), var(--blue-hi));
  background-size: 220% 100%;
  background-position: 0% 50%;
  border: 0;
  color: #fff;
  box-shadow: 0 8px 22px rgba(106, 92, 240, 0.38);
  transition: background-position 0.5s ease;
}
/* Keep the gradient on hover (beat the generic .btn:hover) and animate it. */
.btn.big-blue:hover {
  background-image: linear-gradient(120deg, var(--blue-hi), var(--blue-lo), var(--blue-hi));
  background-size: 220% 100%;
  animation: big-blue-sweep 2.6s ease-in-out infinite;
}
@keyframes big-blue-sweep {
  0%, 100% { background-position: 0% 50%; }
  50% { background-position: 100% 50%; }
}
/* Secondary buttons: outline only, primary-colored text. */
.btn.secondary {
  width: 100%;
  background: transparent;
  border: 1.5px solid var(--blue);
  color: var(--blue);
  font-weight: 700;
  font-size: 15px;
  padding: 10px 13px;
  border-radius: 13px;
  margin-top: 8px;
  transition: background 0.2s ease;
}
.btn.secondary:hover { background: rgba(90, 73, 214, 0.08); color: var(--blue); }
/* First secondary sits under the primary button; give it a touch more room. */
.btn.big-blue + .btn.secondary { margin-top: 11px; }

/* Primary CTA row: Play Daily and/or Resume. One button fills the row; two split
   it 50/50 side by side. Hidden entirely when neither applies. */
.cta-row { display: flex; width: 100%; gap: 10px; }
.cta-row[hidden] { display: none; }
.cta-row .btn.big-blue { flex: 1; width: auto; min-width: 0; margin: 0; font-size: 15px; padding: 10px 8px; white-space: nowrap; border-radius: 50px; }
/* Two-line CTA (Resume Puzzle + which puzzle). */
.cta-title { display: block; }
.cta-sub { display: block; font-size: 12px; font-weight: 500; opacity: 0.85; margin-top: 1px; overflow: hidden; text-overflow: ellipsis; }
.cta-sub:empty { display: none; }

/* New Puzzle split button: a main action + a difficulty caret, joined. */
.split-wrap { position: relative; width: 100%; margin-top: 8px; }
.cta-row + .split-wrap { margin-top: 11px; }
.split-btn { display: flex; width: 100%; }
.split-main, .split-caret {
  background: transparent;
  border: 1.5px solid var(--blue);
  color: var(--blue);
  transition: background 0.2s ease;
}
.split-main {
  flex: 1; cursor: pointer;
  display: flex; flex-direction: column; align-items: center; gap: 1px;
  /* Left padding = right padding + caret width, so the label centers over the
     WHOLE button (caret section included), not just the main part. */
  padding: 10px 15px 10px calc(15px + 46px);
  border-right: 0;
  border-radius: 13px 0 0 13px;
  text-align: center;
}
.split-main-title { font-weight: 700; font-size: 15px; }
.split-main-sub { font-weight: 600; font-size: 12px; opacity: 0.65; }
.split-caret { width: 46px; cursor: pointer; border-radius: 0 13px 13px 0; display: flex; align-items: center; justify-content: center; }
.split-caret svg { width: 18px; height: 18px; }
.split-main:hover, .split-caret:hover { background: rgba(90, 73, 214, 0.08); }
/* When it's the only call to action (daily done, nothing to resume), New Puzzle
   becomes the big-blue primary. The gradient is painted on the CONTAINER so it
   spans both segments as one background, and sweeps on hover -- same as
   .btn.big-blue. The two segments go transparent to let it show through. */
.split-wrap.primary .split-btn {
  border-radius: 13px;
  box-shadow: 0 8px 22px rgba(106, 92, 240, 0.38);
  background-image: linear-gradient(120deg, var(--blue-hi), var(--blue-lo), var(--blue-hi));
  background-size: 220% 100%; background-position: 0% 50%;
  transition: background-position 0.5s ease;
}
.split-wrap.primary .split-btn:hover { animation: big-blue-sweep 2.6s ease-in-out infinite; }
.split-wrap.primary .split-main,
.split-wrap.primary .split-caret { border-color: transparent; background: transparent; color: #fff; }
.split-wrap.primary .split-caret { border-left: 1.5px solid rgba(255, 255, 255, 0.3); }
.split-wrap.primary .split-main-sub { opacity: 0.8; }
.split-wrap.primary .split-main:hover, .split-wrap.primary .split-caret:hover { background: transparent; }
/* Difficulty dropdown, anchored under the caret. */
.diff-dropdown {
  position: absolute; top: calc(100% + 6px); right: 0; z-index: 60;
  min-width: 150px;
  background: var(--bg);
  border: 1.5px solid var(--blue);
  border-radius: 12px;
  box-shadow: 0 10px 26px rgba(0, 0, 0, 0.14);
  overflow: hidden;
}
.diff-dropdown.hidden { display: none; }
.diff-dropdown-opt {
  display: block; width: 100%; text-align: left;
  padding: 11px 15px; background: transparent; border: 0;
  color: var(--title); font-weight: 600; font-size: 14px;
}
.diff-dropdown-opt::before { content: ""; display: inline-block; width: 18px; }
.diff-dropdown-opt.selected::before { content: "\2713"; color: var(--blue); font-weight: 800; }
.diff-dropdown-opt:hover { background: rgba(90, 73, 214, 0.08); }
.diff-dropdown-opt.selected { color: var(--blue); font-weight: 800; }

/* Difficulty selector: a three-way segmented control (main menu + end screen). */
.diff-select {
  position: relative;
  display: inline-flex;
  gap: 4px;
  padding: 4px;
  margin: 0 auto 4px;
  background: var(--panel);
  border-radius: 999px;
  touch-action: manipulation;
}
/* Sliding white thumb -- same feel as the fill/cross toggle. Its position/width
   are set per-instance in JS (renderDiffSelectors) so it fits each segment. */
.diff-select::before {
  content: "";
  position: absolute;
  top: 4px;
  bottom: 4px;
  left: 0;
  width: var(--thumb-w, 0);
  transform: translateX(var(--thumb-x, 0));
  background: #fff;
  border-radius: 999px;
  box-shadow: 0 2px 6px rgba(30, 42, 56, 0.18);
  transition: transform 0.2s cubic-bezier(0.34, 1.3, 0.5, 1), width 0.2s cubic-bezier(0.34, 1.3, 0.5, 1);
}
.diff-select.no-thumb-anim::before { transition: none; } /* skip the slide on first show */
.diff-opt {
  position: relative;
  z-index: 1;
  border: 0;
  background: transparent;
  border-radius: 999px;
  padding: 8px 18px;
  font: inherit;
  font-size: 14px;
  font-weight: 700;
  color: #7c8695;
  cursor: pointer;
  transition: color 0.2s ease;
}
.diff-opt.active { color: var(--blue); }
/* Compact, right-aligned inside a Settings row. */
.setting-row .diff-select { margin: 0; padding: 3px; }
.setting-row .diff-select::before { top: 3px; bottom: 3px; }
.setting-row .diff-opt { padding: 6px 12px; font-size: 13px; }

/* Difficulty control inside the burger popup: a full-width segmented row.
   Equal top/bottom margin so it sits symmetrically between its two dividers. */
.menu-diff { display: flex; margin: 4px 8px; padding: 3px; }
.menu-diff::before { top: 3px; bottom: 3px; }
.menu-diff .diff-opt { flex: 1; padding: 6px 10px; font-size: 13px; }

/* Promotion nudge: a fixed toast so it never affects the board layout. */
.promo-banner {
  position: fixed;
  top: 64px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 60;
  width: calc(100% - 32px);
  max-width: 340px;
  padding: 12px 16px;
  border-radius: 14px;
  background: #eef6ff;
  border: 1px solid #cfe0f5;
  box-shadow: 0 10px 28px rgba(30, 42, 56, 0.2);
  color: #2f4a6b;
  font-size: 13.5px;
  font-weight: 600;
  line-height: 1.4;
  text-align: center;
}
.promo-banner.hidden { display: none; }

/* Full-screen like the menu: transparent over the page gradient, with the header
   spanning the whole width so back/burger sit at the true screen corners. The
   board, lives and toolbar center themselves within it. */
.app {
  min-height: 100vh;
  min-height: 100dvh; /* dvh tracks the visible viewport so mobile browser chrome
                         does not cut off the bottom toolbar (e.g. Firefox) */
  display: flex;
  flex-direction: column;
  padding: 8px 6px calc(16px + env(safe-area-inset-bottom, 0px));
}

/* --- Header --- */
.topbar {
  display: grid;
  grid-template-columns: 40px 1fr 40px;
  align-items: center;
  padding: 6px 8px 10px; /* keep the buttons off the edge; the board (in .stage) still gets the width */
  position: relative;
  z-index: 45; /* stays above the result overlay so back/menu remain usable */
}
.titlewrap {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  line-height: 1.1;
}
.title {
  margin: 0;
  text-align: center;
  font-size: 20px;
  font-weight: 700;
  color: var(--title);
}
/* Name + size chip on one centered line ("Heart [5x5]"). */
.titlerow {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
}
/* Tier + board size ("Hard . 9x9"), deliberately quieter than the name.
   Hidden while empty (before a puzzle is open). */
.tier-chip {
  font-size: 11px;
  font-weight: 600;
  color: #8e7f76;
  background: rgba(142, 127, 118, 0.14);
  padding: 1px 7px;
  border-radius: 999px;
  white-space: nowrap;
}
.tier-chip:empty { display: none; }
/* Subtitle line: lives . timer */
.substat {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  margin-top: 3px;
}
.substat-dot { color: #9aa4b0; font-weight: 700; }
/* --- Result panel: a "Solved!" celebration on a win, a "Game Over" card on a loss.
   It sits IN the stage where the board was (the board is hidden while it shows), on
   the same study background -- not a dimmed modal over the board. --- */
.result-overlay {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 100%;
  /* Above the game-over ghost board and the die-veil (z 30); below the
     topbar/endbar (z 45). */
  position: relative;
  z-index: 40;
}
.result-overlay.hidden { display: none; }
.result-overlay .result-win, .result-overlay .result-over { display: none; }
.result-overlay.win .result-win { display: flex; }
.result-overlay.over .result-over { display: flex; }
.result-emoji { font-size: 76px; line-height: 1; }
.result-word { font-size: 40px; font-weight: 800; color: var(--title); }

/* Win: the card pops in and stays (persistent placement + leaderboard). */
.result-overlay.win { animation: result-fadein 0.3s ease both; }
.result-win { flex-direction: column; align-items: center; gap: 4px; animation: result-pop 1.9s ease both; }
@keyframes result-pop {
  0% { transform: scale(0.4); } 12% { transform: scale(1.12); } 26% { transform: scale(1); }
  60% { transform: scale(1); } 72% { transform: scale(1.07); } 84% { transform: scale(1); }
}

/* Game over: the card fades in and stays; its actions live on the bottom bar. */
.result-overlay.over { animation: result-fadein 1s ease both; }
.result-over { flex-direction: column; align-items: center; gap: 2px; }
.result-over .result-emoji { font-size: 50px; }
.result-over .result-word { font-size: 30px; }
@keyframes result-fadein { from { opacity: 0; } to { opacity: 1; } }

/* Hints used so far, shown in the top bar next to the timer (lightbulb emoji). */
.hints-inline { display: inline-flex; align-items: center; gap: 2px; }
.hints-inline svg { width: 13px; height: 13px; }
.hint-full { color: #e6a817; } /* an available hint */
.hint-used { color: var(--heart-lost); } /* a spent hint, grayed like a lost life */
.timer {
  font-size: 14px;
  font-weight: 600;
  color: #9aa4b0;
  letter-spacing: 0.3px;
  font-variant-numeric: tabular-nums;
}
.icon-btn {
  width: 40px;
  height: 40px;
  border: 0;
  background: transparent;
  color: var(--blue);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 10px;
}
.icon-btn:hover { background: #f0f3f8; }
.icon-btn svg { width: 26px; height: 26px; }

/* --- Lives (inline in the subtitle) --- */
.lives-inline { display: inline-flex; align-items: center; gap: 3px; }
.lives-inline svg { width: 14px; height: 14px; }
.heart-full { color: var(--heart); }
.heart-lost { color: var(--heart-lost); }

/* --- Board --- */
/* The board is centered vertically between two equal .board-spacer flex spacers. */
.stage {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  position: relative; /* anchors the game-over ghost board while it cross-fades */
}
.board-spacer { flex: 1; }
.board.hidden { display: none; } /* while the result panel takes the board's place */
.board {
  position: relative; /* dividers are positioned against the board */
  display: grid;
  grid-template-columns: var(--rowclue) repeat(var(--cols), var(--cell));
  grid-template-rows: var(--colclue) repeat(var(--rows), var(--cell));
  /* pinch-zoom lets two fingers zoom the board (solvable on small screens),
     while single-finger drags still reach our paint handlers. */
  touch-action: pinch-zoom;
  align-content: start;
}
/* Dashed 1px group dividers sitting in the gap; they don't affect cell spacing.
   The dashes are painted with a repeating gradient so a 1px line can be dashed. */
.vdiv, .hdiv { position: absolute; pointer-events: none; }
.vdiv {
  top: var(--colclue); bottom: 0; width: 1px; transform: translateX(-0.5px);
  background: repeating-linear-gradient(to bottom, var(--sep) 0 4px, transparent 4px 8px);
}
.hdiv {
  left: var(--rowclue); right: 0; height: 1px; transform: translateY(-0.5px);
  background: repeating-linear-gradient(to right, var(--sep) 0 4px, transparent 4px 8px);
}
/* Brightness fade-in when a board (re)renders. */
.board.fade-in { animation: board-in 0.4s ease; }
/* Game Over in two beats (see onGameOver): first the WHOLE page blurs over 1s
   behind the die-veil (the same 3px backdrop blur the burger menu's sheet
   applies, minus the dark tint) while the "+Ns" flash plays out, then the
   board ghost fades out while the Game Over card fades in above the veil.
   The board fade uses a TRANSITION, not an animation -- the render-time
   .fade-in animation would override at equal specificity. */
.board { position: relative; transition: opacity 1s ease; }
.board.dying { pointer-events: none; }
/* The veil sits above the stage (board + background art) but below the topbar
   and endbar (both z 45, deliberately crisp/usable) and the result overlay
   (z 40). backdrop-filter itself is transitioned -- fading opacity would not
   fade the blur. */
.die-veil {
  position: fixed; inset: 0; z-index: 30; pointer-events: none;
  backdrop-filter: blur(0); -webkit-backdrop-filter: blur(0);
  transition: backdrop-filter 1s ease, -webkit-backdrop-filter 1s ease;
}
.die-veil.show { backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px); }
/* Beat two: the ghost fade (game.js pins the board absolute at its exact spot
   first, so the card can take its place in the flow underneath). */
.board.fading-out { opacity: 0; }
@keyframes board-in {
  from { opacity: 0; filter: brightness(1.7); }
  to { opacity: 1; filter: brightness(1); }
}
.corner { grid-row: 1; grid-column: 1; }

/* Row/column clue numbers (no background). */
.colclue {
  grid-row: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  gap: 1px;
  padding-bottom: 6px;
  color: var(--clue-ink);
  font-size: var(--clue-font);
  font-weight: 700;
  line-height: 1.05;
  font-variant-numeric: tabular-nums;
}
.rowclue {
  grid-column: 1;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 3px;
  padding: 0 4px 0 0;
  color: var(--clue-ink);
  font-size: var(--clue-font);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.colclue.done, .rowclue.done { color: var(--clue-done); }
/* Individual clue digits gray out once they're resolved (forced + filled). */
.colclue .resolved, .rowclue .resolved { color: var(--clue-done); }

/* Cells are rounded chips (like the app icon). A transparent border makes the
   gap; the chip is inset via background-clip, so nothing shifts alignment. */
.cell {
  position: relative;
  border: var(--cell-gap) solid transparent;
  background: var(--cell-empty);
  background-clip: padding-box;
  border-radius: 26%;
  cursor: pointer;
  transition: box-shadow 0.25s ease; /* fade the hover row/column highlight */
}
/* Once the game is won or Game-Over'd the board isn't playable -- drop the pointer. */
.board.solved .cell, .board.over .cell { cursor: default; }
/* Filled cells use the brand accent. */
.cell.filled {
  background: var(--blue);
  background-clip: padding-box;
}
/* Faint 5-block separators, painted into the gap on the block's edge cells. */
.cell.sep-r { border-right-color: var(--sep); }
.cell.sep-b { border-bottom-color: var(--sep); }

/* Cross drawn as two bars -- no font glyph needed. */
.cell.crossed::before,
.cell.crossed::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 16%;
  width: 2px;
  height: 68%;
  margin-left: -1px;
  background: var(--cross);
  border-radius: 1px;
}
.cell.crossed::before { transform: rotate(45deg); }
.cell.crossed::after { transform: rotate(-45deg); }

/* A misclick leaves a red mark so the mistake stays visible: a red cross for a
   wrong fill (auto-crossed), and a red-bordered box for a wrong cross (auto-filled).
   The box keeps its normal fill; the border is an inset ring so nothing shifts. */
.cell.mistake::before,
.cell.mistake::after { background: #e5484d; }
.cell.filled.mistake { box-shadow: inset 0 0 0 2px #e5484d; }

.cell.mistake { animation: flash 0.5s ease-out; }
@keyframes flash {
  0% { box-shadow: inset 0 0 0 100px rgba(231, 76, 60, 0.5); }
  100% { box-shadow: inset 0 0 0 100px rgba(231, 76, 60, 0); }
}

/* Hint: flash the next logical cell a few times, then leave it highlighted in
   yellow for the player to fill in themselves. */
.cell.hint {
  background: #ffe14d;
  animation: hintflash 0.55s ease-out 3;
}
@keyframes hintflash {
  0%, 100% { box-shadow: 0 0 0 0 rgba(240, 190, 0, 0); }
  50% { box-shadow: 0 0 0 4px rgba(240, 190, 0, 0.85); }
}
/* Inside the hinted cell, cycle fill -> cross -> "?" so it doesn't read as a sure
   fill. The "?" fades in last and stays until the player marks the cell. */
.hint-anim { position: absolute; inset: 0; pointer-events: none; }
.hint-glyph {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  color: #6a5a10; /* dark, readable on the yellow highlight */
}
.hint-glyph svg { width: 58%; height: 58%; }
.hint-glyph.g-qmark { font-size: calc(var(--cell, 30px) * 0.62); font-weight: 800; }
.hint-glyph.g-fill { animation: hint-g-fill 1.9s ease forwards; }
.hint-glyph.g-cross { animation: hint-g-cross 1.9s ease forwards; }
.hint-glyph.g-qmark { animation: hint-g-qmark 1.9s ease forwards; }
@keyframes hint-g-fill { 0% { opacity: 0; } 8% { opacity: 1; } 24% { opacity: 1; } 32% { opacity: 0; } 100% { opacity: 0; } }
@keyframes hint-g-cross { 0%, 34% { opacity: 0; } 42% { opacity: 1; } 58% { opacity: 1; } 66% { opacity: 0; } 100% { opacity: 0; } }
@keyframes hint-g-qmark { 0%, 68% { opacity: 0; } 78% { opacity: 1; } 100% { opacity: 1; } }

/* --- Bottom toolbar --- */
/* The toolbar and end bar share one fixed height so swapping the controls for
   the end-of-game buttons never nudges the (centered) board. */
.toolbar, .endbar {
  /* Constant height in both states: the taller end screen (buttons + difficulty
     selector) sets the floor, so swapping toolbar <-> endbar never shifts the
     board up or down. */
  min-height: 124px;
  display: flex;
  justify-content: center;
  padding: 18px 8px 6px;
  position: relative;
  z-index: 45; /* stays above the (persistent) game-over overlay -> crisp buttons */
}
.toolbar { align-items: flex-start; gap: 26px; padding-top: 6px; } /* pull the tools up toward the board */
.toolbar.hidden, .endbar.hidden { display: none; }

/* Tool-switch flash: a big translucent fill/cross in the screen center for ~0.5s
   so the player registers the switch. Never intercepts taps (click-through). */
.tool-flash { position: fixed; inset: 0; z-index: 60; pointer-events: none; }
/* Positioned at the grid's center (--fx/--fy, set in JS from the cells), not the
   viewport center -- the clue gutters would otherwise offset it. */
.tool-flash svg {
  position: absolute; left: var(--fx, 50%); top: var(--fy, 50%);
  width: 38vmin; height: 38vmin; max-width: 300px; max-height: 300px;
  transform: translate(-50%, -50%); opacity: 0;
}
/* Both tool flashes share the cross's ink color -- the blue fill square read as
   a different "kind" of indicator next to the gray X. */
.tool-flash.fill svg { color: var(--cross); }
.tool-flash.cross svg { color: var(--cross); }
.tool-flash.show svg { animation: tool-flash 0.5s ease-out; }
.penalty-flash {
  position: fixed; left: var(--fx, 50%); top: var(--fy, 50%);
  z-index: 60; pointer-events: none;
  transform: translate(-50%, -50%);
  font-size: clamp(34px, 9vmin, 64px); font-weight: 800;
  opacity: 0; white-space: nowrap;
  text-shadow: 0 2px 10px rgba(255, 250, 240, 0.9);
}
.penalty-flash.mistake { color: var(--heart); }
.penalty-flash.hint { color: #b8860b; }
.penalty-flash.show { animation: penalty-flash 0.9s ease-out; }
@keyframes penalty-flash {
  0% { opacity: 0; transform: translate(-50%, -50%) scale(0.6); }
  18% { opacity: 0.95; transform: translate(-50%, -50%) scale(1.05); }
  55% { opacity: 0.9; transform: translate(-50%, -60%) scale(1); }
  100% { opacity: 0; transform: translate(-50%, -85%) scale(1); }
}
@keyframes tool-flash {
  0% { opacity: 0; transform: translate(-50%, -50%) scale(0.6); }
  22% { opacity: 0.5; transform: translate(-50%, -50%) scale(1); }
  100% { opacity: 0; transform: translate(-50%, -50%) scale(1.12); }
}

/* Win confetti overlay: full-screen, never intercepts taps. */
.confetti {
  position: fixed;
  inset: 0;
  width: 100vw;
  height: 100vh;
  pointer-events: none;
  z-index: 50;
}

/* --- End-of-game bar: just the action buttons (the result is in the header).
   Buttons sit a little lower so they clear the board comfortably. --- */
.endbar { flex-direction: column; align-items: center; justify-content: flex-end; gap: 10px; padding-bottom: 12px; }
.endbar .hidden { display: none; }
.endbar-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
}
/* End-of-game buttons mirror the main-menu primary/secondary, kept compact. The
   win card's action row (.won-actions) shares the look -- its Share/Leaderboard
   are the same buttons the bar used to hold. */
.endbar-actions .btn, .won-actions .btn, .boards-share .btn, .menu-daily .btn {
  padding: 10px 16px;
  font-size: 14px;
  font-weight: 700;
  border-radius: 12px;
}
.endbar-actions .btn:not(.primary), .won-actions .btn:not(.primary),
.boards-share .btn:not(.primary), .menu-daily .btn:not(.primary) { /* secondary: purple outline */
  background: transparent;
  border: 1.5px solid var(--blue);
  color: var(--blue);
}
.endbar-actions .btn:not(.primary):hover, .won-actions .btn:not(.primary):hover,
.boards-share .btn:not(.primary):hover, .menu-daily .btn:not(.primary):hover { background: rgba(90, 73, 214, 0.08); color: var(--blue); }
.endbar-actions .btn.primary,
.endbar-actions .btn.primary:hover { /* primary: brand gradient */
  border: 0;
  color: #fff;
  background-image: linear-gradient(120deg, var(--blue-hi), var(--blue-lo), var(--blue-hi));
  background-size: 220% 100%;
  background-position: 0% 50%;
  box-shadow: 0 6px 16px rgba(106, 92, 240, 0.3);
}
.endbar-actions .btn.primary:hover { animation: big-blue-sweep 2.6s ease-in-out infinite; }
/* Icon-only action buttons (Share / Leaderboard): square, centered glyph. Used
   by the end bar and by the win card's own action row (.won-actions). */
.endbar-actions .btn.icon, .won-actions .btn.icon, .boards-share .btn.icon, .menu-daily .btn.icon {
  padding: 10px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.endbar-actions .btn.icon svg, .won-actions .btn.icon svg,
.boards-share .btn.icon svg, .menu-daily .btn.icon svg { width: 20px; height: 20px; display: block; }
.tool-toggle {
  position: relative;
  display: inline-flex;
  background: var(--panel);
  border-radius: 999px;
  padding: 5px;
  gap: 4px;
  /* Kill the mobile double-tap-zoom + ~300ms click delay so rapid Fill/Cross
     switching registers instantly and no tap is swallowed. */
  touch-action: manipulation;
}
/* Sliding white "thumb" that animates between the two options. */
.tool-toggle::before {
  content: "";
  position: absolute;
  top: 5px;
  left: 5px;
  width: 62px;
  height: 46px;
  border-radius: 999px;
  background: #fff;
  box-shadow: 0 2px 6px rgba(30, 42, 56, 0.18);
  transition: transform 0.2s cubic-bezier(0.34, 1.3, 0.5, 1);
}
.tool-toggle[data-tool="cross"]::before { transform: translateX(0); }
.tool-toggle[data-tool="fill"]::before { transform: translateX(66px); }
.tool-opt {
  position: relative;
  z-index: 1;
  width: 62px;
  height: 46px;
  border: 0;
  background: transparent;
  border-radius: 999px;
  color: #7c8695;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: color 0.2s ease;
}
.tool-opt svg { width: 24px; height: 24px; transition: transform 0.2s ease; }
.tool-opt.active { color: var(--blue); } /* accent-colored active icon -- obvious which tool is live */
.tool-opt.active svg { animation: toolpop 0.25s ease; }
@keyframes toolpop {
  0% { transform: scale(0.7); }
  60% { transform: scale(1.15); }
  100% { transform: scale(1); }
}

.hint-btn {
  position: relative;
  width: 56px;
  height: 56px;
  border: 0;
  border-radius: 999px;
  background: var(--panel);
  color: var(--blue);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}
.hint-btn svg { width: 28px; height: 28px; }
.hint-btn:disabled { color: #b7c0cd; cursor: default; }
.hint-badge {
  position: absolute;
  top: -2px;
  right: -2px;
  min-width: 20px;
  height: 20px;
  padding: 0 5px;
  border-radius: 999px;
  background: var(--blue);
  color: #fff;
  font-size: 12px;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
}
.hint-btn:disabled .hint-badge { background: #b7c0cd; }

/* --- Sheets / overlays --- */
.sheet {
  position: fixed;
  inset: 0;
  background: rgba(20, 28, 40, 0.5);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 70; /* above the result overlay + top bar so modals sit on top */
  padding: 16px;
}
.sheet.hidden { display: none; }
.sheet-card {
  background: #fff;
  border-radius: 16px;
  width: 100%;
  max-width: 420px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
  padding: 18px 20px 22px;
}
.sheet-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 12px;
}
.sheet-head h2 { margin: 0; font-size: 20px; color: var(--title); }
.close-btn {
  width: 34px; height: 34px; border: 0; background: transparent;
  color: #7c8695; cursor: pointer; border-radius: 8px;
}
.close-btn svg { width: 22px; height: 22px; }

.picker-card { max-width: 440px; }
/* The solved-check badge straddles each cell's top-right corner (see .pc-check),
   so the scroll container needs inset room -- and a reserved scrollbar gutter --
   or the rightmost column's badges get clipped by the scrollbar. */
.picker-body {
  height: min(52vh, 380px); /* fixed so switching My-Puzzles tabs never resizes the modal */
  overflow-y: auto;
  padding: 8px 0 0; /* no side padding: the grid aligns with the card's edges */
}

.about-card { max-width: 460px; }
.about-body { max-height: 74vh; overflow-y: auto; font-size: 14.5px; line-height: 1.6; color: #4b5266; }
.about-body p { margin: 0 0 12px; }
.about-body h3 { margin: 18px 0 6px; font-size: 15px; color: var(--title); }
.about-body ul { margin: 0 0 12px; padding-left: 20px; }
.about-body li { margin: 0 0 7px; }
.about-body a { color: var(--blue); font-weight: 600; text-decoration: none; }
.about-body a:hover { text-decoration: underline; }
.about-credit { margin-top: 18px; color: #8a90a2; font-size: 13.5px; }
.about-version { margin: 4px 0 0; color: #a9aebb; font-size: 12px; font-variant-numeric: tabular-nums; }

/* Leaderboard sheet + the "you placed" line on a ranked win. */
.lb-body { max-height: 74vh; overflow-y: auto; }
/* Bounce-fade-in when the board opens (auto after a win, or from the end bar). */
.lb-card { animation: lb-pop 0.3s cubic-bezier(0.18, 0.9, 0.3, 1.3) both; }
@keyframes lb-pop {
  0%   { transform: scale(0.85); opacity: 0; }
  55%  { transform: scale(1.03); opacity: 1; }
  100% { transform: scale(1); opacity: 1; }
}
/* All / Flawless view toggle: same sliding-thumb animation as the Fill/Cross
   toggle. The white thumb (::before) slides between the two equal-width options;
   data-view (set in game.js) drives which side it sits on. */
.lb-toggle {
  position: relative; display: flex; gap: 4px; padding: 4px; margin: 0 4px 12px;
  background: var(--panel); border-radius: 999px; touch-action: manipulation;
}
.lb-toggle::before {
  content: ""; position: absolute; top: 4px; bottom: 4px; left: 4px;
  width: calc(50% - 6px); border-radius: 999px; background: #fff;
  box-shadow: 0 1px 3px rgba(42, 37, 80, 0.12);
  transition: transform 0.2s cubic-bezier(0.34, 1.3, 0.5, 1);
}
.lb-toggle[data-view="all"]::before { transform: translateX(0); }
.lb-toggle[data-view="flawless"]::before { transform: translateX(calc(100% + 4px)); }
/* The standings window switcher: a COMPACT 3-way variant of the same toggle,
   living inside the header row (tier name left, switcher right). Thumb geometry
   matches the sm paddings (3px padding, 3px gaps); the base transition still
   animates the slide. */
.lb-toggle.sm { margin: 0; padding: 3px; gap: 3px; align-self: center; }
.lb-toggle.sm .lb-toggle-opt { flex: 0 0 auto; padding: 4px 10px; font-size: 11.5px; font-weight: 700; }
.lb-toggle.sm::before { top: 3px; bottom: 3px; left: 3px; }
.lb-toggle.sm[data-view]::before { width: calc((100% - 12px) / 3); }
.lb-toggle.sm[data-view="month"]::before { transform: translateX(0); }
.lb-toggle.sm[data-view="week"]::before { transform: translateX(calc(100% + 3px)); }
.lb-toggle.sm[data-view="today"]::before { transform: translateX(calc(200% + 6px)); }
.lb-toggle-opt {
  flex: 1; position: relative; z-index: 1; border: 0; background: transparent; border-radius: 999px;
  padding: 7px 12px; font: inherit; font-weight: 600; color: #8a90a2; cursor: pointer;
  transition: color 0.2s ease;
}
.lb-toggle-opt.active { color: var(--blue); }
/* Fixed rows area so switching All<->Flawless (different row counts) never resizes
   the sheet. Scrolls past a handful of rows. */
#lbRows { height: 272px; overflow-y: auto; }
.lb-head { display: flex; justify-content: space-between; align-items: baseline; padding: 2px 4px 12px; }
.lb-head .lb-name { font-weight: 700; font-size: 18px; color: var(--title); }
.lb-head .lb-meta { color: #8a90a2; font-size: 13px; }
/* One line per row: rank, name (ellipsis), result badge, time -- kept compact so it
   fits a phone width without wrapping. */
.lb-row {
  display: grid; grid-template-columns: 26px minmax(0, 1fr) auto auto; align-items: center; gap: 8px;
  padding: 7px 11px; background: var(--panel); border-radius: 11px; margin-bottom: 6px;
}
.lb-row.me { box-shadow: inset 0 0 0 2px var(--blue); } /* inset so the scroll container never clips it */
.lb-rank { font-weight: 800; text-align: center; color: #8a90a2; font-variant-numeric: tabular-nums; }
.lb-medal { font-size: 18px; text-align: center; }
.lb-name-line { font-weight: 600; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.lb-name-line .lb-you { color: var(--blue); font-size: 10px; font-weight: 800; margin-left: 5px; letter-spacing: 0.5px; }
.lb-result { display: flex; align-items: center; gap: 6px; }
.lb-result .lb-clean { font-size: 11px; font-weight: 700; color: #c9971f; white-space: nowrap; }
.lb-result .lb-hearts, .lb-result .lb-bulbs, .lb-result .lb-retries { display: inline-flex; align-items: center; gap: 1px; }
.lb-result .lb-count { font-size: 11px; font-weight: 700; color: #8a90a2; }
.lb-result svg { width: 12px; height: 12px; }
.lb-time { font-weight: 700; color: var(--blue); font-variant-numeric: tabular-nums; }
.lb-empty { color: #8a90a2; text-align: center; padding: 22px 12px; }
.placement { margin: 0; font-weight: 700; color: var(--blue); }
.placement.hidden { display: none; }

/* Visual guide: an auto-playing board (left) beside step cards (right) that
   highlight in sync. The board reuses the real .cell chips; it is purely
   visual, so it ignores pointer input. */
.about-guide {
  display: flex;
  align-items: flex-start;
  gap: 14px;
  margin: 6px 0 14px;
  padding: 14px;
  background: #f3f4fb;
  border-radius: 14px;
}
.about-demo-wrap { flex: 0 0 auto; }
.about-demo {
  --dcell: 38px;
  display: inline-grid; /* grid-template is set in JS from the demo size */
  pointer-events: none;
}
.about-demo .dclue {
  display: flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: 700; color: var(--clue-ink);
  font-variant-numeric: tabular-nums; line-height: 1.05;
}
.about-demo .rowclue { flex-direction: row; gap: 2px; justify-content: flex-end; padding-right: 5px; }
.about-demo .colclue { flex-direction: column; gap: 1px; justify-content: flex-end; padding-bottom: 2px; }
/* Each clue number sits in its own circular slot, so the highlight can ring a
   single number without shifting the board's layout. */
.about-demo .dclue span {
  display: inline-flex; align-items: center; justify-content: center;
  width: 17px; height: 17px; border-radius: 50%;
  transition: color 0.2s ease, background 0.2s ease;
}
/* The specific run being filled: that number turns black inside a bright
   yellow circle, so beginners can follow which run is in play. */
.about-demo .dclue span.hl { color: #000; background: #ffe100; }
.about-demo-hearts {
  display: flex; justify-content: center; gap: 4px; margin-top: 10px;
}
.about-demo-hearts svg { width: 15px; height: 15px; }
.about-demo-hearts .heart-full { color: var(--heart); }
.about-demo-hearts .heart-lost { color: var(--heart-lost); }

.about-steps {
  flex: 1 1 auto; min-width: 0;
  margin: 0; padding: 0; list-style: none;
  display: flex; flex-direction: column; gap: 8px;
}
.about-step {
  display: flex; gap: 9px; align-items: flex-start;
  padding: 8px 10px; border-radius: 10px;
  background: #fff; border: 1px solid #e5e7f2;
  opacity: 0.55; transition: opacity 0.3s ease, border-color 0.3s ease, background 0.3s ease;
}
.about-step.active { opacity: 1; border-color: var(--blue); background: rgba(90, 73, 214, 0.06); }
.step-num {
  flex: 0 0 auto;
  width: 18px; height: 18px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 11px; font-weight: 800;
  background: #e5e7f2; color: #8a90a2;
}
.about-step.active .step-num { background: var(--blue); color: #fff; }
.step-body { display: flex; flex-direction: column; gap: 2px; }
.step-title { font-size: 12.5px; font-weight: 700; color: var(--title); }
.step-desc { font-size: 11.5px; line-height: 1.35; color: #6b7286; }

/* Inline glyphs that mirror the in-game controls, used in the rule list. */
.ib {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.15em; height: 1.15em; vertical-align: -0.22em; margin: 0 1px;
}
.ib svg { width: 100%; height: 100%; }
.ib-fill { color: var(--blue); }
.ib-cross { color: var(--cross); }
.ib-heart { color: var(--heart); }
.ib-hint { color: var(--blue); }

/* Desktop-only guidance (left/right-click) is hidden by default and revealed
   only on devices whose primary pointer is a mouse. */
.desktop-only { display: none; }
@media (hover: hover) and (pointer: fine) {
  .desktop-only { display: inline; }
}

/* On very narrow screens the guide stacks: board on top, cards below. */
@media (max-width: 430px) {
  .about-guide { flex-direction: column; align-items: center; }
  .about-steps { width: 100%; }
}

/* On phones every sheet reads better as a full-screen page than a floating card;
   on larger screens they stay centered modals (the default above). */
@media (max-width: 560px) {
  .sheet { padding: 0; }
  .sheet-card {
    max-width: none;
    width: 100%;
    height: 100%;
    border-radius: 0;
    display: flex;
    flex-direction: column;
    padding: 16px 18px calc(16px + env(safe-area-inset-bottom, 0px));
  }
  .picker-body,
  .about-body,
  .lb-body { max-height: none; flex: 1; }
  #lbRows { height: auto; flex: 1; } /* full-screen mobile sheet: no fixed rows box */
}
/* My Puzzles section switcher (In progress / Dailies / Easy / Medium / Hard) --
   a sliding-thumb segmented control, same feel as the difficulty selector. */
.mp-tabs {
  position: relative;
  display: inline-flex; gap: 4px; padding: 4px;
  margin: 0 auto 12px; max-width: 100%;
  background: var(--panel); border-radius: 999px;
  touch-action: manipulation;
}
.mp-tabs::before {
  content: "";
  position: absolute; top: 4px; bottom: 4px; left: 0;
  width: var(--thumb-w, 0);
  transform: translateX(var(--thumb-x, 0));
  background: #fff; border-radius: 999px;
  box-shadow: 0 2px 6px rgba(30, 42, 56, 0.18);
  transition: transform 0.2s cubic-bezier(0.34, 1.3, 0.5, 1), width 0.2s cubic-bezier(0.34, 1.3, 0.5, 1);
}
.mp-tabs.no-thumb-anim::before { transition: none; } /* skip the slide on first show */
.mp-tab {
  position: relative; z-index: 1;
  border: 0; background: transparent; border-radius: 999px;
  padding: 8px 14px; font: inherit; font-size: 13px; font-weight: 700;
  color: #7c8695; white-space: nowrap; cursor: pointer;
  transition: color 0.2s ease;
}
.mp-tab.active { color: var(--blue); }

/* Section header: tier name left, average rank right. */
.mp-group-title {
  display: flex; align-items: baseline; justify-content: space-between;
  margin: 15px 4px 8px;
}
.mp-group-title:first-child { margin-top: 2px; }
.mp-group-name { font-size: 13px; font-weight: 700; color: #7c8695; text-transform: uppercase; letter-spacing: 0.5px; }
.mp-group-avg { font-size: 12px; font-weight: 700; color: var(--blue); font-variant-numeric: tabular-nums; }

/* One row per solved puzzle, styled like a leaderboard row: rank, name, badge, time. */
.mp-row {
  display: grid; grid-template-columns: 34px minmax(0, 1fr) auto auto; align-items: center; gap: 8px;
  width: 100%; text-align: left; border: 0; cursor: pointer;
  padding: 8px 11px; margin-bottom: 6px;
  background: var(--panel); border-radius: 11px; color: var(--ink);
  transition: background 0.15s ease, box-shadow 0.15s ease, transform 0.1s ease;
}
.mp-row:hover { background: rgba(106, 92, 240, 0.18); box-shadow: 0 3px 10px rgba(90, 73, 214, 0.2); }
.mp-row:active { transform: scale(0.99); }
.mp-rank { font-weight: 800; color: #8a90a2; font-variant-numeric: tabular-nums; }
.mp-name { font-size: 14px; font-weight: 700; color: var(--title); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.mp-badge { display: inline-flex; align-items: center; gap: 6px; }
.mp-badge svg { width: 13px; height: 13px; }
.mp-time { font-weight: 700; color: var(--blue); font-variant-numeric: tabular-nums; }
.mp-perfect { display: inline-flex; align-items: center; gap: 3px; font-size: 11.5px; font-weight: 700; color: #c9971f; }
.mp-progress { font-size: 11.5px; font-weight: 700; color: var(--blue); }
.mp-row.in-progress { box-shadow: inset 0 0 0 1.5px rgba(90, 73, 214, 0.35); }

/* Result-badge count spans (shared with the leaderboard). */
.pc-lives, .pc-hints, .pc-retries { display: inline-flex; align-items: center; gap: 1px; }
.retry-mark { color: var(--blue); } /* Game Over -> Retry loop glyph */
.pc-count { font-size: 11px; font-weight: 700; color: #8a90a2; }
.picker-empty { text-align: center; color: #7c8695; padding: 26px 10px; font-size: 14px; }

.menu-danger { color: #c0392b; }

.menu-item {
  display: block;
  width: 100%;
  text-align: left;
  border: 0;
  background: #f6f8fb;
  border-radius: 10px;
  padding: 14px 16px;
  font-size: 16px;
  font-weight: 600;
  color: var(--ink);
  cursor: pointer;
  margin-bottom: 8px;
}
.menu-item:hover { background: #eef2f8; }

/* Settings sheet rows. */
.setting-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 4px;
  border-bottom: 1px solid #eef1f5;
  cursor: pointer;
}
.setting-label { font-size: 16px; font-weight: 600; color: var(--ink); }
.setting-input {
  flex: 1;
  max-width: 190px;
  border: 1px solid #dbe1ea;
  border-radius: 8px;
  padding: 9px 11px;
  font-size: 15px;
  font-family: inherit;
  color: var(--ink);
  background: #f6f8fb;
}
.setting-input:focus { outline: none; border-color: var(--blue); background: #fff; }
/* A native checkbox styled as an iOS-style switch. */
.setting-switch {
  appearance: none;
  -webkit-appearance: none;
  width: 46px;
  height: 28px;
  border-radius: 999px;
  background: #cfd6e0;
  position: relative;
  cursor: pointer;
  flex: none;
  transition: background 0.15s ease;
}
.setting-switch::before {
  content: "";
  position: absolute;
  top: 3px;
  left: 3px;
  width: 22px;
  height: 22px;
  border-radius: 999px;
  background: #fff;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);
  transition: transform 0.15s ease;
}
.setting-switch:checked { background: #2fbf6b; }
.setting-switch:checked::before { transform: translateX(18px); }
.setting-note { margin: 10px 4px 0; color: #7c8695; font-size: 12.5px; line-height: 1.5; }
/* Read-only account rows in Settings (username + password). */
.setting-value { font-size: 15px; font-weight: 600; color: var(--ink); }
.setting-pw { display: inline-flex; align-items: center; gap: 12px; }
.pw-dots { letter-spacing: 2px; color: #9aa0b2; }
.btn.small { padding: 7px 14px; font-size: 13.5px; border-radius: 9px; }

.btn {
  font-size: 15px;
  padding: 11px 16px;
  border: 1px solid #cfd6df;
  border-radius: 10px;
  background: #fff;
  color: var(--ink);
  font-weight: 600;
  cursor: pointer;
}
.btn:hover { background: #f2f5f9; }
.btn.primary { background: var(--blue); border-color: var(--blue); color: #fff; }
.btn.primary:hover { background: #2565d6; }

/* Main-menu burger, top-right of the fixed menu page. */
.menu-burger { position: absolute; top: 16px; right: 16px; z-index: 5; }

/* Avatar shown in the profile popup header (the menu triggers are hamburgers). */
.avatar {
  display: flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; border-radius: 50%;
  font-size: 19px; font-weight: 800; color: #fff; text-transform: uppercase;
  background: linear-gradient(135deg, var(--blue-hi), var(--blue-lo));
  user-select: none; flex: none;
}
.avatar.guest { background: #b9c0cd; }

/* --- Profile popup (opened by the profile icon) --- */
/* A compact card anchored under the icon on every screen size (phones too), not
   the full-screen sheet the other overlays use. The higher-specificity rules
   below override the generic .sheet / mobile .sheet-card styles. */
#accountMenu {
  align-items: flex-start;
  justify-content: flex-end;
  background: transparent;    /* click anywhere outside the card to dismiss */
  padding: 62px 14px 14px;
}
#accountMenu .account-card {
  width: min(300px, calc(100vw - 28px));
  height: auto;
  max-height: calc(100vh - 80px);
  overflow-y: auto;
  border-radius: 14px;
  padding: 7px;
  box-shadow: 0 16px 44px rgba(20, 28, 40, 0.26);
  transform-origin: top right;
  animation: menu-pop 0.14s ease-out;
}
@keyframes menu-pop {
  from { opacity: 0; transform: translateY(-6px) scale(0.98); }
  to   { opacity: 1; transform: none; }
}

/* Profile header inside the popup: avatar + name/status. .menu-note carries
   "Signed in as X" / "Playing as guest". */
.menu-profile { display: flex; align-items: center; gap: 11px; padding: 8px 8px 12px; }
.menu-profile-text { min-width: 0; }
.menu-note {
  font-weight: 700; font-size: 14.5px; color: var(--title);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.menu-profile-sub {
  font-size: 12.5px; color: #7c8695; margin-top: 1px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* A hairline divider between popup sections. */
.menu-divider { height: 1px; background: #eceef3; margin: 5px 6px; }

/* One popup row: left icon + label. */
.popup-item {
  display: flex; align-items: center; gap: 12px;
  width: 100%; text-align: left;
  border: 0; background: transparent; cursor: pointer;
  border-radius: 9px; padding: 10px;
  font-size: 14.5px; font-weight: 600; color: var(--ink);
}
.popup-item:hover { background: #f2f4f9; }
.popup-icon { flex: none; display: inline-flex; width: 20px; height: 20px; color: #6b7286; }
.popup-icon svg { width: 20px; height: 20px; }
.popup-item.danger, .popup-item.danger .popup-icon { color: #c0392b; }

/* --- Log in / Sign up pages --- */
.auth-sub { margin: -4px 0 18px; color: #6b7286; font-size: 13.5px; line-height: 1.55; }
.auth-page-form { display: flex; flex-direction: column; gap: 14px; }
.auth-field { display: flex; flex-direction: column; gap: 6px; cursor: text; }
.auth-field-label {
  font-size: 12px; font-weight: 700; color: #7c8695;
  text-transform: uppercase; letter-spacing: 0.4px;
}
.auth-page-form .setting-input { width: 100%; max-width: none; padding: 12px 13px; font-size: 15px; }
.auth-page-form .btn.big-blue { margin-top: 6px; }
.auth-error { color: #d33; font-size: 0.9em; }
.auth-switch { text-align: center; margin-top: 18px; font-size: 0.92em; color: #6b7286; }
.auth-switch a { color: var(--blue); font-weight: 700; text-decoration: none; }
.auth-switch a:hover { text-decoration: underline; }

/* --- Confirm dialog --- */
.confirm-card { max-width: 380px; }
.confirm-card h2 { margin: 0 0 8px; font-size: 19px; color: var(--title); }
.confirm-card p { margin: 0 0 20px; color: #4b5266; font-size: 14.5px; line-height: 1.5; }
.confirm-actions { display: flex; gap: 10px; }
.confirm-actions .btn { flex: 1; margin-top: 0; }
/* Stay a centered card on phones too (it's a small dialog, not a page). */
@media (max-width: 560px) {
  #confirm { padding: 16px; }
  #confirm .confirm-card { width: 100%; height: auto; border-radius: 16px; }
}


/* Prof. Noodle's puzzle study  warm paper-led brand layer. */
:root {
  --bg:#fffaf0;--ink:#473c3b;--title:#3d295e;--blue:#5b3c9d;--blue-hi:#7952bd;--blue-lo:#4d2f89;
  --page-bg:radial-gradient(circle at 12% 8%,rgba(239,176,137,.2),transparent 30%),linear-gradient(180deg,#fffaf0,#f8ead6);
  --cell-empty:#eee5d7;--sep:#b8a990;--clue-ink:#766a68;--clue-done:#c2b7aa;--cross:#6e625d;
  --hl:rgba(91,60,157,.14);--heart:#e85f72;--heart-lost:#d9cec0;--panel:#efe5d8;
  --paper:#fffaf0;--paper-line:rgba(109,82,63,.13);--gold:#dca63c;--shadow-soft:0 18px 50px rgba(91,63,39,.16)
}
html,body{background:var(--page-bg);color:var(--ink)}
button,input{font-family:inherit}
.splash{background:radial-gradient(circle at center,rgba(121,82,189,.08),transparent 30%),#fff8e9}
.splash-spin{border-color:#eadfce;border-top-color:var(--blue)}

/* The home is a quiet paper control panel laid over the professor's study. */
.menu-page{isolation:isolate;background:#f8ead5;padding:clamp(18px,4vw,48px)}
.menu-page::before{content:"";position:fixed;inset:0;z-index:0;background:linear-gradient(90deg,rgba(255,249,235,.2),transparent 56%),url("prof-noodle-study.webp") center/cover no-repeat}
.menu-page::after{content:"";position:fixed;inset:0;z-index:0;pointer-events:none;background:linear-gradient(90deg,rgba(255,248,231,.28),transparent 62%)}
.menu-inner{margin:auto auto auto clamp(0px,5vw,72px);max-width:390px;padding:26px 28px 28px;border:1px solid rgba(255,255,255,.7);border-radius:28px;background:rgba(255,249,235,.88);box-shadow:var(--shadow-soft);backdrop-filter:blur(12px) saturate(.9);-webkit-backdrop-filter:blur(12px) saturate(.9)}
.menu-inner{position:relative;z-index:1}.menu-burger{z-index:1}
.hero{display:flex;justify-content:center}
.hero-logo{width:88px;border-radius:50%;box-shadow:0 8px 22px rgba(71,45,113,.22);filter:none}
.brand-lockup{margin:11px 0 26px}
.brand-maker{display:block;color:#7f624d;font-family:Georgia,"Times New Roman",serif;font-size:14px;font-weight:700;letter-spacing:.16em;text-transform:uppercase}
.brand{margin:1px 0 0;color:var(--blue);font-family:Georgia,"Times New Roman",serif;font-size:clamp(35px,8vw,43px);font-weight:700;letter-spacing:-.035em;line-height:1}
.brand-deck{margin:7px 0 0;color:#8a6f5b;font-family:Georgia,"Times New Roman",serif;font-size:14px;font-style:italic}
.menu-stats{margin-top:18px}
.ms-tile{border:1px solid var(--paper-line);background:rgba(244,231,211,.76)}.ms-val{color:var(--blue)}.ms-sub,.ms-label{color:#88766e}
.btn.big-blue,.split-wrap.primary .split-btn{background-image:linear-gradient(125deg,#7650b4,#52348d,#7650b4);box-shadow:0 8px 20px rgba(76,45,134,.28)}
.btn.big-blue:hover,.split-wrap.primary .split-btn:hover{background-image:linear-gradient(125deg,#7650b4,#52348d,#7650b4)}
.btn.secondary,.split-main,.split-caret{border-color:rgba(91,60,157,.55);color:var(--blue)}
.btn.secondary:hover,.split-main:hover,.split-caret:hover,.diff-dropdown-opt:hover{background:rgba(91,60,157,.08)}
.diff-dropdown{border-color:rgba(91,60,157,.32);background:var(--paper)}

/* Gameplay stays clean and geometric on a lightly ruled puzzle sheet. */
.app{background:linear-gradient(rgba(255,250,240,.91),rgba(255,250,240,.91)),repeating-linear-gradient(0deg,transparent 0 27px,var(--paper-line) 27px 28px)}
.topbar{width:min(100%,720px);margin:0 auto;border-bottom:1px solid var(--paper-line)}
.title{color:var(--title);font-family:Georgia,"Times New Roman",serif;font-size:16px}
.timer,.substat-dot{color:#8e7f76}.icon-btn{color:var(--blue)}.icon-btn:hover{background:rgba(91,60,157,.08)}
.stage::before,.stage::after{content:"";width:min(82vw,340px);height:1px;opacity:.38}
.stage::before{margin-top:auto;background:linear-gradient(90deg,transparent,var(--gold),transparent)}
.stage::after{margin-bottom:auto;background:linear-gradient(90deg,transparent,var(--gold),transparent)}
.board-spacer{flex:.8}.cell{box-shadow:inset 0 0 0 1px rgba(89,72,61,.035)}
.cell.filled{background:linear-gradient(145deg,#7353ae,#54358f);background-clip:padding-box}.cell.hint{background:#f4cb62}
.colclue,.rowclue{font-family:ui-rounded,"Arial Rounded MT Bold",system-ui,sans-serif}
.tool-toggle,.hint-btn,.diff-select,.lb-toggle,.mp-tabs{border:1px solid rgba(111,84,61,.09);background:#eadfce}
.tool-toggle::before,.diff-select::before,.lb-toggle::before,.mp-tabs::before{background:#fffaf0;box-shadow:0 2px 7px rgba(83,61,43,.16)}
.toolbar,.endbar{width:min(100%,720px);margin:0 auto}

/* Modal surfaces and lists read as pages from the professor's notebook. */
.sheet{background:rgba(53,38,46,.46);backdrop-filter:blur(3px);-webkit-backdrop-filter:blur(3px)}
.sheet-card{border:1px solid rgba(115,82,58,.15);background:linear-gradient(rgba(255,250,240,.97),rgba(255,250,240,.97)),repeating-linear-gradient(0deg,transparent 0 27px,var(--paper-line) 27px 28px);box-shadow:0 24px 70px rgba(57,39,31,.3)}
.sheet-head{padding-bottom:10px;border-bottom:1px solid var(--paper-line)}
.sheet-head h2,.confirm-card h2{color:var(--title);font-family:Georgia,"Times New Roman",serif}
.close-btn{color:#826f67}.close-btn:hover{background:rgba(142,124,195,.14)}
.about-body{color:#594c49}.about-credit,.about-version{color:#927f75}
.about-guide,.menu-item,.setting-input,.lb-row,.mp-row{background:rgba(239,228,211,.76)}
.about-step{border-color:rgba(107,79,58,.13);background:rgba(255,250,240,.9)}
.about-step.active{border-color:rgba(91,60,157,.55);background:rgba(91,60,157,.07)}
.setting-row{border-bottom-color:var(--paper-line)}.setting-input{border-color:rgba(107,79,58,.18)}.menu-divider{background:var(--paper-line)}

/* A professor-led win retains the existing randomized shout. The panel sits on the
   study background (no dimmed backdrop, no card surface) -- it replaces the board. */
.result-win{position:relative;width:min(82vw,360px);padding:18px 20px 20px;overflow:hidden}
.result-art{width:min(68vw,260px);height:min(68vw,260px);object-fit:contain;background:transparent;filter:drop-shadow(0 8px 10px rgba(92,65,47,.12));-webkit-mask-image:linear-gradient(to bottom,#000 0%,#000 82%,transparent 100%);mask-image:linear-gradient(to bottom,#000 0%,#000 82%,transparent 100%)}
.result-win .result-emoji{position:absolute;top:19px;right:24px;display:block;font-size:32px;filter:drop-shadow(0 2px 2px rgba(70,42,20,.15))}
.result-word{color:var(--title);font-family:Georgia,"Times New Roman",serif}.result-win .result-word{margin-top:2px;font-size:34px}
.result-over{padding:22px 28px}

@media(max-width:720px){
  .menu-page::before{background-position:61% center}.menu-page::after{background:linear-gradient(rgba(255,248,231,.35),rgba(255,248,231,.68))}
  .menu-inner{margin:auto;max-width:370px;padding:22px 22px 24px;background:rgba(255,249,235,.91)}
}
@media(max-width:430px){
  .menu-page{padding:14px;background:#f8ead5 url("prof-noodle-study.webp") 72% top/auto 230px no-repeat}.menu-page::before{display:none}
  .menu-inner{border-radius:24px;padding:20px 18px 22px}.hero-logo{width:74px}.brand-lockup{margin:8px 0 17px}
  .brand{font-size:35px}.brand-maker{font-size:12px}.brand-deck{font-size:13px}
  .menu-burger{top:12px;right:12px;background:rgba(255,249,235,.8);box-shadow:0 3px 12px rgba(77,51,37,.12)}
  .result-art{width:min(64vw,230px);height:min(64vw,230px)}
}
@media(max-height:720px){
  .hero-logo{width:64px}.brand-lockup{margin-bottom:17px}.brand{font-size:32px}.brand-deck{display:none}
  .menu-inner{padding-top:17px;padding-bottom:18px}.menu-stats{margin-top:12px}
}
@media(prefers-reduced-motion:reduce){.result-win,.result-overlay.win,.board.fade-in{animation-duration:.01ms!important}}


/* Concept-sheet fidelity pass: lavender controls, centered composition, and
   layered study/paper textures across home, game, and notebook surfaces. */
:root{
  --blue:#8e7cc3;--blue-hi:#a894db;--blue-lo:#806bb8;--title:#392f3e;
  --page-bg:#fff5e6;--cell-empty:#eadcc7;--panel:#f1e4d2;--paper:#fff5e6;
  --paper-line:rgba(139,129,118,.13);--gold:#e6b84c
}
html,body{background-color:#fff5e6}
body::before{
  content:"";position:fixed;inset:0;z-index:-1;pointer-events:none;opacity:.35;
  background-image:
    radial-gradient(circle at 9% 18%,rgba(232,93,139,.18) 0 2px,transparent 3px),
    radial-gradient(circle at 91% 12%,rgba(120,191,188,.18) 0 2px,transparent 3px),
    repeating-linear-gradient(0deg,transparent 0 31px,rgba(205,191,174,.18) 31px 32px),
    repeating-linear-gradient(90deg,transparent 0 31px,rgba(205,191,174,.12) 31px 32px)
}

/* The concept centers the controls and lets the illustrated room frame them. */
.menu-inner{
  margin:auto;max-width:400px;padding:24px 26px 27px;border:0;border-radius:32px;
  background:
    linear-gradient(rgba(255,245,230,.8),rgba(255,245,230,.8)),
    repeating-linear-gradient(0deg,transparent 0 27px,rgba(205,191,174,.2) 27px 28px);
  box-shadow:0 14px 38px rgba(104,78,52,.13);backdrop-filter:none;-webkit-backdrop-filter:none
}
.menu-page::after{background:linear-gradient(rgba(255,245,230,.08),rgba(255,245,230,.22))}
.brand{color:#392f3e}.brand-maker{color:#796d66}.brand-deck{color:#8b8176}
.btn.big-blue,.split-wrap.primary .split-btn{
  background:#8e7cc3;background-image:none;border-radius:999px;
  box-shadow:0 6px 14px rgba(142,124,195,.25)
}
.btn.big-blue:hover,.split-wrap.primary .split-btn:hover{background:#806bb8;background-image:none;animation:none}
.btn.secondary{border-color:#a997cf;color:#63518f;border-radius:999px;background:rgba(255,245,230,.42)}
.split-btn{border-radius:999px!important}
.split-main{border-color:#a997cf;color:#63518f;border-radius:999px 0 0 999px;padding-top:8px;padding-bottom:8px}
.split-caret{border-color:#a997cf;color:#63518f;border-radius:0 999px 999px 0}
.split-wrap.primary .split-main{border-radius:999px 0 0 999px}
.split-wrap.primary .split-caret{border-radius:0 999px 999px 0}
.cta-row .btn.big-blue{border-radius:999px}
.diff-dropdown{border-color:#b6a6d5}

/* Use the same study behind the puzzle, with a parchment veil for legibility. */
.app{
  position:relative;isolation:isolate;
  background:
    linear-gradient(rgba(255,245,230,.78),rgba(255,245,230,.88)),
    url("prof-noodle-study.webp") center/cover fixed no-repeat
}
.app::before{
  content:"";position:fixed;inset:0;z-index:-1;pointer-events:none;opacity:.52;
  background-image:
    repeating-linear-gradient(0deg,transparent 0 27px,rgba(139,129,118,.11) 27px 28px),
    repeating-linear-gradient(90deg,transparent 0 27px,rgba(139,129,118,.07) 27px 28px),
    radial-gradient(circle at 12% 82%,rgba(120,191,188,.18) 0 3px,transparent 4px),
    radial-gradient(circle at 88% 20%,rgba(232,93,139,.14) 0 3px,transparent 4px)
}
.topbar{background:rgba(255,247,232,.72);backdrop-filter:blur(9px) saturate(1.05);-webkit-backdrop-filter:blur(9px) saturate(1.05);border-radius:0;border-bottom:1px solid rgba(205,191,174,.55)}
.cell.filled{background:#8e7cc3;background-clip:padding-box}
.tool-toggle,.hint-btn,.diff-select,.lb-toggle,.mp-tabs{background:#eadcc7}
.toolbar .tool-toggle,.toolbar .hint-btn{box-shadow:0 5px 16px rgba(99,77,50,.12)}
.hint-btn{border-radius:999px}

/* Notebook surfaces carry the reference's paper grain, rules, and faint grid. */
.sheet-card{
  border-radius:24px;
  background:
    linear-gradient(rgba(255,245,230,.94),rgba(255,245,230,.94)),
    radial-gradient(circle at 16% 12%,rgba(232,93,139,.18) 0 1.5px,transparent 2px),
    repeating-linear-gradient(0deg,transparent 0 27px,rgba(205,191,174,.22) 27px 28px),
    repeating-linear-gradient(90deg,transparent 0 27px,rgba(205,191,174,.1) 27px 28px)
}
.lb-row,.mp-row,.about-step,.menu-item{
  border:1px solid rgba(205,191,174,.62);border-radius:14px;background:rgba(255,247,234,.78)
}
.lb-row.me,.mp-row.in-progress{box-shadow:inset 0 0 0 2px #a894db}
.diff-select,.lb-toggle,.mp-tabs{border-radius:999px}
.diff-opt,.lb-toggle-opt,.mp-tab{border-radius:999px}
.result-win,.result-over{border-radius:28px;background:transparent}

/* Transparent icon corners; the soft ring belongs to the portrait itself. */
.hero-logo{background:transparent;box-shadow:0 7px 18px rgba(92,70,125,.2)}

@media(max-width:720px){
  .menu-inner{margin:auto;max-width:360px;background:linear-gradient(rgba(255,245,230,.86),rgba(255,245,230,.86)),repeating-linear-gradient(0deg,transparent 0 27px,rgba(205,191,174,.2) 27px 28px)}
}
@media(max-width:430px){
  .menu-page{background:#fff5e6 url("prof-noodle-study.webp") 72% top/auto 230px no-repeat}
  .menu-inner{padding:20px 18px 22px;border-radius:28px}
  .sheet-card{border-radius:0}
}


/* Typography + shared desktop chrome. One family now drives every UI surface;
   the SVG wordmark uses the same rounded fallback stack. */
:root{
  --font-ui:"Trebuchet MS","Avenir Next","Segoe UI",Arial,sans-serif;
  --chrome-max:840px;
  --chrome-inset:max(14px,calc((100vw - var(--chrome-max))/2 + 8px))
}
html,body,button,input,select,textarea{font-family:var(--font-ui)}
.title,.sheet-head h2,.confirm-card h2,.result-word,.brand-deck,
.colclue,.rowclue,.about-body,.setting-label,.menu-note,.popup-item,
.btn,.split-main,.split-caret,.diff-opt,.mp-tab,.lb-toggle-opt{
  font-family:var(--font-ui)
}
.title,.sheet-head h2,.confirm-card h2,.result-word{letter-spacing:-.02em}
.colclue,.rowclue,.timer,.ms-val,.mp-time,.lb-time{font-variant-numeric:tabular-nums}
.brand-lockup{width:100%;margin:8px 0 17px}
.brand-logo{display:block;width:min(100%,330px);height:auto;margin:0 auto}
.brand-deck{margin:-3px 0 0;color:#8b8176;font-size:14px;font-style:italic;letter-spacing:.01em}
.sr-only{
  position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;
  overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important
}

/* Both screens share one centered desktop rail. The popup's right edge follows
   the rail rather than the viewport, while phone behavior remains unchanged. */
.topbar{width:min(100%,var(--chrome-max))}
.menu-burger{
  right:var(--chrome-inset);
  top:16px
}
#accountMenu{
  padding-right:var(--chrome-inset);
  padding-left:14px
}
#accountMenu .account-card{margin-right:0}

@media(max-width:860px){
  .topbar{width:100%}
  .menu-burger{right:14px}
  #accountMenu{padding-right:14px}
}
@media(max-width:430px){
  .brand-lockup{margin:6px 0 17px}
  .brand-logo{width:min(100%,300px)}
  .brand-deck{font-size:13px}
  .menu-burger{top:12px;right:12px}
}


/* Main-menu burger keeps the same rounded surface the game burger shows on hover. */
.menu-page .menu-burger{
  background:rgba(255,245,230,.82);
  border-radius:10px;
  box-shadow:0 3px 12px rgba(77,51,37,.12)
}
.menu-page .menu-burger:hover{background:rgba(142,124,195,.12)}


/* Harmonized interaction palette: every neutral/hover/selected state derives
   from the same lavender and muted-plum family. */
:root{
  --purple-50:#f4f0fa;
  --purple-100:#e8e1f3;
  --purple-300:#b7a8d7;
  --purple-500:#8e7cc3;
  --purple-600:#806db5;
  --purple-700:#6b598f;
  --blue:var(--purple-500);
  --blue-hi:#a493d2;
  --blue-lo:var(--purple-600);
  --hl:rgba(142,124,195,.14)
}
.btn.big-blue,.split-wrap.primary .split-btn,.btn.primary{
  background:var(--purple-500);border-color:var(--purple-500);color:#fff
}
.btn.big-blue:hover,.split-wrap.primary .split-btn:hover,.btn.primary:hover{
  background:var(--purple-600);border-color:var(--purple-600)
}
.btn.secondary,.split-main,.split-caret{
  border-color:var(--purple-300);color:var(--purple-700)
}
.btn.secondary:hover,.split-main:hover,.split-caret:hover,
.icon-btn:hover,.menu-page .menu-burger:hover,.popup-item:hover,
.diff-dropdown-opt:hover,.menu-item:hover{
  background:rgba(142,124,195,.12);color:var(--purple-700)
}
.mp-row:hover{
  background:var(--purple-100);box-shadow:0 3px 10px rgba(107,89,143,.16)
}
.diff-opt.active,.mp-tab.active,.lb-toggle-opt.active,
.about-body a,.auth-switch a,.placement,.mp-time,.lb-time,.ms-val{
  color:var(--purple-700)
}
.tool-opt.active,.hint-btn,.icon-btn{color:var(--purple-600)}
.hint-badge{background:var(--purple-600)}
.diff-dropdown{border-color:var(--purple-300)}
.diff-dropdown-opt.selected{color:var(--purple-700)}
.setting-input:focus{
  border-color:var(--purple-500);box-shadow:0 0 0 3px rgba(142,124,195,.13)
}
.lb-row.me,.mp-row.in-progress{box-shadow:inset 0 0 0 2px var(--purple-500)}
.cell.filled{background:var(--purple-500);background-clip:padding-box}

/* Burger hover: keep an opaque surface so the darker illustration behind the pill
   doesn't bleed through a translucent tint (which read as "turning dark"). */
.menu-page .menu-burger:hover{background:rgba(244,240,250,.96)}

/* Fade every interactive hover/selected state instead of snapping. The compound
   button selectors (big-blue/split/primary/secondary) are listed explicitly so
   this beats their now-dead background-position sweep transition. */
.btn,.btn.big-blue,.btn.primary,.btn.secondary,.split-wrap.primary .split-btn,
.split-main,.split-caret,.icon-btn,.menu-burger,.mp-row,.mp-tab,.diff-opt,
.diff-dropdown-opt,.popup-item,.menu-item,.tool-opt,.lb-toggle-opt,.hint-btn,
.close-btn,.about-guide{
  transition:background-color .18s ease,color .18s ease,box-shadow .18s ease,border-color .18s ease
}

/* Segmented switchers (difficulty / My-Puzzles tabs / leaderboard / tools): tint the
   sliding thumb lavender and give inactive segments a purple hover wash, so they lean
   more purple and visibly react to the cursor. */
.diff-select::before,.lb-toggle::before,.mp-tabs::before,.tool-toggle::before{
  background:var(--purple-50);
  box-shadow:0 2px 7px rgba(107,89,143,.24)
}
.diff-opt:not(.active):hover,.mp-tab:not(.active):hover,
.lb-toggle-opt:not(.active):hover,.tool-opt:not(.active):hover{
  color:var(--purple-600);
  background:rgba(142,124,195,.14)
}

/* My-Puzzles switcher spans the full sheet width, tabs sharing it evenly. */
.mp-tabs{display:flex;width:100%;margin:0 0 12px}
.mp-tab{flex:1;text-align:center;padding:8px 6px}

/* Gentle Professor Noodle illustration for the persistent Game Over card. Sized up
   a touch and tinted to the sad-Noodle art's cream backdrop so the illustration
   melts into the card. Retry lives inside the card (the .over overlay is
   click-through, so the card re-enables pointer events). */
.result-over{
  width:min(88vw,384px);
  padding:22px 26px 24px;
}
.result-art-sad{width:min(68vw,268px);height:min(68vw,268px)}
.result-over .result-emoji{display:none}
.result-over .result-word{margin-top:6px}
.result-note{margin:9px 4px 0;color:#7c6a53;font-size:14px;line-height:1.45;text-align:center}
.result-retry{margin-top:16px;min-width:150px}
/* On desktop the Game Over panel gets a touch more room; content stays centered. */
@media(min-width:600px){
  .result-over{width:400px;justify-content:center;padding:26px 30px}
  .result-art-sad{width:198px;height:198px}
}

/* Main-menu top bar (slim chrome): gives the menu button a clear home instead of
   floating on the illustration. Translucent like the in-game top bar; wordmark
   left, burger right. Fixed so it stays put if the signed-in stats make the menu
   scroll. */
.menu-topbar{
  position:fixed;top:0;left:0;right:0;z-index:16;
  display:flex;align-items:center;justify-content:space-between;gap:10px;
  padding:7px 16px; /* matches the in-game bar's height so the popup gap is equal */
  background:rgba(255,247,232,.72);
  backdrop-filter:blur(9px) saturate(1.05);-webkit-backdrop-filter:blur(9px) saturate(1.05);
  border-bottom:1px solid rgba(205,191,174,.55);
}
.menu-hi{font-size:14px;font-weight:600;color:#7c6a53;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:72%}
.menu-hi-guest{font-style:italic;font-weight:500;opacity:.72}
/* The burger lives in the bar now -- drop the floating pill positioning/surface. */
.menu-topbar .menu-burger{
  position:static;top:auto;right:auto;z-index:auto;
  background:transparent;box-shadow:none;border-radius:10px;
}
.menu-topbar .menu-burger:hover{background:rgba(142,124,195,.14)}
/* Keep the centered menu card clear of the fixed bar on short viewports. */
.menu-page{padding-top:56px}

/* Match the in-game top bar to the menu bar: full-bleed chrome (not the centered
   rail), pulled out of the .app padding so it sits flush at the very top and spans
   edge to edge, with the burger at the same inset. */
.topbar{width:auto;margin:-8px -6px 0;padding:7px 16px} /* symmetric padding centers the 2 title lines and clears the top */
/* The account popup opens from either burger -- drop it just below the bar
   (the game bar is the taller of the two) and align it under the burger. */
#accountMenu{padding-top:58px;padding-right:16px;padding-left:16px}

/* Phones (<=430px) fill the whole screen with the study illustration, same as the
   larger sizes -- was a fixed 230px top banner that left plain cream below. */
@media(max-width:430px){
  .menu-page{background:#f8ead5}
  .menu-page::before{display:block}
}

/* Game Over on phones: shrink the art a touch so the panel doesn't crowd short
   screens (it sits in the stage, with the endbar below it). */
@media(max-width:600px){
  .result-art-sad{width:min(58vw,232px);height:min(58vw,232px)}
}
@media(max-height:720px){
  .result-art-sad{width:min(47vw,184px);height:min(47vw,184px)}
  .result-note{font-size:13px;margin-top:7px}
  .result-retry{margin-top:12px}
}

/* Win: a persistent celebration + placement panel (mirrors the Game Over one) --
   celebrate art, the shout, "you placed #N", a compact board window, and the
   Share / Leaderboard actions. It replaces the board in the stage; the end bar
   below keeps only Next Puzzle. */
.result-win{
  animation:result-fadein .3s ease both;
  width:min(88vw,360px);
  max-height:min(74vh,600px);
  overflow:hidden auto;
  gap:2px;
}
.result-art-win{width:min(34vw,116px);height:auto}
/* Larger screens have the room: let Prof. Noodle celebrate at a proper size. */
@media(min-width:700px) and (min-height:760px){
  .result-win{width:min(88vw,400px)}
  .result-art-win{width:200px}
}
.result-win .result-word{margin-top:6px}
.result-win .placement{margin:7px 0 0;font-weight:700}
/* The offline note replaces the placement line when the finish couldn't be sent. */
.won-offline{margin:7px 0 0;font-style:italic;font-size:13px;color:#927f75;text-align:center}
.won-offline.hidden{display:none}
/* Push opt-in nudge on the daily win card (see maybeShowPushNudge). */
.won-nudge{
  display:flex;flex-direction:column;align-items:center;gap:8px;
  margin:10px auto 0;padding:10px 16px;max-width:340px;
  border:1px solid #b6a6d5;border-radius:14px;background:rgba(142,124,195,.12);
  font-size:14px;
}
.won-nudge.hidden{display:none}
.won-nudge-text{text-align:center;line-height:1.4}
.won-nudge-actions{display:flex;gap:8px}
.won-nudge-actions .btn{padding:7px 16px;font-size:14px}
.won-board{width:100%;margin-top:12px;display:flex;flex-direction:column}
.lb-row-compact{grid-template-columns:26px minmax(0,1fr) auto}
.lb-gap{text-align:center;color:#9aa4b0;font-weight:800;letter-spacing:2px;line-height:.5;padding:1px 0 7px}
/* The card's own action row (Share + Leaderboard, same .btn.icon look as the bar). */
.won-actions{display:flex;gap:10px;justify-content:center;margin:12px 0 2px}

/* --- Today's-daily result card (home.js) + the Leaderboards hub (boards.js) --- */
/* The card sits under the CTA buttons in the stats area, for everyone who solved
   today's daily: time, rank, streak, and the countdown; tapping opens the hub. */
.menu-daily{
  display:flex;align-items:center;justify-content:space-between;gap:10px;
  width:100%;margin-top:14px;padding:10px 14px 9px;cursor:pointer;
  border:1px solid rgba(205,191,174,.62);border-radius:16px;
  background:rgba(255,247,234,.85);font-family:inherit;
}
.menu-daily-text{display:flex;flex-direction:column;gap:2px;align-items:flex-start;text-align:left;min-width:0;flex:1}
.menu-daily-icon{
  flex:0 0 auto;width:38px;height:38px;border-radius:50%;
  display:inline-flex;align-items:center;justify-content:center;font-size:19px;
  background:radial-gradient(circle at 35% 30%,rgba(183,166,223,.55),rgba(125,104,178,.35));
  box-shadow:inset 0 0 0 1px rgba(142,124,195,.35);
}
.menu-daily:hover{background:rgba(142,124,195,.12);border-color:#b6a6d5}
.menu-daily.hidden{display:none}
/* Domain-move banner (legacy origins only): the daily card's look, purple-
   washed so it reads as an announcement, with Go / Later actions. */
.menu-move{
  display:flex;flex-direction:column;gap:10px;
  width:100%;margin-top:14px;padding:12px 14px;
  border:1px solid #b6a6d5;border-radius:16px;
  background:rgba(142,124,195,.14);text-align:left;
}
.menu-move.hidden{display:none}
.menu-move-text{display:flex;flex-direction:column;gap:2px;font-size:14px;line-height:1.4}
.menu-move-text strong{color:var(--title);font-size:15px}
.menu-move-actions{display:flex;gap:8px;justify-content:flex-end}
.menu-move-actions .btn{padding:7px 18px;font-size:14px}
.menu-daily-head{font-weight:800;font-size:14px;color:#392f3e}
.menu-daily-info{font-weight:700;font-size:12.5px;color:#6b598f}
.menu-daily-next{font-size:11px;font-style:italic;color:#927f75;font-variant-numeric:tabular-nums}

/* The hub's Daily-tab pager: older/newer around the date label. */
.boards-pager{display:flex;align-items:center;justify-content:space-between;gap:8px;margin:2px 0 10px}
.boards-page{
  border:1px solid rgba(205,191,174,.7);border-radius:999px;background:transparent;
  color:#6b598f;font-weight:700;font-size:12px;padding:4px 12px;cursor:pointer;font-family:inherit;
}
.boards-page:disabled{opacity:.4;cursor:default}
.boards-page-label{font-weight:800;font-size:14px;color:#392f3e}
/* Standings rows reuse .lb-row; the played-stat strip ("<icon> <n>" per stat)
   stays quiet next to the name. */
.st-stats{display:flex;gap:9px;align-items:center;white-space:nowrap}
.st-stat{display:inline-flex;align-items:center;gap:3px;font-size:11px;font-weight:700;color:#7c6a53;font-variant-numeric:tabular-nums}
.st-stat svg{width:12px;height:12px}
.st-time{color:#6b598f}
/* The hub keeps ONE size: the section box is fixed-height, and inside it only
   the ROWS scroll -- the header ("Easy" + window switcher) and the pager stay
   put on top, the share button pins to the dialog's bottom edge. */
.boards-section{height:min(56vh,440px);overflow:hidden}
.boards-section>div{display:flex;flex-direction:column;height:100%;min-height:0}
.boards-section>div>*{flex-shrink:0}
.boards-scroll{flex:1 1 0;min-height:0;overflow-y:auto}
.boards-share{display:flex;justify-content:center;padding-top:10px}
/* Center the tier name against the pill switcher (baseline puts it too high). */
.boards-head{align-items:center;padding-bottom:10px}
@media (max-width: 560px){.boards-section{height:auto;flex:1;min-height:0}
  #boardsHubBody{display:flex;flex-direction:column;flex:1;min-height:0}}
