/* ============================================================================
   CarrierCommander — single stylesheet
   Sections:
     1. Design tokens (:root) — single source of truth
     2. Shared component rules — .design-* cards (minimalist, one copy)
     3. Page: GAME    (selection screen — index.html, body.page-game)
     4. Page: BUILDER (ship builder — ship-builder.html, body.page-builder)
   ========================================================================= */

/* ============ 1. DESIGN TOKENS (single source of truth) ============ */
:root {
  --bg: #06060c;
  --panel: #0b0b13;
  --line: #221e30;
  --line-soft: #161320;
  --txt: #cdd0da;
  --txt-dim: #8d89a6;     /* ~5.7:1 on --panel — WCAG AA (was #6c6982 ~3.6:1, failed) */
  --txt-faint: #827e98;   /* ~4.9:1 on --panel — WCAG AA (was #423f54 ~2.1:1, failed) */
  --accent: #9a86c8;
  --accent-bright: #bcaae4;
  --ok: #5fc28d; --warn: #d6a85e; --err: #d66a6a;
  --mono: ui-monospace, 'SF Mono', Menlo, Monaco, 'Courier New', monospace;

  /* Brand colors (single source of truth — replaces hardcoded hex scattered below) */
  --blue: #1E78D2;        /* player */
  --blue-detail: #5391E7; /* detail / stat text */
  --pink: #F70194;        /* START / CPU */
  --player1-line: #177BCF; /* Player 1 box outlines (pilot + ship tiles + grid) */
  --player2-line: #543746; /* Player 2 / CPU box outlines (pilot + ship tiles + grid) */

  /* Motion tokens — shared easing curves + durations for consistent, tasteful feel */
  --ease-out: cubic-bezier(0.22, 0.61, 0.36, 1);    /* decel — entrances, hovers */
  --ease-spring: cubic-bezier(0.22, 1.18, 0.36, 1); /* gentle overshoot — picker, pop */
  --t-fast: 0.14s;
  --t-med: 0.26s;
  --t-slow: 0.5s;

  /* Logo wordmark — Orbitron (geometric sci-fi) with a robust offline system fallback. */
  --logo-font: 'Orbitron', 'Eurostile', 'Bank Gothic', 'Trebuchet MS', 'Segoe UI', system-ui, sans-serif;
  --logo-shine-dur: 2.4s;    /* sweep duration — slow, languid glint (was 1.15s) */

  /* Soft interactive glows (GPU-friendly box-shadow on hover/focus) */
  --glow-blue: 0 0 0 1px color-mix(in srgb, var(--blue) 55%, transparent), 0 0 18px -2px color-mix(in srgb, var(--blue) 55%, transparent);
  --glow-pink: 0 0 0 1px color-mix(in srgb, var(--pink) 55%, transparent), 0 0 20px -2px color-mix(in srgb, var(--pink) 55%, transparent);
  --glow-accent: 0 0 16px -3px color-mix(in srgb, var(--accent) 70%, transparent);

  /* Dialog / notification spacing — single source of truth (backlog #27).
     Text needs breathing room from container edges; buttons need blank space
     around their labels; multi-element dialogs want consistent gaps. Apply
     these instead of ad-hoc px so every popup/toast/modal stays consistent. */
  --dialog-pad: 26px;        /* comfortable internal padding for modal/dialog bodies */
  --dialog-gap: 18px;        /* consistent vertical gap between stacked dialog rows */
  --toast-pad-y: 14px;       /* notification/toast vertical breathing room */
  --toast-pad-x: 28px;       /* notification/toast horizontal breathing room */
  --btn-pad-y: 10px;         /* blank space above/below a button label */
  --btn-pad-x: 22px;         /* blank space left/right of a button label */
}

/* Respect reduced-motion: keep state changes, drop the movement. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}

/* ============ 2. SHARED: page-transition system (both pages) ============
   One cohesive vocabulary, reusing the :root motion tokens. GPU-friendly
   (opacity only on the veil; opacity+transform on screen fades). Driven by
   src/ui/page-transition.js. Reduced-motion is handled by the global guard
   above (durations collapse to ~0) — these need no separate override. */

/* Full-screen veil: opaque on arrival (lifted by markArrived) and on exit
   (raised by navigateTo before a cross-page navigation). */
.page-veil {
  position: fixed; inset: 0; z-index: 9999;
  background: var(--bg);
  opacity: 0; pointer-events: none;
  transition: opacity var(--t-med) var(--ease-out);
}
.page-veil.on { opacity: 1; pointer-events: auto; }

/* Branded loading overlay (markup inlined in index.html so it paints on first frame).
   Sits above the arrival veil; bootstrap() drives the bar and fades it out when ready. */
#loading-overlay {
  position: fixed; inset: 0; z-index: 10000;
  background: #050810;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 26px;
  opacity: 1; transition: opacity 300ms ease-out;
}
#loading-overlay.hidden { opacity: 0; pointer-events: none; }
#load-logo {
  width: min(440px, 52vw); height: auto;
  filter: drop-shadow(0 0 24px rgba(0,135,189,0.25));
}
#load-track {
  width: min(360px, 42vw); height: 3px;
  background: rgba(0,135,189,0.18);
  border-radius: 2px; overflow: hidden;
}
#load-bar {
  width: 0%; height: 100%;
  background: #0087bd;
  box-shadow: 0 0 8px rgba(0,135,189,0.6);
  transition: width 220ms ease-out;
}
#load-label {
  font: 500 12px 'Fira Mono', ui-monospace, monospace;
  letter-spacing: 4px; color: #0087bd;
}
/* Angled-frame buttons — the chamfered top-left outline is drawn by the frame-angled SVG, stretched to
   the button with a non-scaling 1px stroke, so the line follows the DIAGONAL cleanly (a clip-path border
   can't outline the cut corner). open = idle, filled = hover (subtle blue wash). Shared by the intro
   ENTER button + the PvP lobby buttons. Per-button rules below set size only. */
#intro-enter, .pvp-btn {
  border: none; background: url('/assets/ui/frame-angled-open.svg') no-repeat center / 100% 100%;
  color: #6cc5e8; cursor: pointer; letter-spacing: 5px;
  font-family: 'Fira Mono', ui-monospace, monospace; font-weight: 500;
  transition: color 160ms ease-out, transform 160ms ease-out, filter 160ms ease-out;
}
#intro-enter:hover, #intro-enter:focus-visible,
.pvp-btn:hover, .pvp-btn:focus-visible {
  background-image: url('/assets/ui/frame-angled-filled.svg');
  color: #eaf4ff; transform: translateY(-2px); outline: none;
  filter: drop-shadow(0 0 9px rgba(0,135,189,0.45));
}
#intro-enter:active, .pvp-btn:active { transform: translateY(0) scale(0.985); }

/* CONTINUE (loader) — the full START-button frame (button_start.svg: translucent blue fill, white
   stroke, blue glow), stretched to the button. Its own look, not the angled-frame family above. */
#load-continue {
  margin: 0; padding: 20px 72px; border: none; cursor: pointer;
  background: url('/assets/ui/button_start.svg') no-repeat center / 100% 100%;
  font: 600 15px 'Fira Mono', ui-monospace, monospace; letter-spacing: 7px; color: #eaf4ff;
  transition: color 160ms ease-out, transform 160ms ease-out, filter 160ms ease-out;
}
#load-continue:hover, #load-continue:focus-visible {
  color: #ffffff; transform: translateY(-2px); outline: none; filter: brightness(1.25);
}
#load-continue:active { transform: translateY(0) scale(0.99); }

/* ============ First-time narrative intro (cold-open) ============
   Full-screen dark overlay shown ONCE (localStorage 'cc-intro-seen-v1', gated in main.js)
   BEFORE the game-mode menu. Above the start-screen (z 60), below the loading overlay (z 10000)
   and arrival veil (z 9999). Markup in index.html; wiring in main.js. Cinematic fade/slide in. */
#intro-overlay {
  /* fixed + above the page-veil (9999) so the lore shows BEFORE the splash/logo: it covers the still-
     veiled page right after the loader (10000) fades, and the logo intro only runs on dismiss. */
  position: fixed; inset: 0; z-index: 10001;
  display: flex; align-items: center; justify-content: center;
  background: #050810; cursor: pointer;
  opacity: 0; transition: opacity 600ms ease-out;
}
#intro-overlay.show { opacity: 1; }
#intro-overlay[hidden] { display: none; }   /* fully removed after the fade-out */
#intro-overlay .intro-inner {
  max-width: 860px; padding: 0 48px; text-align: center;
  transform: translateY(22px); opacity: 0;
  transition: transform 700ms var(--ease-out, cubic-bezier(.2,.7,.2,1)), opacity 700ms ease-out;
}
#intro-overlay.show .intro-inner { transform: translateY(0); opacity: 1; transition-delay: 140ms; }
#intro-overlay .intro-title {
  margin: 0 0 38px; font-family: var(--logo-font);
  font-weight: 900; font-size: 56px; letter-spacing: 10px; line-height: 1.05;
  color: #eaf4ff; text-shadow: 0 0 28px rgba(0,135,189,0.45);
}
#intro-overlay .intro-body {
  font-family: 'Fira Sans', system-ui, sans-serif;
  font-weight: 300; font-size: 20px; line-height: 1.65; color: #b9c9da;
}
#intro-overlay .intro-body p { margin: 0 0 18px; }
#intro-overlay .intro-body p:last-child {
  margin: 4px 0 0; color: #6f8cab; font-style: italic; font-size: 18px;
}
/* Size only — the frame/hover/active come from the shared angled-frame-button rule above. */
#intro-enter { margin-top: 44px; padding: 16px 52px; font-size: 16px; }

/* === PvP ONLINE lobby (src/net/pvp-lobby.js, built in JS) ====================================
   Dark, #0087bd-accented, chamfered buttons via the OPAQUE border-box technique (see #load-continue
   / #intro-enter — a real CSS border gets clipped off the diagonal). Only present while a PvP match
   is being set up; single-player never mounts these. */
