/* =====================================================================
   Rustwing base component classes (UI developer, slice A4).
   Built on src/ui/tokens.css (the art director's tokens, loaded first).
   Every class is rw- prefixed. Source of the rules: art-direction.md
   sections 3, 4 and 11, architecture.md section 8, and the PineBurst
   lessons (docs/research/pineburst-lessons.md section 1.2).

   Laws kept here:
   - every control is at least 44 x 44 pt (--rw-tap);
   - chamfers, not round corners (clip-path on pseudo-elements, so a
     drop-shadow filter on the element itself still shows the glow);
   - only transform and opacity animate; entrances never start at
     opacity 0 (PineBurst lesson 23);
   - one primary (lit) action per screen.
   ===================================================================== */

/* ---------- Layers inside #ui ---------- */
#ui { font-family: var(--rw-font-body); color: var(--rw-ink); }
.rw-layer { position: absolute; inset: 0; pointer-events: none; }
.rw-layer--screens { z-index: auto; }
.rw-layer--overlays { z-index: 40; }
.rw-layer--toasts { z-index: 50; }
.rw-layer--debug { z-index: 60; }
.rw-layer--screens.rw-inert .rw-screen { pointer-events: none; }
.rw-layer--screens.rw-inert .rw-screen * { pointer-events: none !important; }

/* ---------- Screens ---------- */
.rw-screen {
  position: absolute; inset: 0;
  display: flex; flex-direction: column;
  padding: calc(var(--safe-top) + 8px) calc(var(--safe-right) + var(--rw-gutter)) calc(var(--safe-bottom) + 16px) calc(var(--safe-left) + var(--rw-gutter));
  pointer-events: auto;
  overflow: hidden;
  animation: rw-screen-in var(--rw-dur-screen) var(--rw-ease-out) both;
}
.rw-screen--overlay { background: var(--rw-scrim); }
.rw-screen--flow[data-screen="play"] { padding: 0; pointer-events: none; animation: none; touch-action: none; }
@keyframes rw-screen-in { from { transform: translateY(10px); } to { transform: none; } }
/* A hidden document (an automation pane, a backgrounded app) never advances CSS animations, so a
   screen would stay 10 pt low. main.js sets .rw-doc-hidden while the document is hidden. */
/* animation-duration 0s, not animation: none: removing the class must not start a fresh slide (a
   replay on every return to the app); a screen mounted while hidden still ends in its final place. */
.rw-doc-hidden .rw-screen, .rw-doc-hidden .rw-toast { animation-duration: 0s; }

.rw-topbar { display: flex; align-items: center; justify-content: space-between; gap: var(--rw-sp-2); min-height: var(--rw-tap); flex: 0 0 auto; }
.rw-topbar__right { display: flex; align-items: center; gap: var(--rw-sp-2); margin-left: auto; }
.rw-spacer { flex: 1 1 auto; }
.rw-bottom { flex: 0 0 auto; display: flex; flex-direction: column; gap: var(--rw-sp-2); padding-top: var(--rw-sp-2); }

/* ---------- Type ---------- */
.rw-hero { font: 800 var(--rw-fs-hero)/var(--rw-lh-hero) var(--rw-font-display); letter-spacing: 0.04em; text-transform: uppercase; margin: 0; }
.rw-h1 { font: 700 var(--rw-fs-h1)/var(--rw-lh-h1) var(--rw-font-display); letter-spacing: var(--rw-track-caps); text-transform: uppercase; margin: 0; }
.rw-h2 { font: 700 var(--rw-fs-h2)/var(--rw-lh-h2) var(--rw-font-display); margin: 0; }
.rw-h3 { font: 600 var(--rw-fs-h3)/var(--rw-lh-h3) var(--rw-font-display); margin: 0; }
.rw-label { font: 600 var(--rw-fs-label)/var(--rw-lh-label) var(--rw-font-display); letter-spacing: var(--rw-track-label); text-transform: uppercase; color: var(--rw-ink-dim); margin: 0; }
.rw-body { font: 400 var(--rw-fs-body)/var(--rw-lh-body) var(--rw-font-body); margin: 0; }
.rw-body-l { font: 500 var(--rw-fs-body-l)/var(--rw-lh-body-l) var(--rw-font-body); margin: 0; }
.rw-small { font: 500 var(--rw-fs-small)/var(--rw-lh-small) var(--rw-font-body); margin: 0; }
.rw-mono { font: 400 var(--rw-fs-mono)/var(--rw-lh-mono) var(--rw-font-mono); margin: 0; }
.rw-mono-s { font: 400 var(--rw-fs-mono-s)/var(--rw-lh-mono-s) var(--rw-font-mono); margin: 0; }
.rw-num { font-variant-numeric: tabular-nums; }
.rw-dim { color: var(--rw-ink-dim); }
.rw-faint { color: var(--rw-ink-faint); }
.rw-gold { color: var(--rw-gold); }
.rw-mint { color: var(--rw-mint); }
.rw-cyan { color: var(--rw-cyan); }
.rw-warn { color: var(--rw-crimson-ink); }

/* ---------- Chamfered surfaces (art-direction.md 4.1 recipe) ---------- */
.rw-chamfer, .rw-btn, .rw-panel, .rw-card {
  --c: var(--rw-cut-m);
  --bw: var(--rw-stroke);
  --border: var(--rw-line);
  --fill: var(--rw-panel);
  position: relative; isolation: isolate;
}
.rw-chamfer::before, .rw-btn::before, .rw-panel::before, .rw-card::before,
.rw-chamfer::after, .rw-btn::after, .rw-panel::after, .rw-card::after {
  content: ""; position: absolute; z-index: -1; pointer-events: none;
  clip-path: polygon(var(--c) 0, 100% 0, 100% calc(100% - var(--c)), calc(100% - var(--c)) 100%, 0 100%, 0 var(--c));
}
.rw-chamfer::before, .rw-btn::before, .rw-panel::before, .rw-card::before { inset: 0; background: var(--border); }
.rw-chamfer::after, .rw-btn::after, .rw-panel::after, .rw-card::after { inset: var(--bw); background: var(--fill); }

