/* ============================================================================
 * hub.css — Apex Lab visual styling
 * ============================================================================
 *
 * Aesthetic targets (per hub-design.md and decisions.md):
 *   "futuristic, clinical, beautiful, safe, intelligent, slightly sacred"
 *
 * Palette choices:
 *   - Deep navy / near-black background, with a subtle grid texture
 *   - Cyan-teal primary (#88e6ff) for interactive UI
 *   - Soft warm bone-ivory (#e8dfc6) for anatomy accents
 *   - Per-system color codes match Bio-Vat data (skeleton ivory, muscle
 *     crimson, neural electric-blue, vascular red, etc.)
 *   - Tasteful drop-glow on hover/selected; no rainbow chrome
 *
 * Layout strategy:
 *   - CSS Grid for main layouts (screen sections)
 *   - Flexbox for rows/lists
 *   - Generous spacing; readable typography (Inter / system sans)
 *
 * Animation: subtle pulses (sin-driven via CSS keyframes) on interactive
 * affordances. Nothing distracting.
 * ============================================================================ */

/* ─── Reset + globals ────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; padding: 0; height: 100%; }

:root {
  --bg-0:        #060a12;   /* deepest background */
  --bg-1:        #0c1320;   /* panel background */
  --bg-2:        #131c2e;   /* elevated surface */
  --bg-3:        #1b2540;   /* hover surface */
  --border:      #25324c;
  --border-soft: #1a2538;
  --ink:         #e6eef8;   /* primary text */
  --ink-dim:     #9bb1c6;   /* muted text */
  --ink-dimmer:  #6f8294;
  --accent:      #88e6ff;   /* primary cyan-teal */
  --accent-glow: rgba(136, 230, 255, 0.35);
  --accent-warm: #ffd966;   /* gold accent (blueprints, milestones) */
  --bone:        #e8dfc6;
  --muscle:      #d77676;
  --neural:      #88c0ff;
  --vascular:    #d24545;
  --skin:        #d8b07a;
  --lung:        #9ed1ff;
  --gut:         #c69ad0;
  --liver:       #a37a4e;
  --kidney:      #7eb88f;
  --brain:       #b59eff;
  --eyes:        #88fff0;
  --immune:      #9eff88;
  --danger:      #ff7a7a;
  --ok:          #7fc486;
  --warn:        #ffb455;
  --bt:          #56c98a;   /* BioToken green — fixed currency colour for ALL buy/sell UI */

  --font-stack: 'Inter', 'Segoe UI', 'SF Pro Text', system-ui, -apple-system, sans-serif;
  --font-mono:  'JetBrains Mono', 'Consolas', monospace;

  --radius-sm: 4px;
  --radius:    8px;
  --radius-lg: 14px;

  --shadow-sm: 0 2px 8px rgba(0,0,0,0.4);
  --shadow:    0 6px 18px rgba(0,0,0,0.5);
  --shadow-glow: 0 0 22px var(--accent-glow);
}

