/* BUNKED — Fallout-Shelter inspired UI */
:root {
  --bg: #0c0f0a;
  --panel: #14180f;
  --panel-2: #1c2113;
  --gold: #f6c23a;
  --gold-2: #c98f10;
  --green: #6dd36b;
  --red: #d35454;
  --blue: #69b8e7;
  --text: #e9ddb6;
  --muted: #8a8260;
  --border: #3a3320;
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; width: 100%; height: 100%; overflow: hidden; }
body {
  font-family: "Trebuchet MS", "Lucida Sans", system-ui, sans-serif;
  background: var(--bg);
  color: var(--text);
  user-select: none;
}

#app { position: fixed; inset: 0; }
#game {
  position: absolute; inset: 0; width: 100%; height: 100%; display: block;
  transition: filter 0.3s ease;
}
body.paused #game { filter: saturate(0.35) contrast(0.9) brightness(0.85); }

/* Viewport vignette — soft corner darkening that frames the picture without
   stealing focus from the HUD. */
#vignette {
  position: absolute; inset: 0;
  pointer-events: none;
  z-index: 3;
  background:
    radial-gradient(ellipse at center, rgba(0,0,0,0) 55%, rgba(0,0,0,0.55) 100%),
    linear-gradient(180deg, rgba(0,0,0,0.18) 0%, rgba(0,0,0,0) 14%, rgba(0,0,0,0) 88%, rgba(0,0,0,0.22) 100%);
}

/* CRT scanline mode — opt-in via Settings */
body.crt #vignette {
  background:
    repeating-linear-gradient(0deg, rgba(0,0,0,0.18) 0px, rgba(0,0,0,0.18) 1px, transparent 1px, transparent 3px),
    radial-gradient(ellipse at center, rgba(0,0,0,0) 50%, rgba(0,0,0,0.65) 100%),
    linear-gradient(180deg, rgba(0,0,0,0.20) 0%, rgba(0,0,0,0) 14%, rgba(0,0,0,0) 88%, rgba(0,0,0,0.28) 100%);
}
body.crt #game {
  filter: contrast(1.05) saturate(1.08);
}

/* Top HUD */
#hud-top {
  position: absolute; top: 0; left: 0; right: 0;
  display: flex; justify-content: space-between; align-items: center;
  padding: 8px 12px;
  background: linear-gradient(180deg, rgba(0,0,0,0.85), rgba(0,0,0,0.55) 80%, transparent);
  pointer-events: none;
  z-index: 5;
  flex-wrap: wrap;
  gap: 6px;
}
.hud-cluster { display: flex; gap: 10px; align-items: center; pointer-events: auto; flex-wrap: wrap; }

/* Vault I/O dropdown — groups save/load/slots/export/import under one button so
   the top-right HUD doesn't sprawl. The menu floats below the trigger button. */
.io-wrap { position: relative; display: inline-block; }
.io-menu {
  position: absolute; top: calc(100% + 4px); right: 0;
  background: var(--panel); border: 1px solid var(--gold-2);
  box-shadow: 0 8px 20px rgba(0,0,0,0.6);
  display: flex; flex-direction: column; min-width: 160px;
  padding: 4px; z-index: 30;
}
.io-menu.hidden { display: none; }
.io-item {
  text-align: left; justify-content: flex-start;
  padding: 6px 10px; font-size: 11px;
  border-color: transparent;
  background: transparent;
}
.io-item:hover { background: var(--panel-2); border-color: var(--gold-2); }
.io-sep { height: 1px; background: var(--border); margin: 4px 2px; }

/* Narrow-viewport tweaks for phone-ish widths. Keeps the world canvas
   primary; shrinks side panels so they don't dominate the screen. */