.pvp-overlay {
  position: fixed; inset: 0; z-index: 60; display: flex; align-items: center; justify-content: center;
  background: radial-gradient(ellipse at center, rgba(4,10,18,0.72), rgba(2,5,10,0.92));
  font-family: 'Fira Mono', ui-monospace, monospace;
}
.pvp-card {
  position: relative; z-index: 0;
  min-width: 560px; max-width: 640px; padding: 64px 72px 52px; text-align: center;
  /* Two-layer chamfer: the element is the #0087bd border colour; ::before is the dark face inset 1px,
     so the outline shows on EVERY edge incl. the diagonal (a clip-path border can't draw the cut). */
  background: #0087bd; clip-path: polygon(24px 0, 100% 0, 100% 100%, 0 100%, 0 24px);
  box-shadow: 0 0 40px rgba(0,135,189,0.25);
}
.pvp-card::before {
  content: ''; position: absolute; inset: 1px; z-index: -1; background: #071824;
  clip-path: polygon(23px 0, 100% 0, 100% 100%, 0 100%, 0 23px);
}
.pvp-title { font-size: 24px; letter-spacing: 9px; color: #6cc5e8; margin-bottom: 40px; }
.pvp-body { display: flex; flex-direction: column; gap: 30px; }
.pvp-choice { display: flex; flex-direction: column; gap: 26px; align-items: center; }
.pvp-or { color: #4f7d92; font-size: 12px; letter-spacing: 4px; }
.pvp-join { display: flex; gap: 16px; align-items: stretch; }
.pvp-code-input {
  width: 188px; padding: 18px 20px; text-align: center; letter-spacing: 7px; font-size: 19px;
  color: #eaf4ff; background: #04101a; border: 1px solid #0087bd; outline: none;
  font-family: inherit; text-transform: uppercase;
}
.pvp-code-input:focus { box-shadow: 0 0 12px rgba(0,135,189,0.5); }
/* Size only — the frame/hover/active come from the shared angled-frame-button rule near the top. The
   angled-frame SVG stretches under the label, so give it generous horizontal padding (text room) and
   a min-width so HOST GAME / JOIN don't crowd the chamfer. */
.pvp-btn { padding: 18px 52px; min-width: 168px; font-size: 14px; letter-spacing: 4px; }
.pvp-cancel { margin-top: 44px; font-size: 13px; letter-spacing: 3px; color: #6f93a3; }
.pvp-code-display { display: flex; flex-direction: column; gap: 12px; align-items: center; }
.pvp-code-label { color: #4f7d92; font-size: 11px; letter-spacing: 4px; }
.pvp-code { font-size: 44px; letter-spacing: 14px; color: #eaf4ff; text-shadow: 0 0 18px rgba(0,135,189,0.6); }
.pvp-status { min-height: 18px; color: #8fb4c6; font-size: 13px; letter-spacing: 1px; }
/* Back/cancel shown DURING the PvP captain/ship carousels (the overlay root goes non-blocking via
   hidePanel, so this control owns its own pointer-events). PvP-scoped — single-player never mounts it.
   Top-RIGHT, clear of the carousels' top-left .cap-logo / .ship-logo (their own single-player back). */
.pvp-carousel-back {
  position: fixed; top: 28px; right: 28px; z-index: 70; pointer-events: auto;
  padding: 14px 34px; min-width: 132px; font-size: 13px; letter-spacing: 4px;
}
.pvp-carousel-back[hidden] { display: none; }
.pvp-toast {
  position: fixed; left: 50%; bottom: 48px; transform: translate(-50%, 12px); z-index: 80;
  padding: var(--toast-pad-y) var(--toast-pad-x); background: linear-gradient(#071824, #071824) padding-box, #0087bd border-box;
  border: 1px solid transparent; clip-path: polygon(12px 0, 100% 0, 100% 100%, 0 100%, 0 12px);
  color: #cfe6f2; font: 500 13px 'Fira Mono', ui-monospace, monospace; letter-spacing: 2px;
  opacity: 0; transition: opacity .35s ease, transform .35s ease; pointer-events: none;
}
.pvp-toast.show { opacity: 1; transform: translate(-50%, 0); }

/* PvP end / interrupt screen (disconnect). OPAQUE (covers the stopped battle frame), above everything;
   fades in. Reuses .pvp-card / .pvp-btn. */
.pvp-end { z-index: 9000; opacity: 0; transition: opacity .4s ease;
  background: radial-gradient(ellipse at center, rgba(4,10,18,0.96), rgba(2,5,10,0.995)); }
.pvp-end.show { opacity: 1; }
.pvp-end-detail { color: #9fc0d4; font-size: 14px; letter-spacing: 1px; line-height: 1.7; margin: 4px 8px 32px; padding: 0 4px; }

/* Same-document screen ease-out (selection → battle): fade + a faint settle. */
@keyframes screen-out { from { opacity: 1; transform: none; } to { opacity: 0; transform: scale(1.012); } }
.screen-leaving { animation: screen-out var(--t-med) var(--ease-out) both; pointer-events: none; }

/* ============ 2b. SHARED: design cards (minimalist — used by both pages) ============ */
.design-item {
  position: relative; border: 1px solid var(--line-soft); background: transparent;
  cursor: pointer; display: flex; flex-direction: column; overflow: hidden;
  padding-bottom: 6px;
  transition: border-color var(--t-fast) var(--ease-out),
              box-shadow var(--t-med) var(--ease-out),
              transform var(--t-fast) var(--ease-out);
  will-change: transform;
}
.design-item:hover { border-color: var(--line); transform: translateY(-2px); box-shadow: var(--glow-accent); }
.design-item.selected { border-color: var(--accent); box-shadow: var(--glow-accent); }
.design-item:active { transform: translateY(0) scale(0.99); }
.design-preview { display: block; width: 100%; flex: 1; min-height: 130px; cursor: pointer; }
.design-name { color: var(--txt); font-size: 13px; padding: 10px 16px 3px; }
.design-item.selected .design-name { color: var(--accent-bright); }
.design-name.invalid { color: var(--err); }
.design-hull { color: var(--txt-dim); font-size: 10px; padding: 0 16px 3px; letter-spacing: 0.5px; }
.design-weapons { color: var(--txt-dim); font-size: 10px; padding: 0 16px 3px; line-height: 1.3; }
.design-stats { color: var(--blue-detail); font-size: 10px; padding: 3px 16px 8px; letter-spacing: 0.3px; }
.design-badge { position: absolute; top: 5px; right: 5px; font-size: 8px; letter-spacing: 1px; color: var(--blue); background: rgba(5,8,16,0.7); border: 1px solid color-mix(in srgb, var(--blue) 40%, transparent); padding: 2px 5px; pointer-events: none; }

/* ============ 3. PAGE: GAME (selection screen — index.html) ============ */
.page-game * { margin: 0; padding: 0; box-sizing: border-box; }

body.page-game {
  background: var(--bg);
  position: fixed;
  top: 0; left: 0;
  width: 100vw;
  height: 100vh;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
}

#scale-wrapper {
  position: fixed;
  top: 0; left: 0;
  width: 100vw;
  height: 100vh;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
}

#game-container {
  width: 1920px;
  height: 1080px;
  position: absolute;
  transform-origin: top left;
  cursor: default;
}

#game-container:active { cursor: grabbing; }

#game-container > canvas {
  position: absolute;
  top: 0; left: 0;
  width: 1920px;
  height: 1080px;
}

#layer-background { z-index: 0; }
#layer-effects     { z-index: 1; }
#layer-entities    { z-index: 2; }
#layer-ui          { z-index: 3; pointer-events: none; }

/* ── Selection screen ─────────────────────────────────────────────────── */

#selection-screen {
  position: absolute;
  top: 0; left: 0;
  width: 1920px; height: 1080px;
  z-index: 10;
  /* Hidden until the Vs/launch page is revealed (revealSelectionScreen / revealPvpVs set inline
     display:flex; teardown sets display:none). Without this it renders block at boot and FLASHES
     for a frame between the loader fade and the splash. It is the active matchup page — NOT dead code. */
  display: none;
  /* Semi-transparent scrim over the parallax launch background (selection-bg.js draws it on
     #layer-background, z-index 0). Lower the alpha to show more parallax, raise it for readability. */
  background: rgba(5, 8, 16, 0.5);
  color: var(--txt);
  font-family: var(--mono);
  display: none;
  user-select: none;
  overflow: hidden;
}

/* ── Entrance animations (run once on load; staggered for a composed reveal) ──── */
@keyframes sel-fade-down  { from { opacity: 0; transform: translateY(-14px); } to { opacity: 1; transform: none; } }
@keyframes sel-fade-up    { from { opacity: 0; transform: translateY(18px); }  to { opacity: 1; transform: none; } }
@keyframes sel-fade-left  { from { opacity: 0; transform: translateX(-26px); } to { opacity: 1; transform: none; } }
@keyframes sel-fade-right { from { opacity: 0; transform: translateX(26px); }  to { opacity: 1; transform: none; } }
@keyframes sel-pop        { from { opacity: 0; transform: scale(0.86); }       to { opacity: 1; transform: none; } }
/* Slow breathing glow on the armed START button — subtle "ready" pulse */
@keyframes start-pulse {
  0%, 100% { box-shadow: 0 0 0 0 transparent, inset 0 0 0 0 transparent; }
  50%      { box-shadow: 0 0 22px -4px color-mix(in srgb, var(--pink) 60%, transparent), inset 0 0 14px -6px color-mix(in srgb, var(--pink) 45%, transparent); }
}

/* Main screen — dims to 10% while the slide-in picker is open. */
#sel-main {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  padding: 36px 56px 28px;
  box-sizing: border-box;
  transition: opacity 0.28s ease;
}
/* Stagger the reveal of the top-level regions. backwards keeps them hidden pre-delay. */
#sel-logo    { animation: sel-fade-down 0.6s var(--ease-out) both; }
#sel-topbtns { animation: sel-fade-down 0.6s var(--ease-out) 0.08s both; }
#player-col  { animation: sel-fade-left 0.65s var(--ease-out) 0.18s both; }
#cpu-col     { animation: sel-fade-right 0.65s var(--ease-out) 0.18s both; }
/* START button lives in the topbar, always visible, disabled until both ships are chosen
   (via the button's disabled attr — no .ready class is used). */
#sel-center  { display: flex; flex-direction: column; align-items: center; gap: 6px; }
#selection-screen.picking #sel-main { opacity: 0.1; pointer-events: none; }

/* ── Top bar: logo (left) | START (center) | nav buttons (right) ────── */
#sel-topbar {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  flex-shrink: 0;
}
/* Graphic corner logo (carrier + commander pngs). The old text .logo-words/.logo-sub/.logo-shine rules
   below are now dormant (no matching elements) — kept harmless; initLogoShine() no-ops when absent. */
#sel-logo { justify-self: start; display: flex; flex-direction: column; align-items: flex-start; line-height: 0; cursor: pointer; }   /* click → back to mode chooser */
#sel-logo .sel-logo-composit  { width: 232px; height: auto; display: block; }   /* logo_composit 258×66 ×0.9 (matches the captain-screen corner logo) */
#sel-topbtns { justify-self: end; }
/* Wordmark: Orbitron, two stacked words. CARRIER leads heavy/bright; COMMANDER is
   lighter and tracked wider so the two lines lock into a confident block. The whole
   block is the shine stage (relative) so the streak sweeps both words as one. */
#sel-logo .logo-words {
  position: relative;
  display: inline-block;
  font-family: var(--logo-font);
  /* Clip the diagonal shine to the text block so it never bleeds into the layout. */
  overflow: hidden;
  padding: 2px 6px 4px 0;   /* room for the glint at the edges without clipping glyphs */
}
#sel-logo .logo-1 {
  font-size: 44px; font-weight: 900; letter-spacing: 6px; line-height: 0.92;
  /* Cool steel gradient — bright top, dim base — gives weight without cliché chrome. */
  background: linear-gradient(180deg, #ffffff 0%, var(--txt) 52%, #7f8aa6 100%);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
}
#sel-logo .logo-2 {
  font-size: 27px; font-weight: 500; letter-spacing: 13.5px; line-height: 1.0;
  color: var(--txt);
  margin-top: 2px;
  /* Hairline blue underglow ties the wordmark to the player brand. */
  text-shadow: 0 0 14px color-mix(in srgb, var(--blue) 45%, transparent);
}
#sel-logo .logo-sub {
  font-family: var(--mono);
  font-size: 11px; letter-spacing: 6px; color: var(--blue); margin-top: 8px;
  padding-left: 2px;
}

/* Diagonal shine: a soft, narrow light streak parked off the left edge. JS toggles
   .shine-go to replay the sweep at randomized intervals (src/main.js). GPU-only
   (transform + opacity), pointer-transparent, sized to overshoot the block. */
#sel-logo .logo-shine {
  position: absolute;
  top: -30%; left: 0;
  width: 60%; height: 160%;
  pointer-events: none;
  transform: translateX(-180%) skewX(-18deg);
  background: linear-gradient(
    100deg,
    transparent 0%,
    color-mix(in srgb, #ffffff 22%, transparent) 38%,
    color-mix(in srgb, #ffffff 78%, transparent) 50%,
    color-mix(in srgb, #ffffff 22%, transparent) 62%,
    transparent 100%);
  mix-blend-mode: screen;   /* glints over the bright text, vanishes over the dark bg */
  opacity: 0;
  will-change: transform, opacity;
}
#sel-logo .logo-shine.shine-go {
  animation: logo-shine-sweep var(--logo-shine-dur) var(--ease-out) both;
}
@keyframes logo-shine-sweep {
  0%   { transform: translateX(-180%) skewX(-18deg); opacity: 0; }
  12%  { opacity: 1; }
  88%  { opacity: 1; }
  100% { transform: translateX(320%)  skewX(-18deg); opacity: 0; }
}

#sel-topbtns { display: flex; gap: 16px; }
#sel-topbtns > * {
  text-decoration: none;
  background: transparent;
  border: 1px solid color-mix(in srgb, var(--blue) 50%, transparent);
  color: var(--blue);
  font-family: var(--mono);
  font-size: 14px;
  letter-spacing: 1px;
  padding: 12px 26px;
  cursor: pointer;
  transition: border-color var(--t-fast) var(--ease-out),
              background-color var(--t-fast) var(--ease-out),
              box-shadow var(--t-med) var(--ease-out),
              transform var(--t-fast) var(--ease-out);
}
#sel-topbtns > *:hover {
  border-color: var(--blue);
  background: color-mix(in srgb, var(--blue) 10%, transparent);
  box-shadow: var(--glow-blue);
  transform: translateY(-1px);
}
#sel-topbtns > *:active { transform: translateY(0) scale(0.97); }

/* === Top-right nav (Balancing / Ship Builder / Settings) — chamfered SVG frame, 15px from top+right === */
#sel-topbtns { position: absolute; top: 15px; right: 15px; gap: 10px; align-items: center; z-index: 70; }   /* global — above start-screen (60) + captain-select (65) */
#btn-economy, #btn-ship-builder, #btn-settings {
  position: relative; width: 140px; height: 38px; min-width: 0;
  border: 0; padding: 0; background: transparent; box-shadow: none;
  display: flex; align-items: center; justify-content: center;
  font: 400 14px 'Fira Code', var(--mono), monospace; letter-spacing: 0.5px;
  color: #0087bd; text-decoration: none;
}
/* %-based chamfer clip (same stretched frame-angled SVG as .sm-btn). Clips the ::before/::after
   children to the chamfer so the backdrop-blur is confined to the frame shape. */
#btn-economy, #btn-ship-builder, #btn-settings { clip-path: polygon(14.32% 0, 100% 0, 100% 100%, 0 100%, 0 58.05%); }
/* ::before = frame outline + backdrop-blur carrier (no clip/mask on itself → blur survives; the
   button's clip-path shapes it). Faint tint backs the blur over dark space. */
#btn-ship-builder::before, #btn-settings::before {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: rgba(0, 135, 189, 0.05) url(/assets/ui/frame-angled-open.svg) no-repeat center / 100% 100%;
  -webkit-backdrop-filter: blur(3.5px); backdrop-filter: blur(3.5px);
}
#btn-economy:hover, #btn-ship-builder:hover, #btn-settings:hover {
  background: transparent; box-shadow: none; border: 0; transform: translateY(-1px); color: #eaf4ff;
}
#btn-ship-builder:hover::before, #btn-settings:hover::before { background-image: url(/assets/ui/frame-angled-filled.svg); }
/* Balancing (economy) = #00BD8B (dev-only). Frame recolored EXACTLY by masking the SVG shape with the
   colour (hue-rotate can't hit a precise hex). NOTE: this button's ONLY pseudo (::before) is mask-based,
   and a mask on the element suppresses backdrop-filter; a separate ::after blur would paint over the thin
   green frame outline. So the backdrop-blur is intentionally NOT applied here (dev-only button) to avoid a
   broken result — it keeps its solid frame. ship-builder / settings (background-frame, not masked) get it. */
#btn-economy { color: #00BD8B; }
#btn-economy::before {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: #00BD8B;
  -webkit-mask: url(/assets/ui/frame-angled-open.svg) no-repeat center / 100% 100%;
          mask: url(/assets/ui/frame-angled-open.svg) no-repeat center / 100% 100%;
}
#btn-economy:hover { color: #2fe0ad; }
#btn-economy:hover::before { background: #2fe0ad; }

/* ── Columns: Player 1 | Player 2 (CPU) ──────────────────────────────── */
#sel-columns {
  display: flex;
  align-items: stretch;
  flex: 1;
  min-height: 0;
  margin-top: 22px;
  gap: 14px;                /* center gap matches secondary-tile gap */
}
.fleet-col {
  flex: 1;                  /* fill available width — outer edges align with logo/settings */
  display: flex;
  flex-direction: column;
  min-height: 0;
  position: relative;
}

/* ── Fleet main row: pilot portrait beside the ship tile, both flush-height ──── */
.fleet-main-row {
  display: flex;
  align-items: stretch;
  flex: 1;
  min-height: 0;
  gap: 14px;                /* pilot ↔ ship margin matches secondary-tile gap */
}

/* Pilot portrait — flex child, sits beside the ship tile. Player pilot on left, CPU on right. */
.pilot {
  position: relative;
  flex: 0 0 320px;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: transparent;   /* no solid fill — grid + page nebula show through (matches ship tiles) */
  pointer-events: none;  /* CPU pilot — no interaction */
  z-index: 1;
}
.pilot-player { pointer-events: auto; cursor: pointer; }
/* Accent border drawn as an on-top overlay (::before, z above the video) so the video
   can't paint over it — the CPU pilot's right border was being covered by the video. */
