/* ─────────────────────────────────────────────────────────────────────────
   Zero Cascade — variant of Zero Rush (experiment/gravity-refill)
   Design intent: the ± pair must be recognisable BEFORE the arithmetic is.
   Same |value| = same lightness/saturation, opposite hue. Palette is
   9-step (magnitudes 1..9) and computed in JS (valueColor() in game.js),
   not hand-picked CSS classes — see that function for the two endpoint
   colors each sign ramps between.
   ───────────────────────────────────────────────────────────────────────── */

:root {
  --bg:        #11141c;
  --bg-soft:   #191d28;
  --line:      #262c3a;
  --ink:       #e8ecf5;
  --ink-dim:   #8b93a7;
  --gold:      #ffd23f;

  --gap: clamp(3px, 1vw, 6px);
}

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

html, body {
  height: 100%;
  background: var(--bg);
  color: var(--ink);
  font-family: ui-rounded, "SF Pro Rounded", "Segoe UI", system-ui, -apple-system, sans-serif;
  -webkit-font-smoothing: antialiased;
  overscroll-behavior: none;
}

body {
  display: flex;
  justify-content: center;
  /* the board is a drag surface: never let the page pan under the finger */
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  -webkit-tap-highlight-color: transparent;
}

#app {
  width: min(100vw, 520px);
  height: 100dvh;
  padding: max(10px, env(safe-area-inset-top)) 12px max(10px, env(safe-area-inset-bottom));
  display: flex;
  flex-direction: column;
  gap: 10px;
}

/* ─── HUD ───────────────────────────────────────────────────────────────── */

#hud {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 8px;
}

.hud-cell { display: flex; flex-direction: column; gap: 2px; }
#hudScore { align-items: flex-end; }
#hudNeed  { align-items: center; }
#hudTimer { position: relative; }   /* anchors the "+Xs" clock popup (floatTimeAtClock) */

.hud-label {
  font-size: 10px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-dim);
}

.hud-value {
  font-size: 22px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1;
}

/* Shows the actual running chain sum — matches the Godot build's phantom
   sum, so the number moves the direction players expect. */
.hud-need .hud-value {
  font-size: 34px;
  min-width: 2.2ch;
  text-align: center;
  transition: color .12s, transform .12s;
}
.hud-need.idle  .hud-value { color: var(--ink-dim); }
.hud-need.armed .hud-value { color: var(--ink); }
.hud-need.zero  .hud-value { color: var(--gold); transform: scale(1.14); }

#timerValue.urgent { color: #ff5b5b; }

/* ─── Rolling time bar ──────────────────────────────────────────────────── */

#timeBarTrack {
  height: 6px;
  border-radius: 3px;
  background: var(--line);
  overflow: hidden;
}
#timeBar {
  height: 100%;
  width: 100%;
  border-radius: 3px;
  background: linear-gradient(90deg, #57e08a, #ffd23f);
  transform-origin: left center;
  transform: scaleX(1);
  transition: transform .12s linear;
}
#timeBar.low { background: #ff5b5b; }

/* ─── Board ─────────────────────────────────────────────────────────────── */

#boardWrap {
  position: relative;
  flex: 1;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: opacity .28s;
}

#board {
  display: grid;
  gap: var(--gap);
  /* dimensions are injected by JS so the grid stays square-celled */
  touch-action: none;
}

#chainLayer {
  position: absolute;
  pointer-events: none;
  overflow: visible;
}

#chainLine {
  fill: none;
  stroke: rgba(255, 255, 255, .55);
  stroke-width: 7;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: stroke .12s;
}
#chainLine.zero { stroke: var(--gold); stroke-width: 9; }

/* ─── Tiles ─────────────────────────────────────────────────────────────── */

.tile {
  position: relative;
  display: grid;
  place-items: center;
  border-radius: 50%;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  line-height: 1;
  transition: transform .1s ease, opacity .18s ease, box-shadow .12s, filter .12s;
  will-change: transform;
}

/* background-color comes from valueColor() inline (game.js) — a fixed
 * 4-class CSS palette can't cover 9 magnitudes cleanly, so this went
 * JS-computed. Text contrast follows the same light/dark split. */