@media (max-width: 720px) {
  #hud-top { padding: 6px 8px; font-size: 11px; }
  .resource { min-width: 56px; padding: 3px 8px 5px; font-size: 11px; }
  .resource .ico canvas { width: 16px !important; height: 16px !important; }
  .clock { padding: 4px 8px; font-size: 11px; }
  .btn { padding: 5px 9px; font-size: 10px; }
  #build-panel { width: 230px; bottom: 8px; left: 8px; }
  #select-panel { width: 250px; bottom: 8px; right: 8px; }
  .bp-list { max-height: 220px; }
  .bp-item .thumb { width: 56px; height: 32px; }
  .ts-logo { width: 92vw; }
  .ts-tag { font-size: 11px; letter-spacing: 2px; }
}
@media (max-width: 480px) {
  /* Phone portrait: stack build + select horizontally so neither covers
     the world entirely. */
  #build-panel { width: 47vw; }
  #select-panel { width: 47vw; }
  .bp-item .desc, .bp-item .cost { display: none; }
  .bp-item .name { font-size: 10px; }
}
.resource {
  background: var(--panel);
  border: 1px solid var(--border);
  border-left: 4px solid var(--gold);
  padding: 4px 10px 6px;
  min-width: 70px;
  display: flex; gap: 6px; align-items: baseline;
  font-weight: 700;
  letter-spacing: 0.5px;
  box-shadow: inset 0 -2px 0 rgba(0,0,0,0.4);
  position: relative;
  overflow: hidden;
  cursor: help;
}
.resource[data-tip]:hover::after {
  content: attr(data-tip);
  position: absolute;
  top: 100%; left: 0;
  margin-top: 6px;
  white-space: pre-line;
  background: var(--panel);
  border: 1px solid var(--gold-2);
  border-left: 3px solid var(--gold);
  padding: 6px 10px;
  font-size: 11px;
  font-weight: 500;
  color: var(--text);
  letter-spacing: 0.3px;
  z-index: 12;
  box-shadow: 0 4px 12px rgba(0,0,0,0.7);
  pointer-events: none;
  overflow: visible;
  text-transform: none;
  min-width: 140px;
}
.resource .fillbar {
  position: absolute;
  left: 0; bottom: 0; height: 3px;
  background: var(--gold);
  transition: width 0.25s ease, background 0.25s ease;
  pointer-events: none;
}
.resource[data-res="water"] .fillbar { background: var(--blue); }
.resource[data-res="food"] .fillbar { background: var(--green); }
.resource[data-res="dwellers"] .fillbar { background: #d6a16a; }
.resource.danger .fillbar { background: var(--red) !important; }
.resource .ico { font-size: 14px; display: inline-flex; align-items: center; transition: transform 0.18s cubic-bezier(0.34, 1.56, 0.64, 1); }
.resource.gained .ico { transform: scale(1.35); }
.resource .val { color: var(--gold); }
.resource .cap { color: var(--muted); font-size: 11px; }
.resource .rate { font-size: 10px; margin-left: 4px; font-weight: 700; }
.resource .rate.pos { color: var(--green); }
.resource .rate.neg { color: var(--red); }
.resource.danger { animation: lowblink 0.8s ease-in-out infinite; }
@keyframes lowblink {
  0%, 100% { background: var(--panel); }
  50%      { background: #3a1010; }
}
.resource.critical { animation: critshake 0.3s ease-in-out infinite, lowblink 0.6s ease-in-out infinite; }
@keyframes critshake {
  0%, 100% { transform: translateX(0); }
  20%      { transform: translateX(-2px); }
  40%      { transform: translateX(2px); }
  60%      { transform: translateX(-1px); }
  80%      { transform: translateX(1px); }
}
/* Cap-locked: positive net production but the pool is already full. Pulses
 * a subtle gold glow so the player sees that they're "wasting" resources
 * and should build a Storage Vault. Never overrides .danger / .critical. */
.resource.capfull:not(.danger):not(.critical) {
  animation: capfullpulse 1.6s ease-in-out infinite;
  box-shadow: 0 0 0 0 rgba(246, 194, 58, 0.0);
}
.resource.capfull:not(.danger):not(.critical) .fillbar {
  background: var(--gold) !important;
  box-shadow: 0 0 6px rgba(246, 194, 58, 0.6);
}
@keyframes capfullpulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(246, 194, 58, 0.0); }
  50%      { box-shadow: 0 0 8px 1px rgba(246, 194, 58, 0.45); }
}
.resource[data-res="water"] { border-left-color: var(--blue); }
.resource[data-res="water"] .val { color: var(--blue); }
.resource[data-res="food"] { border-left-color: var(--green); }
.resource[data-res="food"] .val { color: var(--green); }
.resource[data-res="scrap"] { border-left-color: #aaa; }
.resource[data-res="scrap"] .val { color: #ddd; }
.resource[data-res="caps"] { border-left-color: var(--gold); }
.resource[data-res="dwellers"] { border-left-color: #d6a16a; }
.resource[data-res="dwellers"] .val { color: #d6a16a; }
/* First-rad tutorial chip — fixed-position card near the rad pill that
 * fires the very first time any dweller crosses the warning threshold.
 * Persists "seen" in localStorage so it never returns. */
#rad-tutorial {
  position: fixed;
  top: 60px; left: 50%;
  transform: translateX(-50%);
  z-index: 60;
  animation: radTutSlide 0.45s cubic-bezier(0.34, 1.56, 0.64, 1);
}
#rad-tutorial.hidden { display: none; }
/* First-raid tutorial chip — same position + animation as the rad chip
   but offset 6px down so a player who already saw the rad chip in this
   session doesn't see them stack. Iter 119. */
#raid-tutorial {
  position: fixed;
  top: 66px; left: 50%;
  transform: translateX(-50%);
  z-index: 60;
  animation: radTutSlide 0.45s cubic-bezier(0.34, 1.56, 0.64, 1);
}
#raid-tutorial.hidden { display: none; }
/* Re-tint the first-raid card border so it reads as danger, not safety. */
#raid-tutorial .rad-tut-card { border-left-color: #d35454; }
#raid-tutorial .rad-tut-icon { color: #d35454; }
#raid-tutorial .rad-tut-title { color: #d35454; }
.rad-tut-card {
  background: var(--panel);
  border: 1px solid var(--gold-2);
  border-left: 4px solid #8aff70;
  box-shadow: 0 8px 22px rgba(0, 0, 0, 0.6);
  display: flex; align-items: center; gap: 12px;
  padding: 10px 14px;
  max-width: 420px;
}
.rad-tut-icon {
  color: #8aff70;
  font-size: 26px;
  flex-shrink: 0;
}
.rad-tut-text { display: flex; flex-direction: column; gap: 3px; }
.rad-tut-title {
  color: #8aff70;
  font-size: 11px;
  letter-spacing: 2px;
  font-weight: 800;
}
.rad-tut-body { color: var(--text); font-size: 12px; line-height: 1.45; }
.rad-tut-body b { color: var(--gold); }
.rad-tut-actions { display: flex; flex-direction: column; gap: 4px; flex-shrink: 0; }
.rad-tut-dismiss { flex-shrink: 0; }
.rad-tut-show { flex-shrink: 0; font-size: 10px; }
/* "Pointed at" pulse — applied to a .bp-item when the rad-tutorial
 * "Show me" button is clicked. Strong-yellow ring that draws the eye
 * straight to the Medbay tile, decays in 4 seconds. */
.bp-item.bp-pointed {
  animation: bpPointed 1.0s ease-in-out infinite;
  z-index: 2;
}
@keyframes bpPointed {
  0%, 100% {
    box-shadow: 0 0 0 1px var(--gold), 0 0 0 4px rgba(246, 194, 58, 0.0);
  }
  50% {
    box-shadow: 0 0 0 1px var(--gold), 0 0 0 7px rgba(246, 194, 58, 0.45);
  }
}
@keyframes radTutSlide {
  from { opacity: 0; transform: translate(-50%, -10px); }
  to   { opacity: 1; transform: translate(-50%, 0); }
}

/* Rad summary — only shown when at least one dweller is carrying rads
 * over the warning threshold. Glow scales with severity: warning = green
 * glow, severe = pulsing red-green. Hidden by default via the
 * markup-level `.hidden` class so a clean vault doesn't see the pill. */
.resource[data-res="rads"] { border-left-color: #8aff70; }
.resource[data-res="rads"] .val { color: #8aff70; }
.resource[data-res="rads"] .fillbar {
  /* Green at 0, orange at 60, red at 100 — sweeps as max-rads climbs. */
  background: linear-gradient(90deg, #8aff70 0%, #ffb060 60%, #d35454 100%);
}
.resource[data-res="rads"].rads-severe {
  border-left-color: #d35454;
  animation: lowblink 0.7s ease-in-out infinite;
}
.resource[data-res="rads"].rads-severe .val { color: #ffb060; }

.clock {
  background: var(--panel);
  border: 1px solid var(--border);
  padding: 5px 10px;
  font-weight: 700;
  color: var(--gold);
}
.speedctl { display: flex; gap: 0; }
.speed-btn { padding: 5px 8px; font-size: 11px; min-width: 36px; }
.speed-btn.active { background: var(--gold-2); color: #1a1408; }

.btn {
  background: linear-gradient(180deg, #2a2614, #1a1709);
  border: 1px solid var(--border);
  color: var(--text);
  padding: 6px 12px;
  font-weight: 700;
  letter-spacing: 0.5px;
  cursor: pointer;
  font-family: inherit;
  text-transform: uppercase;
  font-size: 11px;
}
.btn:hover { background: linear-gradient(180deg, #3a3220, #221c0c); color: var(--gold); }
.btn:active { transform: translateY(1px); }
.btn.primary { border-color: var(--gold-2); color: var(--gold); }
.btn:disabled { opacity: 0.4; cursor: not-allowed; }

/* Rush button cooldown ring — conic gradient fills as cooldown elapses. */
.rush-btn {
  position: relative;
  --cd-deg: 360deg;
}
.rush-btn:disabled::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: conic-gradient(rgba(246, 194, 58, 0.30) var(--cd-deg), transparent var(--cd-deg));
  z-index: 0;
}
.rush-btn:disabled { opacity: 0.7; }

/* Build panel */
#build-panel {
  position: absolute; bottom: 12px; left: 12px;
  width: 290px;
  background: var(--panel);
  border: 1px solid var(--border);
  z-index: 5;
  box-shadow: 0 4px 20px rgba(0,0,0,0.6);
}
.bp-title {
  background: var(--gold-2);
  color: #1a1408;
  padding: 4px 10px;
  font-weight: 800;
  letter-spacing: 2px;
  font-size: 12px;
}
.bp-tabs { display: flex; border-bottom: 1px solid var(--border); }
.bp-tab {
  flex: 1; padding: 6px 4px;
  background: var(--panel-2);
  border: none; border-right: 1px solid var(--border);
  color: var(--muted); font-weight: 700; font-size: 11px;
  cursor: pointer; font-family: inherit;
  text-transform: uppercase;
}
.bp-tab:last-child { border-right: none; }
.bp-tab.active { color: var(--gold); background: var(--panel); border-bottom: 2px solid var(--gold); }

.bp-list { max-height: 360px; overflow-y: auto; padding: 6px; }
.bp-section {
  font-size: 9px;
  font-weight: 800;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--gold-2);
  padding: 6px 6px 2px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 4px;
}
.bp-section:not(:first-child) { margin-top: 6px; }

.bp-hint {
  background: rgba(246, 194, 58, 0.12);
  border-bottom: 1px solid var(--border);
  border-top: 1px solid rgba(246, 194, 58, 0.4);
  color: var(--gold);
  font-size: 10px;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  text-align: center;
  padding: 5px 8px;
  font-weight: 700;
  /* Iter 95: prevent long staff-reco labels ("Staff your Water Treatment
   * — water will run out · 25 scrap, 100 caps") from wrapping into a
   * three-line block that pushes the build menu down on phones. The
   * full text remains accessible via the data-tip popup. */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Recommendation hint: brighter than the idle-staff variant, and pulses
 * gently so the eye catches it during the first 30 minutes. */
.bp-hint.bp-hint-reco {
  background: rgba(246, 194, 58, 0.22);
  border-top-color: var(--gold);
  color: #fff5b8;
  animation: bpRecoPulse 1.8s ease-in-out infinite;
}
/* Iter 60: cost-aware reco color. Greys the hint slightly when the player
 * can't afford the suggestion yet, so it reads as "next big move" not
 * "do this now." */
.bp-hint.bp-hint-reco.bp-hint-unafford {
  color: var(--muted);
  background: rgba(246, 194, 58, 0.10);
  animation: none;
}
/* Iter 65: urgency tiers. Emergencies pulse to draw the eye; advisories
 * keep the cool-gold pulse from .bp-hint-reco.
 * Iter 68: switched emergency from red to amber-coral (#e87a3a) so it
 * doesn't visually compete with the iter-52 `.rads-severe` red rad pill
 * blink. Reds in the HUD are now reserved for "running on fumes"
 * resources (the iter-23 .danger blink) and irradiation severity. */
.bp-hint.bp-hint-reco.bp-hint-emergency {
  background: rgba(232, 122, 58, 0.22);
  border-top-color: #e87a3a;
  color: #ffd9b8;
  animation: bpEmergencyPulse 1.0s ease-in-out infinite;
}
.bp-hint.bp-hint-reco.bp-hint-emergency.bp-hint-unafford {
  /* Emergency that's unaffordable still reads as urgent but muted. */
  background: rgba(232, 122, 58, 0.10);
  color: var(--muted);
  animation: none;
}
@keyframes bpEmergencyPulse {
  0%, 100% { background: rgba(232, 122, 58, 0.18); }
  50%      { background: rgba(232, 122, 58, 0.38); }
}
/* Iter 63: per-component cost coloring inside the reco hint. Inherits
 * the cost-ok / cost-short class names from build-menu items but maps
 * them to the hint's gold/red palette. */
.bp-hint .cost-ok    { color: var(--gold); font-weight: 700; }
.bp-hint .cost-short { color: var(--red);  font-weight: 700; }
/* Click affordance — the hint band is interactive when it carries a reco. */
.bp-hint.bp-hint-reco { cursor: pointer; position: relative; }
/* Iter 68: discovery tooltip via data-tip — matches resource-pill pattern,
 * no 700ms hover delay like the native title attribute. Anchored below
 * the band so it doesn't overlap the menu items beneath. */
.bp-hint[data-tip]:hover::after {
  content: attr(data-tip);
  position: absolute;
  top: 100%; left: 50%;
  transform: translateX(-50%);
  margin-top: 4px;
  background: var(--panel);
  border: 1px solid var(--gold-2);
  padding: 4px 8px;
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.4px;
  color: var(--text);
  text-transform: none;
  white-space: nowrap;
  z-index: 14;
  box-shadow: 0 4px 10px rgba(0,0,0,0.6);
  pointer-events: none;
}
/* Iter 72: on tight viewports flip the tooltip above the hint band so
 * the popup doesn't cover the first build-menu item (which is often
 * the recommended tile). Picks the same breakpoint as the build panel
 * narrow-viewport rules. */
@media (max-width: 720px) {
  .bp-hint[data-tip]:hover::after {
    top: auto;
    bottom: 100%;
    margin-top: 0;
    margin-bottom: 4px;
  }
}
@keyframes bpRecoPulse {
  0%, 100% { background: rgba(246, 194, 58, 0.18); }
  50%      { background: rgba(246, 194, 58, 0.34); }
}
/* Matching tile glow in the build menu — the same gold reads from the hint
 * down to the action so the player's eye tracks left-then-down naturally. */
.bp-item.bp-recommended {
  border-color: var(--gold);
  box-shadow: -3px 0 0 var(--gold), 0 0 10px rgba(246, 194, 58, 0.20) inset;
  background: linear-gradient(90deg, rgba(246, 194, 58, 0.10), var(--panel-2) 60%);
}
.bp-item.bp-recommended::after {
  content: "▶";
  position: absolute;
  right: 6px;
  top: 50%;
  transform: translateY(-50%);
  color: var(--gold);
  font-size: 12px;
  animation: bpRecoArrow 1.4s ease-in-out infinite;
}
.bp-item { position: relative; }
@keyframes bpRecoArrow {
  0%, 100% { transform: translateY(-50%) translateX(0); opacity: 0.7; }
  50%      { transform: translateY(-50%) translateX(2px); opacity: 1.0; }
}
.bp-item {
  background: var(--panel-2);
  border: 1px solid var(--border);
  padding: 6px;
  margin-bottom: 5px;
  cursor: pointer;
  display: flex; gap: 8px; align-items: center;
  transition: transform 0.08s ease, border-color 0.12s ease, box-shadow 0.12s ease;
}
.bp-item:hover {
  border-color: var(--gold);
  transform: translateX(2px);
  box-shadow: -3px 0 0 var(--gold-2);
}
.bp-item:active { transform: translateX(1px) scale(0.99); }
.bp-item.disabled { opacity: 0.5; cursor: not-allowed; transform: none; }
.bp-item .swatch {
  width: 80px; height: 44px;
  border: 1px solid var(--border);
  flex-shrink: 0;
}
.bp-item .thumb {
  width: 80px; height: 44px;
  border: 1px solid var(--border);
  flex-shrink: 0;
  image-rendering: pixelated;
  display: block;
  object-fit: cover;
  border-radius: 2px;
  box-shadow: inset 0 0 0 1px rgba(246, 194, 58, 0.18);
  transition: filter 0.18s ease;
}
/* Unaffordable items: desaturate thumb + dim slightly. Affordable: full color. */
.bp-item.unaffordable .thumb { filter: saturate(0.35) brightness(0.7); }
.bp-item.unaffordable .name { color: var(--muted); }
.bp-item .meta { flex: 1; min-width: 0; }
.bp-item .name {
  font-weight: 800; color: var(--gold); font-size: 12px;
  text-transform: uppercase; letter-spacing: 0.4px;
}
.bp-item .desc {
  font-size: 11px; color: var(--muted); line-height: 1.3;
  overflow: hidden; text-overflow: ellipsis;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
.bp-item .cost { font-size: 10px; color: var(--text); margin-top: 2px; }
.bp-item .cost .cost-ok { color: var(--text); }
.bp-item .cost .cost-short { color: var(--red); font-weight: 700; }
.bp-item.affordable-now {
  animation: justAffordable 0.9s ease-out;
}
@keyframes justAffordable {
  0%   { background: var(--panel-2); box-shadow: none; }
  25%  { background: rgba(109, 211, 107, 0.18); box-shadow: 0 0 0 1px var(--green), 0 0 14px rgba(109, 211, 107, 0.55); }
  100% { background: var(--panel-2); box-shadow: none; }
}

/* Selection panel */
#select-panel {
  position: absolute; bottom: 12px; right: 12px;
  width: 300px;
  background: var(--panel);
  border: 1px solid var(--border);
  z-index: 5;
  box-shadow: 0 4px 20px rgba(0,0,0,0.6);
}
.sp-title {
  background: var(--gold-2);
  color: #1a1408;
  padding: 4px 10px;
  font-weight: 800;
  letter-spacing: 1.5px;
}
.skill-pips { display: inline-flex; gap: 3px; }
.skill-pip {
  width: 11px; height: 11px;
  background: var(--panel-2);
  border: 1px solid var(--border);
}
.skill-pip.filled { background: var(--gold); border-color: var(--gold-2); box-shadow: 0 0 5px rgba(246, 194, 58, 0.4); }
.entity-feed-title {
  font-size: 9px; text-transform: uppercase; letter-spacing: 1.2px;
  color: var(--muted); margin: 8px 0 4px;
}
.entity-feed-row {
  font-size: 11px;
  color: var(--text);
  padding: 3px 6px;
  background: var(--panel-2);
  border-left: 2px solid var(--gold);
  margin-bottom: 2px;
  line-height: 1.3;
}

.rename-input {
  background: transparent; border: none; outline: none;
  color: #1a1408; font: inherit; font-weight: 800; letter-spacing: 1.5px;
  width: 100%; text-transform: uppercase;
}
.rename-input:focus { background: rgba(0,0,0,0.15); }
.sp-body { padding: 10px; font-size: 12px; line-height: 1.5; }
.sp-body .row { display: flex; justify-content: space-between; align-items: center; }
.sp-body .row .k { color: var(--muted); }
.status-chip {
  display: inline-block;
  padding: 2px 8px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  border-radius: 2px;
  border: 1px solid;
}
.status-chip.status-ok    { background: rgba(109, 211, 107, 0.18); border-color: var(--green); color: var(--green); }
.status-chip.status-warn  { background: rgba(246, 194, 58, 0.18); border-color: var(--gold); color: var(--gold); }
.status-chip.status-build { background: rgba(105, 184, 231, 0.18); border-color: var(--blue); color: var(--blue); }
.status-chip.status-bad   { background: rgba(211, 84, 84, 0.18); border-color: var(--red); color: var(--red); }
.sp-actions { display: flex; gap: 4px; padding: 6px; border-top: 1px solid var(--border); flex-wrap: wrap; }
.worker-list { padding: 4px 10px; }
.worker-item {
  display: flex; align-items: center; justify-content: space-between;
  padding: 2px 0; font-size: 12px;
}
.worker-item .w-name { color: var(--gold); }
.worker-item .w-eject { padding: 0 6px; line-height: 1; min-width: 20px; }
.sp-actions .btn { flex: 1; min-width: 80px; }
.hidden { display: none !important; }

/* Settings modal */
#settings-modal {
  position: absolute; inset: 0; background: rgba(0,0,0,0.7);
  display: flex; align-items: center; justify-content: center; z-index: 19;
}
.set-card {
  background: var(--panel); border: 2px solid var(--gold-2);
  min-width: 360px;
  box-shadow: 0 8px 40px rgba(0,0,0,0.8);
}
.set-title {
  background: var(--gold-2); color: #1a1408;
  padding: 6px 12px; font-weight: 800; letter-spacing: 2px;
}
.set-body { padding: 12px 14px; }
/* Tabbed settings: tab strip lives between the title bar and the body so
 * each pane stays short and the panel doesn't grow ten rows tall. Active
 * pane uses gold underline; inactive panes hide via .hidden. */
.set-tabs {
  display: flex; gap: 4px;
  padding: 6px 8px 0;
  background: var(--panel);
  border-bottom: 1px solid var(--border);
}
.set-tab {
  font-size: 10px;
  letter-spacing: 1.2px;
  padding: 5px 12px 6px;
  background: transparent;
  border: none;
  color: var(--muted);
  border-bottom: 2px solid transparent;
}
.set-tab:hover { color: var(--text); }
.set-tab.active {
  color: var(--gold);
  border-bottom-color: var(--gold);
  background: rgba(246, 194, 58, 0.06);
}
.set-pane.hidden { display: none; }
.set-pane { min-height: 120px; }
.set-row {
  display: flex; align-items: center; justify-content: space-between;
  padding: 6px 0;
  font-size: 12px; color: var(--text);
}
.set-label { color: var(--muted); text-transform: uppercase; letter-spacing: 0.6px; font-size: 11px; }
.set-value { color: var(--gold); font-weight: 700; }
.set-help {
  display: inline-flex; align-items: center; justify-content: center;
  width: 14px; height: 14px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 50%;
  color: var(--muted);
  font-size: 9px; font-weight: 700;
  cursor: help;
  margin-left: 4px;
  transition: color 0.15s, border-color 0.15s;
}
.set-help:hover { color: var(--gold); border-color: var(--gold-2); }
.set-row select, .set-row input[type="checkbox"] {
  background: var(--panel-2); color: var(--gold);
  border: 1px solid var(--border); padding: 3px 6px; font-family: inherit;
}
.set-row input[type="checkbox"] {
  width: 18px; height: 18px; accent-color: var(--gold);
}
.set-actions { display: flex; justify-content: flex-end; padding: 6px; border-top: 1px solid var(--border); }

/* Achievements modal — earned milestones with painted badges */
#ach-modal {
  position: absolute; inset: 0; background: rgba(0,0,0,0.7);
  display: flex; align-items: center; justify-content: center; z-index: 18;
}
.ach-card {
  background: var(--panel); border: 2px solid var(--gold-2);
  min-width: 440px; max-width: 540px;
  box-shadow: 0 8px 40px rgba(0,0,0,0.8);
}
.ach-title {
  background: var(--gold-2); color: #1a1408;
  padding: 6px 12px; font-weight: 800; letter-spacing: 2px;
  display: flex; justify-content: space-between; align-items: center;
}
.ach-progress { font-size: 11px; font-weight: 700; letter-spacing: 1px; opacity: 0.7; }
.ach-filter {
  display: flex; gap: 4px; padding: 6px; border-bottom: 1px solid var(--border);
  background: var(--panel-2); flex-wrap: wrap; align-items: center;
}
.ach-filter-btn { font-size: 10px; padding: 4px 10px; }
.ach-filter-btn.active { background: var(--gold-2); color: #1a1408; }
/* Iter 97: per-category completion tint — fully-earned categories get
 * a subtle gold tint on the (non-active) state so the player can see
 * "I have all the Population ones" at a glance from the filter row. */
.ach-filter-btn.ach-cat-complete:not(.active) {
  border-color: var(--gold);
  color: var(--gold);
}
.ach-filter-sep { width: 1px; align-self: stretch; background: var(--border); margin: 0 4px; }
.ach-list {
  padding: 12px;
  max-height: 60vh;
  overflow-y: auto;
  display: grid; grid-template-columns: 1fr 1fr; gap: 8px;
}
.ach-row {
  display: flex; align-items: center; gap: 10px;
  padding: 8px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  font-size: 11px;
}
.ach-row.locked { opacity: 0.4; }
.ach-row.earned { border-left: 3px solid var(--gold); }
/* Hidden-tease rows: italic cryptic hint, slight indent on the name so
 * the row reads as a riddle rather than a missing data field. */
.ach-row.hidden-tease .ach-name { letter-spacing: 4px; }
.ach-row.hidden-tease .ach-day { font-style: italic; opacity: 0.85; }
.ach-icon {
  width: 48px; height: 48px;
  display: flex; align-items: center; justify-content: center;
  font-size: 22px; color: var(--gold);
  flex-shrink: 0;
}
.ach-icon canvas { image-rendering: pixelated; }
.ach-row.locked .ach-icon {
  /* Use silhouette badge instead of placeholder */
  background: transparent; border: none;
}
.ach-row.locked .ach-icon { color: var(--muted); }
.ach-info { display: flex; flex-direction: column; }
.ach-name { color: var(--gold); font-weight: 700; }
.ach-row.locked .ach-name { color: var(--muted); }
.ach-day { color: var(--muted); font-size: 10px; }
.ach-actions { display: flex; justify-content: flex-end; padding: 6px; border-top: 1px solid var(--border); }

/* Slot picker modal */
#slots-modal {
  position: absolute; inset: 0; background: rgba(0,0,0,0.7);
  display: flex; align-items: center; justify-content: center; z-index: 18;
}
.slots-card {
  background: var(--panel); border: 2px solid var(--gold-2);
  min-width: 380px; box-shadow: 0 8px 40px rgba(0,0,0,0.8);
}
.slots-title {
  background: var(--gold-2); color: #1a1408;
  padding: 6px 12px; font-weight: 800; letter-spacing: 2px;
}
.slots-list { padding: 8px; }
.slot-row {
  display: flex; align-items: center; gap: 10px;
  background: var(--panel-2); border: 1px solid var(--border);
  padding: 8px 10px; margin-bottom: 6px;
}
.slot-thumb {
  width: 120px; height: 56px;
  border: 1px solid var(--border);
  image-rendering: pixelated;
  display: block;
  object-fit: cover;
  flex-shrink: 0;
  transition: box-shadow 0.18s ease, transform 0.18s ease;
  position: relative;
}
/* Iter 107: instant data-tip popup on the slot thumb. Same pattern as
 * the iter-68 build-hint tooltip. Anchored above the thumb so the
 * popup doesn't run off the bottom of the modal. */
.slot-thumb[data-tip]:hover::after {
  content: attr(data-tip);
  position: absolute;
  bottom: 100%; left: 0;
  margin-bottom: 4px;
  white-space: pre-line;
  background: var(--panel);
  border: 1px solid var(--gold-2);
  border-left: 3px solid var(--gold);
  padding: 6px 10px;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.3px;
  color: var(--text);
  z-index: 30;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.7);
  pointer-events: none;
  min-width: 160px;
  text-transform: none;
}
.slot-row:hover .slot-thumb {
  box-shadow: 0 0 0 1px var(--gold), 0 0 12px rgba(246, 194, 58, 0.45);
  transform: translateX(1px);
}
.slot-thumb-empty {
  background: #1a1408; color: var(--muted);
  display: flex; align-items: center; justify-content: center;
  font-size: 10px; letter-spacing: 2px;
}
.slot-info { flex: 1; min-width: 0; }
.slot-row .slot-label { font-weight: 700; color: var(--gold); }
.slot-label-input {
  background: transparent; border: none; outline: none;
  color: var(--gold); font: inherit; font-weight: 700;
  letter-spacing: 0.5px; width: 100%; padding: 0;
}
.slot-label-input:focus {
  background: rgba(246, 194, 58, 0.1);
  outline: 1px dashed var(--gold-2);
}
.slot-row .slot-meta { color: var(--muted); font-size: 11px; }
.slot-row .slot-actions { display: flex; flex-direction: column; gap: 4px; }
.slot-row .slot-actions .btn { padding: 4px 8px; font-size: 10px; }
.slots-actions { display: flex; justify-content: flex-end; padding: 6px; border-top: 1px solid var(--border); }

/* Achievement unlocked banner — slides in from the right, holds, slides out */
#ach-banner {
  position: absolute;
  top: 60px; right: 12px;
  z-index: 11;
  background: var(--panel);
  border: 1px solid var(--gold-2);
  border-left: 4px solid var(--gold);
  padding: 10px 14px 10px 10px;
  display: flex; gap: 12px; align-items: center;
  min-width: 280px;
  box-shadow: 0 6px 20px rgba(0,0,0,0.7), 0 0 24px rgba(246, 194, 58, 0.3);
  transform: translateX(110%);
  transition: transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1), opacity 0.3s ease;
  opacity: 0;
}
#ach-banner.show { transform: translateX(0); opacity: 1; }
.ach-banner-badge { width: 56px; height: 56px; flex-shrink: 0; }
.ach-banner-badge canvas { display: block; width: 100%; height: 100%; image-rendering: pixelated; }
.ach-banner-text { display: flex; flex-direction: column; gap: 2px; }
.ach-banner-eyebrow {
  color: var(--gold-2);
  font-size: 9px; font-weight: 700; letter-spacing: 2px;
  text-transform: uppercase;
}
.ach-banner-name {
  color: var(--gold);
  font-size: 14px; font-weight: 800; letter-spacing: 1px;
  text-transform: uppercase;
}

/* Pause overlay — dims the whole world and shows a watermark stamp */
#pause-overlay {
  position: absolute; inset: 0;
  background: rgba(10, 12, 20, 0.45);
  z-index: 8;
  pointer-events: none;
  display: flex; align-items: flex-start; justify-content: center;
  padding-top: 22vh;
  animation: pausefade 0.2s ease-out;
}
.pause-stamp {
  font-size: 88px; font-weight: 900; letter-spacing: 18px;
  color: var(--gold);
  text-shadow: 0 4px 22px rgba(0,0,0,0.8), 0 0 12px rgba(246,194,58,0.5);
  border: 4px solid var(--gold-2);
  padding: 14px 36px;
  background: rgba(20, 16, 8, 0.6);
  transform: rotate(-2deg);
}
@keyframes pausefade { from { opacity: 0; } to { opacity: 1; } }

/* Raid alert banner */
#raid-alert {
  position: absolute; top: 70px; left: 50%; transform: translateX(-50%);
  background: var(--red); color: #fff;
  padding: 6px 18px; font-weight: 800; letter-spacing: 2px; font-size: 14px;
  z-index: 9; border: 2px solid #fff;
  animation: raidpulse 0.6s ease-in-out infinite;
  pointer-events: none;
}
@keyframes raidpulse {
  0%, 100% { transform: translateX(-50%) scale(1); }
  50%      { transform: translateX(-50%) scale(1.05); }
}

/* Title splash card — shown on every load until dismissed */
#title-splash {
  position: absolute; inset: 0;
  background: radial-gradient(ellipse at center, #1a1408 0%, #06040a 100%);
  display: flex; align-items: center; justify-content: center;
  z-index: 50;
  animation: titleFadeIn 0.4s ease-out;
}
#title-splash.fading {
  animation: titleFadeOut 0.45s ease-in forwards;
}
@keyframes titleFadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes titleFadeOut {
  from { opacity: 1; }
  to   { opacity: 0; }
}
.ts-card {
  display: flex; flex-direction: column; align-items: center;
  max-width: 90vw;
}
.ts-logo {
  width: 720px; max-width: 90vw;
  filter: drop-shadow(0 8px 28px rgba(0,0,0,0.75));
}
.ts-logo canvas { display: block; width: 100%; height: auto; image-rendering: pixelated; }
.ts-tag {
  color: var(--gold);
  font-size: 14px; letter-spacing: 4px; text-transform: uppercase;
  margin-top: 14px;
  text-shadow: 0 2px 8px rgba(0,0,0,0.6);
}
.ts-actions {
  display: flex; gap: 10px;
  margin-top: 22px;
}
.ts-btn { padding: 10px 28px; font-size: 13px; min-width: 140px; }
.ts-footer {
  color: var(--muted);
  font-size: 10px; letter-spacing: 2px;
  margin-top: 22px;
  font-family: monospace;
}