.pilot-player::before, .pilot-cpu::before {
  content: ''; position: absolute; inset: 0; pointer-events: none; z-index: 3;
}
.pilot-player::before { border: 1px solid var(--player1-line); }
.pilot-cpu::before    { border: 1px solid var(--player2-line); }
.pilot-frame  {
  flex: 1; min-height: 0; overflow: hidden; position: relative;
  /* Faint builder grid backdrop (matches the ship tiles) — visible when the pilot slot is
     empty ("CHOOSE YOUR COMMANDER"); the captain video/portrait covers it once chosen. */
  background-image:
    repeating-linear-gradient(0deg,  transparent 0 21px, color-mix(in srgb, var(--player1-line) 11%, transparent) 21px 22px),
    repeating-linear-gradient(90deg, transparent 0 21px, color-mix(in srgb, var(--player1-line) 11%, transparent) 21px 22px);
}
.pilot-cpu .pilot-frame {
  background-image:
    repeating-linear-gradient(0deg,  transparent 0 21px, color-mix(in srgb, var(--player2-line) 11%, transparent) 21px 22px),
    repeating-linear-gradient(90deg, transparent 0 21px, color-mix(in srgb, var(--player2-line) 11%, transparent) 21px 22px);
}
.pilot-img    { width: 100%; height: 100%; object-fit: cover; object-position: center top; display: block; }
.pilot-player .pilot-img { transform: scaleX(-1); }

/* Stacked video layers inside .pilot-frame (idle loops silently; speak fades in on voice) */
.pilot-vid {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover; object-position: center top;
  display: block; opacity: 0;
  transition: opacity 0.35s ease;
}
/* Player-side videos (idle AND speak) flip to face right, like the static portrait. */
.pilot-player .pilot-vid { transform: scaleX(-1); }
.pilot-info   { flex: 0 0 auto; padding: 8px 12px 10px; display: flex; flex-direction: column; gap: 4px; }
.pilot-name   { font-size: 13px; color: var(--txt); letter-spacing: 0.3px; }
.pilot-stat   { font-size: 10px; color: var(--txt-dim); letter-spacing: 0.3px; }
.pilot-bubble { font-size: 10px; font-style: italic; color: var(--blue-detail); line-height: 1.35; }
.pilot-player:hover { box-shadow: 0 0 10px -2px var(--blue); }
.pilot-player:hover::before { border-color: var(--blue); }

/* Column header: title + mass (mass stays blue on both sides per spec) */
.fleet-head { display: flex; justify-content: space-between; align-items: baseline; gap: 16px; margin-bottom: 14px; flex-shrink: 0; }
.fleet-title { font-size: 20px; letter-spacing: 1px; color: var(--txt); }
.fleet-mass  { font-size: 15px; letter-spacing: 1px; color: var(--blue); }

/* Fleet tile — big main showcase + small secondaries. Player = blue outline @20%, CPU = pink @20%. */
.fleet-tile {
  position: relative;
  background: transparent;             /* light, open feel — no fill */
  cursor: pointer;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  transition: border-color var(--t-med) var(--ease-out),
              box-shadow var(--t-med) var(--ease-out),
              transform var(--t-med) var(--ease-out),
              background-color var(--t-med) var(--ease-out);
}
.fleet-tile.main { flex: 1; min-height: 0; padding: 18px; overflow: hidden; }
.fleet-col.cpu .fleet-head { justify-content: flex-end; }                        /* "Player 2 (CPU)" right-aligned */
.fleet-tile.main .fleet-mass { position: absolute; bottom: 10px; z-index: 2; pointer-events: none; }
.fleet-tile.main.player .fleet-mass { right: 10px; }   /* inner-bottom (toward center) */
.fleet-tile.main.cpu    .fleet-mass { left: 10px; }    /* inner-bottom (toward center) */
.fleet-secondaries { display: flex; gap: 14px; margin-top: 14px; flex: 0 0 190px; }
.fleet-tile.secondary { flex: 1; padding: 12px; }

/* Fleet: 2×2 ship grid beside the full-height pilot — four equal, full-height tiles. */
.fleet-grid {
  flex: 1; min-height: 0; position: relative;
  display: grid; grid-template-columns: 1fr 1fr; grid-template-rows: 1fr 1fr; gap: 14px;
}
/* Total fleet mass on the header row (space-between puts it at the grid's outer edge). */
.fleet-head-mass { font-size: 13px; letter-spacing: 1px; color: var(--blue); }

.fleet-tile.player { border: 1px solid var(--player1-line); }   /* match the player pilot box */
.fleet-tile.cpu    { border: 1px solid var(--player2-line); }   /* match the CPU pilot box */
.fleet-tile.player:hover, .fleet-tile.player.open {
  border-color: var(--blue);
  box-shadow: var(--glow-blue);
  background: color-mix(in srgb, var(--blue) 5%, transparent);
}
.fleet-tile.cpu:hover, .fleet-tile.cpu.open {
  border-color: var(--pink);
  box-shadow: var(--glow-pink);
  background: color-mix(in srgb, var(--pink) 5%, transparent);
}
/* Big main tile lifts on hover; secondaries get a gentler nudge */
.fleet-tile.main:not(.stub):hover { transform: translateY(-3px); }
.fleet-tile.secondary:not(.stub):hover { transform: translateY(-2px); }
.fleet-tile.open { transform: none; }
.fleet-tile:not(.stub):active { transform: translateY(0) scale(0.995); }
.fleet-tile.stub { cursor: default; opacity: 0.5; }
.fleet-tile.stub:hover { border-color: color-mix(in srgb, var(--blue) 20%, transparent); transform: none; box-shadow: none; }

/* Every ship tile gets the faint blue grid backdrop from the ship builder (subtle
   gridlines behind the preview) — always present on main AND secondary tiles, filled
   or empty, so no box ever reads as an empty/black frame. */
.fleet-tile::before {
  content: '';
  position: absolute; inset: 0;
  background-image:
    repeating-linear-gradient(0deg,  transparent 0 21px, color-mix(in srgb, var(--player1-line) 11%, transparent) 21px 22px),
    repeating-linear-gradient(90deg, transparent 0 21px, color-mix(in srgb, var(--player1-line) 11%, transparent) 21px 22px);
  pointer-events: none;
  z-index: 0;
}
/* Player 2 (CPU) grid uses the pink/red of its outline (#990460) at low opacity. */
.fleet-tile.cpu::before {
  background-image:
    repeating-linear-gradient(0deg,  transparent 0 21px, color-mix(in srgb, var(--player2-line) 11%, transparent) 21px 22px),
    repeating-linear-gradient(90deg, transparent 0 21px, color-mix(in srgb, var(--player2-line) 11%, transparent) 21px 22px);
}
.fleet-tile > * { position: relative; z-index: 1; }   /* preview/name/mass/“+” above the grid */

/* Ship preview gently scales up when its tile is hovered — a touch of life */
.fleet-preview { display: block; width: 100%; flex: 1; min-height: 0;
  transition: transform var(--t-slow) var(--ease-out); }
.fleet-tile:not(.stub):hover .fleet-preview { transform: scale(1.04); }
.fleet-tile.secondary .fleet-preview { flex: 1; height: auto; }   /* catalog treatment: art fills + centers */
.fleet-name  { color: var(--txt); font-size: 18px; margin-top: 8px; }
.fleet-tile.secondary .fleet-name { font-size: 13px; margin-top: 6px; }
.fleet-class { color: var(--blue); font-size: 13px; letter-spacing: 1px; text-transform: uppercase; margin-top: 2px; opacity: 0.9; }
.fleet-tile.secondary .fleet-class { font-size: 10px; }
.fleet-stats { color: var(--blue-detail); font-size: 14px; margin-top: 4px; }
.fleet-tile.secondary .fleet-stats { font-size: 10px; }
/* CPU panel: right-justify the selected-ship name/stats so they don't collide with the
   inner-bottom-LEFT Total Ship Mass (player side stays left; its mass sits bottom-right). */
.fleet-tile.main.cpu .fleet-name,
.fleet-tile.main.cpu .fleet-class,
.fleet-tile.main.cpu .fleet-stats { text-align: right; }

.fleet-empty {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  color: color-mix(in srgb, var(--blue) 60%, transparent);
  font-size: 30px;
  font-weight: 300;
  transition: color var(--t-med) var(--ease-out), transform var(--t-med) var(--ease-out);
}
.fleet-tile.main .fleet-empty { font-size: 14px; letter-spacing: 3px; }
/* "[ SELECT A SHIP ]" — white in all states (overrides the per-side blue/pink tints incl. hover). */
.fleet-empty.big { color: #fff !important; }
.fleet-tile.cpu  .fleet-empty { color: color-mix(in srgb, var(--pink) 60%, transparent); }
.fleet-tile.player:not(.stub):hover .fleet-empty { color: var(--blue); transform: scale(1.08); }
.fleet-tile.cpu:not(.stub):hover .fleet-empty { color: var(--pink); transform: scale(1.08); }

.fleet-remove {
  position: absolute; top: 6px; right: 8px;
  background: transparent; border: none;
  color: var(--txt-faint); font-size: 16px; line-height: 1; cursor: pointer;
  transition: color var(--t-fast) var(--ease-out), transform var(--t-fast) var(--ease-out);
}
.fleet-remove:hover { color: var(--pink); transform: scale(1.2) rotate(90deg); }

/* START button (topbar center) + F1 hint */
#btn-start-battle {
  width: 300px; height: 64px;
  background: transparent;
  border: 1px solid var(--pink);
  color: var(--pink);
  font-family: var(--mono);
  font-size: 18px;
  letter-spacing: 3px;
  cursor: pointer;
  transition: background-color var(--t-fast) var(--ease-out),
              box-shadow var(--t-med) var(--ease-out),
              transform var(--t-fast) var(--ease-out),
              opacity var(--t-med) var(--ease-out);
}
/* Armed (enabled): a slow breathing glow draws the eye to the ready action. */
#btn-start-battle:not(:disabled) { animation: start-pulse 2.6s ease-in-out infinite; }
#btn-start-battle:not(:disabled):hover {
  background: color-mix(in srgb, var(--pink) 14%, transparent);
  box-shadow: var(--glow-pink);
  transform: translateY(-2px) scale(1.03);
  animation-play-state: paused;   /* hover takes over from the idle pulse */
}
#btn-start-battle:not(:disabled):active { transform: translateY(0) scale(0.98); }
#btn-start-battle:disabled { opacity: 0.35; cursor: default; }
#sel-hint { font-size: 14px; letter-spacing: 1px; color: var(--blue); }

/* ════ vs-page (#4) single-ship tiles: REUSE the shared .cap-tile / .ship-tile components ═══════════════
   The PvP/PvC vs-page builds the SAME tiles as the captain/ship-select screens (one source of truth in
   .cap-tile / .ship-tile above) — no bespoke frame/chamfer/grid here. These rules only POSITION the fixed
   320×696 tiles in their flex column and suppress the carousel fly-in (renderAll rebuilds on every pick). */
#selection-screen .fleet-main-row.vs-single { align-items: center; justify-content: center; }
#selection-screen .fleet-main-row.vs-single .cap-tile,
#selection-screen .fleet-main-row.vs-single .ship-tile {
  animation: none; opacity: 1;   /* no slide-in: these are rebuilt frequently by renderAll */
}
/* Empty-state prompts (no captain / no ship picked yet) — centered text in the bare frame. */
#selection-screen .cap-tile.cap-empty .cap-tile-text,
#selection-screen .ship-tile.ship-empty .st-name {
  position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; text-align: center;
  left: 0; right: 0; top: 0; color: #0087bd; letter-spacing: 2px;
}

/* Vs badge — WIDE flat hexagon, 1px blue stroke, transparent interior (SVG outline, 1:1 so the stroke
   stays a uniform 1px). Centered between the two columns. */
#vs-badge {
  align-self: center; flex: 0 0 auto; margin: 0 12px;   /* 12px to the ship tile on each side */
  display: flex; align-items: center; justify-content: center;
  width: 168px; height: 64px;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 168 64' preserveAspectRatio='none'%3E%3Cpolygon points='20,1 148,1 167,32 148,63 20,63 1,32' fill='none' stroke='%230087bd' stroke-width='1'/%3E%3C/svg%3E") no-repeat center / 100% 100%;
  color: #fff; font: 700 22px var(--mono); letter-spacing: 1px;
  opacity: 0;   /* hidden until the clash apex (JS adds .clash-in) */
}
#vs-badge.clash-in { animation: vs-badge-pop 0.42s cubic-bezier(.2,1.5,.4,1) both; }
@keyframes vs-badge-pop { 0% { opacity: 0; transform: scale(0.35); } 60% { opacity: 1; } 100% { opacity: 1; transform: scale(1); } }

/* Battle intro: full-screen dissolve to/from black + the BEGIN title (created on START, removed after). */
#battle-fade {
  position: absolute; inset: 0; z-index: 200; background: #000; opacity: 0; pointer-events: none;
  transition: opacity 0.6s ease;
}
#battle-fade.to-black { opacity: 1; }
#begin-title {
  position: absolute; inset: 0; z-index: 210; display: flex; align-items: center; justify-content: center;
  font: 700 48px 'Fira Mono', ui-monospace, monospace; letter-spacing: 12px; color: #fff;
  text-shadow: 0 0 34px rgba(0,135,189,0.85); opacity: 0; pointer-events: none;
}
/* Fades IN as it grows, then fades OUT still growing — one continuous zoom. */
#begin-title.show { animation: begin-anim 2.6s ease-out forwards; }
@keyframes begin-anim {
  0%   { opacity: 0; transform: scale(0.7); }
  22%  { opacity: 0.7; }
  85%  { opacity: 0.7; }
  100% { opacity: 0; transform: scale(1.3); }
}

/* Bottom bar: START (center) + hint + Cancel. */
#sel-bottom {
  flex-shrink: 0; display: flex; flex-direction: column; align-items: center; gap: 8px;
  margin-top: 18px; animation: sel-fade-up 0.6s var(--ease-out) 0.28s both;
}
#sel-cancel {
  background: 0; border: 0; color: var(--blue); font: 400 16px var(--mono); letter-spacing: 2px; cursor: pointer;
  transition: color var(--t-fast) var(--ease-out);
}
#sel-cancel:hover { color: #19b6ef; }

/* START → button_start.svg with a ready-glow that hugs the SHAPE (filter drop-shadow follows the SVG's
   alpha, NOT a rectangular box-shadow around the element). */
@keyframes start-pulse-blue {
  0%, 100% { filter: drop-shadow(0 0 1px rgba(0,135,189,0.25)); }
  50%      { filter: drop-shadow(0 0 12px rgba(0,135,189,0.85)); }
}
#selection-screen #btn-start-battle {
  width: 360px; height: 98px; border: 0; clip-path: none; box-shadow: none;   /* 459×125 SVG @ ~0.78 */
  background: url(/assets/ui/button_start.svg) no-repeat center / 100% 100%;
  color: #fff; font: 700 28px 'Fira Mono', ui-monospace, monospace; letter-spacing: 4px;
}
#selection-screen #btn-start-battle:not(:disabled) { animation: start-pulse-blue 2.6s ease-in-out infinite; }
#selection-screen #btn-start-battle:not(:disabled):hover {
  background: url(/assets/ui/button_start.svg) no-repeat center / 100% 100%;
  box-shadow: none; filter: drop-shadow(0 0 16px rgba(0,135,189,0.95));   /* glow on the shape */
}