.tile.light { color: #10131a; }
.tile.dark  { color: #f4f7fb; }

/* Selected ring: saturated amber glow + brightened tile — same language as
   the Godot build's GlowRing (RING_COLOR) + lightened(0.4) base color. */
.tile.chained {
  transform: scale(.9);
  filter: brightness(1.35) saturate(1.15);
  box-shadow: 0 0 0 3px rgba(255, 148, 10, .95), 0 0 16px 2px rgba(255, 148, 10, .6);
  z-index: 2;
}
.tile.zero {
  box-shadow: 0 0 0 3px var(--gold), 0 0 18px rgba(255, 210, 63, .55);
}

/* Adjacent tiles that would complete the chain to exactly zero.
   This is the training wheel that turns arithmetic into recognition —
   experienced players stop seeing it because they act before it matters. */
.tile.finisher {
  animation: finisher 1s ease-in-out infinite;
  z-index: 1;
}
@keyframes finisher {
  0%, 100% { box-shadow: 0 0 0 0 rgba(255, 210, 63, 0); }
  50%      { box-shadow: 0 0 0 3px rgba(255, 210, 63, .85); }
}

.tile.hint { animation: hint 1.1s ease-in-out 2; }
@keyframes hint {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(.86); }
}

.tile.cleared {
  opacity: 0;
  transform: scale(.2);
  pointer-events: none;
}

/* Onboarding: tiles not part of the current demo chain (or, before
   revealPathCells() runs, the whole board) fade back. */
.tile.dim { opacity: .18; transition: opacity .25s; }
body.mono .tile.dim { opacity: .22; }

/* Ghost cursor that traces the demo chain. */
#ghost {
  position: absolute;
  width: 23px;
  height: 23px;
  margin: -11.5px 0 0 -11.5px;
  border-radius: 50%;
  background: rgba(255, 255, 255, .55);
  box-shadow: 0 0 0 3px rgba(0, 0, 0, .22), 0 3px 10px rgba(0, 0, 0, .4);
  pointer-events: none;
  z-index: 6;
  transition: left .3s ease, top .3s ease;
}
#ghost[hidden] { display: none; }

/* Controls (dots + Next) pinned to the bottom during the tutorial. */
#tutorialUI {
  position: fixed;
  left: 0;
  right: 0;
  bottom: max(24px, env(safe-area-inset-bottom));
  z-index: 20;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  padding: 0 20px;
  pointer-events: none;
}
#tutorialUI[hidden] { display: none; }

/* Caption lives above the board itself so it grabs the eye before any
   on-board animation starts (see revealCaption() in game.js). */
body:not(.tutorial) #tutorialCaption { display: none; }
#tutorialCaption {
  position: absolute;
  top: max(10px, env(safe-area-inset-top));
  left: 20px;
  right: 20px;
  max-width: 420px;
  margin: 0 auto;
  padding: 12px 18px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: rgba(17, 20, 28, .93);
  color: var(--ink);
  font-size: 15px;
  font-weight: 600;
  text-align: center;
  line-height: 1.35;
  z-index: 15;
  pointer-events: none;
  opacity: 1;
  transform: translateY(0);
  transition: opacity .42s ease, transform .42s ease;
}
#tutorialCaption.fading { opacity: 0; transform: translateY(-8px); }
#tutorialNext {
  width: auto;
  min-width: 140px;
  margin: 0;
  padding: 11px 26px;
  pointer-events: auto;
}
#tutorialClose {
  position: fixed;
  top: max(14px, env(safe-area-inset-top));
  right: 16px;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: rgba(17, 20, 28, .8);
  color: var(--ink-dim);
  font-size: 15px;
  cursor: pointer;
  pointer-events: auto;
  z-index: 21;
}
.tut-dots { display: flex; gap: 7px; pointer-events: none; }
.tut-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--ink-dim);
  opacity: .35;
}
.tut-dot.on { opacity: 1; background: var(--gold); }

/* Cross-fade the board between tutorial pages. */
#boardWrap.fading { opacity: 0; }

/* ─── Start-screen mini "screenshot" (Z chain to zero) ───────────────────── */
.start-art { position: relative; margin: 14px auto 8px; }
.start-mini { display: grid; }
.start-mini .tile { width: 40px; height: 40px; font-size: 18px; }
/* Gold "selected" ring that keeps the stone's own black/white colour. */
.start-mini .tile.lit {
  box-shadow: 0 0 0 3px var(--gold), 0 0 14px rgba(255, 210, 63, .5);
  z-index: 1;
}
.start-mini-line {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
  z-index: 2;               /* draw the connector OVER the selected stones */
}
.start-mini-line line {
  stroke: var(--gold);        /* same colour + fully opaque as the ring → blends */
  stroke-width: 4;
  stroke-linecap: round;
}

