/* Maze — presentation only. The maze itself is drawn to a canvas, because a
   Colossal maze is 12,321 cells and pan/zoom redraws constantly; the renderer
   culls to the visible rectangle so the cost is the screen, not the maze. */

:root {
  --bg: #0f172a;
  --panel: #1e293b;
  --line: #334155;
  --ink: #e2e8f0;
  --dim: #94a3b8;
  --accent: #38bdf8;
  --go: #22c55e;
  --stop: #ef4444;
  --gem: #fbbf24;
  --wall: #cbd5e1;
  --floor: #1c2a44;
  --trail: #38bdf8;
  --fog: #0b1220;
}

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

/* The UA's `[hidden] { display: none }` is a low-specificity rule, so ANY class
   here that sets `display` beats it and the element stays visible. `.big` does,
   which shipped an empty ghost button where the Carry-on button lives. This is
   the same defect pixelator's stylesheet already carries a note about; the note
   was in the wrong file. */
[hidden] { display: none !important; }

html, body {
  margin: 0; padding: 0; height: 100%;
  background: var(--bg); color: var(--ink);
  font: 400 16px/1.45 -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  overscroll-behavior: none;
}

#app { height: 100%; display: flex; flex-direction: column; }

.scr { display: none; flex: 1; min-height: 0; flex-direction: column; }
.scr.on { display: flex; }

/* Menu and the text screens scroll; the play screen never does. */
#scr-menu, #scr-how, #scr-win {
  overflow-y: auto;
  padding: max(16px, env(safe-area-inset-top)) 16px calc(28px + env(safe-area-inset-bottom));
  align-items: stretch;
}

h1 { font-size: 30px; margin: 8px 0 2px; text-align: center; }
h2 { font-size: 17px; margin: 0 0 6px; }
.sub { text-align: center; color: var(--dim); margin-bottom: 16px; }

/* ---- buttons ---- */

