/* Shared arcade shell styles.
   Common top-left control cluster (Menu / Mute / Pause / Quit) for all
   ARCADE GAMES: circular icon buttons with a hover/focus tooltip (driven by
   the data-tooltip attribute) showing what each one does.
   Individual games may override colours in their own site.css. */

/* iOS Safari default gestures (pull-to-refresh/overscroll bounce, double-tap
   and pinch zoom, the press-and-hold callout/selection popup) otherwise
   compete with on-screen action buttons. Killed at the html/body level here
   so every arcade game gets it without repeating it per-game. */
html, body {
    overscroll-behavior: none;
}

/* Nothing on an arcade page is meant to be selected or copied. Without this,
   pressing and holding a button (or the HUD, or a modal) on iOS/iPadOS
   selects the text/icon under the finger and pops up the
   Copy / Look Up / Find Selection bar over the game. The -webkit- forms are
   the ones Safari honours; the callout property also stops the long-press
   image/link menu. */
* {
    -webkit-user-select: none;
    user-select: none;
    -webkit-touch-callout: none;
    -webkit-tap-highlight-color: transparent;
    -webkit-user-drag: none;
}

/* No pinch-zoom or double-tap zoom anywhere. Holding two on-screen buttons at
   once (move + fire) looks like a pinch to iOS, which ignores the viewport
   meta's user-scalable=no and magnifies the whole page. touch-action on the
   root applies to everything inside it, except that a scrolling element
   (below) may re-allow its own scroll direction. */
html, body {
    touch-action: none;
}
.help-panel__body,
.highscore-table-wrap,
.eco-panel__body,
.overlay {
    touch-action: pan-y;
}
.mode-select,
.size-select {
    touch-action: pan-x;
}

/* ---- Play area ----
   Every game draws inside .app, which is pinned to the rectangle that is
   BELOW the HUD, RIGHT of the left-hand button column and ABOVE the bottom
   touch buttons - so nothing the player needs to see or hit is ever covered
   by chrome. Insets (not vh/vw sizes) are used on purpose: on iOS Safari
   100vh is the height with the browser toolbars collapsed, so a 100vh box
   runs underneath the toolbar; a fixed box with a bottom inset always sits
   inside the region actually visible, in either orientation, with or
   without the toolbar.
   Every one of these is a static clamp() - scaled by whichever of
   viewport-width/height is actually scarce - rather than measured from the
   DOM, so the four zones (left button column, HUD, play area, bottom button
   row) are correct on the very first frame and never reflow mid-game. */
:root {
    --arcade-btn-size: clamp(2.75rem, 6vw, 3.25rem);
    --arcade-btn-col: calc(max(0.6rem, env(safe-area-inset-left)) + var(--arcade-btn-size) + 0.6rem);
    --arcade-right: max(0.6rem, env(safe-area-inset-right));
    --hud-zone-h: clamp(2.4rem, min(13vw, 12vh), 4.4rem);
    /* Text size tracks width only (not height): a desktop window that's
       narrowed but still tall must still shrink the text - blending in vh
       (like --hud-zone-h above, which is sizing a box that genuinely needs
       to respect a short landscape viewport) would keep it large just
       because the window is tall. */
    --hud-font-size: clamp(0.75rem, 3.2vw, 1.4rem);
    --hud-gap: clamp(0.4rem, 2vw, 1.5rem);
    --arcade-top: var(--hud-zone-h);
    --touch-size: clamp(2.75rem, min(10vw, 12vh), 4rem);
    --arcade-bottom: max(0.5rem, env(safe-area-inset-bottom));
}

/* Games with an on-screen button row reserve room for it, but only on
   touch devices - it isn't shown otherwise. Two rules, not one, covering
   the same condition two ways:
   - The @media (pointer: coarse) + :has() version is pure CSS, so it
     applies on the very first rendered frame - a <script type="module">
     only runs after the page is parsed, so a JS-class-gated rule alone
     could apply a frame late, visible as the GAME BUTTONS zone/.app's
     bottom edge bouncing into place right as the game screen first appears.
   - The .has-touch-controls.touch version (arcade-shell.js adds both once
     it runs) stays alongside it: that JS check also catches
     "ontouchstart" in window / navigator.maxTouchPoints, which some
     touch-capable devices report without matching (pointer: coarse) - the
     CSS-only version regressed the zone to its un-reserved ~0.5rem height
     (a few px) on exactly those devices until this was restored. Same
     final value either way, so having both is harmless when both fire. */