.rw-panel { --c: var(--rw-cut-m); padding: var(--rw-sp-4); filter: drop-shadow(0 8px 24px rgba(0, 0, 0, 0.45)); }
.rw-panel--glass { --fill: rgba(17, 22, 42, 0.92); }
.rw-panel__head { display: flex; align-items: center; gap: var(--rw-sp-2); min-height: 28px; }
.rw-panel__head::before { content: ""; width: 24px; height: 2px; background: var(--rw-cyan); flex: 0 0 auto; }
.rw-card { --c: var(--rw-cut-s); --fill: var(--rw-panel-2); padding: var(--rw-sp-3); }

/* ---------- Buttons (art-direction.md 4.3) ---------- */
.rw-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--rw-sp-2);
  min-width: var(--rw-tap); min-height: var(--rw-tap);
  padding: 0 var(--rw-sp-4);
  font: 700 15px/1 var(--rw-font-display); letter-spacing: var(--rw-track-caps); text-transform: uppercase;
  color: var(--rw-cyan);
  touch-action: manipulation; cursor: pointer; pointer-events: auto;
  transition: transform var(--rw-dur-fast) var(--rw-ease-out), opacity var(--rw-dur-fast);
  -webkit-user-select: none; user-select: none;
}
.rw-btn__label { position: relative; white-space: nowrap; }
.rw-btn:active:not(:disabled) { transform: translateY(2px) scale(0.985); transition-duration: var(--rw-dur-press); }
.rw-btn:disabled { cursor: default; }
.rw-btn:focus-visible { outline: 2px solid var(--rw-cyan); outline-offset: 2px; }

