/* ─── UI palette (HUD + side gauges) ──────────────────────────────────
   Frame/border colors only — data text stays Matrix green.
   To revert to the blueprint blue look, swap the two blocks below.
*/
:root {
    /* Themes are applied via html[data-ui-theme] overrides below */

    /* Active: ash / charcoal */
    --ui-bg:          rgba(22, 22, 24, 0.66);
    --ui-border:      rgba(195, 195, 200, 0.42);
    --ui-border-dim:  rgba(150, 150, 155, 0.22);
    --ui-tint:        rgba(150, 150, 155, 0.10);
    --ui-label:       rgba(215, 215, 220, 0.62);
    --ui-label-dim:   rgba(215, 215, 220, 0.42);
    --ui-tick:        rgba(195, 195, 200, 0.38);
    --ui-tick-dim:    rgba(195, 195, 200, 0.20);
    --ui-dot:         rgba(230, 230, 232, 0.92);
    --ui-dot-glow:    rgba(200, 200, 205, 0.85);
    --ui-arc-fill:    rgba(225, 225, 230, 0.88);
    --ui-arc-track:   rgba(150, 150, 155, 0.16);
    --ui-arc-glow:    rgba(210, 210, 215, 0.60);
    --ui-arc-glow-hi: rgba(240, 240, 245, 0.88);
    --ui-pulse:       rgba(220, 220, 225, 0.55);
    --ui-pulse-hi:    rgba(240, 240, 245, 0.90);
    --ui-marker:      rgba(195, 195, 200, 0.28);
    --ui-marker-glow: rgba(195, 195, 200, 0.18);
}

html[data-ui-theme="void"] {
    --ui-bg:          rgba(4, 4, 4, 0.85);
    --ui-border:      rgba(255, 255, 255, 0.55);
    --ui-border-dim:  rgba(200, 200, 200, 0.22);
    --ui-tint:        rgba(255, 255, 255, 0.05);
    --ui-label:       rgba(255, 255, 255, 0.75);
    --ui-label-dim:   rgba(200, 200, 200, 0.48);
    --ui-tick:        rgba(255, 255, 255, 0.45);
    --ui-tick-dim:    rgba(255, 255, 255, 0.18);
    --ui-dot:         rgba(255, 255, 255, 0.96);
    --ui-dot-glow:    rgba(255, 255, 255, 0.75);
    --ui-arc-fill:    rgba(255, 255, 255, 0.92);
    --ui-arc-track:   rgba(180, 180, 180, 0.12);
    --ui-arc-glow:    rgba(255, 255, 255, 0.50);
    --ui-arc-glow-hi: rgba(255, 255, 255, 0.92);
    --ui-pulse:       rgba(255, 255, 255, 0.55);
    --ui-pulse-hi:    rgba(255, 255, 255, 0.96);
    --ui-marker:      rgba(255, 255, 255, 0.30);
    --ui-marker-glow: rgba(255, 255, 255, 0.16);
}

html[data-ui-theme="blue"] {
    --ui-bg:          rgba(8, 18, 36, 0.55);
    --ui-border:      rgba(140, 200, 255, 0.40);
    --ui-border-dim:  rgba(80, 170, 240, 0.22);
    --ui-tint:        rgba(80, 170, 240, 0.16);
    --ui-label:       rgba(170, 220, 255, 0.62);
    --ui-label-dim:   rgba(170, 220, 255, 0.45);
    --ui-tick:        rgba(140, 200, 255, 0.40);
    --ui-tick-dim:    rgba(140, 200, 255, 0.22);
    --ui-dot:         rgba(170, 220, 255, 0.85);
    --ui-dot-glow:    rgba(140, 200, 255, 0.85);
    --ui-arc-fill:    rgba(140, 200, 255, 0.85);
    --ui-arc-track:   rgba(80, 170, 240, 0.16);
    --ui-arc-glow:    rgba(140, 200, 255, 0.65);
    --ui-arc-glow-hi: rgba(170, 220, 255, 0.85);
    --ui-pulse:       rgba(140, 200, 255, 0.55);
    --ui-pulse-hi:    rgba(170, 220, 255, 0.90);
    --ui-marker:      rgba(140, 200, 255, 0.28);
    --ui-marker-glow: rgba(140, 200, 255, 0.18);
}

html[data-ui-theme="red"] {
    --ui-bg:          rgba(36, 6, 6, 0.66);
    --ui-border:      rgba(255, 80, 80, 0.42);
    --ui-border-dim:  rgba(200, 50, 50, 0.22);
    --ui-tint:        rgba(200, 50, 50, 0.10);
    --ui-label:       rgba(255, 170, 170, 0.62);
    --ui-label-dim:   rgba(255, 170, 170, 0.42);
    --ui-tick:        rgba(255, 80, 80, 0.38);
    --ui-tick-dim:    rgba(255, 80, 80, 0.20);
    --ui-dot:         rgba(255, 140, 140, 0.92);
    --ui-dot-glow:    rgba(255, 80, 80, 0.85);
    --ui-arc-fill:    rgba(255, 100, 100, 0.88);
    --ui-arc-track:   rgba(160, 40, 40, 0.16);
    --ui-arc-glow:    rgba(255, 80, 80, 0.60);
    --ui-arc-glow-hi: rgba(255, 170, 170, 0.88);
    --ui-pulse:       rgba(255, 100, 100, 0.55);
    --ui-pulse-hi:    rgba(255, 170, 170, 0.90);
    --ui-marker:      rgba(255, 80, 80, 0.28);
    --ui-marker-glow: rgba(255, 80, 80, 0.18);
}

html[data-ui-theme="teal"] {
    --ui-bg:          rgba(6, 28, 36, 0.72);
    --ui-border:      rgba(40, 212, 212, 0.42);
    --ui-border-dim:  rgba(40, 212, 212, 0.20);
    --ui-tint:        rgba(40, 212, 212, 0.08);
    --ui-label:       rgba(140, 240, 230, 0.65);
    --ui-label-dim:   rgba(140, 240, 230, 0.42);
    --ui-tick:        rgba(40, 212, 212, 0.38);
    --ui-tick-dim:    rgba(40, 212, 212, 0.20);
    --ui-dot:         rgba(80, 230, 220, 0.92);
    --ui-dot-glow:    rgba(40, 212, 212, 0.85);
    --ui-arc-fill:    rgba(40, 212, 212, 0.88);
    --ui-arc-track:   rgba(20, 100, 100, 0.18);
    --ui-arc-glow:    rgba(40, 212, 212, 0.60);
    --ui-arc-glow-hi: rgba(140, 240, 230, 0.88);
    --ui-pulse:       rgba(40, 212, 212, 0.55);
    --ui-pulse-hi:    rgba(140, 240, 230, 0.90);
    --ui-marker:      rgba(40, 212, 212, 0.28);
    --ui-marker-glow: rgba(40, 212, 212, 0.18);
}