@media (pointer: coarse) {
    body:has(#touch-controls) {
        --arcade-bottom: calc(max(0.75rem, env(safe-area-inset-bottom)) + var(--touch-size) + 0.5rem);
    }
}
body.has-touch-controls.touch {
    --arcade-bottom: calc(max(0.75rem, env(safe-area-inset-bottom)) + var(--touch-size) + 0.5rem);
}

.app {
    position: fixed;
    top: var(--arcade-top);
    bottom: var(--arcade-bottom);
    left: var(--arcade-btn-col);
    right: var(--arcade-right);
}

/* Begins below the HUD zone, not at the very top of the screen - the
   top-left corner (over the HUD's own left padding) stays blank rather than
   having the Menu button sit beside/under the score text. */
.arcade-actions {
    position: fixed;
    top: max(calc(var(--hud-zone-h) + 0.6rem), calc(env(safe-area-inset-top) + 0.6rem));
    left: max(0.6rem, env(safe-area-inset-left));
    /* Bounds the column's own height to the space actually available above
       the bottom chrome (previously unset, so it was free to grow past the
       viewport on a short landscape phone with up to 6 buttons) - combined
       with the fixed width and the clip-path below, excess buttons are
       simply clipped off the bottom rather than the column reflowing. */
    bottom: var(--arcade-bottom);
    width: var(--arcade-btn-size);
    display: grid;
    grid-auto-flow: row;
    /* Without this, a grid container with spare height (now that bottom:
       above gives it one) defaults to spreading its auto-sized rows evenly
       across that height instead of packing them at the top. */
    align-content: start;
    /* Clips only what runs off the bottom (and left): the equivalent of
       overflow: hidden for the excess buttons, but leaving the tooltips,
       which are wider than the column, free to show above and to the right. */
    clip-path: inset(-100vh -100vw 0 0);
    /* Shrinks on a short viewport (phone landscape) only - starting the
       column below the HUD now eats into the same vertical space a row of
       up to 6 buttons needs, so this claws a little back there; unaffected
       everywhere else since 1.6vh exceeds the 0.6rem ceiling by normal
       viewport heights. */
    gap: clamp(0.3rem, 1.6vh, 0.6rem);
    z-index: 100;
}

.arcade-btn {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    width: var(--arcade-btn-size);
    height: var(--arcade-btn-size);
    padding: 0;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.35);
    color: #d8f5ff;
    border: 2px solid rgba(216, 245, 255, 0.55);
    text-decoration: none;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    user-select: none;
    touch-action: none;
}

.arcade-btn svg {
    width: 45%;
    height: 45%;
    flex-shrink: 0;
    pointer-events: none;
}

/* Mute/Pause buttons hold two icons (action + its opposite state) and show
   only one, toggled by arcade-shell.js via the .is-muted / .is-paused class. */
.arcade-btn .icon-muted,
.arcade-btn .icon-resume {
    display: none;
}
.arcade-btn.is-muted .icon-unmuted {
    display: none;
}
.arcade-btn.is-muted .icon-muted {
    display: block;
}
.arcade-btn.is-paused .icon-pause {
    display: none;
}
.arcade-btn.is-paused .icon-resume {
    display: block;
}

.arcade-btn:hover:not(:disabled) {
    background: rgba(216, 245, 255, 0.15);
    border-color: #d8f5ff;
}

.arcade-btn:disabled {
    opacity: 0.35;
    cursor: not-allowed;
    pointer-events: none;
}

/* Tooltip: laid over the button, starting at its centre and running out to
   the right, styled to match the retro arcade HUD rather than the browser's
   native title tooltip. Appears once the pointer has rested on the button
   for half a second (the delay is on the hover rule below, so it still
   disappears at once). */
.arcade-btn[data-tooltip]::after {
    content: attr(data-tooltip);
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translateY(-50%);
    white-space: nowrap;
    background: rgba(0, 0, 0, 0.75);
    color: rgba(255, 255, 255, 0.85);
    padding: 0.15rem 0.5rem;
    font-family: "VT323", "Consolas", ui-monospace, monospace;
    font-size: 0.65rem;
    letter-spacing: 0.04em;
    text-transform: lowercase;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.12s ease;
    z-index: 150;
}

/* Hover only on a device that really hovers: a touch screen leaves :hover
   stuck on the last button tapped. */