/* First-run onboarding overlay */
#onboarding {
  position: absolute; inset: 0; background: rgba(0,0,0,0.75);
  display: flex; align-items: center; justify-content: center; z-index: 30;
}
.ob-card {
  background: var(--panel); border: 2px solid var(--gold-2);
  padding: 0; min-width: 380px; max-width: 460px;
  box-shadow: 0 8px 40px rgba(0,0,0,0.8);
}
.ob-title {
  background: var(--gold-2); color: #1a1408;
  padding: 8px 14px; font-weight: 800; letter-spacing: 3px; font-size: 14px;
  text-align: center;
}
.ob-body { padding: 14px 18px; }
.ob-row {
  display: flex; align-items: center; gap: 10px;
  padding: 4px 0; font-size: 12px; color: var(--text);
}
.ob-key {
  background: #2a2614; border: 1px solid var(--border);
  color: var(--gold); padding: 2px 7px;
  font-family: monospace; font-size: 11px;
  min-width: 48px; text-align: center;
  border-radius: 3px;
}
.ob-card .btn { display: block; margin: 6px 18px 14px; width: calc(100% - 36px); }

/* Dweller drag-ghost — follows the cursor while assigning by drag */
.dweller-ghost {
  position: fixed;
  pointer-events: none;
  transform: translate(-50%, -50%);
  z-index: 20;
  filter: drop-shadow(0 4px 6px rgba(0,0,0,0.65));
  opacity: 0.92;
}
.dweller-ghost canvas { display: block; image-rendering: pixelated; }