body {
  background:
    radial-gradient(ellipse at center top, #182846 0%, var(--bg-0) 50%) no-repeat,
    var(--bg-0);
  background-attachment: fixed;
  color: var(--ink);
  font-family: var(--font-stack);
  font-size: 14px;
  line-height: 1.45;
  letter-spacing: 0.01em;
  overflow-x: hidden;
  min-height: 100vh;
}

/* Subtle grid overlay across the whole page — clinical-lab feel */
body::before {
  content: '';
  position: fixed;
  inset: 0;
  background-image:
    linear-gradient(rgba(136, 230, 255, 0.025) 1px, transparent 1px),
    linear-gradient(90deg, rgba(136, 230, 255, 0.025) 1px, transparent 1px);
  background-size: 40px 40px;
  pointer-events: none;
  z-index: 0;
}

/* ─── Layout shell ───────────────────────────────────────────────────── */
.status-bar {
  position: sticky;
  top: 0;
  z-index: 50;
  display: grid;
  grid-template-columns: 220px 1fr 240px;
  align-items: center;
  gap: 10px;
  padding: 5px 16px;
  background: linear-gradient(180deg, rgba(16, 24, 42, 0.96) 0%, rgba(8, 14, 26, 0.96) 100%);
  border-bottom: 1px solid var(--border);
  backdrop-filter: blur(8px);
}

.status-logo {
  font-family: var(--font-mono);
  font-weight: 700;
  letter-spacing: 0.18em;
  color: var(--accent);
  font-size: 13px;
  display: flex;
  flex-direction: column;
  line-height: 1.1;
}
.status-sub {
  font-size: 9px;
  letter-spacing: 0.3em;
  color: var(--ink-dimmer);
  text-transform: lowercase;
}

.status-center {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  justify-content: center;
}

.stat-chip {
  display: grid;
  grid-template-columns: auto 1fr;
  grid-template-rows: auto auto;
  align-items: center;
  gap: 0 7px;
  padding: 4px 9px;
  background: var(--bg-1);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  cursor: pointer;
  position: relative;
  min-width: 84px;
  transition: background 0.15s, border-color 0.15s;
}
.stat-chip:hover {
  background: var(--bg-2);
  border-color: var(--accent);
}
.chip-icon {
  grid-row: 1 / span 2;
  font-size: 14px;
  color: var(--accent);
  display: flex;
  align-items: center;
}
.chip-value {
  font-weight: 600;
  font-size: 12.5px;
  color: var(--ink);
}
.chip-label {
  font-size: 8.5px;
  color: var(--ink-dim);
  letter-spacing: 0.05em;
  text-transform: uppercase;
}
.chip-sub {
  color: var(--ok);
  font-weight: 600;
  font-size: 10px;
  margin-left: 4px;
}
.marker {
  position: absolute;
  top: -3px;
  right: -3px;
  width: 10px;
  height: 10px;
  background: var(--accent-warm);
  border-radius: 50%;
  box-shadow: 0 0 8px var(--accent-warm);
  animation: pulse-soft 2.4s ease-in-out infinite;
}

.status-right { display: flex; justify-content: flex-end; }
.btn-launch {
  background: linear-gradient(180deg, var(--accent) 0%, #56c5ee 100%);
  color: #061018;
  font-weight: 700;
  letter-spacing: 0.06em;
  padding: 10px 16px;
  border: none;
  border-radius: var(--radius);
  cursor: pointer;
  box-shadow: var(--shadow-glow);
  transition: transform 0.1s;
}
.btn-launch:hover { transform: translateY(-1px); }
.btn-launch:active { transform: translateY(0); }

/* ─── Main / screens ─────────────────────────────────────────────────── */
.hub-main {
  position: relative;
  z-index: 1;
  padding: 18px 24px 90px;   /* room for bottom nav */
  max-width: 1600px;
  margin: 0 auto;
}

.screen { display: none; }
/* Gentle fade-in each time a screen becomes active (2026-06-01). Opacity-only
   (no transform) so it can't reflow the Bio-Vat's WebGL canvas. The animation is
   on the .screen container, so the frequent inner re-renders don't replay it —
   it only plays on an actual screen switch. */
.screen.active { display: block; animation: screen-in 0.22s ease-out both; }
@keyframes screen-in { from { opacity: 0; } to { opacity: 1; } }

/* No drag-to-select on the game UI (2026-06-01). Dragging the mouse over the
   island/overlays was painting the browser's blue text-selection highlight (it
   lined up with the forge overlay image). This is a game, not a document — kill
   selection + native image-drag across the shell. Form fields keep normal
   selection so typing in the Market etc. still works. If you ever want to
   copy Codex/atlas text, we can carve a `user-select: text` exception for it. */
.hub-main, .status-bar, .hub-back, #app-bg, #app-bg-veil,
.toasts, .notif-modal, .tissue-modal {
  -webkit-user-select: none;
  user-select: none;
}
.hub-main img, .cc-buildings img, #app-bg, .cc-scene-bg {
  -webkit-user-drag: none;
  user-drag: none;
}
input, textarea, select, [contenteditable="true"] {
  -webkit-user-select: text;
  user-select: text;
}

.screen-h {
  margin: 4px 0 18px;
}
.screen-h h2 {
  margin: 0 0 4px;
  font-weight: 600;
  font-size: 22px;
  letter-spacing: 0.02em;
}

/* ─── Bottom nav ─────────────────────────────────────────────────────── */
.bottom-nav {
  position: fixed;
  bottom: 0; left: 0; right: 0;
  z-index: 50;
  display: flex;
  justify-content: center;
  gap: 6px;
  padding: 10px 16px;
  background: linear-gradient(0deg, rgba(8, 14, 26, 0.98) 0%, rgba(8, 14, 26, 0.9) 100%);
  border-top: 1px solid var(--border);
  backdrop-filter: blur(8px);
}
.bottom-nav button {
  background: transparent;
  border: 1px solid transparent;
  color: var(--ink-dim);
  cursor: pointer;
  padding: 6px 14px;
  border-radius: var(--radius);
  display: flex;
  flex-direction: column;
  align-items: center;
  font: inherit;
  transition: color 0.15s, border-color 0.15s, background 0.15s;
  min-width: 80px;
}
.bottom-nav button:hover {
  color: var(--ink);
  background: var(--bg-2);
  border-color: var(--border);
}
.bottom-nav button.active {
  color: var(--accent);
  border-color: var(--accent);
  background: var(--bg-2);
}
.bottom-nav button.primary {
  background: linear-gradient(180deg, var(--accent) 0%, #56c5ee 100%);
  color: #061018;
}
.bottom-nav button.primary .nav-label { font-weight: 700; }
.nav-icon { font-size: 16px; }
.nav-label { font-size: 10px; letter-spacing: 0.06em; text-transform: uppercase; }

/* ─── Panels (reusable) ──────────────────────────────────────────────── */
.panel {
  background: var(--bg-1);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 16px;
  box-shadow: var(--shadow-sm);
}
.panel.wide { grid-column: 1 / -1; }
.panel.side { background: var(--bg-1); }
.panel.detail { background: var(--bg-1); }

.panel-h {
  margin: 0 0 12px;
  font-size: 11px;
  letter-spacing: 0.16em;
  color: var(--ink-dim);
  text-transform: uppercase;
  font-weight: 600;
}
/* Clickable panel header (collapse/expand the panel body). */
.panel-h-toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  cursor: pointer;
  user-select: none;
}
.panel-h-toggle:hover { color: var(--accent, #88e6ff); }
.panel-caret { font-size: 10px; opacity: 0.7; }
/* Collapsed → header only, no bottom margin so it reads as a compact chip. */
.buildings-overview-panel.is-collapsed .panel-h-toggle { margin-bottom: 0; }
.panel-h-sub {
  margin: 12px 0 8px;
  font-size: 11px;
  letter-spacing: 0.16em;
  color: var(--ink-dim);
  text-transform: uppercase;
  font-weight: 600;
}

/* ─── Buttons (reusable) ─────────────────────────────────────────────── */
.btn {
  background: var(--bg-2);
  border: 1px solid var(--border);
  color: var(--ink);
  padding: 8px 14px;
  border-radius: var(--radius);
  cursor: pointer;
  font: inherit;
  letter-spacing: 0.02em;
  transition: background 0.15s, border-color 0.15s, transform 0.05s;
}
.btn:hover:not(:disabled) {
  background: var(--bg-3);
  border-color: var(--accent);
}
.btn:active:not(:disabled) { transform: translateY(1px); }
.btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}
.btn-primary {
  background: linear-gradient(180deg, var(--accent) 0%, #56c5ee 100%);
  color: #061018;
  border: none;
  font-weight: 600;
}
.btn-primary:hover:not(:disabled) {
  filter: brightness(1.1);
  border: none;
}
.btn-danger {
  background: linear-gradient(180deg, #c43c5b 0%, #802234 100%);
  color: #fff;
  border: none;
}
.btn-tiny {
  padding: 4px 10px;
  font-size: 12px;
}
.btn-launch-big {
  width: 100%;
  background: linear-gradient(180deg, var(--accent) 0%, #56c5ee 100%);
  color: #061018;
  font-weight: 800;
  letter-spacing: 0.1em;
  font-size: 15px;
  padding: 14px;
  border: none;
  border-radius: var(--radius);
  cursor: pointer;
  box-shadow: var(--shadow-glow);
}
.btn-launch-big:disabled { background: var(--bg-2); color: var(--ink-dim); cursor: not-allowed; box-shadow: none; }

/* ─── Utility ────────────────────────────────────────────────────────── */
.muted { color: var(--ink-dim); }
.muted.small { font-size: 11px; }
.small { font-size: 11px; }
.big { font-size: 18px; font-weight: 600; }
.hl { color: var(--accent); }
.ok { color: var(--ok); }
.lack { color: var(--danger); }
.dim { opacity: 0.5; }
.mt { margin-top: 6px; }
.sep { border: none; border-top: 1px solid var(--border); margin: 16px 0; }
hr.sep { border: none; border-top: 1px solid var(--border); margin: 16px 0; }
.badge {
  display: inline-block;
  padding: 2px 8px;
  background: var(--bg-3);
  border: 1px solid var(--border);
  border-radius: 99px;
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-dim);
}
.badge.tbd {
  border-color: var(--warn);
  color: var(--warn);
}
.badge.full {
  border-color: var(--ok);
  color: var(--ok);
}

/* ═══════════════════════════════════════════════════════════════════════
   COMMAND CENTER — main HUB overview
   ═══════════════════════════════════════════════════════════════════════ */
.cc-layout {
  display: grid;
  grid-template-columns: 1fr 380px;
  gap: 18px;
  align-items: start;
}

.cc-buildings {
  position: relative;
  aspect-ratio: 1672 / 941;
  height: auto;
  max-height: 82vh;
  background:
    linear-gradient(180deg, rgba(19, 44, 66, 0.16) 0%, rgba(8, 15, 26, 0.05) 36%, rgba(5, 10, 18, 0.46) 100%),
    linear-gradient(135deg, #071827 0%, #102c3e 42%, #071019 100%);
  border: 1px solid rgba(136, 230, 255, 0.22);
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: inset 0 0 70px rgba(136, 230, 255, 0.08), var(--shadow);
  isolation: isolate;
}

.cc-scene-bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  background-image: url('../Main%20HUB/art/main-hub-background-finished.png');
  /* MUST stretch (100% 100%), not cover — see renderHubArtLayer() for why:
     .cc-buildings can clamp to a non-1.777 aspect (max-height), and `cover`
     would then crop the base out of sync with the stretched building overlays
     and the %-positioned platform glow. (The inline style in renderHubArtLayer
     overrides this; kept consistent here as the fallback.) */
  background-size: 100% 100%;
  background-repeat: no-repeat;
  pointer-events: none;
}

/* Animated island background (hub-anim.js, 2026-06-04). The <video>s fill
   .cc-buildings the SAME way .cc-scene-bg does (stretch to 100% 100% via
   object-fit:fill), so the building hotspots/overlays stay in one coordinate
   space at any window aspect. The mount sits just above the static fallback
   (.cc-scene-bg) and below the building art / hotspots by DOM order. */
.cc-scene-video {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
  border-radius: inherit;
}
.cc-scene-video video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: fill;
  display: block;
}
.cc-scene-video .cc-anim-rare { z-index: 1; }   /* easter egg layered over the loop */

/* Top-bar Buildings button + facilities popover (2026-06-04) — replaces the old
   half-hidden floating buildings side panel. */
.btn-buildings {
  background: rgba(20,32,46,0.66);
  border: 1px solid rgba(120,160,200,0.28);
  color: #dce8f4;
  border-radius: 9px;
  padding: 7px 12px;
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: 0.02em;
  cursor: pointer;
  white-space: nowrap;
}
.btn-buildings:hover { background: rgba(30,46,64,0.9); border-color: rgba(150,190,230,0.55); }
.buildings-pop { min-width: 248px; }
.buildings-pop .bpop-row { display: flex; align-items: center; gap: 10px; cursor: pointer; border-radius: 7px; padding: 6px 8px; }
.buildings-pop .bpop-row:hover { background: rgba(120,160,200,0.14); }
.buildings-pop .bpop-lv { margin-left: auto; color: #9bb1c6; font-size: 11px; }
.buildings-pop .bpop-status { font-size: 11px; min-width: 60px; text-align: right; color: #9bb1c6; }
.buildings-pop .bpop-status.up { color: #7cff9b; }
.buildings-pop .bpop-status.building { color: #ffd166; }
.buildings-pop .bpop-status.maxed { color: #f3c64e; }

/* ── Construction side panel (2026-06-11) — slide-in, live build progress ──── */
.construction-panel {
  position: fixed; right: 0; top: 92px; z-index: 60;
  width: 252px; padding: 14px 14px 12px;
  background: linear-gradient(160deg, rgba(18,26,42,0.97), rgba(10,16,28,0.97));
  border: 1px solid var(--border); border-right: none;
  border-radius: 12px 0 0 12px;
  box-shadow: -10px 0 30px rgba(0,0,0,0.45), inset 0 0 0 1px rgba(136,230,255,0.04);
  transform: translateX(115%); opacity: 0; pointer-events: none;
  transition: transform 0.4s cubic-bezier(0.16,0.84,0.3,1), opacity 0.35s ease;
}
.construction-panel.show { transform: translateX(0); opacity: 1; pointer-events: auto; }
.cn-head {
  font-family: var(--font-mono); font-size: 10.5px; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--ink-dimmer); margin-bottom: 11px;
}
.cn-slot {
  display: flex; align-items: center; gap: 11px;
  padding: 9px 10px; margin-bottom: 8px;
  background: rgba(140,170,210,0.05);
  border: 1px solid var(--border-soft); border-radius: 9px;
}
.cn-slot-num {
  flex: none; width: 24px; height: 24px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 11px; font-weight: 700; font-family: var(--font-mono);
  background: var(--bg-1); color: var(--ink-dimmer); border: 1px solid var(--border-soft);
}
.cn-slot-body { flex: 1; min-width: 0; }
.cn-slot-title { font-size: 12.5px; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cn-slot-active {
  background: linear-gradient(100deg, rgba(136,230,255,0.10), rgba(136,230,255,0.02));
  border-color: rgba(136,230,255,0.45); box-shadow: 0 0 14px rgba(136,230,255,0.14);
}
.cn-slot-active .cn-slot-num { background: var(--accent); color: #04141b; border-color: transparent; }
.cn-bar { height: 6px; border-radius: 4px; background: rgba(0,0,0,0.35); overflow: hidden; margin-top: 7px; }
.cn-bar-fill {
  height: 100%; width: 0%; border-radius: 4px;
  background: linear-gradient(90deg, #4fb3d9, var(--accent));
  box-shadow: 0 0 8px var(--accent-glow); transition: width 0.2s linear;
}
.cn-slot-eta { font-family: var(--font-mono); font-size: 10px; color: var(--ink-dim); margin-top: 5px; }
.cn-slot-locked { opacity: 0.55; }
.cn-slot-locked .cn-slot-num { background: transparent; border-style: dashed; }
.cn-slot-empty .cn-slot-num { opacity: 0.6; }
.cn-slot-x {
  flex: none; background: none; border: none; color: #ff8a8a; cursor: pointer;
  font-size: 14px; line-height: 1; padding: 2px 4px; border-radius: 5px;
}
.cn-slot-x:hover { background: rgba(255,138,138,0.14); }
.cn-foot { font-size: 10px; color: var(--ink-dimmer); margin-top: 4px; line-height: 1.4; }
.cn-foot strong { color: var(--accent-warm); }

/* ───────────────────────────────────────────────────────────────────────
   Building art layer (2026-05-13)
   Each unlocked / built building is rendered as a positioned <img>
   over the empty hub. Stages 01-05 swap when the building levels up.
   z-index is between the scene bg (0) and the animated overlay (3) —
   building art reads as PART of the world, with energy pulses flowing
   over and around it.
   ─────────────────────────────────────────────────────────────────────── */
.cc-building-art-layer {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
}
.cc-building-art {
  position: absolute;
  left: var(--bx);
  top: var(--by);
  width: var(--bw);
  height: auto;
  /* --bsy flattens the building vertically (e.g. 0.85 makes it look as
     if viewed from a higher camera angle) — useful when an iso building
     was drawn at a slightly different camera elevation than the landscape. */
  transform: translate(-50%, -50%) rotate(var(--brot, 0deg)) scaleY(var(--bsy, 1));
  transform-origin: center center;
  pointer-events: none;
  filter: drop-shadow(0 14px 22px rgba(0, 0, 0, 0.35));
  /* Smooth cross-fade when stage src swaps on upgrade */
  transition: opacity 0.4s ease-out;
}
.cc-building-art.under-construction {
  opacity: 0.7;
  filter: drop-shadow(0 14px 22px rgba(0, 0, 0, 0.35))
          brightness(0.85) saturate(0.85);
  animation: cc-building-art-build-pulse 1.6s ease-in-out infinite;
}
@keyframes cc-building-art-build-pulse {
  0%, 100% { filter: drop-shadow(0 14px 22px rgba(0, 0, 0, 0.35)) brightness(0.82) saturate(0.85); }
  50%      { filter: drop-shadow(0 14px 28px rgba(120, 220, 255, 0.4)) brightness(1.05) saturate(1.0); }
}

/* 2026-05-26: full-canvas level-overlay variant.
   Each lv*.png is a full 1672×941 RGBA where the building is already at
   its correct plinth position (the rest is transparent). The overlay
   just stretches to fill .cc-buildings — no --bx/--by needed, no transform
   needed, no drop-shadow needed (the painted layer carries its own
   contact shadow on the plinth already). */
.cc-building-art.cc-level-overlay {
  position: absolute;
  inset: 0;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  /* Reset the legacy per-overlay transform from the --bx/--by path */
  transform: none;
  filter: none;
  /* Cross-fade between levels — when the player upgrades, the src changes
     and this transition smooths the swap. */
  transition: opacity 0.5s ease-out;
}
.cc-building-art.cc-level-overlay.under-construction {
  /* Override the legacy pulse — full-canvas overlays use a gentler filter
     pulse so the WHOLE building region doesn't flash on every cycle. */
  animation: cc-level-overlay-build-pulse 1.8s ease-in-out infinite;
  filter: none;
  opacity: 1;
}
@keyframes cc-level-overlay-build-pulse {
  0%, 100% { filter: brightness(0.92) saturate(0.92); }
  50%      { filter: brightness(1.08) saturate(1.05) drop-shadow(0 0 18px rgba(120, 220, 255, 0.25)); }
}

/* ── Forge overlay footprint mask (2026-05-31, per user "use the area of level 1
   for all") ────────────────────────────────────────────────────────────────
   The forge's higher-level overlay PNGs bake in a grassy base disc that WIDENS
   with level: the alpha bbox grows from x≈[1000,1341] at Lv1 to x≈[958,1388] at
   Lv5, and Lv5 adds palm trees at the outer edges. Composited over Background.png
   that wider disc + the palms read as a "pasted overlay" seam (the user's pic 2:
   "you can see the tree and small parts in the overlay").

   This horizontal soft mask fades everything OUTSIDE the Lv1 footprint (~59–80%
   of the 1672 px canvas) so every level occupies the same base width — the trees
   and the extra disc fade out, while the BUILDING (horizontally centred at
   x≈1170 / ~70%, and growing UPWARD with level) stays fully opaque. A soft
   gradient (not a hard clip-path) avoids a hard grass edge.

   SCOPED TO THE FORGE: the percentages are tuned to the forge's specific canvas
   position. Other buildings, once they get overlay art, will need their own mask
   — or, cleaner, art re-exported as building-only with no baked base disc. The
   glow HALO is deliberately left unmasked: it already uses the tight Lv1 art, and
   masking it would clip its outward drop-shadow (which IS the halo). */
.cc-building-art.cc-level-overlay[data-building-art="forge"] {
  -webkit-mask-image: linear-gradient(to right, transparent 57%, #000 61%, #000 79%, transparent 83%);
          mask-image: linear-gradient(to right, transparent 57%, #000 61%, #000 79%, transparent 83%);
}

/* ── Platform glow (2026-05-31, v4 — the one that actually works) ─────────────
   A soft gold smudge that highlights the building. It is NOT a hand-placed oval
   (every % geometry drifted off the painted platform). It's an <img> of a glow
   PNG DERIVED FROM the building's own Lv1 overlay (gold silhouette + heavy blur;
   see tools/gen_building_glow.py), rendered with the EXACT same box rules as the
   building overlay (.cc-level-overlay): inset 0, 100%×100%, object-fit fill. That
   guarantees it maps art-pixel → container the identical way the overlay does, so
   it sits exactly on the building at ANY window aspect — there's no geometry to
   get wrong. The blur is baked in → it reads as a glow, not a traced outline.

   Brightness is driven purely by opacity (the PNG carries the colour). HOVER-ONLY
   (v4.2): hidden by default, revealed only on .hover; a build in progress pulses
   while hovered; .celebrate is a momentary build-complete flare. No always-on glow. */
.cc-platform-glow {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: fill;                 /* identical mapping to .cc-level-overlay */
  pointer-events: none;
  mix-blend-mode: screen;           /* additive gold over the scene */
  opacity: 0;                        /* hidden by default; revealed by state/hover */
  transition: opacity 0.4s ease-out;
  transform-origin: 70% 28%;        /* fallback only — overridden per-building inline (each building's centre) in renderBuildingArtLayer, so the celebrate pop swells from the right spot */
  z-index: 3;
}
/* HOVER-ONLY (2026-05-31 v4.2, per user "the glow should only be when hovering"):
   no ambient / always-on highlight at all — the glow is purely a hover affordance.
   (is-built no longer lights it; the only persistent reveal is .hover.) Kept
   gentle per v4.1. */
.cc-platform-glow.hover { opacity: 0.6; }
/* While a build is running, hovering shows a gentle pulse instead of a flat glow. */
.cc-platform-glow.is-upgrading.hover { animation: cc-platform-glow-pulse 1.9s ease-in-out infinite; }
@keyframes cc-platform-glow-pulse {
  0%, 100% { opacity: 0.5;  filter: brightness(0.95); }
  50%      { opacity: 0.72; filter: brightness(1.3); }
}
/* Build-complete celebration — a MOMENTARY flare (an event, not a persistent
   glow): rises from 0, flares + swells centred on the building, returns to 0. So
   it fires even if you're not hovering, then leaves nothing behind. ~1.6s. */
.cc-platform-glow.celebrate { animation: cc-platform-glow-celebrate 1.6s cubic-bezier(.2,.8,.2,1) 1; }
@keyframes cc-platform-glow-celebrate {
  0%   { opacity: 0;    filter: brightness(1);   transform: scale(1); }
  16%  { opacity: 0.95; filter: brightness(1.9); transform: scale(1.14); }
  100% { opacity: 0;    filter: brightness(1);   transform: scale(1); }
}

/* Buildings with a bespoke platform-glow oval suppress the generic round ring. */
.cc-hotspot.has-platform-glow .cc-hotspot-ring { display: none; }

/* Forge build-progress bar — the generic rule floats it ABOVE the structure
   (top:-22px), which on the tall forge lands it up by the tower tips, divorced
   from the name card. Per user ("move the bar and name so they match the
   building pad"), drop it onto the platform's front lip, directly above the name
   card, so the bar + name read as one unit centred under the pad. */
.cc-hotspot.has-platform-glow .cc-hotspot-progress {
  top: auto;
  bottom: 38px;
}

/* The overlay is an <img> (cheap src-swap, no per-frame layer repaint) */
.cc-art-overlay {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 3;
  object-fit: cover;
  mix-blend-mode: screen;
  opacity: 0.92;
  pointer-events: none;
  /* Hint the compositor that this layer animates so it stays on its own
     GPU surface and src swaps don't repaint the whole scene below it. */
  will-change: transform;
  transform: translateZ(0);
}

/* ───────────────────────────────────────────────────────────────────────
   COMMAND CENTER — scene hotspots
   Each building in the painted scene gets an invisible hit-zone. Hover
   reveals a soft radial glow on the structure plus a typographic label
   pinned below. No visible card chrome — the painting carries the
   composition, the hotspot is just a discoverable click target.
   ─────────────────────────────────────────────────────────────────────── */
.cc-hotspot {
  position: absolute;
  /* Position + size driven entirely by --hx / --hy / --hw / --hh CSS
     vars, all expressed as % of the .cc-buildings container so the
     hotspots track the painted artwork through any resize. */
  left: var(--hx);
  top: var(--hy);
  width: var(--hw);
  height: var(--hh);
  transform: translate(-50%, -50%);
  background: transparent;
  border: none;
  padding: 0;
  margin: 0;
  cursor: pointer;
  z-index: 6;
  pointer-events: auto;
}
.cc-hotspot:focus { outline: none; }
.cc-hotspot:focus-visible .cc-hotspot-ring,
.cc-hotspot:hover .cc-hotspot-ring {
  opacity: 1;
}
.cc-hotspot:focus-visible .cc-hotspot-label,
.cc-hotspot:hover .cc-hotspot-label {
  opacity: 1;
  /* Settle position — base is translate(-50%, 50%) overlapping bottom
     edge; hover slides it up slightly so the player sees a gentle
     "rising banner" feel. */
  transform: translate(-50%, 42%);
}

.cc-hotspot-ring {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.22s ease-out;
  background:
    radial-gradient(ellipse at center,
      color-mix(in srgb, var(--facility-color) 22%, transparent) 0%,
      color-mix(in srgb, var(--facility-color) 8%, transparent) 38%,
      transparent 62%);
  box-shadow:
    0 0 38px color-mix(in srgb, var(--facility-color) 55%, transparent),
    inset 0 0 24px color-mix(in srgb, var(--facility-color) 28%, transparent);
  border: 1px solid color-mix(in srgb, var(--facility-color) 40%, transparent);
  mix-blend-mode: screen;
}

.cc-hotspot-label {
  position: absolute;
  left: 50%;
  /* Attach to the BOTTOM edge of the hotspot and overlap by 50%, so the
     label sits ON the lower half of the building rather than below it.
     Combined with a heavy backdrop-blur + low-opacity background, it
     reads as a translucent banner integrated into the building, not a
     floating tooltip parked off the structure. */
  bottom: 0;
  top: auto;
  transform: translate(-50%, 50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 8px 18px;
  white-space: nowrap;
  background: linear-gradient(180deg, rgba(8, 14, 26, 0.55) 0%, rgba(3, 7, 14, 0.72) 100%);
  border: 1px solid color-mix(in srgb, var(--facility-color) 50%, transparent);
  border-radius: 6px;
  box-shadow:
    0 10px 24px rgba(0, 0, 0, 0.55),
    0 0 20px color-mix(in srgb, var(--facility-color) 25%, transparent);
  opacity: 0;
  transition: opacity 0.22s ease-out, transform 0.22s ease-out;
  pointer-events: none;
  backdrop-filter: blur(8px);
}

.cc-hotspot-name {
  font-family: 'Cormorant Garamond', 'IBM Plex Serif', Georgia, serif;
  font-size: 22px;
  font-weight: 600;
  letter-spacing: 0.06em;
  line-height: 1;
  color: color-mix(in srgb, var(--facility-color) 78%, #ffffff);
  text-shadow:
    0 0 10px color-mix(in srgb, var(--facility-color) 55%, transparent),
    0 1px 2px rgba(0, 0, 0, 0.8);
}

.cc-hotspot-role {
  font-family: 'IBM Plex Sans', system-ui, sans-serif;
  font-size: 11px;
  font-weight: 400;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-dim);
}

/* Hover-revealed Build/Upgrade action inside the hotspot label.
   pointer-events: auto re-enables clicks (parent label has none).
   Stops propagation in JS so clicking doesn't also fire the hotspot's
   nav-to-building handler. */
.cc-hotspot-action {
  margin-top: 8px;
  padding: 6px 12px;
  font-family: 'IBM Plex Sans', system-ui, sans-serif;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  border-radius: 4px;
  pointer-events: auto;
  cursor: pointer;
  user-select: none;
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--facility-color) 25%, rgba(0, 0, 0, 0.6)) 0%,
    color-mix(in srgb, var(--facility-color) 12%, rgba(0, 0, 0, 0.7)) 100%);
  border: 1px solid color-mix(in srgb, var(--facility-color) 60%, transparent);
  color: color-mix(in srgb, var(--facility-color) 85%, white);
  text-shadow: 0 0 8px color-mix(in srgb, var(--facility-color) 50%, transparent);
  transition: background 0.15s, border-color 0.15s, transform 0.1s;
}
.cc-hotspot-action.enabled:hover {
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--facility-color) 40%, rgba(0, 0, 0, 0.55)) 0%,
    color-mix(in srgb, var(--facility-color) 22%, rgba(0, 0, 0, 0.65)) 100%);
  border-color: color-mix(in srgb, var(--facility-color) 90%, transparent);
  transform: translateY(-1px);
}
.cc-hotspot-action.enabled:active {
  transform: translateY(0);
}
.cc-hotspot-action.disabled {
  opacity: 0.45;
  cursor: not-allowed;
  pointer-events: auto;  /* allow title tooltip to show */
}

/* Locked / future-expansion hotspot variant (Overworld Gate) — visible
   but desaturated; hovering still shows the label with a "sealed" hint. */
.cc-hotspot.locked .cc-hotspot-ring {
  background: radial-gradient(ellipse at center, rgba(180, 180, 200, 0.16) 0%, transparent 60%);
  border-color: rgba(180, 180, 200, 0.35);
  box-shadow: 0 0 24px rgba(180, 180, 200, 0.18), inset 0 0 18px rgba(180, 180, 200, 0.12);
}
.cc-hotspot.locked .cc-hotspot-name {
  color: rgba(220, 220, 230, 0.85);
  text-shadow: 0 0 8px rgba(180, 180, 200, 0.4);
}

/* Construction-system hotspot states (2026-05-13). Each painted building
   has 3 possible visual states: site (Lv0, not built), upgrading (build
   countdown running), online (Lv1+ built normally). The 'online' state
   is the existing default styling above. */

/* Site (Lv0) — dashed desaturated ring with a subtle warm tint to suggest
   "buildable opportunity". Hover still lights up the ring like normal so
   the discoverability stays intuitive. */
.cc-hotspot.site .cc-hotspot-ring {
  border-style: dashed;
  border-color: rgba(255, 217, 102, 0.30);
  background: radial-gradient(ellipse at center, rgba(255, 217, 102, 0.06) 0%, transparent 60%);
  box-shadow: 0 0 18px rgba(255, 217, 102, 0.12), inset 0 0 14px rgba(255, 217, 102, 0.08);
  opacity: 0.55;
}
.cc-hotspot.site:hover .cc-hotspot-ring,
.cc-hotspot.site:focus-visible .cc-hotspot-ring {
  opacity: 1;
  border-style: solid;
  border-color: rgba(255, 217, 102, 0.7);
  box-shadow: 0 0 40px rgba(255, 217, 102, 0.4), inset 0 0 22px rgba(255, 217, 102, 0.22);
}
.cc-hotspot.site .cc-hotspot-name {
  color: rgba(255, 217, 102, 0.92);
  text-shadow: 0 0 10px rgba(255, 217, 102, 0.55), 0 1px 2px rgba(0, 0, 0, 0.8);
}

/* Upgrading — pulsing ring that always shows (no hover required) so the
   active build is obvious from across the screen. Uses facility-color so
   each building's pulse looks distinctive. */
.cc-hotspot.upgrading .cc-hotspot-ring {
  opacity: 1;
  border-color: color-mix(in srgb, var(--facility-color) 65%, transparent);
  animation: cc-hotspot-build-pulse 1.6s ease-in-out infinite;
}

/* Construction progress bar on the upgrading hotspot — sits ABOVE the
   structure so the player can read it without the building art
   obscuring it. Always visible (no hover required). z-index 4 puts it
   above the painted scene, the building art, and the energy overlay. */
.cc-hotspot-progress {
  position: absolute;
  left: 0%;
  right: 0%;
  top: -22px;
  height: 12px;
  pointer-events: none;
  background: rgba(2, 8, 18, 0.85);
  border-radius: 4px;
  overflow: hidden;
  box-shadow:
    0 0 14px color-mix(in srgb, var(--facility-color) 50%, transparent),
    0 4px 12px rgba(0, 0, 0, 0.7),
    inset 0 0 2px rgba(0, 0, 0, 0.85);
  border: 1px solid color-mix(in srgb, var(--facility-color) 70%, transparent);
  z-index: 4;
}
.cc-hotspot-progress-fill {
  display: block;
  height: 100%;
  width: 0%;
  background: linear-gradient(90deg,
    color-mix(in srgb, var(--facility-color) 75%, transparent) 0%,
    var(--facility-color) 60%,
    color-mix(in srgb, var(--facility-color) 80%, white) 100%);
  box-shadow:
    4px 0 14px color-mix(in srgb, var(--facility-color) 75%, transparent),
    inset -2px 0 6px color-mix(in srgb, var(--facility-color) 60%, white);
}
@keyframes cc-hotspot-build-pulse {
  0%, 100% {
    box-shadow:
      0 0 30px color-mix(in srgb, var(--facility-color) 40%, transparent),
      inset 0 0 18px color-mix(in srgb, var(--facility-color) 22%, transparent);
    transform: scale(1.0);
  }
  50% {
    box-shadow:
      0 0 56px color-mix(in srgb, var(--facility-color) 70%, transparent),
      inset 0 0 30px color-mix(in srgb, var(--facility-color) 38%, transparent);
    transform: scale(1.02);
  }
}

/* ───────────────────────────────────────────────────────────────────────
   Building-strip — header on every building screen showing current level,
   next level cost, and the Build/Upgrade button. Also reused inside the
   construction-site panel as the primary call-to-action.
   ─────────────────────────────────────────────────────────────────────── */
.building-strip {
  margin: 0 0 18px;
  padding: 14px 18px;
  border-radius: var(--radius);
  background: linear-gradient(180deg, rgba(14, 24, 40, 0.66) 0%, rgba(8, 14, 26, 0.85) 100%);
  border: 1px solid var(--border-soft);
}
.building-strip.site {
  border-color: rgba(255, 217, 102, 0.35);
  background: linear-gradient(180deg, rgba(40, 30, 12, 0.55) 0%, rgba(20, 14, 6, 0.78) 100%);
}
.building-strip.upgrading {
  border-color: color-mix(in srgb, var(--accent) 55%, transparent);
  background: linear-gradient(180deg, rgba(8, 24, 38, 0.68) 0%, rgba(4, 14, 22, 0.86) 100%);
}
.building-strip.maxed {
  border-color: rgba(158, 255, 192, 0.32);
  background: linear-gradient(180deg, rgba(8, 28, 18, 0.55) 0%, rgba(4, 16, 10, 0.78) 100%);
}
.building-strip-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
}
.building-strip-title { display: flex; align-items: baseline; gap: 10px; }
.building-strip-title strong { font-size: 16px; letter-spacing: 0.03em; }
.building-strip-cta { display: flex; align-items: center; gap: 10px; }
.building-strip-eta { color: var(--accent); font-weight: 600; letter-spacing: 0.04em; }
.building-strip-bar {
  margin: 10px 0 6px;
  height: 6px;
  background: rgba(0, 0, 0, 0.45);
  border-radius: 3px;
  overflow: hidden;
}
.building-strip-fill {
  height: 100%;
  background: linear-gradient(90deg, var(--accent) 0%, color-mix(in srgb, var(--accent) 60%, white) 100%);
  transition: width 0.2s ease-out;
  box-shadow: 0 0 12px color-mix(in srgb, var(--accent) 60%, transparent);
}
.building-strip-next { margin-top: 10px; }
.building-strip-cost {
  font-size: 13px;
  margin-top: 4px;
  display: flex;
  flex-wrap: wrap;
  gap: 4px 10px;
  align-items: center;
}

/* Heroes-3-town-view-style requirements checklist (2026-06-01) — replaces the
   terse "build X first" line. Each row is a prerequisite (facility / body %) or
   a cost (BT / ATP / material), green ✓ when met, red ✗ when not. */
.req-h {
  margin-top: 9px;
  font-size: 10px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-dim);
  font-weight: 600;
}
.build-reqs {
  list-style: none;
  margin: 6px 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 5px 18px;
}
.build-req {
  display: flex;
  align-items: baseline;
  gap: 6px;
  font-size: 13px;
}
.build-req .req-mark { font-weight: 700; width: 12px; text-align: center; flex: 0 0 auto; }
.build-req.met            { color: var(--ink); }
.build-req.met   .req-mark { color: #74dca0; }
.build-req.unmet          { color: #ff9a9a; }
.build-req.unmet .req-mark { color: #ff7a7a; }
.req-sub { color: var(--ink-dim); font-size: 11px; opacity: 0.85; }
.cost-token, .cost-rare {
  padding: 2px 8px;
  border-radius: 3px;
  background: rgba(0, 0, 0, 0.35);
  border: 1px solid var(--border-soft);
}
.cost-token.ok, .cost-rare.ok { color: var(--ok); border-color: color-mix(in srgb, var(--ok) 40%, transparent); }
.cost-token.lack, .cost-rare.lack { color: var(--lack); border-color: color-mix(in srgb, var(--lack) 40%, transparent); }

/* ─── Buildings Overview side panel ──────────────────────────────────────
   Compact list of all buildings on the Command Center. Each row shows:
   - Building name
   - Current level
   - Right cell: inline Upgrade button OR live progress bar with countdown
   The progress bar uses [data-progress-for] so the rAF updater in
   hub/app.js animates it inline without a full re-render.
   ──────────────────────────────────────────────────────────────────────── */
.bo-list {
  /* Block container instead of flex — rows are block-level grids, so
     they naturally span the panel width regardless of internal grid
     template. Flex column was collapsing the building-state row to
     its content width. */
  display: block;
}
.bo-list > .bo-row + .bo-row { margin-top: 4px; }
.bo-row {
  /* Flex (not grid) so the bar can grow into remaining row width
     naturally. Grid intrinsic-sizing was collapsing the row to its
     content width when no column had `1fr`. */
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px 10px;
  background: rgba(8, 14, 26, 0.36);
  border: 1px solid var(--border-soft);
  border-radius: 4px;
  font-size: 12px;
  min-height: 46px;
  box-sizing: border-box;
  width: 100%;
}
.bo-row > .bo-name {
  flex: 1 1 auto;       /* name takes remaining space when idle */
}
.bo-row > .bo-level {
  flex: 0 0 auto;       /* level text compact */
}
.bo-row > .bo-upgrade-btn,
.bo-row > .bo-max {
  flex: 0 0 auto;       /* upgrade button + MAX badge compact */
}
.bo-row > .bo-progress {
  flex: 1 1 0;          /* progress bar fills remaining width when building */
}
.bo-row.is-building > .bo-name {
  /* In building state: cap the name's max width hard so the progress
     bar dominates the row. Long names truncate to ellipsis. */
  flex: 0 1 auto;
  min-width: 0;
  max-width: 90px;
  opacity: 0.85;
}
.bo-row.is-building > .bo-level {
  /* Keep the level text compact in building state so the progress bar dominates. */
  opacity: 0.85;
}

/* Current building level text. Replaces the old fixed 5-pip row, which revealed
   the MAX by its dot count — the player now discovers the ceiling by reaching it
   (user 2026-06-01: "max should be unknown"). Shows just "Lv N" / "Not built". */
.bo-level {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--ink-dim);
  white-space: nowrap;
}
.bo-row.site { border-color: rgba(255, 217, 102, 0.28); }
.bo-row.is-building {
  border-color: color-mix(in srgb, var(--accent) 50%, transparent);
  background: linear-gradient(180deg, rgba(8, 24, 38, 0.46) 0%, rgba(4, 14, 22, 0.36) 100%);
  /* When building, the .bo-progress element has flex: 1 1 0 so it
     naturally consumes the leftover row width — see flex setup above. */
}
.bo-name {
  font-weight: 500;
  letter-spacing: 0.02em;
  /* Single line, ellipsis if too long — otherwise long names like
     "Microscope Launch Bay" wrap to 3 lines, making the row taller
     than its progress-bar siblings and creating the "bar floats
     halfway between rows" visual bug. */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}
.bo-level {
  color: var(--ink-dim);
  font-family: 'IBM Plex Mono', monospace;
  font-size: 11px;
  letter-spacing: 0.04em;
}
.bo-max {
  color: var(--ok);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.bo-upgrade-btn {
  font-size: 11px;
  padding: 4px 10px;
  white-space: nowrap;
}
.bo-cancel-btn,
.bo-skip-btn {
  font-size: 14px;
  font-weight: 600;
  padding: 0 8px;
  line-height: 22px;
  height: 22px;
  margin-left: 6px;
}
.bo-skip-btn {
  background: rgba(255, 217, 102, 0.1);
  border-color: rgba(255, 217, 102, 0.35);
  color: var(--accent-warm);
}
.bo-skip-btn:hover {
  background: rgba(255, 217, 102, 0.2);
  border-color: var(--accent-warm);
}
.bo-progress {
  position: relative;
  min-width: 140px;
  height: 18px;
  border-radius: 3px;
  background:
    /* Subtle grid-stripe pattern under the unfilled portion so the bar
       reads as "filled vs empty" even at low fill % — no more flat black. */
    repeating-linear-gradient(90deg,
      rgba(255, 255, 255, 0.03) 0px,
      rgba(255, 255, 255, 0.03) 4px,
      transparent 4px,
      transparent 8px),
    rgba(0, 0, 0, 0.55);
  border: 1px solid color-mix(in srgb, var(--accent) 45%, transparent);
  overflow: hidden;
}
.bo-progress-fill {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  width: 0%;
  /* Solid cyan with a brighter band at the right (leading) edge — reads
     as a moving energy front rather than a flat block with a hard cut. */
  background:
    linear-gradient(90deg,
      color-mix(in srgb, var(--accent) 85%, transparent) 0%,
      var(--accent) 70%,
      color-mix(in srgb, var(--accent) 60%, white) 100%);
  box-shadow:
    /* Glow extending past the right edge — softens the boundary between
       filled and unfilled regions. */
    4px 0 14px color-mix(in srgb, var(--accent) 60%, transparent),
    inset -2px 0 6px color-mix(in srgb, var(--accent) 50%, white);
  /* NO transition — JS updates this every rAF frame (~16 ms / 60 Hz),
     and a 150 ms transition was interrupting each frame's update mid-
     animation, producing visible "step" motion. Without a transition,
     the fill width tracks the timer at full frame rate. */
}
.bo-progress-eta {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--ink);
  text-shadow: 0 0 4px rgba(0, 0, 0, 0.9), 0 1px 2px rgba(0, 0, 0, 0.7);
  z-index: 1;
}

/* Construction-site full-screen panel — shown when a Lv0 building's
   screen is opened. Replaces the normal screen body with a build CTA. */
.construction-site-panel {
  text-align: center;
  padding: 60px 40px;
  max-width: 720px;
  margin: 40px auto;
  background: linear-gradient(180deg, rgba(40, 30, 12, 0.5) 0%, rgba(20, 14, 6, 0.8) 100%);
  border: 1px dashed rgba(255, 217, 102, 0.3);
  border-radius: var(--radius-lg);
}
.construction-site-illo {
  font-size: 96px;
  color: rgba(255, 217, 102, 0.65);
  text-shadow: 0 0 32px rgba(255, 217, 102, 0.55);
  margin-bottom: 18px;
  line-height: 1;
}
.construction-site-panel h3 {
  font-family: 'Cormorant Garamond', 'IBM Plex Serif', Georgia, serif;
  font-size: 26px;
  font-weight: 600;
  letter-spacing: 0.04em;
  margin: 0 0 12px;
}
.construction-site-panel p {
  max-width: 540px;
  margin: 0 auto 28px;
  line-height: 1.55;
}
.construction-site-panel .building-strip {
  text-align: left;
  margin-top: 28px;
}

/* Active-marker pip — drawn on the hotspot ring when the building has a
   pending event (forge ready, market deals, etc.). Pulses softly. */
.cc-hotspot-marker {
  position: absolute;
  top: 4px;
  right: 4px;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--accent-warm);
  box-shadow: 0 0 12px var(--accent-warm);
  animation: hotspot-marker-pulse 1.8s ease-in-out infinite;
  z-index: 1;
}
@keyframes hotspot-marker-pulse {
  0%, 100% { opacity: 0.6; transform: scale(0.92); }
  50%      { opacity: 1.0; transform: scale(1.12); }
}
.cc-buildings::before,
.cc-buildings::after {
  content: '';
  position: absolute;
  pointer-events: none;
}
.cc-buildings::before {
  display: none;
}
.cc-buildings::after {
  inset: 0;
  z-index: 4;
  background:
    linear-gradient(90deg, transparent 0%, rgba(136, 230, 255, 0.04) 50%, transparent 100%);
  opacity: 0.4;
  mix-blend-mode: screen;
  animation: hub-scan 16s linear infinite;
  animation-delay: var(--scene-delay);
  pointer-events: none;
}

.cc-art-layer {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  opacity: 0.18;
  mix-blend-mode: screen;
}
.cc-horizon {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(ellipse at 16% 10%, rgba(232, 223, 198, 0.14) 0%, transparent 22%),
    radial-gradient(ellipse at 72% 6%, rgba(255, 217, 102, 0.11) 0%, transparent 20%),
    linear-gradient(180deg, rgba(119, 179, 196, 0.18) 0%, transparent 31%);
  opacity: 0.72;
}
.cc-lab-platform {
  position: absolute;
  left: 50%;
  top: 52%;
  width: min(78%, 840px);
  aspect-ratio: 1.75;
  border-radius: 50%;
  transform: translate(-50%, -50%) rotate(-2deg);
  background:
    radial-gradient(ellipse at 50% 50%, rgba(136, 230, 255, 0.11) 0%, transparent 21%),
    repeating-conic-gradient(from 4deg at 50% 50%, rgba(136, 230, 255, 0.16) 0deg 2deg, transparent 2deg 19deg),
    radial-gradient(ellipse at 50% 50%, rgba(232, 223, 198, 0.16) 0%, rgba(37, 50, 76, 0.16) 52%, transparent 70%);
  border: 1px solid rgba(232, 223, 198, 0.18);
  box-shadow: inset 0 0 32px rgba(136, 230, 255, 0.12);
}
.cc-vat-monument {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 190px;
  height: 270px;
  transform: translate(-50%, -58%);
  z-index: 2;
  opacity: 0.78;
}
.cc-vat-glass {
  position: absolute;
  inset: 0 42px;
  border-radius: 42px;
  background:
    linear-gradient(90deg, transparent 0%, rgba(136, 230, 255, 0.2) 18%, rgba(136, 230, 255, 0.04) 50%, rgba(255, 255, 255, 0.15) 82%, transparent 100%),
    radial-gradient(ellipse at 50% 25%, rgba(136, 230, 255, 0.28) 0%, transparent 52%);
  border: 1px solid rgba(136, 230, 255, 0.5);
  box-shadow: 0 0 32px rgba(136, 230, 255, 0.35), inset 0 0 28px rgba(136, 230, 255, 0.18);
  animation: vat-column-breathe 5.6s ease-in-out infinite;
  animation-delay: var(--scene-delay);
}
.cc-vat-glass::before,
.cc-vat-glass::after {
  content: '';
  position: absolute;
  left: 50%;
  width: 116%;
  height: 28px;
  border: 1px solid rgba(136, 230, 255, 0.42);
  border-radius: 50%;
  transform: translateX(-50%);
}
.cc-vat-glass::before { top: -10px; background: rgba(136, 230, 255, 0.1); }
.cc-vat-glass::after  { bottom: -10px; background: rgba(136, 230, 255, 0.16); }
.cc-vat-figure {
  position: absolute;
  left: 50%;
  top: 45%;
  width: 54px;
  height: 128px;
  transform: translate(-50%, -50%);
  opacity: 0.72;
  filter: drop-shadow(0 0 10px rgba(136, 230, 255, 0.8));
}
.cc-vat-figure::before {
  content: '';
  position: absolute;
  left: 50%;
  top: 0;
  width: 20px;
  height: 20px;
  border: 2px solid rgba(180, 244, 255, 0.95);
  border-radius: 50%;
  transform: translateX(-50%);
}
.cc-vat-figure::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 22px;
  width: 2px;
  height: 78px;
  background: rgba(180, 244, 255, 0.95);
  box-shadow:
    -16px 18px 0 -1px rgba(180, 244, 255, 0.95),
    16px 18px 0 -1px rgba(180, 244, 255, 0.95),
    -12px 74px 0 -1px rgba(180, 244, 255, 0.95),
    12px 74px 0 -1px rgba(180, 244, 255, 0.95);
  transform: translateX(-50%);
}
.cc-orbit-ring {
  position: absolute;
  left: 50%;
  top: 51%;
  border: 1px solid rgba(136, 230, 255, 0.26);
  border-radius: 50%;
  transform: translate(-50%, -50%);
  opacity: 0.8;
}
.cc-orbit-ring::before {
  content: '';
  position: absolute;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 16px var(--accent);
}
.ring-1 {
  width: 300px;
  height: 108px;
  animation: orbit-drift-1 12s linear infinite;
  animation-delay: var(--scene-delay);
}
.ring-1::before { left: 72%; top: 3px; }
.ring-2 {
  width: 458px;
  height: 182px;
  border-color: rgba(255, 217, 102, 0.18);
  animation: orbit-drift-2 18s linear infinite;
  animation-delay: var(--scene-delay);
}
.ring-2::before { left: 12%; top: 26px; background: var(--accent-warm); box-shadow: 0 0 16px var(--accent-warm); }
.ring-3 {
  width: 620px;
  height: 286px;
  border-color: rgba(158, 255, 192, 0.14);
  animation: orbit-drift-3 24s linear infinite;
  animation-delay: var(--scene-delay);
}
.ring-3::before { right: 18%; bottom: 28px; background: #9effc0; box-shadow: 0 0 16px rgba(158, 255, 192, 0.8); }
.cc-conduit {
  position: absolute;
  left: 50%;
  top: 50%;
  z-index: 2;
  width: 34%;
  height: 3px;
  transform-origin: 0 50%;
  background: linear-gradient(90deg, rgba(136, 230, 255, 0.55), color-mix(in srgb, var(--facility-color) 74%, transparent), transparent);
  box-shadow: 0 0 12px color-mix(in srgb, var(--facility-color) 58%, transparent);
  opacity: 0.84;
}
.cc-conduit i {
  position: absolute;
  top: -4px;
  left: 0;
  width: 18px;
  height: 10px;
  border-radius: 999px;
  background: var(--facility-color);
  box-shadow: 0 0 18px var(--facility-color);
  animation: conduit-flow 3.7s linear infinite;
  animation-delay: var(--flow-delay);
}
.cc-conduit-vault { width: 42%; transform: rotate(-143deg); }
.cc-conduit-dnalab { width: 31%; transform: rotate(-90deg); }
.cc-conduit-forge { width: 42%; transform: rotate(-37deg); }
.cc-conduit-research { width: 35%; transform: rotate(180deg); }
.cc-conduit-engineering { width: 35%; transform: rotate(0deg); }
.cc-conduit-market { width: 42%; transform: rotate(143deg); }
.cc-conduit-launch-bay { width: 33%; transform: rotate(90deg); }
.cc-facility-pad {
  position: absolute;
  z-index: 3;
  width: 184px;
  height: 84px;
  border-radius: 50%;
  transform: translate(-50%, -50%);
  background:
    radial-gradient(ellipse at 50% 50%, color-mix(in srgb, var(--facility-color) 28%, transparent) 0%, transparent 55%),
    radial-gradient(ellipse at 50% 50%, rgba(8, 14, 26, 0.8) 0%, rgba(8, 14, 26, 0.38) 61%, transparent 68%);
  border: 1px solid color-mix(in srgb, var(--facility-color) 48%, transparent);
  box-shadow: 0 0 26px color-mix(in srgb, var(--facility-color) 20%, transparent);
  animation: pad-breathe 7s ease-in-out infinite;
  animation-delay: var(--pad-delay);
}
.cc-pad-core {
  position: absolute;
  left: 50%;
  top: 47%;
  width: 70px;
  height: 32px;
  border-radius: 50%;
  transform: translate(-50%, -50%);
  background: radial-gradient(ellipse at center, var(--facility-color) 0%, rgba(8, 14, 26, 0.72) 58%, transparent 72%);
  opacity: 0.55;
}
.pad-vault { left: 118px; top: 108px; }
.pad-dnalab { left: 50%; top: 106px; }
.pad-forge { right: 118px; top: 108px; transform: translate(50%, -50%); }
.pad-research { left: 118px; top: 50%; }
.pad-biovat {
  left: 50%;
  top: 50%;
  width: 280px;
  height: 140px;
  opacity: 0.72;
}
.pad-engineering { right: 118px; top: 50%; transform: translate(50%, -50%); }
.pad-market { left: 118px; top: calc(100% - 84px); }
.pad-launch-bay { left: 50%; top: calc(100% - 84px); }
.cc-mote-field {
  position: absolute;
  inset: 0;
  z-index: 4;
}
.cc-atp-mote {
  position: absolute;
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 12px var(--accent);
  opacity: 0;
  animation: mote-drift 18s ease-in-out infinite;
  animation-delay: var(--mote-delay);
}
.mote-1  { left: 16%; top: 28%; --mote-x: 34px;  --mote-y: -54px; }
.mote-2  { left: 28%; top: 70%; --mote-x: -38px; --mote-y: -64px; }
.mote-3  { left: 44%; top: 18%; --mote-x: 24px;  --mote-y: 42px; }
.mote-4  { left: 58%; top: 78%; --mote-x: -20px; --mote-y: -70px; }
.mote-5  { left: 74%; top: 26%; --mote-x: -44px; --mote-y: 52px; }
.mote-6  { left: 87%; top: 58%; --mote-x: -58px; --mote-y: -36px; }
.mote-7  { left: 20%; top: 52%; --mote-x: 60px;  --mote-y: -12px; }
.mote-8  { left: 35%; top: 39%; --mote-x: -18px; --mote-y: -48px; }
.mote-9  { left: 66%; top: 45%; --mote-x: 38px;  --mote-y: -46px; }
.mote-10 { left: 50%; top: 62%; --mote-x: 16px;  --mote-y: -76px; }
.mote-11 { left: 80%; top: 78%; --mote-x: -36px; --mote-y: -54px; }
.mote-12 { left: 12%; top: 76%; --mote-x: 42px;  --mote-y: -34px; }
.mote-13 { left: 91%; top: 19%; --mote-x: -40px; --mote-y: 46px; }
.mote-14 { left: 39%; top: 86%; --mote-x: 28px;  --mote-y: -62px; }
.cc-vat-halo {
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: 380px;
  height: 380px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(136, 230, 255, 0.10) 0%, transparent 60%);
  pointer-events: none;
  z-index: 5;
  mix-blend-mode: screen;
  opacity: 0.45;
  animation: vat-pulse 5s ease-in-out infinite;
  animation-delay: var(--scene-delay);
}
@keyframes vat-pulse {
  0%, 100% { opacity: 0.6; transform: translate(-50%, -50%) scale(1); }
  50%      { opacity: 1.0; transform: translate(-50%, -50%) scale(1.08); }
}

.building {
  position: absolute;
  width: 180px;
  z-index: 6;
  background:
    linear-gradient(180deg, rgba(12, 19, 32, 0.92) 0%, rgba(6, 12, 22, 0.86) 100%),
    radial-gradient(circle at 50% 0%, color-mix(in srgb, var(--facility-color, var(--accent)) 22%, transparent) 0%, transparent 58%);
  border: 1px solid color-mix(in srgb, var(--facility-color, var(--border)) 52%, var(--border));
  border-radius: var(--radius);
  padding: 14px;
  cursor: pointer;
  text-align: center;
  overflow: hidden;
  backdrop-filter: blur(8px);
  transition: transform 0.15s, border-color 0.15s, box-shadow 0.15s, background 0.15s;
  box-shadow: var(--shadow-sm), 0 0 18px color-mix(in srgb, var(--facility-color, var(--accent)) 12%, transparent);
  animation: building-breathe 9s ease-in-out infinite;
  animation-delay: var(--building-delay);
}
.building::before {
  content: '';
  position: absolute;
  left: 14px;
  right: 14px;
  top: 0;
  height: 2px;
  background: linear-gradient(90deg, transparent, var(--facility-color, var(--accent)), transparent);
  opacity: 0.78;
}
.building:hover {
  transform: translateY(-2px);
  border-color: var(--facility-color, var(--accent));
  box-shadow: var(--shadow), 0 0 28px color-mix(in srgb, var(--facility-color, var(--accent)) 42%, transparent);
}
.building-icon {
  font-size: 26px;
  color: var(--facility-color, var(--accent));
  margin-bottom: 6px;
  filter: drop-shadow(0 0 8px color-mix(in srgb, var(--facility-color, var(--accent)) 58%, transparent));
}
.building-name {
  font-weight: 600;
  font-size: 13px;
  letter-spacing: 0.02em;
  margin-bottom: 2px;
}
.building-role {
  font-size: 11px;
  color: var(--ink-dim);
  line-height: 1.3;
}
.building-glow {
  position: absolute;
  inset: 0;
  border-radius: var(--radius);
  pointer-events: none;
  background:
    radial-gradient(circle at 50% 0%, color-mix(in srgb, var(--facility-color, var(--accent)) 20%, transparent) 0%, transparent 44%),
    linear-gradient(90deg, transparent 0%, rgba(255, 255, 255, 0.06) 48%, transparent 100%);
  opacity: 0.8;
}

/* Bio-Vat at center */
.building.pos-c.center {
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: 220px;
  padding: 20px;
  border: 2px solid var(--accent);
  background:
    linear-gradient(180deg, rgba(20, 34, 52, 0.84) 0%, rgba(8, 14, 26, 0.74) 100%),
    radial-gradient(circle at 50% 36%, rgba(136, 230, 255, 0.24) 0%, transparent 58%);
  box-shadow: 0 0 46px rgba(136, 230, 255, 0.38), var(--shadow);
  z-index: 7;
}
.building.pos-c.center:hover { transform: translate(-50%, -50%) translateY(-2px); }
.building.pos-c.center .building-icon { font-size: 36px; }
.building.pos-c.center .building-name { font-size: 16px; }

/* Surrounding 8 positions */
.building.pos-nw { top: 30px;  left: 30px; }
.building.pos-n  { top: 30px;  left: 50%;  transform: translateX(-50%); }
.building.pos-ne { top: 30px;  right: 30px; }
.building.pos-w  { top: 50%;   left: 30px;  transform: translateY(-50%); }
.building.pos-e  { top: 50%;   right: 30px; transform: translateY(-50%); }
.building.pos-sw { bottom: 30px; left: 30px; }
.building.pos-s  { bottom: 30px; left: 50%;  transform: translateX(-50%); }
.building.pos-se { bottom: 30px; right: 30px; }
/* Hover variants don't get overridden by these transforms; restate */
.building.pos-n:hover  { transform: translateX(-50%) translateY(-2px); }
.building.pos-w:hover  { transform: translateY(-50%) translateY(-2px); }
.building.pos-e:hover  { transform: translateY(-50%) translateY(-2px); }
.building.pos-s:hover  { transform: translateX(-50%) translateY(-2px); }

.building.primary {
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--facility-color, var(--accent)) 24%, rgba(8, 14, 26, 0.92)) 0%, rgba(8, 14, 26, 0.88) 100%);
  border-color: var(--facility-color, var(--accent));
}

/* Overworld Gate teaser — visible but locked. Future-expansion hook
   per the 2026-05-12 roadmap (multiplayer macro-world combat). Visually
   distinct from regular building cards: desaturated, dashed border,
   lock glyph in the corner. Sits in the SE position. */
.building.overworld-teaser {
  background: linear-gradient(180deg, rgba(40, 50, 70, 0.45) 0%, rgba(20, 28, 46, 0.55) 100%);
  border: 1px dashed var(--border);
  color: var(--ink-dim);
  cursor: not-allowed;
  filter: saturate(0.4);
  opacity: 0.7;
}
.building.overworld-teaser:hover {
  filter: saturate(0.6);
  opacity: 0.9;
  border-color: var(--ink-dim);
}
.building.overworld-teaser .building-icon { color: var(--ink-dim); }
.overworld-lock-icon {
  position: absolute;
  top: 6px;
  right: 8px;
  font-size: 14px;
  color: var(--warn);
  opacity: 0.6;
}

.cc-side {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

/* Progressive-disclosure hint — small footer on the buildings panel
   showing "X of Y facilities online" plus an optional next-up hint list.
   Soft, motivational; disappears at 100% completion. */
.cc-progress-hint {
  position: absolute;
  left: 16px;
  right: auto;
  bottom: 12px;
  z-index: 8;
  max-width: min(320px, calc(100% - 32px));
  padding: 6px 10px;
  background: linear-gradient(180deg, rgba(4, 9, 18, 0.55) 0%, rgba(4, 9, 18, 0.85) 100%);
  border: 1px solid rgba(120, 160, 200, 0.18);
  border-radius: 4px;
  font-size: 11px;
  color: var(--ink-dim);
  line-height: 1.45;
  backdrop-filter: blur(6px);
  transition: max-width 0.2s ease-out, padding 0.2s ease-out;
}
.cc-progress-hint:hover {
  max-width: 340px;
}
.cc-progress-hint strong { color: var(--ink); }
.cc-progress-hint details { margin-top: 6px; }
.cc-progress-hint summary {
  cursor: pointer;
  user-select: none;
}
.cc-progress-hint .locked-hints {
  margin: 8px 0 0;
  padding-left: 18px;
}
.cc-progress-hint .locked-hints li {
  padding: 3px 0;
}

.hub-stat-grid {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 12px;
}
.hub-stat-big {
  font-size: 20px;
  font-weight: 700;
  color: var(--accent);
  font-family: var(--font-mono);
  margin-top: 4px;
}

.next-goal {
  background: linear-gradient(180deg, rgba(136, 230, 255, 0.06) 0%, transparent 100%);
  border: 1px solid var(--border-soft);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius);
  padding: 12px;
  line-height: 1.5;
}
.goal-cta { margin-top: 10px; display: flex; gap: 8px; flex-wrap: wrap; }

.active-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 4px 12px;
  padding: 8px 0;
  border-bottom: 1px solid var(--border-soft);
  font-size: 13px;
}
.active-row:last-child { border-bottom: none; }
.active-name { font-weight: 500; }
.active-time {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--ink-dim);
}
.active-bar {
  grid-column: 1 / -1;
  height: 4px;
  background: var(--bg-3);
  border-radius: 2px;
  overflow: hidden;
}
.active-fill {
  height: 100%;
  background: linear-gradient(90deg, var(--accent) 0%, #56c5ee 100%);
  transition: width 0.5s;
}

.ready-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 6px 0;
  border-bottom: 1px solid var(--border-soft);
  font-size: 13px;
}
.ready-row:last-child { border-bottom: none; }