@media (hover: hover) {
    .arcade-btn[data-tooltip]:hover::after {
        opacity: 1;
        transition-delay: 0.5s;
    }
}
.arcade-btn[data-tooltip]:focus-visible::after {
    opacity: 1;
    transition-delay: 0.5s;
}
/* Just pressed (arcade-shell.js): stays away until the pointer leaves. */
.arcade-btn.tooltip-off[data-tooltip]::after {
    opacity: 0;
}

/* Canonical score HUD for ALL ARCADE GAMES. Centred at the top (clear of the
   control button column on the left, which is short enough not to collide)
   so it stays centred regardless of screen width, using the retro arcade
   font. Individual games must NOT redefine .hud so the score always appears
   in the same position and font (Invaders is the reference).
   Pinned to the fixed --hud-zone-h rectangle rather than sized to its
   content: font-size/gap shrink with the viewport (same clamp() pattern as
   --touch-size) so a 4-5 item HUD fits on one line down to a small phone,
   and overflow: hidden is a safety net - if content ever still doesn't fit,
   it's clipped inside this zone instead of growing --arcade-top and
   shifting the play area (this is how an item appearing/disappearing, e.g.
   Battlefield's reinforcements counter, can no longer move the board). */
.hud {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: var(--hud-zone-h);
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    justify-content: center;
    gap: var(--hud-gap);
    overflow: hidden;
    /* Centred over the play area (right of the button column), not the whole
       screen, so a wrapped HUD never runs under the buttons. */
    padding: 0 var(--arcade-right) 0 var(--arcade-btn-col);
    box-sizing: border-box;
    color: #ffffff;
    font-family: "VT323", "Consolas", ui-monospace, monospace;
    font-size: var(--hud-font-size);
    letter-spacing: 0.15em;
    pointer-events: none;
    text-shadow: 0 0 6px rgba(255, 255, 255, 0.4);
    z-index: 95;
}

.hud__item span {
    margin-left: 0.5rem;
    color: #ffffff;
}

/* Shared touch-control cluster (used by games with discrete on-screen
   buttons rather than drag/point aiming) - centred along the bottom edge so
   it stays reachable and centred on any screen width. Individual games only
   override .touch-btn's colours in their own site.css. */
.touch-controls {
    position: fixed;
    left: 50%;
    bottom: max(0.75rem, env(safe-area-inset-bottom));
    transform: translateX(-50%);
    display: none;
    grid-auto-flow: column;
    grid-auto-columns: auto;
    gap: 1.875rem; /* 50% more than the original 1.25rem - fingers need room */
    pointer-events: none;
    z-index: 5;
}

.touch-btn {
    pointer-events: auto;
    width: var(--touch-size);
    height: var(--touch-size);
    background: rgba(0, 0, 0, 0.35);
    color: #d8f5ff;
    border: 2px solid rgba(216, 245, 255, 0.55);
    border-radius: 50%;
    padding: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    -webkit-tap-highlight-color: transparent;
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    user-select: none;
    touch-action: none;
}

.touch-btn svg {
    width: 60%;
    height: 60%;
}

.touch-btn.pressed {
    background: rgba(216, 245, 255, 0.25);
    color: #ffffff;
}

/* Pure CSS version for the same first-paint reason as the --arcade-bottom
   rule above, kept alongside the JS-class version (arcade-shell.js adds
   .touch) rather than replacing it - see that rule's comment for why both
   are needed. */
@media (pointer: coarse) {
    .touch-controls {
        display: grid;
    }
}
body.touch .touch-controls {
    display: grid;
}

/* Only ever shown while actually playing - never on the level-select, pause
   or game-over screens. arcade-shell.js toggles .is-playing in updateActions()
   on every phase change. Higher specificity than the rules above (and than
   any per-game "always visible" override, e.g. Vector Space's) so this wins
   regardless of source order. */
.touch-controls:not(.is-playing) {
    display: none !important;
}

/* Shared across ALL ARCADE GAMES: the difficulty/level buttons must not be
   selectable (or visible) while paused mid-game - only on the start screen.
   arcade-shell.js adds/removes .is-paused on the overlay; each game's own
   .mode-select selector already exists in its site.css. */
.overlay.is-paused .mode-select {
    display: none;
}