/* Quick action chips floating over the selected entity */
#quick-actions {
  position: absolute; z-index: 7;
  display: flex; gap: 4px;
  transform: translate(-50%, -100%);
  pointer-events: auto;
  opacity: 0;
  transition: opacity 0.18s ease, transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1);
}
#quick-actions.show {
  opacity: 1;
  transform: translate(-50%, calc(-100% - 8px));
}
.qa-chip {
  background: var(--panel);
  border: 1px solid var(--gold-2);
  color: var(--gold);
  padding: 3px 9px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  cursor: pointer;
  white-space: nowrap;
  box-shadow: 0 3px 10px rgba(0,0,0,0.55);
  font-family: inherit;
  transition: transform 0.1s ease, background 0.12s ease;
}
.qa-chip:hover { background: var(--gold-2); color: #1a1408; transform: translateY(-1px); }
.qa-chip:active { transform: translateY(0) scale(0.97); }

/* Hover tooltip — with optional thumbnail preview */
#hover-tip {
  position: absolute; pointer-events: none; z-index: 9;
  background: var(--panel); border: 1px solid var(--border); border-left: 3px solid var(--gold);
  padding: 5px 9px; font-size: 11px; color: var(--text);
  transform: translate(-50%, -120%);
  box-shadow: 0 4px 12px rgba(0,0,0,0.7);
  display: flex; gap: 8px; align-items: center;
  min-width: 0;
}
#hover-tip .tip-thumb {
  width: 80px; height: 44px;
  border: 1px solid var(--border);
  image-rendering: pixelated;
  display: block;
  object-fit: cover;
  flex-shrink: 0;
}
#hover-tip .tip-text { display: flex; flex-direction: column; gap: 2px; white-space: nowrap; }
#hover-tip .tip-title { color: var(--gold); font-weight: 700; text-transform: uppercase; letter-spacing: 0.5px; }
#hover-tip .tip-body { color: var(--text); }