/* ═══════════════════════════════════════════════════════════════════════
   BIO-VAT
   ═══════════════════════════════════════════════════════════════════════ */
.biovat-grid {
  display: grid;
  grid-template-columns: 380px 1fr 360px;
  gap: 14px;
  align-items: start;
}
.biovat-figure-panel {
  display: flex;
  flex-direction: column;
  align-items: stretch;
}

/* Three.js mount — owns the persistent WebGL canvas. Sized to give the
   body model real estate; height is fixed-ish so the OrbitControls camera
   has predictable framing. The canvas inside is sized by biovat-3d.js's
   ResizeObserver to fill this container. */
.biovat-3d-mount {
  position: relative;
  width: 100%;
  height: 540px;
  border-radius: var(--radius);
  overflow: hidden;
  background:
    radial-gradient(ellipse at center 35%, rgba(136, 230, 255, 0.10) 0%, rgba(8, 14, 26, 0.0) 65%),
    linear-gradient(180deg, #0b1320 0%, #06080f 100%);
  border: 1px solid var(--border-soft);
}
.biovat-3d-mount canvas {
  display: block;
  width: 100% !important;
  height: 100% !important;
}
.biovat-3d-loading {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--ink-dim);
  font-size: 12px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  pointer-events: none;
}
/* Hide the loading text once a canvas exists in the mount */
.biovat-3d-mount canvas ~ .biovat-3d-loading,
.biovat-3d-mount:has(canvas) .biovat-3d-loading {
  display: none;
}

