/* ===========================================================================
   Minefield Navigation Simulator — "Field Survey" identity
   The aesthetic of a mine-clearance survey crew: a dark field-green HUD, manila
   logbook cards as the signature surface, caution-amber controls, and marker-
   flag red for danger. Condensed industrial display type over a humanist body
   and monospace telemetry. No decorative gloss; the field log is the design.
   =========================================================================== */

:root {
    /* Chrome — dark warm field-green (light text rides on top) */
    --bg:        #11160F;
    --panel:     #19211A;
    --panel-2:   #212B22;
    --ink:       #ECE6D6;   /* warm bone */
    --muted:     #93A08A;   /* lichen gray-green */
    --line:      #2E3A2C;

    --accent:    #F0A92B;   /* caution amber — primary UI accent */
    --flag:      #C8362A;   /* marker-flag red — danger + signature */

    /* Manila survey paper — the signature surface (mode stakes, etc.) */
    --paper:      #E4DAC4;
    --paper-ink:  #2A2A20;
    --paper-soft: #5A5848;  /* secondary ink on paper */
    --paper-line: #C9BC9E;

    /* Signal level colors (shared by JS for markers + heatmap legend) */
    --lvl-1: #3fbf6f;   /* green       */
    --lvl-2: #9ad035;   /* light green  */
    --lvl-3: #f2c12e;   /* yellow      */
    --lvl-4: #f08a2e;   /* orange      */
    --lvl-5: #e0473b;   /* red         */

    /* Type system */
    --font-display: "Saira Condensed", "Arial Narrow", "Segoe UI", sans-serif;
    --font-body:    "Inter", "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    --font-mono:    "IBM Plex Mono", "Consolas", "SF Mono", Menlo, monospace;

    --field-w: 1000px;
}

* { box-sizing: border-box; }

/* The hidden attribute must always win. Several elements that JS toggles via
   `.hidden` also have author `display:flex/grid` rules, which silently override
   the UA's [hidden]{display:none} — that's how the GPS panel bled into every
   setup modal and the GPS stat card showed during practice. */
[hidden] { display: none !important; }

html, body {
    margin: 0;
    padding: 0;
    background: var(--bg);
    color: var(--ink);
    font-family: var(--font-body);
}

/* The game page owns its frame: the site cookie banner would float over the
   controls. Suppressing it leaves consent unset, which fails closed (analytics
   stay off) — visitors can accept on any other page. */
body > .cookie-banner { display: none !important; }

/* Before the first game the menu overlay IS the masthead — the page-level
   header and the dead HUD gauges behind it are noise until a run exists.
   `pregame` is set at load and removed the moment any game/placement starts. */
body.pregame .app-header,
body.pregame .top-panel,
body.pregame .health-row,
body.pregame .bottom-panel,
body.pregame .legend { display: none; }

/* Condensed industrial display face for headings across the game + overlays. */
.app-header h1,
.start-card h2,
.lb-title,
.results h2,
.howto-card h2,
.safety-card h2,
.lobby-card h2,
.mapwiz h2 {
    font-family: var(--font-display);
}

.app {
    max-width: 1040px;
    margin: 0 auto;
    padding: 24px 20px 48px;
}

/* ---- Header ------------------------------------------------------------- */
.app-header { margin-bottom: 18px; }

.app-eyebrow {
    display: block;
    font-family: var(--font-mono);
    font-size: 0.68rem;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--accent);
    margin-bottom: 2px;
}

.app-header h1 {
    margin: 0;
    font-size: 1.75rem;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    font-weight: 800;
    line-height: 1;
}

.tagline {
    margin: 4px 0 0;
    color: var(--muted);
    font-size: 0.9rem;
}

/* ---- Top telemetry panel ------------------------------------------------ */
/* Signal is the hero reading; the rest are compact companions. */
.top-panel {
    display: grid;
    grid-template-columns: 1.5fr 1fr 1fr 1fr;
    gap: 8px;
    margin-bottom: 10px;
}

.stat {
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: 10px;
    padding: 8px 12px;
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.stat-label {
    font-size: 0.7rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--muted);
}

.stat-value {
    font-family: var(--font-mono);
    font-size: 1.6rem;
    font-weight: 700;
    line-height: 1.1;
}

.stat-value.coords { font-size: 1.1rem; }

.stat-sub {
    font-size: 0.75rem;
    color: var(--muted);
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

/* The signal stat recolors itself by level via an inline custom property. */
.stat-signal {
    border-color: var(--sig-color, var(--line));
    box-shadow: inset 0 0 0 1px var(--sig-color, transparent);
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.stat-signal .stat-value,
.stat-signal .stat-sub { color: var(--sig-color, var(--ink)); }

/* ---- Scoreboard (Head-to-Head) ----------------------------------------- */
.scoreboard {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    gap: 12px;
    margin-bottom: 14px;
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: 8px;
    padding: 10px 18px;
}
.scoreboard[hidden] { display: none; }
.score-team {
    display: flex;
    align-items: center;
    gap: 10px;
}
.score-team:last-child { justify-content: flex-end; }
.score-name {
    font-size: 0.8rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--muted);
}
.score-num {
    font-family: var(--font-mono);
    font-size: 1.8rem;
    font-weight: 700;
}
.score-team.is-active .score-name { color: var(--accent); }
.score-team.is-active .score-num  { color: var(--accent); }
.score-mid {
    text-align: center;
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.score-round {
    font-size: 0.75rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--muted);
}
.score-role {
    font-size: 0.82rem;
    font-weight: 700;
    color: var(--ink);
}

/* ---- Placement bar (Head-to-Head) -------------------------------------- */
.place-bar {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-top: 14px;
    background: var(--panel-2);
    border: 1px solid var(--accent);
    border-radius: 8px;
    padding: 10px 16px;
    flex-wrap: wrap;
}
.place-bar[hidden] { display: none; }
.place-msg { font-weight: 700; letter-spacing: 0.02em; }
.place-count {
    font-family: var(--font-mono);
    color: var(--muted);
    margin-right: auto;
}

/* ---- Health bar --------------------------------------------------------- */
.health-row {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 10px;
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: 10px;
    padding: 6px 12px;
}
.health-row[hidden] { display: none; }
.health-label {
    font-size: 0.62rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--muted);
}
.health-track {
    position: relative;
    flex: 1;
    height: 9px;
    background: #0E140C;
    border: 1px solid var(--line);
    border-radius: 5px;
    overflow: hidden;
}
.health-fill {
    height: 100%;
    width: 100%;
    background: linear-gradient(90deg, color-mix(in srgb, var(--hf, var(--lvl-1)) 75%, #fff 8%), var(--hf, var(--lvl-1)));
    background-color: var(--hf, var(--lvl-1));
    transition: width 0.12s linear, background-color 0.25s ease;
}
.health-row.draining .health-fill { animation: healthPulse 0.6s ease-in-out infinite; }
@keyframes healthPulse { 50% { opacity: 0.55; } }
.health-pct {
    font-family: var(--font-mono);
    font-weight: 700;
    font-size: 0.95rem;
    min-width: 46px;
    text-align: right;
}
.lives-pips { display: inline-flex; align-items: center; gap: 4px; margin-left: 10px; }
.lives-pips[hidden] { display: none; }
.lives-pips .lp-label {
    font-size: 0.62rem; letter-spacing: 0.08em; text-transform: uppercase;
    color: var(--muted); margin-right: 3px;
}
.lives-pips .pip {
    width: 9px; height: 9px; border-radius: 50%;
    background: var(--lvl-5); box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.45);
}
.lives-pips .pip.off { background: var(--panel-2); box-shadow: inset 0 0 0 1px var(--line); }

/* ---- Field -------------------------------------------------------------- */
.field-wrap {
    display: flex;
    justify-content: center;
}

.field {
    position: relative;
    width: var(--field-w);
    /* Keep the 1000:600 ratio so the field scales uniformly (no horizontal
       squish, no oval mines) on viewports narrower than the field. */
    aspect-ratio: 5 / 3;
    max-width: 100%;
    /* Strict, screen-independent grid: a FIXED 25 x 15 cells (the 1000x600
       model at 40px cells), sized as fractions of the field so every screen
       shows the same grid. 100%/25 = 4% wide, 100%/15 = 6.6667% tall; at the
       5:3 box those work out square. (Was a fixed 40px, so the cell COUNT grew
       with the screen.) */
    background:
        linear-gradient(var(--line) 1px, transparent 1px) 0 0 / 4% 6.6667%,
        linear-gradient(90deg, var(--line) 1px, transparent 1px) 0 0 / 4% 6.6667%,
        #0E140C;
    border: 1px solid var(--line);
    border-radius: 10px;
    overflow: hidden;
    cursor: grab;            /* grab-and-drag the marker to move */
    touch-action: none;      /* the drag owns touch input — no scroll/zoom steal */
    user-select: none;       /* dragging must never select the START/END labels */
    -webkit-user-select: none;
}
.field:active { cursor: grabbing; }

/* Radar sweep: a faint band of light that drifts along the travel axis. Pure
   decoration (pointer-events none, ~6% peak alpha) but it makes the field feel
   alive — like the survey gear is scanning. */
.field::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 1;
    pointer-events: none;
    background: linear-gradient(90deg,
        transparent 0%,
        rgba(140, 220, 160, 0.03) 42%,
        rgba(170, 240, 185, 0.07) 50%,
        rgba(140, 220, 160, 0.03) 58%,
        transparent 100%);
    background-size: 240% 100%;
    animation: fieldSweep 9s linear infinite;
}
@keyframes fieldSweep {
    from { background-position: 120% 0; }
    to   { background-position: -120% 0; }
}
/* Portrait: the corridor stands up, so the sweep climbs instead. */
body.is-portrait .field::before {
    background: linear-gradient(0deg,
        transparent 0%,
        rgba(140, 220, 160, 0.03) 42%,
        rgba(170, 240, 185, 0.07) 50%,
        rgba(140, 220, 160, 0.03) 58%,
        transparent 100%);
    background-size: 100% 240%;
    animation: fieldSweepUp 9s linear infinite;
}
@keyframes fieldSweepUp {
    from { background-position: 0 -120%; }
    to   { background-position: 0 120%; }
}
@media (prefers-reduced-motion: reduce) {
    .field::before { display: none; }
}
/* Pulse ring: a soft expanding halo that keeps the marker readable as "you"
   and beats faster as the signal level rises (JS sets --pulse). Replaces the
   old grab-handle knob — the whole area near the marker is grabbable, and a
   floating readout keeps the number visible above your finger while dragging. */