/* Placement reason badge — follows the cursor while placing, surfaces
   the canPlaceRoom/canPlaceSurface reason string in real time when the
   ghost is invalid. Hidden when the placement is valid or no placement
   is active. Iter 117. */
#place-reason {
  position: absolute; pointer-events: none; z-index: 11;
  background: rgba(28, 18, 12, 0.94);
  border: 1px solid #d35454; border-left: 3px solid #d35454;
  padding: 4px 8px; font-size: 11px; color: #f1d6d6;
  transform: translate(-50%, 0);
  letter-spacing: 0.3px;
  box-shadow: 0 3px 10px rgba(0,0,0,0.7);
  max-width: 240px;
  white-space: nowrap;
}
#place-reason.hidden { display: none; }
/* Iter 123: positive "flush" variant — green tint instead of red.
   Fires when the placement is valid AND sits flush against an
   existing room on the same floor. Same DOM element, swapped colors. */
#place-reason.flush {
  border-color: #8aff70; border-left-color: #8aff70;
  color: #d6f5d6;
}
/* Iter 124: "warn" variant — amber/gold for "tiny gap" hints. Mid-
   way between the green-flush positive and the red-invalid error.
   Same DOM element, swapped colors again. */
#place-reason.warn {
  border-color: #f6c23a; border-left-color: #f6c23a;
  color: #f6e0a0;
}

/* Toast stack — each new toast pushes below older ones, all share a column */
#toast { display: none; } /* legacy element from initial HTML */
#toast-stack {
  /* Top-center but shifted down so it doesn't collide with the raid banner
     at top: 70px when present. Sits between HUD and any centered overlay. */
  position: absolute; top: 110px; left: 50%;
  transform: translateX(-50%);
  display: flex; flex-direction: column; gap: 6px;
  z-index: 10; pointer-events: none;
  align-items: center;
}
.toast-item {
  background: var(--panel);
  border: 1px solid var(--gold-2);
  border-left: 4px solid var(--gold);
  padding: 8px 14px;
  color: var(--gold);
  font-weight: 700;
  opacity: 0;
  transform: translateY(-8px) scale(0.92);
  transition: opacity 0.18s ease, transform 0.28s cubic-bezier(0.34, 1.56, 0.64, 1);
  box-shadow: 0 4px 16px rgba(0,0,0,0.5);
  white-space: nowrap;
}
.toast-item.show {
  opacity: 1;
  transform: translateY(0) scale(1);
}

/* In-world log feed — bottom-left ticker, last 3 events fade out */
#log-feed {
  position: absolute;
  left: 12px;
  bottom: 80px;
  width: 320px;
  max-width: 30vw;
  z-index: 4;
  pointer-events: none;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.lf-item {
  background: rgba(20, 24, 15, 0.78);
  border-left: 3px solid var(--gold);
  padding: 4px 8px;
  font-size: 11px;
  color: var(--text);
  line-height: 1.4;
  opacity: 0;
  transform: translateX(-12px);
  transition: opacity 0.25s ease, transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  box-shadow: 0 2px 8px rgba(0,0,0,0.4);
}
.lf-item.show { opacity: 1; transform: translateX(0); }
.lf-item.fading { opacity: 0.3; }
.lf-time { color: var(--muted); margin-right: 6px; font-family: monospace; font-size: 10px; }

/* Help bar */
#help {
  position: absolute; bottom: 0; left: 50%; transform: translateX(-50%);
  background: rgba(0,0,0,0.5);
  padding: 4px 10px;
  font-size: 11px;
  color: var(--muted);
  z-index: 4;
}
#help kbd {
  background: #2a2614; border: 1px solid var(--border);
  padding: 0 4px; border-radius: 2px; color: var(--gold);
  font-family: monospace;
}

/* Build placement ghost cursor */
.placing { cursor: crosshair !important; }