html[data-layout="hidden"] .hud,
html[data-layout="hidden"] .panel-cluster,
html[data-layout="hidden"] .notify {
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.3s ease;
}

/* ── Header layout mode ─────────────────────────────────────────── */
.hud__item--extra { display: none; }
.hud__spacer      { display: none; }

html[data-layout="header"] .hud,
html[data-layout="hidden"] .hud {   /* HIDDEN keeps the SAME fixed-bar position, just opacity:0 —
                                       so HEADER→HIDDEN fades in place instead of the HUD jumping
                                       to the small STAGE header and flashing. */
    position: fixed;
    top: 0;
    bottom: auto;   /* cancel the STAGE-layout absolute `bottom` (was squishing the bar) */
    left: 0;
    right: 0;
    width: auto;
    max-width: none;
    padding: 16px 32px 6px;
    font-size: 20px;
    letter-spacing: 3px;
    justify-content: flex-start;
    gap: 28px;
    z-index: 1000;
}

html[data-layout="header"] .hud__item--extra {
    display: flex;
}

html[data-layout="header"] .hud__spacer {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    flex: 1;
}

#sys-status {
    display: none;
}

html[data-layout="header"] #sys-status {
    display: block;
    position: relative;
    padding-left: 16px;
    font-family: inherit;
    font-size: inherit;
    letter-spacing: inherit;
    white-space: nowrap;
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.55s ease;
    text-transform: uppercase;
}

html[data-layout="header"] #sys-status::before {
    content: '';
    position: absolute;
    left: 0;
    top: 50%;
    transform: translateY(-50%);
    width: 5px;
    height: 5px;
    background: var(--ui-dot);
    box-shadow: 0 0 6px var(--ui-dot-glow);
}

html[data-layout="header"] #sys-status.is-visible {
    opacity: 0.55;
    animation: ss-glow-pulse 4s ease-in-out infinite;
}

html[data-layout="header"] #sys-status.is-visible.is-glyph-blink {
    animation: ss-glow-pulse 4s ease-in-out infinite, ss-double-blink 2.8s ease-in-out infinite;
}

@keyframes ss-double-blink {
    0%, 6%    { opacity: 0.55; }
    11%       { opacity: 0.46; }
    16%, 20%  { opacity: 0.55; }
    25%       { opacity: 0.46; }
    30%, 100% { opacity: 0.55; }
}

@keyframes ss-glow-pulse {
    0%, 80%, 100% { filter: brightness(1); }
    82%           { filter: brightness(0.35); }
    83%           { filter: brightness(1.2); }
    84%           { filter: brightness(1); }
    93%           { filter: brightness(0.6); }
    94%           { filter: brightness(1); }
}

@keyframes ss-ambient-flicker {
    0%, 85%, 100% { opacity: 0.28; }
    87%           { opacity: 0.05; }
    88%           { opacity: 0.28; }
    92%           { opacity: 0.10; }
    93%           { opacity: 0.28; }
}

html[data-layout="header"] .panel-cluster {
    display: none;
}

html[data-layout="header"] .stage-row {
    grid-template-columns: 600px;
    grid-template-rows: 600px;
    gap: 0;
}

html[data-layout="header"] .stage-row .hud {
    /* removed from grid — position:fixed takes it out of flow */
    grid-area: unset;
}

html[data-layout="header"] .stage-row .stage-frame {
    grid-column: 1;
    grid-row: 1;
}

/* No top padding shift between HEADER and HIDDEN — the stage stays centred in both,
   so switching layouts doesn't jump the game up/down. The fixed header bar sits in the
   top margin above the centred stage. */

html {
    box-sizing: border-box;
    /* Fullscreen fixed-layout app — the page itself must never scroll. This kills the
       stray horizontal scroll (and the "crooked layout") that showed up after the boss
       outro when fixed elements briefly overflowed and the outro restored page overflow.
       (Level-select etc. scroll inside their own overlay, not the page — unaffected.) */
    overflow: hidden;
}

*,
*::before,
*::after {
    box-sizing: inherit;
}

/* First-visit anti-flash: set on <html> before first paint (head script) when the intro
   is about to play. Keeps the static game/backdrop hidden so it never flashes before the
   intro's canvas covers the screen. Body bg is black → clean black → intro. Removed in
   restoreIntroState() once the intro finishes. */
html.intro-pending .game,
html.intro-pending .backdrop {
    visibility: hidden !important;
}

.matrix-body {
    margin: 0;
    min-height: 100vh;
    background: #000;
    color: #00ff41;
    font-family: 'VT323', 'Share Tech Mono', monospace;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    position: relative;
}

.backdrop {
    position: fixed;
    top: 0;
    left: 0;
    z-index: 0;
    pointer-events: none;
    opacity: 0.85;
    will-change: transform;
}

.intro-root {
    position: fixed;
    inset: 0;
    z-index: 10000;
    background: transparent;  /* canvas paints its own opaque/transparent bg */
    overflow: hidden;
}

.intro-canvas {
    display: block;
    width: 100vw;
    height: 100vh;
    image-rendering: pixelated;
    image-rendering: crisp-edges;
}

.intro-skip {
    position: absolute;
    top: 16px;
    right: 18px;
    font-family: "Share Tech Mono", "VT323", monospace;
    font-size: 13px;
    letter-spacing: 3px;
    color: rgba(50, 50, 50, 0.6);
    pointer-events: none;
    user-select: none;
    mix-blend-mode: difference;
}

.rain {
    position: fixed;
    top: 0;
    left: 0;
    z-index: 1;
    pointer-events: none;
    opacity: 0.55;
    will-change: transform, opacity;
    transition: opacity 1800ms ease-out;
}

.rain.is-off {
    opacity: 0;
}

.game {
    position: relative;
    z-index: 2;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 16px;
    padding: 20px;
}

.hud {
    width: 600px;
    box-sizing: border-box;
    padding: 22px 32px 10px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    font-size: 28px;
    letter-spacing: 4px;
    text-shadow: 0 0 6px #00ff41, 0 0 12px #00b32d;
    position: relative;
    z-index: 10;
    background-color: var(--ui-bg);
    background-image:
        /* major ticks (taller) — every 32px */
        repeating-linear-gradient(90deg,
            var(--ui-tick) 0 1px,
            transparent 1px 32px),
        /* minor ticks — every 8px */
        repeating-linear-gradient(90deg,
            var(--ui-tick-dim) 0 1px,
            transparent 1px 8px);
    background-size: 320px 9px, 320px 5px;
    background-position: center 60%, center 60%;
    background-repeat: no-repeat, no-repeat;
    border: 1px solid var(--ui-border);
    backdrop-filter: blur(3px);
    -webkit-backdrop-filter: blur(3px);
}

