/* Sapper's Path v3 chrome: castle-wall background (painted by art.js, set as --wall), bevelled stone and gold buttons,
   parchment panels, and the Jersey 10 pixel face (SIL OFL, fonts/) for headings, buttons and numbers. The board sits in
   a light wooden frame; queue tiles are solid colour with big numbers (v4 M1: colour first, three rows). main.js sets the
   material colours. v4 M2: mystery tiles, the rods between linked tiles, the padlocked space and linked spaces.
   v4 Critics 1 fix: the holding line and the queue sit on one light stone tray (--tray); the rows behind the front fade
   toward the tray and step down in size (main.js mixes the colour, layout.fade), never by opacity; a space's badges keep
   to a left column beside its count (a grid), so no badge ever covers a count; mystery tiles are a face-down card; the
   coach has a fixed-height box (above the board, or in the top bar, or in the side panel on wide screens); desktop puts
   the controls, line and queue in one side column the board's height, with a reserved spot for M5's power-up bar.
   v4 M4: the Gallery screen (a grid of picture tiles, dimmed until won) and its buttons on the title and the map, which
   show a padlock and the unlock hint while the Gallery is closed.
   v4 M5: the home screen (on the title scene: a top row of pills, one dominant Play, a tab bar), the settings sheet, the
   level report's rows on the win sheet, report cards on the map and the Gallery, and the power-up bar: a band of four
   round badges under the queue (the only round shapes in a level), the foot of the side column on wide screens. Short
   frames (max-height 640) show two queue rows (body.rows2) so the bar fits. Sizes are the --pw-* variables.
   v4 Critics 2 fix: the coach wraps to two lines in the top bar; the Gallery win's framed picture (#p-pic, #stage-pic);
   the Gallery's next tile (gold frame, Play chip); a buy short of coins (.pw.poor); 44 px badges in small frames; the
   landscape bar's .head and .grid; the home's era chip on the river; era report cards as a band.
   v5.3: the home's painted siege (#title-art, a <picture>) and the realm line over Play. */
@font-face { font-family: "Jersey 10"; src: url("fonts/Jersey10-Regular.ttf?v=90") format("truetype"); font-weight: 400; font-style: normal; font-display: swap; }
:root { --bg: #2e2935; --ink: #221a26; --cream: #f3ead8; --cream-soft: #cfc4d6;
  --tray: #ddd3c0; --tray-hi: #ece5d6; --tray-edge: #c4b89e; --tray-ink: #3a3027; --tray-soft: #6b5c47; --socket: #c3b697; --socket-lo: #a99a7b;
  --band1: #d0c6b4; --band2: #c2baa9; /* the rows' tray bands, set from layout.fade.band at boot */
  --tray-full: #93540a; --tray-bad: #b3301c; --tray-march: #7a5a06; --lock-socket: #3b3342; --ring-w: 2; --ring-a: .8; --ring-halo: #141a33; --ring-halo-w: 4; --ring-halo-a: .4; --key-gilt: #c9a020; --pin-rim: #c2321f; --pin-hatch: rgba(178,36,26,.42); --pin-badge: #b3241a; --mys-dot: rgba(242,194,48,.34); --mys-rim: rgba(242,194,48,.55);
  --stone: #a2a5b0; --stone-hi: #cdd0d8; --stone-lo: #666a77; --gold: #f2c230; --gold-hi: #ffe27a; --gold-lo: #b8860b; --gold-dark: #7a5a06;
  --parch: #fbf5e6; --parch-edge: #e3d3ad; --parch-ink: #2a2430; --parch-soft: #5a4e3c;
  --danger: #b3301c; --danger-fill: #6e1a0e; --danger-ink: #a3271a; /* v5.4: Reset progress */
  --glow: #fff3a8; --flash: #ff5a3c; --pill: rgba(20,16,28,.78); --off: #544e5c;
  --wood: #e8cf9e; --wood-mid: #b98d52; --wood-lo: #7a5a33;
  --px: "Jersey 10", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --gut: max(8px, env(safe-area-inset-left));
  --tile-h: 52px; --tile-n: 40px; --tile-gap: 6px; --gl-s: 14px; --slot-h: 50px; --slot-n: 36px; --man: 18px;
  --s1: .9; --s2: .8; --rim1: 38%; --rim2: 55%; --ch-s: 12px; --bd: 16px; --lk-s: 14px; --out-n: 13px; --coach-h: 46px; --coach-fs: 21px; --tray-pad: 7px;
  /* v4 M5: the power-up bar's band height, badge diameter, icon share of the badge, count bubble; the pills */
  --pw-h: 70px; --pw-d: 58px; --pw-ic: 66%; --pw-b: 24px; --pw-bfs: 20px; --pw-band: #3a3342; --pw-disc: #f3ead8; --pw-disc-lo: #cfc0a0; --pw-plus: #3fbf5a; --pw-plus-lo: #23843a; --pw-poor: #7d7588; --pw-poor-lo: #5a5366; --pw-poor-tag: #ffd9cf; --pw-poor-ink: #b3301c;
  --pill-h: 38px; --pill-fs: 24px; --ico: 24px; --tab-h: 70px; --play-h: 64px; }
* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; font-synthesis: none; overflow: hidden; overscroll-behavior: none; color: var(--cream);
  background: var(--bg) var(--wall, none) repeat; background-size: var(--wall-size, auto); image-rendering: pixelated;
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; -webkit-tap-highlight-color: transparent;
  -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; -webkit-text-size-adjust: 100%; }
#app { position: relative; display: flex; flex-direction: column; height: 100%; height: 100dvh; max-width: 560px; margin: 0 auto;
  padding: env(safe-area-inset-top) var(--gut) 0 var(--gut); image-rendering: auto; overflow: hidden; } /* v4 M5: the level's column behind the home (no board fitted yet) never scrolls the page */
.pix { image-rendering: pixelated; image-rendering: crisp-edges; }

/* Buttons: stone blocks with a lit top edge and a dark lip that drops when pressed; gold for the main action. */
button { font-family: var(--px); font-weight: 400; font-size: 26px; min-height: 48px; padding: 0 16px; border-radius: 6px; border: 3px solid var(--ink);
  background: var(--stone); color: var(--ink); cursor: pointer; touch-action: manipulation;
  box-shadow: inset 0 3px 0 var(--stone-hi), inset 0 -5px 0 var(--stone-lo), 0 3px 0 rgba(0,0,0,.5); }
button:active:not(:disabled) { transform: translateY(2px); box-shadow: inset 0 3px 0 var(--stone-hi), inset 0 -2px 0 var(--stone-lo), 0 1px 0 rgba(0,0,0,.5); }
button:disabled { cursor: default; }
button[hidden] { display: none; }
button.primary { background: var(--gold); box-shadow: inset 0 3px 0 var(--gold-hi), inset 0 -5px 0 var(--gold-lo), 0 3px 0 rgba(0,0,0,.5); }
button.primary:active:not(:disabled) { box-shadow: inset 0 3px 0 var(--gold-hi), inset 0 -2px 0 var(--gold-lo), 0 1px 0 rgba(0,0,0,.5); }
button.round { width: 42px; height: 42px; min-height: 42px; padding: 0; border-radius: 8px; display: flex; align-items: center; justify-content: center; flex: none; }
/* Lands foundation: the play bar's buttons answer 4 px round their face, so a 36-38 px button on a short phone still
   takes a 44 px tap (the bar's 6 px gaps share 2 px between neighbours). */
body.held #pwtip { visibility: hidden; } /* lands foundation: a power-up tip waits while Settings is open over a level */
#top { position: relative; z-index: 4; } #top button.round { position: relative; } #top button.round::after { content: ""; position: absolute; inset: var(--round-tap, -7px); } /* 4 px past the 3 px border; #top over the stage's top edge (sheets, modals, the pause and the screens stay above it) */
/* Land 1 fix (the functional critic's m4): neighbouring round buttons sit 8 px apart, so no tap box gives up 2 px to the
   next one; where the bar is 38 px high (short portrait, body.tight) a 36 px button sits 1 px under the screen's top and
   its box reaches 7 px under it instead of 4, so it is still 44 px tall. */