/* ─── Monochrome variant (body.mono — experiment/black-white) ────────────────
   Black/white "stones" on a neutral board (Go/chess look). */

/* Board surface matches the dark gray used by the main menu sheet + message
   boxes (--bg-soft) instead of a pale neutral, so Play mode reads as one
   consistent dark UI. The box-shadow spread paints --board outward as a
   framing border without changing grid geometry (JS positions the chain SVG
   off #board's box, so real padding/border would misalign it). */
body.mono { --board: var(--bg-soft); }
body.mono #board {
  background: var(--board);
  border-radius: 12px;
  box-shadow: 0 0 0 10px var(--board), 0 10px 26px rgba(0, 0, 0, .45);
}

/* Stone shine: a soft top-left sheen + faint bottom shading for roundness —
   kept subtle (a matte stone, not a billiard ball). Layered as background-image
   over the solid fill that paintTile() sets via backgroundColor. */
body.mono .tile {
  background-image:
    radial-gradient(circle at 33% 27%, rgba(255, 255, 255, .28), rgba(255, 255, 255, 0) 34%),
    radial-gradient(circle at 70% 84%, rgba(0, 0, 0, .16), rgba(0, 0, 0, 0) 55%);
  box-shadow: 0 2px 5px rgba(0, 0, 0, .4);
}
body.mono .tile.light { border: 1px solid rgba(0, 0, 0, .20); }
/* Rim-light instead of a dark outline: on the now-dark board a black-on-dark
   border would erase the stone's edge entirely. */
body.mono .tile.dark  { border: 1px solid rgba(255, 255, 255, .16); }

/* Selected stones wash gold (same --gold as the primary buttons) so the chain
   reads clearly regardless of the stone's own colour; dark text stays legible
   on the gold. Overrides the colour-mode brightness/amber treatment. */
body.mono .tile.chained {
  filter: none;
  color: #17130a;
  border-color: rgba(0, 0, 0, .28);
  background-image: linear-gradient(rgba(255, 210, 63, .92), rgba(255, 210, 63, .92));
  box-shadow: 0 0 0 3px var(--gold), 0 0 16px 2px rgba(255, 210, 63, .6);
}
/* Balanced chain: a stronger gold ring on top of the wash. */
body.mono .tile.zero {
  box-shadow: 0 0 0 4px var(--gold), 0 0 20px rgba(255, 210, 63, .7);
}
/* The drag line is white by default — invisible on the light board — so make it
   gold to match the selected stones. */
body.mono #chainLine { stroke: rgba(255, 200, 45, .9); }

.tile.popping { animation: pop .22s ease-out forwards; }
@keyframes pop {
  0%   { transform: scale(.88); opacity: 1; }
  40%  { transform: scale(1.18); opacity: 1; }
  100% { transform: scale(.2);  opacity: 0; }
}

/* Falling / refilling tiles (gravity variant). The cubic-bezier overshoots
 * slightly past 1 for a small landing bounce. Duration must match FALL_MS
 * in game.js. Higher specificity than the base .tile transition so it wins
 * for the settle animation. */
.tile.falling {
  transition: transform .34s cubic-bezier(.30, 1.30, .55, 1);
  z-index: 1;
}

/* Floating "+score" that rises and fades from where a chain cleared. */
.float-score {
  position: absolute;
  transform: translate(-50%, -50%);
  font-weight: 900;
  font-size: 20px;
  color: var(--gold);
  text-shadow: 0 1px 3px rgba(0, 0, 0, .6);
  pointer-events: none;
  z-index: 5;
  animation: floatscore .85s ease-out forwards;
}
.float-score.big { font-size: 30px; }
@keyframes floatscore {
  0%   { opacity: 0; transform: translate(-50%, -30%) scale(.7); }
  18%  { opacity: 1; transform: translate(-50%, -60%) scale(1.1); }
  100% { opacity: 0; transform: translate(-50%, -160%) scale(1); }
}