/* Large banner titles (BRICK OUT, GAME OVER...). Letter-spacing adds space
   AFTER every letter including the last, so a spaced-out word sits one gap to
   the left of true centre. An equal text-indent on the front puts that gap
   back on the left; the value must match each game's letter-spacing (0.35em
   everywhere; Escape uses 0.4em and sets its own). */
.overlay__title {
    text-align: center;
    text-indent: 0.35em;
}

/* Size the title from the width of the overlay itself (the play area), not
   the whole screen: a 12-letter title such as VECTOR SPACE must stay on one
   line and inside the area, on a tablet as well as a phone. */
.overlay {
    container-type: inline-size;
}
@supports (width: 1cqw) {
    .overlay__title {
        font-size: clamp(1.5rem, 6.3cqw, 4.5rem) !important;
    }
}

/* In the narrow phone-portrait play area the big title can be wider than the
   space beside the button column: shrink it to fit rather than run off one side. */
@media (max-width: 30rem) {
    .overlay__title {
        font-size: min(8vw, 1.7rem) !important;
        letter-spacing: 0.25em !important;
        text-indent: 0.25em !important;
    }
}

/* The play area is narrower than the screen (button column on the left), so
   on a phone in portrait the four difficulty buttons (4 x 4.6rem in each
   game's own css) no longer fit: let the columns shrink instead of clipping
   the first and last buttons off the ends. */
.mode-select {
    grid-template-columns: repeat(4, minmax(0, 4.6rem)) !important;
}
@media (max-width: 26rem) {
    .mode-btn {
        font-size: 0.7rem !important;
        letter-spacing: 0.02em !important;
        padding-left: 0.1rem !important;
        padding-right: 0.1rem !important;
    }
}

/* Short screens (a phone in landscape with the browser toolbar showing leaves
   ~5rem for the play area's overlay): compact the start / pause / game-over
   screens so nothing is squeezed or clipped - selectors and buttons keep
   their size, the big title and the hint give way. */
@media (max-height: 34rem) {
    .overlay {
        gap: 0.5rem !important;
        padding: 0.5rem !important;
        overflow-y: auto;
    }
    .overlay > * {
        flex-shrink: 0;
    }
    .overlay__title {
        font-size: 1.8rem !important;
        letter-spacing: 0.25em !important;
        text-indent: 0.25em !important;
    }
    .overlay__hint {
        display: none !important;
    }
}

/* High-score panel footer: Close, centred, with Share (once a score's been
   submitted) pinned to the right at the same height - not up in the header
   next to the status line, and not crowded right next to Close either.
   Share is taken out of flow (position: absolute) so it can't push Close
   off-centre, and vertically centred against Close's own height, which the
   two share exactly (same font-size/vertical padding, below). */
.highscore-foot {
    position: relative;
    display: flex;
    justify-content: center;
    flex-shrink: 0;
    margin-top: 1rem;
}

.highscore-share {
    position: absolute;
    right: 0;
    top: 50%;
    transform: translateY(-50%);
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: clamp(0.4rem, 1.8vw, 0.6rem) clamp(0.6rem, 2.6vw, 0.9rem);
    background: transparent;
    color: #d8f5ff;
    border: 2px solid rgba(216, 245, 255, 0.7);
    border-radius: 0;
    font-family: "VT323", "Consolas", ui-monospace, monospace;
    font-size: clamp(0.85rem, 3.2vw, 1.3rem);
    line-height: normal;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    touch-action: manipulation;
}

.highscore-share[hidden] {
    display: none;
}

.highscore-share svg {
    width: 1rem;
    height: 1rem;
    flex-shrink: 0;
}

.highscore-share:hover:not(:disabled) {
    background: rgba(216, 245, 255, 0.15);
    border-color: #d8f5ff;
}

.highscore-share:disabled {
    opacity: 0.45;
    cursor: default;
}

/* High-score table as a modal (built by arcade-shell.js, which lifts each
   game's #highscore-panel into #highscore-overlay). Same backdrop treatment as
   the How-to-play modal. The rules below out-rank each game's own
   .highscore-panel styling, which was written for an inline panel. */
.highscore-overlay {
    position: fixed;
    inset: 0;
    z-index: 200;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(0, 0, 0, 0.75);
    padding: 1rem;
    box-sizing: border-box;
}

.highscore-overlay.hidden {
    display: none;
}

.highscore-overlay .highscore-panel {
    width: min(92vw, 46rem);
    max-height: min(84vh, 40rem);
    background: rgba(8, 12, 18, 0.96);
    padding: clamp(0.6rem, 3.5vw, 1.25rem);
    box-sizing: border-box;
    font-family: "VT323", "Consolas", ui-monospace, monospace;
}