#player::after {
    content: "";
    position: absolute;
    inset: -5px;
    border-radius: 50%;
    border: 2px solid rgba(255, 255, 255, 0.85);
    animation: playerPulse var(--pulse, 1.8s) ease-out infinite;
    pointer-events: none;
}
@keyframes playerPulse {
    0%   { transform: scale(0.72); opacity: 0.9; }
    70%  { transform: scale(1.5);  opacity: 0; }
    100% { transform: scale(1.5);  opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
    #player::after { animation: none; opacity: 0.35; }
}
/* A small pop while dragging makes the marker read as the thing you're holding. */
.field.dragging #player { transform: scale(1.12); transition: transform 0.06s ease; }

/* Floating signal readout ("loupe") — shown while touch-dragging so the level
   stays readable even with a finger parked on the marker. Rides above the
   marker; JS flips it below when the marker nears the top of the field. */
.drag-readout {
    position: absolute;
    z-index: 8;
    transform: translate(-50%, -100%);
    display: flex;
    align-items: baseline;
    gap: 7px;
    padding: 6px 13px;
    border-radius: 999px;
    background: var(--dr-bg, var(--lvl-1));
    color: #10130a;
    border: 2px solid rgba(255, 255, 255, 0.9);
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.55);
    pointer-events: none;
    white-space: nowrap;
}
.drag-readout.is-hot { color: #fff; }
.drag-readout .dr-num {
    font-family: var(--font-mono);
    font-size: 1.35rem;
    font-weight: 700;
    line-height: 1;
}
.drag-readout .dr-word {
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    opacity: 0.85;
}
.drag-readout.is-below { transform: translate(-50%, 0); }
/* During Head-to-Head placement the cursor is a crosshair so mines can be aimed. */
.field.placing { cursor: crosshair; }

.zone {
    position: absolute;
    top: 0;
    bottom: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    pointer-events: none;
}
.zone span {
    writing-mode: vertical-rl;
    text-orientation: upright;
    letter-spacing: 0.3em;
    font-size: 0.75rem;
    font-weight: 700;
    color: rgba(255, 255, 255, 0.75);
}
.zone-start {
    left: 0;
    width: var(--zs-w, 80px);
    background: linear-gradient(90deg, rgba(46, 184, 92, 0.45), rgba(46, 184, 92, 0.10));
    border-right: 1px dashed rgba(46, 184, 92, 0.7);
}
.zone-end {
    right: 0;
    width: var(--ze-w, 80px);
    background: linear-gradient(270deg, rgba(53, 132, 224, 0.5), rgba(53, 132, 224, 0.12));
    border-left: 1px dashed rgba(53, 132, 224, 0.8);
}

/* ---- Portrait: the corridor stands up — START at the bottom, END at the top.
   Server geometry is unchanged; this only re-skins zones/edges to match the
   rotated view the canvas + JS transform produce. -------------------------- */
body.is-portrait .field {
    /* HEIGHT-driven (not width) so the standing corridor can never overflow the
       viewport — that overflow is what pushed the START end (and the mines near
       it) below the fold, so they read as "missing". The dvh cap keeps the board
       inside the *visible* height even as the mobile address bar collapses;
       150vw (== 90vw * 5/3) caps the width on narrow phones. width derives from
       the height via aspect-ratio, so the 3:5 box never distorts. */
    aspect-ratio: 3 / 5;
    width: auto;
    height: min(52vh, 150vw);
    height: min(52dvh, 150vw);
    margin: 0 auto;
    /* Same strict grid, rotated for the standing 3:5 board: 15 cols x 25 rows. */
    background-size: 6.6667% 4%, 6.6667% 4%;
}
body.is-portrait .zone { left: 0; right: 0; top: auto; bottom: auto; }
body.is-portrait .zone-start {
    bottom: 0; height: var(--zs-h); width: auto;
    background: linear-gradient(0deg, rgba(46, 184, 92, 0.45), rgba(46, 184, 92, 0.10));
    border-right: none; border-top: 1px dashed rgba(46, 184, 92, 0.7);
}
body.is-portrait .zone-end {
    top: 0; height: var(--ze-h); width: auto;
    background: linear-gradient(180deg, rgba(53, 132, 224, 0.5), rgba(53, 132, 224, 0.12));
    border-left: none; border-bottom: 1px dashed rgba(53, 132, 224, 0.8);
}
body.is-portrait .zone span { writing-mode: horizontal-tb; }
/* Deadly edges become the LEFT/RIGHT bands, spanning between the two zones. */
body.is-portrait .hazard {
    left: auto; right: auto; top: var(--ze-h); bottom: var(--zs-h);
    width: var(--edge-band); height: auto;
}
body.is-portrait .hazard-top    { left: 0;  right: auto; border-bottom: none; border-right: 1px dashed rgba(224, 71, 59, 0.65); }
body.is-portrait .hazard-bottom { right: 0; left: auto;  border-top: none;    border-left: 1px dashed rgba(224, 71, 59, 0.65); }

#overlay {
    position: absolute;
    inset: 0;
    /* A <canvas> is a REPLACED element, so inset:0 alone does NOT stretch it —
       it would render at its intrinsic buffer size (600x1000 portrait / 1000x600
       landscape) and get clipped by the field's overflow:hidden whenever the
       field is smaller than the buffer (every phone; any window < 1000px wide).
       width/height:100% makes the canvas SCALE its buffer to the field box, so
       the mine layout always fills the field instead of spilling out of view. */
    width: 100%;
    height: 100%;
    display: block;
    pointer-events: none;     /* canvas never steals mouse events */
}