/* Labels ("Player 1" / "Player 2 (CPU)") align above their tile pairs: size the columns to content and
   center the [player | Vs | cpu] group, so each header sits directly over its captain+ship pair. */
#selection-screen:not(.mode-fleet) #sel-columns { justify-content: center; gap: 0; }
#selection-screen:not(.mode-fleet) .fleet-col { flex: 0 0 auto; }

/* CPU (Player 2) tiles are auto-picked → not selectable: no hover lift / white outline, default cursor. */
#selection-screen .cap-tile:disabled, #selection-screen .ship-tile:disabled { cursor: default; }
#selection-screen .cap-tile:disabled:hover, #selection-screen .ship-tile:disabled:hover { transform: none; }
#selection-screen .cap-tile:disabled:hover::before, #selection-screen .ship-tile:disabled:hover::before { background: #0087bd; }

/* Player 2 (CPU) tiles MIRROR the chamfer to the TOP-RIGHT (symmetric with P1's top-left). Interior +
   video clips use the mirrored polygon; the frame mask flips via scaleX(-1); the class/template tags move
   to the left corner so they clear the cut. */
#cpu-col .cap-tile::after, #cpu-col .ship-tile::after {
  clip-path: polygon(0 0, 90.93% 0, 100% 4.79%, 100% 100%, 0 100%);
}
/* Mirrored frame via a flipped MASK (not transform: scaleX(-1) — that flipped back during the fly-in
   animation's compositing, so the chamfer read as left). Path is the original mirrored x→320−x. */
#cpu-col .cap-tile::before, #cpu-col .ship-tile::before {
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 320 696'%3E%3Cpath d='M0.5 0.5V695.5H319.5V33.3057L290.9648 0.5H0.5Z' fill='none' stroke='%230087BD'/%3E%3C/svg%3E") no-repeat center / 100% 100%;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 320 696'%3E%3Cpath d='M0.5 0.5V695.5H319.5V33.3057L290.9648 0.5H0.5Z' fill='none' stroke='%230087BD'/%3E%3C/svg%3E") no-repeat center / 100% 100%;
}
#cpu-col .cap-tile-video { clip-path: polygon(0 0, 90.93% 0, 100% 4.79%, 100% 100%, 0 100%); }
#cpu-col .ship-tile .st-class, #cpu-col .ship-tile .st-template { right: auto; left: 16px; }

/* vs-page reveal: the four tiles RUSH in from off-screen (player from the LEFT, CPU from the RIGHT),
   overshoot toward center (the "clash"), then spring back. opacity held at the late keyframes so the
   filled end-state doesn't blink (it's cleared on animationend in JS so hover-scale still works). */
@keyframes vs-fly-left {
  0%   { opacity: 0; transform: translateX(-120vw); }
  60%  { opacity: 1; }
  78%  { opacity: 1; transform: translateX(40px); }
  100% { opacity: 1; transform: translateX(0); }
}
@keyframes vs-fly-right {
  0%   { opacity: 0; transform: translateX(120vw); }
  60%  { opacity: 1; }
  78%  { opacity: 1; transform: translateX(-40px); }
  100% { opacity: 1; transform: translateX(0); }
}
/* Clash flash — white wash + light bloom, clipped to the tile chamfer, fades out. */
.vs-flare {
  position: absolute; inset: 0; z-index: 3; pointer-events: none; background: #eaf4ff;
  clip-path: polygon(9.07% 0, 100% 0, 100% 100%, 0 100%, 0 4.79%);
  animation: vs-flare-anim 0.42s ease-out;
}
@keyframes vs-flare-anim { 0% { opacity: 0; } 22% { opacity: 0.7; } 100% { opacity: 0; } }

/* Game-mode selector (PvP / Fleet) — sits above START. */
/* Mode toggle lives in the top bar (left of Ship Builder). It's a bare segmented container —
   neutralize the #sel-topbtns > * button chrome on the WRAPPER so only the tabs are styled. */
/* Legacy PvP/Fleet tabs — HIDDEN (mode is chosen on the front page now). Kept in the DOM because the
   front-page Arcade/Fleet buttons set the mode by programmatically .click()-ing these (fires even when
   display:none), and initSelectionScreen wires setMode to them. */
#mode-select { display: none; }
#sel-topbtns > #mode-select { padding: 0; border: none; background: transparent; box-shadow: none; }
#sel-topbtns > #mode-select:hover { transform: none; box-shadow: none; background: transparent; }
.mode-tab {
  background: transparent;
  border: 1px solid color-mix(in srgb, var(--blue) 50%, transparent);
  color: var(--blue);
  font-family: var(--mono);
  font-size: 14px; letter-spacing: 1px;
  padding: 12px 18px; cursor: pointer;   /* match the height of the top-bar buttons */
  transition: background-color var(--t-fast) var(--ease-out), color var(--t-fast) var(--ease-out);
}
.mode-tab:first-child { border-right: none; }
.mode-tab:hover { background: color-mix(in srgb, var(--blue) 12%, transparent); }
.mode-tab.active {
  background: color-mix(in srgb, var(--blue) 22%, transparent);
  color: var(--txt);
  box-shadow: inset 0 -2px 0 var(--blue);
}

/* ── Design card list / grid (reused by the picker) ──────────────────── */
.sel-list { overflow-y: auto; min-height: 0; }
.sel-list::-webkit-scrollbar { width: 3px; }
.sel-list::-webkit-scrollbar-track { background: transparent; }
.sel-list::-webkit-scrollbar-thumb { background: var(--line); border-radius: 2px; }

.design-grid {
  display: grid !important;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: 260px;          /* FIXED card height — rows don't stretch to fill the sheet */
  align-content: start;           /* pack rows at the top instead of stretching them */
  gap: 16px;
}

/* ── Slide-in ship picker (anchored left for P1, right for P2) ────────── */
.pick-sheet {
  position: absolute;
  bottom: 0;
  width: 46%;
  height: 92%;
  background: transparent;             /* not darkened — cards float over the dimmed screen */
  border: none;
  box-sizing: border-box;
  padding: 28px 32px;
  z-index: 30;
  display: flex;
  flex-direction: column;
  transform: translateY(105%);
  transition: transform 0.5s cubic-bezier(0.22, 1.18, 0.36, 1);   /* ease-out, gentle spring */
  pointer-events: none;
}
.pick-sheet.left  { left: 0; }
.pick-sheet.right { right: 0; }
.pick-sheet.open  { transform: translateY(0); pointer-events: auto; }

.pick-head { display: flex; align-items: center; gap: 18px; margin-bottom: 22px; flex-shrink: 0; }
.pick-title { font-size: 22px; color: var(--txt); }
.pick-mass  { font-size: 15px; color: var(--blue); }
.pick-remove {
  margin-left: auto;                 /* push to the right, next to the close × */
  background: transparent;
  border: 1px solid color-mix(in srgb, var(--err) 55%, transparent);
  color: var(--err);
  font-family: var(--mono); font-size: 12px; letter-spacing: 1px;
  padding: 6px 12px; cursor: pointer;
  transition: background-color var(--t-fast) var(--ease-out), color var(--t-fast) var(--ease-out);
}
.pick-remove:hover { background: color-mix(in srgb, var(--err) 18%, transparent); color: var(--txt); }
.pick-close {
  margin-left: auto;
  background: transparent; border: none;
  color: var(--blue); font-size: 32px; line-height: 1; cursor: pointer;
  transition: color var(--t-fast) var(--ease-out), transform var(--t-fast) var(--ease-out);
}
.pick-close:hover { color: var(--txt); transform: rotate(90deg) scale(1.1); }
.pick-close:active { transform: rotate(90deg) scale(0.95); }

/* Picker tabs — Templates (built-ins) / Custom (user designs). */
.pick-tabs { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 16px; flex-shrink: 0; }
.pick-tab {
  background: transparent; border: 1px solid var(--line); color: var(--txt-dim);
  font-family: var(--mono); font-size: 12px; letter-spacing: 1px; padding: 6px 14px; cursor: pointer;
  transition: color var(--t-fast) var(--ease-out), border-color var(--t-fast) var(--ease-out), box-shadow var(--t-fast) var(--ease-out);
}
.pick-tab:hover  { color: var(--txt); }
.pick-tab.active { color: var(--txt); border-color: var(--blue); box-shadow: var(--glow-blue); }
.pick-empty { color: var(--txt-dim); font-size: 13px; padding: 20px; grid-column: 1 / -1; }

.pick-sheet .sel-list { flex: 1; }
.pick-sheet .design-item.selected { border-color: var(--txt); box-shadow: inset 0 0 0 1px var(--txt), var(--glow-accent); }


/* Picker header + cards fade/rise in just after the sheet finishes sliding up, so the
   content arrives a beat after the panel — a layered, deliberate reveal. */
.pick-sheet .pick-head,
.pick-sheet .design-item { opacity: 0; }
.pick-sheet.open .pick-head { animation: sel-fade-up 0.4s var(--ease-out) 0.18s both; }
.pick-sheet.open .design-item { animation: sel-fade-up 0.42s var(--ease-out) both; }
/* Gentle per-card stagger (cap the delay so large rosters don't drag). */
.pick-sheet.open .design-item:nth-child(1) { animation-delay: 0.22s; }
.pick-sheet.open .design-item:nth-child(2) { animation-delay: 0.26s; }
.pick-sheet.open .design-item:nth-child(3) { animation-delay: 0.30s; }
.pick-sheet.open .design-item:nth-child(4) { animation-delay: 0.34s; }
.pick-sheet.open .design-item:nth-child(5) { animation-delay: 0.38s; }
.pick-sheet.open .design-item:nth-child(6) { animation-delay: 0.42s; }
.pick-sheet.open .design-item:nth-child(n+7) { animation-delay: 0.46s; }

/* ============ 4. PAGE: BUILDER (ship builder — ship-builder.html) ============ */
body.page-builder { margin: 0; background: var(--bg); color: var(--txt); font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; font-size: 12px; overflow: hidden; user-select: none; -webkit-font-smoothing: antialiased; }
.page-builder canvas { display: block; cursor: crosshair; }

/* Receding parallax space background — full-window, behind the builder work surface + UI.
   The main #canvas clears (transparent) each frame, so the bg shows through; panels sit at z6+. */
.page-builder #builder-bg {
  position: fixed; inset: 0; width: 100vw; height: 100vh;
  z-index: 0; pointer-events: none; cursor: default;
}
/* Faint dark scrim over the bg so the parallax doesn't fight the grid (work surface). */
.page-builder #builder-scrim {
  position: fixed; inset: 0; z-index: 1; pointer-events: none;
  background: rgba(5, 8, 16, 0.45);   /* ALPHA: backdrop dimming for grid readability */
}
/* Work surface sits above the bg + scrim; it clears transparent each frame so the bg shows. */
.page-builder #canvas { position: relative; z-index: 2; background: transparent; }

/* Builder entrance — same restrained vocabulary as the selection screen.
   The left command column slides in from the edge; the right inspector and the
   canvas surface fade up, lightly staggered. backwards keeps them hidden pre-delay. */
.page-builder #leftcol { animation: sel-fade-left 0.6s var(--ease-out) 0.06s both; }
.page-builder #canvas  { animation: sel-fade-up   0.65s var(--ease-out) 0.14s both; }
/* No entrance fade on the catalog popup — it's a tool tray that toggles open and must be
   INSTANTLY available (the fade re-triggered on every display none→flex toggle). */

#leftcol {
  position: absolute; top: 14px; left: 14px; bottom: 14px; width: 320px;
  /* standardized blue panel asset (panel-simple.svg), 9-sliced (rx=6) — matches the info panel */
  border: 6px solid transparent;
  border-image: url(/assets/ui/panel-simple.svg) 6 fill / 6px stretch;
  -webkit-backdrop-filter: blur(5px) saturate(1.3); backdrop-filter: blur(5px) saturate(1.3);   /* iOS-style frosted glass behind the translucent panel */
  z-index: 6;
  display: flex; flex-direction: column;
}
#left-top { display: flex; gap: 10px; padding: 14px; border-bottom: 1px solid var(--line-soft); }
#btn-back {
  display: flex; align-items: center; justify-content: center; width: 38px; flex-shrink: 0;
  background: transparent; border: 1px solid var(--line); color: var(--txt-dim); font-size: 18px; text-decoration: none; line-height: 1;
  transition: border-color var(--t-fast) var(--ease-out), color var(--t-fast) var(--ease-out), transform var(--t-fast) var(--ease-out);
}
#btn-back:hover { border-color: var(--accent); color: var(--accent-bright); transform: translateX(-2px); }
#name-box { flex: 1; border: 1px solid var(--line); padding: 5px 10px; }
#name-box label { display: block; color: var(--txt-faint); font-size: 9px; letter-spacing: 2px; text-transform: uppercase; }
#input-design-name { width: 100%; background: transparent; color: var(--txt); border: none; font-family: inherit; font-size: 14px; outline: none; padding: 2px 0; }

#left-tabs { display: flex; gap: 4px; padding: 12px 12px 0; }
.lc-tab { background: transparent; border: 1px solid transparent; border-bottom: none; color: var(--txt-faint); font-family: inherit; font-size: 12px; padding: 9px 14px; cursor: pointer; transition: color var(--t-fast) var(--ease-out), border-color var(--t-fast) var(--ease-out); }
.lc-tab:hover { color: var(--txt-dim); }
.lc-tab.active { border-color: var(--line); color: var(--txt); }
#left-body { flex: 1; min-height: 0; padding: 14px; display: flex; flex-direction: column; border-top: 1px solid var(--line); margin-top: -1px; }
.lc-panel { display: none; }
@keyframes panel-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
.lc-panel.active { display: flex; flex-direction: column; flex: 1; min-height: 0; overflow-y: auto; scrollbar-width: thin; scrollbar-color: var(--line) transparent; animation: panel-in 0.22s var(--ease-out) both; }
.lc-panel.active::-webkit-scrollbar { width: 5px; }
.lc-panel.active::-webkit-scrollbar-thumb { background: var(--line); border-radius: 3px; }