/* Table text/row padding is otherwise set per-game (each game's own
   .highscore-table, inherited from when the panel was inline rather than a
   shared modal) - these out-rank that with a size proportionate to the
   viewport so every game's table reads the same on a small screen. */
.highscore-overlay .highscore-table {
    font-size: clamp(0.72rem, 2.8vw, 1rem) !important;
}
.highscore-overlay .highscore-table th,
.highscore-overlay .highscore-table td {
    padding: clamp(0.2rem, 1vw, 0.35rem) clamp(0.25rem, 1.2vw, 0.45rem) !important;
}

.highscore-overlay .highscore-panel:not(.hidden):not([hidden]) {
    display: flex;
    flex-direction: column;
}

.highscore-overlay .highscore-table-wrap {
    flex: 1 1 auto;
    min-height: 0;
    max-height: none;
    overflow: auto;
}

.highscore-overlay .highscore-foot,
.highscore-overlay .highscore-close {
    flex-shrink: 0;
}

/* Styled to match the games' Start/Continue button: capitals, same face and
   spacing. Same face, padding and font-size as .help-panel .btn and #btn-start
   (below) so Close/Share/Continue are all the same height everywhere -
   deliberately no min-width, so this sizes itself to its content rather than
   being stretched wide. Centring/spacing now come from .highscore-foot, the
   parent row, not from this element directly. */
.highscore-overlay .highscore-close {
    box-sizing: border-box;
    padding: clamp(0.4rem, 1.8vw, 0.6rem) clamp(0.9rem, 4vw, 1.5rem);
    font-family: "VT323", "Consolas", ui-monospace, monospace;
    font-size: clamp(0.85rem, 3.2vw, 1.3rem);
    line-height: normal;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    text-align: center;
}

/* "How to play" modal, opened by the optional #btn-help button (right below
   Back to menu in .arcade-actions) and shown via #help-overlay. The button
   and panel are entirely optional - arcade-shell.js only wires them up if
   both exist - so games can be migrated one at a time. Rules content is
   game-specific and lives in each game's own index.html inside
   .help-panel__body; only the show/hide mechanics and base look are shared.
   Sits above everything else (including each game's own start/pause
   overlay) so it can be opened from any phase. */
.help-overlay {
    position: fixed;
    inset: 0;
    z-index: 200;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(0, 0, 0, 0.75);
    padding: 1rem;
    box-sizing: border-box;
}

.help-overlay.hidden {
    display: none;
}

.help-panel {
    width: min(92vw, 34rem);
    max-height: min(82vh, 40rem);
    display: flex;
    flex-direction: column;
    gap: 1rem;
    background: rgba(8, 12, 18, 0.96);
    border: 2px solid rgba(216, 245, 255, 0.55);
    box-shadow: 0 0 24px rgba(216, 245, 255, 0.18), inset 0 0 0 1px rgba(216, 245, 255, 0.1);
    padding: clamp(0.6rem, 3.5vw, 1.25rem);
    box-sizing: border-box;
    color: #d8f5ff;
    font-family: "VT323", "Consolas", ui-monospace, monospace;
}

.help-panel__title {
    font-size: clamp(1.1rem, 5vw, 1.6rem);
    letter-spacing: 0.3em;
    color: #fff;
    text-shadow: 0 0 10px rgba(216, 245, 255, 0.6);
    text-align: center;
    flex-shrink: 0;
}

.help-panel__body {
    overflow-y: auto;
    font-size: clamp(0.8rem, 2.8vw, 1.05rem);
    line-height: 1.5;
    color: #cfeaf2;
}

.help-panel__body p {
    margin: 0 0 0.75rem;
}

.help-panel__body p:last-child {
    margin-bottom: 0;
}

.help-panel__body ul {
    margin: 0 0 0.75rem;
    padding-left: 1.3rem;
}

.help-panel__body li {
    margin-bottom: 0.3rem;
}

/* Every game defines its own .btn (colour only, same face/size) in its own
   site.css - but Space Wars/Vector Space drifted to a smaller font-size
   there, used elsewhere in-game for compact buttons, which also made this
   modal's Close button look different from every other game's. Scoping the
   override to .help-panel .btn (not bare .btn) fixes that drift without
   touching those other, intentionally-small buttons, and !important makes
   it proportionate on a small screen regardless of each game's own value. */