#top button.round + button.round { margin-left: var(--round-gap, 2px); } /* lane P Stage 3: wider when the side column is zoomed down */
@media (max-height: 640px) and (max-width: 700px) { #top button.round::after { bottom: -10px; } }
body.tight:not(.wide) #top button.round::after { bottom: -10px; }
button.big { min-height: 58px; font-size: 36px; width: 100%; }
.panel { background: var(--parch); color: var(--parch-ink); border: 3px solid var(--ink); border-radius: 8px;
  box-shadow: inset 0 0 0 3px var(--parch-edge), 0 5px 0 rgba(0,0,0,.45); }
.tog { font-size: 22px; }
/* lane P Stage 3: the speed button with banked 3x time reads e.g. "3× 4:12" (it widens; the level name gives way) */
#top .tog-speed.timed { width: auto; min-width: 42px; padding: 0 7px; font-size: 19px; white-space: nowrap; }
.tog[aria-pressed="true"] { background: var(--gold); box-shadow: inset 0 3px 0 var(--gold-hi), inset 0 -5px 0 var(--gold-lo), 0 3px 0 rgba(0,0,0,.5); }
.tog-cb { display: flex; align-items: center; justify-content: center; gap: 7px; }
.tog-cb svg { flex: none; }
.tog-mute .cross { display: none; }
.tog-mute[aria-pressed="true"] .cross { display: inline; }
.tog-mute[aria-pressed="true"] .waves { display: none; }
/* v5.2: music and effects switch apart. The quick mute buttons are "mixed" when only one is off (one wave shows); the
   settings rows are pressed when on, and wear a cross (effects) or a slash (music) when off. */
.tog-mute[aria-pressed="mixed"] .w2 { display: none; }
.tog-music .cross, .tog-sfx .cross { display: none; }
.tog-music[aria-pressed="false"] .cross, .tog-sfx[aria-pressed="false"] .cross { display: inline; }
.tog-sfx[aria-pressed="false"] .waves { display: none; }

/* v4.3: no difficulty picker. A level's tag (config layout.tags): Hard a strong warning red, Easy a calm teal, Normal
   unmarked. On the map's buttons, the Gallery's tiles, the top bar and the report. */
.tag { display: inline-block; font-family: var(--px); font-style: normal; font-weight: 400; line-height: 1; padding: 2px 5px 1px; border-radius: 4px; border: 2px solid var(--ink); text-transform: uppercase; letter-spacing: .5px; white-space: nowrap; }
.tag[hidden] { display: none; }
.tag-hard { background: #d42a2a; color: #fff6e8; box-shadow: inset 0 -2px 0 #8e1515; }
/* Campaign v6 fix (visual critic m5): Extreme reads harder than Hard's red at a glance: a near-black pill with a red
   inner rim, gold type and a gold skull ahead of the word, on the map, the play bar and every Play. */
.tag-extreme { background: #1d0a10; color: #ffd23f; box-shadow: inset 0 0 0 1.5px #e0322b, inset 0 -3px 0 #5e0a0d; } /* v5 R1 */
.tag-extreme::before { content: ""; display: inline-block; width: .9em; height: .9em; margin: 0 .22em -.06em -.05em; vertical-align: baseline; background: center / contain no-repeat url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M6 .8C3.1.8 1.2 2.8 1.2 5.3c0 1.6.8 2.8 2.1 3.4v2.5h5.4V8.7c1.3-.6 2.1-1.8 2.1-3.4C10.8 2.8 8.9.8 6 .8z' fill='%23ffd23f'/%3E%3Ccircle cx='4.1' cy='5.6' r='1.3' fill='%231d0a10'/%3E%3Ccircle cx='7.9' cy='5.6' r='1.3' fill='%231d0a10'/%3E%3Cpath d='M5.1 11.2V9.4M6.9 11.2V9.4' stroke='%231d0a10' stroke-width='.9'/%3E%3C/svg%3E"); }
.tag-easy { background: #1f7a6f; color: #effff9; box-shadow: inset 0 -2px 0 #14544c; } /* v4.3 fix (m6): 5:1 */
/* v4.3 fix (T1): every Play wears the next level's tag on its corner; a Hard level's Play gets a red face inside its gold
   rim (Food Hunt marks a hard level's button the same way). */
#btn-play, #map-play, #p-primary { position: relative; }
#btn-play .tag, #map-play .tag, #p-primary .tag { position: absolute; z-index: 1; top: -11px; right: -8px; font-size: 16px; padding: 2px 5px 1px; }
button.primary.hard { background: #e8553a; color: #fff6e8; text-shadow: 0 2px 0 rgba(34,26,38,.45); box-shadow: inset 0 0 0 3px var(--gold), inset 0 6px 0 #ff9a80, inset 0 -7px 0 #a8341f, 0 3px 0 rgba(0,0,0,.5); }
button.primary.hard.extreme { background: #9e1418; box-shadow: inset 0 0 0 3px var(--gold), inset 0 6px 0 #d8473a, inset 0 -7px 0 #4e070b, 0 3px 0 rgba(0,0,0,.5); } /* v5 R1; v6 fix: blood red, darker than Hard's */
button.primary.hard:active:not(:disabled) { box-shadow: inset 0 0 0 3px var(--gold), inset 0 6px 0 #ff9a80, inset 0 -4px 0 #a8341f, 0 1px 0 rgba(0,0,0,.5); }

/* Top bar: map, level number and era, the level's tag, retry, 2x, mute. */
#top { flex: none; display: flex; align-items: center; gap: 6px; height: 50px; padding: 0 1px; }
#lvl { flex: 1; min-width: 0; display: flex; align-items: center; gap: 7px; white-space: nowrap; overflow: hidden; }
/* The level's name over its tag (v4.3), beside the number; main.js steps the name's size down until it fits (no ellipsis). */
.lvl-txt { flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: flex-start; gap: 3px; }
#lvl-num { flex: none; font-family: var(--px); font-size: 22px; line-height: 1; padding: 5px 7px 4px; border-radius: 5px; border: 2px solid var(--ink);
  background: var(--gold); color: var(--ink); box-shadow: inset 0 -3px 0 var(--gold-lo); font-variant-numeric: tabular-nums; }
#lvl-name { display: block; max-width: 100%; font-family: var(--px); font-size: 20px; line-height: .9; overflow: hidden; text-shadow: 0 2px 0 var(--ink); }
#tag-chip { flex: none; font-size: 14px; padding: 1px 5px 0; border-width: 1.5px; }

/* Play: the board takes the height; the holding line and the tray sit under it (portrait) or beside it (wide). */
#play { flex: 1; min-height: 0; display: flex; flex-direction: column; }
/* #side holds the top bar and the rail: on a phone it dissolves (the top bar goes first, the rail under the board); on a
   wide screen it is the side column (below). */
#side { display: contents; }
#top { order: -1; }
#stage { flex: 1 1 auto; min-height: 0; position: relative; display: flex; align-items: center; justify-content: center; }
#frame { position: relative; border-radius: 8px; padding: 5px; background: var(--wood); line-height: 0;
  box-shadow: inset 0 -3px 0 var(--wood-mid), 0 0 0 2px var(--wood-lo), 0 5px 0 2px rgba(0,0,0,.45); }
#board { display: block; border-radius: 3px; touch-action: none; cursor: pointer; image-rendering: pixelated; }
/* Teaching coach (Critics 1 fix): a box of --coach-h that never covers the board. A level with a coach reserves the band
   above the frame (body.coach-above), or, where that would cost the board its 8 px cells, the coach sits over the level's
   name in the top bar (body.coach-top); on wide screens it has its own spot in the side column (#coach-dock). main.js
   places it (fixed, from the band's rect) and fits its text on one line, else two. A bouncing arrow points at the thing
   to tap: from above for a space or the line, from the side for a queue tile (placed by main.js). */
body.coach-above #stage { padding-top: calc(var(--coach-h) + 6px); }
#coach { position: fixed; left: 0; top: 0; z-index: 7; margin: 0; height: var(--coach-h); padding: 2px 8px; pointer-events: none; text-align: center;
  display: flex; align-items: center; justify-content: center; font-family: var(--px); font-size: var(--coach-fs); line-height: 1; white-space: nowrap; overflow: hidden; animation: coachin .25s ease-out; }
#coach.two { white-space: normal; }
body.coach-top #coach { border-width: 2px; padding: 0 6px; white-space: nowrap; }
body.coach-top #coach.two { white-space: normal; line-height: .95; } /* Critics 2 fix (V1): two lines in the top bar */
#coach[hidden] { display: none; }
#coach-dock { display: none; flex: none; height: var(--coach-h); }
body.wide.coached #coach-dock { display: block; }
@keyframes coachin { 0% { transform: translateY(-6px); opacity: 0; } 100% { transform: none; opacity: 1; } }
#hand { position: fixed; left: -17px; top: -38px; z-index: 8; pointer-events: none; line-height: 0; transform-origin: 17px 36px; }
#hand[hidden] { display: none; }
#hand svg { display: block; animation: handbob .7s ease-in-out infinite; filter: drop-shadow(0 2px 0 rgba(0,0,0,.45)); }
@keyframes handbob { 50% { transform: translateY(calc(-1 * var(--bob))); } }
#hand { --bob: 8px; } #hand.side { --bob: 4px; }
.coach-on { animation: coachglow .9s ease-in-out infinite; position: relative; z-index: 1; }
.tile.coach-on { z-index: auto; }
@keyframes coachglow { 50% { box-shadow: 0 0 0 3px var(--glow), 0 0 14px 4px rgba(255,243,168,.75); } }
/* Paused: covers the whole game and takes the tap that resumes. */
#pause { position: fixed; inset: 0; z-index: 30; width: 100%; height: 100%; min-height: 0; border: 0; border-radius: 0; padding: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 6px; background: rgba(20,16,28,.72); color: var(--cream); box-shadow: none; font-family: var(--px); cursor: pointer; } /* v4 M5: a container now (its toggles are buttons) */
#pause[hidden] { display: none; }
#pause:active:not(:disabled) { transform: none; box-shadow: none; }
#pause .pz-t { font-size: 56px; line-height: 1; color: var(--gold); text-shadow: 0 4px 0 var(--ink); }
#pause .pz-s { font-size: 26px; line-height: 1; }
/* v4.2 fix: the upright card (layout.upright). Over everything, the wall behind it; a phone and a turning arrow, one line. */
#upright { position: fixed; inset: 0; z-index: 40; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 14px; padding: 16px;
  background: var(--bg) var(--wall, none) repeat; background-size: var(--wall-size, auto); color: var(--cream); font-family: var(--px); text-align: center; }
#upright[hidden] { display: none; }
#upright .up-ico { display: block; filter: drop-shadow(0 4px 0 var(--ink)); }
#upright .up-t { font-size: 30px; line-height: 1; color: var(--gold); text-shadow: 0 3px 0 var(--ink); }
#toast { position: absolute; left: 50%; bottom: 10px; z-index: 3; transform: translateX(-50%); max-width: 92%; text-align: center; line-height: 1.05; pointer-events: none;
  font-family: var(--px); font-size: 20px; padding: 5px 12px 6px; background: var(--parch); color: var(--parch-ink); border: 3px solid var(--ink); border-radius: 8px; box-shadow: 0 4px 0 rgba(0,0,0,.45); }
#toast[hidden] { display: none; }
/* v4.3 fix (m2): on a wide screen a toast in play sits just above the side column's tray (main.js placeToast). */
#toast.side { position: fixed; bottom: auto; z-index: 6; transform: translate(-50%, -100%); }
#toast.bad { background: #ffd9cf; }
/* v7 fix pass: a button whose Zen world is still loading (main.js pendStep, after zen.load.toastMs): it breathes, and
   repeat taps are ignored in main.js */
.busy { animation: busybreathe .9s ease-in-out infinite alternate; cursor: progress; }
@keyframes busybreathe { 100% { filter: brightness(.82) saturate(.8); } }
@media (prefers-reduced-motion: reduce) { .busy { animation: none; filter: brightness(.85) saturate(.8); } }

/* The rail (Critics 1 fix): the holding line and the queue on one light stone tray, so the colours read in a light
   value key (Food Hunt's lesson) while the board keeps the siege field. The brick stays as the margin around it. */
#rail { flex: none; display: flex; flex-direction: column; gap: var(--tray-pad); margin: 6px 0 5px; padding: var(--tray-pad);
  border: 3px solid var(--ink); border-radius: 12px; background: var(--tray); box-shadow: inset 0 3px 0 var(--tray-hi), inset 0 -4px 0 var(--tray-edge), 0 4px 0 rgba(0,0,0,.45); }
/* v4 M5, the power-up bar (main.js buildPowers): a band under the queue with the coins and four round badges, each a
   light disc with its pixel icon, a bubble (the count owned, or a green "+") and, to buy, the price on a pill. Bigger
   than the tiles and the only round shapes in a level. A badge waiting for its target glows; the tiles or spaces it can
   take wear .pickable. */
#powers { flex: none; display: grid; grid-template-columns: auto repeat(var(--pw-n, 5), minmax(0, 1fr)); align-items: center; align-content: center; justify-items: center; column-gap: 4px; height: var(--pw-h);
  margin: 0 0 max(8px, env(safe-area-inset-bottom)); padding: 0 6px; border: 3px solid var(--ink); border-radius: 12px; background: var(--pw-band); box-shadow: inset 0 3px 0 rgba(255,255,255,.12), 0 4px 0 rgba(0,0,0,.45); }
.pill { display: inline-flex; align-items: center; gap: 5px; height: var(--pill-h); padding: 0 11px 0 5px; border-radius: calc(var(--pill-h) / 2); border: 3px solid var(--ink); background: var(--parch); color: var(--parch-ink);
  font-family: var(--px); font-size: var(--pill-fs); line-height: 1; font-variant-numeric: tabular-nums; white-space: nowrap; box-shadow: inset 0 -3px 0 var(--parch-edge), 0 3px 0 rgba(0,0,0,.4); }
.pill[hidden] { display: none; }
.pill b { font-weight: 400; }
.ico { flex: none; display: inline-block; width: var(--ico); height: var(--ico); background: var(--ic-coin) center / contain no-repeat; image-rendering: pixelated; }
.ico-heart { background-image: var(--ic-heart); } .ico-castle { background-image: var(--ic-castle); }
#pw-coins { --pill-h: 32px; --pill-fs: 21px; --ico: 20px; padding-right: 8px; }
.pw { position: relative; width: min(var(--pw-d), 100%); height: auto; aspect-ratio: 1; min-height: 0; padding: 0; border-radius: 50%; border: 3px solid var(--ink); background: var(--pw-disc);
  box-shadow: inset 0 -5px 0 var(--pw-disc-lo), inset 0 3px 0 #fffaf0, 0 3px 0 rgba(0,0,0,.5); }
.pw:active:not(:disabled) { transform: translateY(2px); box-shadow: inset 0 -3px 0 var(--pw-disc-lo), inset 0 3px 0 #fffaf0, 0 1px 0 rgba(0,0,0,.5); }
.pw .pw-ic { position: absolute; left: 50%; top: 47%; width: var(--pw-ic); height: var(--pw-ic); transform: translate(-50%, -50%); background: center / contain no-repeat; image-rendering: pixelated; }
.pw .pw-n { position: absolute; right: -6px; top: -6px; min-width: var(--pw-b); height: var(--pw-b); padding: 0 5px; border-radius: calc(var(--pw-b) / 2); border: 2px solid var(--ink); background: var(--ink); color: #fff;
  display: flex; align-items: center; justify-content: center; font-family: var(--px); font-weight: 400; font-size: var(--pw-bfs); line-height: 1; }
.pw.buy .pw-n { background: var(--pw-plus); color: #fff; box-shadow: inset 0 -3px 0 var(--pw-plus-lo); text-shadow: 0 1px 0 var(--pw-plus-lo); }
.pw.spent .pw-n { background: #6b6474; font-size: 0; } .pw.spent .pw-n::after { content: ""; width: 10px; height: 6px; margin-top: -3px; border: solid #fff; border-width: 0 0 3px 3px; transform: rotate(-45deg); }
.pw.spent .pw-ic { opacity: .55; }
.pw .pw-tag { display: none; position: absolute; left: 50%; bottom: -5px; transform: translateX(-50%); align-items: center; gap: 2px; height: 18px; padding: 0 5px 0 2px; border-radius: 9px; border: 2px solid var(--ink); background: var(--parch);
  color: var(--parch-ink); font-family: var(--px); font-size: 16px; line-height: 1; --ico: 13px; white-space: nowrap; }
.pw.buy .pw-tag { display: inline-flex; }
.pw.poor .pw-n { background: var(--pw-poor); box-shadow: inset 0 -3px 0 var(--pw-poor-lo); text-shadow: none; color: #e9e4ee; } /* m2: short of coins */
.pw.poor .pw-tag { background: var(--pw-poor-tag); color: var(--pw-poor-ink); border-color: var(--pw-poor-ink); }
.pw .pw-need { display: none; }
.pw .pw-name { display: none; }
.pw.picking { box-shadow: 0 0 0 4px var(--glow), 0 0 16px 4px rgba(255,243,168,.8), inset 0 -5px 0 var(--pw-disc-lo); animation: coachglow .9s ease-in-out infinite; }
.pw.pop .pw-ic { animation: pwpop .42s cubic-bezier(.3,1.6,.5,1); }
@keyframes pwpop { 0% { transform: translate(-50%, -50%) scale(1.35); } 100% { transform: translate(-50%, -50%) scale(1); } }
.tile.next.pickable, .tile.card.pickable, .slot.pickable { cursor: pointer; outline: 3px dashed var(--gold-lo); outline-offset: 2px; animation: pickglow .8s ease-in-out infinite; }
@keyframes pickglow { 50% { outline-color: var(--gold-hi); box-shadow: 0 0 0 3px var(--glow), 0 0 12px 3px rgba(255,243,168,.75); } }
/* Short frames: the queue's third row goes (main.js marks it .off) so the bar fits under the queue; its tray band too. */
.next.off { display: none; }
body.rows2 #tray { --y2: 9999px; }
body.rows2:not(.wide) { --pw-h: 54px; --pw-d: 48px; --pw-b: 20px; --pw-bfs: 17px; }
body.rows2:not(.wide) #rail { margin-bottom: 3px; } body.rows2:not(.wide) #pw-coins { --pill-h: 30px; --pill-fs: 19px; --ico: 18px; }
#line-wrap { display: flex; flex-direction: column; gap: 3px; }
#line-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; padding: 0 2px; font-family: var(--px); font-size: 17px; line-height: 1; color: var(--tray-soft); white-space: nowrap; }
#line-cnt { margin-right: var(--cnt-shift, 0px); font-variant-numeric: tabular-nums; }
/* v4.3 fix (m1): the sappers carrying blocks home after their space freed: a return arrow and their number. */
#line-cnt .ret { display: inline-flex; align-items: center; gap: 2px; opacity: .85; }
#line-cnt .ret[hidden] { display: none; }
#line-cnt .lc:not(:empty) + .ret::before { content: "\00b7"; margin: 0 5px 0 4px; }
#line-cnt .ret i { display: inline-block; width: .8em; height: .8em; background: currentColor; -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M4.5 1.5L1.5 4.5l3 3' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3Cpath d='M2 4.5h5a3 3 0 0 1 0 6H4.5' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round'/%3E%3C/svg%3E") center / contain no-repeat; mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M4.5 1.5L1.5 4.5l3 3' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3Cpath d='M2 4.5h5a3 3 0 0 1 0 6H4.5' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round'/%3E%3C/svg%3E") center / contain no-repeat; }
#line { flex: 1; display: grid; grid-template-columns: repeat(var(--cap, 5), 1fr); gap: 4px; border-radius: 8px; }
/* The line's state (v3.1). Full with squads still working: an amber rim, the head says wait, front cards wear a lock
   (a tap is refused, never fatal). Danger (full, or one space left, with at most one squad working): the red pulse.
   Victory march: a gold head. */
#line-wrap.full #line-head { color: var(--tray-full); }
#line-wrap.full #line { box-shadow: 0 0 0 2px rgba(255,190,80,.75); }
#line-wrap.full.danger #line-head, #line-wrap.near #line-head { color: var(--tray-bad); }
#line-wrap.full.danger #line { box-shadow: 0 0 0 2px rgba(255,90,60,.7); animation: fullpulse 1s ease-in-out infinite; }
#line-wrap.march #line-head { color: var(--tray-march); }
@keyframes fullpulse { 50% { box-shadow: 0 0 0 3px rgba(255,90,60,1), 0 0 14px 3px rgba(255,90,60,.55); } }
/* A blocked card is dimmed by a veil under its count (never a filter: the counts sit above the rods). */
.card.blocked::before, .card.waitpair::before { content: ""; position: absolute; inset: 0; border-radius: 6px; background: rgba(34,26,38,.34); pointer-events: none; }
/* v4.3: a linked front card whose partner is still buried waits for it: the veil, a dashed gold edge and a chain badge. */
.card.waitpair::before { outline: 2px dashed rgba(255,226,122,.95); outline-offset: -5px; }
.card.blocked, .card.safe, .card.waitpair { overflow: visible; }
.card.waitpair::after { content: ""; position: absolute; right: -5px; top: -6px; width: 18px; height: 18px; border-radius: 50%; border: 2px solid var(--ink); background: #8a6d4c center / 12px 12px no-repeat url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M5 7l2-2M4.4 8.6a1.7 1.7 0 0 1-2.4-2.4l1.4-1.4a1.7 1.7 0 0 1 2.4 0M7.6 3.4a1.7 1.7 0 0 1 2.4 2.4L8.6 7.2a1.7 1.7 0 0 1-2.4 0' fill='none' stroke='%23fff' stroke-width='1.5' stroke-linecap='round'/%3E%3C/svg%3E"); }
.card.blocked::after, .card.safe::after { content: ""; position: absolute; right: -5px; top: -6px; width: 18px; height: 18px; border-radius: 50%; border: 2px solid var(--ink); background-position: center; background-size: 12px 12px; background-repeat: no-repeat; }
.card.blocked::after { background-color: #5d5566; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M4 5.5V4a2 2 0 0 1 4 0v1.5' fill='none' stroke='%23fff' stroke-width='1.6'/%3E%3Crect x='2.5' y='5.5' width='7' height='5' rx='1' fill='%23fff'/%3E%3C/svg%3E"); }
.card.safe::after { background-color: #3fbf5a; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2.5 6.5l2.3 2.3L9.5 3.5' fill='none' stroke='%23fff' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E"); }
/* v4 M1: the holding spaces are bigger and bolder, with a big count: an empty one is a recessed socket in the tray, a
   taken one a solid tile in its squad's colour. Stuck and working keep their v3.1 marks. Sizes come from --slot-h and
   --slot-n. Critics 1 fix: a space is a grid, its count in the right column and its badges in the left one (the stuck
   lock or the working marker on top, the chain or the walking figures below), so no badge ever covers the count. Where
   a space is too narrow for both side by side (#line.tight: six spaces on a phone, a short landscape screen; main.js
   decides at layout), the badges take the top row and the count the bottom right. */
.slot { position: relative; height: var(--slot-h); border-radius: 9px; border: 3px solid var(--socket-lo); background: var(--socket); box-shadow: inset 0 3px 0 rgba(58,48,39,.22); overflow: hidden;
  display: grid; grid-template-columns: minmax(0, 1fr) auto; grid-template-rows: minmax(0, 1fr) minmax(0, 1fr); column-gap: 2px; align-items: center; padding: 2px 4px 2px 3px; }
.slot.full { border: 3px solid var(--ink); background: var(--mc, #666); color: var(--tc, #fff); box-shadow: inset 0 3px 0 rgba(255,255,255,.34), inset 0 -5px 0 rgba(0,0,0,.26); }
.slot .men { grid-column: 1; grid-row: 2; align-self: end; justify-self: start; position: relative; max-width: 100%; height: var(--man); background-repeat: space no-repeat; background-position: left center; background-size: var(--man) var(--man); image-rendering: pixelated; }
.slot b { grid-column: 2; grid-row: 1 / 3; justify-self: end; position: relative; z-index: 1; font-family: var(--px); font-weight: 400; font-size: var(--slot-n); line-height: .8; font-variant-numeric: tabular-nums; }
.slot.full b { text-shadow: 2px 0 0 var(--oc, transparent), -2px 0 0 var(--oc, transparent), 0 2px 0 var(--oc, transparent), 0 -2px 0 var(--oc, transparent); }
/* Playtest 1: a squad with sappers out wears a gold rim and a walking marker with the number out. */
.slot .out { grid-column: 1; grid-row: 1; align-self: start; justify-self: start; position: relative; z-index: 1; display: flex; align-items: center; gap: 1px; font-family: var(--px); font-style: normal; font-size: var(--out-n); line-height: 1; padding: 1px 2px 0; border-radius: 4px; background: #221a26; color: #ffe27a; }
.slot .out::before { content: ""; width: 0; height: 0; border-left: 2.5px solid transparent; border-right: 2.5px solid transparent; border-bottom: 5px solid currentColor; }
.slot .out:empty { display: none; }
.slot.work { box-shadow: inset 0 3px 0 rgba(255,255,255,.34), inset 0 -5px 0 rgba(0,0,0,.26), 0 0 0 3px rgba(255,226,122,.75); }
.slot.work .men { animation: menstep .36s steps(1) infinite; }
/* Campaign v6 fix (visual critic S2): a squad with a sapper pinned by an archer is hatched red the other way from stuck,
   rimmed red, and its badge turns into a red arrow badge with the number pinned (main.js renderLine; the head counts it
   "1 pinned"). It all clears the moment the tower falls and the sapper gets up. */
.slot.pinned { border-color: var(--pin-rim); }
.slot.pinned::before { content: ""; position: absolute; inset: 0; border-radius: 6px; background: repeating-linear-gradient(45deg, var(--pin-hatch) 0 5px, transparent 5px 10px); }
.slot.pinned .out { background: var(--pin-badge); color: #fff6e8; box-shadow: 0 0 0 1.5px #221a26; padding: 1px 3px 0 2px; gap: 2px; }
.slot.pinned .out::before { width: .95em; height: .95em; border: 0; background: center / contain no-repeat url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M3.6 8.4L10.2 1.8' stroke='%23fff6e8' stroke-width='1.6' stroke-linecap='round'/%3E%3Cpath d='M1.2 10.8l1.1-4.6 3.5 3.5z' fill='%23fff6e8'/%3E%3Cpath d='M8 1.2v2.8h2.8' fill='none' stroke='%23fff6e8' stroke-width='1.3'/%3E%3C/svg%3E"); }
@keyframes menstep { 50% { transform: translateY(-2px); } }
/* v3.1: a stuck squad (nothing it can reach, every sapper home) is hatched dark with a lock; its count stays readable.
   Its figures go (they add nothing the hatch and the lock don't say); a linked space shows its chain there instead. */
.slot.stuck::before { content: ""; position: absolute; inset: 0; border-radius: 6px; background: repeating-linear-gradient(135deg, rgba(20,16,28,.55) 0 5px, rgba(20,16,28,.12) 5px 10px); }
.slot.stuck::after { content: ""; grid-column: 1; grid-row: 1; align-self: start; justify-self: start; position: relative; z-index: 1; width: var(--bd); height: var(--bd); border-radius: 4px; background: #221a26 center / 74% no-repeat; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M4 5.5V4a2 2 0 0 1 4 0v1.5' fill='none' stroke='%23fff' stroke-width='1.6'/%3E%3Crect x='2.5' y='5.5' width='7' height='5' rx='1' fill='%23fff'/%3E%3C/svg%3E"); }
.slot.stuck b { text-shadow: 2px 0 0 #221a26, -2px 0 0 #221a26, 0 2px 0 #221a26, 0 -2px 0 #221a26; color: #fff; }
.slot.stuck .men, .slot.linked .men, #line.tight .slot .men { display: none; }
#line.tight .slot { grid-template-rows: auto minmax(0, 1fr); row-gap: 1px; }
#line.tight .slot b { grid-row: 2; align-self: end; font-size: calc(var(--slot-n) * var(--tight-n, .78)); }
#line.tight .slot .out, #line.tight .slot.stuck::after { grid-column: 1 / 3; }
.slot.last { border-color: rgba(214,70,48,.95); animation: lastpulse .8s ease-in-out infinite; }
@keyframes lastpulse { 50% { background: rgba(255,90,60,.4); box-shadow: 0 0 0 2px rgba(255,90,60,.55); } }
/* v4 M2: the locked space is a dark hatch with a padlock and a dashed cream rim (the same dash its key block wears on
   the board); it pops open when its key block goes. Linked squads' spaces wear a chain (bottom left); a finished one
   holding its space for its partner is dimmed. */
.slot .pad { display: none; position: absolute; left: 50%; top: 50%; width: calc(var(--slot-h) * .62); height: calc(var(--slot-h) * .62); transform: translate(-50%, -50%);
  background: center / contain no-repeat url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M7 11V8a5 5 0 0 1 10 0v3' fill='none' stroke='%23221a26' stroke-width='5'/%3E%3Cpath d='M7 11V8a5 5 0 0 1 10 0v3' fill='none' stroke='%23f3ead8' stroke-width='2.4'/%3E%3Crect x='3.5' y='10' width='17' height='12' rx='2.5' fill='%23221a26'/%3E%3Crect x='5.5' y='12' width='13' height='8' rx='1.5' fill='%23f3ead8'/%3E%3Ccircle cx='12' cy='15.4' r='1.7' fill='%23221a26'/%3E%3Crect x='11.2' y='15.6' width='1.6' height='3' fill='%23221a26'/%3E%3C/svg%3E"); }
.slot.locked { border-style: dashed; border-color: var(--cream); background: var(--lock-socket); box-shadow: inset 0 3px 0 rgba(0,0,0,.35); }
.slot.locked .pad, .slot.unlocking .pad { display: block; }
/* v5 R1: a colour lock's socket shows the colour that opens it (a band of it under the dark hatch, the padlock over it). */
.slot.locked.clock { background: repeating-linear-gradient(135deg, rgba(20,16,28,.55) 0 5px, rgba(20,16,28,.15) 5px 10px), var(--lc); border-color: var(--cream); }
.slot.unlocking .pad { animation: padpop .7s ease-out both; }
/* Campaign v6 fix (visual critic m2): a key lock's socket shows what opens it, as a colour lock's shows its colour: the
   padlock moves left and the board's own key block sits beside it (gilt, the key etched in, the dashed cream square the key
   wears on the board), so each socket pairs with its key or its colour at a glance, with one lock or two. */
.slot.locked.klock .pad { left: 33%; }
.slot.locked.klock::after { content: ""; position: absolute; left: 70%; top: 50%; width: calc(var(--slot-h) * .44); height: calc(var(--slot-h) * .44); transform: translate(-50%, -50%); border-radius: 3px;
  background: var(--key-gilt) center / 80% no-repeat url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Ccircle cx='3.6' cy='6' r='2.1' fill='none' stroke='%23221a26' stroke-width='1.5'/%3E%3Cpath d='M5.7 6h5.3M8.4 6v2.2M10.3 6v2.8' fill='none' stroke='%23221a26' stroke-width='1.5'/%3E%3C/svg%3E"); outline: 2px dashed var(--cream); outline-offset: 1px; box-shadow: inset 0 -2px 0 rgba(0,0,0,.3); }
@keyframes padpop { 0% { transform: translate(-50%, -50%); opacity: 1; } 30% { transform: translate(-50%, -62%) scale(1.25) rotate(-10deg); opacity: 1; } 100% { transform: translate(-50%, -150%) scale(.7) rotate(28deg); opacity: 0; } }
.slot .lk, .tile .ch { display: none; position: relative; z-index: 1; border-radius: 4px; background: #221a26 center / 82% no-repeat;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14'%3E%3Crect x='1' y='4' width='7' height='5' rx='2.5' fill='none' stroke='%23efe2c8' stroke-width='1.6'/%3E%3Crect x='6' y='5' width='7' height='5' rx='2.5' fill='none' stroke='%23b9a48a' stroke-width='1.6'/%3E%3C/svg%3E"); }
.slot .lk { grid-column: 1; grid-row: 2; align-self: end; justify-self: start; width: var(--lk-s); height: var(--lk-s); }
.slot.linked .lk { display: block; }
.slot.held { filter: saturate(.6) brightness(.82); }
.dbg-node { font-size: 16px; line-height: 1; padding: 4px; }

/* v4 M1, the queue: colour first. Five columns of layout.queueRows tiles, each a solid tile in its colour with a big
   count (the material's glyph only in colour-blind mode, body.cb). The front tile is the raised button you tap; the ones
   behind sit back (flat, no lift). Critics 1 fix: they fade toward the tray colour (main.js mixes --fc from
   layout.fade, so every faded tile keeps its hue and stays ΔE00 20+ from every other colour) and step down in size
   (--s1, --s2: width, height and count, never a transform, so the counts stay above the rods), flat, with a rim of their
   own colour toward ink (--rim1, --rim2) instead of the front's black edge. Sizes come from --tile-h,
   --tile-n, --tile-gap. */
#tray { position: relative; display: grid; grid-template-columns: repeat(5, 1fr); gap: var(--tile-gap); }
/* Critics 1 fix 2: the rows behind sit on tray bands a step darker each (--band1, --band2: 6% and 12%), a shelf that
   reads as stepping back without touching the tile faces. The tray reaches out to the panel's edges and foot for them. */
#tray { margin: 0 calc(-1 * var(--tray-pad)) calc(-1 * var(--tray-pad)); padding: 0 var(--tray-pad) var(--tray-pad); border-radius: 0 0 9px 9px;
  --y1: calc(var(--tile-h) + var(--tile-gap) / 2); --y2: calc(var(--y1) + var(--tile-h) * var(--s1) + var(--tile-gap));
  background: linear-gradient(to bottom, transparent var(--y1), var(--tray-hi) var(--y1), var(--tray-hi) calc(var(--y1) + 1px), var(--band1) calc(var(--y1) + 1px), var(--band1) var(--y2),
    var(--tray-hi) var(--y2), var(--tray-hi) calc(var(--y2) + 1px), var(--band2) calc(var(--y2) + 1px)); }
.col { display: flex; flex-direction: column; align-items: center; gap: var(--tile-gap); min-width: 0; }
.tile { position: relative; width: 100%; height: var(--tile-h); min-height: 0; padding: 0; border-radius: 9px; border: 3px solid var(--ink); display: flex; align-items: center; justify-content: center;
  background: var(--mc, var(--stone)); color: var(--tc, var(--ink)); font-family: var(--px); font-size: var(--tile-n); }
.tile .n { position: relative; z-index: 3; font-weight: 400; font-size: 1em; line-height: .8; font-variant-numeric: tabular-nums; padding-top: 1px;
  text-shadow: 2px 0 0 var(--oc, transparent), -2px 0 0 var(--oc, transparent), 0 2px 0 var(--oc, transparent), 0 -2px 0 var(--oc, transparent); }
.tile .gl { display: none; position: absolute; z-index: 3; left: 3px; top: 3px; width: var(--gl-s); height: var(--gl-s); background: currentColor; opacity: .85;
  -webkit-mask: var(--gl, none) center / contain no-repeat; mask: var(--gl, none) center / contain no-repeat; }
body.cb .tile .gl { display: block; }
.card { box-shadow: inset 0 3px 0 rgba(255,255,255,.38), inset 0 -6px 0 rgba(0,0,0,.26), 0 4px 0 rgba(0,0,0,.45); }
.card:active:not(:disabled) { transform: translateY(2px); box-shadow: inset 0 3px 0 rgba(255,255,255,.38), inset 0 -3px 0 rgba(0,0,0,.26), 0 1px 0 rgba(0,0,0,.45); }
.card.empty { background: var(--socket); color: var(--tray-soft); box-shadow: inset 0 3px 0 rgba(58,48,39,.22); border-style: dashed; border-color: var(--socket-lo); }
.next { background: var(--fc, var(--mc, var(--stone))); border-color: color-mix(in srgb, var(--fc, var(--stone)) var(--rim1), var(--ink)); box-shadow: inset 0 2px 0 rgba(255,255,255,.2); }
.next.d2 { border-color: color-mix(in srgb, var(--fc, var(--stone)) var(--rim2), var(--ink)); box-shadow: none; }
.next.d1 { width: calc(100% * var(--s1)); height: calc(var(--tile-h) * var(--s1)); font-size: calc(var(--tile-n) * var(--s1)); }
.next.d2 { width: calc(100% * var(--s2)); height: calc(var(--tile-h) * var(--s2)); font-size: calc(var(--tile-n) * var(--s2)); }
.next.none { visibility: hidden; }
/* v4 M2: a hidden mystery card; main.js never gives it the card's colour, crew or glyph. Critics 1 fix: it reads as a
   card lying face down (a dark back with a gold lattice and rim, a big gold "?" before its count), not as a disabled
   tile. The rods joining linked tiles are an SVG over the tray (main.js draws them) under the counts; each linked tile
   also wears a small chain tag on a bottom corner. */
.tile .q { display: none; position: relative; z-index: 3; order: -1; margin-right: .04em; font-family: var(--px); font-style: normal; font-size: .72em; line-height: .8;
  color: var(--gold-hi); text-shadow: 0 2px 0 var(--ink), 2px 0 0 var(--ink), -1px 0 0 var(--ink); }
.tile.mys { background: radial-gradient(circle, var(--mys-dot) 1.3px, transparent 1.9px) 0 0 / 8px 8px, radial-gradient(circle, var(--mys-dot) 1.3px, transparent 1.9px) 4px 4px / 8px 8px, var(--fc, var(--mc));
  box-shadow: inset 0 0 0 2px var(--mys-rim), inset 0 -3px 0 rgba(0,0,0,.2); }
.tile.mys .q { display: block; }
body.cb .tile.mys .gl { display: none; }
.tile .ch { position: absolute; z-index: 3; left: calc(var(--ch-s) * -.45); bottom: calc(var(--ch-s) * -.45); width: var(--ch-s); height: var(--ch-s); box-shadow: 0 0 0 1px var(--tray); }
.tile.ch-r .ch { left: auto; right: calc(var(--ch-s) * -.45); } /* on the bottom corner away from its rod (main.js), clear of the count */
.next .ch { left: calc(var(--ch-s) * -.7); } .next.ch-r .ch { left: auto; right: calc(var(--ch-s) * -.7); } /* the narrower rows have more gap */
.tile.linked .ch { display: block; }
.rods { position: absolute; left: 0; top: 0; width: 100%; height: 100%; overflow: visible; pointer-events: none; z-index: 2; fill: none; }

/* Win / fail panel: a parchment sheet over the rail in portrait, so its buttons stay under the thumb. Critics 1 fix:
   main.js places it (placeSheet) so it never slices the holding line: a fail sheet starts under the line (the jammed
   line stays in view; .float: above the line, over the board's foot, where the room under it is too small), a win sheet
   covers the whole rail. On wide screens it covers the side column the same way. .tight steps the text down to fit. */
.sheet { position: absolute; left: 0; right: 0; bottom: 0; z-index: 5; display: flex; flex-direction: column; justify-content: flex-end; align-items: center; pointer-events: none; }
.sheet[hidden] { display: none; }
.sheet .sheetcard { pointer-events: auto; width: 100%; max-width: 560px; min-height: 100%; display: flex; flex-direction: column; justify-content: center; border-bottom: 0; border-radius: 12px 12px 0 0; background: var(--parch); color: var(--parch-ink);
  padding: 12px 16px max(14px, env(safe-area-inset-bottom)); text-align: center; animation: sheetin .22s cubic-bezier(.3,1.4,.5,1); }
.sheet.float .sheetcard { min-height: 0; border-bottom: 3px solid var(--ink); border-radius: 12px; padding-bottom: 12px; }
.sheet.fit .sheetcard { min-height: 0; max-height: 100%; overflow-y: auto; overscroll-behavior: contain; justify-content: flex-start; border-bottom: 3px solid var(--ink); border-radius: 12px; } /* lane P Stage 3: the whole room, scrolling inside */
#panel.sheet.fit .sheetcard { padding-top: 6px; padding-bottom: 8px; } #panel.sheet.fit .p-title { font-size: 27px; } #panel.sheet.fit #p-tag { font-size: 14px; margin: -2px auto 3px; } #panel.sheet.fit .p-line { font-size: 16px; margin-bottom: 5px; }
#panel.sheet.fit #p-cont { margin: -2px 0 4px; } #panel.sheet.fit .cont-buy { min-height: 36px; font-size: 20px; } #panel.sheet.fit .cont-say { font-size: 14px; } #panel.sheet.fit .row button { min-height: 42px; font-size: 22px; } /* the tightest words, so Retry shows */
.sheet.tight .p-title { font-size: 32px; } .sheet.tight .p-line { font-size: 19px; margin-bottom: 7px; } .sheet.tight #p-tag { font-size: 16px; margin: -2px auto 5px; } .sheet.tight #p-ribbon { font-size: 17px; margin-bottom: 5px; }
.sheet.tight .sheetcard { padding-top: 7px; padding-bottom: max(9px, env(safe-area-inset-bottom)); } .sheet.tight .row button { min-height: 44px; font-size: 24px; }
/* The jam sheet shows the jammed squads as the player sees them: a chip in the squad's colour with its count (the crew
   names stay in the sheet's aria-label). */
.chip { display: inline-flex; align-items: center; justify-content: center; min-width: 1.5em; height: 1.2em; margin: 0 .08em; padding: .1em .22em 0; vertical-align: -.2em; border-radius: 5px; border: 2px solid var(--ink);
  background: var(--mc); color: var(--tc); font-variant-numeric: tabular-nums; line-height: 1; text-shadow: 1px 0 0 var(--oc), -1px 0 0 var(--oc), 0 1px 0 var(--oc), 0 -1px 0 var(--oc); position: relative; }
.chip .gl { display: none; width: .7em; height: .7em; margin-right: .12em; background: currentColor; -webkit-mask: var(--gl, none) center / contain no-repeat; mask: var(--gl, none) center / contain no-repeat; }
body.cb .chip .gl { display: inline-block; }
@keyframes sheetin { 0% { transform: translateY(12px); opacity: .4; } 100% { transform: none; opacity: 1; } }
.p-title { font-family: var(--px); font-size: 42px; margin: 2px 0 2px; }
.p-line { font-family: var(--px); font-size: 22px; line-height: 1.05; color: var(--parch-soft); margin-bottom: 12px; }
/* v4.3: the report wears the level's tag under its title (the medals are gone). */
#p-tag { display: table; margin: -2px auto 9px; font-size: 20px; }
#p-tag[hidden] { display: none; }
/* v4.3 fix (m3): a first clear's ribbon across the top of the report's cells, stamped in; the coins burst from their cell
   as they start counting (main.js countCoins adds .go). Reduced motion: the ribbon just shows, no coin flies. */
#p-ribbon { position: relative; z-index: 2; align-self: center; margin: -4px 0 8px; padding: 3px 14px 2px; font-family: var(--px); font-size: 20px; line-height: 1; color: #fff6e8; background: #e8553a;
  border: 2px solid var(--ink); border-radius: 4px; box-shadow: inset 0 0 0 2px var(--gold), 0 3px 0 rgba(0,0,0,.35); transform: rotate(-3deg); text-shadow: 0 2px 0 rgba(34,26,38,.45); animation: ribbon .45s cubic-bezier(.3,1.6,.5,1) .35s both; }
#p-ribbon[hidden] { display: none; }
/* v5 R4 fix (S4): the boss's win, the Goblin King's crown recovered: it stamps in over the title with a ring of gold rays
   bursting out (reduced motion: the crown just shows). */
#p-crown { position: relative; align-self: center; width: 92px; height: 66px; margin: -6px 0 2px; animation: crownIn .6s cubic-bezier(.3,1.6,.5,1) .15s both; }
#p-crown[hidden] { display: none; }
#p-crown svg { position: relative; z-index: 1; width: 100%; height: 100%; filter: drop-shadow(0 3px 0 rgba(0,0,0,.35)); }
#p-crown .rays { position: absolute; left: 50%; top: 50%; }
#p-crown .rays i { position: absolute; left: -4px; top: -4px; width: 8px; height: 8px; background: #ffd723; border: 2px solid #1f1b24; transform: rotate(calc(var(--k) * 30deg)) translateY(0) scale(.4); opacity: 0; animation: crownRay 1.1s ease-out .45s both; }
#p-crown .rays i:nth-child(1) { --k: 0; } #p-crown .rays i:nth-child(2) { --k: 1; } #p-crown .rays i:nth-child(3) { --k: 2; } #p-crown .rays i:nth-child(4) { --k: 3; } #p-crown .rays i:nth-child(5) { --k: 4; } #p-crown .rays i:nth-child(6) { --k: 5; }
#p-crown .rays i:nth-child(7) { --k: 6; } #p-crown .rays i:nth-child(8) { --k: 7; } #p-crown .rays i:nth-child(9) { --k: 8; } #p-crown .rays i:nth-child(10) { --k: 9; } #p-crown .rays i:nth-child(11) { --k: 10; } #p-crown .rays i:nth-child(12) { --k: 11; }
@keyframes crownIn { 0% { transform: translateY(-40px) scale(2.4) rotate(-14deg); opacity: 0; } 100% { transform: none; opacity: 1; } }
@keyframes crownRay { 0% { opacity: 1; transform: rotate(calc(var(--k) * 30deg)) translateY(-10px) scale(1); } 100% { opacity: 0; transform: rotate(calc(var(--k) * 30deg)) translateY(-120px) scale(.6); } }
.sheet.tight #p-crown { width: 70px; height: 50px; margin: -4px 0 0; }
@keyframes ribbon { 0% { transform: rotate(-12deg) scale(2); opacity: 0; } 100% { transform: rotate(-3deg); opacity: 1; } }
#p-stats .st.coin { position: relative; }
#p-stats .burst { position: absolute; left: 50%; top: 45%; width: 0; height: 0; pointer-events: none; }
#p-stats .burst i { position: absolute; left: -9px; top: -9px; width: 18px; height: 18px; background: var(--ic-coin) center / contain no-repeat; image-rendering: pixelated; opacity: 0; }
#p-stats .st.coin.go .burst i { animation: coinfly .8s cubic-bezier(.2,.8,.4,1) both; }
#p-stats .st.coin.go .burst i:nth-child(2n) { animation-delay: .06s; } #p-stats .st.coin.go .burst i:nth-child(3n) { animation-delay: .12s; }
@keyframes coinfly { 0% { transform: translate(0, 0) scale(.6); opacity: 1; } 70% { opacity: 1; } 100% { transform: translate(var(--dx), var(--dy)) scale(1.1); opacity: 0; } }
.row { display: flex; gap: 10px; }
/* v5 R1, the continue on a jam's sheet: a green button with a gold rim and its price on a coin pill, its line under it;
   short of coins it is muted (.poor) and the line says how many more are needed. */
#p-cont { display: flex; flex-direction: column; align-items: center; gap: 4px; margin: -4px 0 10px; }
#p-cont[hidden] { display: none; }
.cont-buy { display: inline-flex; align-items: center; gap: 10px; min-height: 46px; padding: 4px 10px 4px 16px; background: #3f8f5a; color: #fff6e8; text-shadow: 0 2px 0 rgba(34,26,38,.4);
  box-shadow: inset 0 0 0 3px var(--gold), inset 0 5px 0 #6cc488, inset 0 -6px 0 #24643a, 0 3px 0 rgba(0,0,0,.5); font-size: 26px; }
.cont-buy .cprice { display: inline-flex; align-items: center; gap: 4px; padding: 2px 8px 1px 5px; border-radius: 999px; background: #fff3cf; color: var(--parch-ink); text-shadow: none; font-size: 22px; --ico: 18px; }
.cont-buy.poor { background: #8c8478; box-shadow: inset 0 0 0 3px #b9ab8c, inset 0 5px 0 #a69e90, inset 0 -6px 0 #6b645a, 0 3px 0 rgba(0,0,0,.5); }
.cont-buy.poor .cprice { background: #ffd9d0; color: #b0301c; }
.cont-say { font-family: var(--px); font-size: 18px; line-height: 1; color: var(--parch-soft); }
.cont-buy.poor + .cont-say { color: #b0301c; }
.sheet.tight #p-cont { margin: -2px 0 6px; } .sheet.tight .cont-buy { min-height: 40px; font-size: 22px; } .sheet.tight .cont-say { font-size: 16px; }
/* v5.1 AD HOOK, the x2 reward on the win sheet (config meta.double; off: never shown yet): the continue's green button,
   its label and the ad line on one row. */
.x2-ad { display: flex; align-items: center; justify-content: center; gap: 10px; width: 100%; min-height: 46px; margin: 0 0 10px; padding: 4px 12px; background: #3f8f5a; color: #fff6e8; text-shadow: 0 2px 0 rgba(34,26,38,.4);
  box-shadow: inset 0 0 0 3px var(--gold), inset 0 5px 0 #6cc488, inset 0 -6px 0 #24643a, 0 3px 0 rgba(0,0,0,.5); font-size: 26px; }
.x2-ad .x2-say { font-size: 18px; color: #fff3cf; }
.sheet.tight .x2-ad { min-height: 40px; margin-bottom: 6px; font-size: 22px; }
.row button { flex: 1; min-width: 0; padding: 0 8px; }

/* Title (v4 M5: the home screen, below): the painted scene fills the screen. */
.screen { position: absolute; inset: 0; z-index: 10; background: var(--bg) var(--wall, none) repeat; background-size: var(--wall-size, auto); image-rendering: pixelated;
  overflow-y: auto; padding: env(safe-area-inset-top) var(--gut) max(16px, env(safe-area-inset-bottom)); scrollbar-width: none; }
.screen::-webkit-scrollbar { display: none; }
.screen > * { image-rendering: auto; }
.screen[hidden] { display: none !important; }
/* v5.3: the home is a painted siege (art/, a <picture>) covering #title's own box (main.js fitTitle sets --art-x so the
   castle sits at the box's centre), fading in over the painting's own sky-to-field colours; a light shade at the top
   (the pills, the logo) and a deeper one at the foot (the realm line, Play, the tabs). */
#title { padding: 0; overflow: hidden; background: linear-gradient(#8e8d84, #6c624a 50%, #534a34); }
#title-art { position: absolute; inset: 0; display: block; }
#title-art img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: var(--art-x, 50%) var(--art-y, 30%); opacity: 0; transition: opacity .6s ease-out; }
#title-art.on img { opacity: 1; }
#title-art::before, #title-art::after { content: ""; position: absolute; left: 0; right: 0; pointer-events: none; }
#title-art::before { top: 0; height: 30%; background: linear-gradient(rgba(20,16,28,.5), rgba(20,16,28,.18) 55%, rgba(20,16,28,0)); }
#title-art::after { bottom: 0; height: 42%; background: linear-gradient(rgba(20,16,28,0), rgba(20,16,28,.32) 50%, rgba(20,16,28,.6)); }
@media (prefers-reduced-motion: reduce) { #title-art img { transition: none; } }
.small { font-size: 16px !important; }

/* Wide screens (desktop, landscape phones): the board takes the full height on the left; the controls, the level's name,
   the holding line and the tray sit together in one side column on the right (main.js sizes --stage-w to the board and
   --rail-w to the screen). Critics 1 fix (desktop 16:9 first): the side column is the board's height (--blk-h, the
   frame's), top-aligned with it, the two centred as one block; the column's foot keeps --pw-h free for M5's power-up bar
   (#powers, empty until then). Fix 2: the tray ends at the queue and #powers sits outside it, so the rest of the column
   is brick, not blank tray. The win / fail sheet covers the column below the line (placed by main.js). */
body.wide #app { max-width: none; display: grid; justify-content: center; align-items: center; column-gap: var(--wide-gap, 28px); padding-top: 8px; padding-bottom: 8px;
  grid-template-columns: var(--stage-w, 60%) var(--rail-col, var(--rail-w, 400px)); grid-template-rows: minmax(0, 1fr); } /* lane P Stage 3: --rail-col, the zoomed side column's width on screen */
body.wide #play { display: contents; }
body.wide #stage { grid-column: 1; grid-row: 1; height: 100%; min-width: 0; }
body.wide #side { grid-column: 2; grid-row: 1; display: flex; flex-direction: column; height: var(--blk-h, auto); min-height: fit-content; max-height: 100%; }
body.wide #top { order: 0; height: auto; padding: 12px 12px 10px; background: rgba(20,16,28,.62); border: 3px solid var(--ink); border-bottom: 0; border-radius: 12px 12px 0 0; }
body.wide #rail { flex: none; margin: 0; padding: var(--tray-pad); gap: 12px; border-radius: 0 0 12px 12px; } /* ends at the queue (fix 2): the column's foot is brick */
body.wide #lvl-name { font-size: 26px; } body.wide #tag-chip { font-size: 17px; }
body.wide { --tile-h: 74px; --tile-n: 54px; --tile-gap: 8px; --gl-s: 18px; --slot-h: 62px; --slot-n: 44px; --man: 20px; --ch-s: 16px; --bd: 20px; --lk-s: 18px; --out-n: 16px; --coach-h: 48px; --pw-h: 176px; --pw-d: 84px; --pw-b: 28px; --pw-bfs: 23px; --tray-pad: 12px; }
/* v4 M5: on wide screens the bar fills the side column's foot under the rail (no bare brick): a header with the coins,
   then the four badges with their names, in a row, or 2 x 2 with bigger badges once the foot is tall (main.js:
   #powers.grid, from layout.pwGrid). */
body.wide #powers { flex: 1 1 0; height: auto; min-height: var(--pw-h); overflow: hidden; margin: 12px 0 0; padding: 10px 12px 14px; grid-template-columns: repeat(var(--pw-n, 5), minmax(0, 1fr)); grid-template-rows: auto 1fr; row-gap: 6px; align-content: center;
  border-radius: 12px; background: var(--tray); box-shadow: inset 0 3px 0 var(--tray-hi), inset 0 -4px 0 var(--tray-edge), 0 4px 0 rgba(0,0,0,.45); }
body.wide #pw-coins { grid-column: 1 / -1; justify-self: start; }
body.wide .pw { width: var(--pw-d); flex: none; margin-bottom: 26px; }
body.wide .pw .pw-name { display: block; position: absolute; left: 50%; top: calc(100% + 12px); transform: translateX(-50%); font-family: var(--px); font-size: 19px; line-height: 1; color: var(--tray-ink); white-space: nowrap; }
body.wide .pw.poor .pw-name { display: none; }
body.wide .pw.poor .pw-need { display: block; position: absolute; left: 50%; top: calc(100% + 12px); transform: translateX(-50%); font-family: var(--px); font-size: 19px; line-height: 1; color: var(--pw-poor-ink); white-space: nowrap; }
body.wide.short .pw .pw-name, body.wide.short .pw.poor .pw-need { display: none; }
body.wide #powers.grid { --pw-b: 32px; --pw-bfs: 26px; grid-template-columns: repeat(var(--pw-c, 3), minmax(0, 1fr)); grid-template-rows: auto 1fr 1fr; row-gap: 8px; }
body.wide #line-head { font-size: 20px; }
body.wide .sheet .sheetcard { max-width: none; border: 3px solid var(--ink); border-radius: 12px; }
body.wide .sheet:not(.float) .sheetcard { border-radius: 10px 10px 12px 12px; }
@media (max-height: 700px) { #top { height: 44px; } :root { --tile-h: 46px; --tile-n: 34px; --slot-h: 44px; --slot-n: 32px; --man: 16px; } }
.slot[hidden] { display: none; }
/* Short screens (landscape phones, small iframes): a tighter chrome so the board keeps its cells. */
@media (max-height: 480px) {
  #top { height: 40px; } button.round { width: 38px; height: 38px; min-height: 38px; } #lvl-num { font-size: 19px; } #lvl-name { font-size: 20px; }
  body.wide #app { padding-top: 4px; padding-bottom: 4px; column-gap: 12px; } body.wide #top { padding: 6px 8px 4px; } body.wide #rail { gap: 6px; padding: 6px var(--tray-pad) var(--tray-pad); }
  body.wide { --tile-h: 46px; --tile-n: 34px; --tile-gap: 5px; --gl-s: 13px; --slot-h: 40px; --slot-n: 30px; --man: 14px; --ch-s: 11px; --bd: 13px; --lk-s: 12px; --out-n: 11px; --coach-h: 40px; --coach-fs: 19px; --pw-h: 60px; --pw-d: 50px; --pw-b: 20px; --pw-bfs: 17px; --tray-pad: 8px; }
  body.wide #powers { margin-top: 6px; padding: 4px 8px; grid-template-columns: auto repeat(var(--pw-n, 5), minmax(0, 1fr)); grid-template-rows: 1fr; align-content: center; }
  body.wide #pw-coins { grid-column: auto; --pill-h: 28px; --pill-fs: 18px; --ico: 16px; }
  body.wide .pw { margin-bottom: 0; }
  body.wide #powers.grid { --pw-b: 22px; --pw-bfs: 18px; grid-template-columns: auto repeat(var(--pw-c, 3), minmax(0, 1fr)); grid-template-rows: 1fr 1fr; row-gap: 8px; } /* m5: 2 x 2 (main.js sizePowers) */
  body.wide #powers.grid #pw-coins { grid-row: 1 / 3; }
  body.wide #powers.head { grid-template-columns: repeat(var(--pw-n, 5), minmax(0, 1fr)); grid-template-rows: auto 1fr; row-gap: 8px; } body.wide #powers.head #pw-coins { grid-column: 1 / -1; justify-self: start; }
  body.wide #lvl-name { font-size: 18px; } body.wide #tag-chip { font-size: 13px; } body.wide #line-head { font-size: 15px; }
  button.big { min-height: 48px; font-size: 30px; }
}
/* Short portrait (a small iframe): every row of chrome gives a few px so a 48-row board keeps 8 px cells. */
@media (max-height: 640px) and (max-width: 700px) {
  #top { height: 38px; } button.round { width: 36px; height: 36px; min-height: 36px; } #lvl-num { font-size: 18px; } #lvl-name { font-size: 19px; } #tag-chip { font-size: 16px; }
  :root { --tile-h: 38px; --tile-n: 28px; --tile-gap: 4px; --gl-s: 11px; --slot-h: 36px; --slot-n: 26px; --man: 13px; --ch-s: 10px; --bd: 12px; --lk-s: 11px; --out-n: 11px; --coach-h: 40px; --coach-fs: 19px; --tray-pad: 4px;
  }
  body.rows2:not(.wide) { --pw-h: 46px; --pw-d: 44px; --pw-b: 18px; --pw-bfs: 15px; } /* Critics 2 fix (m4): 44 px tap targets; a badge sits over the band's 2 px rims */
  #rail { margin-bottom: 3px; } #powers { border-width: 2px; border-radius: 10px; margin-bottom: max(4px, env(safe-area-inset-bottom)); } #pw-coins { --pill-h: 28px; --pill-fs: 18px; --ico: 16px; }
  #rail { margin: 3px 0 max(4px, env(safe-area-inset-bottom)); border-width: 2px; border-radius: 10px; } #frame { padding: 4px; }
  #line-head { font-size: 14px; } #lvl-name { font-size: 17px; } #tag-chip { font-size: 12px; } }
/* Land 1: body.tight (main.js fitBoard): a portrait phone above the short rules (375x667) whose board would still fall
   under layout.minCellCss with two queue rows takes the same compact play chrome, so a 46-row picture keeps 8 px cells. */
body.tight:not(.wide) #top { height: 38px; } body.tight:not(.wide) #top button.round { width: 36px; height: 36px; min-height: 36px; } body.tight:not(.wide) #lvl-num { font-size: 18px; }
body.tight:not(.wide) { --tile-h: 38px; --tile-n: 28px; --tile-gap: 4px; --gl-s: 11px; --slot-h: 36px; --slot-n: 26px; --man: 13px; --ch-s: 10px; --bd: 12px; --lk-s: 11px; --out-n: 11px; --coach-h: 40px; --coach-fs: 19px; --tray-pad: 4px; }
body.tight.rows2:not(.wide) { --pw-h: 46px; --pw-d: 44px; --pw-b: 18px; --pw-bfs: 15px; }
body.tight:not(.wide) #powers { border-width: 2px; border-radius: 10px; margin-bottom: max(4px, env(safe-area-inset-bottom)); } body.tight:not(.wide) #pw-coins { --pill-h: 28px; --pill-fs: 18px; --ico: 16px; }
body.tight:not(.wide) #rail { margin: 3px 0 max(4px, env(safe-area-inset-bottom)); border-width: 2px; border-radius: 10px; } body.tight:not(.wide) #frame { padding: 4px; }
body.tight:not(.wide) #line-head { font-size: 14px; } body.tight:not(.wide) #lvl-name { font-size: 17px; } body.tight:not(.wide) #tag-chip { font-size: 12px; }
@media (prefers-reduced-motion: reduce) { #hand svg, .coach-on, .slot.last, .slot.work .men, #line-wrap.full.danger #line, #p-ribbon, #p-stats .st.coin.go .burst i { animation: none; } }
@media (prefers-reduced-motion: reduce) { #p-crown { animation: none; } #p-crown .rays { display: none; } }


/* ---- v4 M5: the home screen ---------------------------------------------------------------------------------------------
   The title scene fills the screen (main.js paints #title-art); over it a top row (settings, the siege's progress, coins,
   lives when meta.lives is on), the logo, then on the green the next level's era and one dominant Play
   (about 70% wide, --play-h tall), and a tab bar at the foot: Siege map, Home, Gallery (padlocked until it opens). */
.home-card { position: relative; height: 100%; max-width: 480px; margin: 0 auto; display: flex; flex-direction: column; padding: max(10px, env(safe-area-inset-top)) var(--gut) 0; }
.home-card { zoom: var(--ui-z, 1); } /* lane P Stage 3: a big screen's scale (main.js layout) */
.home-top { display: flex; align-items: center; gap: 7px; flex: none; }
.home-top #home-prog { margin-left: auto; }
.home h1 { margin: 16px 0 0; text-align: center; font-family: var(--px); font-weight: 400; font-size: 58px; line-height: 1; letter-spacing: 1px; color: var(--gold);
  text-shadow: -3px 0 0 var(--ink), 3px 0 0 var(--ink), 0 -3px 0 var(--ink), 0 3px 0 var(--ink), -3px -3px 0 var(--ink), 3px -3px 0 var(--ink), -3px 3px 0 var(--ink), 3px 3px 0 var(--ink), 0 7px 0 var(--ink); }
.home-foot { margin-top: auto; display: flex; flex-direction: column; align-items: center; gap: 10px; padding: 0 0 14px; }
/* v5.3: the realm line sits over Play on a solid chip (it lay on the pixel scene's river, Critics 2 fix m6, until the
   painting replaced the scene). */
#home-era { margin: 0; padding: 3px 12px 4px; border-radius: 6px; border: 2px solid var(--ink); background: var(--bg); color: var(--gold-hi); font-family: var(--px); font-size: 22px; line-height: 1; white-space: nowrap; box-shadow: 0 3px 0 rgba(0,0,0,.45); }
#home-era:empty { display: none; }
#btn-play.play { width: 70%; min-height: var(--play-h); height: var(--play-h); display: flex; align-items: center; justify-content: center; gap: 10px; border-radius: 14px; font-size: 40px; line-height: 1; }
#btn-play.wait { background: var(--stone); box-shadow: inset 0 3px 0 var(--stone-hi), inset 0 -5px 0 var(--stone-lo), 0 3px 0 rgba(0,0,0,.5); font-size: 28px; }
#btn-play.wait svg { display: none; }
.home #load-msg { margin: 0; font-family: var(--px); color: var(--cream); text-shadow: 0 2px 0 var(--ink); }
.home #load-msg:empty { display: none; }
.tabs { flex: none; display: grid; grid-template-columns: repeat(2, 1fr); height: calc(var(--tab-h) + env(safe-area-inset-bottom)); margin: 0 calc(-1 * var(--gut)); padding-bottom: env(safe-area-inset-bottom);
  border-top: 3px solid var(--ink); background: var(--bg) var(--wall, none) repeat; background-size: var(--wall-size, auto); }
.tab { height: 100%; min-height: 0; border-radius: 0; border: 0; border-left: 3px solid var(--ink); display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px; padding: 4px 2px 6px;
  background: transparent; color: var(--cream-soft); box-shadow: none; font-size: 19px; line-height: 1; }
.tab:first-child { border-left: 0; }
.tab:active:not(:disabled) { transform: none; box-shadow: none; background: rgba(255,255,255,.06); }
.tab.on { background: rgba(242,194,48,.18); color: var(--gold-hi); box-shadow: inset 0 4px 0 var(--gold); }
/* Settings: a parchment card over a dim backdrop (the gear on the home; the Paused sheet carries colour-blind and sound). */
.modal { position: fixed; inset: 0; z-index: 40; display: flex; align-items: center; justify-content: center; padding: 16px; background: rgba(20,16,28,.66); }
.modal[hidden] { display: none; }
.modal .sheetcard { width: 100%; max-width: 380px; padding: 12px 14px 14px; text-align: center; animation: sheetin .22s cubic-bezier(.3,1.4,.5,1); }
.set-rows { display: flex; flex-direction: column; gap: 8px; margin: 6px 0 12px; }
.set-row { display: flex; align-items: center; gap: 10px; width: 100%; min-height: 50px; font-size: 24px; text-align: left; }
.set-row .sl { flex: 1; } .set-row .sv { font-size: 20px; color: var(--parch-soft); }

.set-row[aria-pressed="true"] .sv { color: var(--ink); }
/* v5.4: a sheet taller than the screen scrolls inside itself (Settings on a 360x640 phone or a short window). The save
   code's two rows sit under the toggles; Reset progress is a quiet danger line at the card's foot, under Done and apart
   from it (a rule between). Its sheet's hold button fills left to right on the game clock (main.js holdStep); letting
   go empties it. */
.modal .sheetcard { max-height: 100%; overflow-y: auto; overscroll-behavior: contain; }
.set-row.set-act { font-size: 22px; }
.set-reset { display: flex; align-items: center; justify-content: center; gap: 8px; width: 100%; min-height: 44px; margin-top: 14px; padding: 0 12px; font-size: 21px;
  background: transparent; color: var(--danger-ink); border: 2px solid transparent; border-top: 2px solid var(--parch-edge); border-radius: 0 0 6px 6px; box-shadow: none; }
.set-reset:active:not(:disabled) { transform: none; box-shadow: none; background: rgba(163,39,26,.08); }
.set-reset:focus-visible { border-color: var(--danger-ink); }
.sub-p { margin: 0 0 10px; font-family: var(--px); font-size: 21px; line-height: 1.05; color: var(--parch-soft); text-align: left; }
.sub-p[hidden], .sub-sum:empty { display: none; }
.sub-sum { margin: 0 0 8px; font-family: var(--px); font-size: 22px; line-height: 1.05; color: var(--parch-ink); }
.sub-sum.bad { color: var(--danger-ink); } .sub-sum.good { color: #24643a; }
.sub-meta { display: flex; justify-content: space-between; gap: 8px; margin: 4px 0 8px; font-family: var(--px); font-size: 18px; line-height: 1; color: var(--parch-soft); }
.sub-meta .bad { color: var(--danger-ink); } .sub-meta .ok { color: #24643a; }
textarea.code { display: block; width: 100%; resize: none; margin: 0; padding: 7px 8px; border: 2px solid var(--parch-soft); border-radius: 6px; background: #fff; color: var(--parch-ink);
  font: 14px/1.25 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; word-break: break-all; -webkit-user-select: text; user-select: text; -webkit-touch-callout: default; }
textarea.code:focus { outline: 3px solid var(--gold-lo); outline-offset: 1px; }
.modal button:disabled { opacity: .55; }
.hold { position: relative; overflow: hidden; display: flex; align-items: center; justify-content: center; width: 100%; min-height: 54px; margin: 4px 0 10px; font-size: 26px;
  background: var(--danger); color: #fff6e8; text-shadow: 0 2px 0 rgba(34,26,38,.4); touch-action: none; -webkit-touch-callout: none;
  box-shadow: inset 0 3px 0 #e2735d, inset 0 -5px 0 #74190c, 0 3px 0 rgba(0,0,0,.5); }
.hold .fill { position: absolute; inset: 0; background: var(--danger-fill); transform: scaleX(0); transform-origin: left center; transition: transform .2s ease-out; }
.hold.on .fill { transition: none; }
.hold .hl { position: relative; }
/* A short, wide window (a desktop window 375 tall; lane P Stage 3: up to 640 tall, the portal's 907x510 and 1080x607): Settings'
   rows go two to a line so the sheet fits without scrolling. */
@media (max-height: 640px) and (min-width: 600px) {
  #settings .sheetcard { max-width: 620px; padding-top: 6px; } #settings .p-title { font-size: 32px; margin: 0; }
  #settings .set-rows { display: grid; grid-template-columns: 1fr 1fr; gap: 6px 8px; margin: 4px 0 8px; } #settings .set-row { min-height: 44px; font-size: 21px; }
  #settings .row button { min-height: 44px; } #settings .set-reset { margin-top: 8px; }
}
#toast.over { position: fixed; top: calc(max(14px, env(safe-area-inset-top)) + 118px); bottom: auto; z-index: 45; }
#toast.over.wide { width: max-content; max-width: min(calc(100vw - 32px), 360px); } /* v7 fix pass: the Zen load-fail line (left: 50% would cap it at half the screen) */
#pause .pz-set { display: flex; gap: 10px; margin-top: 18px; }
/* The level report on the win sheet: time, taps and coins, each with its best (or "New best!") underneath. */
/* Critics 2 fix (V2): a Gallery win's finished picture, in its colours on a gilt frame, above the report (main.js sizes it). */
#p-pic { display: flex; justify-content: center; margin: -4px 0 10px; }
#p-pic[hidden] { display: none; }
#p-pic canvas { display: block; box-sizing: content-box; padding: 4px; border: 3px solid var(--ink); border-radius: 5px; background: var(--gold-lo); box-shadow: inset 0 0 0 2px var(--gold-hi), 0 4px 0 rgba(0,0,0,.35); image-rendering: pixelated; }
#stage-pic { position: absolute; inset: 0; z-index: 2; display: flex; align-items: center; justify-content: center; pointer-events: none; }
#stage-pic[hidden] { display: none; }
#stage-pic canvas { display: block; box-sizing: content-box; padding: 5px; border: 3px solid var(--ink); border-radius: 6px; background: var(--gold-lo); box-shadow: inset 0 0 0 2px var(--gold-hi), 0 5px 0 rgba(0,0,0,.45); image-rendering: pixelated; animation: sheetin .3s cubic-bezier(.3,1.4,.5,1); }
#p-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; margin: -4px 0 10px; }
#p-stats[hidden] { display: none; }
#p-stats .st { display: flex; flex-direction: column; align-items: center; gap: 1px; padding: 4px 2px 5px; border-radius: 8px; border: 2px solid var(--parch-edge); background: #f4ead2; }
#p-stats .k { font-family: var(--px); font-size: 15px; line-height: 1; color: var(--parch-soft); }
#p-stats b { font-family: var(--px); font-weight: 400; font-size: 30px; line-height: 1; color: var(--parch-ink); font-variant-numeric: tabular-nums; }
#p-stats em { font-style: normal; font-family: var(--px); font-size: 15px; line-height: 1; color: var(--parch-soft); min-height: 15px; }
#p-stats .st.new em, #p-stats .st.coin em { color: #2f8a3f; }
#p-stats .st.coin b { color: #8a5f00; }
.sheet.tight #p-stats { margin-bottom: 6px; } .sheet.tight #p-stats b { font-size: 25px; }
/* The map's story (moved off the home) and a report card per era (and the Gallery's): cleared, coins (v4.3: no medals). */
.story { margin: 12px 0 0; padding: 8px 10px 9px; border-radius: 8px; border: 3px solid var(--ink); background: rgba(20,16,28,.72); font-family: var(--px); font-size: 19px; line-height: 1.1; color: var(--cream-soft); }
/* Critics 2 fix (m7): the report card is a band: cleared, then the coins. */
.rc { display: flex; align-items: center; flex-wrap: wrap; gap: 6px 14px; margin: -2px 0 10px; padding: 6px 10px 7px; border-radius: 8px; border: 2px solid var(--ink); background: rgba(243,234,216,.1);
  box-shadow: inset 0 2px 0 rgba(255,255,255,.07); font-family: var(--px); font-size: 20px; line-height: 1; color: var(--cream); }
.rc:empty { display: none; }
.rc-n { flex: 1 0 auto; }
.rc-c b { font-weight: 400; margin-right: 6px; }
.rc-c { display: inline-flex; align-items: center; gap: 5px; --ico: 22px; color: var(--gold-hi); }
@media (max-height: 700px) { :root { --tab-h: 62px; --play-h: 58px; } .home h1 { font-size: 50px; } }
@media (max-height: 640px) and (max-width: 700px) { :root { --tab-h: 58px; --play-h: 54px; --pill-h: 34px; --pill-fs: 21px; --ico: 20px; } .home h1 { font-size: 44px; margin-top: 10px; } .home-foot { gap: 8px; } }
@media (max-height: 480px) {
  :root { --tab-h: 50px; --play-h: 48px; --pill-h: 32px; --pill-fs: 20px; --ico: 18px; }
  .home h1 { font-size: 36px; margin-top: 2px; } .home-foot { flex-direction: row; flex-wrap: wrap; justify-content: center; gap: 8px; padding-bottom: 8px; }
  #btn-play.play { width: auto; flex: 0 1 300px; font-size: 32px; } #home-era { font-size: 18px; }
  .tab { flex-direction: row; gap: 8px; font-size: 18px; }
  body.wide .home-card { max-width: 720px; }
  .home h1 { position: absolute; left: 50%; transform: translateX(-50%); top: max(14px, env(safe-area-inset-top)); margin: 0; font-size: 32px; white-space: nowrap; pointer-events: none; } /* in the top row, centred between the pills and How to play (lane P Stage 3: beside the gear it sat on the coins pill at 821x462) */
}
body.wide .home-card { max-width: 760px; }
@media (prefers-reduced-motion: reduce) { .pw.picking, .pw.pop .pw-ic, .tile.next.pickable, .tile.card.pickable, .slot.pickable { animation: none; } }
/* v4.3 fix (n1, carried from v4.2): a phone under 380 CSS px wide (360-wide Android) trims the play screen's side gutter
   to 4 px, so the full-screen boards draw at 8 px a cell. The home, map and Gallery (screens over #app, padded by --gut)
   keep theirs. */
@media (max-width: 379px) { #app { padding-left: max(4px, env(safe-area-inset-left)); padding-right: max(4px, env(safe-area-inset-right)); } }

/* v5 R1: the 2x speed sheet's price pill (the continue's style). */
.sb-poor { margin: -4px 0 8px; font-size: 16px; color: var(--danger-ink, #a3271a); } .sb-poor[hidden] { display: none; } /* lane P Stage 3: short of coins */
/* Lane P Stage 3 (re-check): a sheet that scrolls keeps its buttons in view (the row sticks to the card's foot; only the body
   scrolls), with a soft edge above it as the sign there is more. */
#panel .sheetcard > .row:last-of-type, #speedbuy .sheetcard > .row { position: sticky; bottom: 0; z-index: 1; background: var(--parch); } /* not the other modals: the reset sheet's hold sits just above its row (and Settings fits at every portal size) */
#panel.sheet.fit .sheetcard > .row:last-of-type { box-shadow: 0 -10px 10px -8px rgba(31,27,36,.35); padding-bottom: 2px; }
#sb-buy .cprice { display: inline-flex; align-items: center; gap: 4px; padding: 2px 8px 1px 5px; border-radius: 999px; background: #fff3cf; color: var(--parch-ink); font-size: 22px; --ico: 18px; vertical-align: middle; }
#sb-title { font-size: 24px; margin: 4px 0 12px; }
/* v5 R1: a power-up's tip, a parchment bubble over its badge (an arrow at --ax); an unlock's intro wears a gold rim. */
#pwtip { position: fixed; z-index: 60; max-width: min(300px, calc(100vw - 16px)); padding: 8px 12px 9px; border: 3px solid var(--ink); border-radius: 10px; background: var(--parch); color: var(--parch-ink);
  box-shadow: 0 4px 0 rgba(0,0,0,.45); font-family: var(--px); line-height: 1.05; pointer-events: none; display: flex; flex-direction: column; gap: 3px; }
#pwtip[hidden] { display: none; }
#pwtip::after { content: ""; position: absolute; left: calc(var(--ax, 50%) - 8px); bottom: -11px; border: 8px solid transparent; border-top-color: var(--ink); border-bottom: 0; }
#pwtip.below::after { bottom: auto; top: -11px; border: 8px solid transparent; border-bottom-color: var(--ink); border-top: 0; }
#pwtip.intro { box-shadow: 0 0 0 3px var(--gold), 0 4px 0 rgba(0,0,0,.45); pointer-events: none; } #pwtip.intro .tt-b { display: none; } /* lane P Stage 3 (critic m1): the short intro; a tap goes through to the card under it (and takes it away) */
#pwtip .tt-h { font-size: 22px; font-weight: 400; } #pwtip .tt-f { font-size: 18px; color: #2f7a46; } #pwtip .tt-f[hidden] { display: none; } #pwtip .tt-b { font-size: 18px; color: var(--parch-soft); }

/* ---- v5 R3: the journey map (main.js buildMap; config map) -----------------------------------------------------------
   The top bar (back, the title, coins, the gear), a debug row under ?debug=1, then the column: one scroller (#jr) of 13
   painted sheets stacked bottom to top (main.js sizes them from --jr-w), each an image, an SVG overlay in sheet px (the
   route, detours, bridges, fog) and a layer of buttons placed in percent of the sheet: level badges (cleared gold with a
   check, the current one parchment in a breathing glow with its label, locked dark), side-quest picture nodes (a prize
   bubble while open, a padlocked prize icon while locked, the finished picture once won), ink easter eggs, realm banners.
   Phone: Play in a foot bar. Wide (#map.cards): the realm card and the next-up card stand beside the column. Reduced
   motion stops every glow, idle sprite and the coin pop's rise. Nothing here runs on scroll. */
#map { padding: 0; overflow: hidden; display: flex; flex-direction: column; }
.map-top { flex: none; position: relative; z-index: 3; display: flex; align-items: center; gap: 8px; height: calc(60px + env(safe-area-inset-top)); padding: env(safe-area-inset-top) var(--gut) 0;
  background: var(--bg) var(--wall, none) repeat; background-size: var(--wall-size, auto); border-bottom: 3px solid var(--ink); }
.map-top h2 { margin: 0; flex: 1; min-width: 0; font-family: var(--px); font-weight: 400; font-size: 30px; line-height: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; text-shadow: 0 2px 0 var(--ink); }
#map-coins { flex: none; }
#jr-dbg { flex: none; display: flex; align-items: center; gap: 6px; padding: 5px var(--gut); background: rgba(20,16,28,.85); border-bottom: 3px solid var(--ink); }
#jr-dbg[hidden] { display: none; }
#jr-dbg .dbg-l { font-family: var(--px); font-size: 15px; color: var(--gold-hi); text-transform: uppercase; white-space: nowrap; }
#jr-dbg .dbg-node { flex: 1; min-width: 0; min-height: 40px; }
#jr-body { flex: 1; min-height: 0; position: relative; display: flex; flex-direction: column; }
#jr { flex: 1; min-height: 0; width: var(--jr-w, 100%); max-width: 100%; margin: 0 auto; overflow-x: hidden; overflow-y: auto; overscroll-behavior: contain; scrollbar-width: none; outline: none; background: #c9bb92; }
#jr::-webkit-scrollbar { display: none; }
#map.cards #jr { border-left: 3px solid var(--ink); border-right: 3px solid var(--ink); width: calc(var(--jr-w) + 6px); }
#jr-world { position: relative; width: 100%; overflow: hidden; }
.jr-sheet { position: absolute; left: 0; width: 100%; }
.jr-img, .jr-ov, .jr-lay { position: absolute; left: 0; top: 0; width: 100%; height: 100%; }
.jr-img { display: block; pointer-events: none; user-select: none; -webkit-user-select: none; }
/* Lands foundation: a land's sheets are used again, mirrored (the image flips; journey.js layoutOf mirrors its marks), and
   crossfade into the sheet below on the page (fade: the bottom overlap rows, --jr-fade of the sheet, go transparent). */
.jr-sheet.mir .jr-img { transform: scaleX(-1); }
.jr-sheet.fade .jr-img { -webkit-mask-image: linear-gradient(to top, transparent, #000 var(--jr-fade, 6%)); mask-image: linear-gradient(to top, transparent, #000 var(--jr-fade, 6%)); }
.jr-ov { pointer-events: none; overflow: visible; }
.jr-lay { pointer-events: none; }
.jr-lay > * { position: absolute; pointer-events: auto; }
.jr-lay button { min-height: 0; padding: 0; border: 0; border-radius: 0; background: transparent; box-shadow: none; color: var(--ink); -webkit-tap-highlight-color: transparent; }
.jr-lay button:active:not(:disabled) { transform: none; box-shadow: none; }
/* Level badges (44 px targets). */
.mn { width: 44px; height: 44px; margin: -22px 0 0 -22px; z-index: 1; }
.mn .bd { position: absolute; left: 50%; top: 50%; width: 34px; height: 34px; margin: -17px 0 0 -17px; border-radius: 50%; border: 3px solid var(--ink); display: flex; align-items: center; justify-content: center;
  background: var(--gold); box-shadow: inset 0 -4px 0 var(--gold-lo), inset 0 2px 0 var(--gold-hi), 0 3px 0 rgba(0,0,0,.45); }
.mn .bd b { font-family: var(--px); font-weight: 400; font-size: 21px; line-height: 1; color: var(--ink); margin-top: -2px; }
.mn.cur { z-index: 2; }
.mn.cur .bd, .mn.open .bd { background: var(--parch); box-shadow: inset 0 -4px 0 var(--parch-edge), 0 3px 0 rgba(0,0,0,.45); }
.mn.cur .bd { width: 42px; height: 42px; margin: -21px 0 0 -21px; } .mn.cur .bd b { font-size: 27px; }
.mn.cur::before { content: ""; position: absolute; left: 50%; top: 50%; width: 66px; height: 66px; margin: -33px 0 0 -33px; border-radius: 50%;
  background: radial-gradient(circle, rgba(255,243,168,.95) 50%, rgba(255,243,168,.5) 62%, rgba(255,243,168,0) 72%); animation: jrglow 1.6s ease-in-out infinite; }
@keyframes jrglow { 50% { transform: scale(1.14); opacity: .7; } }
.mn.locked .bd { background: #736c7e; box-shadow: inset 0 -4px 0 #4a4252, 0 0 0 2px rgba(236,226,200,.55), 0 3px 0 rgba(0,0,0,.45); } .mn.locked .bd b { color: #d6cfe0; } /* v5 R4 fix (N1): a lighter disc and a pale rim, so a locked node reads on the dark Crags and Mistmoor sheets */
.mn .ck { display: none; position: absolute; right: 1px; top: 0; width: 17px; height: 17px; border-radius: 50%; border: 2px solid var(--ink);
  background: #3fbf5a center / 11px 11px no-repeat url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'%3E%3Cpath d='M1.5 5.2l2.4 2.4 4.6-5' fill='none' stroke='%23fff' stroke-width='2'/%3E%3C/svg%3E"); }
.mn.done .ck { display: block; }
.mn .tag { position: absolute; left: 50%; top: 37px; transform: translateX(-50%); font-size: 14px; padding: 1px 3px 0; border-width: 1.5px; } /* v5 R3 fix: 12 px was hard to read at 375 */
.mn.cur .tag, .mn.locked .tag { display: none; }
.jr-cur { z-index: 3; display: flex; align-items: center; gap: 6px; height: 30px; margin: -15px 0 0 30px; padding: 0 9px; border-radius: 8px; background: rgba(20,16,28,.9); box-shadow: 0 0 0 2px var(--ink);
  font-family: var(--px); font-size: 22px; line-height: 1; color: var(--gold-hi); white-space: nowrap; pointer-events: none !important; }
.jr-cur.east { margin-left: -30px; transform: translateX(-100%); }
.jr-cur.up { margin: 0; transform: translate(-50%, calc(-100% - 30px)); } .jr-cur.dn { margin: 0; transform: translate(-50%, 30px); } /* v5 R3 fix: when neither side is clear */
/* v5 R4 fix (S5): the corners, when no side is clear (main.js fitLabel measures them). */
.jr-cur.ne { margin: 0; transform: translate(10px, calc(-100% - 22px)); } .jr-cur.nw { margin: 0; transform: translate(calc(-100% - 10px), calc(-100% - 22px)); }
.jr-cur.se { margin: 0; transform: translate(10px, 22px); } .jr-cur.sw { margin: 0; transform: translate(calc(-100% - 10px), 22px); }
.jr-cur.up.far { transform: translate(-50%, calc(-100% - 56px)); } .jr-cur.dn.far { transform: translate(-50%, 56px); }
.jr-cur.ne.far { transform: translate(10px, calc(-100% - 48px)); } .jr-cur.nw.far { transform: translate(calc(-100% - 10px), calc(-100% - 48px)); }
.jr-cur.se.far { transform: translate(10px, 48px); } .jr-cur.sw.far { transform: translate(calc(-100% - 10px), 48px); }
.jr-cur .tag { font-size: 15px; padding: 1px 4px 0; }
/* Side quests: a picture node, its prize bubble while open, its prize icon (dim, padlocked) while locked, its picture once won. */
.qn { width: 44px; height: 44px; margin: -22px 0 0 -22px; z-index: 1; }
.qn .qf { position: absolute; left: 50%; top: 50%; width: 36px; height: 36px; margin: -18px 0 0 -18px; border-radius: 50%; border: 3px solid var(--ink); overflow: hidden; display: flex; align-items: center; justify-content: center;
  background: #8263ad; box-shadow: inset 0 -4px 0 #5a3f80, 0 3px 0 rgba(0,0,0,.45); }
.qn .qi { width: 19px; height: 17px; background: center / contain no-repeat url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 14' shape-rendering='crispEdges'%3E%3Crect width='16' height='14' fill='%23221a26'/%3E%3Crect x='1' y='1' width='14' height='12' fill='%23f2c230'/%3E%3Crect x='3' y='3' width='10' height='8' fill='%237ec8e8'/%3E%3Cpath d='M3 11V8l3-3 2 2 1-1 4 3v2z' fill='%234f9a3c'/%3E%3Crect x='9' y='4' width='2' height='2' fill='%23ffe27a'/%3E%3C/svg%3E"); }
.qn canvas { display: none; }
/* v5 R3 fix: a won quest keeps its purple (a quest, cleared: its picture in a rounded frame with the level's green check). */
.qn.won .qf { width: 42px; height: 42px; margin: -21px 0 0 -21px; padding: 3px; border-radius: 12px; background: #8263ad; box-shadow: inset 0 -3px 0 #5a3f80, 0 3px 0 rgba(0,0,0,.45); }
.qn.won::after { content: ""; position: absolute; right: -2px; top: -3px; width: 17px; height: 17px; border-radius: 50%; border: 2px solid var(--ink); box-sizing: border-box;
  background: #3fbf5a center / 11px 11px no-repeat url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'%3E%3Cpath d='M1.5 5.2l2.4 2.4 4.6-5' fill='none' stroke='%23fff' stroke-width='2'/%3E%3C/svg%3E"); }
.qn.won canvas { display: block; width: 100%; height: 100%; object-fit: contain; image-rendering: pixelated; background: #1a1620; border-radius: 2px; }
.qn.won .qi { display: none; }
.qn.locked .qf { background: #5d5566; box-shadow: inset 0 -4px 0 #3f3947, 0 3px 0 rgba(0,0,0,.45); } .qn.locked .qi { opacity: .45; }
.qn.next .qf { box-shadow: inset 0 -4px 0 #5a3f80, 0 0 0 3px var(--gold-hi), 0 3px 0 rgba(0,0,0,.45); }
.qn .qp { display: none; position: absolute; right: -3px; bottom: -3px; width: 21px; height: 21px; border-radius: 50%; border: 2px solid var(--ink); background: var(--pw-disc) center / 74% 74% no-repeat; image-rendering: pixelated; }
.qn.locked .qp { display: block; }
.qn .prz { display: none; position: absolute; width: 60px; padding: 3px 0 4px; border-radius: 9px; border: 3px solid var(--ink); background: var(--parch); color: var(--parch-ink);
  box-shadow: inset 0 -3px 0 var(--parch-edge), 0 3px 0 rgba(0,0,0,.35); font-family: var(--px); font-size: 13px; line-height: 1; text-align: center; text-transform: uppercase; }
.qn .prz::after { content: ""; position: absolute; border: 6px solid transparent; }
.qn.bz-n .prz { left: 50%; bottom: calc(100% + 5px); margin-left: -30px; } .qn.bz-n .prz::after { left: 50%; bottom: -10px; margin-left: -6px; border-top: 7px solid var(--ink); border-bottom: 0; }
.qn.bz-e .prz { left: calc(100% + 6px); top: 50%; margin-top: -26px; } .qn.bz-e .prz::after { left: -10px; top: 50%; margin-top: -6px; border-right: 7px solid var(--ink); border-left: 0; }
.qn.bz-w .prz { right: calc(100% + 6px); top: 50%; margin-top: -26px; } .qn.bz-w .prz::after { right: -10px; top: 50%; margin-top: -6px; border-left: 7px solid var(--ink); border-right: 0; }
.qn.bz-s .prz { left: 50%; top: calc(100% + 5px); margin-left: -30px; } .qn.bz-s .prz::after { left: 50%; top: -10px; margin-left: -6px; border-bottom: 7px solid var(--ink); border-top: 0; } /* v5 R3 fix: below */
.qn.open .prz { display: block; }
.qn .pz-r { display: flex; align-items: center; justify-content: center; gap: 2px; font-size: 20px; margin-top: 1px; }
.qn .pi { flex: none; width: 21px; height: 21px; background: center / contain no-repeat; image-rendering: pixelated; }
.qn.tailn .qf { box-shadow: inset 0 -4px 0 #5a3f80, 0 0 0 4px rgba(230,232,222,.75), 0 3px 0 rgba(0,0,0,.45); }
/* The fog's words and, in the wash, the cleared long-tail pictures to play again. */
.fogl { transform: translate(-50%, -50%); font-family: var(--px); font-size: 20px; line-height: 1; color: #f3ead8; white-space: nowrap; pointer-events: none !important;
  text-shadow: 0 2px 0 var(--ink), 2px 0 0 var(--ink), -2px 0 0 var(--ink), 0 -2px 0 var(--ink); }
/* v5 R3 fix: the latest few in one row of 44 px frames (a won quest's look), and past that a parchment chip that opens a
   sheet of all of them (44+ px tiles). */
.thumbs { display: flex; flex-wrap: wrap; gap: 6px; width: calc(var(--row, 3) * 50px - 6px); pointer-events: none !important; }
.thumbs .th, .ts-tile { pointer-events: auto; width: 44px; height: 44px; padding: 3px; border: 3px solid var(--ink) !important; border-radius: 12px !important; background: #8263ad !important; box-shadow: inset 0 -3px 0 #5a3f80, 0 3px 0 rgba(0,0,0,.45) !important; }
.thumbs canvas, .ts-tile canvas { display: block; width: 100%; height: 100%; object-fit: contain; image-rendering: pixelated; background: #1a1620; border-radius: 6px; }
.jr-lay .tchip { pointer-events: auto; flex-basis: 100%; height: 44px; display: flex; align-items: center; justify-content: center; gap: 6px; border: 3px solid var(--ink); border-radius: 9px; background: var(--parch);
  box-shadow: inset 0 -3px 0 var(--parch-edge), 0 3px 0 rgba(0,0,0,.35); color: var(--parch-ink); font-size: 20px; line-height: 1; white-space: nowrap; }
.tchip .qi { flex: none; width: 19px; height: 17px; background: center / contain no-repeat url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 14' shape-rendering='crispEdges'%3E%3Crect width='16' height='14' fill='%23221a26'/%3E%3Crect x='1' y='1' width='14' height='12' fill='%23f2c230'/%3E%3Crect x='3' y='3' width='10' height='8' fill='%237ec8e8'/%3E%3Cpath d='M3 11V8l3-3 2 2 1-1 4 3v2z' fill='%234f9a3c'/%3E%3Crect x='9' y='4' width='2' height='2' fill='%23ffe27a'/%3E%3C/svg%3E"); }
#tailsheet .sheetcard { max-width: 420px; }
#ts-title { font-size: 34px; }
#ts-grid { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; max-height: min(62vh, 520px); overflow-y: auto; margin: 6px 0 12px; padding: 4px 2px 6px; }
.ts-tile { width: 56px; height: 56px; min-height: 0; flex: none; }
/* Easter eggs: ink sprites; a found one keeps its new look (and its little loop of life). */
.egg { width: 44px; height: 44px; margin: -22px 0 0 -22px; }
.egg[hidden] { display: none; }
.egg svg { display: block; width: 100%; height: 100%; overflow: visible; }
.egg svg * { transform-box: fill-box; transform-origin: 50% 100%; }
.egg .coinpop { position: absolute; left: 50%; top: -8px; transform: translateX(-50%); font-family: var(--px); font-size: 24px; line-height: 1; color: var(--gold-hi); white-space: nowrap; pointer-events: none;
  text-shadow: 0 2px 0 var(--ink), 2px 0 0 var(--ink), -2px 0 0 var(--ink), 0 -2px 0 var(--ink); animation: jrpop 1.1s ease-out forwards; }
@keyframes jrpop { from { transform: translate(-50%, 0); opacity: 1; } 70% { opacity: 1; } to { transform: translate(-50%, -34px); opacity: 0; } }
.egg .sway { animation: jrsway 2.4s ease-in-out infinite; } @keyframes jrsway { 50% { transform: skewX(-7deg); } }
.egg .rip { transform-origin: 50% 50%; animation: jrrip 2.2s ease-out infinite; } @keyframes jrrip { from { transform: scale(.6); opacity: 1; } to { transform: scale(1.25); opacity: 0; } }
.egg .tw, .egg .spk { animation: jrtw 1.6s ease-in-out infinite; } @keyframes jrtw { 50% { opacity: .15; } }
.egg .flk { animation: jrflk .45s ease-in-out infinite alternate; } @keyframes jrflk { to { transform: scale(.9, 1.12); } }
.egg .leap, .egg .bob, .egg .flap { animation: jrbob 1.4s ease-in-out infinite; } @keyframes jrbob { 50% { transform: translateY(-3px); } }
.egg .glow { animation: jrtw 2s ease-in-out infinite; }
/* Realm banners: a parchment scroll; a tap shows the realm's lore under its name. */
.jr-lay .bn, .jr-lay .bn:active:not(:disabled) { transform: translate(-50%, -50%); }
.jr-lay .bn { width: min(76%, 290px); padding: 5px 10px 6px; display: flex; flex-direction: column; align-items: center; z-index: 1; border: 3px solid #2a1c12; border-radius: 4px; background: #f1e3bf;
  box-shadow: inset 0 3px 0 #fbf3dc, inset 0 -4px 0 #d6c191, 0 5px 0 rgba(0,0,0,.35); }
.bn::before, .bn::after { content: ""; position: absolute; top: 9px; width: 20px; height: 28px; background: #6b2a24; border: 3px solid #2a1c12; clip-path: polygon(0 0, 100% 0, 100% 100%, 50% 72%, 0 100%); }
.bn::before { left: -23px; } .bn::after { right: -23px; }
.bn .bt { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: center; gap: 0 8px; max-width: 100%; } /* v5 R4 fix: a long name wraps (no ellipsis) */
.bn .bt i { font-style: normal; font-size: 15px; letter-spacing: .5px; text-transform: uppercase; color: #5a4e3c; white-space: nowrap; }
.bn .bt b { font-weight: 400; font-size: 25px; line-height: 1; color: #6b2a24; text-align: center; text-wrap: balance; }
.bn .bt .bby { font-style: normal; font-size: 15px; letter-spacing: .5px; color: #5a4e3c; white-space: nowrap; } /* the third mode: the artist's credit after the name */
.bn .lore { display: none; margin-top: 4px; font-size: 16px; line-height: 1.1; color: #3a3027; text-align: center; }
.bn.open .lore { display: block; }
/* The map's foot: the story and the credits, under the first sheet. */
#jr-start { padding: 12px 12px 16px; background: var(--bg) var(--wall, none) repeat; background-size: var(--wall-size, auto); border-top: 3px solid var(--ink); }
#jr-start .story { margin: 0; }
#map-credits { margin: 10px 2px 0; font-size: 13px; line-height: 1.35; color: var(--cream-soft); overflow-wrap: anywhere; } /* lane P Stage 3: the licence URIs wrap on a phone */
/* Play: a foot bar on a phone; on a wide screen the next-up card holds it, with the next side quest; the realm card. */
.jr-card { display: none; }
#map:not(.cards) #jr-next { display: block; flex: none; padding: 10px var(--gut) max(12px, env(safe-area-inset-bottom)); border-top: 3px solid var(--ink); background: var(--bg) var(--wall, none) repeat; background-size: var(--wall-size, auto); }
#map:not(.cards) #jr-next > :not(#map-play):not(#jr-end) { display: none; }
/* v5 R3 fix: the tag sits inside Play, after its words (the mockup's "Play Level 6 HARD"), not on its corner. */
#map-play { width: 100%; display: flex; align-items: center; justify-content: center; gap: 10px; }
#map-play[hidden], #jr-end[hidden], #jr-quest[hidden] { display: none !important; }
#map-play .tag { position: static; flex: none; font-size: 20px; padding: 3px 6px 2px; }
#jr-end { margin: 0; min-height: 58px; display: flex; align-items: center; justify-content: center; text-align: center; font-family: var(--px); font-size: 22px; line-height: 1.05; color: var(--gold-hi); text-shadow: 0 2px 0 var(--ink); }
#map.cards .jr-card { display: block; position: absolute; top: 18px; width: var(--card-w, 290px); padding: 16px 18px 18px; border-radius: 12px; border: 3px solid var(--ink); background: rgba(20,16,28,.82); box-shadow: 0 5px 0 rgba(0,0,0,.4); font-family: var(--px); }
#map.cards #jr-realm { right: calc(50% + var(--jr-w) / 2 + 3px + var(--card-gap)); }
#map.cards #jr-next { left: calc(50% + var(--jr-w) / 2 + 3px + var(--card-gap)); }
.jr-card .ey { font-size: 18px; letter-spacing: 1px; text-transform: uppercase; color: var(--gold); }
.jr-card h3 { margin: 2px 0 8px; font-weight: 400; font-size: 34px; line-height: 1; display: flex; align-items: center; gap: 8px; }
.jr-card h3 .tag { font-size: 16px; }
#jr-r-note { margin: 0 0 12px; font-size: 19px; line-height: 1.1; color: var(--cream-soft); }
.jr-card .bar { height: 14px; margin: -2px 0 12px; border-radius: 7px; border: 2px solid var(--ink); background: #1a1520; overflow: hidden; }
.jr-card .bar span { display: block; height: 100%; width: 0; background: var(--gold); box-shadow: inset 0 3px 0 var(--gold-hi); }
.jr-card .kv { display: flex; justify-content: space-between; margin: 4px 0; font-size: 21px; } .jr-card .kv b { font-weight: 400; color: var(--gold-hi); }
#map.cards #map-play { margin: 6px 0 14px; }
.sq { width: 100%; min-height: 0; display: flex; align-items: center; gap: 12px; padding: 10px; border-radius: 10px; border: 2px solid var(--ink); background: rgba(255,255,255,.07); box-shadow: none; color: var(--cream); text-align: left; }
.sq:active:not(:disabled) { box-shadow: none; }
.sq.none { opacity: .6; }
.sq-ic { flex: none; width: 44px; height: 40px; background: center / contain no-repeat url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 14' shape-rendering='crispEdges'%3E%3Crect width='16' height='14' fill='%23221a26'/%3E%3Crect x='1' y='1' width='14' height='12' fill='%23f2c230'/%3E%3Crect x='3' y='3' width='10' height='8' fill='%237ec8e8'/%3E%3Cpath d='M3 11V8l3-3 2 2 1-1 4 3v2z' fill='%234f9a3c'/%3E%3Crect x='9' y='4' width='2' height='2' fill='%23ffe27a'/%3E%3C/svg%3E"); }
.sq-t { display: flex; flex-direction: column; gap: 3px; min-width: 0; } .sq-t b { font-weight: 400; font-size: 23px; line-height: 1; } .sq-t span { font-size: 17px; line-height: 1.05; color: var(--cream-soft); }
@media (max-height: 640px) and (max-width: 700px) { .map-top { height: calc(50px + env(safe-area-inset-top)); } .map-top h2 { font-size: 26px; } }
@media (prefers-reduced-motion: reduce) { .mn.cur::before, .egg svg *, .egg .coinpop { animation: none !important; } .egg .coinpop { animation: jrfade 1.1s linear forwards !important; } }
@keyframes jrfade { from { opacity: 1; } to { opacity: 0; } }

/* v6 lane B (Zen mode; tools/zen-mode-notes.md): the home's two mode cards and the map's mode chip. A card is one button:
   the mode's name, its progress line and Play with the next level; the mode played last is lit gold, the other stone.
   Side by side down to a 320 px phone. The chip sits where the map's title was (the title stays for screen readers). */
.vh { position: absolute !important; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
#home-modes { display: flex; gap: 10px; width: 100%; max-width: 460px; margin-top: 12px; }
/* Fix pass (Peter): both cards gold from the first launch; the mode played last wears a cream ring, sits 3 px higher
   and carries a "Continue" chip on its top edge (never a colour swap). Each card holds its own place line (realm or
   world), progress line, and Play with its tag inline. */
#home-modes .mode-card.play { position: relative; flex: 1 1 0; min-width: 0; width: auto; height: auto; min-height: calc(var(--play-h) + 54px); display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px; padding: 12px 6px 11px; font-size: 16px; line-height: 1.1;
  background: var(--gold); color: var(--ink); text-shadow: none; box-shadow: inset 0 3px 0 var(--gold-hi), inset 0 -5px 0 var(--gold-lo), 0 3px 0 rgba(0,0,0,.5); }
#home-modes .mode-card.play.last { transform: translateY(-3px); box-shadow: inset 0 3px 0 var(--gold-hi), inset 0 -5px 0 var(--gold-lo), 0 0 0 3px var(--ink), 0 0 0 6px var(--glow), 0 6px 0 rgba(0,0,0,.45); }
#home-modes .mode-card .mc-last { display: none; position: absolute; top: -13px; left: 50%; transform: translateX(-50%); padding: 2px 8px 3px; border-radius: 6px; border: 2px solid var(--ink); background: var(--glow); color: var(--ink); font-family: var(--px); font-style: normal; font-size: 15px; line-height: 1; white-space: nowrap; }
#home-modes .mode-card.last .mc-last { display: block; }
#home-modes .mode-card .mc-n { font-family: var(--px); font-size: 26px; line-height: 1; }
#home-modes .mode-card .mc-w { font-size: 13px; font-weight: 700; white-space: nowrap; max-width: 100%; overflow: hidden; text-overflow: ellipsis; }
#home-modes .mode-card .mc-w:empty { display: none; }
#home-modes .mode-card .mc-l { font-size: 14px; font-weight: 700; opacity: .85; white-space: nowrap; max-width: 100%; overflow: hidden; text-overflow: ellipsis; }
#home-modes .mode-card .mc-go { display: inline-flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: 3px 5px; font-family: var(--px); font-size: 22px; line-height: 1; white-space: nowrap; max-width: 100%; } /* a long label puts its tag on the line below */
#home-modes .mode-card .mc-go span { overflow: hidden; text-overflow: ellipsis; }
#home-modes .mode-card .tag { position: static; flex: none; font-size: 13px; padding: 1px 4px; }
#home-modes .mode-card.wait .mc-go svg { display: none; }
#home-modes .mode-card.wait .mc-go { font-size: 18px; }
/* lane P Stage 3 (decision B): Zen locked until the Campaign's level zen.openAfter is won: the card greys, a padlock, the hint */
#home-modes .mode-card.locked { filter: saturate(.25) brightness(.92); }
#btn-play.loading { animation: playwait 1s ease-in-out infinite alternate; } @keyframes playwait { to { filter: brightness(.85); } } /* lane P Stage 3: a tap before boot is queued (index.html) */
#home-modes .mode-card.locked .mc-go svg { display: none; }
#home-modes .mode-card.locked .mc-go { font-size: 18px; }
#home-modes .mode-card.locked .mc-go::before, #map-mode button.locked::before { content: ""; display: inline-block; width: 14px; height: 16px; flex: none; background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 14'%3E%3Cpath d='M3.2 6V4.3a2.8 2.8 0 0 1 5.6 0V6' fill='none' stroke='%231f1b24' stroke-width='1.8'/%3E%3Crect x='1' y='6' width='10' height='7.2' rx='1.4' fill='%231f1b24'/%3E%3Crect x='5.2' y='8.2' width='1.6' height='2.8' fill='%23f3ead8'/%3E%3C/svg%3E") center / contain no-repeat; }
#map-mode button.locked { display: inline-flex; align-items: center; gap: 5px; color: var(--ink-soft, #4a4250); }
#map-mode { flex: 1; min-width: 0; display: flex; justify-content: center; }
#map-mode button { min-width: 0; min-height: 44px; padding: 0 12px; font-family: var(--px); font-size: 22px; line-height: 1; border-radius: 0; box-shadow: inset 0 3px 0 var(--stone-hi), inset 0 -4px 0 var(--stone-lo); }
#map-mode button:first-child { border-radius: 12px 0 0 12px; }
#map-mode button + button { margin-left: -3px; } /* The third mode: a third button; the last one shown takes the round end */
#map-mode button:last-child, #map-mode button:nth-last-child(1 of :not([hidden])) { border-radius: 0 12px 12px 0; }
@media (max-width: 460px) { #map-mode.three button { padding: 0 6px; font-size: 18px; } }
#map-mode button[aria-pressed="true"] { background: var(--gold); box-shadow: inset 0 3px 0 var(--gold-hi), inset 0 -4px 0 var(--gold-lo); }
@media (max-width: 360px) { #map-mode button { padding: 0 8px; font-size: 19px; } #home-modes .mode-card .mc-n { font-size: 22px; } #home-modes .mode-card .mc-go { font-size: 19px; } #home-modes .mode-card .mc-w, #home-modes .mode-card .mc-l { font-size: 12px; } }
#home-modes .mode-card[hidden] { display: none; }
/* The third mode (the third mode's notes, in tools/): the third card. Campaign and Zen stay side by side; the third takes the
   row under them, the same gold card laid out in two short lines (its name and Play, then its credit line and progress),
   so the home grows by about one button's height. */
#home-modes { flex-wrap: wrap; row-gap: 14px; }
#home-modes .mode-card.pixels.play { flex: 1 1 100%; display: grid; grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "n go" "w l"; align-items: center; justify-items: start; min-height: 0; row-gap: 3px; column-gap: 10px; padding: 10px 14px 10px; text-align: left; }
#home-modes .mode-card.pixels .mc-n { grid-area: n; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#home-modes .mode-card.pixels .mc-w { grid-area: w; }
#home-modes .mode-card.pixels .mc-l { grid-area: l; justify-self: end; }
#home-modes .mode-card.pixels .mc-go { grid-area: go; justify-self: end; flex-wrap: nowrap; }
/* v6: the reset sheet asks which mode's progress goes (a two-way choice above what it wipes). */
#rs-mode { position: sticky; top: -12px; z-index: 2; display: flex; justify-content: center; margin: 6px -14px 10px; padding: 6px 14px; background: var(--parch); } /* fix pass (m6): room above and below the choice; on a short screen the sheet opens scrolled to Cancel and the choice stays pinned at its top */
#rs-mode[hidden] { display: none; }
#rs-mode button { flex: 1 1 0; min-width: 0; max-width: 140px; min-height: 44px; padding: 0 6px; font-size: 20px; border-radius: 0; }
#rs-mode button + button { margin-left: -3px; }
#rs-mode button:first-child { border-radius: 10px 0 0 10px; }
#rs-mode button:last-child { border-radius: 0 10px 10px 0; }
#rs-mode button[aria-checked="true"] { background: var(--gold); box-shadow: inset 0 3px 0 var(--gold-hi), inset 0 -4px 0 var(--gold-lo); }
/* Fix pass (m7, MINOR-3): the home's gear and the map bar's Back and gear are 44 x 44 at every size (the play bar keeps
   its own sizes and its 44 px tap areas). */
#btn-settings, #btn-home, #map-set { width: 44px; height: 44px; min-height: 44px; }
/* Fix pass (Peter's desktop playtest): the home and the map always fill the window (they used to sit in #app's 560 px
   column until the wide play layout switched on, so the map's side cards were clipped and its top bar shrank). The map's
   column stays centred; the side cards show only when main.js finds room for both (cardsRoom, fitCards). */
#title, #map { position: fixed; inset: 0; }
/* v6 ship fix (Peter): How to play in the home's top row, at its right end (the gear and the coins on the left). A "?" in a
   ring and its label; icon only (its aria-label says it) under 360 px. 44 px tall, its own 44 px tap at least. Hidden while
   the tour runs (body.tut). */
.home-top #btn-howto { margin-left: auto; display: inline-flex; align-items: center; gap: 6px; height: 44px; min-height: 44px; min-width: 44px; padding: 0 12px 0 9px; border-radius: 22px; font-size: 21px; line-height: 1; }
.home-top #btn-howto[hidden], body.tut #btn-howto { display: none; }
@media (max-width: 359px) { .home-top #btn-howto { width: 44px; padding: 0; justify-content: center; } .home-top #btn-howto .hl { display: none; } }
.jr-card .kv[hidden] { display: none; } /* v6 ship fix (m3) */