.big, .linkBtn {
  display: block; width: 100%; margin: 8px 0; padding: 14px 16px;
  font: 600 16px/1 inherit; color: var(--ink);
  background: var(--panel); border: 1px solid var(--line); border-radius: 12px;
  cursor: pointer; text-align: center; text-decoration: none;
  -webkit-appearance: none; appearance: none; touch-action: manipulation;
}
.big.primary { background: var(--accent); color: #04233a; border-color: transparent; }
.big:active { transform: translateY(1px); }

.btn {
  padding: 9px 12px; font: 600 14px/1 inherit; color: var(--ink);
  background: var(--panel); border: 1px solid var(--line); border-radius: 10px;
  cursor: pointer; -webkit-appearance: none; appearance: none;
  touch-action: manipulation;
}

.pill {
  padding: 8px 10px; min-width: 40px; min-height: 40px;
  font: 600 14px/1 inherit; color: var(--ink);
  background: rgba(255, 255, 255, .06); border: 1px solid var(--line);
  border-radius: 10px; cursor: pointer; white-space: nowrap;
  display: flex; align-items: center; justify-content: center;
  -webkit-appearance: none; appearance: none; touch-action: manipulation;
}
/* A spent hint and an undo with nothing to undo have to LOOK unavailable.
   A control that always looks live and then refuses is the button lying. */
.pill:disabled { opacity: .35; cursor: default; }
/* ---- the hint control (docs/offline-pwa.md R-C16) -------------------------
   ONE bulb, and the count as an OVERLAID badge. Absolutely positioned inside
   `.bulb`, so 10 -> 9 -> 8 can never change the button's width and shove
   whatever sits beside it — which is exactly what the inline count did on a
   phone. The number is always how many are LEFT, it is shown at 1 and at 0,
   and at 0 the button is disabled with the badge still on it, because a
   control that vanishes teaches a child nothing about why.
   The badge is dark with a pale ring at every game, on purpose: the games run
   from near-black to amber to a light theme, and a dark pill with a light halo
   is the one combination that reads on all of them. */
.hintBtn { position: relative; overflow: visible; }
.hintBtn .bulb { position: relative; display: inline-block; line-height: 1; }
.hintBtn .hintN {
  position: absolute; right: -9px; bottom: -6px;
  min-width: 16px; height: 16px; padding: 0 3px; border-radius: 999px;
  background: #0f172a; color: #f8fafc; box-shadow: 0 0 0 1.5px rgba(255, 255, 255, .6);
  font: 800 10px/16px inherit; letter-spacing: 0; pointer-events: none;
}
.hintBtn:disabled .hintN, .hintBtn[disabled] .hintN { background: #64748b; }
/* `wide` = the bulb is followed by a WORD. The badge hangs 9px past the
   bulb, so without this it sits on the first letter of the label. */
.hintBtn.wide .bulb { margin-right: 11px; }


/* ---- mode + tiers ---- */

/* #modeRow shipped in v1.2 with NO rule of its own. Its children are `.opt`,
   which are `flex: 1 1 auto` -- and flex sizing does nothing in a plain block
   container, so the two buttons sat squashed together with no gap above or
   below. app.js was patching their padding inline, which is the tell: an
   inline style fixing spacing means the stylesheet is missing a rule. */
#modeRow { display: flex; gap: 8px; margin-bottom: 12px; }
#modeRow .opt { padding: 12px 6px; }

#tierRow { display: flex; gap: 8px; margin-bottom: 18px; }
.tier {
  flex: 1; padding: 12px 6px; border-radius: 12px; cursor: pointer;
  background: var(--panel); border: 1px solid var(--line); color: var(--ink);
  font: 600 13px/1.2 inherit; text-align: center;
  -webkit-appearance: none; appearance: none; touch-action: manipulation;
}
.tier .age { display: block; font-weight: 400; font-size: 11px; color: var(--dim); margin-top: 3px; }
.tier[aria-checked="true"] { border-color: var(--accent); background: #10344a; }

/* ---- customise ---- */

details#custom {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: 12px; margin: 8px 0; padding: 0 14px;
}
details#custom summary {
  padding: 14px 0; font-weight: 600; cursor: pointer; list-style: none;
  display: flex; align-items: center; gap: 8px;
}
details#custom summary::-webkit-details-marker { display: none; }
.badge {
  margin-left: auto; font: 400 12px/1 inherit; color: var(--dim);
  max-width: 60%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.fields { padding-bottom: 12px; }
.field { display: flex; align-items: center; gap: 10px; margin: 10px 0; }
.field .lbl { flex: 0 0 76px; font-size: 13px; color: var(--dim); }
.seg { display: flex; flex: 1; gap: 6px; min-width: 0; }
.seg.wrap { flex-wrap: wrap; }
.opt {
  flex: 1 1 auto; min-width: 0; padding: 9px 6px; border-radius: 9px;
  font: 600 13px/1 inherit; color: var(--ink); cursor: pointer;
  background: rgba(255, 255, 255, .05); border: 1px solid var(--line);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  -webkit-appearance: none; appearance: none; touch-action: manipulation;
}
.opt[aria-checked="true"] { border-color: var(--accent); background: #10344a; color: #bae6fd; }
/* A multi-select MUST NOT look like a single-select. Everything else in this
   menu is "pick one of these", and the powers row is "pick any of these" —
   drawn identically, the row silently teaches that ticking Compass unticks
   Dash. The tick is the difference a child can see; the dimming is the
   difference an adult reads without looking. */
.opt[role="checkbox"] { flex: 0 1 auto; opacity: .55; }
.opt[role="checkbox"][aria-checked="true"] { opacity: 1; }
.opt[role="checkbox"][aria-checked="true"]::before { content: "✓\00a0"; }
/* The pickaxe, armed. The next tap does something irreversible to the maze, so
   the button has to look like it is waiting for that tap rather than like it
   has merely been pressed. */
#btnPick.armed {
  background: #b45309; color: #fff; border-color: #f59e0b;
  animation: pickPulse .9s ease-in-out infinite alternate;
}
@keyframes pickPulse { from { box-shadow: 0 0 0 0 rgba(245,158,11,.6); }
                       to   { box-shadow: 0 0 0 6px rgba(245,158,11,0); } }
@media (prefers-reduced-motion: reduce) { #btnPick.armed { animation: none; } }
.seedRow { display: flex; flex: 1; gap: 6px; }
#seedIn {
  flex: 1; min-width: 0; padding: 9px 10px; border-radius: 9px;
  font: 600 13px/1 inherit; color: var(--ink);
  background: rgba(255, 255, 255, .05); border: 1px solid var(--line);
  -webkit-appearance: none; appearance: none;
}
.hint { font-size: 12px; color: var(--dim); margin: 10px 0 0; }

#statsLine { text-align: center; font-size: 12px; color: var(--dim); margin-top: 14px; }

/* ---- play ---- */

#hdr {
  flex: 0 0 auto; display: flex; gap: 6px; align-items: center;
  padding: max(6px, env(safe-area-inset-top)) 8px 6px;
  border-bottom: 1px solid var(--line); background: var(--bg);
}
#hdrTitle {
  flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; font-weight: 700; font-size: 15px;
}
#hdr .pill { min-width: 44px; min-height: 44px; font-size: 17px; }
/* The play toolbar sits UNDER the header now, so it no longer owns the safe
   area inset — the header does. */
#bar {
  display: flex; gap: 6px; align-items: center;
  padding: 6px 8px;
  border-bottom: 1px solid var(--line); background: var(--bg);
}
#barSpace { flex: 1; min-width: 0; }
/* An endless run's step count has no upper bound, so the readouts have to be
   able to shrink rather than shove each other off the bar. */
#bar .pill { padding: 8px 7px; font-size: 13px; min-width: 34px; }
/* R-C19: a number the player WATCHES CHANGE gets tabular figures. Measured on
   word-search: the clock pill swings between 51.3px and 66.3px as it counts,
   and the pill beside it slides 8px sideways — every second, and again at
   0:09 -> 0:10. Crossword found this, fixed its own clock, and wrote the
   reason into its own stylesheet, where the other four games could not read
   it. Fourth time a lesson has been recorded only where it was learned. */