/* Event log panel */
#log-panel {
  position: absolute; top: 60px; right: 12px; width: 320px; max-height: 50vh;
  background: var(--panel); border: 1px solid var(--border);
  z-index: 6; display: flex; flex-direction: column;
}
.lp-title {
  background: var(--gold-2); color: #1a1408;
  padding: 4px 10px; font-weight: 800; letter-spacing: 1.5px;
  display: flex; justify-content: space-between; align-items: center;
}
.lp-close { padding: 0 8px; line-height: 1; font-size: 16px; }
.lp-list { overflow-y: auto; padding: 6px 10px; font-size: 12px; line-height: 1.5; }
.lp-list .lp-row { padding: 2px 0; border-bottom: 1px dashed #2a2614; }
.lp-list .lp-row:last-child { border-bottom: none; }
.lp-list .lp-time { color: var(--muted); margin-right: 6px; font-family: monospace; font-size: 11px; }

/* Game over modal */
#gameover {
  position: absolute; inset: 0; background: rgba(0,0,0,0.75);
  display: flex; align-items: center; justify-content: center;
  z-index: 20;
}
.go-card {
  background: var(--panel); border: 2px solid var(--gold-2);
  padding: 0; text-align: center; min-width: 460px;
  box-shadow: 0 8px 40px rgba(0,0,0,0.8);
  overflow: hidden;
}
.go-scene {
  width: 100%;
  border-bottom: 2px solid var(--gold-2);
}
.go-scene canvas { display: block; width: 100%; height: auto; image-rendering: pixelated; }
.go-card .go-title { padding: 18px 24px 4px; }
.go-card .go-body { padding: 0 24px 16px; }
.go-card .go-actions { padding: 0 24px 22px; }
.go-title {
  color: var(--gold); font-size: 24px; font-weight: 800; letter-spacing: 4px;
  margin-bottom: 12px;
}
.go-body { color: var(--text); margin-bottom: 18px; }
.go-stats {
  display: flex;
  justify-content: center;
  gap: 18px;
  margin-top: 12px;
  font-size: 11px;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 1px;
}
.go-stats b { color: var(--gold); font-size: 16px; margin-right: 4px; }
.go-actions { display: flex; gap: 8px; justify-content: center; }

/* Memorial scroll on the game-over modal — lists the names of dwellers lost
   on this run. Reads like a roll call, not a stat. */
.go-cause { font-style: italic; color: var(--text); opacity: 0.92; line-height: 1.5; }
.go-memorial {
  margin-top: 18px;
  padding: 14px 18px 16px;
  border: 1px solid rgba(246, 194, 58, 0.28);
  background: linear-gradient(180deg, rgba(246, 194, 58, 0.06), rgba(0, 0, 0, 0.18));
  border-radius: 4px;
  text-align: center;
}
.go-memorial-title {
  color: var(--gold);
  letter-spacing: 4px;
  text-transform: uppercase;
  font-size: 10px;
  margin-bottom: 10px;
  opacity: 0.85;
}
.go-memorial-list {
  color: #d8c990;
  font-size: 13px;
  line-height: 1.7;
  letter-spacing: 0.5px;
}
.go-memorial-name { white-space: nowrap; }

/* Memorial modal — full roster, browsable mid-run. Tone target: a quiet
 * ledger, not a stats screen. Names left-aligned, epitaphs muted italic. */