/* Deadly edge hazard strips — the top/bottom band of the open corridor.
   Positioned from CSS vars set in JS so they track the server's edgeMargin
   and zone widths. Sit under the canvas so markers/path draw over them. */
.hazard {
    position: absolute;
    left: var(--zone-left, 8%);
    right: var(--zone-right, 8%);
    height: var(--edge-band, 6.6%);
    pointer-events: none;
    background: repeating-linear-gradient(
        45deg,
        rgba(224, 71, 59, 0.30) 0 9px,
        rgba(224, 71, 59, 0.08) 9px 18px);
}
.hazard-top    { top: 0;    border-bottom: 1px dashed rgba(224, 71, 59, 0.65); }
.hazard-bottom { bottom: 0; border-top:    1px dashed rgba(224, 71, 59, 0.65); }

/* The player marker doubles as the live signal readout: a level-colored dot
   with the current signal number inside. Color is set from JS per level. */
.player {
    position: absolute;
    width: 32px;
    height: 32px;
    margin: -16px 0 0 -16px;   /* center on the coordinate */
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: var(--font-mono);
    font-weight: 700;
    font-size: 0.95rem;
    color: #10130a;            /* set per-level from JS */
    background: var(--lvl-1);  /* set per-level from JS */
    border: 2px solid #fff;    /* constant ring so "you" always stands out */
    box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.55), 0 0 12px rgba(0, 0, 0, 0.55);
    pointer-events: none;
    z-index: 5;
}

/* Transient in-run message (respawn after death, etc.). */
.run-toast {
    position: absolute;
    top: 18px;
    left: 50%;
    transform: translateX(-50%);
    z-index: 7;
    background: rgba(224, 71, 59, 0.94);
    color: #fff;
    font-family: var(--font-mono);
    font-weight: 700;
    font-size: 0.9rem;
    letter-spacing: 0.02em;
    padding: 8px 16px;
    border-radius: 6px;
    border: 1px solid rgba(255, 255, 255, 0.25);
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.5);
    pointer-events: none;
    max-width: 80%;
    text-align: center;
    animation: runToastIn 0.18s ease;
}
.run-toast[hidden] { display: none; }
@keyframes runToastIn { from { opacity: 0; } }

/* Start / Pause overlay. Anchored to the viewport (not the field) so the
   dialog centers on the page and can use the full window height — this gives
   the settings room to breathe and keeps scrolling inside the card minimal. */
.start-overlay {
    position: fixed;
    inset: 0;
    z-index: 8;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 20px;
    background: rgba(10, 12, 16, 0.72);
    backdrop-filter: blur(2px);
    cursor: default;   /* the field hides the cursor; restore it over the dialog */
}
.start-overlay[hidden] { display: none; }

.start-card {
    width: min(760px, 100%);
    /* dvh tracks the VISIBLE height on mobile (vh includes the area behind the
       collapsed browser toolbar, which would hide the bottom of the card). */
    max-height: 92vh;
    max-height: 92dvh;
    overflow-y: auto;
    text-align: center;
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: 8px;
    /* No bottom padding: the sticky action bar is the card's footer, and any
       padding under it would let scrolled content peek through the gap. The
       menu view (no action bar) restores its own bottom space. */
    padding: 22px 24px 0;
    box-shadow: 0 16px 44px rgba(0, 0, 0, 0.55);
    /* Faint survey-grid wash so the binder reads like gridded field paper. */
    background-image:
        linear-gradient(rgba(147, 160, 138, 0.045) 1px, transparent 1px),
        linear-gradient(90deg, rgba(147, 160, 138, 0.045) 1px, transparent 1px);
    background-size: 22px 22px;
}

/* ---- Two-step menu: VIEW 1 (mode menu) and VIEW 2 (setup) ---------------- */
.menu-view, .setup-view { text-align: left; }
.menu-view[hidden], .setup-view[hidden] { display: none; }
.menu-view { padding-bottom: 22px; }   /* the card itself has no bottom padding */

/* Masthead — the field-log cover line. */
.logbook-masthead {
    border-bottom: 1px solid var(--line);
    padding-bottom: 14px;
    margin-bottom: 4px;
}
.lb-eyebrow {
    display: block;
    font-family: var(--font-mono);
    font-size: 0.68rem;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--accent);
}
.lb-title {
    margin: 6px 0 4px;
    font-weight: 800;
    font-size: clamp(2.1rem, 7vw, 3.1rem);
    line-height: 0.9;
    letter-spacing: 0.01em;
    text-transform: uppercase;
    color: var(--ink);
}
.lb-tagline {
    margin: 0;
    color: var(--muted);
    font-size: 0.92rem;
    max-width: 46ch;
}

/* Mode "stakes" — manila survey cards, each with a red/white marker-flag tab.
   Daily is the hero (full width); GPS spans full width at the bottom. */
.mode-stakes {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 12px;
    margin: 18px 0 14px;
}
.mode-stake {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 6px;
    text-align: left;
    font: inherit;
    background: var(--paper);
    color: var(--paper-ink);
    border: 1px solid var(--paper-line);
    border-radius: 3px;
    padding: 15px 16px 15px 24px;   /* left room for the flag tab */
    cursor: pointer;
    overflow: hidden;
    box-shadow: 0 1px 0 rgba(0, 0, 0, 0.45);
    transition: transform 0.12s ease, box-shadow 0.12s ease, border-color 0.12s ease;
}
.mode-stake:hover {
    transform: translateY(-2px);
    box-shadow: 0 10px 22px rgba(0, 0, 0, 0.5);
    border-color: var(--flag);
}
.mode-stake:active { transform: translateY(0); }
.mode-stake:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.mode-stake.is-featured { grid-column: 1 / -1; }
.mode-stake:last-child   { grid-column: 1 / -1; }   /* GPS spans the full width */

/* Red/white marker-flag tab down the left edge of every stake. */
.ms-flag {
    position: absolute;
    left: 0; top: 0; bottom: 0;
    width: 9px;
    background: repeating-linear-gradient(
        180deg,
        var(--flag) 0 11px,
        #F4EFE2 11px 22px
    );
}
.ms-name {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 1.15rem;
    line-height: 1;
    letter-spacing: 0.03em;
    text-transform: uppercase;
}
.mode-stake.is-featured .ms-name { font-size: 1.6rem; }
.ms-desc {
    font-size: 0.82rem;
    line-height: 1.35;
    color: var(--paper-soft);
}
.ms-tag {
    align-self: flex-start;
    margin-top: 2px;
    font-family: var(--font-mono);
    font-size: 0.6rem;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--flag);
    border: 1px solid currentColor;
    border-radius: 2px;
    padding: 2px 7px;
}

/* Live status line on the Daily stake ("Today: 1/3 cleared · 4-day streak"). */
.ms-status {
    font-family: var(--font-mono);
    font-size: 0.68rem;
    letter-spacing: 0.04em;
    color: #7A5B14;   /* dark amber — legible on the manila paper */
    margin-top: 1px;
}
.ms-status[hidden] { display: none; }

/* How-to lives quietly under the stakes as a full-width ghost button. */
.btn-ghost {
    background: transparent;
    border: 1px solid var(--line);
    color: var(--muted);
}
.btn-ghost:hover:not(:disabled) { color: var(--ink); border-color: var(--muted); }
.menu-view .btn-howto { display: block; width: 100%; }

/* Setup header: Back + the chosen mode's name. */
.setup-head {
    display: flex;
    align-items: center;
    gap: 14px;
    border-bottom: 1px solid var(--line);
    padding-bottom: 12px;
    margin-bottom: 14px;
}
.btn-back {
    flex: none;
    font: inherit;
    font-family: var(--font-mono);
    font-size: 0.78rem;
    letter-spacing: 0.04em;
    background: transparent;
    color: var(--muted);
    border: 1px solid var(--line);
    border-radius: 4px;
    padding: 7px 13px;
    cursor: pointer;
    white-space: nowrap;
    transition: color 0.12s ease, border-color 0.12s ease;
}
.btn-back:hover { color: var(--ink); border-color: var(--accent); }
.setup-head .setup-title {
    margin: 0;
    font-size: 1.4rem;
}
.setup-note {
    background: var(--panel-2);
    border-left: 3px solid var(--accent);
    border-radius: 4px;
    padding: 10px 13px;
    margin: 0 0 14px;
    font-size: 0.86rem;
    line-height: 1.4;
    color: var(--ink);
}
.setup-note[hidden] { display: none; }