#left-controls { padding: 14px; border-top: 1px solid var(--line-soft); display: flex; flex-direction: column; gap: 12px; }
.lc-build-row { display: flex; gap: 8px; align-items: center; }
.lc-build-row button { background: transparent; border: 1px solid var(--line); color: var(--txt-dim); font-family: inherit; font-size: 11px; padding: 7px 14px; cursor: pointer; letter-spacing: 1px; transition: border-color var(--t-fast) var(--ease-out), color var(--t-fast) var(--ease-out), background-color var(--t-fast) var(--ease-out), transform var(--t-fast) var(--ease-out); }
.lc-build-row button:hover { border-color: var(--accent); color: var(--txt); }
.lc-build-row button:not(:disabled):active { transform: scale(0.95); }
.lc-build-row button:disabled { opacity: 0.4; cursor: default; }
#mode-build.active, #mode-test.active { border-color: var(--accent); color: var(--accent-bright); }
#btn-clear { margin-left: auto; }
.lc-save-row { display: flex; gap: 10px; }
#btn-save { flex: 1; background: #342a52; border: 1px solid #4f4080; color: #ddd2f2; font-family: inherit; font-size: 12px; padding: 11px; cursor: pointer; letter-spacing: 1px; transition: background-color var(--t-fast) var(--ease-out), border-color var(--t-fast) var(--ease-out), box-shadow var(--t-med) var(--ease-out), transform var(--t-fast) var(--ease-out); }
#btn-save:hover { background: #3f3463; border-color: #61509a; box-shadow: var(--glow-accent); transform: translateY(-1px); }
#btn-save:active { transform: translateY(0) scale(0.98); }
#btn-save-as { flex: 1; background: transparent; border: 1px solid var(--line); color: var(--txt-dim); font-family: inherit; font-size: 12px; padding: 11px; cursor: pointer; letter-spacing: 1px; transition: border-color var(--t-fast) var(--ease-out), color var(--t-fast) var(--ease-out), transform var(--t-fast) var(--ease-out); }
#btn-save-as:hover { border-color: var(--accent); color: var(--txt); }
#btn-save-as:active { transform: scale(0.98); }
.lc-io-row { display: flex; justify-content: space-between; align-items: baseline; gap: 6px; }
#btn-load, #btn-export, #btn-save-template { flex: 0 0 auto; white-space: nowrap; background: transparent; border: none; color: var(--txt-dim); font-family: inherit; font-size: 11px; cursor: pointer; padding: 2px; letter-spacing: 1px; transition: color var(--t-fast) var(--ease-out); }
#btn-load:hover, #btn-export:hover, #btn-save-template:hover { color: var(--accent-bright); }

#saved-items { overflow-y: auto; scrollbar-width: thin; scrollbar-color: var(--line) transparent; }
#saved-items::-webkit-scrollbar { width: 5px; }
#saved-items::-webkit-scrollbar-thumb { background: var(--line); border-radius: 3px; }
.saved-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 10px 4px; cursor: pointer; border-bottom: 1px solid var(--line-soft); transition: background-color var(--t-fast) var(--ease-out), padding-left var(--t-fast) var(--ease-out); }
.saved-row:hover { background: color-mix(in srgb, var(--accent) 5%, transparent); padding-left: 8px; }
.saved-row:hover .saved-name { color: var(--txt); }
.saved-row.active .saved-name { color: var(--accent-bright); }
.saved-name { color: var(--txt-dim); font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; transition: color var(--t-fast) var(--ease-out); }
.saved-del { background: transparent; border: none; color: var(--txt-faint); font-family: inherit; font-size: 14px; cursor: pointer; padding: 0 4px; line-height: 1; }
.saved-del:hover { color: var(--err); }
.saved-empty { color: var(--txt-faint); font-size: 11px; padding: 14px 4px; letter-spacing: 1px; }

#hud { padding: 0; font-family: var(--mono); }
#hud h1 { margin: 0 0 8px; font-size: 11px; color: var(--accent); letter-spacing: 2px; font-weight: normal; }
#hud h2 { margin: 14px 0 5px; font-size: 10px; color: var(--accent); letter-spacing: 2px; font-weight: normal; text-transform: uppercase; }
.stat { display: flex; justify-content: space-between; padding: 2px 0; font-size: 12px; }
.stat .label { color: var(--txt-dim); }
.stat .value { color: var(--txt); }
.ok { color: var(--ok); } .warn { color: var(--warn); } .err { color: var(--err); }

/* Component catalog — CONTEXTUAL POPUP shown only while a category is open, left of the rail. */
#palette {
  position: absolute; top: 18px; right: 86px; width: 320px; max-height: calc(100vh - 36px);
  border: 6px solid transparent;
  border-image: url(/assets/ui/panel-simple.svg) 6 fill / 6px stretch;
  -webkit-backdrop-filter: blur(5px) saturate(1.3); backdrop-filter: blur(5px) saturate(1.3);   /* iOS-style frosted glass behind the translucent panel */
  flex-direction: column; z-index: 7;
}
#palette-title { padding: 12px 14px 6px; font-size: 16px; color: var(--txt); }

/* Zoom readout + step buttons — bottom-left, just right of the stats panel (matches the comp;
   clears the catalog popup which now occupies the top-right). */
#zoom-ctl {
  position: absolute; bottom: 14px; left: 348px; z-index: 6;
  display: flex; align-items: center; gap: 8px;
  background: var(--panel); border: 1px solid var(--line);
  padding: 5px 9px; font-family: var(--mono); font-size: 12px; color: var(--txt);
}
#zoom-ctl button {
  width: 22px; height: 22px; line-height: 1;
  background: transparent; border: 1px solid var(--line); color: var(--txt-dim);
  font-size: 15px; cursor: pointer;
  transition: color var(--t-fast) var(--ease-out), border-color var(--t-fast) var(--ease-out);
}
#zoom-ctl button:hover { color: var(--txt); border-color: var(--txt-dim); }
#zoom-pct { min-width: 44px; text-align: center; letter-spacing: 0.5px; }

/* RIGHT-EDGE icon rail — skin toggle (top) + circular category badges. */
#palette-tabs {
  position: absolute; right: 16px; top: 20px; z-index: 8;
  display: flex; flex-direction: column; gap: 14px;
}
.ptab {
  width: 52px; height: 52px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center; cursor: pointer;
  transition: transform var(--t-fast) var(--ease-out), box-shadow var(--t-med) var(--ease-out);
}
.ptab-icon { width: 50px; height: 50px; opacity: 0.85; transition: opacity var(--t-fast) var(--ease-out); }
.ptab:hover { transform: scale(1.06); }
.ptab:hover .ptab-icon  { opacity: 1; }
.ptab.active .ptab-icon { opacity: 1; }
.ptab.active { box-shadow: 0 0 0 2px #fff, 0 0 12px -2px color-mix(in srgb, var(--blue) 70%, transparent); }
.ptab.skin-toggle { overflow: hidden; background: #0a0e16; }
.ptab.skin-toggle .skin-swatch { width: 48px; height: 48px; }
.skin-swatch { display: block; border-radius: 50%; }

/* Skin chooser popup — left of the rail, near the top. */
#skin-popup {
  position: absolute; right: 86px; top: 20px; width: 210px; z-index: 7;
  border: 6px solid transparent;
  border-image: url(/assets/ui/panel-simple.svg) 6 fill / 6px stretch;
  -webkit-backdrop-filter: blur(5px) saturate(1.3); backdrop-filter: blur(5px) saturate(1.3);   /* iOS-style frosted glass behind the translucent panel */
  flex-direction: column; gap: 2px; padding: 10px;
}
.skin-row { display: flex; align-items: center; gap: 12px; padding: 6px 8px; border-radius: 6px; cursor: pointer; transition: background var(--t-fast) var(--ease-out); }
.skin-row:hover { background: color-mix(in srgb, var(--blue) 12%, transparent); }
.skin-row .skin-swatch { width: 30px; height: 30px; border: 1px solid var(--line); flex: 0 0 auto; }
.skin-row.active .skin-swatch { box-shadow: 0 0 0 2px #fff; }
.skin-row-label { color: var(--txt); font-size: 13px; }

#palette-detail { flex: 1; overflow-y: auto; padding: 4px 12px 12px; scrollbar-width: thin; scrollbar-color: var(--line) transparent; }
#palette-detail::-webkit-scrollbar { width: 5px; }
#palette-detail::-webkit-scrollbar-thumb { background: var(--line); border-radius: 3px; }
.palette-section h3 { margin: 10px 0 6px; font-size: 9px; color: var(--txt-faint); text-transform: uppercase; letter-spacing: 2px; font-weight: normal; }

/* Single-column horizontal cards — art (left) + name/meta (right). */
.palette-grid { display: flex; flex-direction: column; gap: 6px; }
.palette-item {
  padding: 8px; cursor: pointer; border-radius: 4px;
  border: 1px solid var(--line-soft); background: transparent;
  display: flex; flex-direction: row; align-items: center; gap: 12px;
  transition: border-color var(--t-fast) var(--ease-out),
              background-color var(--t-fast) var(--ease-out),
              box-shadow var(--t-med) var(--ease-out),
              transform var(--t-fast) var(--ease-out);
}
.palette-item:hover    { border-color: var(--line); background: color-mix(in srgb, var(--blue) 8%, transparent); }
.palette-item.selected { border-color: var(--blue); background: color-mix(in srgb, var(--blue) 14%, transparent); box-shadow: var(--glow-blue); }
.palette-item:active   { transform: scale(0.98); }
.palette-item.disabled { opacity: 0.3; cursor: not-allowed; pointer-events: none; }
.palette-item .pthumb  { width: 44px; height: 44px; flex: 0 0 auto; background: transparent; display: block; image-rendering: pixelated; }
.pinfo { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.palette-item .pname   { color: var(--txt); font-size: 12px; line-height: 1.25; }
.palette-item .pmeta   { color: var(--txt-dim); font-size: 10px; line-height: 1.4; }
.palette-item .pmeta .accent { color: var(--accent); }
.palette-item .pmeta .pstat  { color: var(--blue-detail); }   /* per-category headline stat */

/* Inset floating panel (8px margin) with a slightly lighter bg + full border so it reads
   as distinct from / in front of the tab rail, not part of it. Height-capped so a long
   stat list scrolls internally instead of starving the tabs (which caused the vertical
   tab labels to overflow into this area). #16141e keeps --txt-faint ~4.7:1 (WCAG AA). */
/* Component info panel — background is the panel-simple.svg asset, 9-sliced (rx=6) so the
   rounded #177BCF panel scales to any height. Hidden entirely when nothing is selected. */
#selection-info {
  /* FLOATING dialog — flush bottom-right corner, 12px from the right + bottom edges. */
  position: absolute; right: 12px; bottom: 12px; width: 320px; z-index: 7;
  padding: 14px;
  border: 6px solid transparent;
  border-image: url(/assets/ui/panel-simple.svg) 6 fill / 6px stretch;
  -webkit-backdrop-filter: blur(5px) saturate(1.3); backdrop-filter: blur(5px) saturate(1.3);   /* iOS-style frosted glass behind the translucent panel */
  max-height: 60vh; overflow-y: auto;
  scrollbar-width: thin; scrollbar-color: var(--line) transparent;
  transition: box-shadow var(--t-med) var(--ease-out);
}
#selection-info::-webkit-scrollbar { width: 5px; }
#selection-info::-webkit-scrollbar-thumb { background: var(--line); border-radius: 3px; }
#selection-info[data-flash] { box-shadow: var(--glow-accent); }

/* Header — art · name+type · CT badge. Blue accents to match the panel-simple.svg (#177BCF). */
.si-header { display: flex; align-items: center; gap: 10px; }
.si-art { width: 44px; height: 44px; flex: 0 0 auto; }
.si-title { flex: 1; min-width: 0; }
@keyframes name-in { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
#selected-name { color: var(--txt); font-size: 15px; animation: name-in 0.2s var(--ease-out); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.si-type { color: var(--blue-detail); font-size: 11px; margin-top: 2px; }
.si-ct { flex: 0 0 auto; align-self: flex-start; color: var(--blue-detail); font-size: 12px;
  border: 1px solid color-mix(in srgb, var(--blue) 60%, transparent); border-radius: 6px; padding: 5px 10px;
  background: color-mix(in srgb, var(--blue) 10%, transparent); white-space: nowrap; }

.si-divider { height: 1px; background: var(--line); margin: 10px 0; }

/* Two stat columns — general (left, icon gutter) · unique (right) */
.si-stats { display: flex; gap: 16px; }
.si-col { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 6px; }
.si-stat { display: flex; align-items: center; gap: 4px; font-size: 12px; color: var(--txt); }
.si-k { color: var(--txt-dim); }
.si-v { color: var(--txt); }
.si-ico-slot { flex: 0 0 16px; width: 16px; display: inline-flex; align-items: center; }
.si-ico { width: 13px; height: 13px; color: var(--blue-detail); }

/* Footer — facing arrow · rotate/flip buttons · footprint */
.si-footer { display: flex; align-items: center; gap: 7px; }
.si-facing { color: var(--txt-dim); font-size: 12px; display: inline-block; width: 16px; text-align: center; transition: transform var(--t-fast) var(--ease-out); }
.si-spacer { flex: 1; }
.si-footprint { color: var(--txt-dim); font-size: 12px; display: inline-flex; align-items: center; gap: 5px; }
.si-fp-ico { width: 15px; height: 15px; color: var(--blue-detail); }
#orient-controls button {
  display: inline-flex; align-items: center; justify-content: center; min-width: 28px; height: 28px;
  background: color-mix(in srgb, var(--blue) 10%, transparent); color: var(--blue-detail);
  border: 1px solid color-mix(in srgb, var(--blue) 55%, transparent); border-radius: 6px;
  font-size: 13px; cursor: pointer;
  transition: border-color var(--t-fast) var(--ease-out), color var(--t-fast) var(--ease-out), background var(--t-fast) var(--ease-out), transform var(--t-fast) var(--ease-out); }
#orient-controls button:hover { border-color: var(--blue); color: #fff; background: color-mix(in srgb, var(--blue) 22%, transparent); }
#orient-controls button:active { transform: scale(0.88); }
.hint { color: var(--txt-faint); font-size: 10px; margin-top: 8px; font-style: italic; font-family: var(--mono); }
/* Selected-component flavor/description in the builder info box */
.comp-desc { color: var(--txt-dim); font-size: 11px; line-height: 1.45; font-style: italic; }

/* Builder-specific .design-* extension (delete button on saved designs) */
.design-del { position: absolute; top: 6px; right: 6px; background: rgba(6,6,12,0.7); border: 1px solid var(--line); color: var(--txt-faint); font-family: inherit; font-size: 12px; cursor: pointer; padding: 1px 7px; line-height: 1.4; }
.design-del:hover { color: var(--err); border-color: var(--err); }

/* ============ 5. SETTINGS DIALOG (launch screen — index.html) ============ */
/* Centered sci-fi modal over a dimmed backdrop. Open/close animated via the
   shared motion tokens; reduced-motion users get the same states sans movement. */
.settings-overlay {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--bg) 78%, transparent);
  z-index: 90;   /* global modal — above the nav (70) + all screens */
  animation: settings-fade var(--t-med) var(--ease-out) both;
  pointer-events: auto;
}
/* [hidden] must beat the display:flex above — otherwise the class's display overrides the UA
   [hidden]{display:none} rule, so the dialog showed on load AND overlay.hidden=true couldn't close it. */