/* Blueprint-style title strip across the top */
.hud::before {
    content: 'TELEMETRY · FIG.0';
    position: absolute;
    top: 3px;
    left: 3px;
    right: 3px;
    height: 14px;
    line-height: 14px;
    padding: 0 10px;
    box-sizing: border-box;
    background: var(--ui-tint);
    color: var(--ui-label);
    font-family: "Share Tech Mono", monospace;
    font-size: 10px;
    letter-spacing: 2px;
    text-shadow: none;
    pointer-events: none;
}

/* Inner border — second line like the blueprint cards (double-border) */
.hud::after {
    content: '';
    position: absolute;
    inset: 3px;
    border: 1px solid var(--ui-border-dim);
    pointer-events: none;
}

.hud__item {
    position: relative;
    padding-left: 16px;
}

/* Glowing indicator square next to each readout (like blueprint dots) */
.hud__item::before {
    content: '';
    position: absolute;
    left: 0;
    top: 50%;
    transform: translateY(-50%);
    width: 5px;
    height: 5px;
    background: var(--ui-dot);
    box-shadow: 0 0 6px var(--ui-dot-glow);
}

.hud__item span {
    color: #b6ffc8;
    margin-left: 8px;
}

/* Dynamic horizontal marker — slides opposite to snake direction */
.hud__marker {
    --marker-pct: 50;
    position: absolute;
    left: calc(var(--marker-pct) * 1%);
    transform: translateX(-50%);
    top: 22px;
    bottom: 8px;
    width: 1px;
    background: linear-gradient(
        to bottom,
        transparent 0%,
        var(--ui-marker) 30%,
        var(--ui-marker) 70%,
        transparent 100%
    );
    box-shadow: 0 0 4px var(--ui-marker-glow);
    pointer-events: none;
    z-index: 1;
}

/* Small triangle cap above the marker — like a needle pointer */
.hud__marker::before {
    content: '';
    position: absolute;
    top: 0;
    left: 50%;
    transform: translateX(-50%);
    width: 0;
    height: 0;
    border-left: 3px solid transparent;
    border-right: 3px solid transparent;
    border-top: 4px solid var(--ui-marker);
    opacity: 0.85;
}

/* ─── Stage row: grid (hud · stage-frame), gauges float to the left ──────────
   Single 600px column so the STAGE is centred in the viewport. The left gauge
   panel is absolutely positioned to the LEFT of the stage, out of flow, so it
   never shifts the stage off-centre (was `auto 600px` → whole group centred). */
.stage-row {
    position: relative;
    display: grid;
    grid-template-columns: 600px;
    grid-template-rows: 600px;   /* stage only — HUD/gauges float, so the STAGE alone is
                                    what gets centred, both horizontally and vertically. */
    justify-content: center;
    align-content: center;
}

.stage-row .stage-frame { grid-column: 1; grid-row: 1; }
.stage-row .hud {
    position: absolute;
    bottom: calc(100% + 16px);  /* just above the stage (out of flow → no vertical shift) */
    left: 0; right: 0;
}
.panel-cluster--left {
    position: absolute;
    right: calc(100% + 16px);   /* just left of the stage */
    top: 0; bottom: 0;          /* span the stage's height, gauges top-aligned */
}

.panel-cluster {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: clamp(6px, 1.2vh, 14px);
    flex-shrink: 0;
    z-index: 10;
}

/* ─── Gauge panel (round, blueprint card style — matches HUD) ──────── */
.gauge {
    --gauge-pct: 0;
    --gauge-fill: var(--ui-arc-fill);
    --gauge-track: var(--ui-arc-track);
    position: relative;
    width:  clamp(88px, 11vh, 108px);
    height: clamp(88px, 11vh, 108px);
    border-radius: 50%;
    background-color: var(--ui-bg);
    border: 1px solid var(--ui-border);
    backdrop-filter: blur(3px);
    -webkit-backdrop-filter: blur(3px);
    overflow: hidden;
    transition: box-shadow 320ms ease-out, border-color 320ms ease-out;
}

/* Inner double-line border (matches .hud::after) */
.gauge::after {
    content: '';
    position: absolute;
    inset: 3px;
    border: 1px solid var(--ui-border-dim);
    border-radius: 50%;
    pointer-events: none;
}