/* One-tap difficulty presets (Practice / Head-to-Head). */
.preset-row {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    margin-bottom: 14px;
}
.preset-label {
    font-size: 0.68rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--muted);
}
.preset-chips { display: flex; gap: 6px; flex-wrap: wrap; }
.preset-chip {
    font: inherit;
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 0.88rem;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    background: var(--panel-2);
    color: var(--ink);
    border: 1px solid var(--line);
    border-radius: 4px;
    padding: 7px 16px;
    cursor: pointer;
    transition: color 0.12s ease, border-color 0.12s ease, background 0.12s ease;
}
.preset-chip:hover { border-color: var(--muted); }
.preset-chip.is-active {
    border-color: var(--accent);
    color: var(--accent);
    background: rgba(240, 169, 43, 0.09);
}
.preset-chip[hidden] { display: none; }
.preset-custom.is-active {
    border-color: var(--flag);
    color: var(--flag);
    background: rgba(200, 54, 42, 0.10);
}

@media (max-width: 560px) {
    .mode-stakes { grid-template-columns: 1fr; }
    .mode-stake, .mode-stake.is-featured { grid-column: auto; }
}

/* Settings embedded in the Start modal. */
.start-settings { margin: 2px 0 12px; }
.start-settings .settings-grid {
    grid-template-columns: 1fr 1fr;
    gap: 10px 16px;
    text-align: left;
    padding: 0;
}
.start-settings[hidden] { display: none; }

/* vs CPU "Random puzzle" quick-play row. */
.coop-quick {
    display: flex; align-items: center; flex-wrap: wrap; gap: 8px;
    background: var(--panel-2); border: 1px solid var(--line); border-radius: 8px;
    padding: 8px 10px; margin: 0 0 12px;
}
.coop-quick[hidden] { display: none; }
.coop-quick .dq-label {
    font-size: 0.66rem; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted);
}
.cq-hint { font-size: 0.72rem; color: var(--muted); margin-left: auto; }

/* Two-column setup body: preview on the left, field controls on the right so
   the dialog stays short. Collapses to a single column on narrow screens. */
.setup-cols {
    display: grid;
    grid-template-columns: minmax(0, 380px) 1fr;
    gap: 18px;
    align-items: start;
}
/* Stack the four field controls in the right column so they read top-to-bottom
   alongside the preview and fill the column width comfortably. */
.setup-cols .manual-grid { grid-template-columns: 1fr; gap: 12px; }
@media (max-width: 620px) {
    .setup-cols { grid-template-columns: 1fr; }
    /* Back to two-up once the columns stack, to keep the list short. */
    .setup-cols .manual-grid { grid-template-columns: 1fr 1fr; }
}
/* On the narrowest phones two selects per row get cramped — go single column. */
@media (max-width: 400px) {
    .setup-cols .manual-grid { grid-template-columns: 1fr; }
}

/* Live field preview inside the Start modal. */
.preview-wrap { margin: 0; }
.preview-canvas {
    display: block;
    width: 100%;
    max-width: 380px;          /* keep it compact so settings stay in view */
    margin: 0 auto;
    height: auto;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: #0E140C;
}
.preview-foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    margin: 6px auto 0;
    max-width: 380px;
    font-size: 0.74rem;
    color: var(--muted);
}
.btn-sm { padding: 5px 12px; font-size: 0.8rem; }

/* Visible keyboard focus across all interactive controls (none existed). */
.btn:focus-visible,
.btn-sm:focus-visible,
.daily-level:focus-visible,
.setting select:focus-visible,
.setting input:focus-visible,
.advanced > summary:focus-visible,
.debug-toggle input:focus-visible,
a:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/* Advanced (collapsed) settings group. */
.advanced {
    margin-top: 8px;
    border-top: 1px solid var(--line);
    padding-top: 6px;
    text-align: left;
}
.advanced > summary {
    cursor: pointer;
    font-size: 0.78rem;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--muted);
    padding: 4px 2px;
    user-select: none;
}
.advanced > summary:hover { color: var(--ink); }
.advanced[open] > .settings-grid { margin-top: 8px; }
/* The 8 advanced options flow into as many columns as the wider card allows. */
.start-settings .advanced .settings-grid {
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
}
.start-card h2 {
    margin: 0 0 6px;
    font-size: 1.2rem;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--accent);
}
.start-card p {
    margin: 0 0 10px;
    color: var(--muted);
    font-size: 0.86rem;
    line-height: 1.4;
}
.btn-start { font-size: 1.05rem; padding: 12px 28px; }
.start-foot {
    margin: 10px 0 0 !important;
    font-size: 0.74rem;
}
.start-card kbd {
    font-family: var(--font-mono);
    background: var(--panel-2);
    border: 1px solid var(--line);
    border-radius: 4px;
    padding: 1px 6px;
    color: var(--ink);
}

/* Start-card action row. Sticky at the bottom of the card's internal scroll so
   the primary CTA never disappears below the fold on phones (the Daily panel
   is taller than a phone screen). Solid background so scrolled content doesn't
   ghost through while pinned. */
.start-actions {
    position: sticky;
    bottom: 0;
    z-index: 2;
    display: flex;
    gap: 10px;
    justify-content: center;
    align-items: center;
    flex-wrap: wrap;
    background: var(--panel);
    margin: 0 -24px;             /* bleed across the card's side padding */
    padding: 12px 24px 16px;
    border-top: 1px solid var(--line);
}
.start-actions[hidden] { display: none; }
/* GPS mode hides the action bar — its panel carries its own buttons — so the
   setup view restores the card's bottom space (only then: padding below the
   sticky bar would let scrolled content peek through). */
.setup-view:has(> .start-actions[hidden]) { padding-bottom: 22px; }
.btn-howto { font-size: 0.95rem; padding: 12px 20px; }

/* ---- How-to-play (instructions) modal ----------------------------------- */
.howto-backdrop {
    position: fixed;
    inset: 0;
    z-index: 9000;             /* above the Start overlay (8), below Exit-FS (9999) */
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 20px;
    background: rgba(8, 10, 14, 0.82);
    backdrop-filter: blur(2px);
}
.howto-backdrop[hidden] { display: none; }
.howto-card {
    width: min(540px, 100%);
    max-height: 90vh;
    max-height: 90dvh;
    overflow-y: auto;
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: 12px;
    padding: 22px 24px;
    box-shadow: 0 16px 44px rgba(0, 0, 0, 0.6);
}
.howto-card h2 {
    margin: 0 0 14px;
    font-size: 1.25rem;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--accent);
}
.howto-list { list-style: none; margin: 0 0 14px; padding: 0; display: flex; flex-direction: column; gap: 11px; }
.howto-list li { display: grid; grid-template-columns: 64px 1fr; gap: 12px; align-items: start; }
.howto-list span:last-child { font-size: 0.9rem; line-height: 1.4; color: var(--ink); }
.howto-tag {
    font-size: 0.62rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    font-weight: 700;
    color: var(--muted);
    background: var(--panel-2);
    border: 1px solid var(--line);
    border-radius: 4px;
    padding: 4px 0;
    text-align: center;
}
.howto-list .chip { padding: 1px 7px; font-size: 0.7rem; vertical-align: middle; }
.howto-skip {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 0.82rem;
    color: var(--muted);
    margin: 4px 0 16px;
    cursor: pointer;
    user-select: none;
}
.howto-skip input { accent-color: var(--accent); width: 16px; height: 16px; }
.howto-card .btn-primary { width: 100%; padding: 12px 0; font-size: 1.02rem; }