.settings-overlay[hidden] { display: none; pointer-events: none; }
.settings-overlay.closing { animation: settings-fade var(--t-fast) var(--ease-out) reverse forwards; pointer-events: none; }

.settings-modal {
  width: 460px; max-width: 90%;
  background: var(--panel);
  border: 1px solid color-mix(in srgb, var(--blue) 35%, var(--line));
  box-shadow: var(--glow-blue), 0 24px 60px -20px rgba(0,0,0,0.8);
  padding: var(--dialog-pad);
  color: var(--txt);
  font-family: var(--mono);
  animation: settings-pop var(--t-med) var(--ease-spring) both;
}
.settings-overlay.closing .settings-modal { animation: settings-pop var(--t-fast) var(--ease-out) reverse forwards; }

@keyframes settings-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes settings-pop  { from { opacity: 0; transform: translateY(10px) scale(0.96); } to { opacity: 1; transform: none; } }

.settings-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--dialog-gap); }
.settings-title {
  font-family: var(--logo-font); font-size: 18px; letter-spacing: 3px; text-transform: uppercase;
  color: var(--blue); text-shadow: 0 0 14px color-mix(in srgb, var(--blue) 45%, transparent);
}
.settings-close {
  background: rgba(0,0,0,0.4); border: 1px solid var(--line); color: var(--txt-dim);
  font-family: inherit; font-size: 18px; line-height: 1; cursor: pointer;
  width: 28px; height: 28px; padding: 0;
  transition: border-color var(--t-fast) var(--ease-out), color var(--t-fast) var(--ease-out), transform var(--t-fast) var(--ease-out);
}
.settings-close:hover { border-color: var(--pink); color: var(--pink); }
.settings-close:active { transform: scale(0.9); }

.settings-section {
  padding: 14px 0;
  border-top: 1px solid var(--line-soft);
}
.settings-section:first-of-type { border-top: none; padding-top: 4px; }

.settings-row { display: flex; align-items: center; justify-content: space-between; gap: 14px; }
.settings-label { font-size: 13px; letter-spacing: 1px; color: var(--txt); }

.settings-mute {
  background: rgba(0,0,0,0.4); border: 1px solid var(--line); color: var(--txt-dim);
  font-family: inherit; font-size: 11px; letter-spacing: 1px; cursor: pointer;
  padding: var(--btn-pad-y) var(--btn-pad-x); min-width: 78px;
  transition: border-color var(--t-fast) var(--ease-out), color var(--t-fast) var(--ease-out),
              background-color var(--t-fast) var(--ease-out);
}
.settings-mute:hover { border-color: var(--blue); color: var(--blue); }
.settings-mute.muted { border-color: var(--pink); color: var(--pink); background: color-mix(in srgb, var(--pink) 8%, transparent); }

.settings-slider-row { display: flex; align-items: center; gap: 12px; margin-top: 12px; }
.settings-pct { font-size: 12px; color: var(--blue-detail); min-width: 38px; text-align: right; }

/* Range slider — themed to the brand blue across engines. */
.settings-slider {
  -webkit-appearance: none; appearance: none;
  flex: 1; height: 4px; background: var(--line); border-radius: 2px; outline: none; cursor: pointer;
}
.settings-slider::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 14px; height: 14px; border-radius: 50%;
  background: var(--blue); border: none; cursor: pointer;
  box-shadow: 0 0 8px -1px color-mix(in srgb, var(--blue) 70%, transparent);
  transition: transform var(--t-fast) var(--ease-out);
}
.settings-slider::-webkit-slider-thumb:hover { transform: scale(1.2); }
.settings-slider::-moz-range-thumb {
  width: 14px; height: 14px; border-radius: 50%;
  background: var(--blue); border: none; cursor: pointer;
  box-shadow: 0 0 8px -1px color-mix(in srgb, var(--blue) 70%, transparent);
}
.settings-slider:focus-visible { box-shadow: var(--glow-blue); }

/* Segmented Auto/Manual toggle */
.settings-segmented { display: inline-flex; border: 1px solid var(--line); }
.settings-seg {
  background: rgba(0,0,0,0.4); border: none; color: var(--txt-dim);
  font-family: inherit; font-size: 11px; letter-spacing: 1px; cursor: pointer;
  padding: var(--btn-pad-y) var(--btn-pad-x);
  transition: color var(--t-fast) var(--ease-out), background-color var(--t-fast) var(--ease-out);
}
.settings-seg + .settings-seg { border-left: 1px solid var(--line); }
.settings-seg:hover { color: var(--blue); }
.settings-seg[aria-checked="true"] {
  color: var(--blue); background: color-mix(in srgb, var(--blue) 14%, transparent);
}

/* ── Captain select (launch-screen modal) — mirrors the ship-picker visual language ── */
.captain-overlay {
  position: fixed; inset: 0; z-index: 50; display: flex; overflow-y: auto; padding: 24px;
  background: rgba(5, 8, 16, 0.66); backdrop-filter: blur(4px);
  font-family: var(--mono); color: var(--txt); user-select: none;
  animation: cap-fade-in 0.35s var(--ease-out) both;
}
.captain-overlay.closing { animation: cap-fade-out 0.20s var(--ease-out) both; }
@keyframes cap-fade-in  { from { opacity: 0; } to { opacity: 1; } }
@keyframes cap-fade-out { from { opacity: 1; } to { opacity: 0; } }

.captain-panel {
  margin: auto; width: min(1200px, 96vw); padding: 36px 44px 32px; box-sizing: border-box;
  border: 1px solid var(--line); border-radius: 8px; background: rgba(5, 8, 16, 0.5);
  box-shadow: 0 30px 90px -20px #000, var(--glow-accent);
  text-align: center; animation: sel-pop 0.5s var(--ease-out) both;
}
/* Header row: title flush to the grid's LEFT edge, Select Random flush RIGHT. */
.captain-header { display: flex; align-items: center; justify-content: space-between; margin: 0 0 24px; gap: 16px; }
.captain-title {
  margin: 0; font-size: 22px; font-weight: normal; color: var(--txt);
  letter-spacing: 5px; text-transform: uppercase; text-align: left;
}
.captain-random {
  flex: none; background: transparent; border: 1px solid var(--line); color: var(--txt-dim);
  font-family: var(--mono); font-size: 12px; letter-spacing: 2px; text-transform: uppercase;
  padding: 8px 16px; border-radius: 6px; cursor: pointer;
  transition: color var(--t-fast) var(--ease-out), border-color var(--t-fast) var(--ease-out), box-shadow var(--t-fast) var(--ease-out);
}
.captain-random:hover  { color: var(--txt); border-color: var(--accent); box-shadow: var(--glow-accent); }
.captain-random:active { transform: scale(0.98); }

/* Grid of captain cards — 4-up, gap + card treatment matching the ship picker's .design-grid. */
.captain-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; }
@media (max-width: 900px) { .captain-grid { grid-template-columns: repeat(2, 1fr); } }

/* Card = .design-item treatment: soft border, hover lift + glow, accent on select. */
.captain-card {
  position: relative; display: flex; flex-direction: column; padding: 0 0 12px; text-align: center;
  border: 0; background: transparent;   /* chamfered frame is on .captain-art-wrap (the video) */
  color: var(--txt); font: inherit; cursor: pointer; will-change: transform;
  opacity: 0; animation: sel-fade-up 0.42s var(--ease-out) both;
  transition: border-color var(--t-fast) var(--ease-out), box-shadow var(--t-med) var(--ease-out),
              transform var(--t-fast) var(--ease-out);
}
.captain-card:hover  { border-color: var(--line); transform: translateY(-2px); box-shadow: var(--glow-accent); }
.captain-card.sel    { border-color: var(--accent); box-shadow: var(--glow-accent); }
.captain-card:active { transform: translateY(0) scale(0.99); }
.captain-card:nth-child(1) { animation-delay: 0.10s; }
.captain-card:nth-child(2) { animation-delay: 0.14s; }
.captain-card:nth-child(3) { animation-delay: 0.18s; }
.captain-card:nth-child(4) { animation-delay: 0.22s; }
.captain-card:nth-child(5) { animation-delay: 0.26s; }
.captain-card:nth-child(n+6) { animation-delay: 0.30s; }
/* Captain card portrait area — 9:16 aspect box (matches the 9:16 source art so nothing
   is cropped); static image with video overlay when idle video exists. */
/* Chamfered "frame-open" framing for the captain video (clip-path, fixed-px chamfer = preserves the
   angled corner at any card size, like 9-slice; the source SVG is 160×43 and can't be 9-sliced — its
   chamfer is taller than half the source). The wrap is the blue frame; ::before is the dark interior
   inset by the 2px stroke (leaves a 2px blue chamfered OUTLINE); the video is inset 10px (2px stroke +
   8px gap) and clip-masked to the SAME chamfer so its corner is cut too. --cs-ch = chamfer size. */
.captain-art-wrap {
  position: relative; display: block; width: 100%; aspect-ratio: 9 / 16;
  --cs-ch: 26px; --cs-stroke: 1px; --cs-gap: 8px; --cs-inset: 9px;   /* inset = stroke 1 + gap 8 */
  background: #0087BD;   /* frame-open blue */
  clip-path: polygon(var(--cs-ch) 0, 100% 0, 100% 100%, 0 100%, 0 var(--cs-ch));
}
.captain-art-wrap::before {   /* dark interior, inset by the stroke → leaves the blue chamfered outline */
  content: ''; position: absolute; inset: var(--cs-stroke); background: #0a0e16; z-index: 0;
  clip-path: polygon(calc(var(--cs-ch) - var(--cs-stroke)) 0, 100% 0, 100% 100%, 0 100%, 0 calc(var(--cs-ch) - var(--cs-stroke)));
}
/* <img> (not a CSS background) so the browser uses its high-quality downscaler — the source art is
   9:16 shrunk into a ~270px card, and CSS background-image downsampling looks noisy on that. */
/* Inner box owns the inset (8px gap + 2px stroke), the chamfer mask, and overflow. A DIV sizes reliably
   from `inset`; the replaced img/video then fill it at 100% (they don't size to `inset` themselves). */
.captain-art-inner {
  position: absolute; inset: var(--cs-inset); z-index: 1; overflow: hidden; background: #000;
  clip-path: polygon(calc(var(--cs-ch) - var(--cs-inset)) 0, 100% 0, 100% 100%, 0 100%, 0 calc(var(--cs-ch) - var(--cs-inset)));
}
.captain-art {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: center top; background-color: #000; image-rendering: auto;
}
.captain-art-vid {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: center top; opacity: 0; transition: opacity 0.4s ease;
}
/* Flip the selector portraits/videos horizontally so the captains face the other way. */
.captain-art, .captain-art-vid { transform: scaleX(-1); }
.captain-name  { color: var(--txt); font-size: 14px; padding: 12px 14px 4px; }
.captain-card.sel .captain-name { color: var(--accent-bright); }
.captain-bonus { color: var(--txt-dim); font-size: 11px; padding: 0 14px; letter-spacing: 0.4px; }
.captain-quote { color: var(--blue-detail); font-size: 11px; font-style: italic; padding: 6px 14px 0; line-height: 1.35; }

/* ── Captain-select screen (#4) — own flow screen, over the parallax (no scrim). Fira Sans/Mono. ───── */
#captain-select.captain-screen {
  position: absolute; inset: 0; z-index: 65; overflow: hidden; cursor: default;   /* above the exiting splash (z60) */
  display: flex; flex-direction: column; align-items: center; justify-content: center;   /* carousel centered vertically */
  font-family: 'Fira Sans', system-ui, sans-serif;
}
#captain-select[hidden] { display: none; }
#captain-select .cap-logo { position: absolute; top: 14px; left: 14px; width: 232px; height: auto; z-index: 3; cursor: pointer; }   /* click → back to mode chooser; logo_composit 258×66 ×0.9 */
#captain-select .cap-header {
  position: absolute; top: 70px; left: 0; right: 0; text-align: center; z-index: 4;   /* overlaid → carousel centers on the window */
  margin: 0; font: 500 26px 'Fira Sans', system-ui, sans-serif; letter-spacing: 4px;
  color: #0087bd; text-transform: uppercase;
}
/* Carousel: horizontal scroll viewport (full width, centered), ~5.5 tiles visible. Native bar hidden;
   a custom thumb sits 30px below. */
#captain-select .cap-carousel {
  width: 100%; overflow-x: auto; overflow-y: hidden; scrollbar-width: none; cursor: grab;   /* only flex child → window-centered */
}
#captain-select .cap-carousel::-webkit-scrollbar { display: none; }
#captain-select .cap-row {
  display: flex; gap: 12px; align-items: flex-start; width: max-content; margin: 0 auto; position: relative;
  padding: 26px 40px;   /* vertical room for hover scale + glow (kept to ~26 so the scrollbar sits just below) */
}

/* Captain tile: 331×718 chamfered blue frame; 316×562 video on top; name + ability below.
   (All numbers are the Figma specs ×0.9 — Figma was measured at 1200px tall; the game is 1080.) */
/* CHAMFER = the tile_chamfer_320x696.svg corner as size-independent percentages (29.04/320, 33.31/696). */
.cap-tile {
  --ch: 9.07% 0, 100% 0, 100% 100%, 0 100%, 0 4.79%;   /* clip polygon points matching the frame SVG */
  position: relative; flex: 0 0 320px; width: 320px; height: 696px;   /* = tile_chamfer_320x696.svg */
  border: 0; padding: 0; background: transparent; cursor: pointer; text-align: left;
  opacity: 0; animation: ship-tile-in .6s cubic-bezier(.25,.8,.35,1) both;   /* fly in from the right (same as ships) */
  transition: transform .22s var(--ease-spring), filter .22s var(--ease-out);   /* spring hover (unifies w/ pop) */
}
.cap-tile::after {   /* interior: 24% black tint (+blur), clipped to the frame chamfer */
  content: ''; position: absolute; inset: 0; z-index: 0;
  background: rgba(0,0,0,0.24); backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  clip-path: polygon(var(--ch));
}
.cap-tile::before {   /* frame outline = the SVG masking a colour layer (recolour via background) */
  content: ''; position: absolute; inset: 0; z-index: 2; pointer-events: none; background: #0087bd;
  -webkit-mask: url(/assets/ui/tile_chamfer_320x696.svg) no-repeat center / 100% 100%;
          mask: url(/assets/ui/tile_chamfer_320x696.svg) no-repeat center / 100% 100%;
}
/* Hover / keyboard-focus / selected: +3% zoom + the outline turns white. (No glow — it kept fighting the
   chamfer / video mask, so it's removed.) */