/* Outer arc (speed gauge — fills via --gauge-pct) */
.gauge__ring {
    position: absolute;
    inset: 0;
    border-radius: 50%;
    background:
        conic-gradient(
            from -90deg,
            var(--gauge-fill) 0deg,
            var(--gauge-fill) calc(var(--gauge-pct) * 3.6deg),
            var(--gauge-track) calc(var(--gauge-pct) * 3.6deg),
            var(--gauge-track) 360deg
        );
    -webkit-mask: radial-gradient(circle at center, transparent 60%, #000 64%, #000 76%, transparent 80%);
            mask: radial-gradient(circle at center, transparent 60%, #000 64%, #000 76%, transparent 80%);
    filter:
        drop-shadow(0 0 5px var(--ui-arc-glow))
        drop-shadow(0 0 2px var(--ui-arc-glow-hi));
    transition: background 320ms ease-out;
    pointer-events: none;
    animation: arc-breathe 2.6s ease-in-out infinite;
}

@keyframes arc-breathe {
    0%, 100% {
        opacity: 0.85;
        filter:
            drop-shadow(0 0 5px var(--ui-arc-glow))
            drop-shadow(0 0 2px var(--ui-arc-glow-hi));
    }
    50% {
        opacity: 1.00;
        filter:
            drop-shadow(0 0 9px var(--ui-arc-glow-hi))
            drop-shadow(0 0 3px var(--ui-arc-glow-hi));
    }
}

/* Ring flash when tier increases — overrides breathe briefly */
.gauge.is-pulse .gauge__ring {
    animation: arc-flash 480ms ease-out, arc-breathe 2.6s ease-in-out 480ms infinite;
}

@keyframes arc-flash {
    0% {
        opacity: 1;
        filter:
            drop-shadow(0 0 14px var(--ui-pulse-hi))
            drop-shadow(0 0 6px var(--ui-pulse-hi));
    }
    100% {
        opacity: 0.85;
        filter:
            drop-shadow(0 0 5px var(--ui-arc-glow))
            drop-shadow(0 0 2px var(--ui-arc-glow-hi));
    }
}

.gauge__inner {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding: 0 8px;
    pointer-events: none;
}

.gauge__label {
    font-family: "Share Tech Mono", monospace;
    font-size: 9px;
    letter-spacing: 2px;
    color: var(--ui-label);
    text-shadow: none;
    margin-bottom: 1px;
}

.gauge__value {
    font-family: 'VT323', 'Share Tech Mono', monospace;
    font-size: 28px;
    line-height: 1;
    color: #b6ffc8;
    text-shadow: 0 0 6px #00ff41, 0 0 12px rgba(0, 179, 45, 0.45);
    letter-spacing: 1px;
    display: flex;
    align-items: baseline;
    gap: 1px;
}

.gauge__value--wide {
    font-size: 18px;
    letter-spacing: 0.5px;
}

.gauge__unit {
    font-family: "Share Tech Mono", monospace;
    font-size: 9px;
    letter-spacing: 1px;
    color: var(--ui-label);
    text-shadow: none;
}

.gauge__sub {
    font-family: "Share Tech Mono", monospace;
    font-size: 8px;
    letter-spacing: 1.5px;
    color: var(--ui-label-dim);
    text-shadow: none;
    margin-top: 3px;
}

/* Glowing indicator dot at top of each panel (matches .hud__item::before) */
.gauge__dot {
    position: absolute;
    top: 8px;
    left: 50%;
    transform: translateX(-50%);
    width: 5px;
    height: 5px;
    background: var(--ui-dot);
    box-shadow: 0 0 6px var(--ui-dot-glow);
    pointer-events: none;
}

/* Pulse on value update */
.gauge.is-pulse {
    animation: gauge-pulse 480ms ease-out;
}

@keyframes gauge-pulse {
    0%   { box-shadow: 0 0 0 transparent;                border-color: var(--ui-border); }
    35%  { box-shadow: 0 0 14px var(--ui-pulse);         border-color: var(--ui-pulse-hi); }
    100% { box-shadow: 0 0 0 transparent;                border-color: var(--ui-border); }
}

.stage-frame {
    position: relative;
    width: 600px;
    height: 600px;
    will-change: transform;
}

.boss-hp-bar {
    position: absolute;
    bottom: -46px;
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 5px;
    white-space: nowrap;
    width: 560px;
    transition: opacity 0.45s ease;
}
.boss-hp-bar.is-hidden { opacity: 0; pointer-events: none; }
.boss-hp-bar__label {
    font-family: "VT323", monospace;
    font-size: 14px;
    color: #ff6680;
    letter-spacing: 2px;
    text-align: center;
}
.boss-hp-bar__track {
    width: 100%;
    height: 10px;
    background: #1a0505;
    border: 1px solid #ff2a4a;
    box-shadow: 0 0 6px rgba(255, 42, 74, 0.5);
}
.boss-hp-bar__fill {
    height: 100%;
    width: 100%;
    background: linear-gradient(90deg, #ff2a4a, #cc1133, #ff6688);
    transition: width 0.15s linear;
}

.stage {
    position: relative;
    width: 600px;
    height: 600px;
    border: 1px solid #00ff41;
    box-shadow:
        0 0 12px #00ff41,
        0 0 32px rgba(0, 255, 65, 0.35),
        inset 0 0 24px rgba(0, 255, 65, 0.15);
    background: #000;
    overflow: hidden;
    transition:
        transform 360ms cubic-bezier(0.2, 0.8, 0.2, 1),
        border-radius 360ms cubic-bezier(0.2, 0.8, 0.2, 1),
        box-shadow 360ms ease-out;
}

.stage::before {
    content: '';
    position: absolute;
    inset: -2px;
    pointer-events: none;
    z-index: 3;
    background:
        radial-gradient(
            circle at 24% 20%,
            rgba(255, 255, 255, 0.18) 0%,
            rgba(255, 255, 255, 0.04) 16%,
            transparent 36%
        ),
        radial-gradient(
            circle at center,
            transparent 45%,
            rgba(0, 60, 30, 0.22) 80%,
            rgba(0, 0, 0, 0.4) 100%
        );
    opacity: 0;
    transition: opacity 380ms ease-out;
}

.stage::after {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    z-index: 4;
    box-shadow:
        inset 0 0 50px 8px rgba(0, 0, 0, 0.4),
        inset 0 0 120px 30px rgba(0, 30, 15, 0.25);
    border-radius: inherit;
    opacity: 0;
    transition: opacity 380ms ease-out, box-shadow 380ms ease-out;
}

#game {
    display: block;
    width: 100%;
    height: 100%;
    image-rendering: pixelated;
    image-rendering: crisp-edges;
    transition: filter 320ms ease-out, transform 360ms cubic-bezier(0.2, 0.8, 0.2, 1);
    transform-origin: center;
}

.stage.is-bullet-time {
    transform: scale(1.02);
    border-radius: 5%;
    box-shadow:
        0 0 28px #00ff41,
        0 0 90px rgba(0, 255, 65, 0.55),
        inset 0 0 80px rgba(0, 255, 65, 0.18);
}

.stage.is-bullet-time::before {
    opacity: 1;
    animation: bt-breathe 1.8s ease-in-out infinite alternate;
}

.stage.is-bullet-time::after {
    opacity: 1;
}

.stage.is-bullet-time #game {
    filter:
        saturate(1.55)
        brightness(1.06)
        contrast(1.12)
        hue-rotate(-4deg);
    transform: scale(1);
}

.stage.is-bullet-time-burst #game {
    animation: bt-burst 600ms cubic-bezier(0.2, 0.8, 0.2, 1);
}

.stage.is-bullet-time-burst {
    animation: bt-stage-burst 600ms cubic-bezier(0.2, 0.8, 0.2, 1);
}

@keyframes bt-burst {
    0% {
        filter: saturate(3) brightness(1.6) contrast(1.4) hue-rotate(-12deg);
        transform: scale(1.08);
    }
    100% {
        filter: saturate(1.55) brightness(1.06) contrast(1.12) hue-rotate(-4deg);
        transform: scale(1);
    }
}

@keyframes bt-stage-burst {
    0% {
        border-radius: 0;
        transform: scale(0.97);
    }
    50% {
        border-radius: 50%;
        transform: scale(1.06);
    }
    100% {
        border-radius: 5%;
        transform: scale(1.02);
    }
}

.stage.is-bullet-time-exit {
    animation: bt-stage-exit 520ms cubic-bezier(0.2, 0.8, 0.2, 1);
}

@keyframes bt-stage-exit {
    0% {
        border-radius: 5%;
        transform: scale(1.02);
    }
    45% {
        border-radius: 50%;
        transform: scale(1.05);
    }
    100% {
        border-radius: 0;
        transform: scale(1);
    }
}

@keyframes bt-breathe {
    from { opacity: 0.88; }
    to { opacity: 1; }
}

.matrix-body.is-bullet-time .rain {
    opacity: 0.78;
    filter: saturate(1.4) brightness(1.1);
    transition: opacity 320ms ease-out, filter 320ms ease-out;
}