/* ---- Forfeit-confirm modal (leaving a live daily run) -------------------- */
.confirm-backdrop {
    position: fixed;
    inset: 0;
    z-index: 9500;             /* above the Start overlay AND the pause view */
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 20px;
    background: rgba(8, 10, 14, 0.82);
    backdrop-filter: blur(2px);
}
.confirm-backdrop[hidden] { display: none; }
.confirm-card {
    width: min(420px, 100%);
    background: var(--panel);
    border: 1px solid var(--flag);
    border-radius: 10px;
    padding: 20px 22px;
    box-shadow: 0 16px 44px rgba(0, 0, 0, 0.6);
}
.confirm-card h2 {
    margin: 0 0 8px;
    font-family: var(--font-display);
    font-size: 1.25rem;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--flag);
}
.confirm-text {
    margin: 0 0 16px;
    font-size: 0.9rem;
    line-height: 1.45;
    color: var(--ink);
}
.confirm-actions { display: flex; gap: 10px; justify-content: flex-end; }

/* ---- Bottom controls ---------------------------------------------------- */
.bottom-panel {
    display: flex;
    align-items: center;
    gap: 14px;
    margin: 16px 0 10px;
    flex-wrap: wrap;
}

/* Kill the double-tap-zoom gesture on all tap controls — rapid taps (Place
   Observation especially) must never zoom the page instead. */
.btn, .btn-sm, .btn-back, .preset-chip, .mode-stake, .daily-level,
.rw-diff-chip, .rw-mode-btn, .debug-toggle, .advanced > summary,
.daily-step, .lvl-cell {
    touch-action: manipulation;
}

.btn {
    font: inherit;
    font-weight: 600;
    color: var(--ink);
    background: var(--panel-2);
    border: 1px solid var(--line);
    border-radius: 10px;
    padding: 10px 18px;
    cursor: pointer;
    transition: background 0.12s ease, border-color 0.12s ease, transform 0.05s ease, box-shadow 0.12s ease;
}
.btn:hover:not(:disabled) { border-color: var(--muted); }
.btn:active:not(:disabled) { transform: translateY(1px); }
.btn:disabled { opacity: 0.45; cursor: not-allowed; }

.btn-primary {
    background: linear-gradient(180deg, #F7BA45 0%, var(--accent) 55%, #DE961D 100%);
    color: #1a1d10;
    border-color: var(--accent);
    box-shadow: 0 2px 10px rgba(240, 169, 43, 0.22);
}
.btn-primary:hover:not(:disabled) { filter: brightness(1.06); box-shadow: 0 3px 14px rgba(240, 169, 43, 0.32); }

/* Quiet meta actions (Sound / Menu / Restart / Fullscreen): visually recessive
   so the play controls read as the primary tier of the bottom bar. */
.btn-quiet {
    background: transparent;
    color: var(--muted);
    border-color: var(--line);
    padding: 9px 14px;
    font-size: 0.86rem;
}
.btn-quiet:hover:not(:disabled) { color: var(--ink); border-color: var(--muted); }

/* Icon-only meta buttons: one glyph, fixed square-ish hit area. Keeps the
   bottom bar to a single quiet cluster instead of a paragraph of words. */
.btn-icon {
    min-width: 44px;
    padding: 9px 10px;
    font-size: 1.02rem;
    line-height: 1;
    text-align: center;
}
.meta-group {
    margin-left: auto;
    display: inline-flex;
    gap: 8px;
    flex-wrap: wrap;
    justify-content: flex-end;
}

/* Destructive confirm action (forfeit a daily run). */
.btn-danger {
    background: transparent;
    color: var(--flag);
    border-color: var(--flag);
}
.btn-danger:hover:not(:disabled) { background: rgba(200, 54, 42, 0.12); }

.debug-toggle {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    color: var(--muted);
    font-size: 0.85rem;
    cursor: pointer;
    user-select: none;
}
.debug-toggle input { accent-color: var(--accent); width: 16px; height: 16px; }
.debug-toggle input:disabled { opacity: 0.4; }
/* Group wrapper: transparent to layout so each toggle is still a flex item,
   but hideable as one unit while a game is in progress. */
.debug-toggles { display: contents; }
.debug-toggles[hidden] { display: none; }

/* Floating "Exit Fullscreen" — sits above every overlay so it's reachable even
   from the Start menu while fullscreen. Shown only in fullscreen (JS-toggled). */
.fs-exit {
    position: fixed;
    top: 10px; right: 10px;
    z-index: 9999;
    font: inherit; font-size: 0.76rem; font-weight: 600;
    color: var(--ink);
    background: rgba(20, 24, 30, 0.88);
    border: 1px solid var(--line);
    border-radius: 8px;
    padding: 7px 12px;
    cursor: pointer;
    backdrop-filter: blur(2px);
}
.fs-exit:hover { border-color: var(--muted); }
.fs-exit[hidden] { display: none; }

/* ---- Legend ------------------------------------------------------------- */
.legend {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
    margin: 6px 0 0;
}
.chip {
    font-family: var(--font-mono);
    font-size: 0.72rem;
    font-weight: 700;
    color: #10130a;
    padding: 3px 9px;
    border-radius: 20px;
}
.chip.lvl-1 { background: var(--lvl-1); }
.chip.lvl-2 { background: var(--lvl-2); }
.chip.lvl-3 { background: var(--lvl-3); }
.chip.lvl-4 { background: var(--lvl-4); color: #fff; }
.chip.lvl-5 { background: var(--lvl-5); color: #fff; }

/* ---- Settings grid (used by the Start modal) ---------------------------- */
.settings-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 14px;
    padding: 8px 0 4px;
}
.setting { display: flex; flex-direction: column; gap: 5px; }
.setting label {
    font-size: 0.72rem;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--muted);
    display: flex;
    justify-content: space-between;
}
.setting output { color: var(--accent); font-family: var(--font-mono); }
.setting select,
.setting input[type="range"] {
    font: inherit;
    width: 100%;
    accent-color: var(--accent);
}
.setting select {
    background: var(--panel-2);
    color: var(--ink);
    border: 1px solid var(--line);
    border-radius: 6px;
    padding: 6px 8px;
}
@media (max-width: 720px) { .settings-grid { grid-template-columns: 1fr 1fr; } }

/* ---- Results overlay — the "Field Report" -------------------------------
   The payoff screen carries the signature manila-paper identity: a survey
   sheet with the red/white flag tab, ink text, and a faint grid wash. */
.results-outcome {
    margin: -6px 0 16px;
    font-size: 0.95rem;
    color: var(--paper-soft);
}
/* Defeat styling — the report header turns marker-flag red on death. */
.results.defeat h2 { color: var(--flag); }

.results-actions {
    display: flex;
    gap: 10px;
    justify-content: center;
}

/* Floating button to reopen results after reviewing the revealed field. */
.reopen-results {
    position: fixed;
    right: 18px;
    bottom: 18px;
    z-index: 60;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5);
}
.reopen-results[hidden] { display: none; }

.results-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(8, 10, 14, 0.78);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 50;
}
/* The `hidden` attribute must win over `display:flex` above, otherwise the
   dialog can never be dismissed. */
.results-backdrop[hidden] { display: none; }
.results {
    position: relative;
    overflow: hidden;
    background: var(--paper);
    color: var(--paper-ink);
    border: 1px solid var(--paper-line);
    border-radius: 4px;
    padding: 24px 28px 24px 36px;   /* left room for the flag tab */
    width: min(520px, 92vw);
    max-height: 92vh;
    max-height: 92dvh;
    overflow-y: auto;
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.6);
    /* Layer 1: the red/white marker-flag tab down the left edge (a background,
       not a positioned child, so it stays pinned while the report scrolls).
       Layers 2–3: the faint survey-grid wash, like the logbook cards. */
    background-image:
        repeating-linear-gradient(180deg, var(--flag) 0 11px, #F4EFE2 11px 22px),
        linear-gradient(rgba(42, 42, 32, 0.05) 1px, transparent 1px),
        linear-gradient(90deg, rgba(42, 42, 32, 0.05) 1px, transparent 1px);
    background-size: 9px 100%, 22px 22px, 22px 22px;
    background-repeat: no-repeat, repeat, repeat;
    background-position: left top, 0 0, 0 0;
}
/* Retired in favor of the background layer above; kept inert for the markup. */
.results-flag { display: none; }
.results-eyebrow {
    display: block;
    font-family: var(--font-mono);
    font-size: 0.64rem;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--paper-soft);
    margin-bottom: 2px;
}
.results h2 {
    margin: 0 0 14px;
    font-size: 1.7rem;
    line-height: 1;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    color: var(--paper-ink);
}
.results-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
    margin-bottom: 16px;
}
.result-item {
    background: rgba(255, 255, 255, 0.45);
    border: 1px solid var(--paper-line);
    border-radius: 4px;
    padding: 10px 12px;
    display: flex;
    flex-direction: column;
    gap: 3px;
}
.result-label {
    font-size: 0.66rem;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: var(--paper-soft);
}
.result-value {
    font-family: var(--font-mono);
    font-size: 1.35rem;
    font-weight: 700;
    color: var(--paper-ink);
}
.results-caption {
    font-size: 0.85rem;
    color: var(--paper-soft);
    margin: 0 0 18px;
}
.results-caption strong { color: var(--paper-ink); }