.biovat-body-stat {
  margin-top: 14px;
  text-align: center;
  width: 100%;
  padding-top: 12px;
  border-top: 1px solid var(--border);
}
.biovat-body-stat .big {
  display: block;
  font-size: 26px;
  color: var(--accent);
  font-family: var(--font-mono);
  margin-top: 4px;
}

.systems-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.system-row {
  display: grid;
  grid-template-columns: 16px 1fr 1fr auto auto;
  align-items: center;
  gap: 12px;
  background: var(--bg-1);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
  padding: 10px 12px;
  cursor: pointer;
  text-align: left;
  font: inherit;
  color: inherit;
  transition: border-color 0.15s, background 0.15s;
}
.system-row:hover {
  border-color: var(--sys-color, var(--accent));
  background: var(--bg-2);
}
.system-row.selected {
  border-color: var(--sys-color, var(--accent));
  background: var(--bg-2);
  box-shadow: 0 0 12px rgba(136, 230, 255, 0.12);
}
.system-color {
  width: 12px; height: 12px;
  border-radius: 50%;
  box-shadow: 0 0 6px currentColor;
}
.system-name { font-weight: 500; }
.system-bar {
  height: 6px;
  background: var(--bg-3);
  border-radius: 3px;
  overflow: hidden;
}
.system-fill { display: block; height: 100%; }
.system-pct {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--ink);
  min-width: 48px;
  text-align: right;
}
.system-atp {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--ok);
  min-width: 78px;
  text-align: right;
}

.synergy-panel {
  margin-top: 16px;
  padding: 14px;
  background: linear-gradient(180deg, rgba(136, 192, 255, 0.06) 0%, transparent 100%);
  border: 1px solid var(--border-soft);
  border-left: 3px solid var(--neural);
  border-radius: var(--radius);
}

/* Anatomy-progress strip — per-biome blueprint completion as either
   X / N count or X.X% network. Lives between the system list and the
   muscle-neural synergy panel in the Bio-Vat screen. */
.anatomy-progress-strip {
  margin-top: 14px;
  padding: 10px 12px;
  background: rgba(232, 223, 198, 0.04);
  border: 1px solid var(--border-soft);
  border-left: 3px solid var(--bone);
  border-radius: var(--radius);
}
.anatomy-progress-strip.empty { font-style: italic; }
.anatomy-progress-h {
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-dim);
  font-weight: 600;
  margin-bottom: 8px;
}
.anatomy-row {
  display: grid;
  grid-template-columns: 1.4fr auto auto;
  grid-template-rows: auto auto;
  gap: 2px 12px;
  padding: 4px 0;
  font-size: 12px;
  align-items: center;
}
.anatomy-row-name {
  font-weight: 500;
  grid-row: 1;
}
.anatomy-row-value {
  grid-row: 1;
  font-family: var(--font-mono);
  text-align: right;
  font-weight: 600;
  color: var(--ink);
}
.anatomy-row-unit {
  grid-row: 1;
  grid-column: 3;
  text-align: right;
}
.anatomy-row-bar {
  grid-row: 2;
  grid-column: 1 / -1;
  height: 3px;
  background: var(--bg-3);
  border-radius: 2px;
  overflow: hidden;
}
.anatomy-row-fill {
  height: 100%;
  transition: width 0.4s;
}
.synergy-formula {
  font-size: 12px;
  font-family: var(--font-mono);
  color: var(--ink-dim);
  margin-bottom: 10px;
}
.synergy-row {
  display: flex;
  justify-content: space-between;
  padding: 4px 0;
  font-size: 13px;
}
.synergy-row.big {
  border-top: 1px solid var(--border-soft);
  margin-top: 6px;
  padding-top: 8px;
  font-size: 15px;
}
.synergy-row.big strong { color: var(--accent); }

.detail-block {
  padding: 12px 0;
  border-bottom: 1px solid var(--border-soft);
}
.detail-block:last-child { border-bottom: none; }
/* Muscle-atlas honesty block (Info panel): "X of N modeled" + named lists of
   the muscles in this region that are / aren't in the 3D model. */
.atlas-block { background: rgba(215, 118, 118, 0.06); border: none; border-left: 2px solid var(--muscle, #d77676); border-radius: var(--radius); padding: 10px 12px; }
.atlas-count { float: right; font-weight: 600; color: var(--ink); }
.atlas-tag {
  display: inline-block; font-size: 9px; font-weight: 700; letter-spacing: 0.06em;
  text-transform: uppercase; padding: 1px 6px; border-radius: 4px; margin-right: 5px; vertical-align: 1px;
}
.atlas-tag.ok   { color: #7fc486; background: rgba(127, 196, 134, 0.14); }
.atlas-tag.warn { color: #e0b15a; background: rgba(224, 177, 90, 0.14); }
.atlas-note { font-size: 10px; line-height: 1.45; opacity: 0.7; }
.detail-block.note {
  background: rgba(136, 192, 255, 0.05);
  padding: 10px 12px;
  border: none;
  border-radius: var(--radius);
  border-left: 2px solid var(--neural);
  font-size: 12px;
  color: var(--ink-dim);
}
.detail-block ul {
  margin: 6px 0 0;
  padding-left: 18px;
}
.detail-block li { padding: 2px 0; }

.system-summary {
  margin: 0 0 8px;
  color: var(--ink-dim);
  font-style: italic;
}

.placeable-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 8px;
  padding: 10px 0;
  border-top: 1px solid var(--border-soft);
}
.placeable-row:first-of-type { border-top: none; }
.placeable-counts {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 4px;
  font-size: 12px;
}

/* ═══════════════════════════════════════════════════════════════════════
   VAULT
   ═══════════════════════════════════════════════════════════════════════ */
.vault-layout {
  display: grid;
  grid-template-columns: 200px 1fr 380px;
  gap: 14px;
  align-items: start;
}
.vault-rail {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.cat-btn {
  display: grid;
  grid-template-columns: 12px 1fr auto;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  background: var(--bg-1);
  border: 1px solid var(--border-soft);
  color: var(--ink);
  font: inherit;
  text-align: left;
  border-radius: var(--radius);
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s;
}
.cat-btn:hover { background: var(--bg-2); border-color: var(--cat-color); }
.cat-btn.active { background: var(--bg-2); border-color: var(--cat-color); }
.cat-dot { width: 8px; height: 8px; border-radius: 50%; }
.cat-count {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--ink-dim);
}

.vault-grid {
  background: var(--bg-1);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 16px;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 10px;
  align-content: start;
  max-height: 70vh;
  overflow-y: auto;
}
.vault-card {
  display: grid;
  grid-template-columns: 46px 1fr;
  align-items: center;
  gap: 10px;
  padding: 10px;
  background: var(--bg-2);
  border: 1px solid var(--border-soft);
  border-left: 3px solid var(--rarity, var(--ink-dim));
  border-radius: var(--radius);
  cursor: pointer;
  font: inherit;
  color: inherit;
  text-align: left;
  transition: background 0.15s, transform 0.05s;
}
.vault-card:hover { background: var(--bg-3); }
.vault-card.selected {
  background: var(--bg-3);
  box-shadow: 0 0 12px var(--accent-glow);
}
.vault-icon {
  font-size: 18px;
  text-align: center;
  background: var(--bg-1);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-sm);
  padding: 3px;
  color: var(--rarity, var(--ink));
  display: flex; align-items: center; justify-content: center;
  min-height: 44px; overflow: hidden;
}
/* Loot item illustration (assets/loot/<id>.png) shown in the Vault, with the
   emoji as graceful fallback — see hub/vault.js resIconHtml(). */
.vault-img { width: 100%; height: 40px; object-fit: contain; display: block; }
.detail-icon { overflow: hidden; }
.detail-img { width: 100%; height: 100%; object-fit: contain; display: block; }
.vault-card-name { font-weight: 500; font-size: 13px; }
.vault-card-meta {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--ink-dim);
  display: flex;
  gap: 8px;
}
.vault-amt { color: var(--ink); }
.vault-pin { color: var(--accent-warm); }
.big-empty { padding: 40px; text-align: center; grid-column: 1 / -1; }

.vault-detail {
  background: var(--bg-1);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 16px;
  max-height: 75vh;
  overflow-y: auto;
}
.detail-h {
  display: flex;
  gap: 12px;
  align-items: center;
  margin-bottom: 14px;
}
.detail-icon {
  width: 44px; height: 44px;
  background: var(--bg-2);
  border-radius: var(--radius);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 22px;
  color: #061018;
}
.detail-h h3 { margin: 0 0 2px; font-size: 16px; }

/* Resource description — the biological "what is this?" blurb shown
   prominently above the stats grid. Italicized, lightly tinted, with a
   left rule to mark it as educational copy distinct from gameplay data. */
.resource-description {
  padding: 10px 12px;
  margin: 10px 0;
  background: rgba(136, 230, 255, 0.04);
  border-left: 2px solid var(--accent);
  border-radius: var(--radius);
  font-size: 12px;
  color: var(--ink-dim);
  font-style: italic;
  line-height: 1.55;
}

.detail-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  padding: 10px 0;
  border-bottom: 1px solid var(--border-soft);
}
.detail-grid > div { display: flex; flex-direction: column; gap: 2px; font-size: 13px; }

.detail-section {
  padding: 12px 0;
  border-bottom: 1px solid var(--border-soft);
}
.detail-section:last-child { border-bottom: none; }
/* (Removed 2026-06-03: .used-in-list / .pin-row / .pin-form / .sell-row /
   .safe-* — the Vault's old in-place sell + recipe-pinning UI. Selling moved
   to the Market and pinning was dropped in the view-only Vault redesign.) */

/* ═══════════════════════════════════════════════════════════════════════
   DNA LAB
   ═══════════════════════════════════════════════════════════════════════ */
.dnalab-grid {
  /* 2026-05-14 redesign — DNA Lab now a single vertical stack:
     Trickle Slots → Culture Library → Stockpile. All panels span full
     width because each is a list of equal-weight rows. */
  display: grid;
  grid-template-columns: 1fr;
  gap: 14px;
  align-items: start;
}
.dnalab-grid .wide { grid-column: 1 / -1; }

/* ── Trickle slots (one row per slot — assigned or empty) ─────────── */
.trickle-slot {
  display: grid;
  grid-template-columns: 1fr;
  gap: 6px;
  padding: 12px 14px;
  background: var(--bg-2);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
  margin-bottom: 8px;
}
.trickle-slot.empty {
  border-style: dashed;
  opacity: 0.75;
}
.trickle-slot.paused { border-color: var(--danger); }
.trickle-slot .slot-head {
  display: flex;
  gap: 10px;
  align-items: baseline;
}
.trickle-slot .slot-name {
  color: var(--accent);
  font-weight: 500;
}
.trickle-slot .slot-pause-tag {
  margin-left: auto;
  font-size: 11px;
  color: var(--danger);
  background: rgba(255, 80, 80, 0.08);
  padding: 2px 8px;
  border-radius: 10px;
}
.trickle-slot .slot-meta { line-height: 1.4; }
.trickle-slot .slot-bar {
  height: 6px;
  background: var(--bg-3);
  border-radius: 3px;
  overflow: hidden;
}
.trickle-slot .slot-fill {
  height: 100%;
  background: linear-gradient(90deg, var(--accent) 0%, #56c5ee 100%);
}
.trickle-slot.paused .slot-fill { background: var(--danger); opacity: 0.5; }
.trickle-slot .slot-foot {
  display: flex;
  gap: 8px;
  align-items: center;
}
.trickle-slot .slot-foot .muted { margin-right: auto; }
.trickle-slot .slot-action {
  display: flex;
  justify-content: flex-start;
}

/* ── Culture Code Library (one row per known/locked code) ─────────── */
.lib-picker-banner {
  background: rgba(86, 197, 238, 0.1);
  border: 1px solid var(--accent);
  border-radius: var(--radius);
  padding: 8px 12px;
  margin-bottom: 10px;
  display: flex;
  align-items: center;
  gap: 10px;
}
.lib-picker-banner button { margin-left: auto; }
.lib-list { display: flex; flex-direction: column; gap: 4px; }
.lib-row {
  display: grid;
  grid-template-columns: 1fr 180px 90px;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  background: var(--bg-2);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
}
.lib-row.locked { opacity: 0.55; }
.lib-row.rarity-uncommon { border-left: 3px solid #6cdf99; }
.lib-row.rarity-rare      { border-left: 3px solid #c89eff; }
.lib-row.rarity-signature { border-left: 3px solid #ffb85c; }
.lib-name { font-weight: 500; }
.lib-rarity { color: var(--ink-dim); font-size: 11px; font-weight: 400; }
.lib-stats { text-align: right; font-family: var(--font-mono); font-size: 11px; }
.lib-act { display: flex; justify-content: flex-end; }

.code-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.code-row {
  display: grid;
  grid-template-columns: 8px 1fr auto;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  background: var(--bg-2);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
  cursor: pointer;
  font: inherit;
  color: inherit;
  text-align: left;
  transition: background 0.15s, border-color 0.15s;
}
.code-row:hover:not(:disabled) { background: var(--bg-3); border-color: var(--accent); }
.code-row.selected { background: var(--bg-3); border-color: var(--accent); }
.code-row.locked { opacity: 0.45; cursor: not-allowed; }
.code-color { width: 4px; height: 30px; border-radius: 2px; }
.code-name { font-weight: 500; }
.code-time, .code-lock {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--ink-dim);
}

.codex-note {
  background: rgba(200, 158, 255, 0.06);
  border-left: 2px solid var(--brain);
  padding: 10px 12px;
  border-radius: var(--radius);
  font-size: 12px;
  color: var(--ink-dim);
  font-style: italic;
  margin-bottom: 12px;
}

.req-list {
  margin: 6px 0 0;
  padding-left: 18px;
  font-size: 13px;
}
.req-list li.ok { color: var(--ok); }
.req-list li.lack { color: var(--danger); }

.action-row {
  margin-top: 14px;
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
}
.action-row.big { margin-top: 18px; }
.auto-toggle {
  display: flex;
  gap: 6px;
  align-items: center;
  font-size: 12px;
  color: var(--ink-dim);
}

.prod-row {
  display: grid;
  grid-template-columns: 1fr auto auto;
  gap: 8px 12px;
  padding: 10px;
  background: var(--bg-2);
  border-radius: var(--radius);
  margin-bottom: 6px;
  align-items: center;
}
.prod-row.queued { opacity: 0.6; }
.prod-name { font-weight: 500; }
.prod-time {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--ink-dim);
}
.prod-bar {
  grid-column: 1 / -1;
  height: 4px;
  background: var(--bg-3);
  border-radius: 2px;
  overflow: hidden;
}
.prod-fill {
  height: 100%;
  background: linear-gradient(90deg, var(--accent) 0%, #56c5ee 100%);
  transition: width 0.5s;
}

.stock-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 8px;
}
.stock-cell {
  display: grid;
  grid-template-columns: 24px 1fr auto;
  gap: 10px;
  align-items: center;
  padding: 10px;
  background: var(--bg-2);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
}
.stock-cell.empty { opacity: 0.5; }
.stock-name { font-size: 13px; }
.stock-amt {
  font-family: var(--font-mono);
  font-weight: 600;
  color: var(--accent);
}

/* ═══════════════════════════════════════════════════════════════════════
   FORGE
   ═══════════════════════════════════════════════════════════════════════ */
/* Mode toggle: "Build Structures" vs "Synthesize Cells" — added 2026-05-14
   when the Forge gained the burst cell-synth path.  Sits between the
   construction strip and the category tabs. */
.forge-mode-tabs {
  display: flex;
  gap: 8px;
  margin-bottom: 12px;
}
.mode-tab {
  flex: 1 1 0;
  background: var(--bg-2);
  border: 1px solid var(--border-soft);
  color: var(--ink-dim);
  padding: 10px 14px;
  border-radius: var(--radius);
  font: inherit;
  font-weight: 500;
  cursor: pointer;
  text-align: left;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.mode-tab:hover { color: var(--ink); border-color: var(--accent); }
.mode-tab.active {
  background: var(--bg-3);
  color: var(--accent);
  border-color: var(--accent);
}

.forge-tabs {
  display: flex;
  gap: 4px;
  margin-bottom: 14px;
  border-bottom: 1px solid var(--border);
  padding-bottom: 6px;
}
.cat-tab {
  background: transparent;
  border: 1px solid transparent;
  color: var(--ink-dim);
  padding: 6px 12px;
  border-radius: var(--radius);
  cursor: pointer;
  font: inherit;
  font-size: 12px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.cat-tab:hover { color: var(--ink); }
.cat-tab.active {
  color: var(--cat-color, var(--accent));
  border-color: var(--cat-color, var(--accent));
}

.forge-grid {
  display: grid;
  grid-template-columns: 380px 1fr;
  grid-template-rows: auto auto;
  gap: 14px;
  align-items: start;
}
.forge-grid .wide { grid-column: 1 / -1; }

/* Build Bays + Ready-to-Place dock — a compact 2-up strip pinned at the TOP of
   the Forge content (right under the mode tabs) so active builds + their
   progress are always visible, instead of being marooned below a 62-row recipe
   list. The recipe browser + detail sit below it. */
.forge-dock {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
  margin-bottom: 14px;
}
.forge-dock-panel { min-width: 0; }
.forge-list-panel { align-self: start; }
@media (max-width: 720px) {
  .forge-dock { grid-template-columns: 1fr; }
}

.recipe-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
  /* Cap the list height so a long category (the 62-bone Skeleton tab) scrolls
     INTERNALLY instead of stretching the whole Forge screen — otherwise the
     Build Bays + Ready-to-Place panels get shoved far below the fold. The
     recipe DETAIL panel (right column) holds the build button, so the player
     never has to scroll the list to build. */
  max-height: min(54vh, 540px);
  overflow-y: auto;
  padding-right: 4px;
  scrollbar-width: thin;
}
.recipe-row {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  background: var(--bg-2);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
  cursor: pointer;
  font: inherit;
  color: inherit;
  text-align: left;
}
.recipe-row:hover { background: var(--bg-3); }
.recipe-row.selected {
  background: var(--bg-3);
  border-color: var(--accent);
}
.recipe-state {
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 3px 8px;
  border-radius: 99px;
  background: var(--bg-1);
  border: 1px solid var(--border);
  color: var(--ink-dim);
}
.recipe-state.ready { color: var(--ok); border-color: var(--ok); }
.recipe-state.needs { color: var(--warn); border-color: var(--warn); }
.recipe-state.locked { color: var(--ink-dimmer); }

.req-grid {
  display: grid;
  /* auto-fit so a wide detail column lays the 4 requirement cells out in a
     single row (was a fixed 2×2 that doubled the panel height and pushed the
     Build Bays off-screen). */
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 10px;
  padding: 8px 0;
}
.req-grid > div { background: var(--bg-2); padding: 8px 10px; border-radius: var(--radius); }

.effect-preview {
  margin-top: 12px;
  padding: 12px;
  border: 1px solid var(--border-soft);
  border-left: 3px solid var(--sys-color, var(--accent));
  border-radius: var(--radius);
  background: rgba(136, 230, 255, 0.03);
}

/* ═══════════════════════════════════════════════════════════════════════
   ENGINEERING
   ═══════════════════════════════════════════════════════════════════════ */
.engineering-grid {
  display: grid;
  grid-template-columns: 340px 1fr;
  grid-template-rows: auto auto;
  gap: 14px;
  align-items: start;
}
.engineering-grid .wide { grid-column: 1 / -1; }

.module-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.module-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 10px;
  padding: 10px 12px;
  background: var(--bg-2);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
  cursor: pointer;
  font: inherit;
  color: inherit;
  text-align: left;
}
.module-row:hover { background: var(--bg-3); }
.module-row.selected { background: var(--bg-3); border-color: var(--accent); }
.module-row.rig-locked {
  opacity: 0.45;
  cursor: not-allowed;
  border-style: dashed;
}
.module-row.rig-locked:hover { background: var(--bg-2); }
.module-name { font-weight: 500; }
.module-meta { color: var(--ink-dim); font-size: 11px; }

.module-level {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 2px;
}
.module-lv-label {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--ink-dim);
}
.lv-dot {
  display: inline-block;
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--bg-3);
  border: 1px solid var(--border);
  margin: 0 1px;
}
.lv-dot.filled { background: var(--accent); border-color: var(--accent); box-shadow: 0 0 4px var(--accent-glow); }