#memorial-modal {
  position: fixed; inset: 0; z-index: 80;
  display: flex; align-items: center; justify-content: center;
  background: rgba(0, 0, 0, 0.74);
}
#memorial-modal.hidden { display: none; }
.mem-card {
  width: min(560px, 92vw);
  max-height: 78vh;
  background: var(--panel);
  border: 1px solid var(--gold-2);
  box-shadow: 0 12px 36px rgba(0, 0, 0, 0.7);
  display: flex; flex-direction: column;
  padding: 18px 22px 16px;
  gap: 10px;
}
.mem-title {
  color: var(--gold);
  letter-spacing: 6px;
  font-size: 14px;
  display: flex; justify-content: space-between; align-items: baseline;
}
.mem-progress { color: var(--muted); font-size: 11px; letter-spacing: 1px; }
.mem-sub {
  color: var(--muted);
  font-size: 11px;
  font-style: italic;
  letter-spacing: 0.5px;
  border-bottom: 1px dashed rgba(246, 194, 58, 0.20);
  padding-bottom: 8px;
}
.mem-list {
  flex: 1; overflow-y: auto;
  padding-right: 4px;
  display: flex; flex-direction: column; gap: 8px;
}
.mem-empty {
  color: var(--muted);
  font-style: italic;
  text-align: center;
  padding: 24px 0;
  letter-spacing: 0.5px;
}
.mem-row {
  display: grid;
  grid-template-columns: 18px 1fr auto;
  gap: 8px 10px;
  align-items: baseline;
  padding: 6px 8px;
  border-left: 2px solid rgba(246, 194, 58, 0.35);
  background: rgba(0, 0, 0, 0.18);
}
.mem-row .mem-mark { color: var(--gold); font-size: 13px; line-height: 1; }
.mem-row .mem-name { color: var(--text); font-weight: 700; letter-spacing: 0.5px; }
.mem-row .mem-day  { color: var(--muted); font-size: 10px; letter-spacing: 1px; }
.mem-row .mem-meta { grid-column: 2 / span 2; color: #c9bd7f; font-size: 11px; opacity: 0.85; }
.mem-row .mem-meta em { font-style: italic; color: var(--muted); }

/* Linked-pair carry-forward — when a friendship pair from an older vault
   appears on this vault's memorial, render in cool-blue (matching the
   founders'-stone palette and the inseparable-couple tether) so the visual
   language of *kept connections* reads consistently across surfaces. */
.mem-divider.mem-divider-linked {
  color: rgba(174, 186, 255, 0.85);
  border-bottom-color: rgba(174, 186, 255, 0.4);
}
.mem-row.mem-row-linked {
  border-left-color: rgba(174, 186, 255, 0.55);
  background: linear-gradient(180deg, rgba(174, 186, 255, 0.06), rgba(0, 0, 0, 0.20));
}
.mem-row.mem-row-linked .mem-mark { color: rgba(174, 186, 255, 0.95); font-size: 16px; }
.mem-row.mem-row-linked .mem-name { color: #d8e0ff; }

/* Iter 78 — lost-closer memorial row. Warm-amber tint (kin to the
   closer-trust line in the dweller panel + the bequest's voice). The
   epitaph line italicizes the regretful tone explicitly. */
.mem-row.mem-row-closer {
  border-left-color: rgba(240, 196, 110, 0.55);
  background: linear-gradient(180deg, rgba(240, 196, 110, 0.07), rgba(0, 0, 0, 0.20));
}
.mem-row.mem-row-closer .mem-mark { color: rgba(240, 196, 110, 0.95); }
.mem-row .mem-meta-closer {
  color: rgba(240, 206, 130, 0.92);
  font-style: italic;
  letter-spacing: 0.4px;
}
.mem-divider {
  color: var(--gold);
  font-size: 10px;
  letter-spacing: 4px;
  text-transform: uppercase;
  text-align: center;
  padding: 12px 0 6px;
  border-top: 1px dashed rgba(246, 194, 58, 0.30);
  margin-top: 4px;
}
.mem-divider:first-child { border-top: none; padding-top: 4px; }
.mem-actions { display: flex; justify-content: flex-end; }

/* Dweller persona block — trait + origin line in the selection panel.
   Quiet, italic, small. Sits above the numbers so the player meets the
   person first. */
.persona {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 6px 0 10px;
  margin-bottom: 8px;
  border-bottom: 1px dashed rgba(246, 194, 58, 0.18);
}
.persona-trait {
  color: var(--gold);
  font-size: 11px;
  letter-spacing: 2px;
  text-transform: uppercase;
  opacity: 0.88;
}
.persona-origin {
  color: var(--text);
  font-size: 12px;
  font-style: italic;
  opacity: 0.78;
  line-height: 1.4;
}
.persona-friend {
  color: rgba(174, 186, 255, 0.85);
  font-size: 11px;
  letter-spacing: 0.3px;
  opacity: 0.92;
  margin-top: 2px;
}
.persona-friend-label {
  text-transform: uppercase;
  letter-spacing: 1.5px;
  font-size: 9px;
  opacity: 0.65;
  margin-right: 4px;
}

/* Linked-pair epitaph in panel (iter 57) — when a dweller is half of a
   carried-forward linked pair AND the other half is alive in this vault,
   surface that recognition. Slightly larger and more weighted than the
   "Closest" line because it's a rare cross-vault inheritance moment. */
.persona-linked {
  color: rgba(195, 205, 255, 0.95);
  font-size: 11px;
  letter-spacing: 0.3px;
  opacity: 0.95;
  margin-top: 4px;
  padding-top: 4px;
  border-top: 1px dashed rgba(174, 186, 255, 0.35);
  display: block;
}
.persona-linked-label {
  text-transform: uppercase;
  letter-spacing: 2px;
  font-size: 9px;
  color: rgba(174, 186, 255, 0.95);
  margin-right: 5px;
}
.persona-linked-name { font-style: italic; }

/* Mourned hours (iter 64) — small line acknowledging how long the dweller
   has tended the Memorial Wall. Soft amber-gold; reads as a measurable
   role, not a stat. */
.persona-mourned {
  color: rgba(216, 201, 144, 0.92);
  font-size: 11px;
  letter-spacing: 0.3px;
  opacity: 0.92;
  margin-top: 3px;
  display: block;
}
.persona-mourned-label {
  text-transform: uppercase;
  letter-spacing: 2px;
  font-size: 9px;
  color: rgba(246, 194, 58, 0.85);
  margin-right: 5px;
}
.persona-mourned-time { font-style: italic; }

/* Quiet-trait silence indicator (iter 64) — when a quiet dweller is in
   a silent night (iter 63's 30% skip), the panel acknowledges it. Muted
   slate-blue palette so it reads as *withheld speech*, not stat. */
.persona-silence {
  color: rgba(180, 190, 220, 0.85);
  font-size: 11px;
  letter-spacing: 0.3px;
  opacity: 0.85;
  margin-top: 3px;
  display: block;
}
.persona-silence-label {
  text-transform: uppercase;
  letter-spacing: 2px;
  font-size: 9px;
  color: rgba(174, 186, 255, 0.75);
  margin-right: 5px;
}
.persona-silence-text { font-style: italic; }

/* Iter 77 — closer-trust line on the dweller panel. The Overseer's
   trusted-candidate for the bequest closer earns a quiet acknowledgment
   here. Warm-amber palette (kin to the bequest itself), slightly more
   weight than silence (this is about *active trust*, not just practice). */
.persona-closer {
  color: rgba(232, 210, 168, 0.88);
  font-size: 11px;
  letter-spacing: 0.3px;
  opacity: 0.9;
  margin-top: 3px;
  display: block;
}
.persona-closer-label {
  text-transform: uppercase;
  letter-spacing: 2px;
  font-size: 9px;
  color: rgba(240, 196, 110, 0.85);
  margin-right: 5px;
}
.persona-closer-text { font-style: italic; }

/* Iter 79 — wall-watcher recognition line. Same warm-amber as the
   closer-trust line (kin to the bequest voice). When both lines fire
   on the same dweller, they stack cleanly. */
.persona-watcher {
  color: rgba(232, 210, 168, 0.88);
  font-size: 11px;
  letter-spacing: 0.3px;
  opacity: 0.9;
  margin-top: 3px;
  display: block;
}
.persona-watcher-label {
  text-transform: uppercase;
  letter-spacing: 2px;
  font-size: 9px;
  color: rgba(240, 196, 110, 0.85);
  margin-right: 5px;
}
.persona-watcher-text { font-style: italic; }

/* Iter 79 — aftermath line. Cool-blue (kin to bereavement / silence)
   because this is *grief about replaced trust*, not a recognition of
   the new dweller themselves. The label is the lost one's name; the
   text describes what the Overseer is doing. */
.persona-aftermath {
  color: rgba(180, 190, 220, 0.85);
  font-size: 11px;
  letter-spacing: 0.3px;
  opacity: 0.88;
  margin-top: 3px;
  display: block;
}
.persona-aftermath-label {
  text-transform: uppercase;
  letter-spacing: 2px;
  font-size: 9px;
  color: rgba(174, 186, 255, 0.75);
  margin-right: 5px;
}
.persona-aftermath-text { font-style: italic; }

/* Iter 79 — yawn-count tally. Single-line "N mornings here" badge. Very
   quiet — small, muted, kin to the arrived-line. Reads as ambient
   biographical texture. */
.persona-yawn {
  color: rgba(180, 178, 168, 0.7);
  font-size: 10px;
  letter-spacing: 0.4px;
  opacity: 0.85;
  margin-top: 2px;
  display: block;
  font-style: italic;
}

/* Iter 80 — trait-shaped cross-vault cairn reaction line. The current
   trusted dweller responds to the inherited grave in their own voice.
   Cool-blue palette (kin to silence + bereavement) — this is a
   *grieving* register, not a celebratory one. The from-line attributes
   the voice. */
.cairn-reaction {
  margin-top: 8px;
  padding: 8px 10px;
  border-left: 2px solid rgba(174, 186, 255, 0.40);
  background: linear-gradient(180deg, rgba(174, 186, 255, 0.05), rgba(0, 0, 0, 0.16));
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 5px;
  font-size: 12px;
}
.cairn-reaction-mark {
  color: rgba(174, 186, 255, 0.75);
  font-size: 14px;
  line-height: 1;
}
.cairn-reaction-text {
  color: rgba(216, 220, 255, 0.92);
  font-style: italic;
  line-height: 1.45;
}
.cairn-reaction-from {
  color: rgba(174, 186, 255, 0.65);
  font-size: 10px;
  letter-spacing: 0.4px;
  margin-left: auto;
}

/* Iter 74 — silence-night tally on the Memorial Wall panel. Same shape
   as the memorial scroll but cool-blue palette, distinct from the
   gold-amber loss list. Wall as accumulator of practices alongside
   accumulator of names. */
.mem-wall-silence {
  margin-top: 12px;
  border-left: 2px solid rgba(174, 186, 255, 0.45);
  background: linear-gradient(180deg, rgba(174, 186, 255, 0.06), rgba(0, 0, 0, 0.18));
}
.mem-wall-silence .mem-wall-title { color: rgba(174, 186, 255, 0.9); }
.mem-wall-silence-row .mem-wall-name { color: rgba(216, 220, 255, 0.92); }
.mem-wall-silence-row .mem-wall-trait {
  color: rgba(174, 186, 255, 0.7);
  font-style: italic;
}

/* Iter 76 — wall-keeper longevity. The dweller in the vault longest who
   has stood at the wall. Warm-amber palette this time (kin to the
   gold-amber memorial scroll, not the silence-blue) because *tenure*
   is closer to the wall's memorial register than to its quiet register. */
.mem-wall-watcher {
  margin-top: 10px;
  border-left: 2px solid rgba(240, 196, 110, 0.45);
  background: linear-gradient(180deg, rgba(240, 196, 110, 0.05), rgba(0, 0, 0, 0.16));
}
.mem-wall-watcher .mem-wall-title { color: rgba(240, 206, 130, 0.88); }
.mem-wall-watcher-row .mem-wall-name { color: rgba(250, 232, 200, 0.95); }
.mem-wall-watcher-row .mem-wall-trait {
  color: rgba(240, 196, 110, 0.72);
  font-style: italic;
}

/* Iter 82 — "Still Carrying" block on the Memorial Wall. Surfaces the
   living dwellers actively grieving the lost closer-candidate. Deeper
   blue than the silence block — bereavement is louder than vigil.
   Border + tint shift the wall scroll into a third emotional register
   (gold = loss, blue-light = silence-practice, blue-deep = active grief). */
.mem-wall-bereaved {
  margin-top: 12px;
  border-left: 2px solid rgba(140, 156, 224, 0.55);
  background: linear-gradient(180deg, rgba(140, 156, 224, 0.09), rgba(0, 0, 0, 0.20));
}
.mem-wall-bereaved .mem-wall-title { color: rgba(140, 156, 224, 0.95); }
.mem-wall-bereaved-row .mem-wall-name { color: rgba(204, 212, 248, 0.95); }
.mem-wall-bereaved-row .mem-wall-trait {
  color: rgba(140, 156, 224, 0.75);
  font-style: italic;
}

/* Iter 83: clickable friend name navigates the selection to them.
 * Subtle underline-on-hover so the affordance reads without competing
 * with the persona block's quiet weight. */
.persona-friend-name {
  cursor: pointer;
  text-decoration: none;
  border-bottom: 1px dotted transparent;
  transition: border-color 0.15s ease, color 0.15s ease;
}
.persona-friend-name:hover {
  color: #c8d4ff;
  border-bottom-color: rgba(174, 186, 255, 0.6);
}
/* Iter 95: friendship duration suffix — sits to the right of the
 * friend name in a muted color so it reads as the time investment
 * (1.4h, 23m) without competing with the name itself. */
.persona-friend-dur {
  color: var(--muted);
  font-size: 10px;
  letter-spacing: 0.5px;
  margin-left: 2px;
}
/* Iter 105: "joined Day N · N days in vault" line. Muted, sits under
 * the trait + origin so the temporal weight reads quietly without
 * pulling focus from the personality lines. */
.persona-arrived {
  color: var(--muted);
  font-size: 10px;
  letter-spacing: 0.5px;
  margin-top: 2px;
}
/* Iter 110: cohort glyph (📻 for radio, ⚓ for founder). Slightly
 * brighter than the muted arrived line so the badge reads as a
 * marker, not a continuation of the timeline. Hovers for title text. */
.persona-cohort {
  color: var(--text);
  opacity: 0.85;
  font-size: 11px;
  cursor: help;
}

/* Crisis line — a trait-shaped reaction the dweller is having to the vault's
   current shortage. Only renders while food or water is in the bottom 15%
   of cap. Tone: italic, muted, weighted. Not a stat. A voice. */
.crisis-line {
  display: flex;
  gap: 8px;
  align-items: baseline;
  padding: 8px 10px 10px;
  margin-bottom: 10px;
  border-left: 2px solid var(--red);
  background: linear-gradient(180deg, rgba(211, 84, 84, 0.10), rgba(0, 0, 0, 0.18));
  border-radius: 2px;
}
.crisis-mark {
  color: var(--red);
  font-size: 14px;
  line-height: 1;
  letter-spacing: 1px;
}
.crisis-text {
  color: var(--text);
  font-style: italic;
  font-size: 12px;
  line-height: 1.45;
  opacity: 0.92;
}

/* Bereavement variant — quieter than crisis. Cool-blue accent (matches the
   founder's-stone palette so the language of loss reads consistently), no
   red. Fires for 3 in-game days after a close friend dies. */
.crisis-line.bereaved {
  border-left-color: rgba(174, 186, 255, 0.55);
  background: linear-gradient(180deg, rgba(174, 186, 255, 0.06), rgba(0, 0, 0, 0.18));
}
.crisis-line.bereaved .crisis-mark { color: rgba(174, 186, 255, 0.9); }
.crisis-line.bereaved .crisis-text { opacity: 0.85; }

/* Brief moment-of-silence on dweller death. Renderer sets body.silence for
   ~1.6s; visual chrome dims gently, then returns. Subtle on purpose. */
body.silence #game {
  filter: saturate(0.6) brightness(0.88);
  transition: filter 0.45s ease-out;
}
body.silence #hud,
body.silence #log-feed,
body.silence #toast-stack { opacity: 0.55; transition: opacity 0.45s ease-out; }

/* Opening cinematic — first-frame fade-in beat between title-splash dismissal
   and game chrome. Black veil holds for ~0.9s with a single caption line
   fading in, then the veil clears over 1.5s while the caption holds, then
   the caption itself fades. The whole beat is ~3s of held atmosphere. */
#open-cinematic {
  position: fixed; inset: 0; z-index: 90;
  background: #000;
  opacity: 1;
  pointer-events: none;
  transition: opacity 1.5s ease-out;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  padding-bottom: 18vh;
}
#open-cinematic.clearing { opacity: 0; }
.oc-caption {
  color: var(--gold);
  font-family: "Georgia", "Iowan Old Style", serif;
  font-size: 17px;
  font-style: italic;
  letter-spacing: 0.5px;
  text-shadow: 0 1px 0 rgba(0, 0, 0, 0.85);
  opacity: 0;
  transition: opacity 0.9s ease-out;
  text-align: center;
  max-width: 80vw;
}
#open-cinematic.show .oc-caption { opacity: 0.95; }
#open-cinematic.caption-fade .oc-caption { opacity: 0; transition: opacity 0.6s ease-in; }