/* "+Xs" clock reward — green, drifts up alongside the score popup */
.float-time {
  position: absolute;
  transform: translate(-50%, -50%);
  font-weight: 800;
  font-size: 15px;
  color: #57e08a;
  text-shadow: 0 1px 3px rgba(0, 0, 0, .6);
  pointer-events: none;
  z-index: 5;
  animation: floattime .85s ease-out forwards;
}
@keyframes floattime {
  0%   { opacity: 0; transform: translate(-50%, -10%); }
  22%  { opacity: 1; transform: translate(-50%, -70%); }
  100% { opacity: 0; transform: translate(-50%, -190%); }
}
/* Anchored on #hudTimer (position:relative) instead of the board — ties the
   reward explicitly to the clock it's feeding (floatTimeAtClock()). */
.float-time.clock { left: 50%; top: 0; }

/* ─── Footer ────────────────────────────────────────────────────────────── */

#footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 11px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-dim);
}

.footer-right {
  display: flex;
  align-items: center;
  gap: 12px;
}

.mute-btn {
  background: none;
  border: none;
  padding: 2px 4px;
  font-size: 17px;
  line-height: 1;
  cursor: pointer;
  opacity: .85;
  transition: opacity .12s, transform .08s;
  -webkit-tap-highlight-color: transparent;
}
.mute-btn:hover  { opacity: 1; }
.mute-btn:active { transform: scale(.9); }
.mute-btn.is-muted { opacity: .5; }

/* ─── Overlay ───────────────────────────────────────────────────────────── */

.overlay {
  position: fixed;
  inset: 0;
  background: rgba(9, 11, 16, .9);
  backdrop-filter: blur(6px);
  display: grid;
  place-items: center;
  padding: 16px;
  z-index: 10;
}
.overlay[hidden] { display: none; }

.sheet {
  width: min(100%, 420px);
  max-height: 100%;
  overflow-y: auto;
  background: var(--bg-soft);
  border: 1px solid var(--line);
  border-radius: 20px;
  padding: 26px 22px;
  text-align: center;
}

.logo {
  font-size: 40px;
  font-weight: 900;
  letter-spacing: -.02em;
  line-height: .95;
}
.logo span { display: block; color: var(--gold); }
/* One-line variant (start screen) — frees vertical room below. */
.logo-inline { white-space: nowrap; }
.logo-inline span { display: inline; }
/* "ZERO" is now its own span too (so the splash intro can reveal it
   independently of "RUSH") — pull it back out of the generic `.logo span`
   gold-coloring, which is meant only for the logo's second word. */
#logoZero { color: inherit; }

.tagline {
  margin-top: 8px;
  font-size: 13px;
  color: var(--ink-dim);
}
/* Start-screen objective: brighter + a touch larger than a plain tagline. */
#startSub {
  margin-top: 12px;
  font-size: 15px;
  font-weight: 600;
  color: var(--ink);
  min-height: 1.6em;   /* holds the line's height while the intro types it in */
}

/* ─── Splash intro reveal (playSplashIntro() in game.js) ───────────────────
   Staged appearance on first load: ZERO, then RUSH, then the mini board,
   then the typed tagline, then the menu buttons.

   ZERO/RUSH (`.splash-word`) run as a plain CSS @keyframes animation that
   starts the moment the page renders — no JS needed to kick it off, so
   there's no race with page-load timing (a JS class-toggle on the very
   first tick has no earlier "hidden" frame to transition from and can pop
   in instead of fading; a declarative animation has no such race).

   Everything after that (board / buttons) IS JS-driven: `.reveal-pre` is
   the hidden rest state, `.reveal-in` (added in sequence by JS, well after
   first paint so no race there either) transitions it in. pointer-events
   stay off until revealed so a still-invisible button can't be tapped
   early. Tapping the sheet mid-sequence skips straight to the end (see
   skipSplash()). */
/* No fade — a hard cut from invisible to visible at each word's delay.
 * animation-duration:0 + forwards just flips opacity the instant the delay
 * elapses; still a plain declarative animation (see note above), so there's
 * still no JS/paint race to worry about. Numbers here must match
 * SPLASH_LOGO_DELAY_MS / SPLASH_LOGO_STAGGER_MS in game.js, which waits out
 * the same span before revealing the mini board. */
@keyframes splashWordIn {
  to { opacity: 1; }
}
.splash-word {
  opacity: 0;
  animation: splashWordIn 0s linear .5s forwards;
}
#logoRush { animation-delay: .75s; }   /* ZERO at .5s, RUSH .25s later at .75s */