.current-level {
  padding: 12px;
  background: var(--bg-2);
  border-radius: var(--radius);
  margin: 12px 0;
}
.next-level {
  padding: 12px;
  background: var(--bg-2);
  border: 1px solid var(--border-soft);
  border-left: 3px solid var(--accent-warm);
  border-radius: var(--radius);
  margin-bottom: 12px;
}
.upgrade-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: 10px;
}
.cost { font-family: var(--font-mono); font-weight: 700; }

.stat-layers {
  margin-top: 14px;
  background: var(--bg-2);
  padding: 14px;
  border-radius: var(--radius);
  border: 1px solid var(--border-soft);
}
.stat-layers-h {
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-dim);
  margin-bottom: 6px;
}
.stat-layers-formula {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--ink-dim);
  margin-bottom: 12px;
}
.stat-layers-grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 10px;
}
.stat-layers-grid > div {
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: 12px;
}
.final-col strong.final-val {
  color: var(--accent);
  font-size: 18px;
  font-family: var(--font-mono);
}

.stat-summary-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 8px;
}
.stat-cell {
  background: var(--bg-2);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
  padding: 10px 12px;
  display: grid;
  grid-template-columns: 24px 1fr auto;
  grid-template-rows: auto auto;
  gap: 2px 10px;
}
.stat-cell-icon {
  grid-row: 1 / span 2;
  font-size: 18px;
  color: var(--accent);
}
.stat-cell-name {
  font-size: 11px;
  color: var(--ink-dim);
  letter-spacing: 0.04em;
}
.stat-cell-val {
  grid-row: 2;
  font-family: var(--font-mono);
  font-weight: 600;
  font-size: 16px;
  color: var(--ink);
}
.stat-cell-val .unit { font-size: 11px; color: var(--ink-dim); margin-left: 2px; }
.stat-cell-breakdown {
  grid-row: 1 / span 2;
  grid-column: 3;
  display: flex;
  flex-direction: column;
  gap: 2px;
  text-align: right;
  font-size: 10px;
  font-family: var(--font-mono);
}

/* ═══════════════════════════════════════════════════════════════════════
   RESEARCH
   ═══════════════════════════════════════════════════════════════════════ */
.research-tabs {
  display: flex;
  gap: 4px;
  margin-bottom: 14px;
  border-bottom: 1px solid var(--border);
  padding-bottom: 6px;
}
.branch-tab {
  display: flex;
  align-items: center;
  gap: 8px;
  background: transparent;
  border: 1px solid transparent;
  color: var(--ink-dim);
  padding: 6px 14px;
  border-radius: var(--radius);
  cursor: pointer;
  font: inherit;
  font-size: 12px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.branch-tab:hover { color: var(--ink); }
.branch-tab.active {
  color: var(--bcolor, var(--accent));
  border-color: var(--bcolor, var(--accent));
}
.branch-dot {
  width: 8px; height: 8px;
  border-radius: 50%;
}

.research-grid {
  display: grid;
  grid-template-columns: 1fr 360px;
  gap: 14px;
  align-items: start;
}

.nodes-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 10px;
}
.node-card {
  background: var(--bg-2);
  border: 1px solid var(--border-soft);
  border-left: 3px solid var(--bcolor, var(--accent));
  border-radius: var(--radius);
  padding: 12px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.node-card.locked { opacity: 0.55; }
.node-name { font-weight: 600; }
.node-desc { font-size: 12px; }
.node-bottom {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: auto;
  padding-top: 8px;
  border-top: 1px solid var(--border-soft);
}
.node-level { display: flex; align-items: center; gap: 6px; }

.bonus-list { padding-left: 18px; }
.bonus-list li { padding: 3px 0; font-size: 12px; }

.reset-row {
  display: grid;
  grid-template-columns: 1fr 1fr auto;
  gap: 10px;
  align-items: end;
  margin-top: 10px;
}

/* ═══════════════════════════════════════════════════════════════════════
   LAUNCH BAY
   ═══════════════════════════════════════════════════════════════════════ */
.launchbay-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
  align-items: start;
}
.biome-cards {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}
.biome-card {
  display: flex;
  flex-direction: column;
  gap: 4px;
  background: var(--bg-2);
  border: 1px solid var(--border-soft);
  border-left: 4px solid var(--bcolor, var(--accent));
  border-radius: var(--radius);
  padding: 12px;
  cursor: pointer;
  font: inherit;
  color: inherit;
  text-align: left;
  transition: background 0.15s, transform 0.05s;
}
.biome-card:hover { background: var(--bg-3); }
.biome-card.selected {
  background: var(--bg-3);
  box-shadow: 0 0 12px rgba(136, 230, 255, 0.18);
}
.biome-card.soft-locked { opacity: 0.6; }
.biome-card-h {
  display: flex;
  gap: 8px;
  align-items: baseline;
}
.biome-num {
  font-family: var(--font-mono);
  color: var(--ink-dimmer);
  font-size: 12px;
}
.biome-name { font-weight: 600; }
.biome-style { font-size: 11px; }
.biome-progress {
  font-size: 11px;
  margin-top: 4px;
  font-family: var(--font-mono);
}
.biome-gate { font-style: italic; margin-top: 4px; }

.biome-detail {
  border-left: 4px solid var(--bcolor, var(--accent));
  padding-left: 12px;
}
.biome-detail-h {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 10px;
}
.biome-detail-h h3 { margin: 0; font-size: 18px; }
.biome-style-badge {
  padding: 3px 10px;
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: 99px;
  font-size: 11px;
  color: var(--ink-dim);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.rec-modules { padding-left: 18px; }
.rec-modules li { padding: 2px 0; }

.gate-block {
  margin-top: 12px;
  padding: 10px 12px;
  background: rgba(255, 180, 85, 0.06);
  border-left: 2px solid var(--warn);
  border-radius: var(--radius);
}

.loadout-panel {
  margin: 14px 0;
  padding: 12px;
  background: var(--bg-2);
  border-radius: var(--radius);
  border: 1px solid var(--border-soft);
}
.loadout-chips {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  margin: 6px 0;
}
.loadout-chip {
  padding: 3px 10px;
  background: var(--bg-3);
  border: 1px solid var(--border);
  border-radius: 99px;
  font-size: 11px;
}

/* Dive ATP cost panel — shows Hub reserve, dive cost (= nano-bot
   capacity), and projected reserve-after-launch. The third row goes
   red when the player can't afford the dive. */
.dive-cost-panel {
  margin: 14px 0 4px;
  padding: 12px 14px;
  background: linear-gradient(180deg, rgba(136, 230, 255, 0.06) 0%, transparent 100%);
  border: 1px solid var(--border-soft);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius);
}
.dive-cost-row {
  display: flex;
  justify-content: space-between;
  padding: 5px 0;
  font-size: 13px;
}
.dive-cost-row:not(:last-child) {
  border-bottom: 1px solid var(--border-soft);
}

/* Slider control for choosing dive ATP deposit (2026-05-15) */
.dive-atp-control {
  margin: 10px 0;
  padding: 10px 0;
  border-top: 1px solid var(--border-soft);
  border-bottom: 1px solid var(--border-soft);
}
.dive-atp-control-h {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: 6px;
}
.dive-atp-readout {
  color: var(--accent);
  font-family: var(--font-mono);
  font-size: 15px;
}
.dive-atp-slider {
  width: 100%;
  margin: 2px 0 8px;
  -webkit-appearance: none;
  appearance: none;
  height: 6px;
  background: var(--bg-3);
  border-radius: 3px;
  outline: none;
}
.dive-atp-slider:disabled { opacity: 0.4; }
.dive-atp-slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--accent);
  border: 2px solid var(--bg-1);
  cursor: grab;
  box-shadow: 0 0 8px rgba(86, 197, 238, 0.5);
}
.dive-atp-slider::-moz-range-thumb {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--accent);
  border: 2px solid var(--bg-1);
  cursor: grab;
}
.dive-quickpicks {
  display: flex;
  gap: 4px;
  margin-bottom: 8px;
}
.dive-quickpicks .btn-tiny {
  flex: 1 1 0;
  font-size: 11px;
}
.dive-atp-hint {
  line-height: 1.5;
}

/* Dev button base — used by the consolidated Dev Tools bar (.cc-devbar) and
   the per-row Forge "Skip" affordance. Dashed-warning styling so dev controls
   read as scaffolding, not gameplay. (The old .dev-panel / .dev-h side-rail
   container + the Launch-Bay .sim-buttons simulator were removed 2026-05-30
   when all cheats were consolidated into the one bottom bar.) */
.dev-btn {
  margin-top: 8px;
  width: 100%;
  border-color: var(--warn);
  color: var(--warn);
}
.dev-btn:hover:not(:disabled) {
  background: rgba(255, 180, 85, 0.12);
  border-color: var(--warn);
}

/* Per-row dev affordance — small "Skip" button next to Cancel on active
   DNA / Forge productions. Same dashed-warning treatment as the larger
   dev panel so it reads as scaffolding, not a permanent gameplay button. */
.dev-skip {
  border: 1px dashed var(--warn) !important;
  color: var(--warn) !important;
  background: transparent !important;
}
.dev-skip:hover:not(:disabled) {
  background: rgba(255, 180, 85, 0.12) !important;
}

/* Cost-curve preview shown under a research node — small summary of
   total BT needed to fully max this node, with per-level breakdown
   in the native title tooltip. */
.cost-curve {
  margin-top: 4px;
  padding: 4px 0;
  border-top: 1px solid var(--border-soft);
  font-size: 11px;
}
.cost-curve strong { color: var(--ink); }

/* Dev tool grid — 2-up button layout used inside the consolidated Dev Tools
   bar's columns (.cc-devbar-body > .dev-col). */
.dev-tools-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px;
  margin-top: 10px;
}
.dev-tools-grid .dev-btn {
  margin-top: 0;
  width: 100%;
  font-size: 11px;
  padding: 6px 8px;
}

/* Dev panel: group sub-labels + per-biome loot buttons (2026-05-29). The
   biome buttons are accented with that biome's own colour via --biome-color
   (set inline) so the 14 of them stay scannable. */
.dev-sub {
  margin-top: 12px;
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-dim);
}
.dev-biome-grid { grid-template-columns: 1fr 1fr; }
.dev-biome-all {
  grid-column: 1 / -1;
  border-style: solid !important;
}
.dev-biome-btn {
  border-color: var(--border-soft) !important;
  border-left: 3px solid var(--biome-color, var(--accent)) !important;
  color: var(--ink) !important;
  text-align: left;
  white-space: normal;
  line-height: 1.15;
}
.dev-biome-btn:hover:not(:disabled) {
  background: rgba(136, 230, 255, 0.10) !important;
  border-left-color: var(--biome-color, var(--accent)) !important;
}
/* Per-button "what it grants" sub-label (bones / muscles / …) so the player
   doesn't have to know that "Soft Tissue Cavern" means muscles. */
.dev-biome-grant {
  display: block;
  font-size: 10px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--biome-color, var(--accent));
  opacity: 0.85;
  margin-top: 2px;
}
.dev-biome-grant.muted { color: var(--ink-dim); opacity: 0.6; }
/* Biomes with no authored loot yet — dimmed so clicks aren't wasted on them. */
.dev-biome-empty { opacity: 0.45; }
.dev-biome-empty:hover:not(:disabled) { opacity: 0.7; }

/* ───────────────────────────────────────────────────────────────────────
   DEV TOOLS BAR (2026-05-30) — the SINGLE consolidated cheat surface.
   A collapsible bar pinned to the bottom-left of the viewport, rendered only
   inside #screen-command-center. Because a hidden screen is display:none, this
   fixed child is hidden too — so the bar appears on the Command Center and
   nowhere else (no leakage onto the Bio-Vat / biome screens). Replaces the old
   side-rail dev panel and the in-biome cheats. .hub-main has no transform, so
   `position: fixed` anchors to the viewport as intended.
   ─────────────────────────────────────────────────────────────────────── */
.cc-devbar {
  position: fixed;
  left: 14px;
  bottom: 14px;
  z-index: 50;
  display: flex;
  flex-direction: column-reverse;   /* toggle (1st in DOM) sits at the bottom; body expands UP */
  align-items: flex-start;
  gap: 8px;
  max-width: min(720px, calc(100vw - 28px));
  pointer-events: none;             /* the empty gap is click-through; children re-enable below */
}
.cc-devbar > * { pointer-events: auto; }

.cc-devbar-toggle {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 7px 13px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--warn);
  background: rgba(14, 22, 33, 0.92);
  border: 1px dashed var(--warn);
  border-radius: 999px;
  cursor: pointer;
  backdrop-filter: blur(8px);
  box-shadow: var(--shadow);
  transition: background 0.15s ease, transform 0.08s ease;
}
.cc-devbar-toggle:hover { background: rgba(255, 180, 85, 0.14); }
.cc-devbar-toggle:active { transform: translateY(1px); }
.cc-devbar-caret { font-size: 9px; opacity: 0.8; }

.cc-devbar-body {
  width: min(680px, calc(100vw - 28px));
  max-height: 64vh;
  overflow-y: auto;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px 18px;
  padding: 14px 16px;
  background: rgba(10, 17, 27, 0.95);
  border: 1px dashed var(--warn);
  border-radius: var(--radius-lg);
  backdrop-filter: blur(12px);
  box-shadow: var(--shadow);
}
.dev-col { min-width: 0; }
/* Shared .dev-sub adds margin-top:12px; kill it on each column's first label so
   the panel's top edge stays tight. */
.dev-col > .dev-sub:first-child { margin-top: 0; }

@media (max-width: 720px) {
  .cc-devbar-body { grid-template-columns: 1fr; max-height: 56vh; }
}

/* ═══════════════════════════════════════════════════════════════════════
   MARKET
   ═══════════════════════════════════════════════════════════════════════ */