.cap-tile:hover, .cap-tile.focus {
  transform: scale(1.03); z-index: 1;
}
/* Press feedback — a gentle push-in from the hover lift, matching the scale(0.97–0.99)
   :active vocabulary on every other clickable (sm-btn, fleet-tile, design-item). */
.cap-tile:active { transform: scale(1.005); }
.cap-tile:hover::before,
.cap-tile.focus::before { background: #ffffff; }
.cap-tile.sel::before { background: #393939; }   /* selected outline (mockup) */

/* Video 316×562, inset 7px at top, chamfer-masked top-left to match the frame (same % chamfer as ::after). */
.cap-tile-video {
  position: absolute; top: 7px; left: 7px; width: 306px; height: 540px; z-index: 1; overflow: hidden; background: #000;
  clip-path: polygon(9.07% 0, 100% 0, 100% 100%, 0 100%, 0 4.79%);
  /* Still PORTRAIT shows instantly behind the <img>/<video> (set per-tile in buildCaptainTile) so a tile
     is never a black box before its video decodes. Mirrors the img/video object-fit + flip. */
  background-size: cover; background-position: center top; background-repeat: no-repeat;
  transform: scaleX(-1);
}
.cap-tile-video img, .cap-tile-video video {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: center top; transform: none;   /* flip lives on the wrapper now (so the bg portrait matches) */
}
.cap-tile-video video { opacity: 0; transition: opacity .4s ease; }

/* Name (Fira Sans 24px #fff) 20px below the video; ability (Fira Mono 14px #0087BD) 20px below name.
   Left-aligned 26px from the frame's left edge. */
.cap-tile-text { position: absolute; left: 23px; right: 20px; top: 558px; z-index: 1; }   /* below the 540 video (+7 top +11 gap) */
.cap-tile-name { font: 400 18px 'Fira Sans', system-ui, sans-serif; color: #fff; }
.cap-tile-ability { margin-top: 18px; font: 400 13px 'Fira Mono', ui-monospace, monospace; color: #0087bd; line-height: 1.45; }
/* Hovered/focused captain's quote — single line, CENTER-BOTTOM of the screen, 20px tall. */
#captain-select .cap-quote {
  position: absolute; left: 0; right: 0; bottom: 50px; height: 28px; line-height: 28px; z-index: 4;
  text-align: center; font: 300 21px 'Fira Sans', system-ui, sans-serif; color: #fff;   /* Fira Sans Light (300), no italic */
  opacity: 0; transition: opacity var(--t-med) var(--ease-out); pointer-events: none;
}
#captain-select .cap-quote.show { opacity: 0.8; }   /* 80% */

/* Custom scrollbar: 27px below the carousel (30×0.9); thumb = 1px #0087BD outline rect, 9px tall, width
   ∝ visible. The track stretches full-width minus the row's 40px padding, so it aligns with the tile
   area — the thumb at scroll 0 sits under the leftmost tile. */
#captain-select .cap-scrollbar { position: absolute; left: 40px; right: 40px; top: calc(50% + 374px); height: 9px; z-index: 4; }   /* 26px below the 696 tile (half 348 + 26) */
#captain-select .cap-scroll-thumb {
  position: absolute; top: 0; left: 0; height: 9px; min-width: 24px;
  border: 1px solid #0087bd; background: transparent; cursor: grab;
}
#captain-select .cap-scroll-thumb:active { cursor: grabbing; }

/* No screen-wide slide — the captain TILES fly in individually (ship-tile-in), like the ships. */
#captain-select.collapsing { animation: cap-screen-out .5s ease-in forwards; }
@keyframes cap-screen-in  { from { transform: translateX(60%); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes cap-screen-out { to { opacity: 0; transform: scale(.98); } }
/* Entry fade ONLY — must not animate transform, or the filled (`both`) end-state pins transform:none
   and overrides the hover scale (the "panel won't grow" bug). */
@keyframes cap-card-in    { from { opacity: 0; } to { opacity: 1; } }

/* ── Ship-select screen (#4) — chosen captain anchored left, class tabs, ship carousel ─────────────── */
#ship-select.ship-screen {
  position: absolute; inset: 0; z-index: 65; overflow: hidden; cursor: default;
  font-family: 'Fira Sans', system-ui, sans-serif;
}
#ship-select[hidden] { display: none; }
#ship-select .ship-logo { position: absolute; top: 14px; left: 14px; width: 232px; height: auto; z-index: 3; cursor: pointer; }
/* Header row OVERLAID at the top (doesn't push the main content down → captain centers at the same Y as
   the captain-select carousel for a seamless hand-off). */
/* Header: title left-aligned to the FIRST ship tile (40 pad + 320 captain + 16 gap + 24 row-pad = 400),
   then a 50px gap to the tab tray. */
#ship-select .ship-head { position: absolute; top: 135px; left: 400px; z-index: 4; display: flex; align-items: center; gap: 50px; }
#ship-select .ship-title { font: 700 21px 'Fira Sans', system-ui, sans-serif; color: #fff; white-space: nowrap; }   /* Fira Bold 21 */
#ship-select .ship-tabs { display: flex; gap: 10px; }
/* Tabs 140×38 — frame-angled-open (idle) / frame-angled-filled (selected), matching the start-screen buttons. */
#ship-select .ship-tab {
  position: relative; width: 140px; height: 38px; border: 0; padding: 0; background: transparent; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  font: 400 15px 'Fira Sans', system-ui, sans-serif; color: #0087bd;
  transition: color var(--t-fast) var(--ease-out);
}
/* ::before = the frame outline (idle/filled). It is ALSO the backdrop-blur carrier: the blur
   element must have NO clip/mask of its own (that suppresses backdrop-filter); the chamfer comes
   from the BUTTON's clip-path below clipping this child. Faint tint backs the blur over dark space. */
#ship-select .ship-tab::before {
  content: ''; position: absolute; inset: 0;
  background: rgba(0, 135, 189, 0.05) url(/assets/ui/frame-angled-open.svg) no-repeat center / 100% 100%;
  -webkit-backdrop-filter: blur(3.5px); backdrop-filter: blur(3.5px);
}
/* %-based chamfer clip (same stretched SVG as .sm-btn → identical top-left cut). Clips the ::before. */
#ship-select .ship-tab { clip-path: polygon(14.32% 0, 100% 0, 100% 100%, 0 100%, 0 58.05%); }
#ship-select .ship-tab:hover { color: #eaf4ff; }
#ship-select .ship-tab.active { color: #fff; }
#ship-select .ship-tab.active::before { background-image: url(/assets/ui/frame-angled-filled.svg); }
/* Main: anchored captain (left) + ship carousel (right), VERTICALLY CENTERED in the full screen (matches
   the captain-select carousel's center → the chosen captain tile doesn't jump on hand-off). */
#ship-select .ship-main { position: absolute; inset: 0; display: flex; align-items: center; gap: 16px; padding-left: 40px; }
#ship-select .ship-captain { flex: 0 0 320px; padding: 16px 0; }   /* = .cap-tile width; 16px vert pad matches .ship-row so the captain aligns with the ship tiles */
#ship-select .ship-carousel { flex: 1; align-self: center; overflow-x: auto; overflow-y: hidden; scrollbar-width: none; cursor: grab; }
#ship-select .ship-carousel::-webkit-scrollbar { display: none; }
/* padding-left 24 ≥ the 18px overshoot so the leftmost tile doesn't clip the carousel's left edge. */
#ship-select .ship-row { display: flex; gap: 14px; align-items: center; width: max-content; padding: 16px 40px 16px 24px; position: relative; }

/* Anchored captain card (the chosen commander, static) — chamfered like a captain tile. */
#ship-select .ship-captain .sc-card { --t-ch: 22px; position: relative; width: 300px; }
#ship-select .ship-captain .sc-frame { position: relative; width: 300px; aspect-ratio: 9 / 16;
  clip-path: polygon(var(--t-ch) 0, 100% 0, 100% 100%, 0 100%, 0 var(--t-ch)); background: #0087bd; }
#ship-select .ship-captain .sc-frame::after { content: ''; position: absolute; inset: 1px; background: rgba(0,0,0,0.24);
  clip-path: polygon(calc(var(--t-ch) - 1px) 0, 100% 0, 100% 100%, 0 100%, 0 calc(var(--t-ch) - 1px)); }
#ship-select .ship-captain .sc-media { position: absolute; inset: 7px; overflow: hidden; background: #000;
  clip-path: polygon(calc(var(--t-ch) - 7px) 0, 100% 0, 100% 100%, 0 100%, 0 calc(var(--t-ch) - 7px)); }
#ship-select .ship-captain .sc-media img, #ship-select .ship-captain .sc-media video {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: center top; transform: scaleX(-1); }
#ship-select .ship-captain .sc-media video { opacity: 0; transition: opacity .4s ease; }
#ship-select .ship-captain .sc-name { margin-top: 14px; font: 400 18px 'Fira Sans', system-ui, sans-serif; color: #fff; }
#ship-select .ship-captain .sc-bonus { margin-top: 8px; font: 400 13px 'Fira Mono', ui-monospace, monospace; color: #0087bd; line-height: 1.45; }

/* Ship tile: frame-angled-open container; ship preview (top) + name + stats (bottom).
   SHARED COMPONENT — bare .ship-tile (no screen scope) so the ship-select carousel AND the vs-page
   (#selection-screen) both render the identical tile. Screen-specific behavior (e.g. #ship-select's
   no-hover guard, #selection-screen's fly-in suppression) stays scoped below. */
.ship-tile {
  position: relative; flex: 0 0 320px; width: 320px; height: 696px;   /* same default height as the captain tile */
  border: 0; padding: 0; background: transparent; cursor: pointer; text-align: left;
  opacity: 0; animation: ship-tile-in .6s cubic-bezier(.25,.8,.35,1) both;   /* slide in from the right + spring */
  transition: transform .22s var(--ease-spring);   /* spring hover (unifies w/ pop) */
}
/* Overshoot is a FIXED small amount (keyframe at 80%), not proportional to the slide distance — otherwise
   the spring overshoot scales with the 1200px travel and the leftmost tile flies past into the clip. */