/* ---- Daily Challenge ---------------------------------------------------- */
.daily-panel { text-align: left; margin: 4px 0 8px; }
.daily-panel[hidden] { display: none; }
#manualSettings[hidden], #previewWrap[hidden], #advancedWrap[hidden] { display: none; }

/* Browse tier — stepping/jumping to other days lives BELOW the selected day's
   levels and board, separated as clearly secondary. */
.daily-browse {
    margin-top: 14px;
    border-top: 1px dashed var(--line);
    padding-top: 10px;
}
.daily-browse-label {
    display: block;
    font-size: 0.66rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--muted);
    margin-bottom: 8px;
}
.daily-datebar { display: flex; align-items: flex-end; gap: 8px; margin-bottom: 10px; flex-wrap: wrap; }
.daily-datebar .setting { flex: 1; min-width: 0; }   /* let the date input shrink, don't overflow */
.daily-datebar input[type="date"] {
    background: var(--panel-2); color: var(--ink);
    border: 1px solid var(--line); border-radius: 6px;
    padding: 6px 8px; font: inherit; width: 100%;
}
/* One-tap prev/next day steppers flanking the date input. */
.daily-step {
    font-family: var(--font-mono);
    font-size: 1rem;
    line-height: 1;
    padding: 8px 12px;
}
.daily-step:disabled { opacity: 0.35; }