.overlay {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    /* `safe center` → centred when it fits, but falls back to top-start (no clipped,
       unreachable top) when the content is taller than the stage, so it can scroll. */
    justify-content: safe center;
    gap: 14px;
    padding: 16px 10px;
    overflow-y: auto;
    background: rgba(0, 0, 0, 0.65);
    backdrop-filter: blur(2px);
    text-align: center;
    transition: opacity 0.25s ease;
}

.overlay.is-hidden {
    opacity: 0;
    pointer-events: none;
}

.overlay__title {
    font-size: 56px;
    letter-spacing: 10px;
    padding-left: 10px;
    text-shadow: 0 0 8px #00ff41, 0 0 24px #00b32d;
    animation: title-glow 4.5s ease-in-out infinite;
}

.overlay__hint {
    font-size: 22px;
    letter-spacing: 4px;
    padding-left: 4px;
    color: #6fff95;
    text-shadow: 0 0 6px #00ff41;
}

.overlay__hint--small {
    font-size: 16px;
    color: #3fb463;
    letter-spacing: 3px;
    padding-left: 3px;
}

/* Breathing hint (e.g. "PRESS SPACE FOR NEXT LEVEL") */
.overlay__hint.is-breathing {
    animation: hint-breathe 1.8s ease-in-out infinite;
}

@keyframes hint-breathe {
    0%, 100% { opacity: 0.35; }
    50%      { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
    .overlay__hint.is-breathing { animation: none; opacity: 0.8; }
}

.overlay__btn {
    margin-top: 18px;
    background: transparent;
    border: 1px solid #00ff41;
    color: #6fff95;
    font-family: inherit;
    font-size: 18px;
    letter-spacing: 4px;
    padding: 8px 22px;
    cursor: pointer;
    text-shadow: 0 0 6px #00ff41;
    box-shadow: 0 0 8px rgba(0, 255, 65, 0.25);
    transition: color 160ms ease, box-shadow 160ms ease, background 160ms ease, transform 120ms ease;
}

.overlay__buttons {
    display: flex;
    flex-direction: column;
    gap: 10px;
    margin-top: 22px;
    align-items: center;
}

.overlay__buttons .overlay__btn {
    margin-top: 0;
    min-width: 260px;
    text-align: center;
}

.overlay__btn:hover {
    color: #b6ffc8;
    background: rgba(0, 255, 65, 0.08);
    box-shadow: 0 0 14px rgba(0, 255, 65, 0.5);
}

.overlay__btn:active {
    transform: scale(0.97);
}

.overlay__btn:focus-visible {
    outline: none;
    color: #b6ffc8;
    box-shadow: 0 0 14px rgba(0, 255, 65, 0.5);
    border-color: #00ff41;
}

/* ── Password-crack reveal (level-clear popup) ────────────────────────── */
/* Password shown as collected cubes — one cell per fragment you picked up. */
.pw-cells {
    display: flex;
    flex-wrap: nowrap;
    justify-content: center;
    gap: 6px;
    margin-top: 10px;
    max-width: 560px;
}

.pw-cell {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    font-family: inherit;
    font-size: 18px;
    border: 1px solid rgba(0, 255, 65, 0.35);
    background: rgba(0, 255, 65, 0.05);
    color: #3fb463;
    border-radius: 3px;
    text-shadow: 0 0 4px #00ff41;
    transition: transform 120ms ease, box-shadow 160ms ease, background 160ms ease;
}

/* Locked-in cube — matches the bright green breathing food cube. */
.pw-cell.is-got {
    border-color: #00ff41;
    background: rgba(0, 255, 65, 0.2);
    color: #b6ffc8;
    text-shadow: 0 0 8px #00ff41;
    box-shadow: 0 0 14px rgba(0, 255, 65, 0.55);
    transform: scale(1.08);
}

/* Solid collected cube — start state before it flips open into its symbol. */
.pw-cell.is-full {
    color: transparent;
    background: #00ff41;
    border-color: #00ff41;
    box-shadow: 0 0 16px rgba(0, 255, 65, 0.6);
}

.pw-cell.flip-y { animation: pw-flip 300ms ease; }

@keyframes pw-flip {
    0%   { transform: rotateY(0); }
    50%  { transform: rotateY(90deg); }
    100% { transform: rotateY(0); }
}

/* ── Custom padlock icon (locked level tiles) ─────────────────────────── */
.lock-ico {
    display: block;
    width: 20px;
    height: 20px;
}

/* Number span carries letter-spacing/padding for digits — neutralize it for the
   lock glyph so the icon sits dead-center in the tile. */
.level-tile.is-locked .level-tile__num {
    letter-spacing: 0;
    padding-left: 0;
    display: flex;
    justify-content: center;
}

.lock-ico rect,
.lock-ico path {
    fill: none;
    stroke: currentColor;
    stroke-width: 2;
}

.lock-ico circle {
    fill: currentColor;
    stroke: none;
}

/* ── Level-select grid (main menu) ────────────────────────────────────────
   Cards match the header chrome: dark translucent panel + hairline frame,
   monochrome per theme (uses the same --ui-* tokens the HUD uses). */
.level-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 14px;
    margin-top: 10px;
    max-width: 400px;
}

.level-tile {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 5px;
    width: 84px;
    height: 70px;
    padding-top: 3px;
    background:
        linear-gradient(180deg, rgba(255, 255, 255, 0.04), transparent 42%),
        var(--ui-bg);
    border: 1px solid var(--ui-border-dim);
    border-radius: 4px;
    color: var(--ui-label);
    font-family: inherit;
    cursor: pointer;
    overflow: hidden;
    transition: border-color 160ms ease, box-shadow 160ms ease, background 160ms ease, transform 120ms ease;
}

/* thin top accent rule — theme-coloured, faint until hovered/current */
.level-tile::before {
    content: '';
    position: absolute;
    top: 0; left: 10%; right: 10%;
    height: 1px;
    background: linear-gradient(90deg, transparent, var(--ui-border), transparent);
    opacity: 0.45;
    transition: opacity 160ms ease, left 160ms ease, right 160ms ease;
}

/* inner hairline frame — the extra bit of detail */
.level-tile::after {
    content: '';
    position: absolute;
    inset: 4px;
    border: 1px solid var(--ui-tick-dim);
    border-radius: 2px;
    pointer-events: none;
    transition: border-color 160ms ease;
}

.level-tile__num {
    font-size: 21px;
    letter-spacing: 3px;
    padding-left: 3px;
    color: var(--ui-dot);
    font-variant-numeric: tabular-nums;
}

.level-tile__act {
    font-size: 9px;
    letter-spacing: 2.5px;
    color: var(--ui-label-dim);
}