#hudSteps, #hudGems, #hudTime {
  flex-shrink: 1; overflow: hidden; font-variant-numeric: tabular-nums;
}
#stage { flex: 1; min-height: 0; position: relative; overflow: hidden; }
#cv { position: absolute; inset: 0; width: 100%; height: 100%; touch-action: none; display: block; }
#playHint {
  padding: 6px 12px calc(6px + env(safe-area-inset-bottom));
  font-size: 12px; color: var(--dim); text-align: center; min-height: 24px;
}

/* ---- cards ---- */

.card {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: 12px; padding: 14px; margin: 8px 0; font-size: 14px;
}
.card.win { text-align: center; }

/* ---- the legend (docs/offline-games-pwa.md R-L1) ----
   Same row shape as Chef Quest's, Diner Rush's and breakout's: a fixed-width
   swatch column so the eye can run the marks instead of the sentences. Every
   swatch takes its colour from `--m`, which app.js sets to the SAME custom
   property the canvas resolves — the stylesheet holds the shape and nothing
   else, so a retheme cannot leave the legend behind. */
.lgSub { font-weight: 600; font-size: 13px; color: var(--dim); margin: 10px 0 6px; }
.legend { display: flex; flex-direction: column; gap: 8px; }
.lgRow { display: flex; align-items: center; gap: 10px; }
.lgArt { flex: none; width: 40px; height: 20px; display: flex; align-items: center; justify-content: center; font-style: normal; }
.lgArt.lg-dot { }
.lgArt.lg-dot::after { content: ''; width: 13px; height: 13px; border-radius: 50%; background: var(--m); }
.lgArt.lg-ring::after { content: ''; width: 16px; height: 16px; border-radius: 50%; border: 3px solid var(--m); }
/* ring PLUS a centre pip — what mark(…, ring) actually draws */
.lgArt.lg-ringpip { position: relative; }
.lgArt.lg-ringpip::after { content: ''; width: 16px; height: 16px; border-radius: 50%; border: 3px solid var(--m); }
.lgArt.lg-ringpip::before { content: ''; position: absolute; left: 50%; top: 50%; width: 6px; height: 6px; margin: -3px 0 0 -3px; border-radius: 50%; background: var(--m); }
.lgArt.lg-line::after { content: ''; width: 34px; height: 6px; border-radius: 3px; background: var(--m); }
.lgArt.lg-dash::after { content: ''; width: 34px; height: 6px; border-radius: 3px; background: repeating-linear-gradient(90deg, var(--m) 0 7px, transparent 7px 13px); }
.lgArt.lg-thin::after { content: ''; width: 34px; height: 2px; background: var(--m); opacity: 0.6; }
.lgArt.lg-arrow::after { content: ''; width: 0; height: 0; border-left: 13px solid var(--m); border-top: 8px solid transparent; border-bottom: 8px solid transparent; }
.lgArt.lgGlyph { font-size: 19px; }
.lgTxt { display: flex; flex-direction: column; min-width: 0; }
.lgTxt b { font-weight: 700; }
.lgTxt small { font-size: 12.5px; color: var(--dim); line-height: 1.35; }
#winStars { font-size: 34px; letter-spacing: 4px; }
#winBody { color: var(--dim); margin-top: 6px; }
#winBest { color: var(--gem); font-weight: 600; margin-top: 8px; min-height: 20px; }

/* ---- toast ---- */

#toast {
  position: fixed; left: 50%; bottom: calc(64px + env(safe-area-inset-bottom));
  transform: translateX(-50%) translateY(12px);
  background: #0b1220; border: 1px solid var(--line); color: var(--ink);
  padding: 10px 14px; border-radius: 10px; font-size: 14px;
  opacity: 0; pointer-events: none; transition: opacity .18s, transform .18s;
  z-index: 50; max-width: calc(100vw - 32px); text-align: center;
}
#toast.on { opacity: 1; transform: translateX(-50%) translateY(0); }

/* A wide screen is more room, never a bigger maze — the cell count is fixed
   per preset on every device (docs/maze-spec.md R10). */
@media (min-width: 720px) {
  #scr-menu, #scr-how, #scr-win { max-width: 560px; margin: 0 auto; width: 100%; }
}

/* docs/offline-pwa.md R-C15 — the PAGE must never scroll.
   The product is a fixed frame: header, a named scroll region, footer. If the
   document scrolls too, the header scrolls away, the version chip drifts, and
   a drag that reaches the end of the inner region chains out to the page and
   drags the whole board under the player's thumb. That is the "double scroll".
   `overflow: hidden` stops the second scrollbar; `overscroll-behavior: none`
   stops the chaining, which is the half that is invisible on a desktop mouse
   and obvious on a phone. */
html, body {
    overflow: hidden;
    overscroll-behavior: none;
}