.daily-levels { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-bottom: 10px; }
.daily-level {
    display: flex; flex-direction: column; gap: 3px; align-items: flex-start;
    background: var(--panel-2); border: 1px solid var(--line); border-radius: 8px;
    padding: 8px 10px; cursor: pointer; color: var(--ink); font: inherit; text-align: left;
    transition: border-color 0.12s ease, box-shadow 0.12s ease;
}
.daily-level:hover { border-color: var(--muted); }
.daily-level.is-active { border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
.dl-name { font-weight: 700; letter-spacing: 0.03em; }
.dl-meta { font-size: 0.68rem; color: var(--muted); font-family: var(--font-mono); }
.daily-level.is-active .dl-name { color: var(--accent); }

.daily-attempts { margin: 0 0 12px; font-size: 0.85rem; color: var(--ink); font-weight: 600; }

/* "Clear all three" framing + per-day progress. */
.daily-goal { margin: 0 0 10px; font-size: 0.86rem; color: var(--ink); }
.daily-goal strong { color: var(--accent); }
.daily-progress { margin: 0 0 8px; font-size: 0.8rem; color: var(--muted); font-family: var(--font-mono); }
.daily-progress.is-complete { color: var(--accent); font-weight: 700; }
.daily-progress:empty { display: none; }

/* Quick-play row (random / random past). */
.daily-quick {
    display: flex; align-items: center; flex-wrap: wrap; gap: 8px;
    background: var(--panel-2); border: 1px solid var(--line); border-radius: 8px;
    padding: 8px 10px; margin: 0 0 12px;
}
.daily-quick .dq-label {
    font-size: 0.66rem; letter-spacing: 0.08em; text-transform: uppercase;
    color: var(--muted); margin-right: auto;
}

/* Completed-level badge on the level picker. */
.daily-level.is-done { border-color: var(--lvl-1); }
.daily-level.is-done .dl-name::after {
    content: " ✓"; color: var(--lvl-1); font-weight: 700;
}

/* "Challenge a friend" — shares a deep link to this exact date/level. */
.daily-share {
    display: inline-block;
    margin: 0 0 12px;
    background: transparent;
    border-color: var(--accent);
    color: var(--accent);
}
.daily-share:hover { background: rgba(240, 169, 43, 0.10); }
.daily-share[hidden] { display: none; }

.daily-board { background: #0E140C; border: 1px solid var(--line); border-radius: 8px; padding: 8px 10px; }
.daily-board-head { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 6px; }
.daily-board-title { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.08em; color: var(--muted); font-weight: 700; }
.daily-board-sub { font-size: 0.72rem; color: var(--muted); font-family: var(--font-mono); }
.daily-board-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; max-height: 140px; overflow-y: auto; }
.daily-board-list li {
    display: grid; grid-template-columns: 30px 1fr auto auto; gap: 8px; align-items: center;
    font-size: 0.82rem; padding: 3px 4px; border-radius: 4px;
}
.daily-board-list .db-rank  { color: var(--muted); font-family: var(--font-mono); text-align: right; }
.daily-board-list .db-name  { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.daily-board-list .db-score { font-family: var(--font-mono); font-weight: 700; color: var(--accent); }
.daily-board-list .db-time  { font-family: var(--font-mono); color: var(--muted); min-width: 48px; text-align: right; }
.daily-board-list .db-you   { background: var(--panel-2); border: 1px solid var(--line); }
.daily-board-list .db-you .db-name { color: var(--accent); font-weight: 700; }
.daily-board-empty { color: var(--muted); font-size: 0.8rem; padding: 6px 4px !important; display: block !important; }

.daily-editor-link { display: inline-block; margin-top: 10px; font-size: 0.78rem; color: var(--muted); text-decoration: none; }
.daily-editor-link:hover { color: var(--accent); }
.daily-editor-link[hidden] { display: none; }
.daily-season-link { display: block; margin-top: 12px; font-size: 0.8rem; color: var(--accent); text-decoration: none; }
.daily-season-link:hover { text-decoration: underline; }

/* Daily result block inside the results dialog (paper "field report" tones). */
.daily-result { margin: 4px 0 16px; border-top: 1px dashed var(--paper-line); padding-top: 14px; }
.daily-result[hidden] { display: none; }
.dr-headline { display: flex; align-items: center; gap: 18px; margin-bottom: 8px; }
.dr-score { display: flex; flex-direction: column; align-items: center; line-height: 1; }
.dr-score-num { font-family: var(--font-mono); font-size: 2.4rem; font-weight: 700; color: var(--flag); }
.dr-score-label { font-size: 0.62rem; text-transform: uppercase; letter-spacing: 0.12em; color: var(--paper-soft); margin-top: 3px; }
.dr-stats { display: flex; flex-direction: column; gap: 3px; font-size: 0.88rem; color: var(--paper-ink); }
.dr-stats span { font-family: var(--font-mono); }
.dr-breakdown { font-family: var(--font-mono); font-size: 0.74rem; color: var(--paper-soft); margin-bottom: 10px; }
.dr-share-row { display: flex; gap: 8px; flex-wrap: wrap; margin: 0 0 14px; }
.dr-share-row .daily-share { margin: 0; }

/* The shared leaderboard/share components render on paper inside the report. */
.results .daily-board { background: rgba(255, 255, 255, 0.45); border-color: var(--paper-line); }
.results .daily-board-title,
.results .daily-board-sub { color: var(--paper-soft); }
.results .daily-board-list .db-rank,
.results .daily-board-list .db-time { color: var(--paper-soft); }
.results .daily-board-list .db-score { color: #7A5B14; }
.results .daily-board-list .db-you { background: rgba(42, 42, 32, 0.06); border-color: var(--paper-line); }
.results .daily-board-list .db-you .db-name { color: var(--paper-ink); }
.results .daily-board-empty { color: var(--paper-soft); }
.results .daily-share { border-color: var(--flag); color: var(--flag); }
.results .daily-share:hover { background: rgba(200, 54, 42, 0.08); }

@media (max-width: 560px) { .daily-levels { grid-template-columns: 1fr; } }

/* Touch-friendly + non-overflowing on phones. */
.stat { min-width: 0; }   /* let grid cells shrink instead of forcing overflow */
@media (max-width: 640px) {
    /* Trim the page chrome so the board isn't pushed off-screen. */
    .app { padding: 12px 12px 16px; }
    .app-header { margin-bottom: 8px; }
    .app-header h1 { font-size: 1.15rem; }
    .tagline { display: none; }                       /* fluff on a phone */
    /* One compact 4-up strip (short labels) instead of a tall 2x2 block —
       the board gets the reclaimed vertical room. */
    .top-panel { grid-template-columns: 1.4fr 1fr 1fr 1fr; gap: 6px; margin-bottom: 8px; }
    .stat { padding: 6px 8px; border-radius: 8px; }
    .stat-value { font-size: 1.1rem; }
    .stat-label { font-size: 0.58rem; letter-spacing: 0.05em; white-space: nowrap; overflow: hidden; }
    .stat-sub { font-size: 0.62rem; white-space: nowrap; overflow: hidden; }
    .bottom-panel { gap: 10px; justify-content: center; }
    .bottom-panel .btn { padding: 13px 18px; min-height: 46px; }
    .meta-group { margin-left: 0; justify-content: center; }
    .btn-sm { min-height: 40px; padding: 8px 14px; }   /* Shuffle / Today reachable by thumb */
    .debug-toggle { font-size: 0.9rem; }
    .debug-toggle input { width: 20px; height: 20px; }
    /* 44px minimum tap targets on the remaining small controls. */
    .preset-chip, .daily-step, .btn-quiet, .rw-diff-chip, .btn-back { min-height: 44px; }
    /* "Puzzle Date" label: visually hidden (context comes from the "Browse
       another day" group header), still announced to screen readers. */
    .daily-datebar .sr-date-label {
        position: absolute; width: 1px; height: 1px; overflow: hidden;
        clip: rect(0 0 0 0); white-space: nowrap;
    }
}

/* ---- Fullscreen ---------------------------------------------------------- */
/* In fullscreen it's a game, not a web page: drop the page header + legend and
   tighten spacing. The whole game is laid out as a viewport-tall flex column
   that is CENTERED vertically (so it isn't pinned to the top) and never scrolls.
   `is-fullscreen` is toggled from JS on fullscreenchange. */
body.is-fullscreen { overflow: hidden; }
body.is-fullscreen .app {
    display: flex;
    flex-direction: column;
    justify-content: center;     /* centre the stack — no more "pushed to the top" */
    height: 100vh;
    height: 100dvh;
    max-width: 100%;             /* use the full width the centred board may need */
    overflow: hidden;            /* hard requirement: fullscreen must not scroll */
    padding: 6px 12px;
    gap: 6px;
}
body.is-fullscreen .app-header,
body.is-fullscreen .legend { display: none; }
body.is-fullscreen .top-panel,
body.is-fullscreen .health-row,
body.is-fullscreen .bottom-panel,
body.is-fullscreen .scoreboard { margin: 0; flex: 0 0 auto; }
/* Compact telemetry so the field gets the reclaimed vertical room. */
body.is-fullscreen .stat { padding: 6px 10px; }
body.is-fullscreen .stat-value { font-size: 1.15rem; }
/* The board takes the leftover middle and centres itself there. */
body.is-fullscreen .field-wrap { flex: 1 1 auto; min-height: 0; align-items: center; }
/* Size the board by whichever axis is limiting so it always fits the leftover
   space without distorting the 5:3 mines or overflowing (which would scroll):
   height is capped at ~70dvh (room for telemetry + controls) AND at the height
   whose derived width (height*5/3) still fits 96vw. width follows from aspect. */
body.is-fullscreen:not(.is-portrait) .field {
    width: auto;
    height: min(70dvh, 96vw * 3 / 5);
    max-width: 96vw;
    max-height: 100%;
}
/* Portrait fullscreen: stand the board up and fit the leftover height the same
   way (width = height*3/5, kept within 96vw). */
body.is-fullscreen.is-portrait .field {
    width: auto;
    height: min(88dvh, 96vw * 5 / 3);
    max-width: 96vw;
    max-height: 100%;
}

/* ---- Portrait fit-to-viewport (phones) ----------------------------------
   Belt-and-suspenders for the standing board: lay the page out as a
   viewport-tall flex column so the board can be clamped to the space the page
   chrome leaves, rather than relying on the min(52vh, 150vw) guess alone. The
   board keeps that height but max-height:100% trims it to the flex wrap when
   the chrome is tall — and because width is auto, aspect-ratio recomputes the
   width from the clamped height, so the 3:5 box never distorts (unlike a
   max-WIDTH clamp, which would leave the height untouched and squish it). */
@media (max-width: 640px) {
    body.is-portrait .app {
        display: flex;
        flex-direction: column;
        min-height: 100vh;
        min-height: 100dvh;
    }
    body.is-portrait .field-wrap {
        flex: 1 1 auto;
        min-height: 0;           /* allow the board to shrink to the space available */
        align-items: center;     /* centre the standing board in the leftover height */
    }
    body.is-portrait .field {
        max-height: 100%;        /* never taller than the leftover; width follows */
    }
}

/* ===========================================================================
   Real-world GPS mode — setup wizard, lobby, safety gate, HUD
   Same Field Survey identity: dark panels, bone ink, caution-amber accent.
   =========================================================================== */

/* GPS accuracy stat in the telemetry row */
.stat-gps .stat-value { font-size: 1.2rem; color: var(--accent); }

/* Player marker once you've finished the crossing */
.player.finished { box-shadow: 0 0 0 3px var(--accent), 0 0 14px var(--accent); }

/* ---- Portrait-first GPS HUD ------------------------------------------- */
/* The beacon already shows the signal number, and lives don't apply to a
   real-world run (the server owns the outcome) — drop both cards so the
   field gets the room. */
body.gps-mode #signalStat,
body.gps-mode #livesStat { display: none; }
body.gps-mode .top-panel {
    grid-template-columns: repeat(3, 1fr);
    gap: 8px;
    margin-bottom: 10px;
}
body.gps-mode .stat { padding: 7px 10px; }
body.gps-mode .stat-value { font-size: 1.15rem; }
/* The beacon is a scaled disc (sized inline from JS); drop the drag knob. */
body.gps-mode #player { opacity: 0.86; border-width: 3px; }
body.gps-mode #player::after { display: none; }
/* While the full-screen beacon is up, the map/field underneath is hidden. */
body.beacon-view-on .field-wrap,
body.beacon-view-on .top-panel,
body.beacon-view-on .bottom-panel,
body.beacon-view-on .legend,
body.beacon-view-on .health-row { visibility: hidden; }

/* ---- Beacon / map view toggle ----------------------------------------- */
.gps-view-toggle {
    position: fixed;
    top: 54px;
    right: 12px;
    z-index: 1400;
    background: var(--panel);
    color: var(--ink);
    border: 1px solid var(--accent);
    border-radius: 999px;
    padding: 8px 16px;
    font-size: 0.85rem;
    font-weight: 600;
    cursor: pointer;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.4);
}
.gps-view-toggle[hidden] { display: none; }

/* ---- Full-screen Beacon view ------------------------------------------ */
.beacon-view {
    position: fixed;
    inset: 0;
    z-index: 1500;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    background: var(--bv-color, #3fbf6f);
    transition: background 0.25s ease;
    padding: 6vmin;
}
.beacon-view[hidden] { display: none; }
.bv-num {
    font-family: var(--font-mono);
    font-size: 48vmin;
    font-weight: 800;
    line-height: 0.9;
    color: #10130a;            /* overridden inline for levels 4–5 */
}
.bv-word {
    margin-top: 2vmin;
    font-size: 6vmin;
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: rgba(0, 0, 0, 0.62);
}
.bv-meta {
    margin-top: 3vmin;
    font-size: 3.6vmin;
    font-family: var(--font-mono);
    color: rgba(0, 0, 0, 0.55);
}
.bv-controls {
    position: absolute;
    left: 0; right: 0;
    bottom: 5vmin;
    display: flex;
    gap: 12px;
    justify-content: center;
}

/* "How to begin" prompt — sits over the field until the run is underway */
.gps-hint {
    position: absolute;
    left: 50%;
    bottom: 16px;
    transform: translateX(-50%);
    z-index: 30;
    width: min(92%, 440px);
    background: rgba(20, 24, 30, 0.94);
    border: 1px solid var(--accent);
    border-radius: 10px;
    padding: 12px 16px;
    text-align: center;
    box-shadow: 0 6px 24px rgba(0, 0, 0, 0.45);
}
.gps-hint[hidden] { display: none; }
.gps-hint-msg { margin: 0 0 4px; font-size: 0.95rem; font-weight: 600; color: var(--ink); }
.gps-hint-sub { margin: 0 0 10px; font-size: 0.78rem; color: var(--muted); font-family: var(--font-mono); }
.gps-hint .btn { margin: 0; }

/* ---- Real-World panel (in the Start overlay) --------------------------- */
.rw-panel {
    display: flex;
    flex-direction: column;
    gap: 16px;
    text-align: left;
    margin-top: 6px;
}
.rw-intro {
    margin: 0;
    color: var(--muted);
    font-size: 0.9rem;
    line-height: 1.5;
}
.rw-intro strong { color: var(--ink); }
.rw-sub {
    display: block;
    font-size: 0.72rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--muted);
    margin-bottom: 8px;
}
.rw-diff-chips { display: flex; gap: 8px; }
.rw-diff-chip {
    flex: 1 1 0;
    background: var(--panel-2);
    border: 1px solid var(--line);
    color: var(--ink);
    border-radius: 6px;
    padding: 8px 6px;
    font-size: 0.85rem;
    cursor: pointer;
}
.rw-diff-chip.is-active {
    border-color: var(--accent);
    color: var(--accent);
    box-shadow: inset 0 0 0 1px var(--accent);
}
.rw-mode-btns { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 8px; }
.rw-mode-btn {
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
    text-align: left;
    padding: 12px;
    height: auto;
    white-space: normal;
}
.rw-mode-name { font-weight: 700; font-size: 0.95rem; }
.rw-mode-desc { font-size: 0.72rem; color: var(--muted); }
.rw-join-row { display: flex; gap: 8px; }
.rw-code-input {
    flex: 1 1 auto;
    min-width: 0;      /* inputs have an intrinsic ~20ch min-width that would
                          otherwise push the Join button off narrow screens */
    background: var(--panel-2);
    border: 1px solid var(--line);
    color: var(--ink);
    border-radius: 6px;
    padding: 10px 12px;
    font-family: var(--font-mono);
    font-size: 1.1rem;
    letter-spacing: 0.22em;
    text-transform: uppercase;
}
.rw-join-msg { margin: 6px 0 0; font-size: 0.82rem; color: var(--accent); min-height: 1em; }

@media (max-width: 560px) {
    .rw-mode-btns { grid-template-columns: 1fr; }
}

/* ---- Shared modal backdrop for the GPS overlays ------------------------ */
.safety-backdrop,
.lobby-backdrop,
.mapwiz-backdrop {
    position: fixed;
    inset: 0;
    z-index: 4000;
    background: rgba(8, 10, 14, 0.82);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 18px;
}
.safety-backdrop[hidden],
.lobby-backdrop[hidden],
.mapwiz-backdrop[hidden] { display: none; }

.safety-card,
.lobby-card {
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: 12px;
    padding: 24px;
    max-width: 460px;
    width: 100%;
    max-height: 92vh;
    max-height: 92dvh;
    overflow: auto;
}
.safety-card h2,
.lobby-card h2 {
    margin: 0 0 14px;
    font-size: 1.2rem;
    letter-spacing: 0.03em;
    text-transform: uppercase;
}

/* ---- Safety gate ------------------------------------------------------- */
.safety-list { list-style: none; margin: 0 0 16px; padding: 0; display: flex; flex-direction: column; gap: 12px; }
.safety-list li { display: flex; gap: 12px; font-size: 0.9rem; line-height: 1.45; }
.safety-tag {
    flex: 0 0 64px;
    font-size: 0.68rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--accent);
    padding-top: 2px;
}
.safety-ack {
    display: flex;
    gap: 8px;
    align-items: center;
    font-size: 0.88rem;
    color: var(--muted);
    margin-bottom: 16px;
    cursor: pointer;
}
.safety-actions,
.lobby-actions { display: flex; gap: 10px; }

/* ---- Map-setup wizard --------------------------------------------------- */
.mapwiz {
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: 12px;
    width: 100%;
    max-width: 720px;
    height: 88vh;
    height: 88dvh;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}
.mapwiz-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 14px 18px;
    border-bottom: 1px solid var(--line);
}
.mapwiz-head h2 { margin: 0; font-size: 1.05rem; letter-spacing: 0.03em; text-transform: uppercase; }
.mapwiz-map { flex: 1 1 auto; min-height: 220px; background: #0B100A; }
.mapwiz-controls { padding: 14px 18px; border-top: 1px solid var(--line); display: flex; flex-direction: column; gap: 10px; }
.mapwiz-gpsline {
    font-family: var(--font-mono);
    font-size: 0.82rem;
    color: var(--muted);
}
.mapwiz-gpsline.is-locked { color: var(--accent); }
.mapwiz-sliders { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 12px; }
.mapwiz-sliders label {
    display: flex;
    flex-direction: column;
    gap: 4px;
    font-size: 0.72rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--muted);
}
.mapwiz-sliders output { color: var(--ink); font-family: var(--font-mono); font-size: 0.85rem; }
.mapwiz-hint { margin: 0; font-size: 0.78rem; color: var(--muted); }
.edge-key { font-weight: 600; }
.edge-key.edge-start { color: #34d17a; }
.edge-key.edge-end { color: #3aa0ff; }
.mapwiz-actions { display: flex; gap: 10px; justify-content: flex-end; }

@media (max-width: 560px) {
    .mapwiz-sliders { grid-template-columns: 1fr; gap: 8px; }
    .mapwiz { height: 92vh; height: 92dvh; }
}

/* ---- Lobby -------------------------------------------------------------- */
.lobby-mode { margin: -6px 0 14px; color: var(--accent); font-size: 0.85rem; letter-spacing: 0.06em; text-transform: uppercase; }
.lobby-code-wrap { text-align: center; margin-bottom: 18px; }
.lobby-code-label { display: block; font-size: 0.72rem; color: var(--muted); margin-bottom: 6px; }
.lobby-code {
    font-family: var(--font-mono);
    font-size: 2.2rem;
    font-weight: 700;
    letter-spacing: 0.3em;
    color: var(--accent);
    background: var(--panel-2);
    border: 1px dashed var(--line);
    border-radius: 8px;
    padding: 10px;
}
.lobby-code-actions { margin-top: 8px; }
.lobby-roster-wrap { margin-bottom: 14px; }
.lobby-roster-label { display: block; font-size: 0.72rem; letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted); margin-bottom: 8px; }
.lobby-roster { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.lobby-player {
    display: flex;
    justify-content: space-between;
    background: var(--panel-2);
    border: 1px solid var(--line);
    border-radius: 6px;
    padding: 8px 12px;
    font-size: 0.9rem;
}
.lobby-player.is-you { border-color: var(--accent); }
.lp-role { color: var(--muted); font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.05em; }
.lobby-status { font-size: 0.85rem; color: var(--muted); margin: 0 0 16px; }

/* Leaflet tiles can otherwise paint over our chrome; keep the map self-contained. */
.mapwiz-map .leaflet-container { width: 100%; height: 100%; background: #0B100A; }
body.mapwiz-open { overflow: hidden; }