.help-panel .btn {
    align-self: center;
    flex-shrink: 0;
    font-size: clamp(0.85rem, 3.2vw, 1.3rem) !important;
    line-height: normal !important;
    padding: clamp(0.4rem, 1.8vw, 0.6rem) clamp(0.9rem, 4vw, 1.5rem) !important;
    letter-spacing: 0.2em !important;
}

/* The overlay's Start/Continue button (every game's start, pause, and
   game-over screens all reuse the one #btn-start, just relabelled) gets the
   exact same font-size and vertical padding as the Close/Share buttons
   above, so all three are the same height on every game and every screen
   size - each game's own site.css otherwise sets this with a fixed,
   non-responsive font-size/padding (and sometimes a redundant #btn-start
   rule matching its own .btn), which only matched by coincidence at desktop
   width and diverged from Close/Share on a small screen. Horizontal padding
   and min-width are left to each game - only the height-determining
   properties are unified here. */
#btn-start {
    font-size: clamp(0.85rem, 3.2vw, 1.3rem) !important;
    line-height: normal !important;
    padding-top: clamp(0.4rem, 1.8vw, 0.6rem) !important;
    padding-bottom: clamp(0.4rem, 1.8vw, 0.6rem) !important;
}

/* ---- Debug zone overlay ----
   Opt-in via ?debugzones=1 (arcade-shell.js adds body.debug-zones), works on
   any game since the four zones it outlines are entirely shell-defined.
   Tints/labels the LEFT MENU, HUD, PLAYING AREA and GAME BUTTONS rectangles
   so the shell's layout variables can be checked visually on a real device
   across desktop/iPad/iPhone and both orientations. pointer-events: none
   throughout so it never blocks real interaction testing. */
body.debug-zones .app {
    background: rgba(77, 210, 255, 0.05) !important;
    outline: 1px dashed #4dd2ff;
    outline-offset: -1px;
}
body.debug-zones .app::before {
    content: "PLAYING AREA";
    position: absolute;
    top: 0.3rem;
    left: 50%;
    transform: translateX(-50%);
    color: #4dd2ff;
    font: 0.65rem/1 monospace;
    letter-spacing: 0.05em;
    text-shadow: 0 0 4px rgba(0, 0, 0, 0.9);
    pointer-events: none;
    z-index: 999;
}
body.debug-zones .hud {
    background: rgba(255, 179, 71, 0.08) !important;
    outline: 1px dashed #ffb347;
    outline-offset: -1px;
}
body.debug-zones .hud::before {
    content: "HUD";
    position: absolute;
    top: 0.1rem;
    left: 0.4rem;
    color: #ffb347;
    font: 0.6rem/1 monospace;
    letter-spacing: 0.05em;
    text-shadow: 0 0 4px rgba(0, 0, 0, 0.9);
    pointer-events: none;
    z-index: 999;
}
body.debug-zones::before {
    content: "LEFT\A MENU";
    white-space: pre;
    position: fixed;
    /* Starts below the HUD zone, matching .arcade-actions - the box above
       this (over the HUD's own top-left corner) is deliberately left blank. */
    top: var(--hud-zone-h);
    bottom: 0;
    left: 0;
    width: var(--arcade-btn-col);
    box-sizing: border-box;
    background: rgba(255, 92, 102, 0.08);
    outline: 1px dashed #ff5c66;
    outline-offset: -1px;
    display: flex;
    align-items: flex-end;
    justify-content: center;
    color: #ff5c66;
    font: 0.6rem/1.2 monospace;
    text-align: center;
    text-shadow: 0 0 4px rgba(0, 0, 0, 0.9);
    padding-bottom: 0.4rem;
    pointer-events: none;
    z-index: 999;
}
body.debug-zones.has-touch-controls.touch::after {
    content: "GAME BUTTONS";
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    height: var(--arcade-bottom);
    box-sizing: border-box;
    background: rgba(124, 252, 0, 0.08);
    outline: 1px dashed #7CFC00;
    outline-offset: -1px;
    color: #7CFC00;
    font: 0.65rem/1 monospace;
    letter-spacing: 0.05em;
    text-align: center;
    text-shadow: 0 0 4px rgba(0, 0, 0, 0.9);
    padding-top: 0.3rem;
    pointer-events: none;
    z-index: 999;
}