.market-grid {
  display: grid;
  grid-template-columns: 1fr 1fr 360px;
  gap: 14px;
  align-items: start;
}
.market-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
  max-height: 70vh;
  overflow-y: auto;
}
.market-row {
  display: grid;
  grid-template-columns: 44px 1fr auto;
  gap: 11px;
  padding: 9px 11px;
  background: var(--bg-2);
  border: 1px solid var(--border-soft);
  border-left: 3px solid var(--rarity, var(--ink-dim));
  border-radius: var(--radius);
  align-items: center;
  transition: border-color 0.14s, background 0.14s, transform 0.14s;
}
.market-row:hover {
  background: var(--bg-1);
  border-color: color-mix(in srgb, var(--rarity, #6f8196) 55%, var(--border-soft));
  transform: translateX(1px);
}
/* Item badge — a rarity-tinted slot so each material reads as a real "item",
 * elegant even before bespoke PNG art exists. The glyph (chemical symbol /
 * emoji) sits centered; a dropped-in assets/loot/<id>.png replaces it (see
 * mktIconHtml — filename-based drop-in art, no code change needed). */
.mkt-icon {
  width: 44px; height: 44px;
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-mono);
  font-size: 15px; font-weight: 700; letter-spacing: -0.02em;
  color: var(--rarity, var(--ink));
  background:
    radial-gradient(125% 125% at 30% 22%,
      color-mix(in srgb, var(--rarity, #6f8196) 30%, transparent),
      color-mix(in srgb, var(--rarity, #6f8196) 9%, transparent) 72%);
  border: 1px solid color-mix(in srgb, var(--rarity, #6f8196) 52%, transparent);
  border-radius: 11px;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.07), 0 1px 4px rgba(0,0,0,0.25);
  overflow: hidden;
}
/* Loot illustration in market rows (assets/loot/<id>.png), emoji fallback. */
.mkt-img { width: 36px; height: 36px; object-fit: contain; display: block; }
.market-row.sold-out { opacity: 0.55; }
.mkt-name { font-weight: 600; letter-spacing: 0.01em; }
.mkt-meta { font-family: var(--font-mono); margin-top: 1px; }
.mkt-actions { display: flex; gap: 4px; }

/* ── BioToken currency styling — green everywhere it's bought/sold/held ───────
 * `.bt-amt` colours a BioToken figure green; `.bt-coin` is the little green
 * token badge that stands in for the old ◈ glyph (a "cooler", cash-like mark). */
.bt-amt { color: var(--bt); font-weight: 600; }
.bt-coin {
  display: inline-block;
  width: 0.92em; height: 0.92em;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #c2f6d6, var(--bt) 60%, #2f8f5a);
  box-shadow: 0 0 4px rgba(86, 201, 138, 0.5), inset 0 0 0 1px rgba(255, 255, 255, 0.22);
  vertical-align: -0.12em;
  margin-right: 0.18em;
}

/* ── ATP packs — compact horizontal cards (wrap on narrow / phone) ──────────── */
.atp-pack-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 10px;
}
.atp-pack {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 10px 12px;
  background: var(--bg-2);
  border: 1px solid var(--border-soft);
  border-left: 3px solid var(--accent-warm);
  border-radius: var(--radius);
}
.atp-pack-h { display: flex; align-items: center; gap: 6px; }
.atp-pack-icon { color: var(--accent-warm); }
.atp-pack-name { font-weight: 600; font-size: 13px; }
.atp-pack-amt { font-size: 15px; font-weight: 700; }
.atp-pack-rate { font-family: var(--font-mono); }
.atp-pack-buy { margin-top: 7px; align-self: stretch; }

.hist-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
  max-height: 300px;
  overflow-y: auto;
}
.hist-row {
  display: grid;
  grid-template-columns: 16px 1fr auto;
  gap: 8px;
  padding: 6px 8px;
  background: var(--bg-2);
  border-radius: var(--radius-sm);
  font-family: var(--font-mono);
  font-size: 11px;
}
.hist-row.sell { color: var(--ok); }
.hist-row.buy  { color: var(--accent-warm); }

/* ═══════════════════════════════════════════════════════════════════════
   NOTIFICATIONS
   ═══════════════════════════════════════════════════════════════════════ */
.notif-modal {
  position: fixed;
  inset: 0;
  background: rgba(4, 8, 16, 0.7);
  display: none;
  align-items: center;
  justify-content: center;
  z-index: 100;
  backdrop-filter: blur(4px);
}
.notif-modal.active { display: flex; }

.notif-card {
  background: linear-gradient(180deg, var(--bg-2) 0%, var(--bg-1) 100%);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 24px 28px;
  min-width: 460px;
  max-width: 560px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.6), 0 0 60px var(--accent-glow);
  position: relative;
  overflow: hidden;
}
.notif-card[data-kind="recipe_unlock"]  { box-shadow: 0 20px 60px rgba(0,0,0,0.6), 0 0 60px rgba(255, 217, 102, 0.4); }
.notif-card[data-kind="culture_unlock"] { box-shadow: 0 20px 60px rgba(0,0,0,0.6), 0 0 60px rgba(200, 158, 255, 0.4); }
.notif-card[data-kind="biome_unlock"]   { box-shadow: 0 20px 60px rgba(0,0,0,0.6), 0 0 60px rgba(136, 230, 255, 0.5); }
.notif-card[data-kind="placement"]      { box-shadow: 0 20px 60px rgba(0,0,0,0.6), 0 0 60px rgba(127, 196, 134, 0.4); }
.notif-card[data-kind="milestone"]      { box-shadow: 0 20px 60px rgba(0,0,0,0.6), 0 0 60px rgba(255, 217, 102, 0.5); }

.notif-accent {
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 3px;
  background: linear-gradient(90deg, var(--accent) 0%, #56c5ee 100%);
}
.notif-card[data-kind="recipe_unlock"]  .notif-accent { background: var(--accent-warm); }
.notif-card[data-kind="culture_unlock"] .notif-accent { background: var(--brain); }
.notif-card[data-kind="biome_unlock"]   .notif-accent { background: var(--accent); }
.notif-card[data-kind="placement"]      .notif-accent { background: var(--ok); }
.notif-card[data-kind="milestone"]      .notif-accent { background: linear-gradient(90deg, var(--accent-warm) 0%, var(--accent) 100%); }

.notif-title {
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-dim);
  margin-bottom: 8px;
}
.notif-name {
  font-size: 22px;
  font-weight: 700;
  color: var(--ink);
  margin-bottom: 12px;
}
.notif-body {
  font-size: 14px;
  color: var(--ink-dim);
  line-height: 1.6;
  margin-bottom: 18px;
}
.notif-actions {
  display: flex;
  gap: 8px;
  justify-content: flex-end;
}

/* ═══════════════════════════════════════════════════════════════════════
   TISSUE INVESTIGATION MODAL (2026-05-14)
   The educational Culture Code reveal flow. Shares its overlay backdrop
   shape with .notif-modal but uses a wider, biology-themed card.
   ═══════════════════════════════════════════════════════════════════════ */
.tissue-modal {
  position: fixed;
  inset: 0;
  background: rgba(4, 8, 16, 0.72);
  display: none;
  align-items: center;
  justify-content: center;
  z-index: 110;
  backdrop-filter: blur(4px);
}
.tissue-modal.active { display: flex; }
.tissue-card {
  background: linear-gradient(180deg, var(--bg-2) 0%, var(--bg-1) 100%);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 24px 30px;
  min-width: 520px;
  max-width: 640px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.6), 0 0 60px rgba(200, 158, 255, 0.35);
  position: relative;
  overflow: hidden;
}
.tissue-accent {
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 3px;
  background: linear-gradient(90deg, var(--brain) 0%, var(--accent) 100%);
}
.tissue-card.rarity-uncommon  .tissue-accent { background: linear-gradient(90deg, #6cdf99 0%, var(--accent) 100%); }
.tissue-card.rarity-rare      .tissue-accent { background: linear-gradient(90deg, #c89eff 0%, var(--accent) 100%); }
.tissue-card.rarity-signature .tissue-accent { background: linear-gradient(90deg, #ffb85c 0%, var(--accent-warm) 100%); }
.tissue-card.rarity-signature {
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.6), 0 0 60px rgba(255, 184, 92, 0.45);
}
.tissue-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: 6px;
}
.tissue-tag {
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-dim);
}
.tissue-biome {
  font-size: 11px;
  color: var(--ink-dim);
  font-style: italic;
  text-transform: capitalize;
}
.tissue-title {
  margin: 0 0 6px;
  font-size: 24px;
  color: var(--ink);
}
.tissue-sub {
  margin-bottom: 16px;
  font-size: 13px;
}
.tissue-codex {
  background: rgba(200, 158, 255, 0.08);
  border-left: 3px solid var(--brain);
  padding: 12px 14px;
  border-radius: var(--radius);
  font-size: 13px;
  color: var(--ink);
  line-height: 1.55;
  margin-bottom: 18px;
  font-style: italic;
}
.tissue-cost-row {
  display: flex;
  gap: 10px;
  align-items: baseline;
  margin-bottom: 8px;
  font-size: 13px;
}
.tissue-actions {
  margin-top: 18px;
  display: flex;
  gap: 10px;
  align-items: center;
  flex-wrap: wrap;
}
.tissue-actions .muted { margin-left: auto; }

/* Pre-investigation: cell name hidden behind a placeholder */
.tissue-title-unknown {
  font-style: italic;
  color: var(--ink-dim);
  letter-spacing: 0.04em;
}

/* Sequencing-cost / -time / -outcome 3-column grid on the pending card */
.tissue-stat-grid {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 12px;
  background: rgba(0,0,0,0.18);
  border-radius: var(--radius);
  padding: 12px 14px;
  margin-bottom: 16px;
}
.tissue-stat-grid > div {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.tissue-stat-grid strong {
  font-size: 15px;
  color: var(--ink);
}
.tissue-stat-grid strong.lack { color: var(--danger); }

/* Investigation countdown progress bar */
.tissue-progress {
  margin: 12px 0 16px;
}
.tissue-progress-bar {
  height: 10px;
  background: var(--bg-3);
  border-radius: 5px;
  overflow: hidden;
  margin-bottom: 6px;
}
.tissue-progress-fill {
  height: 100%;
  background: linear-gradient(90deg, var(--brain) 0%, var(--accent) 100%);
  transition: width 0.2s linear;
}
.tissue-progress-eta {
  font-family: var(--font-mono);
  text-align: right;
}

/* Identification-complete badge accent */
.tissue-tag-success { color: var(--ok); }

/* Production-summary teaser shown when an investigation completes */
.tissue-prod {
  background: rgba(127, 196, 134, 0.08);
  border-left: 3px solid var(--ok);
  padding: 10px 12px;
  border-radius: var(--radius);
  font-size: 12.5px;
  line-height: 1.55;
  margin-bottom: 14px;
}
.tissue-prod div + div { margin-top: 4px; }

/* Other-samples row at the bottom of the modal */
.tissue-queue {
  width: 100%;
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--border-soft);
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
}
.tissue-other {
  background: transparent;
  border: 1px solid var(--border-soft);
  color: var(--ink-dim);
  border-radius: 12px;
  padding: 4px 10px;
  font: inherit;
  font-size: 11px;
  cursor: pointer;
}
.tissue-other:hover {
  border-color: var(--accent);
  color: var(--ink);
}

/* Side-panel Tissue Samples summary tile (Command Center) */
.tissue-samples-panel { cursor: pointer; transition: border-color 0.15s; }
.tissue-samples-panel:hover { border-color: var(--brain); }

/* Compact "Ready to Place" summary panel — opens the Bio-Vat instead of
   stacking every ready structure as a row in the Hub. */
.ready-place-panel { cursor: pointer; transition: border-color 0.15s; }
.ready-place-panel:hover { border-color: var(--accent); }
.ready-summary { font-size: 13px; color: var(--ink-dim); }
.ready-summary strong { color: var(--accent); }
.tissue-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 6px 10px;
  padding: 8px 10px;
  background: var(--bg-2);
  border-radius: var(--radius);
  margin-bottom: 4px;
  align-items: center;
  font-size: 13px;
}
.tissue-row.complete { border-left: 3px solid var(--ok); }
.tissue-row.investigating { border-left: 3px solid var(--brain); }
.tissue-row.pending { border-left: 3px solid var(--ink-dim); }
.tissue-row-bar {
  grid-column: 1 / -1;
  height: 4px;
  background: var(--bg-3);
  border-radius: 2px;
  overflow: hidden;
}
.tissue-row-fill {
  height: 100%;
  background: linear-gradient(90deg, var(--brain) 0%, var(--accent) 100%);
}

/* ═══════════════════════════════════════════════════════════════════════
   DNA Lab "Tissue Samples" bench panel — pending + investigating rows
   live inline in the DNA Lab screen (NOT in a modal).  Modal is reserved
   for the educational completion reveal only.
   ═══════════════════════════════════════════════════════════════════════ */
.tissue-bench { border-left: 3px solid var(--brain); }
.bench-help { margin-bottom: 10px; }
.bench-list { display: flex; flex-direction: column; gap: 8px; }
.bench-row {
  display: grid;
  grid-template-columns: 1fr;
  gap: 6px;
  padding: 12px 14px;
  background: var(--bg-2);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
}
.bench-row.pending { border-left: 3px solid var(--ink-dim); }
.bench-row.investigating { border-left: 3px solid var(--brain); }
.bench-row.rarity-uncommon  { border-left-color: #6cdf99; }
.bench-row.rarity-rare      { border-left-color: #c89eff; }
.bench-row.rarity-signature { border-left-color: #ffb85c; }
.bench-head {
  display: flex;
  gap: 10px;
  align-items: baseline;
}
.bench-head strong { color: var(--ink); }
.bench-head .muted { margin-left: auto; }
.bench-meta { line-height: 1.5; }
.bench-meta strong { color: var(--ink); }
.bench-meta strong.ok   { color: var(--ok); }
.bench-meta strong.lack { color: var(--danger); }
.bench-actions {
  display: flex;
  gap: 8px;
  margin-top: 4px;
}
.bench-bar {
  height: 8px;
  background: var(--bg-3);
  border-radius: 4px;
  overflow: hidden;
}
.bench-fill {
  height: 100%;
  background: linear-gradient(90deg, var(--brain) 0%, var(--accent) 100%);
}

/* Toast layer */
.toasts {
  position: fixed;
  bottom: 80px;
  right: 24px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  z-index: 90;
  pointer-events: none;
}
.toast {
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius);
  padding: 10px 14px;
  font-size: 13px;
  box-shadow: var(--shadow);
  opacity: 0;
  transform: translateY(10px);
  transition: opacity 0.25s, transform 0.25s;
  max-width: 320px;
}
.toast.show { opacity: 1; transform: translateY(0); }
.toast[data-kind="placement"]     { border-left-color: var(--ok); }
.toast[data-kind="culture_unlock"]{ border-left-color: var(--brain); }
.toast[data-kind="recipe_unlock"] { border-left-color: var(--accent-warm); }

/* ═══════════════════════════════════════════════════════════════════════
   ANIMATIONS
   ═══════════════════════════════════════════════════════════════════════ */
@keyframes pulse-soft {
  0%, 100% { transform: scale(1);   opacity: 1; }
  50%      { transform: scale(1.15);opacity: 0.7; }
}

/* Scrollbars — keep them dark and slim */
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: var(--bg-1); }
::-webkit-scrollbar-thumb { background: var(--bg-3); border-radius: 4px; }
::-webkit-scrollbar-thumb:hover { background: var(--border); }

/* ============================================================================
 * 2026-05-28 UI PASS — full-screen island backdrop, glass panels, responsive
 * ----------------------------------------------------------------------------
 * Goal: the Hub island painting becomes the persistent backdrop for the whole
 * app; every screen's content floats over it as translucent "glass" panels.
 * This is purely additive — declared LAST so it overrides earlier .panel /
 * .status-bar / .bottom-nav rules without editing them, and it does NOT touch
 * any screen's render JS. Mobile media queries collapse the desktop grids.
 * ========================================================================== */
:root {
  /* The persistent blurred island backdrop behind every screen (building
     sub-screens, pop-ups). 2026-05-31: now the new level-0 island so it matches
     the Command Center, instead of the old all-built finished painting. */
  --app-bg-image: url('../Main%20HUB/art/Background.png');
  --glass-bg:        rgba(11, 18, 31, 0.60);
  --glass-bg-strong: rgba(9, 15, 26, 0.74);
  --glass-border:    rgba(136, 230, 255, 0.16);
  --glass-blur:      blur(15px) saturate(1.12);
}

/* ── Persistent island backdrop ─────────────────────────────────────────── */
#app-bg {
  position: fixed; inset: 0; z-index: 0; pointer-events: none;
  background: var(--app-bg-image) center / cover no-repeat;
  /* Ambient by default — softly blurred + dimmed so panels stay legible. The
     command-center screen relaxes the blur (rule below) so the world reads
     as "live" while you're on the HUB. transform:scale hides blur edge bleed. */
  filter: blur(20px) brightness(0.40) saturate(1.05);
  transform: scale(1.08);
  transition: filter 0.7s ease, transform 0.7s ease;
}
#app-bg-veil {
  position: fixed; inset: 0; z-index: 0; pointer-events: none;
  background:
    radial-gradient(120% 90% at 50% -10%, rgba(26,44,76,0.30) 0%, rgba(6,10,18,0.55) 55%, rgba(4,7,14,0.86) 100%);
}

/* Keep the clinical grid + chrome above the backdrop. */
body::before { z-index: 0; }
.status-bar  { z-index: 60; }
.hub-main    { z-index: 2; }
.bottom-nav  { z-index: 60; }

/* On the HUB there is just ONE picture — the sharp .cc-buildings scene. Hide
   the blurred backdrop + veil so the HUB isn't "a background behind a background"
   (user 2026-06-04). Other screens keep the ambient backdrop. */
body[data-screen="command-center"] #app-bg,
body[data-screen="command-center"] #app-bg-veil {
  display: none;
}

/* The main HUB fits the viewport — no page scroll (user 2026-06-04). Desktop
   only; the phone layout (≤900px) stacks + scrolls (re-enabled in that query). */
body[data-screen="command-center"] { overflow: hidden; }
body[data-screen="command-center"] .cc-side {
  max-height: calc(100vh - 165px);
  overflow-y: auto;
}

/* ── Glass panels ───────────────────────────────────────────────────────── */
.panel {
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  box-shadow: 0 12px 34px rgba(0,0,0,0.46), inset 0 1px 0 rgba(255,255,255,0.05);
}
.panel.side, .panel.detail, .panel.cards-panel { background: var(--glass-bg-strong); }

/* Status bar + bottom nav → frosted glass over the island. */
.status-bar {
  background: linear-gradient(180deg, rgba(12,19,32,0.78) 0%, rgba(8,13,24,0.62) 100%);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border-bottom: 1px solid var(--glass-border);
}
.bottom-nav {
  background: linear-gradient(0deg, rgba(8,13,24,0.86) 0%, rgba(8,13,24,0.52) 100%);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border-top: 1px solid var(--glass-border);
}
.stat-chip { background: rgba(12,19,32,0.55); backdrop-filter: blur(6px); }
.stat-chip:hover { background: rgba(20,30,50,0.7); }

/* ── Command-center: meld the sharp scene into the backdrop ─────────────── */
/* Drop the hard "screen" border/box so the sharp painting floats seamlessly
   over its own blurred full-viewport extension (a natural focus effect). */
body[data-screen="command-center"] .cc-buildings {
  border-color: transparent;
  box-shadow: 0 30px 80px rgba(0,0,0,0.45);
  background: transparent;
  /* Fit the viewport so the HUB never scrolls (status bar + bottom nav +
     padding ≈ 165px of chrome). The aspect-ratio keeps the scene undistorted. */
  max-height: calc(100vh - 165px);
}
body[data-screen="command-center"] .cc-buildings .cc-scene-bg {
  /* Feather the sharp scene's edges into the blurred backdrop. */
  -webkit-mask-image: radial-gradient(125% 115% at 50% 45%, #000 70%, transparent 100%);
          mask-image: radial-gradient(125% 115% at 50% 45%, #000 70%, transparent 100%);
}

/* ── Elevated, larger, touch-friendlier bottom nav ──────────────────────── */
.bottom-nav button { min-height: 46px; border-radius: var(--radius-lg); }
.bottom-nav button.active { box-shadow: 0 0 16px var(--accent-glow); }
.bottom-nav button.primary { box-shadow: 0 0 20px var(--accent-glow); }

/* ════════════════════════════════════════════════════════════════════════
 * RESPONSIVE — tablet / phone. Desktop (>=900px) keeps its grids untouched.
 * ════════════════════════════════════════════════════════════════════════ */
@media (max-width: 900px) {
  .hub-main { padding: 12px 12px 96px; }

  /* Status bar: let the chips wrap instead of forcing a 3-column grid. */
  .status-bar {
    grid-template-columns: 1fr;
    gap: 8px;
    padding: 8px 12px;
  }
  .status-center { justify-content: flex-start; overflow-x: auto; flex-wrap: nowrap; }
  .stat-chip { min-width: 96px; }

  /* Command center → single column, scene first then side panel. The desktop
     "no-scroll" rule is reverted here: stacked phone layout needs to scroll. */
  .cc-layout { grid-template-columns: 1fr; }
  body[data-screen="command-center"] { overflow: auto; }
  body[data-screen="command-center"] .cc-buildings { max-height: 56vh; }
  body[data-screen="command-center"] .cc-side { max-height: none; overflow-y: visible; }

  /* Generic two/three-column screen grids collapse to one column. */
  .launchbay-grid,
  .biovat-grid,
  .detail-grid,
  .forge-grid,
  .vault-grid,
  .engineering-grid,
  .research-grid,
  .market-grid { grid-template-columns: 1fr !important; }

  /* Bottom nav: horizontal scroll dock with comfortable touch targets so all
     entries remain reachable on a phone without shrinking them. (A grouped
     "More" dropdown is a possible future refinement.) */
  .bottom-nav {
    justify-content: flex-start;
    overflow-x: auto;
    scroll-snap-type: x proximity;
    padding: 8px 10px calc(8px + env(safe-area-inset-bottom));
    -webkit-overflow-scrolling: touch;
  }
  .bottom-nav button {
    flex: 0 0 auto;
    min-width: 72px;
    scroll-snap-align: center;
  }
  .bottom-nav::-webkit-scrollbar { height: 0; }
}

@media (max-width: 560px) {
  .screen-h h2 { font-size: 18px; }
  .panel { padding: 12px; border-radius: var(--radius); }
  .stat-chip { min-width: 84px; padding: 5px 8px; }
  .chip-value { font-size: 13px; }
  /* Bigger primary action buttons for thumbs. */
  .btn { min-height: 40px; }
  .btn-launch-big { min-height: 52px; font-size: 15px; }
}

/* Graceful fallback when backdrop-filter is unsupported — use solid panels so
   text never sits on a see-through background. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .panel       { background: rgba(11,18,31,0.95); }
  .status-bar  { background: rgba(10,16,28,0.97); }
  .bottom-nav  { background: rgba(10,16,28,0.97); }
}

/* ── Drag-to-place affordances (2026-05-28) ─────────────────────────────── */
.placeable-row.draggable { cursor: grab; transition: background 0.15s, box-shadow 0.15s; }
.placeable-row.draggable:hover {
  background: rgba(136, 230, 255, 0.07);
  box-shadow: inset 0 0 0 1px var(--glass-border);
  border-radius: var(--radius);
}
.placeable-row.draggable:active { cursor: grabbing; }
.badge.drag-hint {
  background: rgba(136, 230, 255, 0.14);
  color: var(--accent);
  border: 1px solid var(--glass-border);
  font-size: 9px; letter-spacing: 0.04em;
}
/* The Bio-Vat 3D mount lights up as a drop target while dragging a bone. */
.biovat-3d-mount { transition: box-shadow 0.18s, outline-color 0.18s; outline: 2px dashed transparent; outline-offset: -6px; }
.biovat-3d-mount.drop-active {
  outline-color: var(--accent);
  box-shadow: inset 0 0 60px rgba(136, 230, 255, 0.25);
}
.biovat-3d-mount.drop-active::after {
  content: 'Release to place';
  position: absolute; left: 50%; top: 12px; transform: translateX(-50%);
  background: rgba(8,13,24,0.85); color: var(--accent);
  border: 1px solid var(--glass-border); border-radius: var(--radius);
  padding: 4px 10px; font-size: 11px; letter-spacing: 0.08em; pointer-events: none;
  z-index: 25;
}

/* ════════════════════════════════════════════════════════════════════════
 * 2026-05-29 UI PASS v2 — make the island a VISIBLE full-screen background,
 * not a dim void; full-bleed command-center with the menu floating on top.
 * Declared last → overrides the v1 rules above.
 * ════════════════════════════════════════════════════════════════════════ */

/* Brighter, crisper backdrop. v1 dimmed it to ~black so glass panels looked
   solid and the "island background" read as an empty void. Glass only reads
   as glass over a bright surface — so we lift brightness a lot and cut the
   blur. */
#app-bg {
  filter: blur(9px) brightness(0.62) saturate(1.1);
  transform: scale(1.06);
}
body[data-screen="command-center"] #app-bg {
  filter: blur(2px) brightness(0.82) saturate(1.12);
  transform: scale(1.03);
}
/* Much lighter veil — just enough vignette for depth + edge legibility. */
#app-bg-veil {
  background:
    radial-gradient(120% 95% at 50% 0%, rgba(20,34,60,0.10) 0%, rgba(6,10,18,0.28) 60%, rgba(4,7,14,0.62) 100%);
}

/* Slightly more opaque glass so text stays crisp over the brighter island. */
:root { --glass-bg: rgba(10, 17, 30, 0.66); --glass-bg-strong: rgba(8, 14, 26, 0.78); }

/* ── Full-bleed command-center (desktop/tablet) ──────────────────────────
   The island painting fills the whole content area; the menu column floats
   over it on the right as a glass overlay — "menus on top of the picture". */
@media (min-width: 900px) {
  /* The island painting IS the game window: it fills the viewport and the HUD
     (status bar with stats + launch, and the buildings panel) floats ON it.
     (user 2026-06-04) The status bar overlays the picture's top instead of
     sitting in a dark strip above it. */
  body[data-screen="command-center"] .status-bar {
    position: fixed;
    left: 0; right: 0; top: 0;
    /* Glass HUD over the picture — fade from a faint top wash to fully transparent
       so the top bar reads as ONE integrated screen, not a dark strip above a
       separate photo (user 2026-06-04). Stat chips carry their own contrast. */
    background: linear-gradient(180deg, rgba(6,12,20,0.82) 0%, rgba(6,12,20,0.42) 58%, rgba(6,12,20,0) 100%);
    border-bottom: none;
    box-shadow: none;
    -webkit-backdrop-filter: blur(2px);
    backdrop-filter: blur(2px);
  }
  body[data-screen="command-center"] .hub-main {
    max-width: none;
    padding: 0;
  }
  /* .cc-layout matches the PICTURE's footprint (centered) so the floating
     buildings panel anchors to the picture's edge, not the dark surround. */
  body[data-screen="command-center"] .cc-layout {
    display: block;
    position: relative;
    width: 100%;
    max-width: calc(100vh * 1.777);   /* 1.777 = 1672/941 scene aspect */
    margin: 0 auto;
    min-height: 0;
  }
  /* Picture fills the viewport height; the glass HUD bar overlays its top edge. */
  body[data-screen="command-center"] .cc-buildings {
    width: 100%;
    max-height: 100vh;
    margin: 0;
    border-radius: 0;
    box-shadow: none;
  }
  /* Compact buildings panel, anchored to the PICTURE's top-right, below the HUD. */
  body[data-screen="command-center"] .cc-side {
    position: absolute;
    top: 56px;
    right: 12px;
    width: 232px;
    max-height: calc(100vh - 72px);
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding-right: 4px;
    scrollbar-width: thin;
  }
  /* Give the floating rail's panels a touch more contrast since they sit on
     the brightest part of the scene. */
  body[data-screen="command-center"] .cc-side .panel {
    background: var(--glass-bg-strong);
    box-shadow: 0 14px 40px rgba(0,0,0,0.55), inset 0 1px 0 rgba(255,255,255,0.05);
  }
}

/* ── Back-to-Hub button + logo home shortcut (2026-05-29) ────────────────
   Replaces the removed bottom nav. The back button shows only on sub-screens;
   navigation is otherwise by clicking buildings in the scene. */
.hub-back {
  position: fixed;
  left: 18px;
  top: 68px;                 /* just below the status bar */
  z-index: 55;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 9px 16px 9px 12px;
  font: 700 13px/1 var(--font-stack);
  letter-spacing: 0.05em;
  color: #061018;
  /* Bright accent pill so it's an obvious, can't-miss "way back". */
  background: linear-gradient(180deg, var(--accent) 0%, #56c5ee 100%);
  border: 1px solid rgba(255,255,255,0.25);
  border-radius: 999px;
  box-shadow: 0 6px 20px var(--accent-glow), 0 2px 8px rgba(0,0,0,0.5);
  cursor: pointer;
  transition: filter 0.15s, transform 0.12s, box-shadow 0.15s;
}
.hub-back:hover { filter: brightness(1.08); transform: translateX(-2px); box-shadow: 0 8px 26px var(--accent-glow); }
.hub-back-arrow { font-size: 18px; line-height: 1; color: #061018; font-weight: 800; }
/* Hidden on the Hub itself (you're already home). */
body[data-screen="command-center"] .hub-back { display: none; }

/* Logo doubles as a home button. */
.status-logo { cursor: pointer; }
.status-logo:hover { color: #b8f1ff; }

/* No bottom nav anymore → reclaim the page's bottom padding. */
.hub-main { padding-bottom: 28px; }
@media (max-width: 900px) { .hub-main { padding-bottom: 24px; } }

/* Give sub-screens top clearance so the fixed back button never overlaps the
   screen title. (The command-center has no back button, so it's exempt.) */
body:not([data-screen="command-center"]) .hub-main { padding-top: 50px; }

/* Keep the top status bar to a single clean row (it was wrapping to two rows,
   growing its height and covering the back button). Chips scroll horizontally
   if they don't all fit rather than stacking. */
.status-center { flex-wrap: nowrap; overflow-x: auto; overflow-y: hidden; }
.status-center::-webkit-scrollbar { height: 0; }
.status-bar { align-items: center; }

/* ════════════════════════════════════════════════════════════════════════
 * BIO-VAT — full-screen 3D stage + floating pop-up panels (2026-05-29)
 * ════════════════════════════════════════════════════════════════════════
 * The body model is the centerpiece now: a full-bleed 3D stage that fills the
 * screen (mirrors the command-center island). The old 3-column grid (figure /
 * systems / detail) became "semi-pop-up" panels toggled from a floating
 * toolbar, so they overlay the model only when opened — otherwise the view is
 * an unobstructed body. Per the user's 2026-05-29 request.
 * ──────────────────────────────────────────────────────────────────────── */

/* Trim page chrome on the Bio-Vat screen so the stage gets maximum room.
   (No boxed screen-h title here — the stage IS the screen.) */
body[data-screen="biovat"] .hub-main { padding: 14px 16px; }

.biovat-stage {
  position: relative;
  width: 100%;
  height: calc(100vh - 96px);   /* sticky status bar (~64) + trimmed padding */
  min-height: 520px;
  border-radius: var(--radius-lg);
  overflow: hidden;
  isolation: isolate;
  border: 1px solid rgba(136, 230, 255, 0.18);
  box-shadow: inset 0 0 90px rgba(136, 230, 255, 0.06), var(--shadow);
}

/* The 3D mount fills the whole stage (overrides the old fixed-height box at
   .biovat-3d-mount — higher specificity, defined later, so it wins). */
.biovat-3d-mount.biovat-3d-fill {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: none;
  border-radius: 0;
}

/* ── Floating body-completion gauge (bottom-left) ───────────────────────── */
.biovat-gauge {
  position: absolute;
  left: 16px;
  bottom: 16px;
  z-index: 6;
  padding: 9px 18px;
  text-align: center;
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  box-shadow: 0 10px 28px rgba(0, 0, 0, 0.4);
}
.biovat-gauge .big {
  display: block;
  margin-top: 2px;
  font-family: var(--font-mono);
  font-size: 22px;
  color: var(--accent);
}
.biovat-mapped { margin-top: 5px; }

/* ── Layers toggle (bottom-right) — study skeleton vs connective tissue ──── */
.biovat-layers {
  position: absolute;
  right: 16px;
  bottom: 16px;
  z-index: 6;
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 9px 14px;
  font-size: 12px;
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  box-shadow: 0 10px 28px rgba(0, 0, 0, 0.4);
}
.biovat-layers-h { letter-spacing: 0.12em; margin-bottom: 2px; }
.biovat-layers label { display: flex; align-items: center; gap: 6px; cursor: pointer; color: var(--ink); }
/* "Restore N hidden parts" — appears only when ≥1 part is Alt-click-hidden. */
.biovat-restore-hidden {
  margin-top: 6px;
  padding: 4px 8px;
  font-size: 11px;
  color: var(--accent);
  background: rgba(136, 230, 255, 0.10);
  border: 1px solid rgba(136, 230, 255, 0.35);
  border-radius: 6px;
  cursor: pointer;
  white-space: nowrap;
}
.biovat-restore-hidden:hover { background: rgba(136, 230, 255, 0.2); }

/* ── Camera hint (bottom-center) ────────────────────────────────────────── */
.biovat-hint {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  bottom: 16px;
  z-index: 5;
  padding: 5px 12px;
  border-radius: 999px;
  background: rgba(6, 11, 20, 0.5);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  pointer-events: none;
  white-space: nowrap;
}

/* ── Floating toolbar (top-right) ───────────────────────────────────────── */
.biovat-toolbar {
  position: absolute;
  top: 14px;
  right: 14px;
  z-index: 7;
  display: flex;
  gap: 8px;
}
.bv-tool {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1px;
  padding: 8px 14px;
  min-width: 92px;
  cursor: pointer;
  color: var(--ink);
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  box-shadow: 0 8px 22px rgba(0, 0, 0, 0.4);
  transition: border-color 0.15s, background 0.15s, transform 0.1s;
}
.bv-tool:hover { background: var(--glass-bg-strong); transform: translateY(-1px); }
.bv-tool.active {
  border-color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent) inset, 0 8px 22px var(--accent-glow);
}
.bv-tool-label { font-weight: 600; font-size: 13px; letter-spacing: 0.02em; }
.bv-tool-sub   { font-size: 10px; color: var(--ink-dim); text-transform: uppercase; letter-spacing: 0.08em; }

/* ── Floating pop-up panels ─────────────────────────────────────────────── */
/* The wrap is click-through (pointer-events:none) so the 3D model behind it
   stays draggable everywhere except over an open panel. */
.biovat-pop-wrap { position: absolute; inset: 0; z-index: 8; pointer-events: none; }
.biovat-pop {
  position: absolute;
  top: 78px;
  right: 14px;
  width: min(380px, calc(100% - 28px));
  max-height: calc(100% - 100px);
  display: flex;
  flex-direction: column;
  pointer-events: auto;
  border-radius: var(--radius-lg);
  animation: bvPopIn 0.16s ease-out;
}
.biovat-pop[hidden] { display: none; }
@keyframes bvPopIn {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: translateY(0); }
}
.biovat-pop-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  flex: 0 0 auto;
}
.biovat-pop-head .panel-h { margin: 0; }
.bv-pop-close {
  flex: 0 0 auto;
  width: 28px;
  height: 28px;
  font-size: 18px;
  line-height: 1;
  color: var(--ink-dim);
  background: transparent;
  border: 1px solid var(--glass-border);
  border-radius: 8px;
  cursor: pointer;
}
.bv-pop-close:hover { color: var(--ink); border-color: var(--accent); }
.biovat-pop-body {
  flex: 1 1 auto;
  overflow-y: auto;
  margin-top: 8px;
  padding-right: 4px;
}
.placeable-list { display: flex; flex-direction: column; gap: 8px; }
.placeable-row.ready { border-left: 2px solid var(--accent); }

/* Per-system grouping in the unified Place panel (skeleton / muscle / …). */
.placeable-system { display: flex; flex-direction: column; gap: 6px; }
.placeable-system + .placeable-system { margin-top: 14px; }
.placeable-system-h {
  display: flex;
  align-items: baseline;
  gap: 8px;
  width: 100%;
  padding: 7px 8px;
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--border-soft);
  border-left: 3px solid var(--sys-color, var(--accent));
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.placeable-system-h:hover { background: rgba(255, 255, 255, 0.04); }
.placeable-system.collapsed .placeable-system-h { border-bottom-color: transparent; }
.placeable-caret {
  color: var(--sys-color, var(--accent));
  font-size: 10px;
  flex: 0 0 12px;
}
.placeable-system-name {
  font-size: 12px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--sys-color, var(--ink));
  font-weight: 600;
}
.placeable-system-h .muted { margin-left: auto; }

/* Mobile: panels span the width and the toolbar wraps under the back button. */
@media (max-width: 720px) {
  .biovat-toolbar { left: 14px; right: 14px; flex-wrap: wrap; justify-content: flex-end; }
  .biovat-pop { left: 14px; right: 14px; width: auto; top: 130px; max-height: calc(100% - 150px); }
  .biovat-stage { height: calc(100vh - 80px); }
}

/* ════════════════════════════════════════════════════════════════════════
 * PER-BUILDING SCREEN THEME (2026-05-31)
 *   Each of the 7 "document" screens (.doc-screen, set in index.html) gets its
 *   own ACCENT identity — a colour + glyph declared on body[data-screen] — and
 *   shares ONE chrome layer below: a serif title with the building glyph + an
 *   ember underline, frosted-glass panels, accent-gradient primary buttons,
 *   quieter rows with status dots, accent-bar codex notes, and a moody
 *   per-screen backdrop glow. command-center + biovat are full-screen scenes and
 *   deliberately opt out (no .doc-screen class) so they keep their own look.
 *
 *   To retheme a screen, change its accent/ember/glyph in the identity block.
 * ════════════════════════════════════════════════════════════════════════ */

/* ── Per-screen identity (colour + glyph) ──────────────────────────────────── */
body[data-screen="forge"]       { --screen-accent:#ffb86b; --screen-ember:#ff8f47; --screen-glyph:'\2692'; } /* amber  */
body[data-screen="dnalab"]      { --screen-accent:#c79bff; --screen-ember:#9a6bff; --screen-glyph:'\25CC'; } /* violet */
body[data-screen="engineering"] { --screen-accent:#86b5ff; --screen-ember:#5b8fe0; --screen-glyph:'\2699'; } /* steel  */
body[data-screen="research"]    { --screen-accent:#6fe6cf; --screen-ember:#2cc4a8; --screen-glyph:'\2726'; } /* teal   */
body[data-screen="vault"]       { --screen-accent:#ffcf73; --screen-ember:#d9a94a; --screen-glyph:'\25A4'; } /* gold   */
body[data-screen="market"]      { --screen-accent:#9be082; --screen-ember:#5fc06a; --screen-glyph:'\25C8'; } /* green  */
body[data-screen="launch-bay"]  { --screen-accent:#74d6ff; --screen-ember:#3fb0e0; --screen-glyph:'\25B8'; } /* cyan   */

.doc-screen {
  --screen-line: color-mix(in srgb, var(--screen-accent, #88e6ff) 22%, transparent);
  --screen-soft: color-mix(in srgb, var(--screen-accent, #88e6ff) 8%, transparent);
  /* Re-point the GLOBAL accent vars to this screen's colour, scoped to the
     screen subtree. Every screen-specific card/row/fill that uses var(--accent)
     (they were all hard-cyan) now picks up the room's identity for free — the
     single biggest lever for making each building feel distinct. The status bar
     and other chrome live OUTSIDE .doc-screen, so they keep the base cyan. */
  --accent: var(--screen-accent, #88e6ff);
  --accent-glow: color-mix(in srgb, var(--screen-accent, #88e6ff) 35%, transparent);
}

/* ── Moody backdrop — dim the island on every doc screen + a tinted top glow ── */
body:not([data-screen="command-center"]):not([data-screen="biovat"]) #app-bg {
  filter: blur(9px) brightness(0.32) saturate(0.92);
  transform: scale(1.05);
}
.doc-screen.active::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background: radial-gradient(90% 52% at 50% -8%,
    color-mix(in srgb, var(--screen-accent, #88e6ff) 14%, transparent) 0%, transparent 60%);
}
.doc-screen.active > * { position: relative; z-index: 1; }

/* ── Header — serif title with the building glyph + an ember underline ─────── */
.doc-screen .screen-h {
  border-bottom: 1px solid var(--screen-line);
  padding-bottom: 14px;
  margin-bottom: 20px;
}
.doc-screen .screen-h h2 {
  font-family: 'Cormorant Garamond', 'IBM Plex Serif', Georgia, serif;
  font-size: 30px;
  font-weight: 600;
  letter-spacing: 0.015em;
  color: color-mix(in srgb, var(--screen-accent, #88e6ff) 72%, #ffffff);
  display: inline-flex;
  align-items: baseline;
  gap: 11px;
}
.doc-screen .screen-h h2::before {
  content: var(--screen-glyph, '');
  font-size: 0.78em;
  color: var(--screen-accent, #88e6ff);
}

/* ── Panels → glass with the screen's hairline ─────────────────────────────── */
.doc-screen .panel {
  background: var(--glass-bg);
  border: 1px solid var(--screen-line);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border-radius: 12px;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.42), inset 0 1px 0 rgba(255, 255, 255, 0.04);
}
.doc-screen .panel-h { color: color-mix(in srgb, var(--screen-accent, #88e6ff) 52%, var(--ink-dim)); }

/* ── Construction strip — warm the level/upgrade bar to the accent ─────────── */
.doc-screen .building-strip-eta { color: var(--screen-accent); }
.doc-screen .building-strip-fill {
  background: linear-gradient(90deg, var(--screen-accent), var(--screen-ember));
  box-shadow: 0 0 12px color-mix(in srgb, var(--screen-accent) 50%, transparent);
}

/* ── Primary action buttons → accent → ember gradient ──────────────────────── */
.doc-screen .btn-primary {
  background: linear-gradient(180deg, var(--screen-accent) 0%, var(--screen-ember) 100%);
  color: #0f1320;
  border: none;
  box-shadow: 0 6px 18px color-mix(in srgb, var(--screen-ember) 38%, transparent),
              inset 0 1px 0 rgba(255, 255, 255, 0.22);
}
.doc-screen .btn-primary:hover:not(:disabled) { filter: brightness(1.06); border: none; }

/* ── Mode tabs (Forge: Structures/Cells; others where present) ─────────────── */
.doc-screen .mode-tab {
  background: rgba(255, 255, 255, 0.02);
  border: 1px solid var(--border-soft);
  border-radius: 11px;
  padding: 12px 16px;
}
.doc-screen .mode-tab:hover { color: var(--ink); border-color: var(--screen-line); }
.doc-screen .mode-tab.active {
  color: color-mix(in srgb, var(--screen-accent) 85%, #ffffff);
  border-color: color-mix(in srgb, var(--screen-accent) 60%, transparent);
  background: linear-gradient(180deg, var(--screen-soft), transparent);
  box-shadow: inset 0 0 18px color-mix(in srgb, var(--screen-accent) 10%, transparent);
}

/* ── Category tabs — accent active ─────────────────────────────────────────── */
.doc-screen .forge-tabs { border-bottom-color: var(--screen-line); }
.doc-screen .cat-tab.active {
  color: var(--screen-accent);
  border-color: color-mix(in srgb, var(--screen-accent) 55%, transparent);
}

/* ── List rows — glassy, accent spine when selected ────────────────────────── */
.doc-screen .recipe-row {
  background: rgba(255, 255, 255, 0.016);
  border: 1px solid var(--border-soft);
  border-left: 3px solid transparent;
  border-radius: 10px;
  transition: background 0.15s ease, border-color 0.15s ease;
}
.doc-screen .recipe-row:hover { background: rgba(255, 255, 255, 0.05); }
.doc-screen .recipe-row.selected {
  background: linear-gradient(180deg, var(--screen-soft), transparent);
  border-color: var(--screen-line);
  border-left-color: var(--screen-accent);
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--screen-accent) 12%, transparent), 0 6px 18px rgba(0, 0, 0, 0.35);
}
.doc-screen .recipe-name {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-size: 17px;
  font-weight: 600;
  letter-spacing: 0.015em;
  color: var(--ink);
  line-height: 1.15;
}

/* ── Status as a quiet dot, not a loud text pill ───────────────────────────── */
.doc-screen .recipe-state {
  font-size: 0;
  width: 9px;
  height: 9px;
  padding: 0;
  border-radius: 50%;
  background: var(--ink-dim);
  border: none;
  flex: 0 0 auto;
}
.doc-screen .recipe-state.ready { background: #74dca0; box-shadow: 0 0 7px rgba(116, 220, 160, 0.6); }
.doc-screen .recipe-state.needs { background: #e8ab5f; box-shadow: 0 0 7px rgba(232, 171, 95, 0.5); }

/* ── Requirement cards — glassy, accent-dim uppercase labels ───────────────── */
.doc-screen .req-grid > div {
  background: rgba(255, 255, 255, 0.02);
  border: 1px solid var(--border-soft);
  border-radius: 10px;
  padding: 10px 12px;
}
.doc-screen .req-grid > div > .muted.small:first-child {
  color: color-mix(in srgb, var(--screen-accent) 48%, var(--ink-dim));
  letter-spacing: 0.1em;
  text-transform: uppercase;
  font-size: 10px;
  margin-bottom: 4px;
}

/* ── Codex / note callout → accent bar ─────────────────────────────────────── */
.doc-screen .codex-note {
  background: var(--screen-soft);
  border-left: 2px solid var(--screen-accent);
  color: var(--ink-dim);
}

/* ── Production / progress rows ────────────────────────────────────────────── */
.doc-screen .prod-row {
  background: rgba(255, 255, 255, 0.022);
  border: 1px solid var(--border-soft);
  border-radius: 10px;
}
.doc-screen .prod-fill { background: linear-gradient(90deg, var(--screen-accent), var(--screen-ember)); }

/* ── Screen-specific cards/rows → translucent so they sit ON the glass panels
 *    (instead of opaque dark boxes), matching the forge rows. Background-only +
 *    border tweaks — no layout changes. Text legibility is unaffected (it reads
 *    against the dark panel/backdrop, not the faint card fill). Selected/active
 *    states pick up the room accent (which --accent already re-points). ──────── */
.doc-screen .vault-card,
.doc-screen .stat-cell,
.doc-screen .stat-summary-grid > div,
.doc-screen .module-row,
.doc-screen .upgrade-row,
.doc-screen .biome-card,
.doc-screen .market-row,
.doc-screen .lib-row,
.doc-screen .trickle-slot,
.doc-screen .stock-cell,
.doc-screen .dive-cost-panel,
.doc-screen .loadout-panel,
.doc-screen .reset-row {
  background: rgba(255, 255, 255, 0.022);
  border-color: var(--border-soft);
}
.doc-screen .vault-card:hover,
.doc-screen .module-row:hover,
.doc-screen .biome-card:hover,
.doc-screen .market-row:hover,
.doc-screen .trickle-slot:hover {
  background: rgba(255, 255, 255, 0.05);
}
.doc-screen .biome-card.selected,
.doc-screen .module-row.selected,
.doc-screen .market-row.selected,
.doc-screen .trickle-slot.selected {
  background: linear-gradient(180deg, var(--screen-soft), transparent);
  border-color: var(--screen-line);
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--screen-accent) 12%, transparent), 0 6px 18px rgba(0, 0, 0, 0.35);
}

/* ════════════════════════════════════════════════════════════════════════
 * JUICE FX (2026-06-01) — floating "+N" gain text + click ripple. Spawned by
 * hub/fx.js, fixed-position, self-removing, pointer-events:none so they never
 * intercept input. Cheap DOM/CSS; degrade to nothing if fx is disabled.
 * ════════════════════════════════════════════════════════════════════════ */
.fx-float {
  position: fixed;
  z-index: 9999;
  transform: translate(-50%, 0);
  font: 600 15px/1 'JetBrains Mono', 'Consolas', monospace;
  color: #b9f5c9;
  text-shadow: 0 0 8px rgba(120, 230, 160, 0.6), 0 1px 2px rgba(0, 0, 0, 0.85);
  pointer-events: none;
  white-space: nowrap;
  animation: fx-float-up 1.05s ease-out forwards;
}
.fx-float.cost { color: #ff9a9a; text-shadow: 0 0 8px rgba(255, 120, 120, 0.5), 0 1px 2px rgba(0, 0, 0, 0.85); }
.fx-float.atp  { color: #ffe08a; text-shadow: 0 0 8px rgba(255, 200, 90, 0.5),  0 1px 2px rgba(0, 0, 0, 0.85); }
@keyframes fx-float-up {
  0%   { opacity: 0; transform: translate(-50%, 4px)   scale(0.9); }
  18%  { opacity: 1; transform: translate(-50%, -2px)  scale(1.05); }
  100% { opacity: 0; transform: translate(-50%, -34px) scale(1); }
}
.fx-burst {
  position: fixed;
  z-index: 9998;
  width: 10px;
  height: 10px;
  margin: -5px 0 0 -5px;
  border-radius: 50%;
  border: 2px solid var(--fx-burst-color, rgba(160, 220, 255, 0.85));
  pointer-events: none;
  animation: fx-burst-out 0.5s ease-out forwards;
}
@keyframes fx-burst-out {
  0%   { opacity: 0.85; transform: scale(0.4); }
  100% { opacity: 0;    transform: scale(3.2); }
}

/* Status-bar mute toggle */
.status-mute {
  position: relative;
  background: none;
  border: 1px solid var(--glass-border);
  color: var(--ink-dim);
  border-radius: 8px;
  width: 30px;
  height: 30px;
  cursor: pointer;
  font-size: 14px;
  line-height: 1;
  transition: color 0.15s, border-color 0.15s;
}
.status-mute:hover { color: var(--ink); border-color: var(--accent); }
.status-mute.muted { color: #7a8aa0; opacity: 0.55; }
/* Unmistakable "off" slash across the glyph — the music button keeps its 🎵
   icon when muted, so dimming alone wouldn't read as off. */
.status-mute.muted::after {
  content: '';
  position: absolute;
  left: 4px; right: 4px; top: 50%;
  height: 2px;
  background: #e0556b;
  transform: rotate(-20deg);
  border-radius: 2px;
  pointer-events: none;
}

/* Music button + volume slider sit together in a subtle pill. */
.audio-cluster {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 0 8px 0 2px;
  border: 1px solid var(--glass-border);
  border-radius: 8px;
}
.audio-cluster .status-mute { border: none; width: 26px; }
.audio-cluster .status-mute:hover { border: none; }
.music-vol {
  -webkit-appearance: none;
  appearance: none;
  width: 70px;
  height: 4px;
  border-radius: 2px;
  background: linear-gradient(90deg, var(--accent, #7fc486), #2b3a4a);
  outline: none;
  cursor: pointer;
}
.music-vol::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 12px; height: 12px;
  border-radius: 50%;
  background: var(--ink, #dfe9f3);
  border: 1px solid var(--accent, #7fc486);
  cursor: pointer;
}
.music-vol::-moz-range-thumb {
  width: 12px; height: 12px;
  border-radius: 50%;
  background: var(--ink, #dfe9f3);
  border: 1px solid var(--accent, #7fc486);
  cursor: pointer;
}

/* ============================================================================
 * Bot-cargo popover (status-bar.js) — anchored just under the cargo chip
 * ========================================================================== */
.cargo-pop {
  position: fixed;
  z-index: 9500;
  min-width: 240px;
  max-width: 360px;
  background: rgba(14, 24, 35, 0.98);
  border: 1px solid var(--glass-border);
  border-radius: 10px;
  box-shadow: 0 14px 36px rgba(0, 0, 0, 0.55);
  padding: 10px 12px;
  font-size: 13px;
  color: var(--ink);
  backdrop-filter: blur(6px);
  animation: cargoPopIn 0.12s ease-out;
}
@keyframes cargoPopIn { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }
.cargo-pop-head { font-weight: 600; margin-bottom: 8px; }
.cargo-pop-list { display: flex; flex-direction: column; gap: 2px; max-height: 320px; overflow-y: auto; }
.cargo-pop-row { display: flex; align-items: center; gap: 8px; padding: 3px 2px; }
.cargo-pop-dot { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; }
.cargo-pop-name { flex: 1 1 auto; white-space: nowrap; }
.cargo-pop-rarity { font-size: 11px; text-transform: capitalize; opacity: 0.85; }
.cargo-pop-qty { font-variant-numeric: tabular-nums; font-weight: 600; min-width: 34px; text-align: right; }
.cargo-pop-foot { margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--glass-border); font-size: 12px; }
.cargo-pop-empty { padding: 4px 2px; }

/* ============================================================================
 * Vault Reserve Yield bar (vault.js) — passive interest on stored loot
 * ========================================================================== */
.vault-yield {
  display: grid;
  grid-template-columns: auto auto auto;
  gap: 14px 36px;
  align-items: center;
  background: linear-gradient(90deg, rgba(127, 196, 134, 0.08), rgba(127, 196, 134, 0.02));
  border: 1px solid var(--glass-border);
  border-radius: 12px;
  padding: 12px 20px;
  margin-bottom: 16px;
}
.vault-yield .vy-cell { display: flex; flex-direction: column; gap: 2px; }
.vault-yield .vy-label { font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ink-dim); }
.vault-yield .vy-value { font-size: 18px; font-weight: 700; font-variant-numeric: tabular-nums; }
.vault-yield .vy-rate .vy-value { color: #7fc486; }
.vault-yield .vy-note { grid-column: 1 / -1; font-size: 12px; margin-top: 2px; }
/* shimmer on the live rate so passive income reads as "something happening" */
.vault-yield.active .vy-glow {
  background: linear-gradient(90deg, #7fc486 0%, #d7ffe0 50%, #7fc486 100%);
  background-size: 200% 100%;
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent;
  animation: vyShimmer 2.6s linear infinite;
}
@keyframes vyShimmer { from { background-position: 200% 0; } to { background-position: -200% 0; } }

/* ============================================================================
 * Bio-Vat mesh-load failure banner (biovat-3d.js)
 * ----------------------------------------------------------------------------
 * Surfaces the otherwise-SILENT "the mesh server is down so the GLBs can't
 * download" case. Without this, a dead dev server makes the vat look empty and
 * reads as a render bug / lost progress. Fixed bottom-center, amber warning.
 * ========================================================================== */
.biovat-meshfail {
  position: fixed;
  left: 50%;
  bottom: 28px;
  transform: translateX(-50%);
  z-index: 9000;
  width: min(560px, calc(100vw - 32px));
  padding: 16px 18px;
  border-radius: 14px;
  background: linear-gradient(180deg, rgba(40,22,8,0.96), rgba(26,15,7,0.96));
  border: 1px solid rgba(255,176,80,0.55);
  box-shadow: 0 18px 50px rgba(0,0,0,0.55), inset 0 0 0 1px rgba(255,176,80,0.10);
  color: #ffe9cf;
  font-size: 13px;
  line-height: 1.5;
  backdrop-filter: blur(8px);
  animation: screen-in 0.22s ease-out;
}
.biovat-meshfail .mf-title {
  font-weight: 700;
  font-size: 14px;
  color: #ffb950;
  margin-bottom: 6px;
  letter-spacing: 0.02em;
}
.biovat-meshfail .mf-body { color: #f3dcc4; }
.biovat-meshfail .mf-body code {
  background: rgba(255,176,80,0.16);
  padding: 1px 5px;
  border-radius: 4px;
  font-size: 12px;
}
.biovat-meshfail .mf-body b { color: #ffd9a8; }
.biovat-meshfail .mf-actions { display: flex; gap: 10px; margin-top: 12px; }
.biovat-meshfail .mf-btn {
  cursor: pointer;
  border-radius: 8px;
  padding: 7px 16px;
  font-size: 12.5px;
  font-weight: 600;
  border: 1px solid rgba(255,176,80,0.40);
  background: rgba(255,176,80,0.14);
  color: #ffe9cf;
  transition: background 0.15s, border-color 0.15s;
}
.biovat-meshfail .mf-btn:hover {
  background: rgba(255,176,80,0.26);
  border-color: rgba(255,176,80,0.70);
}
.biovat-meshfail .mf-reload { background: rgba(255,176,80,0.28); }

/* ============================================================================
 * ENGINEERING — Nano-Bot Bay 3D viewer (hub/eng-bot-3d.js)
 * ========================================================================== */
.engbot-bay { margin-bottom: 14px; }
.engbot-wrap { display: flex; gap: 16px; align-items: stretch; }
.engbot-mount {
  position: relative; flex: 1 1 auto; min-width: 0; height: 440px;
  border: 1px solid var(--line, #22304a); border-radius: 12px; overflow: hidden;
  background: radial-gradient(900px 500px at 70% 0%, #15233c 0%, #0a0f18 60%);
}
.engbot-mount canvas { display: block; width: 100%; height: 100%; }
.engbot-loading {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  color: var(--ink-dim, #8fa1bb); font-size: 13px; letter-spacing: .4px;
}
.engbot-side { flex: 0 0 232px; display: flex; flex-direction: column; gap: 16px; }
.engbot-h {
  font-size: 11px; text-transform: uppercase; letter-spacing: 1px;
  color: var(--ink-dim, #8fa1bb); margin-bottom: 8px;
}
.engbot-chips { display: flex; flex-wrap: wrap; gap: 7px; }
.engbot-chip {
  display: flex; align-items: center; gap: 7px; padding: 8px 11px; cursor: pointer;
  border: 1px solid var(--line, #22304a); border-radius: 9px; background: rgba(16,26,44,.7);
  color: var(--ink, #e6edf7); font-weight: 600; font-size: 12.5px; transition: .12s;
}
.engbot-chip:hover { border-color: var(--accent, #7cc6ff); transform: translateY(-1px); }
.engbot-chip .engbot-led { width: 9px; height: 9px; border-radius: 50%; background: #33415e; transition: .15s; }
.engbot-chip.on { border-color: var(--accent, #7cc6ff); background: rgba(21,38,62,.9); }
.engbot-chip.on .engbot-led { background: var(--accent, #7cc6ff); box-shadow: 0 0 8px var(--accent, #7cc6ff); }
.engbot-skins { display: flex; flex-wrap: wrap; gap: 9px; }
.engbot-sw {
  width: 32px; height: 32px; border-radius: 9px; cursor: pointer;
  border: 2px solid #2a3a55; transition: .12s; padding: 0;
}
.engbot-sw:hover { transform: translateY(-2px); }
.engbot-sw.on { border-color: #fff; box-shadow: 0 0 10px rgba(255,255,255,.35); }
.engbot-bench { display: flex; flex-direction: column; gap: 7px; }
.engbot-btn {
  text-align: left; padding: 9px 12px; cursor: pointer;
  border: 1px solid var(--line, #22304a); border-radius: 9px;
  background: linear-gradient(180deg, rgba(22,36,62,.9), rgba(16,26,44,.9));
  color: var(--ink, #e6edf7); font-weight: 600; font-size: 12.5px; transition: .12s;
}
.engbot-btn:hover { border-color: var(--accent, #7cc6ff); transform: translateY(-1px); }
.engbot-empty { color: var(--ink-dim, #8fa1bb); font-size: 12px; line-height: 1.4; padding: 2px 0 4px; }
.engbot-dev { margin-top: 8px; display: flex; gap: 6px; }
.engbot-dev button {
  font-size: 10.5px; padding: 4px 8px; border: 1px dashed #3a4a63; border-radius: 7px;
  background: transparent; color: var(--ink-dim, #8fa1bb); cursor: pointer; transition: .12s;
}
.engbot-dev button:hover { border-color: var(--accent, #7cc6ff); color: var(--ink, #e6edf7); }
@media (max-width: 820px) {
  .engbot-wrap { flex-direction: column; }
  .engbot-side { flex-basis: auto; flex-direction: row; flex-wrap: wrap; }
}

/* ============================================================================
 * RESEARCH WING — skill tree (hub/research.js). AAA tech-tree look.
 * ========================================================================== */
.rt-wrap{display:flex;flex-direction:column;gap:10px}
.rt-tabs{display:flex;justify-content:center;gap:0;border-bottom:1px solid var(--border-soft);padding-bottom:6px}
.rt-tab{display:flex;align-items:center;gap:8px;padding:8px 20px;cursor:pointer;font-weight:700;letter-spacing:.12em;font-size:12px;color:var(--ink-dim);text-transform:uppercase;transition:.15s;position:relative}
.rt-tab .rt-dia{width:7px;height:7px;transform:rotate(45deg);background:#2b3a55;transition:.15s}
.rt-tab.active{color:var(--ink)}
.rt-tab.active .rt-dia{background:var(--tc);box-shadow:0 0 10px var(--tc)}
.rt-tab:hover{color:var(--ink)}
.rt-tab .rt-ct{font-size:10px;color:var(--ink-dim);letter-spacing:.05em}
.rt-board-wrap{position:relative;overflow:auto;height:60vh;min-height:380px;border:1px solid var(--border-soft);border-radius:var(--radius);
  background:radial-gradient(1200px 600px at 35% 25%, rgba(28,44,72,.28), transparent 60%),var(--bg-1)}
.rt-board{position:relative}
svg.rt-pipes{position:absolute;inset:0;pointer-events:none;overflow:visible;z-index:2}
.rt-pipes path{fill:none;stroke-linecap:round;stroke-linejoin:round}
.rt-pipes path.back{stroke:#1d2c46;stroke-width:5;opacity:.7}
.rt-pipes path.on{stroke:var(--rt-accent,#7cc6ff);stroke-width:4;opacity:.9;filter:drop-shadow(0 0 4px var(--rt-accent,#7cc6ff))}
.rt-pipes path.off{stroke:#2a3a58;stroke-width:3;opacity:.55;stroke-dasharray:2 7}
.rt-energy{position:absolute;border-radius:50%;pointer-events:none;z-index:1;filter:blur(15px)}
.rt-tierhead{position:absolute;left:0;top:0;z-index:18;pointer-events:none}
.rt-phase{position:absolute;top:6px;height:20px;display:flex;align-items:center;justify-content:center;font-size:10px;letter-spacing:.22em;text-transform:uppercase;color:#9fb2d0;font-weight:700;background:linear-gradient(180deg,rgba(18,28,46,.9),rgba(18,28,46,.4));border:1px solid var(--border-soft);border-radius:20px}
.rt-tcol{position:absolute;top:30px;width:60px;text-align:center;font-size:10px;letter-spacing:.1em;color:var(--ink-dim);font-weight:600}
.rt-tcol.locked{color:#cf8a8a}
.rt-rail{position:absolute;left:0;top:0;width:148px;z-index:19;pointer-events:none}
.rt-cat{position:absolute;left:8px;width:132px;display:flex;align-items:center;gap:8px;padding:6px 8px;border:1px solid var(--border-soft);border-radius:11px;pointer-events:auto;background:linear-gradient(180deg,rgba(16,24,40,.95),rgba(12,18,30,.92))}
.rt-cat .rt-ic{width:26px;height:26px;border-radius:8px;display:flex;align-items:center;justify-content:center;font-size:14px;background:color-mix(in srgb,var(--cc) 22%,#0b1220);border:1px solid color-mix(in srgb,var(--cc) 45%,transparent);box-shadow:0 0 8px color-mix(in srgb,var(--cc) 35%,transparent)}
.rt-cat .rt-clb{font-size:11px;font-weight:700;line-height:1.1}
.rt-cat .rt-clb small{display:block;color:var(--ink-dim);font-weight:600;font-size:9.5px}
.rt-cat.lit{border-color:color-mix(in srgb,var(--cc) 60%,transparent);box-shadow:0 0 16px color-mix(in srgb,var(--cc) 22%,transparent)}
.rt-node{position:absolute;width:56px;height:56px;border-radius:14px;z-index:5;cursor:pointer;display:flex;align-items:center;justify-content:center;background:radial-gradient(circle at 50% 35%,#1a2740,#0d1422);border:1.5px solid #2a3850;transition:transform .1s,box-shadow .14s,border-color .14s}
.rt-node:hover{transform:scale(1.12);z-index:15}
.rt-node .rt-glyph{font-size:22px;color:var(--bc);line-height:1;filter:drop-shadow(0 0 5px color-mix(in srgb,var(--bc) 60%,transparent))}
.rt-node .rt-pips{position:absolute;bottom:-9px;left:0;right:0;display:flex;gap:3px;justify-content:center}
.rt-node .rt-pips i{width:5px;height:5px;border-radius:50%;background:#2c3a56}
.rt-node .rt-pips i.on{background:var(--bc);box-shadow:0 0 4px var(--bc)}
.rt-node .rt-badge{position:absolute;top:-7px;right:-7px;font-size:10px;width:18px;height:18px;border-radius:50%;display:flex;align-items:center;justify-content:center;background:#0c1322;border:1px solid var(--border-soft)}
.rt-node .rt-badge.bt{color:var(--gold,#ffcf5a);border-color:#5a4a1e}
.rt-node .rt-badge.xt{color:#e6a8ff;border-color:#4a2a55}
.rt-node.s-available{border-color:var(--bc);box-shadow:0 0 0 1px var(--bc),0 0 16px color-mix(in srgb,var(--bc) 55%,transparent)}
.rt-node.s-owned{border-color:color-mix(in srgb,var(--bc) 70%,#3f6ea0);background:radial-gradient(circle at 50% 35%,color-mix(in srgb,var(--bc) 26%,#101a2e),#0c1320)}
.rt-node.s-maxed{border-color:var(--gold,#ffcf5a);box-shadow:0 0 0 1px var(--gold,#ffcf5a),0 0 14px rgba(255,207,90,.4);background:radial-gradient(circle at 50% 35%,#3a3318,#14130c)}
.rt-node.s-maxed .rt-glyph{color:var(--gold,#ffcf5a);filter:drop-shadow(0 0 6px var(--gold,#ffcf5a))}
.rt-node.s-unaffordable{border-color:color-mix(in srgb,var(--bc) 35%,#33415e)}
.rt-node.s-locked_prereq{opacity:.5;border-style:dashed}
.rt-node.s-locked_prereq .rt-glyph{opacity:.5}
.rt-node.fog{opacity:.5;border-style:dashed;border-color:#2a3850;background:repeating-linear-gradient(135deg,#0f1727 0 7px,#0b1220 7px 14px)}
.rt-node.fog .rt-glyph{color:#46557a;filter:none}
.rt-node .rt-foglv{position:absolute;bottom:-15px;left:0;right:0;text-align:center;font-size:9px;color:#cf8a8a;font-weight:700}
.rt-node.preset-hi{outline:2px dashed var(--gold,#ffcf5a);outline-offset:4px}
.rt-botbar{display:flex;align-items:center;gap:14px;flex-wrap:wrap;padding:8px 4px}
.rt-pts{display:flex;align-items:center;gap:8px}
.rt-pts .rt-gem{font-size:18px;color:var(--accent);filter:drop-shadow(0 0 8px var(--accent))}
.rt-pts .rt-n{font-size:20px;font-weight:800;font-variant-numeric:tabular-nums}
.rt-pts .rt-lb{font-size:10px;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-dim);line-height:1.05}
.rt-sep{width:1px;height:24px;background:var(--border-soft)}
.rt-lvl{color:var(--ink-dim);font-size:11px;text-transform:uppercase;letter-spacing:.05em}
.rt-lvl b{color:var(--ink);font-size:15px;margin:0 4px}
.rt-spacer{flex:1}
#rt-tip{position:fixed;max-width:300px;z-index:200;pointer-events:none;display:none;background:var(--bg-2);border:1px solid var(--accent);border-radius:12px;padding:12px 14px;box-shadow:0 14px 40px rgba(0,0,0,.65)}
#rt-tip h3{margin:0 0 2px;font-size:14px}
#rt-tip .meta{font-size:10.5px;color:var(--ink-dim);text-transform:uppercase;letter-spacing:.5px;margin-bottom:8px}
#rt-tip .eff{font-size:12.5px;margin-bottom:8px}
#rt-tip .req{font-size:11.5px;margin:2px 0}
#rt-tip .req .ok{color:var(--good,#6fe6a8)} #rt-tip .req .no{color:var(--danger,#ff7a7a)} #rt-tip .req .xt{opacity:.65}
#rt-tip .fl{font-size:11px;color:var(--ink-dim);font-style:italic;border-top:1px solid var(--border-soft);margin-top:8px;padding-top:7px}
#rt-tip .why{font-size:11.5px;color:var(--danger,#ff7a7a);margin-top:7px;font-weight:600}
#rt-tip .buy{font-size:11.5px;color:var(--good,#6fe6a8);margin-top:7px;font-weight:600}
#rt-tip .fogmsg{font-size:11.5px;color:#cf8a8a;font-weight:600}

/* ============================================================================
 * ENGINEERING — module detail redesign + locked skin swatches (2026-06-02)
 * ========================================================================== */
.engbot-sw.locked{opacity:.4;cursor:not-allowed;position:relative}
.engbot-sw.locked:hover{transform:none;border-color:#2a3a55}
.engbot-sw .sw-lock{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-size:11px}
.mod-detail{display:flex;flex-direction:column;gap:12px}
.mod-head{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.mod-stat-chip{font-size:10.5px;font-weight:700;letter-spacing:.04em;color:var(--accent);background:color-mix(in srgb,var(--accent) 14%,transparent);border:1px solid color-mix(in srgb,var(--accent) 35%,transparent);border-radius:20px;padding:3px 10px}
.mod-summary{margin:0;font-size:12.5px;line-height:1.45}
.mod-eyebrow{font-size:10px;text-transform:uppercase;letter-spacing:.12em;color:var(--ink-dim);font-weight:700;margin-bottom:3px}
.mod-tier-card{display:grid;grid-template-columns:1fr auto;gap:14px;align-items:center;padding:14px 16px;border:1px solid var(--border-soft);border-radius:var(--radius);background:linear-gradient(180deg,rgba(20,30,50,.5),rgba(12,18,30,.5))}
.mod-tier-name{font-size:15px;font-weight:700;margin-bottom:6px}
.mod-dots{display:flex;gap:4px;margin-bottom:6px}
.mod-final{text-align:right;border-left:1px solid var(--border-soft);padding-left:14px;min-width:118px}
.mod-final-val{font-size:26px;font-weight:800;color:var(--accent);font-variant-numeric:tabular-nums;line-height:1}
.mod-final-bd{margin-top:4px;font-family:var(--font-mono);letter-spacing:-.02em}
.mod-upgrade{display:grid;grid-template-columns:1fr auto;gap:14px;align-items:center;padding:14px 16px;border:1px solid color-mix(in srgb,var(--accent) 30%,var(--border-soft));border-radius:var(--radius);background:linear-gradient(180deg,color-mix(in srgb,var(--accent) 7%,transparent),transparent)}
.mod-up-name{font-size:14px;font-weight:700;margin:1px 0 3px}
.mod-up-delta{font-size:12px;color:var(--ink-dim);margin-bottom:4px}
.mod-up-delta b{color:var(--ink)}
.mod-up-action{text-align:right;display:flex;flex-direction:column;gap:8px;align-items:flex-end}
.mod-up-action .cost{font-size:15px;font-weight:800;font-variant-numeric:tabular-nums}
.mod-up-action .cost.ok{color:var(--good,#6fe6a8)}
.mod-up-action .cost.lack{color:var(--danger,#ff7a7a)}
.mod-maxed{padding:14px 16px;border:1px solid var(--gold,#ffcf5a);border-radius:var(--radius);background:rgba(255,207,90,.08);color:var(--gold,#ffcf5a);font-weight:700;text-align:center}