.rw-btn--primary {
  --c: var(--rw-cut-l); --border: #9AF3FF; --fill: var(--rw-cyan); --bw: 1px;
  min-height: var(--rw-btn-h); min-width: 160px; padding: 0 var(--rw-sp-6);
  font-size: 17px; color: var(--rw-ink-dark);
  filter: drop-shadow(0 0 9px rgba(63, 230, 255, 0.35));
}
.rw-btn--primary:active:not(:disabled) { --fill: var(--rw-cyan-press); filter: drop-shadow(0 0 4px rgba(63, 230, 255, 0.30)); }
.rw-btn--primary:disabled { --fill: var(--rw-panel-3); --border: var(--rw-panel-3); color: var(--rw-ink-dim); filter: none; }
.rw-btn--secondary { --c: var(--rw-cut-m); --border: var(--rw-cyan); --fill: var(--rw-panel); --bw: var(--rw-stroke-2); min-height: var(--rw-btn-h-2); }
.rw-btn--secondary:active:not(:disabled) { --fill: #12324A; }
.rw-btn--secondary:disabled { --border: var(--rw-line); color: var(--rw-ink-dim); }
.rw-btn--reward { --c: var(--rw-cut-l); --border: var(--rw-gold); --fill: var(--rw-panel); --bw: var(--rw-stroke-2); min-height: var(--rw-btn-h); color: var(--rw-gold); font-size: 17px; }
.rw-btn--reward:disabled { --border: var(--rw-line); color: var(--rw-ink-dim); }
.rw-btn--danger { --c: var(--rw-cut-m); --border: var(--rw-crimson-ink); --fill: var(--rw-panel); --bw: var(--rw-stroke-2); min-height: var(--rw-btn-h-2); color: var(--rw-crimson-ink); }
.rw-btn--danger[data-armed="true"] { --fill: var(--rw-danger); --border: var(--rw-danger); color: #FFFFFF; }
.rw-btn--text, .rw-btn--back, .rw-btn--icon { --border: transparent; --fill: transparent; }
.rw-btn--text { font-weight: 600; text-transform: none; letter-spacing: 0; }
.rw-btn--back { padding: 0 var(--rw-sp-2) 0 0; justify-content: flex-start; font: 600 14px/1 var(--rw-font-display); color: var(--rw-ink-dim); }
.rw-btn--back:active { color: var(--rw-ink); }
.rw-btn--icon { padding: 0; width: var(--rw-tap); height: var(--rw-tap); color: var(--rw-ink-dim); }
.rw-btn--block { width: 100%; }

/* ---------- Emblems (painted, art-direction.md 13) ---------- */
.rw-emblem { display: inline-block; flex: 0 0 auto; position: relative; }
.rw-emblem img { width: 100%; height: 100%; object-fit: contain; display: block; }
.rw-emblem--missing { border: 1px solid var(--rw-line); clip-path: polygon(6px 0, 100% 0, 100% calc(100% - 6px), calc(100% - 6px) 100%, 0 100%, 0 6px); background: rgba(34, 43, 75, 0.35); }

/* ---------- Currency chips (4.5) ---------- */
.rw-chip {
  display: inline-flex; align-items: center; gap: 6px;
  min-height: var(--rw-tap); min-width: var(--rw-tap); padding: 4px 2px; pointer-events: auto;
  background: transparent; border: 0; color: var(--rw-ink);
  font: 700 16px/1 var(--rw-font-display); font-variant-numeric: tabular-nums;
  touch-action: manipulation; cursor: pointer;
}
.rw-chip__pill { display: inline-flex; align-items: center; gap: 6px; height: var(--rw-chip-h); padding: 0 10px 0 4px; border-radius: var(--rw-radius-pill); background: rgba(17, 22, 42, 0.85); border: 1px solid var(--rw-line); }
.rw-chip[data-currency="credits"] .rw-chip__num { color: var(--rw-gold); }
.rw-chip[data-currency="cores"] .rw-chip__num { color: var(--rw-mint); }

/* ---------- Red dot (4.10) ---------- */
.rw-dot { position: absolute; top: -2px; right: -2px; width: var(--rw-badge-dot); height: var(--rw-badge-dot); border-radius: 50%; background: var(--rw-danger); box-shadow: 0 0 0 2px var(--rw-panel); pointer-events: none; animation: rw-pop 600ms var(--rw-ease-pop) 1; }
@keyframes rw-pop { from { transform: scale(0.4); } to { transform: none; } }

/* ---------- Tab bar (4.4) ---------- */
.rw-tabbar {
  position: absolute; left: 0; right: 0; bottom: 0;
  display: flex; justify-content: space-around; align-items: stretch;
  height: calc(var(--rw-tabbar-h) + var(--safe-bottom)); padding: 0 calc(var(--safe-right) + 4px) var(--safe-bottom) calc(var(--safe-left) + 4px);
  background: rgba(17, 22, 42, 0.94); border-top: 1px solid var(--rw-line);
  -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
}
.rw-tab {
  position: relative; flex: 1 1 0; min-width: 64px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px;
  background: none; border: 0; color: var(--rw-ink-dim); pointer-events: auto; touch-action: manipulation; cursor: pointer;
  font: 600 var(--rw-fs-tab)/var(--rw-lh-tab) var(--rw-font-display); letter-spacing: var(--rw-track-caps); text-transform: uppercase;
}
.rw-tab .rw-emblem { opacity: 0.6; }
.rw-tab[data-state="selected"] { color: var(--rw-cyan); }
.rw-tab[data-state="selected"] .rw-emblem { opacity: 1; }
.rw-tab[data-state="selected"]::before { content: ""; position: absolute; top: -1px; left: 50%; width: 24px; height: 2px; margin-left: -12px; background: var(--rw-cyan); }
.rw-tab__icon { position: relative; }

/* ---------- Toasts (4.9) ---------- */
/* A toast takes no pointer events (ui-screens.md 1.4 and 3.20): it never swallows a tap meant for a
   control beneath it and times out by itself. It docks 8 pt below the top bar (56 pt below the top
   inset), never on the top bar's back control, chips or Settings. */
.rw-toasts { position: absolute; left: 0; right: 0; top: calc(var(--safe-top) + 56px); display: flex; flex-direction: column; align-items: center; gap: 8px; padding: 0 16px; pointer-events: none; }
.rw-toast {
  --c: var(--rw-cut-s); --fill: rgba(25, 32, 57, 0.96); --border: var(--rw-line);
  max-width: 358px; min-height: var(--rw-tap); padding: 10px 14px 10px 17px;
  font: 600 15px/20px var(--rw-font-body); color: var(--rw-ink); pointer-events: none;
  animation: rw-toast-in 160ms var(--rw-ease-out) both;
}
.rw-toast::before { inset: 0; }
.rw-toast > .rw-toast__bar { position: absolute; left: 1px; top: 1px; bottom: 1px; width: 3px; background: var(--rw-cyan); }
.rw-toast[data-kind="reward"] > .rw-toast__bar { background: var(--rw-gold); }
.rw-toast[data-kind="unlock"] > .rw-toast__bar { background: var(--rw-mint); }
.rw-toast[data-kind="warn"] > .rw-toast__bar { background: var(--rw-crimson-ink); }
.rw-toast[data-leaving="1"] { opacity: 0; transition: opacity 200ms; }
@keyframes rw-toast-in { from { transform: translateY(-8px); } to { transform: none; } }

/* ---------- Fallback page (a screen whose module is not built yet) ---------- */
.rw-fallback__body { margin: auto 0; display: flex; flex-direction: column; gap: 12px; align-items: flex-start; }

/* =====================================================================
   HUD (architecture.md 8.6). The root never takes pointer events; the pause
   button is the only live control and stays live above a pick overlay.
   ===================================================================== */
.rw-hud { position: absolute; inset: 0; pointer-events: none; font-family: var(--rw-font-mono); }
/* The band is 40 pt below the top inset (architecture.md 8.6: on the 390 x 844 phone it ends at world
   y 87, above the formation's top row at y 96). The 44 x 44 pause hit area overflows the 40 pt content
   box by 2 pt each side (align-items: center), into the inset above and a transparent strip below.
   The band's top padding is at least 2 pt, so on a phone with no top inset (an iPhone SE in the app,
   status bar hidden) the button starts at y 0, not y -2 (test round 1, F4); the band is then 42 pt. */
.rw-hud__band {
  position: absolute; left: 0; right: 0; top: 0;
  height: calc(max(var(--safe-top), 2px) + 40px); padding: max(var(--safe-top), 2px) calc(var(--safe-right) + 8px) 0 calc(var(--safe-left) + 4px);
  display: flex; align-items: center; gap: 8px;
  background: var(--rw-scrim);
}
/* Every text in the band (and on the corner chips) carries the comm halo, so debris and explosions behind the band
   never wash it out: ink-dim over the 0.72 scrim is 4.6:1 even over an L* 90 flash (first-session-ui.md 3.1). */
.rw-hud__hull, .rw-hud__word, .rw-hud__wave, .rw-hud__rig, .rw-hud__score, .rw-hud__ammo, .rw-hud__boss-name, .rw-hud__chip,
.rw-hud__pause .rw-btn__label { text-shadow: 0 0 2px #05060D, 0 0 4px #05060D; }
.rw-hud__pause { position: relative; z-index: 45; pointer-events: auto; font: 800 16px/1 var(--rw-font-display); letter-spacing: 0.1em; color: var(--rw-ink); }
#ui[data-overlay="pick"] .rw-hud__pause { z-index: 45; pointer-events: auto !important; }
#ui[data-overlay="pause"] .rw-hud__pause, #ui[data-overlay="settings"] .rw-hud__pause { visibility: hidden; }
.rw-hud__vitals { display: flex; flex-direction: column; gap: 3px; width: 92px; flex: 0 0 auto; }
/* "HULL 212" (ui-screens.md 3.14), crimson-ink at 30 percent or less; the bar under it stays cyan: it is yours (FL-16, FL-22) */
.rw-hud__hull { font: 400 12px/13px var(--rw-font-mono); color: var(--rw-ink); font-variant-numeric: tabular-nums; white-space: nowrap; overflow: hidden; }
.rw-hud__hull[data-low="1"] { color: var(--rw-crimson-ink); }
.rw-hud__bar { position: relative; height: 6px; background: rgba(34, 43, 75, 0.9); overflow: hidden; }
.rw-hud__fill { position: absolute; inset: 0; transform-origin: 0 50%; background: var(--rw-cyan); }
.rw-hud__fill--hull { background: var(--rw-cyan); }
/* the hull ghost (first-session-ui.md 3.6): a hit leaves the lost part crimson for 300 ms, then it drains over 400 ms */
.rw-hud__ghost { background: var(--rw-crimson-ink); opacity: 0.8; transform: scaleX(1); }
.rw-hud__ghost[data-drain="1"] { transition: transform 400ms var(--rw-ease-out); }
.rw-hud__hull[data-nudge="1"] { animation: rw-hull-nudge-a 160ms linear both; }
.rw-hud__hull[data-nudge="2"] { animation: rw-hull-nudge-b 160ms linear both; }
@keyframes rw-hull-nudge-a { 0%, 100% { transform: none; } 33% { transform: translateX(2px); } 66% { transform: translateX(-2px); } }
@keyframes rw-hull-nudge-b { 0%, 100% { transform: none; } 33% { transform: translateX(2px); } 66% { transform: translateX(-2px); } }
/* low hull is the crimson-ink number plus the vignette; the bar keeps its own colour (ui-screens.md 3.14) */
.rw-hud__row { display: flex; align-items: center; gap: 6px; height: 12px; font: 400 12px/12px var(--rw-font-mono); color: var(--rw-ink-dim); font-variant-numeric: tabular-nums; }
.rw-hud__pips { display: inline-flex; gap: 2px; padding-left: 1px; }
.rw-hud__pip { width: 7px; height: 7px; border: 1px solid var(--rw-glow-steel); transform: rotate(45deg); }
.rw-hud__pip[data-on="1"] { background: var(--rw-glow-steel); }
.rw-hud__word { font: 400 12px/12px var(--rw-font-mono); color: var(--rw-ink-dim); white-space: nowrap; }
/* The centre: the Wave on row 1 ("WAVE 2 OF 7", "SALVAGE RUN"), the next field rig on row 2 in cyan (FL-05). */
.rw-hud__center { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px; text-align: center; }
.rw-hud__wave { max-width: 100%; font: 400 var(--rw-fs-mono-s)/15px var(--rw-font-mono); color: var(--rw-ink); white-space: nowrap; overflow: hidden; text-overflow: clip; }
.rw-hud__rig { max-width: 100%; min-height: 14px; font: 400 12px/14px var(--rw-font-mono); color: var(--rw-cyan); white-space: nowrap; overflow: hidden; text-overflow: clip; }
/* after the last field rig: "ELITE IN 0:42" or "BOSS IN 0:42" in ink-dim (first-session-ui.md 2.2) */
.rw-hud__rig[data-dim="1"] { color: var(--rw-ink-dim); }
/* The Salvage Run is a bonus, not a Wave (U13): its words are mint (a reward colour; gold stays credits), and row 2 says nobody shoots back. */
.rw-hud__center[data-kind="bonus"] .rw-hud__wave { color: var(--rw-mint); }
.rw-hud__center[data-kind="bonus"] .rw-hud__rig { color: var(--rw-ink); }
/* The Level's length: a 2 pt line along the band's lower edge, filled with play time over the Level's duration. */
.rw-hud__progress { position: absolute; left: 0; right: 0; bottom: 0; height: 2px; background: rgba(34, 43, 75, 0.7); overflow: hidden; pointer-events: none; }
.rw-hud__fill--prog { background: var(--rw-ink-dim); opacity: 0.8; }
/* its marks (first-session-ui.md 2.3) hang from the line into the 2 pt gap under the band, so they never cross the
   shield pips or the ammo row above it nor the comm callout below: the Salvage Run's span under the fill, a 2 by 4
   notch at each field rig (cyan 60 percent ahead, full from 3 s before it, dim once taken), a 6 by 4 finale mark */
.rw-hud__bonus { position: absolute; top: 0; bottom: 0; background: var(--rw-ink-dim); opacity: 0.35; }
.rw-hud__marks { position: absolute; left: 0; right: 0; bottom: -2px; height: 4px; pointer-events: none; }
.rw-hud__notch { position: absolute; top: 0; width: 2px; height: 4px; background: var(--rw-cyan); opacity: 0.6; }
.rw-hud__notch[data-state="soon"] { opacity: 1; }
.rw-hud__notch[data-state="taken"] { background: var(--rw-ink-dim); opacity: 0.5; }
.rw-hud__finale { position: absolute; right: 0; top: 0; width: 6px; height: 4px; background: var(--rw-ink); opacity: 0.6; }
.rw-hud__finale[data-on="1"] { opacity: 1; }
.rw-hud__right { display: flex; flex-direction: column; align-items: flex-end; gap: 1px; flex: 0 0 auto; min-width: 72px; }
.rw-hud__score { font: 400 var(--rw-fs-hud)/var(--rw-lh-hud) var(--rw-font-mono); font-variant-numeric: tabular-nums; color: var(--rw-ink); }
/* The magazine: "AMMO 36/36" (U3; the word steps aside for RELOAD), the reload bar as a 2 pt line under the whole row. */
.rw-hud__ammo { position: relative; font: 400 12px/14px var(--rw-font-mono); color: var(--rw-ink-dim); font-variant-numeric: tabular-nums; display: flex; align-items: center; gap: 4px; }
.rw-hud__ammolabel { font: 400 10px/14px var(--rw-font-mono); letter-spacing: 0.06em; color: var(--rw-ink-faint, var(--rw-ink-dim)); }
.rw-hud__ammolabel[hidden] { display: none; }
.rw-hud__reload { position: absolute; left: 0; right: 0; bottom: -2px; height: 2px; background: rgba(34, 43, 75, 0.9); overflow: hidden; }
.rw-hud__reload > i { position: absolute; inset: 0; transform-origin: 0 50%; background: var(--rw-ink-dim); } /* gold means credits (FL-22) */
/* A finale: the boss name and bar take the band's centre slot (hud.js hides the centre text), so the band is the
   only HUD over the boss painting (render C3 fix round 1: the row under the band and the comm strip below it hid
   the top two thirds of Cantor on a notched 390 x 844 phone). 16 + 3 + 5 pt fits the 40 pt band. */
.rw-hud__boss { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; justify-content: center; gap: 3px; }
/* 12 px with no tracking: "SCRAPJACK FOREMAN", the longest of the 12 elite and boss names, is 128 px against the 131 px
   slot at 375 x 667 (146 px at 390 x 844); at 13 px with 0.12em tracking it was 166 px and cut (C3 fix round 3) */
.rw-hud__boss-name { font: 600 var(--rw-fs-label)/var(--rw-lh-label) var(--rw-font-display); font-size: 12px; letter-spacing: 0; text-transform: uppercase; color: var(--rw-ink); text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rw-hud__boss .rw-hud__bar { height: 5px; }
.rw-hud__boss .rw-hud__fill { background: var(--rw-ink); } /* never crimson: that band is shots, telegraphs, mine lamps and the low-hull vignette (ui-screens.md 3.14) */
/* The DASH button (first-session-ui.md 3.5; owner decision 37: bottom right): a 56 pt ring, no solid fill, so the
   ship stays visible under it; the ring fills clockwise while the dash recharges (--p), full cyan when ready. It shows
   only while the ship holds Phase Dash; a tap dashes, as a double-tap does. */
.rw-hud__dash { position: absolute; right: calc(var(--safe-right) + 12px); bottom: calc(var(--safe-bottom) + 12px); width: 56px; height: 56px;
  min-width: 56px; min-height: 56px; padding: 0; border-radius: 50%; pointer-events: auto; touch-action: none; display: flex; align-items: center; justify-content: center;
  background: rgba(5, 6, 13, 0.24); color: var(--rw-ink-dim); font: 400 12px/14px var(--rw-font-mono); text-shadow: 0 0 2px #05060D, 0 0 4px #05060D; }
.rw-hud__dash::before, .rw-hud__dash::after { display: none; }
.rw-hud__dash[hidden] { display: none; }
.rw-hud__dash-ring { position: absolute; inset: 2px; border-radius: 50%; pointer-events: none;
  background: conic-gradient(var(--rw-ink-dim) var(--p, 0%), rgba(34, 43, 75, 0.7) 0);
  -webkit-mask: radial-gradient(circle, transparent 23.5px, #000 24px); mask: radial-gradient(circle, transparent 23.5px, #000 24px); }
.rw-hud__dash[data-ready="1"] { color: var(--rw-cyan); }
.rw-hud__dash[data-ready="1"] .rw-hud__dash-ring { background: var(--rw-cyan); }
.rw-hud__dash-label { position: relative; font: 600 12px/14px var(--rw-font-display); letter-spacing: 0.04em; }
.rw-hud__dash:not([data-ready="1"]) .rw-hud__dash-label { font: 400 12px/14px var(--rw-font-mono); }
/* A dash that fires flashes the button (FL-30): two keyframe names, so every dash restarts it. Transform and opacity only. */
.rw-hud__dash[data-flash="1"] { animation: rw-dash-flash-a 360ms var(--rw-ease-out) both; }
.rw-hud__dash[data-flash="2"] { animation: rw-dash-flash-b 360ms var(--rw-ease-out) both; }
@keyframes rw-dash-flash-a { 0% { transform: scale(1.18); opacity: 1; } 100% { transform: none; opacity: 1; } }
@keyframes rw-dash-flash-b { 0% { transform: scale(1.18); opacity: 1; } 100% { transform: none; opacity: 1; } }
/* While the DASH button shows, the loot chips stack above it. */
.rw-hud[data-dash="1"] .rw-hud__loot { bottom: calc(var(--safe-bottom) + 12px + 56px + 8px); }
/* The lower right corner (FL-16): running timed power cells with their seconds left, the cores and the salvage
   picked up this Level. Small chips on the HUD scrim; the HUD root takes no pointer events, so they never steer. */
.rw-hud__loot { position: absolute; right: calc(var(--safe-right) + 12px); bottom: calc(var(--safe-bottom) + 12px); display: flex; flex-direction: column; align-items: flex-end; gap: 4px; pointer-events: none; }
.rw-hud__chip { display: inline-flex; align-items: center; gap: 4px; height: 24px; padding: 2px 8px 2px 4px; background: var(--rw-scrim-hud); font: 400 12px/14px var(--rw-font-mono); color: var(--rw-ink-dim); font-variant-numeric: tabular-nums; }
.rw-hud__cell { color: var(--rw-ink); }
.rw-hud__scrap > .rw-num { color: var(--rw-ink); }
.rw-hud__cores > .rw-num { color: var(--rw-mint); }
.rw-hud__scrap[data-bump="1"] { animation: rw-loot-bump-a 220ms var(--rw-ease-out) both; }
.rw-hud__scrap[data-bump="2"] { animation: rw-loot-bump-b 220ms var(--rw-ease-out) both; }
@keyframes rw-loot-bump-a { 0% { transform: scale(1.12); } 100% { transform: none; } }
@keyframes rw-loot-bump-b { 0% { transform: scale(1.12); } 100% { transform: none; } }
/* The teaching pill (first-session-ui.md 4.1): the drag hint and the first-time hints. Its bottom edge sits 8 pt above
   the top of the ship's zone (hud.js sets bottom from the live view), so it never covers the ship; one row is 44 pt
   and two rows grow upward. A 3 pt accent bar in the hint's colour at the left, a 24 pt emblem, then at most two rows
   of text. It ducks to 12 percent while a threat is in its box (data-ducked); the HUD root takes no pointer events,
   so the drag starts anywhere, the pill too. */
.rw-hud__hint { position: absolute; left: calc(var(--safe-left) + 16px); right: calc(var(--safe-right) + 16px); bottom: 40%; min-height: 44px;
  display: flex; align-items: center; gap: 8px; padding: 4px 12px 4px 15px; background: var(--rw-scrim); color: var(--rw-ink);
  box-shadow: inset 0 0 0 1px var(--rw-line-strong); clip-path: polygon(var(--rw-cut-s) 0, 100% 0, 100% calc(100% - var(--rw-cut-s)), calc(100% - var(--rw-cut-s)) 100%, 0 100%, 0 var(--rw-cut-s));
  font: 600 15px/20px var(--rw-font-body); text-align: left; pointer-events: none; opacity: 1;
  transition: opacity 160ms linear; animation: rw-hint-in 160ms var(--rw-ease-out) both; }
.rw-hud__hint::before { content: ""; position: absolute; left: 1px; top: 1px; bottom: 1px; width: 3px; background: var(--accent, var(--rw-cyan)); }
.rw-hud__hint[data-ducked="1"] { opacity: 0.12; transition: opacity 80ms linear; }
.rw-hud__hint-icon { flex: 0 0 auto; display: inline-flex; width: 24px; height: 24px; }
.rw-hud__hint-icon[hidden] { display: none; }
.rw-hud__hint-text { flex: 1 1 auto; min-width: 0; max-height: 40px; overflow: hidden; }
.rw-hud__hint[data-tip="drag"] { justify-content: center; text-align: center; }
.rw-hud__hint[hidden] { display: none; }
@keyframes rw-hint-in { from { transform: translateY(8px); opacity: 0.85; } to { transform: none; opacity: 1; } }
/* Damage numbers beside the ship (first-session-ui.md 3.6): crimson-ink for a hit, with its cause word; BLOCKED in
   cyan, DODGED in ink-dim. Each rises 18 pt over 600 ms and fades over its last 200 ms (an exit). */
.rw-hud__dmg { position: absolute; left: 0; top: 0; display: flex; align-items: baseline; gap: 4px; white-space: nowrap; pointer-events: none;
  color: var(--rw-crimson-ink); text-shadow: 0 0 2px #05060D, 0 0 4px #05060D; }
.rw-hud__dmg[hidden] { display: none; }
.rw-hud__dmg-num { font: 700 15px/18px var(--rw-font-display); }
.rw-hud__dmg-word { font: 700 12px/14px var(--rw-font-display); letter-spacing: 0.04em; }
.rw-hud__dmg[data-tone="blocked"] { color: var(--rw-cyan); }
.rw-hud__dmg[data-tone="heal"] { color: var(--rw-mint); }
.rw-hud__dmg[data-tone="dodged"] { color: var(--rw-ink-dim); }
.rw-hud__dmg[data-tone="blocked"] .rw-hud__dmg-num, .rw-hud__dmg[data-tone="dodged"] .rw-hud__dmg-num { font: 600 12px/14px var(--rw-font-display); letter-spacing: 0.04em; }
.rw-hud__dmg[data-run="1"] { animation: rw-dmg-a 600ms linear both; }
.rw-hud__dmg[data-run="2"] { animation: rw-dmg-b 600ms linear both; }
@keyframes rw-dmg-a { 0% { transform: none; opacity: 1; } 66% { opacity: 1; } 100% { transform: translateY(-18px); opacity: 0; } }
@keyframes rw-dmg-b { 0% { transform: none; opacity: 1; } 66% { opacity: 1; } 100% { transform: translateY(-18px); opacity: 0; } }
#ui[data-overlay] .rw-hud__band, #ui[data-overlay] .rw-hud__boss { opacity: 1; }
/* The pause overlay (and Settings opened from it) has its own "‹ RESUME" in the top bar, where the band's hull
   number and pips sit: the band steps out of view while it is open, so the two never overlap (FL-17). */
#ui[data-overlay="pause"] .rw-hud__band, #ui[data-overlay="settings"] .rw-hud__band { opacity: 0; }

/* =====================================================================
   Upgrade pick overlay (art-direction.md 4.6, architecture.md 4.9,
   ui-screens.md 3.16). Three or four cards and Reroll fit without
   scrolling on 375 x 667 (GOAL.md section 4) and on the 390 x 844
   reference phone with its 47 / 34 insets: measured with every card at
   every rank, the tallest three and the tallest four.
   The column is centred with auto margins, not justify-content: center,
   so if it ever overflows the overflow is at the bottom, where the scroll
   reaches it; a centred flex column overflows at the top too, and that
   part can never be scrolled into view.
   The emblem's size is an inline style from dom.js emblem(), hence
   !important.
   ===================================================================== */
.rw-pick { justify-content: flex-start; gap: 8px; padding-top: calc(var(--safe-top) + 40px); padding-bottom: calc(var(--safe-bottom) + 8px); overflow-y: auto; }
.rw-pick__head { text-align: center; display: flex; flex-direction: column; gap: 2px; margin-top: auto; flex: 0 0 auto; }
.rw-pick__cards { display: flex; flex-direction: column; gap: 8px; flex: 0 0 auto; }
/* row-gap: .rw-btn's 8 px gap would also be a grid row gap; the spec's card rows sit about 4 pt apart.
   Scoped under .rw-pick: menus.css .rw-btn--card (loaded later) set padding 0, the small cut and the line border on
   these cards, so the emblem touched the chamfer and the rank ran to the border (acceptance fix round 1, FL-12). */
.rw-pick .rw-pickcard {
  --c: var(--rw-cut-l); --fill: var(--rw-panel-2); --border: var(--rw-cyan); --bw: var(--rw-stroke-2);
  display: grid; grid-template-columns: 52px 1fr; column-gap: 12px; row-gap: 2px; align-items: start; text-align: left;
  width: 100%; min-height: 0; padding: 12px; color: var(--rw-ink); text-transform: none; letter-spacing: 0; font: inherit;
  transition: transform 120ms var(--rw-ease-out), opacity 200ms;
}
/* The category emblem at 52 pt (ui-screens.md 3.16 asks 56; 52 keeps the tallest three cards on 375 x 667), clear of
   the chamfer by more than 4 pt inside the 12 pt padding (acceptance fix round 1, FL-12). */
.rw-pickcard .rw-emblem { grid-row: 1 / span 4; width: 52px !important; height: 52px !important; }
.rw-pickcard__top { display: flex; align-items: center; justify-content: space-between; gap: 8px; min-width: 0; }
.rw-pickcard__cat { font: 600 var(--rw-fs-label)/var(--rw-lh-label) var(--rw-font-display); letter-spacing: var(--rw-track-label); text-transform: uppercase; color: var(--rw-ink-dim); }
.rw-pickcard__rank { display: inline-flex; align-items: center; gap: 4px; font: 600 12px/14px var(--rw-font-display); letter-spacing: 0.06em; text-transform: uppercase; color: var(--rw-ink-dim); white-space: nowrap; }
.rw-pickcard__rank[data-new="1"] { color: var(--rw-mint); }
.rw-pickcard__pip { width: 8px; height: 8px; border: 1.5px solid var(--rw-line-strong); border-width: 0 2px 2px 0; transform: rotate(-135deg) translate(-1px, -1px); }
.rw-pickcard__pip[data-on="1"] { border-color: var(--rw-cyan); }
.rw-pickcard__name { font: 700 18px/22px var(--rw-font-display); color: var(--rw-ink); margin-top: 2px; }
.rw-pickcard__blurb { font: 400 14px/18px var(--rw-font-body); color: var(--rw-ink-dim); margin-top: 2px; white-space: normal; }
/* One numbers line per row: a card with two stats (Cell Affinity) puts each on its own row, never one run to the edge. */
.rw-pickcard__nums { font: 400 12px/16px var(--rw-font-mono); color: var(--rw-comm-ink); margin-top: 2px; display: flex; flex-direction: column; white-space: normal; min-width: 0; }
.rw-pickcard__num { overflow-wrap: anywhere; }
.rw-pickcard[data-chosen="1"] { transform: scale(1.03); --fill: #1B3A52; }
.rw-pick[data-committing="1"] .rw-pickcard:not([data-chosen="1"]) { opacity: 0.15; }
.rw-pick__foot { display: flex; flex-direction: column; align-items: center; gap: 8px; margin-top: 16px; margin-bottom: auto; flex: 0 0 auto; }
/* Reroll: full width, 24 pt below the last card (the column's 8 pt gap plus the foot's 16 pt), the utility emblem
   before its label (first-session-ui.md 5.10: fixes the mis-tap on the last card in fan-07) */
.rw-pick__reroll { width: 100%; min-height: 48px; gap: 8px; }
.rw-pick__held { font: 500 var(--rw-fs-small)/var(--rw-lh-small) var(--rw-font-body); color: var(--rw-ink-faint); text-align: center; }
/* Four cards (Wide Scan): ui-screens.md 3.16 uses small type, an effect of two lines at most and one
   from-to line. */
.rw-pick--four .rw-pickcard { padding: 8px 12px; grid-template-columns: 48px 1fr; }
.rw-pick--four .rw-pickcard .rw-emblem { width: 48px !important; height: 48px !important; }
.rw-pick--four .rw-pickcard__name { font-size: 16px; line-height: 20px; margin-top: 0; }
.rw-pick--four .rw-pickcard__blurb { font-size: 13px; line-height: 17px; margin-top: 1px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.rw-pick--four .rw-pickcard__nums { max-height: 16px; overflow: hidden; margin-top: 1px; }
/* Short phones (375 x 667; the app hides the status bar, so the top inset is 0): no holding line.
   pick.js decides this in JS with the same query and writes no text when it is hidden (hidden
   elements hold no text); this rule is only a backstop. */
@media (max-height: 700px) {
  .rw-pick__held { display: none; }
}

/* =====================================================================
   First-cut menu screens (title, hangar, loadout, pause, results).
   Slice B4 may move these into src/ui/menus.css.
   ===================================================================== */
.rw-title { justify-content: flex-end; align-items: center; text-align: center; padding-bottom: calc(var(--safe-bottom) + 40px); background: radial-gradient(ellipse at 50% 38%, rgba(63, 230, 255, 0.10), transparent 60%), var(--rw-void); }
.rw-title__scene { position: absolute; inset: 0; background-size: cover; background-position: center; z-index: -1; }
.rw-title__mark { position: absolute; top: calc(var(--safe-top) + 12%); left: 0; right: 0; display: flex; flex-direction: column; align-items: center; gap: 6px; }
.rw-title__word { font: 800 44px/48px var(--rw-font-display); letter-spacing: 0.14em; color: var(--rw-ink); text-shadow: 0 0 12px rgba(63, 230, 255, 0.6); margin: 0; }
.rw-title__rule { width: 200px; height: 2px; background: var(--rw-magenta); }
.rw-title__tag { font: 500 var(--rw-fs-small)/var(--rw-lh-small) var(--rw-font-body); color: var(--rw-ink-dim); }
.rw-title__ship { position: absolute; left: 50%; top: 52%; width: 46%; max-width: 260px; aspect-ratio: 1; transform: translate(-50%, -50%); }
.rw-title__tap { width: 100%; max-width: 358px; min-height: var(--rw-btn-h); background: rgba(5, 6, 13, 0.82); border-top: 1px solid var(--rw-line); border-bottom: 1px solid var(--rw-line); color: var(--rw-ink); font: 600 15px/1 var(--rw-font-display); letter-spacing: 0.12em; text-transform: uppercase; }
.rw-title__tap .rw-btn__label { animation: rw-breathe 2.4s ease-in-out infinite alternate; }
@keyframes rw-breathe { from { opacity: 1; } to { opacity: 0.55; } }
.rw-version { position: absolute; right: calc(var(--safe-right) + 10px); bottom: calc(var(--safe-bottom) + 8px); font: 400 12px/14px var(--rw-font-mono); color: var(--rw-ink-faint); }

.rw-hangar { padding-bottom: calc(var(--rw-tabbar-h) + var(--safe-bottom) + 12px); background: radial-gradient(ellipse at 50% 40%, #142040 0%, var(--rw-night) 55%, var(--rw-void) 100%); }
.rw-hangar__scene { position: absolute; inset: 0; background-size: cover; background-position: center; z-index: -1; }
.rw-hangar__chips { display: flex; gap: 8px; flex-wrap: nowrap; overflow: hidden; }
.rw-hangar__stage { position: relative; flex: 1 1 auto; min-height: 140px; display: flex; align-items: center; justify-content: center; }
.rw-hangar__ship { width: min(290px, 72vw); height: min(290px, 46%); max-height: 46vh; }
.rw-hangar__ship canvas { width: 100%; height: 100%; display: block; }
.rw-hangar__row { display: flex; gap: var(--rw-sp-2); align-items: stretch; }
.rw-hangar__feed { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; gap: 8px; }
.rw-hangar__monitor { --c: var(--rw-cut-s); --fill: var(--rw-comm-screen); --border: var(--rw-line-strong); height: 54px; overflow: hidden; display: flex; align-items: center; justify-content: center; }
.rw-hangar__monitor::after { background: repeating-linear-gradient(to bottom, rgba(0, 0, 0, 0.30) 0 1px, transparent 1px 3px), var(--rw-comm-screen); }
.rw-hangar__cargo { font: 400 var(--rw-fs-mono-s)/var(--rw-lh-mono-s) var(--rw-font-mono); color: var(--rw-comm-ink); font-variant-numeric: tabular-nums; white-space: nowrap; }
.rw-hangar__next { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; gap: 2px; justify-content: center; }
.rw-relative { position: relative; }

.rw-loadout__card { display: flex; flex-direction: column; gap: 10px; margin-top: 8px; }
.rw-statline { display: flex; justify-content: space-between; gap: 8px; font: 500 var(--rw-fs-body)/var(--rw-lh-body) var(--rw-font-body); }
.rw-statline b { font: 700 16px/22px var(--rw-font-display); font-variant-numeric: tabular-nums; }
.rw-gunrow { display: flex; flex-wrap: wrap; gap: 8px; }
.rw-gunrow .rw-btn { flex: 1 1 96px; min-width: 96px; font-size: 13px; padding: 0 10px; }
.rw-gunrow .rw-btn[data-state="selected"] { --fill: #12324A; color: var(--rw-ink); }

.rw-pause { justify-content: center; align-items: stretch; gap: 12px; }
.rw-pause__panel { display: flex; flex-direction: column; gap: 12px; }
.rw-pause__held { display: flex; flex-wrap: wrap; gap: 6px; }
.rw-tag { font: 600 12px/14px var(--rw-font-display); letter-spacing: 0.06em; text-transform: uppercase; padding: 5px 8px; border: 1px solid var(--rw-line); color: var(--rw-ink-dim); }

/* Results: the actions (.rw-bottom) sit outside the body and stay pinned 16 pt above the bottom
   inset; the body takes the rest and is compressed to fit 375 x 667 in the worst case (a loss
   with three upgrades, two core families and two Get-stronger rows; a win with four unlocks).
   If a longer case ever arrives, the body scrolls by itself and never pushes the actions off. */
.rw-results { gap: 10px; background: radial-gradient(ellipse at 50% 20%, rgba(63, 230, 255, 0.08), transparent 60%), rgba(5, 6, 13, 0.88); }
.rw-results[data-outcome="lost"], .rw-results[data-outcome="abandoned"] { background: radial-gradient(ellipse at 50% 20%, rgba(255, 107, 139, 0.08), transparent 60%), rgba(5, 6, 13, 0.88); }
.rw-results__body { flex: 1 1 auto; min-height: 0; overflow-x: hidden; overflow-y: auto; touch-action: pan-y; overscroll-behavior: contain; display: flex; flex-direction: column; gap: 10px; }
.rw-results__body > * { flex: 0 0 auto; }
.rw-results__banner { text-align: center; margin-top: 4px; }
.rw-results__panel { padding: 12px 16px; }
.rw-results__list { display: flex; flex-direction: column; gap: 4px; }
.rw-results__list .rw-statline > span { flex: 0 1 auto; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rw-results__list .rw-statline > b { flex: 0 1 auto; min-width: 0; text-align: right; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* The upgrades and the cores may take two lines, never more. */
.rw-results__list .rw-statline--clamp > span { flex: 0 0 auto; }
.rw-results__list .rw-statline--clamp > b { white-space: normal; font: 600 13px/18px var(--rw-font-body); padding-top: 2px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.rw-results__unlocks { display: flex; flex-direction: column; gap: 2px; }
.rw-results__unlocks p { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.rw-results__get { display: flex; flex-direction: column; gap: 8px; }
.rw-results__row { justify-content: flex-start; width: 100%; padding: 0; color: var(--rw-cyan); }

/* =====================================================================
   Debug panel (?debug=1 only).
   ===================================================================== */
.rw-debug { position: absolute; right: calc(var(--safe-right) + 4px); top: calc(var(--safe-top) + 120px); display: flex; flex-direction: column; align-items: flex-end; pointer-events: auto; max-width: calc(100% - 8px); font: 400 11px/13px var(--rw-font-mono); color: var(--rw-ink-dim); }
.rw-debug__toggle { min-width: 44px; min-height: 44px; background: rgba(5, 6, 13, 0.7); border: 1px dashed var(--rw-line-strong); color: var(--rw-ink-faint); font: 600 11px/1 var(--rw-font-mono); }
.rw-debug__body { display: none; order: 2; background: rgba(5, 6, 13, 0.9); border: 1px solid var(--rw-line); padding: 6px; margin-top: 4px; width: 236px; }
.rw-debug[data-open="1"] .rw-debug__body { display: block; }
.rw-debug__btns { display: grid; grid-template-columns: repeat(4, minmax(44px, 1fr)); gap: 4px; }
.rw-debug__btns button { min-height: 44px; min-width: 44px; background: var(--rw-panel-2); border: 1px solid var(--rw-line); color: var(--rw-ink); font: 600 11px/1 var(--rw-font-mono); }
.rw-debug__stats { white-space: pre; margin: 6px 0 0; max-height: 120px; overflow: hidden; }

/* Reduced Motion: the OS setting, and its twin for the in-app switch (main.js applySettings sets
   .rw-reduced-motion on <html>): screen changes become an instant cut, nothing blinks or slides. */
@media (prefers-reduced-motion: reduce) {
  .rw-screen, .rw-toast, .rw-dot { animation: none; }
  .rw-title__tap .rw-btn__label { animation: none; }
  .rw-hud__dash, .rw-hud__scrap, .rw-hud__hull, .rw-hud__hint { animation: none !important; }
  .rw-hud__hint, .rw-hud__ghost { transition: none !important; }
  .rw-hud__dmg[data-run] { animation-name: rw-dmg-fade !important; }
}
.rw-reduced-motion .rw-hud__dash, .rw-reduced-motion .rw-hud__scrap, .rw-reduced-motion .rw-hud__hull, .rw-reduced-motion .rw-hud__hint { animation: none !important; }
.rw-reduced-motion .rw-hud__hint, .rw-reduced-motion .rw-hud__ghost { transition: none !important; }
.rw-reduced-motion .rw-hud__dmg[data-run] { animation-name: rw-dmg-fade !important; }
@keyframes rw-dmg-fade { 0%, 66% { opacity: 1; } 100% { opacity: 0; } }
.rw-reduced-motion .rw-screen, .rw-reduced-motion .rw-toast, .rw-reduced-motion .rw-dot,
.rw-reduced-motion .rw-title__tap .rw-btn__label { animation: none; }