.level-tile:hover {
    border-color: var(--ui-border);
    background:
        linear-gradient(180deg, rgba(255, 255, 255, 0.07), transparent 42%),
        var(--ui-tint), var(--ui-bg);
    /* No translateY here: lifting the tile moved it out from under the cursor at the
       bottom edge → hover toggled on/off rapidly (flicker). The drop shadow below
       already reads as "lifted"; the hit box now stays put. */
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.45), inset 0 0 22px rgba(255, 255, 255, 0.03);
}
.level-tile:hover::before { opacity: 1; left: 0; right: 0; }
.level-tile:hover::after  { border-color: var(--ui-tick); }
.level-tile:hover .level-tile__num  { color: #fff; }
.level-tile:hover .level-tile__act  { color: var(--ui-label); }

.level-tile:active {
    transform: translateY(-1px) scale(0.97);
}

.level-tile:focus-visible {
    outline: none;
    border-color: var(--ui-border);
    box-shadow: 0 0 0 1px var(--ui-border), 0 6px 18px rgba(0, 0, 0, 0.45);
}

/* current level — filled + accent rule lit */
.level-tile.is-current {
    border-color: var(--ui-border);
    /* keep the same translucent bg as other tiles (circuit texture shows through) —
       just a touch more top-sheen; the highlight comes from the border/accent/number.
       (A colour in a non-final background layer is invalid and rendered opaque black.) */
    background:
        linear-gradient(180deg, rgba(255, 255, 255, 0.09), transparent 45%),
        var(--ui-bg);
}
.level-tile.is-current::before { opacity: 1; left: 0; right: 0; }
.level-tile.is-current::after  { border-color: var(--ui-tick); }
.level-tile.is-current .level-tile__num { color: #fff; }

/* locked — dim, greyed, no lift */
.level-tile.is-locked {
    border-color: var(--ui-border-dim);
    color: var(--ui-label-dim);
    background: rgba(8, 8, 10, 0.5);
    cursor: not-allowed;
    opacity: 0.55;
}
.level-tile.is-locked::before { opacity: 0.2; }
.level-tile.is-locked .level-tile__num { color: var(--ui-label-dim); }
.level-tile.is-locked:hover {
    transform: none;
    box-shadow: none;
    border-color: var(--ui-border-dim);
    background: rgba(8, 8, 10, 0.5);
}
.level-tile.is-locked:hover::before { opacity: 0.2; left: 10%; right: 10%; }
.level-tile.is-locked:hover::after  { border-color: var(--ui-tick-dim); }

.settings:focus {
    outline: none;
}

.settings {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;
    gap: 18px;
    padding: 24px 0;
    overflow-y: auto;
    background: rgba(0, 0, 0, 0.78);
    backdrop-filter: blur(3px);
    text-align: center;
    z-index: 5;
    transition: opacity 0.25s ease;
    scrollbar-width: thin;
    scrollbar-color: #1f7a3a transparent;
}

.settings.is-hidden {
    opacity: 0;
    pointer-events: none;
}

.settings__title {
    font-size: 40px;
    letter-spacing: 10px;
    color: #00ff41;
    text-shadow: 0 0 8px #00ff41, 0 0 22px #00b32d;
    margin-bottom: 8px;
}

.settings__group {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
}

.settings__label {
    font-size: 18px;
    letter-spacing: 5px;
    color: #6fff95;
    text-shadow: 0 0 4px #00ff41;
}

.settings__options {
    display: flex;
    flex-direction: column;
    gap: 10px;
    width: 320px;
}

.settings__option {
    background: rgba(0, 30, 12, 0.5);
    border: 1px solid #1f7a3a;
    color: #6fff95;
    font-family: inherit;
    padding: 12px 18px;
    cursor: pointer;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    text-shadow: 0 0 4px rgba(0, 255, 65, 0.5);
    transition: background 140ms ease, border-color 140ms ease, color 140ms ease, transform 120ms ease, box-shadow 140ms ease;
}

.settings__option:hover {
    border-color: #00ff41;
    color: #b6ffc8;
    background: rgba(0, 60, 25, 0.55);
    box-shadow: 0 0 10px rgba(0, 255, 65, 0.3);
}

.settings__option.is-active {
    border-color: #00ff41;
    background: rgba(0, 90, 35, 0.55);
    color: #b6ffc8;
    box-shadow: 0 0 14px rgba(0, 255, 65, 0.5), inset 0 0 12px rgba(0, 255, 65, 0.2);
}

.settings__option:active {
    transform: scale(0.98);
}

/* Disabled option (e.g. TRACKING camera on mobile/compact — always static there). */
.settings__option.is-disabled {
    opacity: 0.4;
    filter: grayscale(0.6);
    cursor: not-allowed;
    pointer-events: none;
}

.settings__option:focus-visible {
    outline: none;
    border-color: #00ff41;
    box-shadow: 0 0 10px rgba(0, 255, 65, 0.3), inset 0 0 0 1px rgba(0, 255, 65, 0.2);
}

.settings__option-name {
    font-size: 22px;
    letter-spacing: 6px;
}

.settings__option-desc {
    font-size: 13px;
    letter-spacing: 3px;
    color: #3fb463;
}


.settings__back {
    margin-top: 14px;
    background: transparent;
    border: 1px solid #1f7a3a;
    color: #6fff95;
    font-family: inherit;
    font-size: 18px;
    letter-spacing: 4px;
    padding: 8px 22px;
    cursor: pointer;
    text-shadow: 0 0 6px #00ff41;
    transition: color 160ms ease, background 160ms ease, border-color 160ms ease, transform 120ms ease;
}

.settings__back:hover {
    color: #b6ffc8;
    background: rgba(0, 255, 65, 0.08);
    border-color: #00ff41;
}

.settings__back:active {
    transform: scale(0.97);
}

.settings__back:focus-visible {
    outline: none;
    border-color: #00ff41;
    box-shadow: 0 0 10px rgba(0, 255, 65, 0.3);
}

.notify {
    position: absolute;
    top: 16px;
    left: 0;
    right: 0;
    display: flex;
    justify-content: center;
    pointer-events: none;
    z-index: 2;
}

.notify__msg {
    font-size: 24px;
    letter-spacing: 4px;
    padding: 8px 18px;
    background: rgba(0, 0, 0, 0.55);
    border: 1px solid currentColor;
    text-shadow:
        2px 0 0 rgba(255, 0, 64, 0.7),
        -2px 0 0 rgba(0, 255, 255, 0.7),
        0 0 8px currentColor;
    animation: notify-in 180ms ease-out, notify-jitter 90ms steps(2) infinite;
}

.notify__msg.is-out {
    animation: notify-out 220ms ease-in forwards;
}

.notify__msg--warn { color: #ffe14a; }
.notify__msg--danger { color: #ff4a6b; }
.notify__msg--pickup { color: #5cf0ff; }
.notify__msg--info { color: #00ff41; }

@keyframes notify-in {
    from { opacity: 0; transform: translateY(-8px); }
    to { opacity: 1; transform: translateY(0); }
}

@keyframes notify-out {
    from { opacity: 1; }
    to { opacity: 0; transform: translateY(-4px); }
}

@keyframes notify-jitter {
    0% { transform: translate(0, 0); }
    50% { transform: translate(1px, 0); }
    100% { transform: translate(-1px, 0); }
}

/* Smooth neon breathing — the ambient glow ebbs in and out. */
@keyframes title-glow {
    0%, 100% { text-shadow: 0 0 8px #00ff41, 0 0 24px #00b32d; }
    50%      { text-shadow: 0 0 15px #00ff41, 0 0 34px #00b32d, 0 0 62px rgba(0, 255, 65, 0.45); }
}

@media (prefers-reduced-motion: reduce) {
    .overlay__title { animation: none; }
}

/* ── Mobile / tablet controls — hidden for now (added in a later step) ── */
.touch-controls { display: none; }

/* ── Compact layout (mobile / tablet / narrow) — body.is-compact set by JS ─── */
/* Board: a fixed block, position + scale computed by fitGame(). Works for both
   the header and hidden layouts. */
body.is-compact .stage-frame {
    position: fixed;
    top: 0;
    left: 0;
    transform-origin: 0 0;
    z-index: 5;
}
/* Canvas is scaled down (non-integer) on mobile — smooth rendering keeps thin 1px
   wall outlines from dropping out under nearest-neighbour scaling. */
body.is-compact #game {
    image-rendering: auto;
    image-rendering: smooth;
}
body.is-compact .panel-cluster { display: none; }

/* Boss HP bar: on compact the board is a fixed, scaled block, but this bar is a
   sibling of .stage-frame (not scaled), so its default absolute position detaches
   from the board. fitGame() sets top/left/width so it sits flush under the scaled
   board — centred, board-width, small gap. Also trimmed a touch for phones. */
body.is-compact .boss-hp-bar {
    position: fixed;
    left: 0;
    bottom: auto;          /* fitGame() sets top instead (just below the board) */
    transform: none;
    width: auto;           /* fitGame() sets width = board width */
    gap: 2px;
    margin: 0;
    z-index: 6;
}
/* Small + compact so it fits the gap under the board without touching the D-pad. */
body.is-compact .boss-hp-bar__label { font-size: 10px; letter-spacing: 1.5px; }
body.is-compact .boss-hp-bar__track { height: 5px; }

/* Website-style fixed header bar at the very top (header layout only). */
html[data-layout="header"] body.is-compact .hud {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    width: auto;
    margin: 0;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
    gap: 4px 16px;
    padding: 8px 12px;
    font-size: 15px;
    letter-spacing: 2px;
    background-image: none;   /* drop ruler ticks — clash with wrapped text */
    z-index: 1000;
}
html[data-layout="header"] body.is-compact .hud__spacer { display: none; }
html[data-layout="header"] body.is-compact .hud::before,
html[data-layout="header"] body.is-compact .hud::after { display: none; }

/* Phone width: trim to LVL · KEYS · SCORE so the bar stays one line (tablets keep all). */
@media (max-width: 600px) {
    html[data-layout="header"] body.is-compact .hud__item:has(#hdr-speed),
    html[data-layout="header"] body.is-compact .hud__item:has(#hdr-att),
    html[data-layout="header"] body.is-compact .hud__item:has(#hdr-time),
    html[data-layout="header"] body.is-compact .hud__item:has(#best) {
        display: none;
    }
}

/* Mobile level-select: single-column list of big, wide, tappable rows.
   The whole overlay scrolls (reliable inside the scaled stage). */
body.is-compact .overlay {
    justify-content: flex-start;
    gap: 12px;
    padding: 26px 0 44px;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    touch-action: pan-y;
}
body.is-compact .overlay__title { font-size: 34px; letter-spacing: 5px; }
body.is-compact .level-grid {
    grid-template-columns: 1fr;
    width: 90%;
    max-width: 420px;
    gap: 12px;
}
body.is-compact .level-tile {
    flex-direction: row;
    /* number pinned left, label pinned right — so numbers line up in a column
       regardless of label width (BOSS vs ACT I/II/III). */
    justify-content: space-between;
    gap: 14px;
    width: 100%;
    height: 66px;          /* big comfortable tap target (scaled down on mobile) */
    padding: 0 22px;
}
body.is-compact .level-tile__num {
    font-size: 25px;
    padding-left: 0;
    letter-spacing: 1px;
    min-width: 2.2em;      /* fixed slot keeps every number at the same x */
    text-align: left;
}
body.is-compact .level-tile__act { font-size: 14px; }
body.is-compact .lock-ico { width: 22px; height: 22px; }

/* Bigger, more tappable menu / pop-up controls on compact (mobile + tablet).
   These live inside the scaled .stage-frame, so sizes are generous so they land
   near ~44px on-screen after the mobile downscale (s ≈ 0.55–0.70 on phones). */
body.is-compact .overlay__btn {
    font-size: 26px;
    letter-spacing: 4px;
    padding: 16px 30px;
}
body.is-compact .overlay__buttons {
    gap: 14px;
    margin-top: 24px;
}
body.is-compact .overlay__buttons .overlay__btn {
    min-width: 340px;
}
body.is-compact .overlay__hint { font-size: 24px; }
body.is-compact .overlay__hint--small { font-size: 17px; }

body.is-compact .settings__title { font-size: 34px; }
body.is-compact .settings__label { font-size: 20px; }
body.is-compact .settings__options { width: 400px; }
body.is-compact .settings__option { padding: 16px 22px; }
body.is-compact .settings__option-name { font-size: 26px; }
body.is-compact .settings__option-desc { font-size: 15px; }
body.is-compact .settings__back {
    font-size: 24px;
    padding: 15px 30px;
    margin-top: 18px;
}

@media (max-width: 480px) {
    html[data-layout="header"] body.is-compact .hud {
        font-size: 13px;
        gap: 3px 12px;
        letter-spacing: 1px;
    }
}

.touch-controls { display: contents; }

/* Hidden by default — higher specificity than .tc-btn{display:flex} so it actually wins. */
.touch-controls .tc-btn, .tc-dpad { display: none; }

/* PAUSE — rounded-rectangle button, top-right corner, only while playing.
   Scoped to .touch-controls so it outranks .tc-btn{position:relative}. */
/* House/home icon — header green + glow */
.tc-ico {
    width: 24px;
    height: 24px;
    display: block;
    filter: drop-shadow(0 0 4px rgba(0, 255, 65, 0.6));
}
.tc-ico path {
    fill: none;
    stroke: #b6ffc8;
    stroke-width: 2;
    stroke-linejoin: round;
    stroke-linecap: round;
}

/* MENU / PAUSE — compact icon button in the top-right corner of the header (adaptive).
   Replaces the old full-gap "TAP FOR MENU" tap zone, which barely fit on small screens. */
.touch-controls .tc-pause {
    position: fixed;
    top: 0;                       /* aligned with the fixed header (also top:0) */
    right: calc(env(safe-area-inset-right, 0px) + 12px);
    left: auto;
    width: 40px;
    height: 40px;                 /* ≈ header height → icon centres on the header row */
    box-sizing: border-box;
    padding: 0;
    /* Bare hamburger — no button box (border/bg/shadow removed). */
    border: none;
    border-radius: 0;
    background: transparent;
    box-shadow: none;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    align-items: center;
    justify-content: center;
    z-index: 2100;
}
.touch-controls .tc-pause::after { display: none; }   /* kill the inner button frame */
.touch-controls .tc-pause:active .tc-ico { opacity: 0.5; }   /* press feedback on the lines */
body.is-touch.is-playing .tc-pause { display: flex; }

/* Slightly bigger tap target + icon on tablets, matching the larger D-pad. */
@media (pointer: coarse) and (min-width: 700px) and (min-height: 700px) {
    .touch-controls .tc-pause { width: 48px; height: 48px; }
    .touch-controls .tc-pause .tc-ico { width: 30px; height: 30px; }
}

/* D-pad — big arrow cross, centred under the board, only while playing */
.tc-dpad {
    position: fixed;
    left: 50%;
    bottom: calc(16px + env(safe-area-inset-bottom, 0px));
    transform: translateX(-50%);
    grid-template-columns: repeat(3, 62px);
    grid-template-rows: repeat(3, 62px);
    gap: 6px;
    z-index: 2000;
}
body.is-touch .tc-dpad { display: grid; }                              /* arrows always in adaptive */
body.is-touch .tc-dpad .tc-btn:not(.tc-fire) { display: flex; }
.tc-up    { grid-area: 1 / 2; }
.tc-left  { grid-area: 2 / 1; }
.tc-right { grid-area: 2 / 3; }
.tc-down  { grid-area: 3 / 2; }

/* FIRE — rounded-rectangle button in the CENTRE of the arrow cross, only when the
   laser is charged (pill picked up). Different design from the arrows. */
.tc-fire {
    grid-area: 2 / 2;
    width: 62px;
    height: 62px;
    border-radius: 14px;
}
body.is-touch.is-playing.can-fire .tc-fire { display: flex; }

/* ── Intro (retro-LCD scene) — reuse the same D-pad, recoloured to the scene's
   charcoal-on-light-grey palette and lifted above the intro canvas (z 10000). */
body.intro-playing .tc-dpad { z-index: 10001; }
body.intro-playing .tc-btn {
    color: #383838;
    background: rgba(224, 224, 224, 0.5);
    border-color: #4a4a4a;
    text-shadow: none;
    box-shadow: 0 2px 7px rgba(0, 0, 0, 0.22);
}
body.intro-playing .tc-btn::after { border-color: rgba(56, 56, 56, 0.32); }
body.intro-playing .tc-btn:active {
    background: rgba(56, 56, 56, 0.88);
    color: #ececec;
    border-color: #383838;
}

/* Fade the D-pad in/out (used at the end of the intro so it appears together with
   the game). #touch-controls is display:contents, so animate the visible .tc-dpad. */
.tc-dpad { transition: opacity 0.35s ease, filter 0.35s ease; }
body.intro-hide-controls .tc-dpad { opacity: 0; pointer-events: none; }

/* The D-pad stays put (no show/hide flicker on death → menu → retry), but reads as
   muted and is non-interactive whenever you can't steer — i.e. any game state that
   isn't active play. Intro phases have their own handling, so exclude them here. */
body.is-touch:not(.is-playing):not(.intro-playing):not(.intro-hide-controls) .tc-dpad {
    opacity: 0.28;
    filter: grayscale(0.5);
    pointer-events: none;
}

/* Same ash frame as the header (var(--ui-*)) + green data glow. */
.tc-btn {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 56px;
    height: 56px;
    font-family: 'Share Tech Mono', monospace;
    font-size: 22px;
    color: #b6ffc8;
    background: var(--ui-bg);
    border: 1px solid var(--ui-border);
    border-radius: 6px;
    text-shadow: 0 0 6px #00ff41;
    box-shadow: 0 0 8px rgba(0, 255, 65, 0.12);
    backdrop-filter: blur(3px);
    -webkit-backdrop-filter: blur(3px);
    -webkit-tap-highlight-color: transparent;
    touch-action: none;
    user-select: none;
    cursor: pointer;
}
.tc-btn::after {
    content: '';
    position: absolute;
    inset: 3px;
    border: 1px solid var(--ui-border-dim);
    border-radius: 4px;
    pointer-events: none;
}
.tc-btn:active {
    background: rgba(0, 255, 65, 0.18);
    border-color: #00ff41;
    box-shadow: 0 0 14px rgba(0, 255, 65, 0.45);
}

/* Big D-pad buttons */
.tc-dpad .tc-btn { width: 62px; height: 62px; font-size: 26px; }

/* FIRE: sits in the centre cell of the D-pad, red laser accent (distinct from arrows). */
.tc-fire {
    width: 62px;
    height: 62px;
    border-radius: 14px;
    font-size: 26px;
    border-color: rgba(255, 42, 74, 0.65);
    color: #ff9ab0;
    text-shadow: 0 0 8px #ff2a4a;
    box-shadow: 0 0 12px rgba(255, 42, 74, 0.28);
}
.tc-fire::after { border-radius: 12px; }
.tc-fire:active { background: rgba(255, 42, 74, 0.22); border-color: #ff2a4a; }

/* Tablet: the D-pad is fixed px (not scaled with the board), so the phone-sized
   62px buttons look small on a big iPad — scale them up. There's plenty of room
   in the control strip. Gated on BOTH dimensions being large so a phone held in
   landscape (wide but short) keeps the phone size. */
@media (pointer: coarse) and (min-width: 700px) and (min-height: 700px) {
    .tc-dpad {
        grid-template-columns: repeat(3, 82px);
        grid-template-rows: repeat(3, 82px);
        gap: 8px;
    }
    .tc-dpad .tc-btn { width: 82px; height: 82px; font-size: 34px; }
    .tc-fire { width: 82px; height: 82px; font-size: 34px; border-radius: 18px; }
}
