/* Page frame of the web game: canvas, overlay layers, loading line, error box.
   The menu screens are styled by menu.css (game UI port, scoped to .gm); the HUD by hud.css; the loader is the JETS layer (loader.css);
   the error card is a JETS panel (menu.css .jt-panel recipe). */
html, body { margin: 0; height: 100%; overflow: hidden; background: var(--av-page); color: var(--av-text); }
/* WHAT: The page can never be wider or taller than the layout viewport: html and body clip (overflow: clip where
         supported, the hidden above is the fallback), never exceed 100% of the viewport, and body is a fixed box over
         the viewport with no scroll container of its own.
   WHY:  Phone landscape black band (live alpha-1.519.0): mobile Chromium / WebKit derive the minimum page scale from the
         document's scrollable size; one box past the right edge makes a reload or rotation land zoomed out, the canvas
         (100vw) then stops short of the screen and the html background fills the rest. overflow: hidden still lets
         scrollWidth grow; clip removes the scroll container, and a fixed body has no scrollable overflow to measure.
         Touch scrolling stays inside the lists (settings, news, pause), which scroll on their own boxes. */
html, body { overflow: clip; max-width: 100%; overscroll-behavior: none; }
body { position: fixed; inset: 0; width: 100%; height: 100%; }
body { font: 15px/1.45 B612, sans-serif; -webkit-font-smoothing: antialiased; }
#game { position: fixed; inset: 0; width: 100vw; height: 100vh; height: 100dvh; display: block; outline: none; }
/* Game roots never start a text selection or the iOS / Android press callout (Firefox Android 2026-11-03: a 1 s press
   opened the selection and context menu, which dropped the pointer lock and paused the run; main.js also blocks the
   contextmenu / selectstart events). */
#game, #hud { user-select: none; -webkit-user-select: none; -webkit-touch-callout: none; }

.layer { position: fixed; inset: 0; z-index: 10; }
/* Menu layers and the loading screen are self-contained full-window boxes (UI-LATENCY #5): a screen switch inside one
   never invalidates the layout or paint of the page around it, and its size never depends on its content. */
.layer.gm, #loading { contain: strict; }
/* Menu layers start at the game scale 1 until ui/kit.js writes --u. */
:root { --u: 1px; }
/* WHAT: Smallest menu text size: every `N * --u` font size in menu.css / shell.css is written max(--font-min, N * --u).
   WHY:  Responsive UI (operator 2026-11-03 "the UI NOT being responsive enough"): the 1920 x 1080 design scale drops to
         --u 0.38 on a phone in landscape, where the 13-17 u captions drew at 5-7 px; 11 px is the readability floor. */
:root { --font-min: 11px; }
/* WHAT: Smallest key size: 40 px with a mouse, 44 px on touch screens (menu.css --hit-min, shell keys, NEWS key).
   WHY:  Responsive UI: on a phone the design scale made keys 34-40 px tall; 44 px is the touch target floor. */
:root { --touch-min: 40px; }
body.is-touch { --touch-min: 44px; }
.hidden:not(.ui-keep) { display: none !important; }
/* Kept screens (UI-LATENCY #6): a layer or screen marked .ui-keep stays rendered while .hidden, moved off the page by a
   transform instead of display:none. Showing it again changes one non-inherited property of one element (the A51 then
   restyles one element, not the 50-130 of the screen, and lays out nothing), so a menu switch is a paint, not a rebuild.
   The resting transform keeps the containing block / stacking of the box identical in both states (a none <-> translate
   change would relayout its positioned descendants). Kept boxes are full-window fixed / absolute boxes whose neighbours
   never flow around them (contain: strict layers, inset 0 screens). Animations inside a kept hidden box stop, so a
   covered screen costs no frame work. */
.ui-keep { transform: translate(0, 0); }
.ui-keep.hidden { transform: translate(-10000px, 0) !important; }
.ui-keep.hidden :is(.gm-nc-skel-line, .gm-result-badge),
.ui-keep.hidden .jt-sweep::before, .ui-keep.hidden .jt-go::after,
.ui-keep.hidden .loader-bar--indet::after, .ui-keep.hidden .loader-items li::before { animation: none !important; }

/* .loading (the loader layer) is styled by loader.css. */

/* Errors: a JETS glass panel (main.js gives #errors the kit panel() classes at boot) with the red edge light, pinned to the bottom.
   --hu is pinned to 1 px: the card can paint before menu.js writes --u (UI log iteration 4). */
.errors { position: fixed; left: 12px; right: 12px; bottom: 12px; z-index: 40; max-height: 40vh; overflow: auto;
  --hu: 1px; --hg-edge: var(--red); --hg-lit: var(--red); --hg-line: var(--red-a55); padding: 10px 14px;
  font: 13px/1.4 var(--font-body); color: var(--text); white-space: pre-wrap; }
/* Card content (main.js errorCard, UI_UNIFORMITY.md R7): one plain sentence, staging-only detail lines, CLOSE | RELOAD.
   Centred at the bottom, at most 560 px wide, so it never spans the shell keys or the whole HUD. */
.errors { left: 50%; right: auto; width: min(560px, calc(100vw - 24px)); transform: translateX(-50%); white-space: normal; }
.errors-text { font-size: 15px; line-height: 1.4; color: var(--white); }
.errors-detail:empty { display: none; }
.errors-detail { margin-top: 8px; font-size: 12px; color: var(--text2); white-space: pre-wrap; overflow-wrap: anywhere; }
.errors-detail > div + div { margin-top: 4px; padding-top: 4px; border-top: 1px solid var(--hg-line); }
.errors-keys { display: flex; justify-content: flex-end; gap: 10px; margin-top: 10px; }
.errors-key { min-height: 44px; min-width: 120px; padding: 0 16px; font: 16px/1 var(--font-ui); letter-spacing: .06em; }

/* The kit panel recipe (menu.css, loaded later) sets position: relative; the error card stays pinned. */
.errors.jt-panel { position: fixed; }