/* Memorial Wall — inline name scroll inside the room selection panel. Same
   tone as the modal but compact. The wall is the player's own monument, not
   a system list. */
.mem-wall-scroll {
  margin-top: 10px;
  padding: 10px 12px 12px;
  border: 1px solid rgba(246, 194, 58, 0.22);
  background: linear-gradient(180deg, rgba(246, 194, 58, 0.04), rgba(0, 0, 0, 0.22));
  border-radius: 2px;
}
.mem-wall-title {
  color: var(--gold);
  letter-spacing: 3px;
  text-transform: uppercase;
  font-size: 10px;
  margin-bottom: 8px;
  opacity: 0.88;
}
.mem-wall-list {
  display: flex; flex-direction: column; gap: 2px;
  max-height: 220px; overflow-y: auto;
}
.mem-wall-row {
  display: flex; justify-content: space-between; align-items: baseline;
  padding: 3px 2px;
  border-bottom: 1px solid rgba(246, 194, 58, 0.06);
}
.mem-wall-name { color: #d8c990; font-size: 12px; letter-spacing: 0.5px; }
.mem-wall-trait {
  color: var(--muted); font-size: 10px; font-style: italic;
  letter-spacing: 1px; text-transform: lowercase;
}
.mem-wall-empty {
  margin-top: 10px;
  padding: 14px;
  text-align: center;
  font-style: italic;
  color: var(--muted);
  letter-spacing: 0.5px;
  border: 1px dashed rgba(246, 194, 58, 0.18);
}

/* Overseer's Notebook modal — pages from the previous Overseer. Reads like
   a notebook: pale page color, indented handwriting, generous line height.
   This is the lore-discovery surface. Tone matters more than chrome. */
#journal-modal {
  position: fixed; inset: 0; z-index: 80;
  display: flex; align-items: center; justify-content: center;
  background: rgba(0, 0, 0, 0.78);
}
#journal-modal.hidden { display: none; }
.jrn-card {
  width: min(620px, 92vw);
  max-height: 80vh;
  background: linear-gradient(180deg, #1a1610 0%, #14110a 100%);
  border: 1px solid var(--gold-2);
  box-shadow: 0 16px 44px rgba(0, 0, 0, 0.78);
  display: flex; flex-direction: column;
  padding: 18px 24px 16px;
  gap: 10px;
}
.jrn-title {
  color: var(--gold); letter-spacing: 6px; font-size: 14px;
  text-align: center;
}
.jrn-sub {
  color: var(--muted); font-size: 11px; font-style: italic;
  letter-spacing: 0.5px; text-align: center;
  border-bottom: 1px dashed rgba(246, 194, 58, 0.22);
  padding-bottom: 10px;
}
.jrn-list {
  flex: 1; overflow-y: auto;
  padding: 4px 10px 4px 4px;
  display: flex; flex-direction: column; gap: 18px;
  background:
    repeating-linear-gradient(180deg, transparent 0 22px, rgba(246, 194, 58, 0.05) 22px 23px);
}
.jrn-entry {
  display: flex; flex-direction: column; gap: 4px;
  padding: 6px 12px 10px 14px;
  border-left: 3px solid rgba(246, 194, 58, 0.45);
}
.jrn-day {
  color: var(--gold); font-size: 10px; letter-spacing: 3px;
  text-transform: uppercase; opacity: 0.78;
}
.jrn-text {
  color: #e3d7a7;
  font-family: "Georgia", "Iowan Old Style", serif;
  font-size: 14px;
  line-height: 1.55;
  letter-spacing: 0.2px;
  font-style: italic;
}
.jrn-actions { display: flex; justify-content: flex-end; padding-top: 8px; }

/* Bequest preview mode (iter 65) — when the journal modal is opened via
   "Preview your bequest", a small banner across the top signals that
   what the player is reading is a *draft*, not a final notebook. The
   underlying journal modal styling is unchanged; this is a visual
   reminder, not a structural rebuild. */
.jrn-card.jrn-preview::before {
  content: "PREVIEW — this is what your vault would leave behind now";
  display: block;
  margin: -18px -24px 10px;
  padding: 8px 24px;
  background: linear-gradient(180deg, rgba(174, 186, 255, 0.18), rgba(174, 186, 255, 0.06));
  color: rgba(174, 186, 255, 0.95);
  font-size: 10px;
  letter-spacing: 4px;
  text-transform: uppercase;
  text-align: center;
  border-bottom: 1px dashed rgba(174, 186, 255, 0.45);
}

/* Bequest-growing pulse (iter 68) — when the Memorial Wall's Preview
   button has new lore the player hasn't seen since their last preview,
   the button breathes a soft amber glow. Subtle, no animation longer
   than 1.5s per cycle so it doesn't compete with gameplay urgency. */
.bequest-grown {
  animation: bequestGrowBreath 1.5s ease-in-out infinite;
  box-shadow: 0 0 0 1px rgba(246, 194, 58, 0.35);
}
@keyframes bequestGrowBreath {
  0%, 100% { box-shadow: 0 0 0 1px rgba(246, 194, 58, 0.20); }
  50%      { box-shadow: 0 0 10px 2px rgba(246, 194, 58, 0.55); }
}

/* Section divider for the journal modal — used when both the canonical
   Old Overseer's entries and the player's bequeathed Founder's Stone
   entries are present. Two voices, two hands. */
.jrn-section {
  margin: 8px 0 4px;
  padding: 10px 14px 8px;
  border-bottom: 1px dashed rgba(246, 194, 58, 0.30);
}
.jrn-section-title {
  color: var(--gold);
  font-size: 11px;
  letter-spacing: 4px;
  text-transform: uppercase;
  opacity: 0.9;
}
.jrn-section-sub {
  color: var(--muted);
  font-size: 11px;
  font-style: italic;
  letter-spacing: 0.5px;
  margin-top: 2px;
}
/* Founder's Stone entries — same shape as the canonical entries but with a
   cooler border-tone so the player feels the change of hand. */
.jrn-entry-founder { border-left-color: rgba(174, 186, 255, 0.55); }

/* Older generations of founders' journals — runs from earlier than the
   most recent one. Dimmer text + dustier border so deeper history reads
   as further away in time. The journal is a stack of voices fading into
   older runs. */
.jrn-entry-older { border-left-color: rgba(174, 186, 255, 0.30); }
.jrn-entry-older .jrn-text { opacity: 0.78; }
.jrn-entry-older .jrn-day { opacity: 0.6; }

/* Game-over generation stamp — appears under the vault-fell title for any
   player on their second or later vault. Renders the lineage in Roman
   numerals so it reads as a chronicle, not a save-slot number. */
.go-generation {
  color: rgba(174, 186, 255, 0.85);
  font-size: 11px;
  letter-spacing: 6px;
  text-transform: uppercase;
  margin: 0 24px 14px;
  padding-bottom: 8px;
  border-bottom: 1px dashed rgba(174, 186, 255, 0.25);
  text-align: center;
}

/* First-death gentle reveal — a one-time pulse on the Memorial HUD button
   the first time a player ever loses a dweller. Auto-removed after 6s.
   Tone: a held breath, not a notification — soft amber bloom that grows
   and recedes rather than blinking. */
.hint-pulse {
  animation: hintBreath 1.8s ease-in-out infinite;
  box-shadow: 0 0 0 2px rgba(246, 194, 58, 0.45);
}
@keyframes hintBreath {
  0%, 100% { box-shadow: 0 0 0 0 rgba(246, 194, 58, 0); }
  50%      { box-shadow: 0 0 14px 4px rgba(246, 194, 58, 0.55); }
}