@keyframes ship-tile-in {
  0%   { opacity: 0; transform: translateX(1200px); }
  60%  { opacity: 1; transform: translateX(2px); }
  80%  { opacity: 1; transform: translateX(-18px); }
  100% { opacity: 1; transform: translateX(0); }
}
.ship-tile::after {   /* interior: dark tint + faint blue cell grid, clipped to the frame chamfer */
  content: ''; position: absolute; inset: 0; z-index: 0;
  background:
    repeating-linear-gradient(0deg,  transparent 0 23px, rgba(0,135,189,0.13) 23px 24px),
    repeating-linear-gradient(90deg, transparent 0 23px, rgba(0,135,189,0.13) 23px 24px),
    rgba(0,0,0,0.24);
  clip-path: polygon(9.07% 0, 100% 0, 100% 100%, 0 100%, 0 4.79%);
}
.ship-tile::before {   /* frame outline = tile_chamfer SVG masking a colour layer */
  content: ''; position: absolute; inset: 0; z-index: 2; pointer-events: none; background: #0087bd;
  -webkit-mask: url(/assets/ui/tile_chamfer_320x696.svg) no-repeat center / 100% 100%;
          mask: url(/assets/ui/tile_chamfer_320x696.svg) no-repeat center / 100% 100%;
}
.ship-tile .st-class, .ship-tile .st-preview,
.ship-tile .st-name, .ship-tile .st-stats,
.ship-tile .st-template { z-index: 1; }
.ship-tile:hover, .ship-tile.focus { transform: scale(1.03); z-index: 1; }
.ship-tile:active { transform: scale(1.005); }   /* press push-in (matches the app-wide :active vocabulary) */
.ship-tile:hover::before, .ship-tile.focus::before { background: #ffffff; }
.ship-tile.sel::before { background: #393939; }   /* selected outline (mockup) */
/* On load the cursor may already sit over a tile that slid in under it → suppress hover until the user
   actually moves the mouse (or uses arrows), so no ship reads as selected on entry. */
#ship-select.no-hover .ship-tile { pointer-events: none; }
.ship-tile .st-class { position: absolute; top: 14px; right: 16px; font: 400 13px 'Fira Mono', ui-monospace, monospace; color: #0087bd; }
/* Template tag — directly below the class, top-right, muted. */
.ship-tile .st-template { position: absolute; top: 32px; right: 16px; font: 400 9px 'Fira Mono', ui-monospace, monospace; letter-spacing: 1.5px; color: rgba(0,135,189,0.55); }
.ship-tile .st-preview { position: absolute; top: 28px; left: 16px; right: 16px; height: 470px; }
.ship-tile .st-preview canvas { width: 100%; height: 100%; display: block; }
.ship-tile .st-name { position: absolute; left: 18px; right: 16px; top: 450px; font: 400 18px 'Fira Sans', system-ui, sans-serif; color: #fff; }   /* all names share this Y */
.ship-tile .st-stats { position: absolute; left: 18px; right: 16px; top: 482px; font: 400 10px 'Fira Mono', ui-monospace, monospace; color: #0087bd; line-height: 1.7; }

/* Scrollbar — same Y as the captain carousel's (26px below the 696 tile); spans the carousel (after the
   captain). Hidden by JS when all ships fit (no scroll needed). */
#ship-select .ship-scrollbar { position: absolute; left: 387px; right: 40px; top: calc(50% + 374px); z-index: 4; height: 9px; }
#ship-select .ship-scroll-thumb { position: absolute; top: 0; left: 0; height: 9px; min-width: 24px; border: 1px solid #0087bd; background: transparent; cursor: grab; }

/* NO screen-wide slide on enter — the anchored captain must STAY exactly where the collapse left it
   (sliding the whole screen made it re-animate/"reload"). The ship tiles do their own stagger-in. */
#ship-select.collapsing { animation: cap-screen-out .5s ease-in forwards; }

/* Player 1 pilot spot stays empty until a captain is chosen. */
.pilot-empty .pilot-img       { visibility: hidden; }
.pilot-empty .pilot-info      { display: none; }
.pilot-empty-prompt {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: 11px; letter-spacing: 2px; color: var(--txt-dim);
  text-align: center; line-height: 1.9; pointer-events: none;
}
/* The player pilot spot re-opens the commander select on click. The base .pilot sets
   pointer-events:none (decorative, clicks fall to the ship box) — re-enable it here so the
   player's portrait is actually clickable. */
.pilot-clickable { cursor: pointer; pointer-events: auto; }
.pilot-clickable .pilot-frame { transition: box-shadow var(--t-med) var(--ease-out); }
.pilot-clickable:hover .pilot-frame { box-shadow: var(--glow-accent); }

/* ── Selection fly-to animations ───────────────────────────────────────────────
   Captain portrait and ship card each fly from their picker position to their
   destination panel. The clone transitions position + size + opacity; on landing
   the destination gets a brief lock-in flash via a pseudo-element overlay.   */
.flying-card {
  pointer-events: none;
  overflow: hidden;
  border-radius: 4px;
  position: absolute;   /* ship-flying clone — in selection-screen coordinate space */
  transition: left    0.45s cubic-bezier(0.25, 0.0, 0.1, 1),
              top     0.45s cubic-bezier(0.25, 0.0, 0.1, 1),
              width   0.45s cubic-bezier(0.25, 0.0, 0.1, 1),
              height  0.45s cubic-bezier(0.25, 0.0, 0.1, 1),
              opacity 0.30s ease 0.22s;
}
/* Captain portrait flies across the full page — fixed + z-index set inline by JS */
.flying-card.captain-flying { border: 1px solid var(--player1-line); }

/* Ship SPRITE clone — just the ship preview (no card box/border/bg), flies above the
   closing picker (pick-sheet z-index: 30) and grows into the tile. In selection-screen
   coordinate space (absolute). */
.ship-flying {
  position: absolute;
  pointer-events: none;
  z-index: 40;
  transition: left   0.5s cubic-bezier(0.25, 0.0, 0.1, 1),
              top    0.5s cubic-bezier(0.25, 0.0, 0.1, 1),
              width  0.5s cubic-bezier(0.25, 0.0, 0.1, 1),
              height 0.5s cubic-bezier(0.25, 0.0, 0.1, 1);
}

/* Lock-in flash — pseudo-element white burst that fades after the card lands */
@keyframes lock-in-flash {
  0%   { opacity: 1; }
  100% { opacity: 0; }
}
.fleet-tile.lock-in::after,
.pilot.lock-in::after {
  content: '';
  position: absolute;
  inset: 0;
  background: rgba(255, 255, 255, 0.14);
  box-shadow: inset 0 0 0 2px rgba(255, 255, 255, 0.9);
  pointer-events: none;
  z-index: 10;
  animation: lock-in-flash 0.55s ease-out forwards;
}


/* ── Start sequence (backlog #4): logo intro → game-mode menu ───────────────────
   One #start-screen, phased by class (main.js playStartSequence), matching loading01-05:
     .play — INTRO: CARRIER swoops from the TOP, COMMANDER from the BOTTOM, the streak-line
             "blazes across" between them + an impact flash (loading01-03).
     .menu — logo settles up top, the game-mode options load in (loading04).
     .exit — logo sweeps to the top-left corner + fade → selection screen (loading05).
   Logo nesting + streak seam are derived from the loading-frame coords. */
#start-screen.start-screen {
  position: absolute; inset: 0; z-index: 60; cursor: pointer;
  /* NO scrim/dim — only the procedural stars + planet (selection-bg.js on #layer-background) show
     behind the splash. The old setup screen is hidden during the splash (main.js) so nothing else
     shows through. */
  background: transparent;
}
#start-screen[hidden] { display: none; }

/* Composed logo — each part absolutely positioned at its measured 1920×1080 px (centered on x). The
   .start-logo is a full-screen anchor that the EXIT state transforms as a unit. The three TOP / WIDTH
   values below are the layout dials (from the Figma, mapped at 1920×1080). The particle bursts/steam/
   sparkle read these elements' live positions (main.js elBox), so moving a value moves its FX too. */
#start-screen .start-logo {
  position: absolute; inset: 0;
  transition: transform .6s cubic-bezier(.5,0,.3,1), opacity .5s ease;
}
#start-screen .sl-carrier   { position: absolute; left: 50%; top: 156px; transform: translateX(-50%); width: 1040px; height: auto; opacity: 0; transition: filter .22s ease-out; }
#start-screen .sl-streak    { position: absolute; left: calc(50% - 60px); top: 217px; transform: translateX(-50%); width: 1155px; height: auto; opacity: 0; clip-path: inset(0 0 0 100%); }
#start-screen .sl-commander { position: absolute; left: 50%; top: 363px; transform: translateX(-50%); width: 770px;  height: auto; opacity: 0; transition: filter .22s ease-out; }
/* White-flash on land — an ANIMATION (overrides the .sl-* filter transition so it SNAPS to white then
   fades, instead of easing). brightness(0)+invert(1) = a pure-white silhouette of the logo png. */
#start-screen .fx-flash { animation: fx-flash-anim 0.18s ease-out; }
@keyframes fx-flash-anim {
  from { filter: brightness(0) invert(1) drop-shadow(0 0 30px rgba(255,255,255,0.9)); }
  to   { filter: brightness(1) invert(0) drop-shadow(0 0 0   rgba(255,255,255,0)); }
}
/* Particle FX canvas (start-fx.js); pure visual, never eats clicks. Appended last → on top. The WebGL
   buffer is OPAQUE BLACK with ADDITIVE particles; `mix-blend-mode: screen` drops the black and ADDS the
   light to the logo (brightens, never darkens; accumulation → white blowout). Try `plus-lighter` for
   harder/true-additive blowout, or `lighten` for points-of-light with no overall brightening. */
#start-screen .start-fx { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; mix-blend-mode: screen; }

/* Game-mode options (hidden until .menu). TOP-anchored (not centered) so the first button sits a fixed
   distance below COMMANDER: 48.3% ≈ 68px under COMMANDER's bottom (bottom ≈ 454px = top 363 + ~91px
   tall). TWEAK `top`. */
#start-screen .start-modes {
  position: absolute; left: 50%; top: 47.6%; transform: translateX(-50%);   /* ≈60px below COMMANDER's bottom */
  display: flex; flex-direction: column; align-items: center; gap: 40px;   /* between groups (load→PvC, PvC→PvP) */
  opacity: 0; pointer-events: none; transition: opacity .5s ease .25s;
}
#start-screen .sm-group { display: flex; flex-direction: column; align-items: center; gap: 9px; }   /* label → row */
#start-screen .sm-label { font: 400 20px Inter, system-ui, sans-serif; color: #0087bd; }
#start-screen .sm-row { display: flex; gap: 9px; }   /* x spacing between Arcade and Fleet */
/* Angled-frame button = the chamfered SVG frame stretched over a dark fill (single-piece vector,
   not a 9-slice). frame-angled-open = idle, frame-angled-filled = hover. */
#start-screen .sm-btn {
  position: relative; width: 283px; height: 68px; border: 0; padding: 0; background: transparent;
  display: flex; align-items: center; justify-content: center;
  font: 400 24px Inter, system-ui, sans-serif; color: #0087bd;
  cursor: pointer; transition: color var(--t-fast) var(--ease-out), transform var(--t-fast) var(--ease-out);
}
/* ::before = backdrop BLUR. The blur element has NO clip/mask on ITSELF (clip-path/mask on the same
   element is what suppresses backdrop-filter — the captain-tile wall) and NO negative z-index (also breaks
   backdrop sampling). The chamfer comes from the BUTTON's clip-path (parent-clip + child-blur). Paints
   behind the label; a faint tint backs it up over dark space (where backdrop-blur shows ~nothing). */
#start-screen .sm-btn::before {
  content: ""; position: absolute; inset: 0;
  background: rgba(0, 135, 189, 0.05);   /* faint glass tint (// ALPHA) */
  -webkit-backdrop-filter: blur(3.5px); backdrop-filter: blur(3.5px);   /* halved from 7px */
}
/* ::after = the frame outline (mirrors per row/mode without flipping the label). Paints over the label
   edges (it's just an outline). */
#start-screen .sm-btn::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: url(/assets/ui/frame-angled-open.svg) no-repeat center / 100% 100%;
}
#start-screen .sm-btn:hover:not([disabled])::after, #start-screen .sm-btn:focus-visible:not([disabled])::after {
  background-image: url(/assets/ui/frame-angled-filled.svg);
}
#start-screen .sm-btn:hover:not([disabled]), #start-screen .sm-btn:focus-visible:not([disabled]) {
  color: #eaf4ff; transform: translateY(-2px);
}
#start-screen .sm-btn:active:not([disabled]) { transform: translateY(0) scale(0.985); }

/* Chamfer clip on the BUTTON — clips both the blur (::before) and the frame (::after). %-based so it
   matches the stretched frame SVG, with a variant per mirror state. */
#start-screen .sm-btn                               { clip-path: polygon(14.32% 0, 100% 0, 100% 100%, 0 100%, 0 58.05%); }
#start-screen .sm-row .sm-btn:last-child            { clip-path: polygon(0 0, 85.68% 0, 100% 58.05%, 100% 100%, 0 100%); }
#start-screen .sm-btn[data-pvp]                     { clip-path: polygon(0 0, 100% 0, 100% 100%, 14.32% 100%, 0 41.95%); }
#start-screen .sm-row .sm-btn[data-pvp]:last-child  { clip-path: polygon(0 0, 100% 0, 100% 41.95%, 85.68% 100%, 0 100%); }
/* Frame (::after) mirror per state — matches the clip-path variants above. */
#start-screen .sm-row .sm-btn:last-child::after           { transform: scaleX(-1); }
#start-screen .sm-btn[data-pvp]::after                    { transform: scaleY(-1); }
#start-screen .sm-row .sm-btn[data-pvp]:last-child::after { transform: scaleX(-1) scaleY(-1); }
#start-screen .sm-btn[disabled] { opacity: .35; cursor: not-allowed; }

/* INTRO animations */
/* Timing (60 ticks/s): SNAPPY ease-in swoop (slow start → accelerate) with a single spring-back overshoot
   at the end. CARRIER swoops 0→0.5s; COMMANDER starts +0.83s (the 20-tick gap), swoops to ~1.33s; streak
   wipes after. start-fx fires each .pex burst as its word LANDS (≈10 ticks before the swoop's end, since
   ease-in arrives late) — SPLASH_FX_* in main.js. */
#start-screen.play .sl-carrier   { animation: sl-carrier-in   .5s cubic-bezier(.45,0,.35,1.5) both; }
#start-screen.play .sl-commander { animation: sl-commander-in .5s cubic-bezier(.45,0,.35,1.5) .83s both; }
#start-screen.play .sl-streak    { animation: sl-streak-blaze .42s ease-out 1.25s both; }
@keyframes sl-carrier-in   { from { opacity:0; transform: translate(-50%,-160px) scale(1.12); } 60% { opacity:1; } to { opacity:1; transform: translate(-50%,0) scale(1); } }
@keyframes sl-commander-in { from { opacity:0; transform: translateX(-50%) translateY(150px); } to { opacity:1; transform: translateX(-50%) translateY(0); } }
@keyframes sl-streak-blaze { from { opacity:0; clip-path: inset(0 0 0 100%); } 12% { opacity:1; } to { opacity:1; clip-path: inset(0 0 0 0); } }

/* MENU — logo stays at its measured position; options load in below (loading04). */
#start-screen.menu .start-modes { opacity: 1; pointer-events: auto; }

/* EXIT — logo shrinks toward the top-left + fade → selection screen (loading05). The whole anchor
   transforms as a unit; the screen fades (opacity 0) so the exact corner spot isn't critical. */
#start-screen.exit { opacity: 0; transition: opacity .5s ease .15s; }
/* Anchor toward the TOP-LEFT corner (where the selection screen's graphic #sel-logo sits) so the entry
   logo reads as settling into the corner — not fading center-screen. Tune the translate/scale to land it
   exactly on #sel-logo. (Screen still fades; the corner logo is now graphic→graphic, no text behind.) */
#start-screen.exit .start-logo  { transform: translate(-38%, -44%) scale(.29); transform-origin: 50% 160px; }
#start-screen.exit .start-modes { opacity: 0; transform: translateX(-120%); transition: transform .5s cubic-bezier(.5,0,.3,1), opacity .35s ease; }   /* mode UI slides off-left */

/* Campaign buttons use their own SVG art (assets/ui/button-*campaign.svg); disabled for now. */
/* Campaign buttons: the SVG is the FRAME only (no text baked in), so the label sits on top.
   Sizes are the Figma frame sizes (Start 574x76, Load 382x53). */
#start-screen .sm-campaign { gap: 9px; }   /* Start → Load */
#start-screen .sm-cbtn {
  position: relative; border: 0; cursor: pointer; color: #0087bd; background: transparent;
  display: flex; align-items: center; justify-content: center;
  font: 400 24px Inter, system-ui, sans-serif;
}
/* ::before = backdrop-blur carrier (no clip/mask on ITSELF → blur survives; the button's per-variant
   clip-path shapes it to the SVG chamfer). Faint tint backs the blur over dark space. ::after = the
   frame SVG on top, so the blur sits BEHIND both label and frame outline. */
#start-screen .sm-cbtn::before {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: rgba(0, 135, 189, 0.05);
  -webkit-backdrop-filter: blur(3.5px); backdrop-filter: blur(3.5px);
}
#start-screen .sm-cbtn::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: no-repeat center / 100% 100%;   /* frame image set per variant; SVG carries its own fill */
}
#start-screen .sm-cbtn.sm-start { width: 574px; height: 76px;
  /* chamfer from button-startcampaign.svg (574×76): bevelled top corners */
  clip-path: polygon(0 50%, 6.272% 0, 94.251% 0, 100% 50%, 100% 100%, 0 100%); }
#start-screen .sm-cbtn.sm-start::after { background-image: url(/assets/ui/button-startcampaign.svg); }
#start-screen .sm-cbtn.sm-load  { width: 382px; height: 53px;
  /* chamfer from button-loadcampaign.svg (382×53): straight top, bevelled bottom corners */
  clip-path: polygon(0 28.302%, 6.272% 100%, 94.251% 100%, 100% 28.302%, 100% 0, 0 0); }
#start-screen .sm-cbtn.sm-load::after  { background-image: url(/assets/ui/button-loadcampaign.svg); }
#start-screen .sm-cbtn[disabled] { opacity: .55; cursor: not-allowed; }
#start-screen .sm-cbtn:not([disabled]):hover { color: #eaf4ff; }