.reveal-pre {
  opacity: 0;
  transform: translateY(10px) scale(.97);
  pointer-events: none;
  transition: opacity .5s ease, transform .5s cubic-bezier(.2, .8, .3, 1);
}
.reveal-pre.reveal-in {
  opacity: 1;
  transform: none;
  pointer-events: auto;
}

.rules { margin: 22px 0; text-align: left; }

.rule { display: flex; align-items: center; gap: 14px; }
.rule p { font-size: 14px; line-height: 1.45; }

.rule-art { display: flex; gap: 4px; flex: none; }
.rule-art .tile { width: 30px; height: 30px; font-size: 13px; }

.rule-list {
  margin-top: 14px;
  padding-left: 18px;
  font-size: 13px;
  line-height: 1.7;
  color: var(--ink-dim);
}
.rule-list strong { color: var(--ink); font-weight: 700; }

.btn {
  display: block;
  width: 100%;
  margin-top: 10px;
  padding: 14px;
  border: 1px solid var(--line);
  border-radius: 13px;
  background: #222736;
  color: var(--ink);
  font: inherit;
  font-size: 15px;
  font-weight: 700;
  cursor: pointer;
  transition: filter .12s, transform .08s;
}
.btn:hover  { filter: brightness(1.16); }
.btn:active { transform: scale(.985); }

.btn.primary { background: var(--gold); border-color: var(--gold); color: #17130a; }
.btn.ghost   { background: none; border-color: transparent; color: var(--ink-dim); font-weight: 600; font-size: 13px; }

/* ─── Result panel ──────────────────────────────────────────────────────── */

.result-reason {
  font-size: 12px;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--ink-dim);
}

.result-score {
  margin-top: 6px;
  font-size: 62px;
  font-weight: 900;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.result-total { font-size: 24px; color: var(--ink-dim); }

.result-pct { margin-top: 4px; font-size: 13px; color: var(--ink-dim); }

.result-grid {
  display: grid;
  gap: 2px;
  justify-content: center;
  margin: 20px 0;
}
.result-grid i {
  width: 10px;
  height: 10px;
  border-radius: 2px;
  background: #2b3140;
}
.result-grid i.on { background: var(--gold); }

.result-stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
  margin-bottom: 18px;
}
.result-stats div { display: flex; flex-direction: column; gap: 3px; }
.result-stats span { font-size: 21px; font-weight: 800; font-variant-numeric: tabular-nums; }
.result-stats em {
  font-size: 10px;
  font-style: normal;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ink-dim);
}

/* ─── High Scores panel ─────────────────────────────────────────────────── */

.scores-title { font-size: 30px; margin-bottom: 4px; }

.tabs {
  display: flex;
  gap: 6px;
  margin: 16px 0 12px;
}
.tab {
  flex: 1;
  padding: 9px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: transparent;
  color: var(--ink-dim);
  font: inherit;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: .04em;
  cursor: pointer;
  transition: background .12s, color .12s, border-color .12s;
}
.tab.active {
  background: #222736;
  color: var(--ink);
  border-color: #333b4e;
}

.score-list {
  list-style: none;
  margin: 0 0 12px;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-height: 210px;
}
.score-row {
  display: grid;
  grid-template-columns: 26px 1fr auto;
  align-items: baseline;
  gap: 10px;
  padding: 9px 12px;
  border-radius: 10px;
  background: var(--bg);
  text-align: left;
}
.score-row.you {
  background: #2a2f1e;
  outline: 1px solid var(--gold);
}
.score-rank {
  font-weight: 800;
  color: var(--ink-dim);
  font-variant-numeric: tabular-nums;
}
.score-row.you .score-rank { color: var(--gold); }
.score-main { font-weight: 700; }
.score-sub {
  font-size: 11px;
  color: var(--ink-dim);
  font-variant-numeric: tabular-nums;
}
.scores-note {
  font-size: 11px;
  color: var(--ink-dim);
  margin-bottom: 14px;
}

/* ─── Toast ─────────────────────────────────────────────────────────────── */

.toast {
  position: fixed;
  left: 50%;
  bottom: 32px;
  transform: translateX(-50%);
  padding: 11px 18px;
  border-radius: 11px;
  background: var(--ink);
  color: var(--bg);
  font-size: 13px;
  font-weight: 700;
  z-index: 20;
  animation: toast .25s ease-out;
}
.toast[hidden] { display: none; }
@keyframes toast {
  from { opacity: 0; transform: translate(-50%, 8px); }
  to   { opacity: 1; transform: translate(-50%, 0); }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}
