/* Extracted verbatim from steam_rolled_foundation.html — lines 8–1423 */

/* ── Reset & Base ──────────────────────────────── */
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
  background: #0c0a07;
  color: #d4c5a0;
  font-family: Georgia, serif;
  height: 100vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  font-size: 14px;
}

/* ── Header ──────────────────────────────────── */
#hdr {
  background: #14110d;
  border-bottom: 2px solid #c8a44c;
  padding: 8px 16px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-shrink: 0;
}
#hdr h1 { font-size: 1.3rem; color: #c8a44c; letter-spacing: .2em; font-variant: small-caps; }
#hdr .sub { font-size: .7rem; color: #7a6a50; }

/* ── Layout ──────────────────────────────────── */
#main { display: flex; flex: 1; overflow: hidden; }

/* ── Board column ─────────────────────────────── */
#board-col {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 16px;
  overflow: hidden;
}
#board-wrap {
  background: #0a0805;
  border: 2px solid #8a6820;
  padding: 6px;
  box-shadow: 0 0 28px rgba(120,90,20,.25), inset 0 0 12px rgba(0,0,0,.4);
  /* The frame is a window onto the table. It fills the column rather than
     shrink-wrapping the grid, so the board has room to be panned and zoomed
     into — which is the whole point of it being a window. */
  position: relative;
  overflow: hidden;
  touch-action: none;
  cursor: grab;
  flex: 1;
  align-self: stretch;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 0;
  /* A ceiling so the window cannot become a letterbox. In the stacked layout
     the column spans the full width and the frame would otherwise stretch to
     ~1350px around a 508px board -- a lot of empty felt either side. The row
     layout wants roughly 780px at 1900px wide, comfortably under this. */
  max-width: 900px;
}
#board-wrap.is-panning { cursor: grabbing; }
#board {
  display: grid;
  grid-template-columns: repeat(7, 70px);
  grid-template-rows: repeat(7, 70px);
  gap: 3px;
  /* State lives in these custom properties, on the container. renderBoard
     clears with innerHTML = '' which replaces children only, so the view
     survives every re-render with nothing to keep in sync. */
  transform: scale(var(--board-zoom, 1))
             translate(var(--board-x, 0px), var(--board-y, 0px));
  transform-origin: 50% 50%;
  will-change: transform;
}

/* Board view controls — bottom-right of the frame, over the felt. */
#bv-controls {
  position: absolute;
  right: 8px; bottom: 8px;
  display: flex; gap: 3px;
  z-index: 20;
}
#bv-controls button {
  width: 22px; height: 22px;
  display: flex; align-items: center; justify-content: center;
  font: 700 13px/1 'Archivo Narrow', 'Arial Narrow', sans-serif;
  color: #c8a44c;
  background: rgba(12,10,6,.82);
  border: 1px solid #5b4930;
  border-radius: 3px;
  cursor: pointer;
  transition: color .12s, border-color .12s, background .12s;
}
#bv-controls button:hover { color: #f0d48a; border-color: #8a6820; background: rgba(24,19,11,.92); }
#bv-controls button:focus-visible { outline: 2px solid #c8a44c; outline-offset: 1px; }
#bv-controls button[aria-disabled="true"] { opacity: .38; cursor: default; }

/* ── Tiles ─────────────────────────────────────── */
.tile {
  width: 70px;
  height: 70px;
  border: 2px solid #1c1408;
  border-radius: 2px;
  cursor: pointer;
  display: flex;
  flex-direction: row;
  align-items: stretch;
  padding: 0;
  position: relative;
  user-select: none;
  transition: filter .1s, transform .08s;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.45), inset 0 -2px 3px rgba(0,0,0,.22);
  overflow: hidden;
}
.tile:hover {
  filter: brightness(1.22);
  transform: scale(1.06);
  z-index: 5;
}

/* ── Medallion ─────────────────────────────────────────────────────────────
   The approved face art, circular-cropped. The crop lives on the WRAPPER, not
   on the image: clip-path on the image clips the image's own box-shadow too,
   so a ring drawn there is invisible. The brass ring matters most on parchment,
   where the ivory disc measures only 1.6:1 against the ground and the ring is
   the only thing giving it an edge; on the dark locus grounds the disc is
   already at ~17:1 and the ring is decoration.
   48px is the ceiling on a 70px tile: the centre column is 52px tall once the
   old range/average band is gone, but only 49px wide after the two 9% side
   slots.                                                          ───────── */
.tile-med {
  width: 48px;
  height: 48px;
  border-radius: 50%;
  overflow: hidden;
  display: block;
  flex: none;
  line-height: 0;
  box-shadow: 0 0 0 2px #9a6c15, 0 1px 3px rgba(0,0,0,.5);
}
.tile-med img { display: block; width: 100%; height: 100%; }

/* ── Locus mark ────────────────────────────────────────────────────────────
   Which of the seven loci a die belongs to, carried WITHOUT spending a colour.
   The Loci Canon lists the seven locus colours under Preserved Open Design
   Space, so nothing here assigns one; the mark is shape only.
   Brass, matching the medallion rim, because it is the only value that works on
   both grounds: dark ink measures 1.1:1 on the locus tiles and pale ink 1.3:1
   on parchment, while brass holds 2.6-4.2:1 everywhere.       ───────── */
.tile-locus {
  position: absolute;
  top: -3px; right: -3px;
  width: 15px; height: 15px;
  color: #9a6c15;
  pointer-events: none;
  z-index: 4;
}
.tile-locus svg { display: block; width: 100%; height: 100%; }

/* ── Status marks ──────────────────────────────────────────────────────────
   Three marks, each carrying exactly one meaning. A single badge tinted four
   ways would have made one element mean four things, which the Visual Identity
   Canon forbids outright.
     blocking  — something here stops you acting
     contested — a claim or contest over the coordinate
     built     — TEMPORARY, until structures get their own board tokens
   Every one carries its descriptors in a native title, one per line. */
.tile-status-chip,
.tile-status-mark {
  position: absolute;
  min-width: 13px; height: 13px;
  display: flex; align-items: center; justify-content: center;
  font-family: 'Archivo Narrow', 'Arial Narrow', sans-serif;
  font-size: 8px; font-weight: 800; line-height: 1;
  color: #f6eeda; cursor: help; z-index: 5;
  box-shadow: 0 0 0 1px rgba(0,0,0,.55), 0 1px 2px rgba(0,0,0,.5);
}
.tile-status-chip { padding: 0 2px; border-radius: 3px; }
.tile-status-mark { width: 13px; border-radius: 50%; }

/* Two marks describing the TILE, never the reader — the board is shared, so a
   mark that flips with the turn inverts the whole screen at End Turn. Polarity
   is fixed to the tile; whose it is rides on the accent below. */
.mark-impaired { bottom: 2px; left: 2px; background: #5a4a44; }
/* Blocking is not a third mark; it tints this one, so "you cannot act here"
   still reads at a glance without costing another position. */
.mark-impaired.is-blocking { background: #9c3326; }
.mark-enhanced { top: 2px;    left: 2px; background: #4b7f3a; }

/* Whose, in the colours the board already uses for ownership everywhere else.
   A ring rather than a fill, so the mark's own colour keeps saying what the
   status IS while the ring says who it belongs to — two systems, still separate. */
.tile-status-mark.owner-pd { box-shadow: 0 0 0 1.5px #c0392b, 0 1px 2px rgba(0,0,0,.6); }
.tile-status-mark.owner-sm { box-shadow: 0 0 0 1.5px #2980b9, 0 1px 2px rgba(0,0,0,.6); }
/* Track and rail spurs only -- laid rather than standing, and without art.
   Top-centre, because a Rail Town stands on track and the structure token owns
   bottom-centre. */
.chip-built      { top: 2px; left: 50%; transform: translateX(-50%); background: #7a5a12; }

/* ── Terrain backgrounds — uniform antique parchment map surface ───────────
   All normal terrain shares one base color.
   Terrain identity = glyph + label, not tile color.              ───────── */
.terrain-ironPeaks,
.terrain-timberStands,
.terrain-reservoir,
.terrain-peatBogs,
.terrain-ashFlats     {
  background-color: #cfc2a3;
  background-image: linear-gradient(155deg, rgba(255,255,255,.30) 0%, transparent 48%, rgba(80,60,30,.18) 100%);
}
/* Wasteland — scarred parchment, darker map section, heavier ink border */
.terrain-neutralWasteland {
  background-color: #b5ab96;
  background-image: linear-gradient(155deg, rgba(255,255,255,.12) 0%, transparent 40%, rgba(50,35,15,.28) 100%);
  border-color: #160e04;
  border-width: 3px;
}
/* Wildflower Field (EVID-0117) — a planted, cultivated tile. Deliberately its
   own colour rather than the shared ordinary-terrain parchment: it is the one
   terrain a player MAKES, it is always owned, and a board where it read as
   generic land would hide the single most contested tile on it. Keeps the
   ordinary 2px border (it is not scarred ground like Wasteland). */
.terrain-wildflowerField {
  background-color: #c8cda0;
  background-image:
    radial-gradient(circle at 28% 34%, rgba(255,232,120,.55) 0 2px, transparent 2.5px),
    radial-gradient(circle at 68% 24%, rgba(238,170,205,.50) 0 2px, transparent 2.5px),
    radial-gradient(circle at 44% 70%, rgba(255,232,120,.45) 0 2px, transparent 2.5px),
    radial-gradient(circle at 76% 66%, rgba(200,170,240,.45) 0 2px, transparent 2.5px),
    linear-gradient(155deg, rgba(255,255,255,.32) 0%, transparent 48%, rgba(60,80,30,.22) 100%);
}
/* A tapped field is visibly spent — the same reading the `committed` state gets
   elsewhere, stated on the tile because this field is a resource a player plans
   a whole turn around. */
.terrain-wildflowerField.tile-committed { filter: saturate(.45) brightness(.88); }

/* Captain — warm parchment, slightly more golden to distinguish command tiles */
.terrain-captain { background-color: #d4c898; background-image: linear-gradient(155deg, rgba(255,255,255,.32) 0%, transparent 48%, rgba(80,55,10,.22) 100%); }
/* Custom dice — dark material pieces sitting on the map */
.terrain-railroad    { background-color: #100c04; background-image: linear-gradient(145deg, rgba(200,130,20,.12) 0%, transparent 55%, rgba(0,0,0,.38) 100%); border-color: #4a2e08; }
.terrain-cultivation { background-color: #0d1a08; background-image: linear-gradient(145deg, rgba(120,200,60,.12) 0%, transparent 55%, rgba(0,0,0,.28) 100%); border-color: #2a5010; }

/* ── Railroad tile frame — brassy orange / hot-coal (extraction identity) ── */
.tile-railroad {
  border-color: #7a4a10;
  box-shadow: 0 0 7px 2px rgba(200,120,30,.50), inset 0 1px 0 rgba(240,180,60,.10), inset 0 -2px 4px rgba(0,0,0,.50);
}
.tile-railroad .tile-slot-l { background: rgba(190,110,20,.18); border-right-color: rgba(210,140,40,.20); }
.tile-railroad .tile-slot-r { background: rgba(190,110,20,.18); border-left-color:  rgba(210,140,40,.20); }
.tile-railroad .tile-type-letter { color: #e09040; font-size: .5rem; letter-spacing: .04em; text-shadow: 0 2px 6px rgba(0,0,0,.85), 0 0 10px rgba(200,120,20,.5); }
.tile-railroad .tile-range-val   { color: #c07828; text-shadow: 0 1px 3px rgba(0,0,0,.9); }
.tile-railroad .tile-avg-val     { color: #c07828; text-shadow: 0 1px 3px rgba(0,0,0,.9); }
.tile-rail-dir {
  position: absolute; bottom: 2px; right: 4px;
  font-size: .75rem; color: #e09040; text-shadow: 0 0 4px rgba(200,120,20,.7);
  pointer-events: none;
}

/* ── Cultivation tile frame — earthy leaf-green ─────────────────────────── */
.tile-cultivation {
  border-color: #3a6020;
  box-shadow: 0 0 6px 1px rgba(80,180,40,.30), inset 0 1px 0 rgba(120,200,60,.08), inset 0 -2px 4px rgba(0,0,0,.42);
}
.tile-cultivation .tile-slot-l { background: rgba(80,160,40,.10); border-right-color: rgba(100,180,60,.15); }
.tile-cultivation .tile-slot-r { background: rgba(80,160,40,.10); border-left-color:  rgba(100,180,60,.15); }
.tile-cultivation .tile-type-letter { color: #90d050; font-size: .5rem; letter-spacing: .04em; text-shadow: 0 2px 6px rgba(0,0,0,.85), 0 0 10px rgba(80,200,40,.4); }
.tile-cultivation .tile-range-val   { color: #70b040; text-shadow: 0 1px 3px rgba(0,0,0,.9); }
.tile-cultivation .tile-avg-val     { color: #70b040; text-shadow: 0 1px 3px rgba(0,0,0,.9); }

/* ── Preservation tile frame — muted violet to match faction identity ────── */
.terrain-preservation {
  background-color: #100818;
  background-image: linear-gradient(145deg, rgba(160,100,220,.10) 0%, transparent 55%, rgba(0,0,0,.30) 100%);
  border-color: #3a1e5a;
}
.tile-preservation {
  border-color: #6040a0;
  box-shadow: 0 0 6px 1px rgba(120,60,200,.35), inset 0 1px 0 rgba(180,120,255,.08), inset 0 -2px 4px rgba(0,0,0,.42);
}
.tile-preservation .tile-slot-l { background: rgba(120,60,200,.10); border-right-color: rgba(160,80,220,.15); }
.tile-preservation .tile-slot-r { background: rgba(120,60,200,.10); border-left-color:  rgba(160,80,220,.15); }
.tile-preservation .tile-type-letter { color: #c090f0; font-size: .5rem; letter-spacing: .04em; text-shadow: 0 2px 6px rgba(0,0,0,.85), 0 0 10px rgba(120,60,200,.4); }
.tile-preservation .tile-range-val   { color: #9060c0; text-shadow: 0 1px 3px rgba(0,0,0,.9); }
.tile-preservation .tile-avg-val     { color: #9060c0; text-shadow: 0 1px 3px rgba(0,0,0,.9); }

.terrain-exploration {
  background: radial-gradient(circle at 48% 38%, #294958 0%, #142d38 54%, #091820 100%);
}
.tile-exploration { border-color: rgba(91,197,210,.45); }
.tile-exploration .tile-slot-l { background: rgba(55,150,165,.10); border-right-color: rgba(91,197,210,.18); }
.tile-exploration .tile-slot-r { background: rgba(55,150,165,.10); border-left-color: rgba(91,197,210,.18); }
.tile-exploration .tile-type-letter { color: #9de8e8; font-size: .5rem; letter-spacing: .04em; text-shadow: 0 2px 6px rgba(0,0,0,.85), 0 0 10px rgba(55,180,190,.45); }
.tile-exploration .tile-range-val, .tile-exploration .tile-avg-val { color: #70bdc5; text-shadow: 0 1px 3px rgba(0,0,0,.9); }
.tier-exploration { border-color: #4d9ba7; }

/* Mutation: presentation colour only, not a locus-colour ruling. */
.terrain-mutation {
  background: radial-gradient(circle at 48% 38%, #3f4a1c 0%, #262e10 54%, #141a07 100%);
}
.tile-mutation { border-color: rgba(170,200,70,.45); }
.tile-mutation .tile-slot-l { background: rgba(140,170,50,.10); border-right-color: rgba(170,200,70,.18); }
.tile-mutation .tile-slot-r { background: rgba(140,170,50,.10); border-left-color: rgba(170,200,70,.18); }
.tile-mutation .tile-type-letter { color: #d6ec8a; font-size: .5rem; letter-spacing: .04em; text-shadow: 0 2px 6px rgba(0,0,0,.85), 0 0 10px rgba(160,190,60,.45); }
.tile-mutation .tile-range-val, .tile-mutation .tile-avg-val { color: #a9c25a; text-shadow: 0 1px 3px rgba(0,0,0,.9); }
.tier-mutation { border-color: #8fa83a; }

/* ── Test Die tile — high-contrast amber/orange to signal "temporary test tool" ── */
.terrain-testDie {
  background-color: #1e1200;
  background-image: linear-gradient(145deg, rgba(255,160,20,.14) 0%, transparent 55%, rgba(0,0,0,.32) 100%);
  border-color: #6a4010;
}
.tile-test-die {
  border-color: #c87020;
  box-shadow: 0 0 7px 1px rgba(200,112,32,.50), inset 0 1px 0 rgba(255,180,60,.10), inset 0 -2px 4px rgba(0,0,0,.42);
}
.tile-test-die .tile-slot-l { background: rgba(200,112,32,.10); border-right-color: rgba(220,140,50,.18); }
.tile-test-die .tile-slot-r { background: rgba(200,112,32,.10); border-left-color:  rgba(220,140,50,.18); }
.tile-test-die .tile-type-letter { color: #f0a030; font-size: .5rem; letter-spacing: .04em; text-shadow: 0 2px 6px rgba(0,0,0,.85), 0 0 10px rgba(200,120,20,.5); }
.tile-test-die .tile-range-val   { color: #c08020; text-shadow: 0 1px 3px rgba(0,0,0,.9); }
.tile-test-die .tile-avg-val     { color: #c08020; text-shadow: 0 1px 3px rgba(0,0,0,.9); }

/* ── Elite terrain backgrounds — darker, distinct from normal terrain ───── */
.terrain-eliteVanguard { background-color: #200a0a; background-image: linear-gradient(145deg, rgba(255,90,50,.08)  0%, transparent 55%, rgba(0,0,0,.28) 100%); }
.terrain-eliteSentinel { background-color: #081818; background-image: linear-gradient(145deg, rgba(50,200,170,.08) 0%, transparent 55%, rgba(0,0,0,.28) 100%); }
.terrain-eliteMarshal  { background-color: #1c1208; background-image: linear-gradient(145deg, rgba(255,170,30,.08) 0%, transparent 55%, rgba(0,0,0,.28) 100%); }

/* ── Elite tile frame — heavy ornamental ink frame (important map landmark) ── */
.tile-elite {
  border: 3px solid #4a3008 !important;
  box-shadow: 0 0 10px 2px rgba(120,85,15,.55), inset 0 0 0 1px rgba(200,160,50,.25), inset 0 -2px 4px rgba(0,0,0,.30);
}
.tile-elite .tile-slot-l { background: rgba(130,95,20,.22); border-right-color: rgba(180,140,40,.25); }
.tile-elite .tile-slot-r { background: rgba(130,95,20,.22); border-left-color:  rgba(180,140,40,.25); }
.tile-elite .tile-type-letter { color: #2a1e08; text-shadow: 0 1px 0 rgba(255,220,100,.5); }
.tile-elite .tile-range-val   { color: #2a1e08; text-shadow: none; }
.tile-elite .tile-avg-val     { color: #2a1e08; text-shadow: none; }
.tile-elite .tile-name-label  { color: #3a2a10; }

/* ── Ownership — border-color frame + parchment film on ALL owned tiles ────────
   Static owned (any turn): colored border + semi-transparent captain-color film
   layered over the terrain's parchment gradient. No outer glow.
   Pulse: active player's owned tiles only (see tile-active-own rules).        ── */
.own-plagueDoctor {
  background-image:
    linear-gradient(rgba(160,30,30,.22), rgba(140,20,20,.13)),
    linear-gradient(155deg, rgba(255,255,255,.25) 0%, transparent 48%, rgba(80,60,30,.15) 100%);
  border-color: #a02828;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.38), inset 0 -2px 3px rgba(0,0,0,.22);
}
.own-steamMechanic {
  background-image:
    linear-gradient(rgba(30,80,160,.22), rgba(20,60,140,.13)),
    linear-gradient(155deg, rgba(255,255,255,.25) 0%, transparent 48%, rgba(80,60,30,.15) 100%);
  border-color: #2050a0;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.38), inset 0 -2px 3px rgba(0,0,0,.22);
}
/* Active-turn pulse keyframes — border color jumps dark→bright (like gold selected border) */
@keyframes owned-pulse-pd {
  0%, 100% { border-color: #781818; }
  50%       { border-color: #ff3535; }
}
@keyframes owned-pulse-sm {
  0%, 100% { border-color: #183478; }
  50%       { border-color: #2d8fff; }
}

/* ── Board highlight states — glow/tint only, no outlines or borders ─
   Normal:  legal-claim < legal-attack < adj < selected
   Combat:  attacker < defender                                         */
.tile-legal-claim  { box-shadow: inset 0 0 0 999px rgba(74,138,74,.13), 0 0 13px 2px rgba(74,160,74,.72); }
.tile-legal-attack { box-shadow: inset 0 0 0 999px rgba(160,55,45,.13), 0 0 15px 3px rgba(200,70,50,.78); }
.tile-selected     { border: 3px solid #c8a44c !important; box-shadow: 0 0 18px 3px rgba(200,164,76,.85) !important; outline: none; }
.tile-attacker     { box-shadow: inset 0 0 0 999px rgba(232,144,26,.11), 0 0 13px 2px rgba(232,144,26,.65); }
.tile-defender     { box-shadow: inset 0 0 0 999px rgba(160,55,45,.14), 0 0 16px 3px rgba(200,60,50,.8) !important; outline: none; }

/* Hover on legal tiles: amplify glow for clear interactive feedback */
.tile-legal-claim:hover  { filter: brightness(1.3); box-shadow: 0 0 20px 5px rgba(74,160,74,.9) !important; }
.tile-legal-attack:hover { filter: brightness(1.3); box-shadow: 0 0 22px 5px rgba(210,70,50,.92) !important; }
.tile-attacker:hover     { filter: brightness(1.3); box-shadow: 0 0 20px 5px rgba(232,144,26,.85) !important; }

/* Exhausted marker — top-left corner */
.tile-exhausted::after {
  content: 'EX';
  position: absolute;
  top: 2px; left: 3px;
  font-size: 9px; font-weight: bold;
  font-family: 'Courier New', monospace;
  color: #ff6600; line-height: 1;
  text-shadow: 0 0 6px rgba(255,102,0,.8);
  z-index: 4;
}
.tile-exhausted { opacity: .68; filter: grayscale(0.55) brightness(0.72); }

/* Committed resource tile — temporarily spent industrial throughput */
.tile-committed::after {
  content: '⊛';
  position: absolute;
  top: 2px; left: 3px;
  font-size: 9px; font-weight: bold;
  color: rgba(200,140,40,.90);
  text-shadow: 0 0 5px rgba(160,100,20,.7);
  line-height: 1;
  z-index: 4;
}
.tile-committed {
  opacity: .70;
  filter: sepia(0.5) brightness(0.78);
  box-shadow: inset 0 0 9px rgba(180,120,20,.40) !important;
}

/* Committed marker on active-own tiles — needs brighter override since active background is dark */
.tile-active-own.tile-committed::after {
  color: rgba(255,200,60,1.0);
  text-shadow: 0 0 6px rgba(255,180,20,.95), 0 0 12px rgba(255,160,0,.6);
}

/* Revealed hidden-identity markers — top-right corner (::before so they stack with EX ::after) */
.tile-id-hazard::before {
  content: '⚠';
  position: absolute;
  top: 2px; right: 3px;
  font-size: 9px; color: #c04040; line-height: 1;
}
.tile-id-treasure::before {
  content: '✧';
  position: absolute;
  top: 2px; right: 3px;
  font-size: 10px; color: #c8a44c; line-height: 1;
}

/* ── Tile 4-zone layout ─────────────────────────────── */
/* Side slot channels — ink binding strips */
.tile-slot   { width: 5px; flex-shrink: 0; background: rgba(0,0,0,.30); }
.tile-slot-l { border-right: 1px solid rgba(0,0,0,.12); }
.tile-slot-r { border-left:  1px solid rgba(0,0,0,.12); }

/* Inner column fills remaining width */
.tile-inner {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  padding: 4px 2px 3px;
  min-width: 0;
}

/* Top band: range left, avg right — prominent brass */
.tile-top-band {
  width: 100%;
  display: flex;
  justify-content: space-between;
  align-items: center;
  line-height: 1;
}
.tile-range-val {
  font-size: 10px;
  font-weight: bold;
  color: #2a1e10;
  font-family: 'Courier New', monospace;
  letter-spacing: .01em;
  text-shadow: 0 1px 0 rgba(255,255,255,.5);
}
.tile-avg-val {
  font-size: 10px;
  font-weight: bold;
  color: #2a1e10;
  font-family: 'Courier New', monospace;
  letter-spacing: .01em;
  text-shadow: 0 1px 0 rgba(255,255,255,.5);
}

/* Center: dominant terrain letter or captain icon */
.tile-center {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 1;
}
.tile-type-letter {
  font-size: 30px;
  font-weight: bold;
  color: #111111;
  line-height: 1;
  letter-spacing: -.01em;
  text-shadow: 0 1px 0 rgba(255,255,255,.6), 0 1px 3px rgba(0,0,0,.12);
}

/* Bottom label: terrain name — cartographic ink label */
.tile-name-label {
  font-size: 7px;
  color: #4b3a27;
  font-family: 'Courier New', monospace;
  letter-spacing: .05em;
  text-transform: uppercase;
  line-height: 1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}

/* Owner seal dot — bottom-right corner, wax-seal sized */
.tile-owner-dot  { position: absolute; bottom: 2px; right: 6px; font-size: 11px; line-height: 1; filter: drop-shadow(0 1px 1px rgba(0,0,0,.5)); }
.tile-lock-icon  { position: absolute; top: 3px; right: 6px; font-size: 9px; line-height: 1; color: #6a4a18; opacity: .90; }

/* ── Status badge strip — compact flex row at bottom-left of tile ─────────── */
.tile-status-strip {
  position: absolute; bottom: 2px; left: 2px;
  display: flex; flex-wrap: wrap; gap: 1px;
  pointer-events: none;
  max-width: calc(100% - 14px);
}
/* Swarmed (EVID-0117). Amber-on-dark like the sabotage badge it sits beside —
   both mean "this object is temporarily inert" — but its own class, because the
   two have different causes, different durations and different clearing rules,
   and a shared class would invite one to be styled for the other. */

/* A Swarmed coordinate is dimmed and drained so it reads as inert at a glance,
   not merely badged. Applied to the tile, so it covers a Swarmed structure and a
   Swarmed die alike; the badge says WHICH object. */
.tile-swarmed {
  filter: saturate(.35) brightness(.82);
}
.tile-swarmed .tile-type-letter { opacity: .75; }

/* Owner accent — colored left border on badge (PD=red, SM=blue) */
.badge-owner-pd { border-left: 2px solid #a03030; }
.badge-owner-sm { border-left: 2px solid #2060a8; }

/* Locked attacker — glow only, no border */
.tile-locked {
  box-shadow: 0 0 10px 2px rgba(200,164,76,.5), inset 0 0 4px rgba(200,164,76,.15) !important;
}
.tile-lock-icon { font-size: 10px; }

/* ── Battle result banner — above board ─────────────── */
@keyframes bannerIn {
  from { opacity: 0; transform: scale(0.95); }
  to   { opacity: 1; transform: scale(1); }
}
#battle-banner {
  text-align: center;
  padding: 10px 20px;
  margin-bottom: 12px;
  width: 100%;
  min-height: 60px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: rgba(10,8,5,0.85);
  border: 1px solid #3a2e14;
  border-radius: 4px;
  box-shadow: 0 0 30px rgba(200,164,76,0.15);
}
#battle-banner .bn-headline {
  font-size: 1.75rem;
  font-weight: bold;
  font-variant: small-caps;
  letter-spacing: .13em;
  line-height: 1.2;
}
#battle-banner .bn-sub {
  font-size: .68rem;
  font-family: 'Courier New', monospace;
  margin-top: 4px;
  opacity: .7;
}
#battle-banner.idle .bn-headline { color: #3a2e18; font-size: .8rem; font-variant: normal; letter-spacing: .04em; font-weight: normal; }
#battle-banner.win  { animation: bannerIn 200ms ease-out forwards; box-shadow: 0 4px 28px rgba(74,160,74,.45), 0 0 50px rgba(74,160,74,.15); border-color: #3a6a3a; }
#battle-banner.lose { animation: bannerIn 200ms ease-out forwards; box-shadow: 0 4px 28px rgba(200,60,60,.45), 0 0 50px rgba(200,60,60,.15); border-color: #6a3a3a; }
#battle-banner.tie  { animation: bannerIn 200ms ease-out forwards; box-shadow: 0 4px 24px rgba(200,164,76,.35); border-color: #6a5820; }

/* ── Game-over banner states ──────────────────────── */
#battle-banner.gameover-pd,
#battle-banner.gameover-sm,
#battle-banner.gameover-draw {
  animation: bannerIn 300ms ease-out forwards;
  border-color: #c8a44c;
  box-shadow: 0 0 40px rgba(200,164,76,.3);
  padding: 14px 24px;
}
#battle-banner.gameover-pd   .bn-headline { color: #e06060; text-shadow: 0 0 24px rgba(160,40,40,.9);  font-size: 1.55rem; }
#battle-banner.gameover-sm   .bn-headline { color: #78b4e0; text-shadow: 0 0 24px rgba(41,128,185,.9); font-size: 1.55rem; }
#battle-banner.gameover-draw .bn-headline { color: #c8a44c; text-shadow: 0 0 24px rgba(200,164,76,.8); font-size: 1.55rem; }
#battle-banner.gameover-pd   .bn-sub { color: #6a3a3a; font-size: .78rem; }
#battle-banner.gameover-sm   .bn-sub { color: #4a7898; font-size: .78rem; }
#battle-banner.gameover-draw .bn-sub { color: #8a7840; font-size: .78rem; }
#battle-banner.win  .bn-headline { color: #7ab87a; text-shadow: 0 0 18px rgba(74,138,74,.85); }
#battle-banner.lose .bn-headline { color: #c07070; text-shadow: 0 0 18px rgba(180,64,64,.85); }
#battle-banner.tie  .bn-headline { color: #c8a44c; text-shadow: 0 0 18px rgba(200,164,76,.8);  }
#battle-banner.win  .bn-sub { color: #5a8a5a; }
#battle-banner.lose .bn-sub { color: #8a5a5a; }
#battle-banner.tie  .bn-sub { color: #8a7a40; }

/* ── Active player tile — ownership PULSES on the active captain's turn ──────
   Deeper tint + border-color pulse animation.
   Inactive player's tiles use the static .own-* rule above.            ──── */
.tile-active-own.own-plagueDoctor {
  background-image:
    linear-gradient(rgba(160,30,30,.28), rgba(140,20,20,.18)),
    linear-gradient(155deg, rgba(255,255,255,.22) 0%, transparent 48%, rgba(80,60,30,.12) 100%);
  animation: owned-pulse-pd 2.4s ease-in-out infinite;
}
.tile-active-own.own-steamMechanic {
  background-image:
    linear-gradient(rgba(30,80,160,.28), rgba(20,60,140,.18)),
    linear-gradient(155deg, rgba(255,255,255,.22) 0%, transparent 48%, rgba(80,60,30,.12) 100%);
  animation: owned-pulse-sm 2.4s ease-in-out infinite;
}
/* Combat attacker: pulsing orange overrides ownership on active tile */
.tile-active-own.tile-attacker {
  background-image: none;
  background-color: rgba(232,144,26,.11);
  animation: attacker-pulse 1.0s ease-in-out infinite !important;
}

/* tile-dim: class applied to non-current-player tiles by renderTile.js.
   Intentionally no visual effect — dimming neutral tiles creates a charcoal
   cross around the captain. Focus modes use tile-mode-dim (!important) instead. */
.tile-dim { }
/* Stop pulse when tile is under a strong action highlight */
.tile-selected.own-plagueDoctor,
.tile-selected.own-steamMechanic,
.tile-legal-claim.own-plagueDoctor,
.tile-legal-claim.own-steamMechanic { animation: none; }
/* Restore ownership border on selected owned tiles — tile-selected's !important gold would otherwise override */
.tile-selected.own-plagueDoctor  { border-color: #a02828 !important; }
.tile-selected.own-steamMechanic { border-color: #2050a0 !important; }

/* ── Summary panel (left) — widened for Pass 3 dashboard ─────────────── */
#summary {
  width: 268px;
  background: #14110d;
  border-right: 1px solid #4a3a1e;
  padding: 12px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  overflow-y: auto;
  flex-shrink: 0;
}
.sum-player { padding: 3px 0; }
.sum-name {
  font-size: .8rem; font-weight: bold;
  font-variant: small-caps; letter-spacing: .06em;
  margin-bottom: 5px;
}
.sum-name.pd { color: #c05050; }
.sum-name.sm { color: #5599cc; }
.sum-row {
  display: flex; justify-content: space-between;
  font-size: .72rem; padding: 1px 0;
}
.sum-k { color: #5a4a30; }
.sum-v { color: #c4b590; font-family: 'Courier New', monospace; }
.sum-terrain {
  font-size: .68rem; color: #7a6a50;
  font-family: 'Courier New', monospace;
  padding: 2px 0 1px;
}
.sum-divider { border-top: 1px solid #2a2218; margin: 5px 0; }

/* ── Right panel ──────────────────────────────── */
#right {
  width: 275px;
  background: #14110d;
  border-left: 1px solid #4a3a1e;
  padding: 12px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  overflow-y: auto;
  flex-shrink: 0;
}
.lbl {
  font-size: .65rem;
  color: #c8a44c;
  letter-spacing: .1em;
  text-transform: uppercase;
  border-bottom: 1px solid #3a2e14;
  padding-bottom: 3px;
  margin-bottom: 6px;
}

/* ── Turn panel ─────────────────────────────── */
@keyframes banner-pulse-pd {
  0%   { box-shadow: 0 0 0 rgba(160,40,40,0); }
  35%  { box-shadow: 0 0 16px 3px rgba(160,40,40,.75); }
  100% { box-shadow: 0 0 6px rgba(160,40,40,.28); }
}
@keyframes banner-pulse-sm {
  0%   { box-shadow: 0 0 0 rgba(41,128,185,0); }
  35%  { box-shadow: 0 0 16px 3px rgba(41,128,185,.75); }
  100% { box-shadow: 0 0 6px rgba(41,128,185,.28); }
}
.player-banner {
  padding: 7px 10px;
  border-radius: 3px;
  border: 1px solid;
  text-align: center;
  font-variant: small-caps;
  letter-spacing: .1em;
  font-size: 1rem;
  font-weight: bold;
}
.player-banner.pd {
  border-color: #8a3a3a; background: rgba(140,40,40,.10); color: #c05050;
  box-shadow: 0 0 6px rgba(160,40,40,.28);
}
.player-banner.sm {
  border-color: #2980b9; background: rgba(41,128,185,.1); color: #5599cc;
  box-shadow: 0 0 6px rgba(41,128,185,.28);
}
.player-banner.pulse-pd { animation: banner-pulse-pd .7s ease-out forwards; }
.player-banner.pulse-sm { animation: banner-pulse-sm .7s ease-out forwards; }

/* ── Guidance banner ──────────────────────────── */
#guidance {
  font-size: .74rem;
  color: #b8a870;
  background: rgba(200,164,76,.05);
  border: 1px solid #2e2410;
  border-radius: 3px;
  padding: 6px 8px;
  line-height: 1.5;
}

#turn-status {
  font-size: .72rem;
  color: #7a6a50;
  font-family: 'Courier New', monospace;
  text-align: center;
  padding: 4px 2px;
  line-height: 1.6;
}
#turn-status .action-avail  { color: #6a9a6a; }
#turn-status .action-used   { color: #9a6050; }

/* ── Mode banner ──────────────────────────────── */
#mode-banner {
  display: none;
  padding: 7px 10px;
  border: 1px solid #8a5020;
  background: rgba(138,80,32,.12);
  color: #d4903a;
  border-radius: 3px;
  font-size: .78rem;
  font-variant: small-caps;
  letter-spacing: .06em;
  text-align: center;
  line-height: 1.4;
}
#mode-banner.active { display: block; }
.mode-cancel-btn {
  display: inline-block;
  margin-left: 10px;
  padding: 1px 8px;
  font-size: .72rem;
  font-family: Georgia, serif;
  font-variant: small-caps;
  background: rgba(180,60,40,.18);
  border: 1px solid #a04030;
  color: #e07060;
  border-radius: 3px;
  cursor: pointer;
  vertical-align: middle;
  letter-spacing: .04em;
}
.mode-cancel-btn:hover { background: rgba(180,60,40,.35); color: #f09080; }

/* ── Detail panel ────────────────────────────── */
#detail-panel { font-size: .8rem; line-height: 1.8; color: #7a6a50; }
#detail-panel .no-sel { font-style: italic; }
.detail-row { display: flex; justify-content: space-between; gap: 8px; }
.detail-key { color: #7a6a50; flex-shrink: 0; }
.detail-val { color: #d4c5a0; text-align: right; word-break: break-all; }
.detail-val.pd  { color: #c05050; }
.detail-val.sm  { color: #5599cc; }
.detail-val.neu { color: #888; }
.detail-val.face-highlight { color: #c8a44c; font-weight: bold; font-size: 1rem; }
.faces-grid { display: flex; gap: 4px; flex-wrap: wrap; margin-top: 2px; }
.face-pip {
  width: 22px; height: 22px;
  border: 1px solid #3a2e14; border-radius: 3px;
  background: #1a1510;
  display: flex; align-items: center; justify-content: center;
  font-size: .8rem; color: #d4c5a0;
}
.face-pip.current { border-color: #c8a44c; background: #2a2010; color: #c8a44c; }

/* ── Validation rows ─────────────────────────── */
.valid-section { margin-top: 8px; padding-top: 6px; border-top: 1px solid #2a2218; }
.valid-row {
  display: flex; justify-content: space-between;
  align-items: baseline; font-size: .75rem;
  padding: 2px 0; border-bottom: 1px solid #1a1510; gap: 6px;
}
.valid-key    { color: #6a5a40; flex-shrink: 0; font-size: .72rem; }
.valid-result { text-align: right; }
.valid-yes    { color: #6a9a6a; }
.valid-no     { color: #9a5a4a; }
.valid-reason { display: block; font-size: .66rem; color: #4a3a28; font-style: italic; text-align: right; }

/* ── Action Row (under top bar) ───────────────── */
#action-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 20px;
  background: #0d0b08;
  border-bottom: 1px solid #221c0c;
  flex-shrink: 0;
}
#action-row .abtn {
  display: block;
  width: auto;
  flex: 1;
  margin-bottom: 0;
  text-align: center;
  padding: 6px 8px;
}

/* ── Action buttons ──────────────────────────── */
.abtn {
  display: block; width: 100%;
  padding: 7px 10px;
  border: 1px solid #4a3a1e;
  background: #1a1510; color: #d4c5a0;
  font: inherit; font-size: .75rem;
  letter-spacing: .05em; text-align: left;
  cursor: pointer; border-radius: 3px;
  margin-bottom: 4px;
  transition: border-color .1s, color .1s, background .1s;
}
.abtn:hover:not(:disabled) { border-color: #c8a44c; color: #c8a44c; }
.abtn:disabled { opacity: .3; cursor: default; }
.abtn.claim-btn:hover:not(:disabled)  { border-color: #4a8a4a; color: #7ab87a; background: rgba(74,138,74,.06); }
.abtn.attack-btn:hover:not(:disabled) { border-color: #8a4040; color: #c07070; background: rgba(138,64,64,.06); }
.abtn.attack-btn.cancel-mode { border-color: #8a5020; color: #d4903a; }
.abtn.attack-btn.cancel-mode:hover:not(:disabled) { background: rgba(138,80,32,.12); }
/* ── Top Command Bar ──────────────────────────── */
#top-cmd {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 9px 20px;
  background: #0f0d09;
  border-bottom: 2px solid #2a2010;
  flex-shrink: 0;
  gap: 16px;
}
#tcb-player {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 195px;
}
#tcb-icon { font-size: 1.5rem; line-height: 1; }
#tcb-name {
  font-size: 1rem; font-weight: bold;
  font-variant: small-caps; letter-spacing: .1em;
}
#tcb-round  { font-size: .63rem; color: #4a3a28; font-family: 'Courier New', monospace; margin-top: 1px; }
#tcb-tokens { font-size: .63rem; color: #8a7a50; font-family: 'Courier New', monospace; margin-top: 1px; letter-spacing: .04em; }
#tcb-tokens.tokens-low   { color: #b87a30; }
#tcb-tokens.tokens-empty { color: #6a3a28; }
#tcb-player.pd #tcb-name { color: #c05050; }
#tcb-player.sm #tcb-name { color: #5599cc; }
#tcb-player.pd { text-shadow: 0 0 10px rgba(160,40,40,.4); }
#tcb-player.sm { text-shadow: 0 0 10px rgba(41,128,185,.4); }
@keyframes tcb-flash-pd {
  0%   { text-shadow: 0 0 0 rgba(160,40,40,0); }
  30%  { text-shadow: 0 0 20px rgba(160,40,40,.9); }
  100% { text-shadow: 0 0 10px rgba(160,40,40,.4); }
}
@keyframes tcb-flash-sm {
  0%   { text-shadow: 0 0 0 rgba(41,128,185,0); }
  30%  { text-shadow: 0 0 20px rgba(41,128,185,.9); }
  100% { text-shadow: 0 0 10px rgba(41,128,185,.4); }
}
.tcb-flash-pd { animation: tcb-flash-pd .65s ease-out forwards; }
.tcb-flash-sm { animation: tcb-flash-sm .65s ease-out forwards; }
/* The one line that speaks for the game — guidance, battle outcomes and the
   game-over result. It replaced a banner above the board whose usual content
   was "No battle this turn", which spent a band of the play area reporting that
   nothing had happened. Composed in ui/statusLine.js. */
#tcb-guidance {
  flex: 1;
  text-align: center;
  font-size: .95rem;
  color: #b8a870;
  font-style: italic;
  letter-spacing: .03em;
  line-height: 1.3;
}
#tcb-guidance .tcb-primary { display: block; }
#tcb-guidance .tcb-detail {
  display: block;
  font-style: normal;
  font-size: .74rem;
  letter-spacing: .05em;
  color: #8a7a52;
  margin-top: 1px;
}
/* Outcomes keep the colour they carried in the banner, so a result still reads
   as a result rather than as another line of advice. */
#tcb-guidance:not(.idle) .tcb-primary {
  font-style: normal;
  font-variant: small-caps;
  font-weight: 700;
  letter-spacing: .08em;
}
#tcb-guidance.win  .tcb-primary { color: #7fc47f; }
#tcb-guidance.lose .tcb-primary { color: #e08080; }
#tcb-guidance.tie  .tcb-primary { color: #d6b45a; }
#tcb-guidance.gameover-pd   .tcb-primary { color: #e07070; }
#tcb-guidance.gameover-sm   .tcb-primary { color: #6aaee0; }
#tcb-guidance.gameover-draw .tcb-primary { color: #c8a44c; }
#btn-endturn {
  padding: 8px 18px;
  background: #12100c;
  border: 2px solid #2e2410; color: #3a2e14;
  font: inherit; font-size: .78rem;
  letter-spacing: .1em; font-variant: small-caps;
  cursor: pointer; border-radius: 3px;
  transition: border-color .2s, color .2s, box-shadow .2s, background .2s;
  min-width: 110px;
}
#btn-endturn:hover { border-color: #5a4a20; color: #8a7440; }
@keyframes endturn-ready {
  0%, 100% { box-shadow: 0 0 6px rgba(200,164,76,.2); }
  50%       { box-shadow: 0 0 14px rgba(200,164,76,.55); }
}
#btn-endturn.ready {
  background: linear-gradient(#1c180c, #110e07);
  border-color: #c8a44c; color: #c8a44c;
  animation: endturn-ready 1.6s ease-in-out infinite;
}
#btn-endturn.ready:hover { border-color: #e8c46c; color: #e8c46c; }

/* ── Log ─────────────────────────────────────── */
#log-wrap { flex: 1; min-height: 0; display: flex; flex-direction: column; }
#log {
  flex: 1; overflow-y: auto;
  font-size: .72rem; line-height: 1.6;
  color: #6a5a40;
  font-family: 'Courier New', monospace;
  min-height: 0;
}
#log.log-collapsed { display: none; }
.log-lbl-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 0;
}
.log-toggle-btn {
  font-size: .60rem;
  font-family: 'Courier New', monospace;
  letter-spacing: .04em;
  padding: 1px 6px;
  border: 1px solid #3a2e14;
  background: #14110d;
  color: #6a5a40;
  cursor: pointer;
  border-radius: 2px;
  transition: border-color .1s, color .1s;
}
.log-toggle-btn:hover { border-color: #c8a44c; color: #c8a44c; }
.le { margin-bottom: 2px; }
.le-click  { color: #8a7a60; }
.le-roll   { color: #a89a6a; }
.le-ok     { color: #6a9a6a; }
.le-no     { color: #9a6050; }
.le-combat { color: #c8a44c; }
.le-turn   { color: #9a8aaa; font-style: italic; }
.le-switch { color: #7a9aaa; }
.le-ts     { color: #7a6a50; font-size: .67rem; }
.le-result { color: #e8d080; font-weight: bold; font-size: .78rem; }

/* ── Turn Events Panel ────────────────────────────── */
#turn-events-panel {
  height: 140px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.no-events { font-style: italic; color: #3a2e18; font-size: .72rem; }
.te {
  font-size: .71rem;
  color: #8a7a5a;
  line-height: 1.55;
  padding: 2px 0;
  border-bottom: 1px solid #1a1710;
}
.te:last-child { border-bottom: none; }
.te-turn { color: #c8a44c; font-style: italic; }
.te-claim  { color: #6a9a6a; }
.te-attack { color: #9a7060; }
.te-deploy { color: #7a8aaa; }
.te-reroll { color: #7a7a5a; }

/* ── Battle Results Panel ─────────────────────────── */
.no-battle { font-style: italic; color: #3a2e18; font-size: .72rem; }

/* Primary result headline */
.battle-headline {
  text-align: center;
  font-size: 1.25rem;
  font-weight: bold;
  font-variant: small-caps;
  letter-spacing: .1em;
  padding: 6px 6px 2px;
  line-height: 1.2;
}
.battle-headline.win  { color: #7ab87a; text-shadow: 0 0 16px rgba(74,138,74,.7); }
.battle-headline.lose { color: #c07070; text-shadow: 0 0 16px rgba(138,64,64,.7); }
.battle-headline.tie  { color: #b8a060; text-shadow: 0 0 12px rgba(200,164,76,.6); }

/* Disabled action button — tooltip showing reason */
#action-row { position: relative; }
.abtn { position: relative; }
.abtn:disabled[data-reason]:hover::after {
  content: attr(data-reason);
  position: absolute;
  bottom: calc(100% + 6px);
  left: 50%;
  transform: translateX(-50%);
  background: #1a1510;
  border: 1px solid #c8a44c;
  color: #b8a870;
  font-size: .70rem;
  padding: 4px 9px;
  border-radius: 3px;
  white-space: nowrap;
  pointer-events: none;
  z-index: 30;
  letter-spacing: .02em;
  box-shadow: 0 2px 10px rgba(0,0,0,.6);
}
.battle-detail {
  text-align: center;
  font-size: .66rem;
  color: #5a4a30;
  font-family: 'Courier New', monospace;
  padding-bottom: 8px;
  border-bottom: 1px solid #1e1a10;
  margin-bottom: 3px;
}

.battle-section { padding: 4px 0; border-bottom: 1px solid #1e1a10; }
.battle-section:last-child { border-bottom: none; }
.battle-row { display: flex; justify-content: space-between; gap: 6px; font-size: .72rem; padding: 1px 0; }
.battle-key { color: #5a4a30; flex-shrink: 0; }
.battle-val { color: #c4b590; text-align: right; word-break: break-all; }
.battle-val.pd   { color: #c05050; }
.battle-val.sm   { color: #5599cc; }
.battle-val.neu  { color: #888; }
.battle-val.win  { color: #6a9a6a; font-weight: bold; }
.battle-val.lose { color: #9a6050; font-weight: bold; }
.battle-outcome-badge {
  text-align: center;
  font-size: 1.8rem;
  font-weight: bold;
  font-variant: small-caps;
  letter-spacing: .12em;
  padding: 6px 0 4px;
  line-height: 1;
}
.battle-outcome-badge.win  { color: #7ab87a; text-shadow: 0 0 20px rgba(74,138,74,.8); }
.battle-outcome-badge.lose { color: #c07070; text-shadow: 0 0 20px rgba(192,80,80,.8); }
.battle-outcome-badge.tie  { color: #b8a060; text-shadow: 0 0 16px rgba(200,164,76,.7); }

.battle-winner {
  text-align: center; padding: 5px 8px; border-radius: 3px;
  font-variant: small-caps; letter-spacing: .08em;
  font-size: .8rem; font-weight: bold; margin: 5px 0;
}
.battle-winner.win  { background: rgba(74,138,74,.08); color: #7ab87a; border: 1px solid #3a6a3a; }
.battle-winner.lose { background: rgba(138,64,64,.08); color: #c07070; border: 1px solid #6a3a3a; }
.battle-winner.tie  { background: rgba(200,164,76,.06); color: #b8a060; border: 1px solid #6a5820; }
.battle-outcome { font-size: .7rem; color: #9a8a60; font-style: italic; text-align: center; padding: 3px 0; }

/* Dim class for focus modes — the non-target tiles of an open mode */
.tile-mode-dim { filter: brightness(0.48) saturate(0.30) !important; transition: filter .15s; }

/* ── Combat flashes ────────────────────────────────── */
@keyframes combat-flash {
  0%   { box-shadow: 0 0 0 rgba(200,164,76,0); }
  25%  { box-shadow: 0 0 22px rgba(200,164,76,1), 0 0 6px rgba(200,164,76,.7); }
  100% { box-shadow: 0 0 0 rgba(200,164,76,0); }
}
.tile-combat-flash { animation: combat-flash 1.3s ease-out forwards; }

@keyframes exhausted-flash {
  0%   { box-shadow: 0 0 0 rgba(255,102,0,0); }
  25%  { box-shadow: 0 0 22px rgba(255,102,0,.9), 0 0 6px rgba(255,102,0,.6); }
  100% { box-shadow: 0 0 0 rgba(255,102,0,0); }
}
.tile-exhausted-flash { animation: exhausted-flash .8s ease-out forwards; }

@keyframes capture-pulse-pd {
  0%   { box-shadow: 0 0 0 rgba(160,40,40,0); }
  30%  { box-shadow: 0 0 28px 8px rgba(160,40,40,.95); }
  100% { box-shadow: 0 0 10px 3px rgba(160,40,40,.5); }
}
@keyframes capture-pulse-sm {
  0%   { box-shadow: 0 0 0 rgba(41,128,185,0); }
  30%  { box-shadow: 0 0 28px 8px rgba(41,128,185,.95); }
  100% { box-shadow: 0 0 10px 3px rgba(41,128,185,.5); }
}
.tile-capture-pd { animation: capture-pulse-pd 1.4s ease-out forwards; }
.tile-capture-sm { animation: capture-pulse-sm 1.4s ease-out forwards; }


/* ── VISUAL POLISH — animations & UI ────────────── */

/* Selected tile: brightness pulse */
@keyframes selected-pulse {
  0%, 100% { filter: brightness(1.08); }
  50%       { filter: brightness(1.30); }
}
.tile-selected { animation: selected-pulse 1.1s ease-in-out infinite; }

/* Board wrap: deeper ambient shadow */
#board-wrap {
  box-shadow: 0 0 40px rgba(200,164,76,.14), 0 6px 24px rgba(0,0,0,.65);
}

/* Re-roll tumble animation */
@keyframes tile-reroll {
  0%   { transform: rotate(0deg)  scale(1.00); }
  18%  { transform: rotate(-9deg) scale(0.92); }
  38%  { transform: rotate(7deg)  scale(1.05); }
  58%  { transform: rotate(-4deg) scale(0.97); }
  78%  { transform: rotate(2deg)  scale(1.01); }
  100% { transform: rotate(0deg)  scale(1.00); }
}
.tile-reroll-anim { animation: tile-reroll 340ms ease-out forwards; z-index: 6; }

/* Combat tactile animations */
@keyframes tile-lunge {
  0%   { transform: scale(1.00) translateY(0);   }
  25%  { transform: scale(1.10) translateY(-5px); }
  55%  { transform: scale(0.95) translateY(2px);  }
  100% { transform: scale(1.00) translateY(0);   }
}
@keyframes tile-recoil {
  0%   { transform: translateX(0);   }
  15%  { transform: translateX(-5px); }
  35%  { transform: translateX(4px);  }
  55%  { transform: translateX(-3px); }
  75%  { transform: translateX(2px);  }
  100% { transform: translateX(0);   }
}
@keyframes tile-win-flash {
  0%   { filter: brightness(2.2); }
  50%  { filter: brightness(1.4); }
  100% { filter: brightness(1.0); }
}
@keyframes tile-lose-flash {
  0%   { filter: brightness(0.35); }
  100% { filter: brightness(1.0);  }
}
.tile-anim-lunge   { animation: tile-lunge    340ms ease-out forwards; z-index: 6; }
.tile-anim-recoil  { animation: tile-recoil   280ms ease-out forwards; }
.tile-anim-winglow { animation: tile-win-flash  500ms ease-out forwards; }
.tile-anim-losdim  { animation: tile-lose-flash 500ms ease-out forwards; }

/* Labels — sepia ink heading */
.lbl { color: #b89050; font-weight: bold; letter-spacing: .10em; font-variant: small-caps; }

/* Action buttons — richer hover backgrounds */
.abtn:hover:not(:disabled)            { background: rgba(200,164,76,.07); border-color: #c8a44c; color: #c8a44c; }
.abtn.claim-btn:hover:not(:disabled)  { background: rgba(74,138,74,.10); }
.abtn.attack-btn:hover:not(:disabled) { background: rgba(138,64,64,.10); }

/* Side panel borders — slightly warmer/more visible */
#summary { border-right-color: #5a4828; }
#right   { border-left-color:  #5a4828; }

/* Event log — slightly better line separation */
.le { padding: 1px 2px; border-bottom: 1px solid rgba(255,255,255,.025); }
.le:last-child { border-bottom: none; }
.le-result { letter-spacing: .04em; }

/* ── Legend ──────────────────────────────────── */
.legend { display: grid; grid-template-columns: 1fr 1fr; gap: 3px; font-size: .68rem; }
.li { display: flex; align-items: center; gap: 5px; }
.ls { width: 10px; height: 10px; border-radius: 2px; flex-shrink: 0; }
/* Terrain glyph in legend — monospace, right-aligned in a fixed column */
.lg { display: inline-block; width: 14px; text-align: center; font-size: .85rem; color: #2a1e10; flex-shrink: 0; line-height: 1; }
.hl-legend { font-size: .68rem; display: flex; flex-direction: column; gap: 3px; }
.hl-li { display: flex; align-items: center; gap: 6px; }
.hl-swatch { width: 18px; height: 10px; border-radius: 1px; flex-shrink: 0; }

/* The six universal interaction marks, compacted into three paired rows. The
   board uses these exact shapes; this key teaches family (diamond vs circle)
   and state (hollow vs filled) without relying on colour. */
.selection-legend {
  display: flex;
  flex-direction: column;
  gap: 3px;
  margin: 3px 0 7px;
  font-size: .64rem;
  color: #6f6048;
}
.selection-legend-row { display: grid; grid-template-columns: 15px 15px 1fr; align-items: center; gap: 3px; }
.selection-legend-mark {
  width: 13px;
  height: 13px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid currentColor;
  border-radius: 2px;
  background: #241f18;
  font-size: 8px;
  line-height: 1;
}
.selection-legend-resource    { color: #9a771d; }
.selection-legend-target      { color: #287a73; }
.selection-legend-unavailable { color: #81745a; }
.selection-legend-rejected    { color: #a54e3f; font-weight: 800; }
.lbl-secondary { margin-top: 4px; font-size: .52rem; opacity: .78; }

/* ── Status badge legend ─────────────────────────────────────────────────── */
.badge-legend { display: flex; flex-wrap: wrap; gap: 4px 10px; margin-top: 3px; }
.badge-li { display: flex; align-items: center; gap: 5px; font-size: .65rem; color: #8a7040; }

/* ── Inspector status section ──────────────────────────────────────────── */
.insp-status-section { margin: 5px 0 0; padding: 5px 7px 4px; background: rgba(0,0,0,.22); border-radius: 3px; }
.insp-status-section .insp-section-lbl { margin-bottom: 4px; }
.insp-status-row { display: flex; align-items: center; gap: 6px; margin: 2px 0; }
.insp-status-by { font-size: .62rem; color: #8a7040; font-style: italic; }

/* ── Deploy Elite selection row ──────────────── */
#deploy-select-row {
  display: none;
  align-items: center;
  gap: 6px;
  padding: 5px 20px;
  background: rgba(140,100,20,.09);
  border-bottom: 1px solid #3a2e14;
  border-top: 1px solid rgba(140,100,20,.22);
  flex-shrink: 0;
}
#deploy-select-row .ds-label {
  font-size: .66rem;
  color: #c8a44c;
  font-family: 'Courier New', monospace;
  white-space: nowrap;
  letter-spacing: .04em;
}
.ds-elite-btn {
  flex: 1;
  padding: 4px 6px;
  border: 1px solid #7a5a1a;
  background: rgba(140,100,20,.10);
  color: #d4a830;
  font: inherit;
  font-size: .70rem;
  cursor: pointer;
  border-radius: 3px;
  transition: border-color .1s, color .1s, background .1s;
  text-align: center;
}
.ds-elite-btn:hover:not(:disabled) { border-color: #c8a44c; color: #e8c040; background: rgba(140,100,20,.18); }
.ds-elite-btn:disabled { opacity: .30; cursor: default; }
/* Pass 5.1 — says why the offered list is shorter than the stash. Without it a
   filtered picker and a broken picker look identical. */
#deploy-select-row .ds-note {
  font-size: .64rem;
  font-style: italic;
  color: #a89464;
  align-self: center;
  margin-left: 6px;
}
/* PASS 6D — CANCEL EMPHASIS.

   Playtest: the far-right Cancel in the deploy row and the action/resource
   prompts was too quiet to find. It was #5a4a30 text on a #14110d ground —
   near-invisible beside the lit buttons it sits next to, so a player looking for
   a way out of a mode could not see one.

   It is now a legible DESTRUCTIVE control, using the same red the mode banner's
   own cancel already uses (.mode-cancel-btn) so the two read as one idea rather
   than two conventions. Deliberately OUTLINE-ONLY: Execute and the deploy dice
   are filled, and the whole point is that Cancel must be easy to find without
   ever competing for the primary click.

   Placement and behaviour are unchanged. See the matching prompt-button rules
   further down for the same treatment on the ability/resource prompts. */
#ds-cancel {
  padding: 4px 10px;
  border: 1px solid #a04030;
  background: rgba(180,60,40,.18);
  color: #e07060;
  font: inherit;
  font-size: .70rem;
  cursor: pointer;
  border-radius: 3px;
  transition: background .1s, border-color .1s, color .1s;
}
#ds-cancel:hover {
  background: rgba(180,60,40,.35);
  border-color: #c05a48;
  color: #f09080;
}

/* ── Legacy stash badges (kept for CSS stability) ────────────────────── */
.stash-row { display: flex; gap: 4px; flex-wrap: wrap; margin-top: 3px; }
.stash-badge {
  font-size: .64rem; padding: 1px 6px; border-radius: 2px;
  border: 1px solid #6a4a10; background: rgba(160,120,30,.12);
  color: #c8a030; font-family: 'Courier New', monospace;
  letter-spacing: .05em; cursor: default;
}
.stash-empty { color: #4a3a20; font-style: italic; font-size: .68rem; }
.dash-stash-badges { display: inline-flex; gap: 4px; flex-wrap: wrap; align-items: center; }

/* ── Reserve Dice (Stash) Panel ──────────────────────────────────────── */
.dash-stash {
  padding: 8px 10px;
  border-bottom: 1px solid #2a2218;
}
.stash-reserve-badge {
  font-size: .60rem;
  font-family: 'Courier New', monospace;
  color: #7a6a48;
  margin-left: 6px;
  letter-spacing: .02em;
}

/* Individual die card */
.stash-die-card {
  padding: 5px 7px;
  margin-bottom: 5px;
  background: rgba(28,24,16,.60);
  border: 1px solid #2e2a1a;
  border-left: 2px solid #5a4820;
  border-radius: 3px;
  transition: border-left-color .15s, background .15s;
  cursor: default;
}
.stash-die-card:last-child { margin-bottom: 0; }
/* Per-type left accent + hover tint */
.stash-die-card[data-die-type="vanguard"] { border-left-color: #9a3828; }
.stash-die-card[data-die-type="sentinel"] { border-left-color: #2a608a; }
.stash-die-card[data-die-type="marshal"]  { border-left-color: #8a7220; }
.stash-die-card[data-die-type="vanguard"]:hover { border-left-color: #d06050; background: rgba(50,22,18,.60); }
.stash-die-card[data-die-type="sentinel"]:hover { border-left-color: #5090c0; background: rgba(18,30,50,.60); }
.stash-die-card[data-die-type="marshal"]:hover  { border-left-color: #c8a44c; background: rgba(42,36,18,.70); }

.stash-die-header {
  display: flex;
  align-items: center;
  gap: 5px;
  margin-bottom: 5px;
}
.stash-die-icon {
  font-size: .78rem;
  line-height: 1;
  flex-shrink: 0;
  width: 16px;
  text-align: center;
}
.vanguard-icon { color: #c04838; }
.sentinel-icon { color: #4080b0; }
.marshal-icon  { color: #b89030; }

.stash-die-name-block { flex: 1; min-width: 0; }
.stash-die-name {
  font-size: .72rem;
  font-weight: bold;
  color: #c4b490;
  display: block;
  line-height: 1.2;
  letter-spacing: .04em;
}
.stash-die-role {
  font-size: .57rem;
  color: #5a4a38;
  font-style: italic;
  display: block;
  line-height: 1.2;
  margin-top: 1px;
}

/* Type-key badge — top-right of card header */
.stash-type-key {
  font-size: .57rem;
  font-family: 'Courier New', monospace;
  font-weight: 700;
  padding: 1px 4px;
  border-radius: 2px;
  align-self: flex-start;
  flex-shrink: 0;
  letter-spacing: .02em;
}
.stash-die-card[data-die-type="vanguard"] .stash-type-key {
  background: rgba(160,50,36,.20); color: #c06050; border: 1px solid rgba(160,50,36,.38);
}
.stash-die-card[data-die-type="sentinel"] .stash-type-key {
  background: rgba(36,88,160,.20); color: #5888c8; border: 1px solid rgba(36,88,160,.38);
}
.stash-die-card[data-die-type="marshal"] .stash-type-key {
  background: rgba(160,130,28,.16); color: #b89030; border: 1px solid rgba(160,130,28,.36);
}

/* Die face row — 6 faces sorted low→high */
.stash-die-faces {
  display: flex;
  gap: 3px;
}
.sf {
  width: 22px; height: 22px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 3px;
  font-size: .72rem;
  font-family: 'Courier New', monospace;
  font-weight: 700;
  line-height: 1;
  border: 1px solid;
  flex-shrink: 0;
}
/* Face value tiers — low=danger, high=power */
.sf-zero { background: rgba(70,18,8,.50);  color: #783028; border-color: #3a1210; }
.sf-low  { background: rgba(28,24,16,.65); color: #7a6a50; border-color: #2c2618; }
.sf-mid  { background: rgba(40,34,20,.65); color: #a89870; border-color: #3c3018; }
.sf-high { background: rgba(58,48,18,.60); color: #c8a44c; border-color: #584820; }
.sf-max  {
  background: rgba(80,62,10,.55); color: #e8c060; border-color: #786020;
  text-shadow: 0 0 5px rgba(220,180,50,.45);
}

/* Empty reserve state */
.stash-empty-state {
  font-size: .67rem;
  color: #4a3a28;
  font-style: italic;
  padding: 6px 2px;
  text-align: center;
}

/* ── Structures Panel ───────────────────────────────────────────────────── */
#structures-panel { display: flex; flex-direction: column; gap: 4px; }

.struct-entry {
  display: flex; align-items: flex-start; gap: 7px;
  padding: 5px 7px; border-radius: 3px;
  border: 1px solid #1e1a10; font-size: .72rem; line-height: 1.4;
}
.struct-entry.active  { border-color: #3a3020; background: rgba(255,255,255,.022); }
.struct-entry.inactive { opacity: .38; }
.struct-icon { font-size: .88rem; line-height: 1.5; flex-shrink: 0; }
.struct-body { flex: 1; min-width: 0; }
.struct-name { font-size: .72rem; font-weight: bold; letter-spacing: .04em; }
.struct-name.inactive-name  { color: #7a6a50; }
.struct-desc   { font-size: .65rem; color: #6a5a40; line-height: 1.3; margin-top: 1px; }
.struct-recipe { font-size: .60rem; color: #3a3020; font-family: 'Courier New', monospace; margin-top: 1px; }
.struct-badge  {
  font-size: .60rem; padding: 1px 5px; border-radius: 2px;
  font-family: 'Courier New', monospace; flex-shrink: 0; align-self: flex-start; margin-top: 2px;
}
.struct-badge.on  { background: rgba(200,164,76,.10); color: #b8943c; border: 1px solid rgba(200,164,76,.28); }
.struct-badge.off { background: rgba(30,26,16,.5);   color: #3a3020; border: 1px solid #1e1a10; }

/* ── Industrial Command Dashboard (left panel) ──────────────────────────── */
#pd-panel, #sm-panel {
  display: flex;
  flex-direction: column;
  gap: 0;
}

/* Captain identity card */
.dash-captain-card {
  padding: 10px 10px 8px;
  border-bottom: 1px solid #2a2218;
  background: rgba(0,0,0,.15);
}
.dash-captain-header {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 5px;
}
.dash-captain-icon-big {
  font-size: 1.6rem;
  line-height: 1;
  flex-shrink: 0;
}
.dash-captain-name-block { flex: 1; min-width: 0; }
.dash-captain-name {
  font-size: .88rem;
  font-weight: bold;
  font-variant: small-caps;
  letter-spacing: .08em;
}
.dash-captain-name.pd { color: #c05050; }
.dash-captain-name.sm { color: #5599cc; }
.dash-captain-tagline {
  font-size: .62rem;
  color: #9a8a68;
  font-style: italic;
  line-height: 1.3;
  margin-top: 2px;
}

/* ── Token count block — prominent display inside the active captain card ── */
.dash-token-block {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  min-width: 44px;
  padding: 4px 8px;
  border: 1px solid rgba(200,164,76,.35);
  border-radius: 3px;
  background: rgba(200,164,76,.07);
}
.dash-token-num {
  font-size: 1.85rem;
  font-weight: bold;
  font-family: 'Courier New', monospace;
  color: #d4b85a;
  line-height: 1;
  text-shadow: 0 0 12px rgba(200,164,76,.45);
  letter-spacing: -.02em;
}
.dash-token-num.tok-low   { color: #c88c30; text-shadow: 0 0 10px rgba(200,130,40,.4); }
.dash-token-num.tok-empty { color: #b05040; text-shadow: 0 0 10px rgba(180,70,50,.4); }
.dash-token-label {
  font-size: .63rem;
  color: #9a8a68;
  font-family: 'Courier New', monospace;
  letter-spacing: .10em;
  margin-top: 2px;
  text-transform: uppercase;
}

/* Ability rows within captain card — kept for reference, section removed from HTML */
.dash-ability-section {
  margin-top: 4px;
  padding-top: 4px;
  border-top: 1px solid #1e1a10;
}
.dash-ability-row {
  display: flex;
  align-items: flex-start;
  gap: 5px;
  margin-bottom: 3px;
}
.dash-ability-label {
  font-size: .55rem;
  font-family: 'Courier New', monospace;
  letter-spacing: .06em;
  color: #a08838;
  border: 1px solid #2e2410;
  border-radius: 2px;
  padding: 1px 3px;
  flex-shrink: 0;
  align-self: flex-start;
  margin-top: 2px;
  background: rgba(200,164,76,.04);
}
.dash-ability-body { flex: 1; min-width: 0; }
.dash-ability-name {
  font-size: .68rem;
  font-weight: bold;
  color: #c4b590;
  line-height: 1.2;
}
.dash-ability-desc {
  font-size: .58rem;
  color: #7a6a52;
  line-height: 1.3;
  margin-top: 1px;
}
.ability-status-ready { color: #72b872; font-size: .62rem; font-family: 'Courier New', monospace; }
.ability-status-used  { color: #a86050; font-size: .62rem; font-family: 'Courier New', monospace; }

/* ── Available Actions — display-only pilot face list (Pass 1A) ─────────── */
.avail-actions-section {
  padding: 5px 10px 7px;
  border-top: 1px solid #1e1a10;
  background: rgba(0,0,0,.10);
}
.avail-actions-hdr {
  font-size: .72rem;
  font-family: 'Courier New', monospace;
  letter-spacing: .07em;
  color: #c4a840;
  text-transform: uppercase;
  font-weight: 700;
  margin-bottom: 5px;
  padding-bottom: 3px;
  border-bottom: 1px solid rgba(196,168,64,.22);
}
.avail-action-row {
  display: flex;
  align-items: baseline;
  gap: 5px;
  padding: 2px 0;
  font-size: .68rem;
  line-height: 1.3;
}
.avail-action-name {
  font-weight: 700;
  color: #c4b590;
  flex-shrink: 0;
}
.avail-action-sep {
  color: #4a3c22;
  flex-shrink: 0;
}
.avail-action-source {
  color: #8a7a56;
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.avail-action-cost {
  font-family: 'Courier New', monospace;
  font-size: .66rem;
  color: #a08838;
  letter-spacing: .03em;
  flex-shrink: 0;
}
/* Rows are clickable — subtle affordance */
.avail-action-row {
  cursor: pointer;
  border-radius: 2px;
  transition: background .1s;
  padding: 2px 3px;
  margin: 0 -3px;
}
.avail-action-row:hover {
  background: rgba(200,164,76,.08);
}
/* Selected / active row */
.avail-action-row.avail-action-selected {
  background: rgba(200,164,76,.14);
  outline: 1px solid rgba(200,164,76,.35);
}
.avail-action-row.avail-action-selected .avail-action-name {
  color: #e8d080;
}
/* Used face ability row — visible but inactive */
.avail-action-row.avail-action-used {
  cursor: default;
  opacity: 0.42;
}
.avail-action-row.avail-action-used:hover {
  background: none;
}
.avail-action-used-badge {
  font-size: .54rem;
  color: #6a5030;
  font-style: italic;
  margin-left: auto;
  flex-shrink: 0;
}
/* Barrister — Litigation status on a captain panel (Pass 3E).
   The burdened captain's badge states ONLY that a burden exists; the hidden
   resource type is never rendered here. The author variant appears on the
   Barrister controller's own panel and names the type only on their own turn
   (gated in ui/renderDashboard.js renderCaptainPanel). */
.dash-litigation-badge {
  display: flex;
  flex-direction: column;
  gap: 1px;
  margin: 4px 0 2px;
  padding: 4px 7px;
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .02em;
  color: #6b2d2d;
  background: rgba(150, 60, 45, .14);
  border-left: 3px solid #8c3a2c;
  border-radius: 2px;
}
.dash-litigation-note {
  font-size: .56rem;
  font-weight: 400;
  font-style: italic;
  color: #7a5a48;
  letter-spacing: 0;
}
.dash-litigation-badge.dash-litigation-author {
  color: #4a4326;
  background: rgba(120, 105, 45, .13);
  border-left-color: #7d6d34;
}
/* Litigation surcharge prompt — normalized states (Playtest Correction Pass 2).
   The payable and unpayable states share one shape: headline, demand, then
   either candidates or the reason there are none, then the controls. */
.lit-prompt-action { color: #d8b45c; font-weight: 700; }
.lit-prompt-none   { color: #e08a72; }
.lit-prompt-safe   { font-size: .88em; font-style: italic; opacity: .85; }
/* Barrister controller-side Litigation state — the "cleared" line. */
.dash-litigation-badge.dash-litigation-clear {
  color: #35603a;
  background: rgba(74, 138, 74, .14);
  border-left-color: #4a8a4a;
}
/* Litigate banner — the secret-choice note in the mode banner */
.lit-secret-note {
  font-size: .78em;
  font-style: italic;
  opacity: .8;
}
/* Inactive player rows — read-only opponent intel */
.avail-action-row.avail-action-readonly {
  cursor: default;
  opacity: 0.52;
}
.avail-action-row.avail-action-readonly:hover {
  background: none;
}
/* Mode banner — face ability selection */
#mode-banner.face-ability-active {
  border-color: #4a6a30;
  background: rgba(40,80,20,.13);
  color: #90c060;
}
.avail-actions-note {
  font-size: .54rem;
  color: #4a3c22;
  font-style: italic;
  margin-top: 4px;
}
/* Resource preview — owned terrain matching a face ability cost (eligible, not yet selected) */
.tile-resource-preview {
  box-shadow: inset 0 0 0 999px rgba(180,150,40,.15), 0 0 12px 3px rgba(200,170,50,.55) !important;
  outline: 1px dashed rgba(200,170,50,.75);
  outline-offset: -2px;
}
/* ── Resource present-but-UNAVAILABLE (Pass 6B) ───────────────────────────────
   The right terrain type, owned by the paying player, and NOT selectable:
   Exhausted, Committed, or already earmarked by this action's own native cost.

   Before this pass these were dimmed exactly like terrain of the wrong type, so
   a player who owned three Timber Stands and had exhausted all three saw an
   apparently empty board with no explanation. This says "you have the right
   terrain, it is just not available" — a strategic fact, since Exhaustion is
   precisely what makes resource choice matter.

   MUST NOT LOOK CLICKABLE, which is the whole design constraint here:
     • no glow — every actionable state on this board carries one;
     • desaturated and dimmed rather than tinted, so it reads as absence;
     • a solid rather than dashed outline, so it cannot be mistaken for the
       dashed candidate outline directly beside it;
     • not-allowed cursor, so the pointer says the same thing the colour does.
   Deliberately quieter than .tile-resource-preview and louder than plain dim. */
.tile-resource-unavailable {
  outline: 1px solid rgba(150, 130, 90, .45);
  outline-offset: -2px;
  filter: brightness(0.62) saturate(0.35);
  cursor: not-allowed;
}

/* Resource selected — chosen as payment candidate (not exhausted) */
.tile-resource-selected {
  box-shadow: inset 0 0 0 999px rgba(190,155,35,.30), 0 0 18px 5px rgba(215,185,45,.90) !important;
  outline: 2px solid rgba(215,185,45,.95);
  outline-offset: -2px;
}
/* Target preview — valid Record target tiles (teal, distinct from amber resource highlight) */
.tile-target-preview {
  box-shadow: inset 0 0 0 999px rgba(40,160,160,.14), 0 0 12px 3px rgba(50,180,175,.55) !important;
  /* DOTTED, where an offered RESOURCE is dashed. The two "you may click this"
     states previously differed by hue alone, which is exactly the confusion the
     selection-mark work exists to remove — and the board already carries other
     blues (Steam Mechanic territory, Sentence/Jurisdiction overlays). */
  outline: 1px dotted rgba(50,180,175,.85);
  outline-offset: -2px;
}
/* Target selected — chosen Record target tile */
.tile-target-selected {
  box-shadow: inset 0 0 0 999px rgba(40,160,160,.28), 0 0 18px 5px rgba(50,190,185,.85) !important;
  outline: 2px solid rgba(50,190,185,.95);
  outline-offset: -2px;
}

/* Broad target field — preserve the universal dotted outline and circle marker
   while dropping the repeated wash and halo. A chosen target immediately
   returns to the stronger selected treatment above. */
.tile-target-preview.tile-target-field {
  box-shadow: inset 0 0 0 1px rgba(50,130,122,.25) !important;
  background-image: none;
}
.tile-target-field .tile-selection-mark-target { opacity: .78; }

/* Rejected choice — the most recent click the current selection refused.
   Deliberately the ONLY red in the selection language: preview and selected are
   teal, resources amber, and a refusal has to read as a different KIND of
   statement rather than a third shade of the same one. Cleared by the next
   click that lands, so it never accumulates. */
.tile-target-invalid {
  box-shadow: inset 0 0 0 999px rgba(170,45,35,.22), 0 0 14px 4px rgba(205,70,55,.75) !important;
  outline: 2px dashed rgba(215,85,70,.95);
  outline-offset: -2px;
}
/* The coordinate inside a refusal line, quieter than the reason itself. */
.fa-reject-coord { opacity: .75; font-variant-numeric: tabular-nums; }

/* ── SELECTION MARK — interaction state without relying on hue ──────────────
   Shape family says WHICH KIND of choice a tile is (diamond = resource, round =
   target); fill says whether it is already taken; a slash and a cross cover
   unusable and refused. Every distinction survives greyscale, so a
   colour-impaired player reads the same board as everyone else — and the same
   four-way vocabulary is what a later 3D board would float above a tile.

   Placed on the left slot's vertical centre, the one region no property badge
   occupies. Keeping interaction state off the corners is itself a cue: corners
   describe the TILE, this describes the pending ACTION.

   Sized and coloured to stay quiet. It is a legend, not decoration. */
.tile-selection-mark {
  position: absolute;
  left: -1px;
  top: 50%;
  transform: translateY(-50%);
  width: 14px;
  height: 14px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 9px;
  line-height: 1;
  border-radius: 2px;
  border: 1px solid currentColor;
  /* Opaque enough to stay legible over any terrain, including a dimmed tile. */
  background: rgba(10, 8, 5, .86);
  text-shadow: 0 0 3px rgba(0,0,0,.9);
  pointer-events: none;
  z-index: 4;
}
.tile-selection-mark-resource    { color: #ddc04a; }
.tile-selection-mark-target      { color: #4fd0cb; }
.tile-selection-mark-unavailable { color: #9c8c66; opacity: .85; }
.tile-selection-mark-rejected    { color: #ef8871; }

/* A refused tile is the one state a player must not miss, so its mark is the
   only one that carries weight rather than merely colour. */
.tile-selection-mark-rejected {
  border-width: 2px;
  font-weight: 700;
}

/* Forced-colours (Windows high contrast) drops the palette entirely. The glyph
   and the border are what remain, which is the whole point of choosing shape as
   the primary cue. */
@media (forced-colors: active) {
  .tile-selection-mark { forced-color-adjust: none; background: Canvas; color: CanvasText; border-color: CanvasText; }
}

/* ── UX Recovery Pass 2 — THE UNIVERSAL REFUSAL LINE ────────────────────────
   One appearance for a refused click, wherever it is shown: attached to the
   mode banner for the eleven board-interaction modes, and composed into the
   Conservatory interruption for the one decision that does not live on the
   banner. It borrows .fa-prompt-refused's colour on purpose — the Face Ability
   family already speaks in that voice, and a second red would read as a
   different kind of message rather than the same one from another mode.

   Sentence case and left-aligned against the banner's small-caps guidance
   text: guidance is a label, a refusal is a sentence addressed to the player. */
.mode-rejection {
  margin-top: 5px;
  padding-top: 4px;
  border-top: 1px solid rgba(224,144,106,.35);
  color: #e0906a;
  font-variant: normal;
  letter-spacing: normal;
  text-align: left;
  line-height: 1.35;
}
.mode-rejection .mode-rejection-reason { font-weight: 600; }
/* A mode that refused a click without naming a requirement is a defect, not a
   copy problem, and it is meant to look like one on screen as well as in the
   console. See _demandReason in ui/interactionRejection.js. */
.mode-rejection-unspecified {
  color: #ff6b6b;
  background: rgba(255,107,107,.10);
  outline: 1px dashed rgba(255,107,107,.6);
}
/* Inside the Conservatory interruption the line sits on a wider, calmer
   surface, so it gets its own breathing room rather than the banner's rule. */
#conservatory-prompt .mode-rejection {
  margin: 6px 0 2px;
  padding: 5px 8px;
  border-top: none;
  border-left: 3px solid rgba(224,144,106,.7);
  background: rgba(224,144,106,.08);
  border-radius: 2px;
}

/* Dispatch source — Phase 1: eligible friendly units that can be dispatched */
.tile-dispatch-source {
  box-shadow: inset 0 0 0 999px rgba(220,100,20,.12), 0 0 12px 3px rgba(230,120,30,.55) !important;
  outline: 1px dashed rgba(230,120,30,.80);
  outline-offset: -2px;
  cursor: pointer !important;
}
/* Dispatch selected source — Phase 2: the unit chosen to be moved */
.tile-dispatch-selected-source {
  box-shadow: inset 0 0 0 999px rgba(220,100,20,.28), 0 0 18px 5px rgba(240,130,30,.90) !important;
  outline: 2px solid rgba(245,140,30,.95);
  outline-offset: -2px;
}
/* Dispatch destination — Phase 2: valid landing tiles for the dispatched unit */
.tile-dispatch-dest {
  box-shadow: inset 0 0 0 999px rgba(60,130,210,.14), 0 0 12px 3px rgba(80,150,225,.55) !important;
  outline: 1px dashed rgba(80,150,225,.75);
  outline-offset: -2px;
  cursor: pointer !important;
}

/* ── Territory summary section ──────────────────────────────────────────── */
.dash-territory {
  padding: 8px 10px;
  border-bottom: 1px solid #2a2218;
}
.dash-section-lbl {
  font-size: .85rem;
  color: #c8a44c;
  letter-spacing: .10em;
  text-transform: uppercase;
  font-family: 'Courier New', monospace;
  border-bottom: 1px solid #2a2010;
  padding-bottom: 3px;
  margin-bottom: 6px;
}
/* Dominant total tile count */
.dash-total-tiles {
  font-size: 2.5rem;
  font-weight: bold;
  font-family: 'Courier New', monospace;
  color: #c8a44c;
  text-align: center;
  line-height: 1;
  padding: 4px 0 6px;
  text-shadow: 0 0 14px rgba(200,164,76,.35);
  letter-spacing: -.02em;
}
.dash-terrain-subtotals {
  padding-bottom: 4px;
  margin-bottom: 4px;
  border-bottom: 1px solid #1e1a10;
}
.dash-terrain-row {
  display: flex;
  justify-content: space-between;
  font-size: .63rem;
  padding: 1px 0;
  font-family: 'Courier New', monospace;
}
.dash-terrain-key { color: #8a7a60; }
.dash-terrain-val { color: #a89a78; }
.dash-terrain-val.has-tiles { color: #90bc90; }
.dash-total-row {
  display: flex;
  justify-content: space-between;
  font-size: .85rem;
  padding-top: 4px;
  margin-top: 2px;
}
.dash-total-key { color: #9a8a68; font-family: 'Courier New', monospace; }
.dash-total-val { color: #c8a44c; font-family: 'Courier New', monospace; font-weight: bold; }

/* ── Industrial structures section ──────────────────────────────────────── */
.dash-structures {
  padding: 8px 10px;
}
.dash-struct-card {
  padding: 6px 7px;
  border: 1px solid #1e1a10;
  border-radius: 3px;
  margin-bottom: 5px;
  font-size: .68rem;
  line-height: 1.4;
  cursor: default;
  transition: border-color 0.2s, box-shadow 0.2s;
}
.dash-struct-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 3px;
}
.dash-struct-title {
  font-weight: bold;
  font-size: .72rem;
  letter-spacing: .04em;
}
.dash-struct-title.inactive-name  { color: #7a6a50; }
.dash-struct-status {
  font-size: .59rem;
  font-family: 'Courier New', monospace;
  padding: 1px 6px;
  border-radius: 2px;
  flex-shrink: 0;
  font-weight: bold;
  letter-spacing: .04em;
}
.dash-struct-status.active {
  background: rgba(200,164,76,.18);
  color: #e8c040;
  border: 1px solid rgba(200,164,76,.45);
}
.dash-struct-status.inactive {
  background: rgba(30,26,16,.5);
  color: #7a6a50;
  border: 1px solid #1e1a10;
  font-weight: normal;
}
/* ── Structure terrain grid ─────────────────────────────────────────────── */
.dsg-table { width: 100%; font-family: 'Courier New', monospace; }
.dsg-header-row,
.dsg-row {
  display: flex;
  align-items: center;
  gap: 0;
  padding: 2px 0;
}
.dsg-row { border-bottom: 1px solid #1a1710; cursor: default; transition: background .15s; border-left: 2px solid transparent; }
.dsg-row:last-of-type { border-bottom: none; }
.dsg-row:hover { background: rgba(255,255,255,.025); }
/* Active (online) structures — stronger left border + per-structure tint */
.dsg-row.dsg-row-active { background: rgba(255,255,255,.028); }
/* Inactive (offline) structures — dormant/unavailable feel */
.dsg-row.dsg-row-inactive { opacity: 0.42; filter: grayscale(0.30); }
.dsg-name {
  flex: 1;
  font-size: .76rem;
  font-weight: bold;
  letter-spacing: .03em;
  padding-right: 4px;
  display: flex;
  align-items: center;
  gap: 3px;
  min-width: 0;
}
.dsg-name.inactive-name  { color: #7a6a50; }
/* ONLINE / OFFLINE status chips */
.dsg-status-chip {
  font-size: .52rem; font-family: 'Courier New', monospace;
  font-weight: 700; letter-spacing: .06em;
  padding: 1px 4px; border-radius: 2px;
  display: inline-block; line-height: 1.5; flex-shrink: 0;
}
.dsg-online  { background: rgba(55,150,65,.22); color: #78d885; border: 1px solid rgba(55,150,65,.52); }
.dsg-offline { background: rgba(30,26,16,.50);  color: #5a5040; border: 1px solid #2a2618; }
.dsg-active-mark { color: #90c888; font-size: .62rem; margin-left: 3px; font-weight: bold; }
.dsg-cell {
  width: 18px;
  text-align: center;
  font-size: .80rem;
  line-height: 1.8;
  flex-shrink: 0;
}
.dsg-hdr { color: #8a7a60; font-size: .68rem; font-weight: bold; letter-spacing: .04em; }
.dsg-na  { color: #4a4030; font-size: .55rem; }
.dsg-owned  { opacity: 1; }
.dsg-needed { opacity: .45; }
@keyframes dsg-cell-pulse {
  0%, 100% { filter: brightness(0.55); }
  50%       { filter: brightness(1.50); }
}
.dsg-cell-pulse { animation: dsg-cell-pulse 1.3s ease-in-out infinite; }
.dsg-connectivity {
  font-size: .59rem; color: #a07a50; font-style: italic;
  padding: 1px 0 3px 2px;
}
.dash-struct-effect {
  font-size: .62rem;
  color: #9a8a6a;
  margin-bottom: 3px;
}
.dash-struct-reqs { margin-top: 3px; }
.dash-struct-req-row {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: .63rem;
  padding: 1px 0;
}
.req-check { color: #5a9a5a; font-weight: bold; }
.req-cross { color: #9a5a4a; font-weight: bold; }
.req-name { color: #7a6a50; }
.req-name.owned { color: #8aaa80; }
.dash-struct-missing {
  font-size: .62rem;
  color: #9a7040;
  font-style: italic;
  margin-top: 3px;
  padding-top: 3px;
  border-top: 1px solid #1e1a10;
}
.dash-struct-gap-hint {
  font-size: .60rem;
  color: #5588aa;
  margin-top: 2px;
}

/* ── Debug Panel — clearly auxiliary, visually separated from game UI ──── */
#debug-panel {
  padding: 8px 9px;
  background: rgba(0,0,0,.28);
  border: 1px solid #1e1808;
  border-top: 2px solid #2a1e0c;
  border-radius: 3px;
  margin-top: 4px;
}
#debug-panel .lbl {
  color: #5a4a2e;
  letter-spacing: .08em;
  border-bottom-color: #1e1808;
}

/* Mode-banner modes for captain abilities */
#mode-banner.repair-active {
  border-color: #3070a0; background: rgba(30,100,180,.11); color: #70b8f0;
}
#mode-banner.railroad-active,
#mode-banner.mode-banner-railroad {
  border-color: #2a6040; background: rgba(20,80,50,.13); color: #50e090;
}
.rail-dir-btn {
  display: inline-block;
  margin: 0 4px;
  padding: 3px 10px;
  background: rgba(40,160,90,.15);
  border: 1px solid rgba(60,180,110,.35);
  border-radius: 3px;
  color: #50e090;
  font-family: 'Courier New', monospace;
  font-size: .75rem;
  font-weight: 700;
  cursor: pointer;
  transition: background .12s;
}
.rail-dir-btn:hover { background: rgba(40,160,90,.32); border-color: rgba(80,220,140,.55); }

/* Opponent summary strip at bottom of left panel */
.dash-opponent-strip {
  padding: 6px 10px;
  border-top: 1px solid #2a2218;
  font-size: .66rem;
}
.dash-opp-header {
  color: #4a3a28;
  font-size: .62rem;
  font-variant: small-caps;
  letter-spacing: .06em;
  margin-bottom: 3px;
}
.dash-opp-row {
  display: flex;
  justify-content: space-between;
  padding: 1px 0;
  font-family: 'Courier New', monospace;
}
.dash-opp-key { color: #3a2e1e; }
.dash-opp-val { color: #6a5a40; }

/* ══════════════════════════════════════════════════════════════════════════
   UI CLARITY PASS — Action Hover Previews, Structure Hovers, Dual Captains
══════════════════════════════════════════════════════════════════════════ */

/* ── Dual Captain Panel States — static, no pulsing ───────────────────── */
.dash-captain-card.captain-panel-active.pd {
  border-left: 3px solid rgba(160,40,40,.7);
  box-shadow: 0 0 10px rgba(160,40,40,.22);
}
.dash-captain-card.captain-panel-active.sm {
  border-left: 3px solid rgba(41,128,185,.7);
  box-shadow: 0 0 10px rgba(41,128,185,.22);
}
.dash-captain-card.captain-panel-inactive {
  opacity: 0.65;
  filter: brightness(0.80) saturate(0.6);
  transition: opacity 0.3s, filter 0.3s;
  padding: 8px 10px 6px;
}
.dash-captain-card.captain-panel-inactive:hover {
  opacity: 0.88;
  filter: brightness(0.95) saturate(0.85);
}
.dash-captain-divider {
  height: 1px;
  background: linear-gradient(90deg, transparent, #3a2e18, transparent);
  margin: 0;
}
.dash-inactive-row {
  display: flex;
  justify-content: space-between;
  font-size: .64rem;
  padding: 1px 0;
  font-family: 'Courier New', monospace;
}
.dash-inactive-key { color: #3a2e1e; }
.dash-inactive-val { color: #5a4a38; }
.dash-inactive-ability {
  font-size: .61rem;
  color: #4a3a28;
  font-style: italic;
  margin-top: 3px;
  padding-top: 3px;
  border-top: 1px solid #1e1a10;
}

/* ── Action Hover Preview — tile highlights ────────────────────────────── */
@keyframes hover-pulse-claim {
  0%,100% { box-shadow: 0 0 0 4px #4aaa50, 0 0 12px #4aaa5099, 0 0 28px #4aaa5055; }
  50%     { box-shadow: 0 0 0 4px #4aaa50, 0 0 18px #4aaa50cc, 0 0 40px #4aaa5077; }
}
@keyframes hover-pulse-attack {
  0%,100% { box-shadow: 0 0 0 4px #c05050, 0 0 14px #c0505099, 0 0 30px #c0505055; }
  50%     { box-shadow: 0 0 0 4px #c05050, 0 0 22px #c05050cc, 0 0 44px #c0505077; }
}
@keyframes hover-pulse-reroll {
  0%,100% { box-shadow: 0 0 0 3px #c8a44c, 0 0 10px #c8a44c88; }
  50%     { box-shadow: 0 0 0 3px #c8a44c, 0 0 22px #c8a44ccc; }
}
@keyframes hover-pulse-deploy {
  0%,100% { box-shadow: 0 0 0 4px #c87830, 0 0 12px #c8783099, 0 0 26px #c8783055; }
  50%     { box-shadow: 0 0 0 4px #c87830, 0 0 20px #c87830cc, 0 0 38px #c8783066; }
}
@keyframes hover-pulse-rail {
  0%,100% { box-shadow: 0 0 0 3px #a0e890, 0 0 12px #a0e89099, 0 0 24px #a0e89044; }
  50%     { box-shadow: 0 0 0 3px #a0e890, 0 0 22px #a0e890cc, 0 0 38px #a0e89066; }
}
@keyframes attacker-pulse {
  0%,100% { box-shadow: 0 0 0 3px #e89020, 0 0 14px #e8902099, 0 0 28px #e8902055; }
  50%     { box-shadow: 0 0 0 3px #e89020, 0 0 24px #e89020cc, 0 0 44px #e8902077; }
}
.tile-hover-claim  { animation: hover-pulse-claim  1.1s ease-in-out infinite !important; z-index: 1; background-color: rgba(74,170,80,.12) !important; }
.tile-hover-attack { animation: hover-pulse-attack 1.1s ease-in-out infinite !important; z-index: 1; background-color: rgba(192,80,80,.12) !important; }
.tile-hover-reroll { animation: hover-pulse-reroll 1.1s ease-in-out infinite !important; z-index: 1; }
.tile-hover-deploy { animation: hover-pulse-deploy 1.1s ease-in-out infinite !important; z-index: 1; background-color: rgba(200,120,48,.10) !important; }
.tile-hover-deploy-rail { animation: hover-pulse-rail 1.1s ease-in-out infinite !important; z-index: 1; background-color: rgba(160,232,144,.16) !important; }
/* Dim tiles not highlighted during action hover */
.tile-hover-others-dim { filter: brightness(0.42) saturate(0.3) !important; transition: filter .15s; }
/* Attacker source tiles pulse strongly in combat mode */
.tile-attacker { animation: attacker-pulse 1.0s ease-in-out infinite !important; background-color: rgba(232,144,26,.11); }

/* ── Structure Hover — board participation highlights ──────────────────── */
@keyframes rail-hover-pulse {
  0%,100% { box-shadow: 0 0 0 3px #88dd88, 0 0 14px #88dd8899, 0 0 28px #88dd8844 !important; }
  50%     { box-shadow: 0 0 0 3px #88dd88, 0 0 28px #88dd88cc, 0 0 48px #88dd8866 !important; }
}
@keyframes rail-ext-pulse {
  0%,100% { box-shadow: 0 0 0 2px #88dd8888, 0 0 8px #88dd8855 !important; }
  50%     { box-shadow: 0 0 0 2px #88dd88aa, 0 0 18px #88dd8877 !important; }
}
.tile-hover-rail-extended { animation: rail-ext-pulse 1.6s ease-in-out infinite !important; background-color: rgba(136,221,136,.12) !important; border-style: dashed; }

/* ── Resource capacity display ──────────────────────────────────────── */
.res-capacity-table {
  margin-top: 7px;
}
.res-hdr {
  font-size: .63rem; font-weight: 700; letter-spacing: .07em; text-transform: uppercase;
  color: #8a7a58; margin-bottom: 4px; padding-bottom: 3px;
  border-bottom: 1px solid rgba(100,90,70,.28);
}
.res-hdr-sublbl {
  font-weight: 400; letter-spacing: .02em; text-transform: none;
  color: #5a5038; margin-left: 4px;
}
.res-row {
  display: flex; justify-content: space-between; align-items: center;
  padding: 2.5px 0;
  font-size: .72rem;
  line-height: 1.45;
}
.res-row-empty { opacity: .30; }
.res-row-strained .res-label { color: rgba(210,150,45,.90); }
.res-label { color: #9a8a6a; }
.res-nums  { display: flex; align-items: center; gap: 1px; }
.res-avail {
  font-weight: 700; min-width: 1.2em; text-align: right;
  color: #b0a888;
}
.res-avail-has  { color: #f0e8c8; }
.res-avail-zero { color: rgba(220,160,50,.95); }
.res-sep   { color: #7a6a52; padding: 0 2px; font-size: .67rem; }
.res-total { color: #8a7860; min-width: 1.2em; font-size: .67rem; }
.res-committed-badge {
  font-size: .58rem; color: rgba(200,140,40,.75);
  margin-left: 5px; letter-spacing: -.01em;
}

/* ── Board resource inventory ────────────────────────────────────────── */
.res-inventory {
  margin-top: 8px;
}
.res-inv-hdr {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  font-size: .78rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: #a89a72;
  margin-bottom: 5px;
  padding-bottom: 4px;
  border-bottom: 1px solid rgba(140,120,70,.40);
}
.res-inv-col-legend {
  display: flex;
  gap: 8px;
  font-weight: 700;
  letter-spacing: .05em;
  text-transform: none;
  font-family: 'Courier New', monospace;
  font-size: .75rem;
}
.res-inv-lbl-pd  { color: rgba(192,80,80,.90); }
.res-inv-lbl-sm  { color: rgba(70,140,204,.90); }
.res-inv-lbl-neu { color: #8a7860; }
.res-inv-row {
  display: flex;
  align-items: center;
  padding: 3.5px 0;
  font-size: .87rem;
  line-height: 1.45;
  border-bottom: 1px solid rgba(60,50,35,.50);
}
.res-inv-row:last-child { border-bottom: none; }
.res-inv-row-empty { opacity: .42; }
.res-inv-glyph {
  width: 1.6em;
  flex-shrink: 0;
  color: #c8a44c;
  font-family: 'Courier New', monospace;
  font-size: 1.05rem;
  text-shadow: 0 0 8px rgba(200,164,76,.25);
}
.res-inv-name {
  flex: 1;
  color: #9a8a6a;
  font-size: .80rem;
  font-variant: small-caps;
  letter-spacing: .04em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.res-inv-counts {
  display: flex;
  gap: 6px;
  font-family: 'Courier New', monospace;
  font-size: .87rem;
  font-weight: 700;
  flex-shrink: 0;
}
.res-inv-pd  { color: #c05050; min-width: 1.5em; text-align: right; }
.res-inv-sm  { color: #5599cc; min-width: 1.5em; text-align: right; }
.res-inv-neu { color: #8a7860; min-width: 1.5em; text-align: right; }
@keyframes tile-bombarded-flash-anim {
  0%   { background-color: rgba(255,120,0,.70) !important; box-shadow: 0 0 0 4px #ff6600, 0 0 24px #ff660099 !important; }
  60%  { background-color: rgba(180,80,0,.40) !important; box-shadow: 0 0 0 2px #c84400, 0 0 12px #c8440066 !important; }
  100% { background-color: transparent !important; box-shadow: none !important; }
}
.tile-bombarded-flash        { animation: tile-bombarded-flash-anim 0.8s ease-out forwards !important; }

/* ══════════════════════════════════════════════════════════════════════════
   PASS 2 — CUSTOM DICE FOUNDATION
   Stash hierarchy · Die inspection · Face visual language · Captain scale-back
══════════════════════════════════════════════════════════════════════════ */

/* ── Captain card ────────────────────────────────────────────────────────── */
.dash-captain-icon-big {
  font-size: 1.5rem;
}
.dash-captain-name {
  font-size: .97rem;
}
.dash-captain-tagline {
  font-size: .72rem;
  color: #8a7a60;
}

/* ── Stash section — strategic reserve hierarchy ─────────────────────────── */

/* Deployed-units indicator line */
.stash-deployed-note {
  font-size: .60rem;
  color: #8a7a50;
  font-family: 'Courier New', monospace;
  font-style: italic;
  padding: 1px 0 4px;
}

/* Elite group container */
.stash-elite-group {
  margin-top: 2px;
}

/* Group heading — thin label above the elite card list */
.stash-group-label {
  font-size: .52rem;
  font-family: 'Courier New', monospace;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: #6a5a3a;
  border-bottom: 1px solid #2a2010;
  padding-bottom: 2px;
  margin-bottom: 5px;
}

/* Tier badge — replaces the old single-letter type-key */
.stash-tier-badge {
  font-size: .50rem;
  font-family: 'Courier New', monospace;
  font-weight: 700;
  letter-spacing: .06em;
  padding: 1px 4px;
  border-radius: 2px;
  flex-shrink: 0;
  align-self: flex-start;
}
.stash-tier-badge.elite-badge {
  background: rgba(140,110,20,.22);
  color: #b89030;
  border: 1px solid rgba(160,130,28,.38);
}
/* Future placeholders — not yet rendered */
.stash-tier-badge.basic-badge {
  background: rgba(80,70,50,.22);
  color: #7a6a50;
  border: 1px solid rgba(80,70,50,.30);
}
.stash-tier-badge.captain-badge {
  background: rgba(60,100,60,.18);
  color: #70a870;
  border: 1px solid rgba(60,120,60,.32);
}
.stash-tier-badge.railroad-badge {
  background: rgba(30,100,60,.22);
  color: #50e090;
  border: 1px solid rgba(40,160,90,.38);
}
.stash-tier-badge.cultivation-badge {
  background: rgba(50,110,20,.22);
  color: #90d050;
  border: 1px solid rgba(80,160,30,.38);
}
.stash-tier-badge.test-badge {
  background: rgba(160,80,10,.22);
  color: #e09030;
  border: 1px solid rgba(200,120,20,.38);
}

/* Die card — improved spacing for visual breathing room */
.stash-die-card {
  padding: 6px 8px;
  margin-bottom: 6px;
}
.stash-die-card:last-child { margin-bottom: 0; }

/* Faces section — label + row inline */
.stash-faces-section {
  display: flex;
  align-items: center;
  gap: 5px;
  margin-bottom: 4px;
}
.stash-faces-label {
  font-size: .49rem;
  font-family: 'Courier New', monospace;
  color: #4a3a28;
  letter-spacing: .08em;
  flex-shrink: 0;
  padding-top: 1px;
}

/* Stats row — avg / range / deploy hint */
.stash-die-stats {
  display: flex;
  align-items: baseline;
  gap: 9px;
  padding-top: 4px;
  border-top: 1px solid #1e1a10;
}
.stash-stat-item {
  display: flex;
  gap: 2px;
  align-items: baseline;
}
.stash-stat-k {
  font-size: .51rem;
  color: #4a3a28;
  font-family: 'Courier New', monospace;
  letter-spacing: .03em;
}
.stash-stat-v {
  font-size: .65rem;
  color: #a09070;
  font-family: 'Courier New', monospace;
  font-weight: 700;
}
.stash-deploy-hint {
  margin-left: auto;
  font-size: .51rem;
  color: #5a4a30;
  font-family: 'Courier New', monospace;
  letter-spacing: .03em;
  font-style: italic;
}

/* Stash card hover — feel selectable (deployment planning) */
.stash-die-card:hover .stash-deploy-hint { color: #b89030; }
.stash-die-card:hover .stash-die-name    { color: #e8d898; }

/* Face value tier improvements — larger pips for stash readability */
.stash-die-faces .sf {
  width: 24px;
  height: 24px;
  font-size: .75rem;
}

/* ── Die Inspection Panel — strategic identity layout ─────────────────────── */

/* Identity block — name, tier, role */
.di-identity {
  padding-bottom: 6px;
  border-bottom: 1px solid #2a2218;
  margin-bottom: 5px;
}
.di-identity-header {
  display: flex;
  align-items: flex-start;
  gap: 6px;
}
.di-identity-icon {
  font-size: 1.1rem;
  line-height: 1.2;
  flex-shrink: 0;
}
.di-identity-icon.pd  { color: #c05050; }
.di-identity-icon.sm  { color: #5599cc; }
.di-identity-icon.neu { color: #6a5a40; }
.di-identity-name-block { flex: 1; min-width: 0; }
.di-identity-name {
  display: block;
  font-size: .84rem;
  font-weight: bold;
  font-variant: small-caps;
  letter-spacing: .06em;
  color: #c4b590;
  line-height: 1.2;
}
.di-identity-role {
  display: block;
  font-size: .58rem;
  color: #5a4a38;
  font-style: italic;
  margin-top: 1px;
}

/* Tier badge on inspection panel */
.di-tier-badge {
  font-size: .50rem;
  font-family: 'Courier New', monospace;
  font-weight: 700;
  letter-spacing: .06em;
  padding: 1px 4px;
  border-radius: 2px;
  flex-shrink: 0;
  align-self: flex-start;
  margin-top: 2px;
}
.di-tier-badge.tier-elite {
  background: rgba(140,110,20,.22); color: #b89030;
  border: 1px solid rgba(160,130,28,.38);
}
.di-tier-badge.tier-captain {
  background: rgba(60,100,60,.18); color: #70a870;
  border: 1px solid rgba(60,120,60,.32);
}
.di-tier-badge.tier-basic {
  background: rgba(80,70,50,.18); color: #6a5a40;
  border: 1px solid rgba(80,70,50,.28);
}
.di-tier-badge.tier-railroad {
  background: rgba(30,100,60,.22); color: #50e090;
  border: 1px solid rgba(40,160,90,.38);
}
.di-tier-badge.tier-cultivation {
  background: rgba(50,110,20,.22); color: #90d050;
  border: 1px solid rgba(80,160,30,.38);
}
.di-tier-badge.tier-test {
  background: rgba(160,80,10,.22); color: #e09030;
  border: 1px solid rgba(200,120,20,.38);
}

/* Status row — owner / position / flags */
.di-status-row {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  padding: 4px 0 5px;
  border-bottom: 1px solid #1e1a10;
  margin-bottom: 5px;
}
.di-status-item {
  display: flex;
  gap: 3px;
  align-items: baseline;
}
.di-status-k {
  font-size: .58rem;
  color: #5a4a30;
  font-family: 'Courier New', monospace;
}
.di-status-v {
  font-size: .68rem;
  color: #c4b590;
  font-family: 'Courier New', monospace;
}
.di-status-v.pd  { color: #c05050; }
.di-status-v.sm  { color: #5599cc; }
.di-status-v.neu { color: #6a5a40; }
.di-status-flag {
  font-size: .60rem;
  font-family: 'Courier New', monospace;
  font-weight: 700;
  padding: 1px 4px;
  border-radius: 2px;
}
.flag-ex { background: rgba(180,60,0,.22); color: #e07030; border: 1px solid rgba(180,60,0,.38); }
.flag-lk { background: rgba(180,150,30,.18); color: #c8a44c; border: 1px solid rgba(180,150,30,.35); }

/* Faces block — improved layout */
.di-faces-block {
  padding: 5px 0 5px;
  border-bottom: 1px solid #1e1a10;
  margin-bottom: 5px;
}
.di-faces-hdr {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: 4px;
}
.di-faces-title {
  font-size: .52rem;
  font-family: 'Courier New', monospace;
  color: #5a4a38;
  letter-spacing: .08em;
  text-transform: uppercase;
}
.di-faces-stats {
  font-size: .58rem;
  color: #6a5a40;
  font-family: 'Courier New', monospace;
}
.di-faces-stats strong { color: #a09070; }

/* Improved face pips — semantic tier coloring */
.di-faces-grid { margin-bottom: 4px; }
.face-pip.fp-zero { background: rgba(70,18,8,.55);  color: #804030; border-color: #3a1210; }
.face-pip.fp-low  { background: rgba(28,24,16,.70); color: #7a6a50; border-color: #2c2618; }
.face-pip.fp-mid  { background: rgba(40,34,20,.70); color: #a89870; border-color: #3c3018; }
.face-pip.fp-high { background: rgba(60,50,18,.65); color: #c8a44c; border-color: #584820; }
.face-pip.fp-max  {
  background: rgba(82,64,10,.60); color: #e8c060; border-color: #786020;
  text-shadow: 0 0 5px rgba(220,180,50,.45);
}
.face-pip.current {
  border-color: #c8a44c !important;
  box-shadow: 0 0 6px rgba(200,164,76,.55);
}

/* Active face prominent display */
.di-face-active {
  font-size: .62rem;
  color: #7a6a50;
  font-family: 'Courier New', monospace;
  margin-bottom: 4px;
}
.di-face-active-val {
  font-size: .90rem;
  font-weight: 700;
  color: #c8a44c;
  font-family: 'Courier New', monospace;
  text-shadow: 0 0 8px rgba(200,164,76,.4);
}

/* Face tier legend — color key */
.di-face-legend {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
}
.dfl-k {
  font-size: .50rem;
  font-family: 'Courier New', monospace;
}
.dfl-k.zero { color: #804030; }
.dfl-k.low  { color: #6a5a40; }
.dfl-k.mid  { color: #9a8a68; }
.dfl-k.high { color: #c8a44c; }
.dfl-k.max  { color: #e8c060; }

/* Future readiness block — placeholder rows, visually dim */
.di-future-block {
  padding: 5px 0 4px;
  border-bottom: 1px solid #1e1a10;
  margin-bottom: 5px;
}
.di-future-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: 1.5px 0;
  font-size: .62rem;
}
.di-future-k {
  font-size: .58rem;
  color: #4a3a28;
  font-family: 'Courier New', monospace;
  letter-spacing: .03em;
}
.di-future-v {
  color: #3a3020;
  font-family: 'Courier New', monospace;
  font-style: italic;
}

/* Debug section — clearly auxiliary */
.di-debug {
  padding-top: 4px;
  margin-top: 2px;
  opacity: .42;
}
.di-debug-lbl {
  font-size: .50rem;
  font-family: 'Courier New', monospace;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: #4a3a28;
  border-bottom: 1px solid #1e1a10;
  padding-bottom: 2px;
  margin-bottom: 3px;
}
.di-debug-row {
  display: flex;
  justify-content: space-between;
  font-size: .60rem;
  color: #4a3a28;
  font-family: 'Courier New', monospace;
  padding: 1px 0;
}

/* ── Game Events column (flex sibling between #summary and #board-col) ── */
#game-events-col {
  flex-shrink: 0;
  width: 250px;
  background: #14110d;
  border-right: 1px solid #5a4828;
  padding: 12px 8px;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.ge-lbl {
  font-size: .60rem;
  text-transform: uppercase;
  letter-spacing: .13em;
  color: #4a3a28;
  margin-bottom: 4px;
  flex-shrink: 0;
}
#game-events-panel {
  flex: 1;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 1px;
}
.ge-empty { font-style: italic; color: #2e2618; font-size: .69rem; }
.ge {
  font-size: .69rem;
  color: #7a6a4a;
  line-height: 1.5;
  padding: 1px 0;
  border-bottom: 1px solid #131208;
  white-space: normal;
  word-wrap: break-word;
}
.ge:last-child { border-bottom: none; }
.ge-separator   { color: #b09040; font-style: italic; }
.ge-claim       { color: #5a8a5a; }
.ge-move        { color: #6a8898; }
.ge-blocked     { color: #7a5a4a; }
.ge-reroll      { color: #888858; }
.ge-cultivation { color: #6a8848; }

/* ── Dice / Tile Inspector column ────────────────────────────────────────────── */
#inspector-col {
  flex-shrink: 0;
  width: 280px;
  background: #12100c;
  border-left: 1px solid #3a2e14;
  border-right: 1px solid #3a2e14;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.insp-col-lbl {
  flex-shrink: 0;
  font-size: .58rem;
  text-transform: uppercase;
  letter-spacing: .13em;
  color: #c8a44c;
  border-bottom: 1px solid #3a2e14;
  padding: 7px 10px 5px;
  background: #14110d;
}
#inspector-panel {
  flex: 1;
  overflow-y: auto;
  padding: 10px;
  display: flex;
  flex-direction: column;
  gap: 0;
}

/* Empty state */
.insp-empty {
  font-style: italic;
  color: #3a2e18;
  font-size: .72rem;
  padding: 4px 0;
}

/* ── Header block ── */
.insp-header {
  padding-bottom: 8px;
  border-bottom: 1px solid #2a2218;
  margin-bottom: 8px;
}
.insp-header-top {
  display: flex;
  align-items: flex-start;
  gap: 7px;
  margin-bottom: 6px;
}
.insp-icon {
  font-size: 1.15rem;
  line-height: 1.2;
  flex-shrink: 0;
}
.insp-icon.pd  { color: #c05050; }
.insp-icon.sm  { color: #5599cc; }
.insp-icon.neu { color: #6a5a40; }
.insp-name-block { flex: 1; min-width: 0; }
.insp-die-name {
  display: block;
  font-size: .88rem;
  font-weight: bold;
  font-variant: small-caps;
  letter-spacing: .06em;
  color: #c4b590;
  line-height: 1.2;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.insp-die-type {
  display: block;
  font-size: .60rem;
  color: #5a4a38;
  font-style: italic;
  margin-top: 2px;
  font-family: 'Courier New', monospace;
}
.insp-meta-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 12px;
  margin-bottom: 3px;
}
.insp-meta-item {
  display: flex;
  gap: 4px;
  align-items: baseline;
}
.insp-meta-k {
  font-size: .58rem;
  color: #4a3a28;
  font-family: 'Courier New', monospace;
  letter-spacing: .03em;
}
.insp-meta-v {
  font-size: .70rem;
  color: #c4b590;
  font-family: 'Courier New', monospace;
}
.insp-meta-v.pd  { color: #c05050; }
.insp-meta-v.sm  { color: #5599cc; }
.insp-meta-v.neu { color: #6a5a40; }
.insp-face-abbr  { color: #c8a44c; font-weight: bold; }
.insp-state-ok   { font-size: .70rem; font-family: 'Courier New', monospace; color: #6a9a6a; }
.insp-state-ex   { font-size: .70rem; font-family: 'Courier New', monospace; color: #e07030; font-weight: bold; }
.insp-state-pending { color: #b8a060; font-style: italic; }

/* ── Active face section ── */
.insp-active-section {
  padding-bottom: 8px;
  border-bottom: 1px solid #2a2218;
  margin-bottom: 8px;
}
.insp-section-lbl {
  font-size: .52rem;
  font-family: 'Courier New', monospace;
  text-transform: uppercase;
  letter-spacing: .10em;
  color: #5a4a38;
  margin-bottom: 5px;
}
.insp-section-hint {
  font-size: .50rem;
  color: #3a2e18;
  text-transform: none;
  letter-spacing: .02em;
  font-style: italic;
}
.insp-af-nameline {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin-bottom: 3px;
}
.insp-af-name {
  font-size: .84rem;
  font-weight: bold;
  font-variant: small-caps;
  color: #c4b590;
  letter-spacing: .04em;
}
.insp-af-cv {
  font-size: .68rem;
  font-family: 'Courier New', monospace;
  color: #c8a44c;
  font-weight: bold;
}
.insp-af-ability {
  font-size: .70rem;
  color: #a09060;
  font-style: italic;
  margin-bottom: 4px;
  font-family: 'Courier New', monospace;
}
.insp-af-no-ability {
  font-size: .62rem;
  color: #4a3a28;
  font-style: italic;
  margin-bottom: 4px;
}
.insp-af-desc {
  font-size: .68rem;
  color: #7a6a50;
  line-height: 1.55;
}

/* ── Six-face section ── */
.insp-six-section {
  padding-bottom: 6px;
}
.insp-face-row {
  display: flex;
  gap: 5px;
  flex-wrap: wrap;
  margin-bottom: 6px;
}
.insp-face-box {
  width: 38px;
  height: 34px;
  border: 1px solid #3a2e14;
  border-radius: 3px;
  background: #1a1510;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: .62rem;
  font-family: 'Courier New', monospace;
  color: #6a5a40;
  cursor: pointer;
  user-select: none;
  transition: border-color .1s, color .1s, background .1s;
}
.insp-face-box:hover {
  border-color: #7a6a40;
  color: #c4b590;
  background: #201c14;
}
.insp-face-box-active {
  border-color: #c8a44c !important;
  background: #2a2010 !important;
  color: #c8a44c !important;
  box-shadow: 0 0 6px rgba(200,164,76,.4);
}
.insp-face-box-open {
  border-color: #7a9aaa !important;
  background: #101820 !important;
  color: #8ac8e8 !important;
  box-shadow: 0 0 5px rgba(80,160,200,.3);
}
.insp-face-box-active.insp-face-box-open {
  border-color: #c8a44c !important;
  background: #202810 !important;
  color: #c8e060 !important;
  box-shadow: 0 0 8px rgba(200,164,76,.5);
}

/* ── Expanded face detail ── */
.insp-fd {
  background: #0e0c0a;
  border: 1px solid #2a2218;
  border-radius: 3px;
  padding: 7px 9px;
  margin-top: 2px;
}
.insp-fd-active {
  border-color: #4a4020;
  background: #121008;
}
.insp-fd-hdr {
  display: flex;
  align-items: baseline;
  gap: 7px;
  margin-bottom: 4px;
}
.insp-fd-num {
  font-size: .56rem;
  font-family: 'Courier New', monospace;
  color: #4a3a28;
  letter-spacing: .04em;
}
.insp-fd-name {
  font-size: .78rem;
  font-weight: bold;
  font-variant: small-caps;
  color: #c4b590;
  letter-spacing: .04em;
}
.insp-fd-cv {
  font-size: .62rem;
  font-family: 'Courier New', monospace;
  color: #c8a44c;
  margin-left: auto;
}
.insp-fd-ability-name {
  font-size: .68rem;
  font-family: 'Courier New', monospace;
  color: #90a070;
  font-style: italic;
  margin-bottom: 4px;
}
.insp-fd-no-ability {
  font-size: .62rem;
  color: #3a2e18;
  font-style: italic;
  margin-bottom: 4px;
}
.insp-fd-desc {
  font-size: .67rem;
  color: #6a5a40;
  line-height: 1.55;
}

/* ── Inspector tier badge — test ── */
.di-tier-badge.tier-test,
.insp-die-type.tier-test { color: #e09030; }

/* ── Basic tile note ── */
.insp-basic-note {
  font-size: .65rem;
  color: #3a2e18;
  font-style: italic;
  line-height: 1.5;
  margin-top: 4px;
}

/* ── Inspector: static (non-interactive) face box for terrain values ── */
.insp-face-static {
  cursor: default !important;
}
.insp-face-static:hover {
  border-color: #3a2e14 !important;
  color: #6a5a40 !important;
  background: #1a1510 !important;
}
.insp-face-static.insp-face-box-active:hover {
  border-color: #c8a44c !important;
  background: #2a2010 !important;
  color: #c8a44c !important;
}

/* ── Inspector: Conductor direction picker ── */
.insp-cond-section {
  padding: 8px 10px;
  border: 1px solid rgba(80,200,120,.3);
  border-radius: 3px;
  background: rgba(40,80,50,.12);
  margin-bottom: 6px;
}
.insp-cond-hint {
  font-size: .65rem;
  color: #6a8a6a;
  margin: 3px 0 6px;
}
.insp-cond-btns {
  display: flex;
  gap: 5px;
  flex-wrap: wrap;
}

/* ── Inspector: Run the Line state section ── */
.insp-rail-state {
  padding: 6px 0 4px;
  border-top: 1px solid #2a2218;
  margin-bottom: 4px;
}
.insp-rail-state-note {
  font-size: .62rem;
  color: #6a7a6a;
  font-style: italic;
  margin-top: 3px;
  padding-left: 2px;
}

/* ── Inspector: Guard the Grove / buff section ── */
.insp-buff-section {
  padding: 6px 0 4px;
  border-top: 1px solid #2a2218;
  margin-bottom: 4px;
}
.insp-buff-item {
  font-size: .68rem;
  color: #8dc88d;
  padding: 2px 0 1px 2px;
  line-height: 1.35;
}

/* ══════════════════════════════════════════════════════════════════════════
   Dice Control — reroll cost + physical rotation controls (Dice Control pass)
   Rendered by ui/renderDiceInspector.js for any die with an authored physical
   D6 topology. Adjacent destinations (1 token) and the opposite one (2 tokens)
   are visually distinct so the price is readable before the click, and the
   disabled state is genuine — a greyed control is one the rules would refuse.
   ══════════════════════════════════════════════════════════════════════════ */
.insp-dice-section {
  padding: 6px 0 5px;
  border-top: 1px solid #2a2218;
  margin-bottom: 4px;
}
.insp-dice-sub {
  font-size: .54rem;
  font-family: 'Courier New', monospace;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: #6a5a40;
  margin: 6px 0 4px;
}
.insp-dice-note {
  font-size: .58rem;
  color: #8a5a3a;
  padding: 2px 0 0 2px;
  line-height: 1.3;
}
.insp-dice-btn {
  font-family: 'Courier New', monospace;
  font-size: .62rem;
  color: #c4b590;
  background: #1a1510;
  border: 1px solid #3a2e14;
  border-radius: 3px;
  padding: 5px 7px;
  cursor: pointer;
  transition: border-color .1s, color .1s, background .1s;
}
.insp-dice-btn:hover:not(:disabled) {
  border-color: #c8a44c;
  color: #e0cf9c;
  background: #241d10;
}
.insp-dice-btn:disabled {
  opacity: .42;
  cursor: not-allowed;
  color: #6a5a40;
}
.insp-dice-reroll {
  display: block;
  width: 100%;
  text-align: left;
  border-color: #4a5e6a;
  color: #9ab8c8;
}
.insp-dice-reroll:hover:not(:disabled) {
  border-color: #7a9aaa;
  color: #cfe4ef;
  background: #101820;
}
.insp-rot-row {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}
.insp-rotate-btn {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1px;
  min-width: 88px;
  flex: 1 1 88px;
  line-height: 1.2;
}
.insp-rot-pos {
  font-size: .50rem;
  letter-spacing: .08em;
  color: #6a5a40;
}
.insp-rot-name { font-size: .64rem; }
.insp-rot-meta {
  font-size: .52rem;
  color: #7a6a50;
}
/* Opposite-face control reads as the premium, 2-token option. */
.insp-rot-row-opposite .insp-rotate-btn {
  border-color: #6a4a2a;
}
.insp-rot-row-opposite .insp-rotate-btn:hover:not(:disabled) {
  border-color: #c88a4c;
  background: #241a10;
}
/* Physical cube position tag on the six-face row — kept visually subordinate
   to the face abbreviation, because array index and physical position are
   deliberately separate concepts. */
.insp-face-pos {
  font-size: .44rem;
  color: #4a3e28;
  margin-left: 2px;
  letter-spacing: .04em;
}
.insp-face-box-active .insp-face-pos { color: #a08540; }

/* ══════════════════════════════════════════════════════════════════════════
   Generic event animation framework
   Transient classes auto-remove on animationend via animationUtils.js flashTileEl.
   Persistent rarity classes (.rarity-*) are set by renderTile and stay until
   the next renderBoard call.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── Persistent rarity — unit nameplate / collectible card treatment ─────────
   Visual ownership model:
     Tile border       = ownership / selection / action (untouched)
     .unit-nameplate   = rarity / unit identity — a card sitting on the tile
     .tile-type-letter = unit glyph, gets rarity-colored halo
   Rarity palette (user-specified):
     Common = grey/iron  Uncommon = blue  Rare = purple
     Epic = gold         Legendary = platinum
   .unit-nameplate is injected by renderTile only for custom dice (railroad /
   cultivation / preservation / elite / testDie). Terrain and captain tiles
   receive no nameplate and are visually unchanged.                        ── */

/* ── Base nameplate layout ── */
.unit-nameplate {
  flex: 1;
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  border-radius: 3px;
  padding: 3px 2px 3px;
  position: relative;          /* anchor for ::before / ::after ornaments */
}
/* Prevent tile-center flex-grow inside nameplate context */
.unit-nameplate > .tile-center { flex: 0 0 auto; }
/* Default name label colour for dark nameplate backgrounds */
.unit-nameplate .tile-name-label { color: rgba(210,206,198,.84); }

/* ── Common — iron/grey nameplate, polished but simple ── */
.rarity-common .unit-nameplate {
  background: rgba(175,170,162,.34);
  border: 1.5px solid rgba(162,158,150,.60);
  box-shadow: 0 1px 4px rgba(0,0,0,.55),
              inset 0 1px 0 rgba(255,255,255,.12);
}
.rarity-common .unit-nameplate .tile-name-label { color: rgba(218,214,206,.90); }

/* ── Uncommon — cobalt blue nameplate, clearly framed ── */
.rarity-uncommon .unit-nameplate {
  background: rgba(44,114,222,.38);
  border: 1.5px solid rgba(68,145,242,.72);
  box-shadow: 0 0 9px  rgba(52,136,238,.34),
              0 1px 4px rgba(0,0,0,.55),
              inset 0 0 8px rgba(68,145,242,.20);
}
.rarity-uncommon .unit-nameplate .tile-name-label { color: rgba(152,200,255,.94); }

/* ── Rare — deep purple nameplate + bottom-corner ◆ ornaments ── */
.rarity-rare .unit-nameplate {
  background: rgba(138,50,232,.40);
  border: 2px solid rgba(162,76,248,.78);
  box-shadow: 0 0 11px rgba(148,62,242,.42),
              0 1px 4px rgba(0,0,0,.55),
              inset 0 0 10px rgba(152,68,242,.24);
}
.rarity-rare .unit-nameplate .tile-name-label { color: rgba(214,174,255,.96); }
.rarity-rare .unit-nameplate::before {
  content: '◆';
  position: absolute; bottom: 2px; left: 3px;
  font-size: 6px; line-height: 1; pointer-events: none; z-index: 4;
  color: rgba(162,76,248,.80);
}
.rarity-rare .unit-nameplate::after {
  content: '◆';
  position: absolute; bottom: 2px; right: 3px;
  font-size: 6px; line-height: 1; pointer-events: none; z-index: 4;
  color: rgba(162,76,248,.80);
}

/* ── Epic — gold radiant nameplate + top crown ✦ + bottom ◆ ── */
.rarity-epic .unit-nameplate {
  background: linear-gradient(175deg, rgba(248,186,28,.44) 0%, rgba(218,142,8,.35) 100%);
  border: 2px solid rgba(248,192,40,.90);
  box-shadow: 0 0 13px rgba(248,190,28,.50),
              0 1px 4px rgba(0,0,0,.55),
              inset 0 0 12px rgba(248,186,20,.28);
}
.rarity-epic .unit-nameplate .tile-name-label { color: rgba(255,220,88,.98); }
.rarity-epic .unit-nameplate::before {
  content: '✦';
  position: absolute; top: -8px; left: 50%; transform: translateX(-50%);
  font-size: 12px; line-height: 1; pointer-events: none; z-index: 5;
  color: rgba(248,202,50,.98);
  text-shadow: 0 0 6px rgba(248,190,20,.92), 0 0 12px rgba(248,190,20,.50);
}
.rarity-epic .unit-nameplate::after {
  content: '◆';
  position: absolute; bottom: 2px; left: 50%; transform: translateX(-50%);
  font-size: 7px; line-height: 1; pointer-events: none; z-index: 4;
  color: rgba(248,192,40,.88);
}

/* ── Legendary — platinum nameplate + top ✦ crown + bottom ✦ + shimmer ── */
.rarity-legendary .unit-nameplate {
  background: linear-gradient(175deg,
    rgba(212,232,255,.48) 0%,
    rgba(180,210,250,.40) 50%,
    rgba(212,232,255,.48) 100%);
  border: 2.5px solid rgba(205,228,255,.94);
  box-shadow: 0 0 20px rgba(180,210,255,.62),
              0 1px 4px rgba(0,0,0,.55),
              inset 0 0 16px rgba(185,215,255,.36);
  animation: rarity-legendary-nameplate-shimmer 2.8s ease-in-out infinite;
}
.rarity-legendary .unit-nameplate .tile-name-label { color: rgba(224,242,255,.99); }
@keyframes rarity-legendary-nameplate-shimmer {
  0%,100% {
    border-color: rgba(205,228,255,.94);
    box-shadow: 0 0 20px rgba(180,210,255,.62), 0 1px 4px rgba(0,0,0,.55), inset 0 0 16px rgba(185,215,255,.36);
  }
  50% {
    border-color: rgba(235,250,255,.99);
    box-shadow: 0 0 28px rgba(200,232,255,.78), 0 1px 4px rgba(0,0,0,.55), inset 0 0 22px rgba(200,232,255,.50);
  }
}
.rarity-legendary .unit-nameplate::before {
  content: '✦';
  position: absolute; top: -10px; left: 50%; transform: translateX(-50%);
  font-size: 15px; line-height: 1; pointer-events: none; z-index: 5;
  color: rgba(222,242,255,.99);
  text-shadow: 0 0 8px rgba(185,215,255,.98), 0 0 16px rgba(185,215,255,.65);
  animation: rarity-legendary-crown-shimmer 2.8s ease-in-out infinite;
}
.rarity-legendary .unit-nameplate::after {
  content: '✦';
  position: absolute; bottom: -4px; left: 50%; transform: translateX(-50%);
  font-size: 9px; line-height: 1; pointer-events: none; z-index: 5;
  color: rgba(222,242,255,.92);
  text-shadow: 0 0 5px rgba(185,215,255,.90);
  animation: rarity-legendary-crown-shimmer 2.8s ease-in-out infinite;
}
@keyframes rarity-legendary-crown-shimmer {
  0%,100% { color: rgba(222,242,255,.99); text-shadow: 0 0 8px rgba(185,215,255,.98), 0 0 16px rgba(185,215,255,.65); }
  50%     { color: rgba(248,255,255,1.00); text-shadow: 0 0 12px rgba(215,240,255,1.0), 0 0 24px rgba(185,215,255,.82); }
}

/* ── Unit glyph rarity halo ──
   Placed after die-type .tile-type-letter rules so cascade order wins.
   Replaces the die-type glow with a rarity-palette glow.                ── */
.rarity-common .tile-type-letter {
  text-shadow: 0 2px 6px rgba(0,0,0,.85), 0 0 9px rgba(175,170,160,.70);
}
.rarity-uncommon .tile-type-letter {
  text-shadow: 0 2px 6px rgba(0,0,0,.85), 0 0 12px rgba(55,138,238,.82);
}
.rarity-rare .tile-type-letter {
  text-shadow: 0 2px 6px rgba(0,0,0,.85), 0 0 14px rgba(155,65,245,.86), 0 0 24px rgba(155,65,245,.44);
}
.rarity-epic .tile-type-letter {
  text-shadow: 0 2px 6px rgba(0,0,0,.85), 0 0 16px rgba(248,188,25,.92), 0 0 28px rgba(248,188,25,.50);
}
.rarity-legendary .tile-type-letter {
  text-shadow: 0 2px 6px rgba(0,0,0,.85), 0 0 18px rgba(210,230,255,.94), 0 0 32px rgba(185,212,255,.60);
  animation: rarity-legendary-glyph-shimmer 2.8s ease-in-out infinite;
}
@keyframes rarity-legendary-glyph-shimmer {
  0%,100% { text-shadow: 0 2px 6px rgba(0,0,0,.85), 0 0 18px rgba(210,230,255,.94), 0 0 32px rgba(185,212,255,.60); }
  50%     { text-shadow: 0 2px 6px rgba(0,0,0,.85), 0 0 24px rgba(235,250,255,1.00), 0 0 42px rgba(200,230,255,.76); }
}

/* ── Entry: tile slides up and fades in on deploy ── */
@keyframes anim-enter-kf {
  from { opacity: 0; transform: translateY(6px) scale(.93); }
  to   { opacity: 1; transform: translateY(0)   scale(1);   }
}
.anim-enter { animation: anim-enter-kf .32s ease-out forwards; }

/* ── Arrival reveal pulses — dramatic multi-flash keyed to rarity tier ──
   Applied transiently by flashDeployRarity after slide-in completes.
   Each rarity tier pulses more times and more intensely.
   The pulse targets filter:brightness + scale so it reads on dark tile backgrounds.
   animationend removes the class; rarity-frame then holds the persistent look. */
@keyframes anim-arrive-common-kf {
  0%,100% { filter: brightness(1);   transform: scale(1);    }
  50%     { filter: brightness(1.45); transform: scale(1.04); }
}
@keyframes anim-arrive-uncommon-kf {
  0%,100% { filter: brightness(1);   transform: scale(1);    }
  50%     { filter: brightness(1.65) saturate(1.2); transform: scale(1.05); }
}
@keyframes anim-arrive-rare-kf {
  0%,100% { filter: brightness(1);   transform: scale(1);    }
  50%     { filter: brightness(1.85) saturate(1.3); transform: scale(1.06); }
}
@keyframes anim-arrive-epic-kf {
  0%,100% { filter: brightness(1);   transform: scale(1);    }
  50%     { filter: brightness(2.10) saturate(1.5); transform: scale(1.08); }
}
@keyframes anim-arrive-legendary-kf {
  0%,100% { filter: brightness(1);   transform: scale(1);    }
  50%     { filter: brightness(2.40) saturate(1.8); transform: scale(1.10); }
}
/* iteration counts scale with rarity (2→5) so higher-rarity reveals feel weightier */
.anim-arrive-common    { animation: anim-arrive-common-kf    .30s ease-in-out 2 forwards; z-index: 5; }
.anim-arrive-uncommon  { animation: anim-arrive-uncommon-kf  .28s ease-in-out 3 forwards; z-index: 5; }
.anim-arrive-rare      { animation: anim-arrive-rare-kf      .26s ease-in-out 4 forwards; z-index: 5; }
.anim-arrive-epic      { animation: anim-arrive-epic-kf      .24s ease-in-out 5 forwards; z-index: 5; }
.anim-arrive-legendary { animation: anim-arrive-legendary-kf .22s ease-in-out 5 forwards; z-index: 5; }

/* ── Actor pulse: unit taking an action ── */
@keyframes anim-actor-pulse-kf {
  0%,100% { box-shadow: none; }
  50%     { box-shadow: inset 0 0 0 2px rgba(232,200,80,.85), 0 0 10px rgba(232,200,80,.4); }
}
.anim-actor-pulse { animation: anim-actor-pulse-kf .55s ease-in-out forwards; }

/* ── Target pulse: tile receiving an effect ── */
@keyframes anim-target-pulse-kf {
  0%,100% { box-shadow: none; }
  50%     { box-shadow: inset 0 0 0 2px rgba(220,80,80,.85), 0 0 10px rgba(220,80,80,.4); }
}
.anim-target-pulse { animation: anim-target-pulse-kf .55s ease-in-out forwards; }

/* ── Status badge applied (e.g. Recorded, Indexed) ── */
@keyframes anim-status-pulse-kf {
  0%   { filter: brightness(1); }
  35%  { filter: brightness(1.55) saturate(1.4); }
  100% { filter: brightness(1); }
}
.anim-status-pulse { animation: anim-status-pulse-kf .6s ease-out forwards; }

/* ── Tile conversion (terrain type change) ── */
@keyframes anim-tile-convert-kf {
  0%   { filter: brightness(1)    saturate(1); }
  30%  { filter: brightness(1.45) saturate(.3) sepia(.6); }
  100% { filter: brightness(1)    saturate(1); }
}
.anim-tile-convert { animation: anim-tile-convert-kf .75s ease-out forwards; }

/* ═══════════════════════════════════════════════════════════════════════════
   ACTION-INTERCEPTION NOTICE (Playtest Correction Pass 2)
   ═══════════════════════════════════════════════════════════════════════════
   One transient card directly above the board, rendered by ui/actionNotice.js
   from a single structured notice object. The Game Events column stays the
   permanent record; this says what just happened, where the player is looking.
   Severity drives the accent only — layout is identical for all four so a
   blocked and a resolved notice cannot be confused by shape alone. */
#action-notice.an-empty { display: none; }
#action-notice.an-live  { display: block; margin: 0 0 6px; }

.an-card {
  border: 1px solid #8b6914;
  border-left-width: 5px;
  border-radius: 3px;
  background: linear-gradient(180deg, #221a0c 0%, #1a1408 100%);
  box-shadow: 0 2px 10px rgba(0, 0, 0, .45);
  padding: 6px 9px 7px;
  animation: an-appear .22s ease-out;
}
@keyframes an-appear {
  0%   { opacity: 0; transform: translateY(-5px); }
  100% { opacity: 1; transform: translateY(0); }
}

.an-head {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 3px;
}
.an-glyph { font-size: .95rem; line-height: 1; }
.an-title {
  flex: 1;
  font-size: .8rem;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: #e0c877;
}
.an-dismiss {
  flex: 0 0 auto;
  background: none;
  border: 1px solid #5a4a24;
  border-radius: 2px;
  color: #a89464;
  font-size: .62rem;
  line-height: 1;
  padding: 2px 5px;
  cursor: pointer;
}
.an-dismiss:hover { color: #e8d9a8; border-color: #8b6914; background: rgba(139, 105, 20, .2); }

.an-body {
  font-size: .74rem;
  line-height: 1.45;
  color: #ddd0ae;
}
.an-detail {
  margin-top: 2px;
  font-size: .66rem;
  font-style: italic;
  line-height: 1.4;
  color: #a89464;
}
.an-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 8px;
  margin-top: 4px;
  font-family: 'Courier New', monospace;
  font-size: .6rem;
  color: #8a7a54;
}
.an-meta .an-action { color: #c8a44c; font-weight: 700; }

/* ═══════════════════════════════════════════════════════════════════════════
   CONSERVATORY INTERRUPTION (Pass 5)
   ───────────────────────────────────────────────────────────────────────────
   A decision, not a report. It sits directly above the board and above the
   action notice, and is deliberately the loudest transient surface in the
   layout: it appears during the OPPONENT's turn, addressed to a player who has
   not clicked anything, and a player who misses it stalls the game. Hence the
   full-width panel, the pulsing accent, and the two unmissable buttons —
   everything the quieter .an-card notice below it deliberately is not.
   ═══════════════════════════════════════════════════════════════════════════ */
#conservatory-prompt.cons-empty { display: none; }
#queens-directive-prompt.qd-empty { display: none; }

/* FIXED, NOT IN FLOW — and that is a correctness fix, not a style choice.
   #board-col is a centred flex column with overflow:hidden, so a tall child
   overflows EQUALLY in both directions and the top of it is silently clipped.
   Live playtest of this pass caught exactly that: the headline naming the
   defending Captain, the sentence describing the attempt, and the cost line
   were all cut off, leaving a panel that opened mid-way through its own
   resource picker. Taking the panel out of flow is what makes "prominent, no
   scrolling required" true rather than merely intended — and a decision that
   halts play until it is answered is the one surface in this layout that has
   earned an overlay. */
#conservatory-prompt.cons-live {
  display: block;
  position: fixed;
  top: 96px;
  left: 50%;
  transform: translateX(-50%);
  width: min(720px, 92vw);
  max-height: calc(100vh - 120px);
  overflow-y: auto;
  z-index: 40;
  border: 2px solid #7a5fa8;
  border-left-width: 6px;
  border-radius: 3px;
  background: linear-gradient(180deg, #241a30 0%, #1a1224 100%);
  box-shadow: 0 6px 34px rgba(0, 0, 0, .78), 0 0 0 1px rgba(150, 120, 200, .18),
              0 0 0 100vmax rgba(6, 4, 10, .5);
  padding: 9px 13px 11px;
  animation: cons-appear .2s ease-out, cons-pulse 2.2s ease-in-out infinite .2s;
}
@keyframes cons-appear {
  0%   { opacity: 0; transform: translateY(-6px); }
  100% { opacity: 1; transform: translateY(0); }
}
@keyframes cons-pulse {
  0%, 100% { border-left-color: #7a5fa8; }
  50%      { border-left-color: #b394e0; }
}

.cons-head {
  display: flex;
  align-items: baseline;
  gap: 7px;
  margin-bottom: 4px;
}
.cons-glyph { font-size: 1rem; color: #c0a4e8; line-height: 1; }
.cons-title {
  flex: 1;
  font-size: .84rem;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: #d8c4f0;
}
.cons-where {
  font-family: 'Courier New', monospace;
  font-size: .62rem;
  color: #9880b8;
}

.cons-body   { font-size: .76rem; line-height: 1.45; color: #ded4ee; }
.cons-body strong { color: #f0e4ff; }
.cons-mech   { font-family: 'Courier New', monospace; color: #c0a4e8; }
.cons-cost   { margin-top: 4px; font-size: .7rem; line-height: 1.4; color: #b0a0c8; }
.cons-cost strong { color: #e0cef8; }

.cons-unfunded {
  margin-top: 5px;
  padding: 5px 7px;
  border-left: 3px solid #b03a2e;
  background: rgba(120, 40, 30, .18);
  font-size: .72rem;
  line-height: 1.45;
  color: #e8b8ae;
}

.cons-picker {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 4px;
  margin-top: 5px;
}
.cons-picker-lbl {
  min-width: 92px;
  font-size: .66rem;
  font-weight: 700;
  letter-spacing: .03em;
  text-transform: uppercase;
  color: #a890c8;
}
.cons-res-btn {
  background: rgba(120, 95, 168, .18);
  border: 1px solid #6a5490;
  border-radius: 2px;
  color: #d0c0e8;
  font-family: 'Courier New', monospace;
  font-size: .66rem;
  padding: 2px 6px;
  cursor: pointer;
}
.cons-res-btn:hover    { background: rgba(150, 120, 200, .3); color: #f0e4ff; }
.cons-res-btn.selected { background: #6a4f9a; border-color: #b394e0; color: #fff; font-weight: 700; }

.cons-status {
  margin-top: 5px;
  font-size: .68rem;
  font-style: italic;
  line-height: 1.4;
  color: #9880b8;
}
.cons-status-ready { font-style: normal; color: #9fd89f; }

.cons-actions { display: flex; gap: 8px; margin-top: 7px; }
.cons-btn {
  border-radius: 3px;
  font-size: .74rem;
  font-weight: 700;
  letter-spacing: .03em;
  padding: 5px 12px;
  cursor: pointer;
}
.cons-btn-protect {
  background: linear-gradient(180deg, #4a7a4a 0%, #365c36 100%);
  border: 1px solid #6aa86a;
  color: #eaffea;
}
.cons-btn-protect:hover:not(:disabled) { background: linear-gradient(180deg, #5a8f5a 0%, #427042 100%); }
.cons-btn-protect:disabled {
  background: #2a2a2a;
  border-color: #4a4a4a;
  color: #7a7a7a;
  cursor: not-allowed;
}
.cons-btn-allow {
  background: linear-gradient(180deg, #3a3348 0%, #2a2436 100%);
  border: 1px solid #6a5490;
  color: #d0c0e8;
}
.cons-btn-allow:hover { background: linear-gradient(180deg, #4a4058 0%, #362e46 100%); color: #f0e4ff; }

/* Board highlights while a decision is open, and when a Conservatory is
   inspected. The contested coordinate and the responding structure are called
   out separately so "what is being defended" and "by what" are answerable at a
   glance; the footprint ring answers "what would this protect?" on inspection,
   which is the question a player asks before building. */
.tile-conservatory-contested {
  outline: 2px solid #c04a4a !important;
  outline-offset: -2px;
  box-shadow: inset 0 0 12px rgba(200, 70, 70, .4) !important;
}
.tile-conservatory-source {
  outline: 2px solid #b394e0 !important;
  outline-offset: -2px;
  box-shadow: inset 0 0 12px rgba(150, 120, 200, .45) !important;
}
.tile-conservatory-footprint {
  outline: 1px dashed #9878c8 !important;
  outline-offset: -3px;
  background-image: linear-gradient(135deg, rgba(150, 120, 200, .14) 25%, transparent 25%,
                                    transparent 50%, rgba(150, 120, 200, .14) 50%,
                                    rgba(150, 120, 200, .14) 75%, transparent 75%);
  background-size: 8px 8px;
}

/* ── Face reach / Jurisdiction (Pass 6A) ─────────────────────────────────────
   "Where can this die's CURRENT face matter?" — context, never an invitation.

   Every choice here is about staying BELOW the actionable layers, because the
   one thing this must never do is look clickable:

     • NO outer glow. Every actionable state on this board announces itself with
       a box-shadow halo — claim green, attack red, target teal, selection gold.
       Reach has none, which is the single strongest signal that it is scenery.
     • Neutral graphite corner brackets, so reach never borrows either Captain's
       ownership hue or a locus colour.
     • Open corners against the Conservatory aura's full dashed perimeter and
       diagonal hatch. Different geometry and texture separate transient range
       from persistent protection even where they overlap.
     • No interior wash: terrain, ownership, character identity and status all
       remain readable through the notation.

   renderTile appends a dedicated child element so this layer composes with the
   tile's background and status pseudo-elements rather than replacing them. It
   sits at a low z-index so selection, targets and markers paint over it. */
/* ── Shared resource-requirement slots (Pass 6B) ──────────────────────────────
   One row of typed slots, used by every manual resource picker. Generalized
   from the Conservatory Protect prompt, which was already the clearest of the
   three implementations this pass consolidated.

   Each slot names its resource in full and shows 0/1 or 1/1 with the coordinate
   that filled it, so a player never has to infer which click counted as what —
   the single sharpest complaint the Pass 6B audit found. */
.rs-slots {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 4px 0 2px;
}
.rs-slot {
  display: inline-flex;
  align-items: baseline;
  gap: 5px;
  padding: 2px 7px;
  border: 1px dashed rgba(200, 170, 50, .55);
  border-radius: 2px;
  background: rgba(180, 150, 40, .08);
  font-size: .68rem;
  white-space: nowrap;
}
/* Filled reads as settled: solid border, brighter ground, a tick. The contrast
   with the dashed unfilled state is what makes progress readable at a glance. */
.rs-slot-filled {
  border-style: solid;
  border-color: rgba(210, 185, 70, .85);
  background: rgba(200, 170, 50, .18);
}
.rs-slot-name  { color: #d8c98a; letter-spacing: .02em; }
.rs-slot-count { color: #9a8c60; font-variant-numeric: tabular-nums; }
.rs-slot-filled .rs-slot-count { color: #e8d79a; }
.rs-slot-tile  { color: #b8a870; font-size: .62rem; }

/* One complete selection surface shared by ordinary abilities, optional
   payments, Litigation, and Conservatory. Amber deliberately matches the
   board's resource states; the surrounding prompt retains action identity. */
.rs-selection {
  width: min(100%, 46rem);
  box-sizing: border-box;
  margin: 6px auto;
  padding: 7px 9px;
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr);
  align-items: center;
  gap: 4px 10px;
  border: 1px solid rgba(200, 170, 50, .55);
  border-left: 3px solid #c8a43e;
  border-radius: 4px;
  background: linear-gradient(180deg, rgba(55, 46, 24, .72), rgba(34, 28, 16, .82));
  text-align: left;
}
.rs-selection-head {
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: #eadb9c;
}
.rs-selection .rs-slots { margin: 0; justify-content: flex-start; }
.rs-selection-status {
  grid-column: 1 / -1;
  font-size: .72rem;
  line-height: 1.35;
  color: #c9bc91;
}
.rs-selection-ready {
  border-left-color: #79a866;
  background: linear-gradient(180deg, rgba(43, 58, 29, .7), rgba(29, 39, 21, .8));
}
.rs-selection-ready .rs-selection-status { color: #b9d8a8; }
.rs-candidate-group {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 5px;
  margin: 5px 0;
}
.rs-candidate-label {
  min-width: 112px;
  font-size: .68rem;
  font-weight: 700;
  color: #d8c98a;
}
.rs-resource-choice {
  min-height: 28px;
  padding: 4px 8px;
  border: 1px dashed rgba(215, 185, 65, .82);
  border-radius: 3px;
  background: rgba(180, 150, 40, .13);
  color: #eadb9c;
  font-family: 'Courier New', monospace;
  font-size: .72rem;
  cursor: pointer;
}
.rs-resource-choice:hover,
.rs-resource-choice:focus-visible {
  border-style: solid;
  background: rgba(200, 170, 50, .28);
  outline: 2px solid rgba(235, 205, 90, .45);
  outline-offset: 1px;
}
.rs-resource-choice.selected {
  border-style: solid;
  border-color: #e0c052;
  background: rgba(200, 170, 50, .38);
  color: #fff4bf;
  font-weight: 700;
}

/* ── PASS 6D — THE ABILITY PROMPT COMPOSITION ──────────────────────────────

   Playtest: the generic ability/resource display "feels uneven / wonky" —
   centred prose with left-justified requirement boxes underneath it — while the
   Conservatory response dialog reads clearly. The cause is that #mode-banner is
   a centred small-caps text block, and Pass 6B's .rs-slots is a left-flowing
   flex row. Centred text over a left-aligned row has no shared axis, so nothing
   lines up with anything.

   This borrows the Conservatory dialog's HIERARCHY — title, then requirements,
   then one instruction, then the controls — without turning ordinary abilities
   into modals. The banner stays exactly where it is, in the same flow, at the
   same size; only its internal composition changes.

   The whole block is centred as a COLUMN: each part is centred on the same
   vertical axis, so the requirement slots sit under the title rather than
   escaping to the left edge. text-align is reset to left inside the parts that
   are sentences, because centred prose is what made this read as a
   development-UI readout in the first place. */
.fa-prompt {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  text-align: center;
}
/* Title — the ability's name is the loudest thing here, as it is in the
   Conservatory dialog's .cons-title. The glyph stays a quiet prefix. */
.fa-prompt-head {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 7px;
  flex-wrap: wrap;
}
.fa-prompt-glyph { opacity: .7; }
.fa-prompt-title {
  font-size: .92rem;
  font-weight: bold;
  letter-spacing: .05em;
  color: #c8e0a0;
}
/* Cost is supporting detail, not a headline — the named slots below say the
   same thing more precisely, so this stays small and quiet rather than
   competing with them. */
.fa-prompt-cost {
  font-size: .66rem;
  color: #7a8a60;
  font-variant: small-caps;
  letter-spacing: .08em;
}
/* The slots row now centres with everything else instead of hugging the left
   edge — the specific misalignment the playtest called wonky. */
.fa-prompt .rs-slots { justify-content: center; margin: 0; }
/* One concise instruction, in ordinary sentence case: small-caps prose is
   decorative on a title and hard to read on a sentence. */
.fa-prompt-status {
  font-size: .72rem;
  font-variant: normal;
  letter-spacing: .01em;
  color: #b8c8a0;
  max-width: 46em;
}
.fa-prompt-status.fa-prompt-ready { color: #9fd07a; }
/* A refusal must not look like an instruction. */
.fa-prompt-status.fa-prompt-refused { color: #e0906a; }
/* Controls on their own row, so Execute and Cancel are found in one place
   rather than trailing off the end of a sentence. */
.fa-prompt-actions {
  display: flex;
  gap: 8px;
  justify-content: center;
  flex-wrap: wrap;
  margin-top: 1px;
}

/* PASS 6D — PRIMARY vs DESTRUCTIVE, stated once for every prompt control.

   Execute/Begin are FILLED: they are the primary action and should read as the
   thing to click. Cancel is OUTLINED in the shared destructive red: unmissable,
   but never mistakable for the primary. This is the same pairing the
   Conservatory dialog uses for Protect vs Continue, and the same red as
   .mode-cancel-btn and #ds-cancel, so all four surfaces share one convention. */
#btn-face-ability-execute,
#btn-dispatch-begin,
#btn-litigation-confirm,
#btn-litigation-pay {
  padding: 4px 12px;
  font: inherit;
  font-size: .74rem;
  font-variant: small-caps;
  letter-spacing: .05em;
  cursor: pointer;
  border-radius: 3px;
  border: 1px solid #5a8f5a;
  background: linear-gradient(180deg, #4a7a4a 0%, #365c36 100%);
  color: #eaffea;
  transition: background .1s, border-color .1s;
}
#btn-face-ability-execute:hover,
#btn-dispatch-begin:hover,
#btn-litigation-confirm:hover,
#btn-litigation-pay:hover {
  background: linear-gradient(180deg, #5a8f5a 0%, #427042 100%);
  border-color: #6ea86e;
}
#btn-face-ability-cancel,
#btn-litigation-cancel {
  padding: 4px 12px;
  font: inherit;
  font-size: .74rem;
  font-variant: small-caps;
  letter-spacing: .05em;
  cursor: pointer;
  border-radius: 3px;
  border: 1px solid #a04030;
  background: rgba(180,60,40,.18);
  color: #e07060;
  transition: background .1s, border-color .1s, color .1s;
}
#btn-face-ability-cancel:hover,
#btn-litigation-cancel:hover {
  background: rgba(180,60,40,.35);
  border-color: #c05a48;
  color: #f09080;
}

/* Reach chip in the Dice Inspector's Active Face line. Matches the board
   overlay's slate-blue so the two read as one idea, and stays a quiet chip
   rather than a sentence — the authored ability text already states the range
   in prose, and this must not become a second copy of it. The Global and Local
   variants are the ONLY place those two reaches are communicated at all, since
   neither may honestly be drawn as a radius, so they are tinted apart. */
.insp-af-reach {
  margin-left: auto;
  padding: 1px 6px;
  border: 1px dotted rgba(120, 165, 210, .55);
  border-radius: 2px;
  background: rgba(96, 150, 205, .10);
  color: #9fc0dd;
  font-size: .62rem;
  letter-spacing: .04em;
  white-space: nowrap;
}
.insp-af-reach.insp-reach-global { border-color: rgba(200,164,76,.55); color: #d8b866; background: rgba(200,164,76,.10); }
.insp-af-reach.insp-reach-local  { border-color: rgba(150,120,200,.55); color: #b9a2dd; background: rgba(150,120,200,.10); }

/* Temporary reach is survey notation, not territory. Neutral graphite corner
   brackets preserve the terrain and ownership wash beneath them and cannot be
   confused with Steam Mechanic blue. No fill, no glow, no animation. */
.tile-reach-layer {
  position: absolute;
  inset: 4px;
  border: 0;
  background:
    linear-gradient(#665d4d, #665d4d) left top / 7px 1px no-repeat,
    linear-gradient(#665d4d, #665d4d) left top / 1px 7px no-repeat,
    linear-gradient(#665d4d, #665d4d) right top / 7px 1px no-repeat,
    linear-gradient(#665d4d, #665d4d) right top / 1px 7px no-repeat,
    linear-gradient(#665d4d, #665d4d) left bottom / 7px 1px no-repeat,
    linear-gradient(#665d4d, #665d4d) left bottom / 1px 7px no-repeat,
    linear-gradient(#665d4d, #665d4d) right bottom / 7px 1px no-repeat,
    linear-gradient(#665d4d, #665d4d) right bottom / 1px 7px no-repeat;
  opacity: .78;
  pointer-events: none;
  z-index: 0;
}

/* Severity accents. Border-left + title colour only — see the note above. */
.an-card.an-blocked   { border-left-color: #b03a2e; }
.an-card.an-blocked   .an-title { color: #e8836f; }
.an-card.an-surcharge { border-left-color: #a8802c; }
.an-card.an-surcharge .an-title { color: #e0be6a; }
.an-card.an-resolved  { border-left-color: #4a8a4a; }
.an-card.an-resolved  .an-title { color: #8fc48f; }
.an-card.an-info      { border-left-color: #4a7090; }
.an-card.an-info      .an-title { color: #86b4d6; }


/* ══════════════════════════════════════════════════════════════════════════
   COMMAND DECK (Scoring Pass 3B)

   One console row replacing three stacked full-width bands. Left to right it
   follows the order a player actually works in: what my position is, what I can
   do about it, and where I do it.

     [ scores ] [ actions ] [ context tray .......................... ]

   The whole deck is height-bounded and the tray scrolls internally, so a long
   stash can never push the board down the page again — which was the specific
   failure of the layout this replaces.
   ══════════════════════════════════════════════════════════════════════════ */

/* MIRRORED ABOUT THE WHEEL. Captain, score, wheel, score, Captain.
   The extra height over the old 152px cap comes from the board column, which is
   the element already designated to absorb resizing. */
#command-deck {
  display: grid;
  grid-template-columns: minmax(210px, 1fr) minmax(420px, 640px) minmax(210px, 1fr);
  gap: 10px;
  align-items: stretch;
  padding: 6px 12px 4px;
  background: #100d09;
  border-bottom: 1px solid #3a2e1a;
  flex-shrink: 0;
  max-height: 226px;
}
/* The live controls are MOVED into the active Captain's panel by
   ui/renderCaptainDeck.js, so they must not reserve layout where they are
   declared. */
#command-deck > #action-row,
#command-deck > #deploy-select-row { display: none; }

/* ── the shared mode strip, centred under the wheel ─────────────────────── */
#deck-banner {
  background: #100d09;
  border-bottom: 1px solid #3a2e1a;
  padding: 0 12px 5px;
  flex-shrink: 0;
  display: flex; justify-content: center;
}
#deck-banner #mode-banner { min-width: 0; max-width: 900px; }
#deck-banner #mode-banner:empty { display: none; }

/* ── one Captain's outer panel ──────────────────────────────────────────── */
.deck-side {
  display: flex; flex-direction: column; gap: 3px;
  min-width: 0; padding: 4px 8px;
  border: 1px solid #2a2216; border-radius: 4px;
  background: #14100a;
  transition: opacity .18s, border-color .18s;
}
/* WHOSE TURN IT IS, said by weight rather than by a label. The idle side is
   information; the lit side is the one that can act. */
.deck-active { border-color: #5a4a22; background: #191308; }
.deck-idle   { opacity: .5; }
.deck-pd.deck-active { border-color: #7a3028; }
.deck-sm.deck-active { border-color: #2f5a76; }

.dk-head { display: flex; align-items: baseline; gap: 6px; min-width: 0; }
.dk-icon { font-size: .95rem; line-height: 1; }
.dk-name {
  font-size: .66rem; font-variant: small-caps; letter-spacing: .07em;
  color: #d8cdb4; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.deck-pd .dk-name { color: #e08878; }
.deck-sm .dk-name { color: #8fc0e0; }
.dk-turn, .dk-waiting {
  font-size: .46rem; letter-spacing: .08em; color: #7d7364;
  margin-left: auto; white-space: nowrap;
}
.dk-waiting { font-style: italic; opacity: .8; }

/* ── tokens: big, countable pips ────────────────────────────────────────── */
.dk-tokens { display: flex; align-items: center; gap: 6px; }
.dk-pips { display: flex; gap: 4px; align-items: center; min-height: 14px; }
.dk-pip {
  width: 13px; height: 13px; border-radius: 50%;
  background: #4a4033; border: 1px solid #6a5c42;
}
.dk-tokens-active .dk-pip {
  background: #e0b64e; border-color: #f0d68e;
  box-shadow: 0 0 5px rgba(224,182,78,.5);
}
.dk-pip-none { font-size: .48rem; font-style: italic; color: #8a6a4a; }
.dk-token-label {
  font-size: .44rem; font-variant: small-caps; letter-spacing: .12em; color: #7d7364;
}

.dk-lit {
  font-size: .46rem; letter-spacing: .05em; padding: 1px 4px; border-radius: 2px;
  border: 1px solid #6a4a1a; color: #c8a44c; background: rgba(120,80,20,.14);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.dk-lit-burdened { border-color: #7a3028; color: #e08878; background: rgba(120,40,30,.14); }

/* ── action picker ─────────────────────────────────────────────────────── */
.dk-controls { display: flex; }
.dk-controls #action-row {
  display: grid; grid-template-columns: 1fr 1fr; gap: 3px; width: 100%;
}
.dk-actions-inert { display: grid; grid-template-columns: 1fr 1fr; gap: 3px; width: 100%; }
.dk-act {
  font-size: .52rem; padding: 3px 5px; border: 1px solid #3a3020; border-radius: 3px;
  color: #6a6252; background: #171208; text-align: center;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  user-select: none; pointer-events: none;
}

/* ── reserve ───────────────────────────────────────────────────────────── */
.dk-stash { min-width: 0; display: flex; flex-direction: column; gap: 2px; overflow: hidden; }
.dk-stash-head {
  display: flex; justify-content: space-between; gap: 6px;
  font-size: .44rem; font-variant: small-caps; letter-spacing: .1em; color: #7d7364;
}
.dk-reserve { white-space: nowrap; }
.dk-stash-empty { font-size: .48rem; font-style: italic; color: #6a6252; }
.dk-chips { display: flex; flex-wrap: wrap; gap: 2px; overflow: hidden; }
.dk-chip {
  display: flex; align-items: center; gap: 3px; min-width: 0;
  padding: 1px 4px; border: 1px solid #33291a; border-radius: 2px; background: #191308;
}
.dk-chip-icon { font-size: .6rem; line-height: 1; color: #c8a44c; }
.dk-chip-body { display: flex; flex-direction: column; min-width: 0; }
.dk-chip-name {
  font-size: .48rem; color: #cbbf9f; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}
.dk-chip-meta { font-size: .4rem; color: #7d7364; white-space: nowrap; }

/* THE RESERVE IS THE DEPLOY PICKER. While the picker shows, the inert chips
   stand down rather than competing with it for the same slot. */
.dk-stash:has(#deploy-select-row[style*="flex"]) .dk-chips,
.dk-stash:has(#deploy-select-row[style*="flex"]) .dk-stash-head { display: none; }
.dk-stash #deploy-select-row { flex-wrap: wrap; gap: 3px; }

@media (max-height: 760px) {
  #command-deck { max-height: 186px; padding: 4px 10px 3px; }
  .dk-pip { width: 11px; height: 11px; }
}

/* ── Column 1 · the two compact instruments ─────────────────────────────── */
#influence-display { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.infl-banner {
  font-size: .52rem;
  font-variant: small-caps;
  letter-spacing: .12em;
  color: #8a7a52;
  text-align: center;
  line-height: 1;
}
.infl-panels { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 4px; min-width: 0; }

/* Each instrument is one short row: a gauge, and a stacked body beside it. */
.infl-panel {
  display: grid;
  grid-template-columns: auto 1fr;
  grid-template-areas: "gauge body";
  gap: 0 7px;
  align-items: center;
  padding: 4px 7px;
  border: 1px solid #3a2e1a;
  border-left-width: 3px;
  border-radius: 3px;
  background: linear-gradient(180deg, #171309 0%, #120f0a 100%);
  min-width: 0;
}
.infl-pd { border-left-color: #8a3a3a; }
.infl-sm { border-left-color: #2980b9; }

.infl-gauge-wrap { grid-area: gauge; }
.infl-gauge { width: 62px; height: 46px; display: block; }
.infl-arc         { fill: none; stroke: #3d3320; stroke-width: 6; stroke-linecap: round; }
.infl-tick        { stroke: #6a5a38; stroke-width: 1.2; }
.infl-target-mark { stroke: #e0b84c; stroke-width: 2.2; }
.infl-needle      { stroke: #e8e0d0; stroke-width: 2; stroke-linecap: round; }
.infl-hub         { fill: #c8a44c; }
.infl-pd .infl-needle { stroke: #e08080; }
.infl-sm .infl-needle { stroke: #7fb8e8; }

/* THREE LINES BESIDE THE GAUGE, and that is the whole instrument:
     1. name + ACTIVE TURN + the one readout
     2. T / C / S + the short status
     3. both requirement rows, side by side
   Each of those was previously its own stacked block, which is what made the
   rejected cards tall enough to push the board down the page. */
.infl-body { grid-area: body; min-width: 0; display: flex; flex-direction: column; gap: 0; }

.infl-idline { display: flex; align-items: baseline; gap: 5px; min-width: 0; }
/* THE one prominent readout. Stated here and nowhere else in the instrument,
   pushed to the right of the identity so both share a single line. */
.infl-readout { margin-left: auto; display: flex; align-items: baseline; gap: 3px; white-space: nowrap; }
.infl-total { font-size: 1rem; font-weight: bold; color: #e8d79a; line-height: 1.15; }
.infl-of    { font-size: .58rem; color: #8a7a52; }

/* The source breakdown and the short status share line 2. */
.infl-sources {
  display: flex; align-items: baseline; gap: 4px; flex-wrap: wrap;
  font-size: .58rem; color: #7a6a4a; line-height: 1.3;
}
.infl-sources abbr { text-decoration: none; border-bottom: 1px dotted #5a4a30; cursor: help; }
.infl-src b { color: #d4c5a0; font-variant-numeric: tabular-nums; }
.infl-src-op,
.infl-src-divider { color: #6d5d3c; font-weight: 700; }
.infl-src-total { color: #45381f; font-weight: 800; font-variant-numeric: tabular-nums; }

.infl-state-line { font-size: .58rem; line-height: 1.3; }
/* Both requirement rows on one line; each wraps only if it truly must. */
.infl-reqs { display: flex; flex-wrap: wrap; gap: 2px 12px; }
.infl-headline { color: #d4c5a0; font-variant: small-caps; letter-spacing: .04em; }
.infl-sub      { color: #8a7a58; }
.infl-state-target-met-requirements-unmet .infl-headline { color: #e0a860; }
.infl-state-qualified-provisional .infl-headline         { color: #9fd07a; }
.infl-state-official-influence-win .infl-headline        { color: #b8e89a; font-weight: bold; }
.infl-state-official-other .infl-headline                { color: #c8a44c; }
.infl-overscale { font-size: .52rem; color: #d0a050; font-style: italic; }

/* Requirement lamps — one line each. Shape (filled vs hollow) and the words
   met / not met carry the state, so it survives greyscale and colour-vision
   deficiency without depending on the lamp colour. */
.infl-req { display: flex; align-items: baseline; gap: 3px; font-size: .56rem; color: #7a6a4a; line-height: 1.3; }
.infl-req-label { color: #6a5a3e; }
.infl-lamps { display: inline-flex; gap: 1px; }
.infl-lamp     { color: #4a3f28; font-size: .62rem; line-height: 1; }
.infl-lamp-lit { color: #e0b84c; text-shadow: 0 0 3px rgba(224,184,76,.5); }
.infl-req-count { color: #d4c5a0; font-variant-numeric: tabular-nums; }
.infl-req-state { font-variant: small-caps; letter-spacing: .05em; color: #a06a50; }
.infl-req-met .infl-req-state { color: #7fa86a; }
.infl-req-optional { font-style: italic; color: #6a5a40; }

/* ── ACTIVE-TURN ILLUMINATION ───────────────────────────────────────────────
   The active instrument must be unmistakable BEFORE its label is read, so the
   treatment stacks: a brighter Captain-coloured border, an outer glow, an inset
   pressure light, a lifted ground, and a slow pulse. The ACTIVE TURN chip stays
   regardless, because none of the above may be the only signal. */
.infl-name { font-size: .66rem; font-variant: small-caps; letter-spacing: .05em; }
.infl-pd .infl-name { color: #c05050; }
.infl-sm .infl-name { color: #5599cc; }
.infl-active-tag {
  font-size: .5rem; font-variant: small-caps; letter-spacing: .1em;
  border-radius: 2px; padding: 0 3px; margin-left: 4px; white-space: nowrap;
}
.infl-pd .infl-active-tag { color: #ffb0a0; border: 1px solid #c05050; background: rgba(192,80,80,.22); }
.infl-sm .infl-active-tag { color: #b0dcff; border: 1px solid #5599cc; background: rgba(85,153,204,.22); }

.infl-active { background: linear-gradient(180deg, #221a10 0%, #191309 100%); }
.infl-pd.infl-active {
  border-color: #c05050;
  box-shadow: 0 0 12px 2px rgba(192,80,80,.42), inset 0 0 14px rgba(192,80,80,.16);
  animation: inflPulsePd 3.4s ease-in-out infinite;
}
.infl-sm.infl-active {
  border-color: #5599cc;
  box-shadow: 0 0 12px 2px rgba(85,153,204,.42), inset 0 0 14px rgba(85,153,204,.16);
  animation: inflPulseSm 3.4s ease-in-out infinite;
}
@keyframes inflPulsePd {
  0%,100% { box-shadow: 0 0 10px 1px rgba(192,80,80,.34), inset 0 0 12px rgba(192,80,80,.13); }
  50%     { box-shadow: 0 0 16px 3px rgba(192,80,80,.55), inset 0 0 18px rgba(192,80,80,.22); }
}
@keyframes inflPulseSm {
  0%,100% { box-shadow: 0 0 10px 1px rgba(85,153,204,.34), inset 0 0 12px rgba(85,153,204,.13); }
  50%     { box-shadow: 0 0 16px 3px rgba(85,153,204,.55), inset 0 0 18px rgba(85,153,204,.22); }
}
/* Reduced motion keeps the border and the glow and drops only the movement:
   the illumination is information, the pulse is decoration. */
@media (prefers-reduced-motion: reduce) {
  .infl-pd.infl-active, .infl-sm.infl-active { animation: none; }
}

/* ── Column 2 · the vertical action stack ───────────────────────────────── */
#action-row {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 0;
  background: none;
  border: none;
  min-width: 0;
}
#action-row .abtn {
  display: block;
  width: 100%;
  flex: 1 1 0;
  margin: 0;
  text-align: center;
  padding: 4px 5px;
  font-size: .68rem;
  /* Deploy's label grows when a Signalman surcharge applies, so the button
     wraps to a second line rather than clipping or overflowing its column. */
  white-space: normal;
  line-height: 1.15;
  overflow-wrap: anywhere;
}
/* A disabled action must still read as an action that exists and is currently
   unavailable — never as an absence. */
#action-row .abtn:disabled { opacity: .55; }

/* ── Column 3 · the context tray ────────────────────────────────────────── */
#command-context {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
  border: 1px solid #3a2e1a;
  border-radius: 3px;
  background: linear-gradient(180deg, #14110c 0%, #100d09 100%);
  padding: 5px 8px;
  overflow-y: auto;               /* a long reserve scrolls HERE, not the page */
  overflow-x: hidden;
}
/* The relocated workflow surfaces keep their own ids and renderers; only the
   surrounding chrome is neutralised now that the tray supplies it. */
#command-context #mode-banner { margin: 0; text-align: center; }
/* THE TRAY YIELDS DECLARATIVELY. When a workflow banner or the deploy picker is
   showing, the default stash stands down — expressed in CSS rather than in a
   render pass because those two surfaces are shown by their OWN renderers, which
   do not always run the coordinated refresh. A render-driven rule would leave
   the stash stale for exactly one click; this cannot. commandContextState()
   remains the logical model the markup builder uses. */
#command-context:has(#mode-banner.active) #command-stash,
#command-context:has(#deploy-select-row[style*="display: flex"]) #command-stash { display: none !important; }
#command-context #deploy-select-row {
  flex-wrap: wrap;
  padding: 0;
  background: none;
  border: none;
}

.cs-head { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.cs-title { font-size: .62rem; font-variant: small-caps; letter-spacing: .08em; color: #c8a44c; }
.cs-reserve, .cs-deployed { font-size: .55rem; color: #7a6a4a; }
.cs-empty { font-size: .6rem; font-style: italic; color: #6a5a40; }

.cs-chips { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 3px; }
.cs-chip {
  display: flex; align-items: center; gap: 5px;
  padding: 2px 6px;
  border: 1px solid #3a2e1a;
  border-left-width: 2px;
  border-radius: 3px;
  background: #17130d;
  min-width: 0;
}
.cs-chip-icon { font-size: .8rem; color: #c8a44c; }
.cs-chip-body { display: flex; flex-direction: column; line-height: 1.15; min-width: 0; }
.cs-chip-name { font-size: .62rem; color: #d4c5a0; white-space: nowrap; }
.cs-chip-count { color: #e0b84c; margin-left: 3px; }
.cs-chip-meta { font-size: .52rem; color: #7a6a4a; white-space: nowrap; }
/* Family identity, matching the established locus colours. */
.cs-tier-elite        { border-left-color: #8b6914; }
.cs-tier-railroad     { border-left-color: #4aaa50; }
.cs-tier-cultivation  { border-left-color: #6a9a3a; }
.cs-tier-preservation { border-left-color: #8a6ac0; }
.cs-tier-exploration { border-left-color: #4d9ba7; }
.cs-tier-mutation     { border-left-color: #8fa83a; }
.cs-tier-test         { border-left-color: #6a6a6a; }

/* ── Narrow windows ─────────────────────────────────────────────────────── */
/* The tray drops below the score-and-action cluster rather than the scores
   reverting to two full-width cards, which is the shape this pass replaced. */
/* The mirrored deck needs roughly 880px (210 + 420 + 210 plus gaps), so it holds
   far longer than the old three-column tray did -- that 1500px breakpoint was
   written for a layout that no longer exists, and at 1280px it was dropping the
   whole score band into its own row. */
@media (max-width: 1040px) {
  /* Narrow: the two Captain panels sit side by side and the score band, wheel
     included, drops beneath them. The mirroring is a wide-screen affordance. */
  #command-deck {
    grid-template-columns: 1fr 1fr;
    grid-template-areas: "pd sm" "scores scores";
    max-height: 260px;
  }
  #deck-pd           { grid-area: pd; }
  #deck-sm           { grid-area: sm; }
  #influence-display { grid-area: scores; }
}
/* The old 118px short-screen cap and the .infl-gauge sizing belonged to the
   retired pressure gauges. The deck's own short-screen rule is declared with the
   rest of the deck above. */
.fa-prompt-top {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}
.fa-prompt-top .fa-prompt-head { justify-content: flex-start; }
.fa-prompt-top .fa-prompt-actions { margin-top: 0; flex-shrink: 0; }

@media (max-width: 620px) {
  .infl-panels { grid-template-columns: 1fr; }
  .rs-selection { width: 100%; grid-template-columns: 1fr; }
  .rs-selection-status,
  .rs-candidate-group { grid-column: 1; }
  .rs-candidate-label { flex-basis: 100%; min-width: 0; }
}

/* ══════════════════════════════════════════════════════════════════════════
   SURVEYOR'S CABINET — visual foundation

   The play surface is a map under study.  The header and command deck are the
   ebonized cabinet that contains it; reference panels are vellum folios; score
   gauges are enamel instruments.  Brass is reserved for joints, readings and
   thresholds.  Oxblood and mineral blue remain player/state accents rather
   than becoming the ground behind ordinary prose.
   ══════════════════════════════════════════════════════════════════════════ */
:root {
  --cab-ebon: #171511;
  --cab-wood: #2b241d;
  --cab-wood-raised: #382e24;
  --cab-vellum: #e8dfcc;
  --cab-vellum-hi: #f3ecdc;
  --cab-vellum-low: #d8ccb4;
  --cab-mineral: #aeb3a8;
  --cab-mineral-dark: #73786f;
  --cab-ink: #29261f;
  --cab-ink-soft: #675f51;
  --cab-rule: #a49372;
  --cab-brass: #947631;
  --cab-brass-hi: #c4a75f;
  --cab-oxblood: #783a3e;
  --cab-blue: #355f76;
  --cab-verdigris: #4f7168;
  --cab-paper-shadow: rgba(30, 24, 17, .28);
}

body {
  background: var(--cab-ebon);
  color: var(--cab-ink);
  font-family: "Segoe UI", Aptos, Arial, sans-serif;
  font-weight: 500;
}

#hdr {
  background:
    linear-gradient(90deg, rgba(255,255,255,.025), transparent 24%, rgba(0,0,0,.16)),
    linear-gradient(180deg, var(--cab-wood-raised), var(--cab-ebon));
  border-bottom: 2px solid var(--cab-brass);
  box-shadow: 0 2px 10px rgba(0,0,0,.32);
}
#hdr h1 {
  color: #dfcca0;
  font-family: Baskerville, "Palatino Linotype", Georgia, serif;
  font-weight: 600;
  letter-spacing: .14em;
  text-shadow: 0 1px 0 #000;
}
#hdr .sub { color: #b9ad97; font-weight: 600; }

#top-cmd,
#command-deck {
  background:
    linear-gradient(90deg, rgba(255,255,255,.02), transparent 35%, rgba(0,0,0,.12)),
    var(--cab-ebon);
}
#command-deck { border-bottom-color: #5d4c32; }

#main {
  background:
    linear-gradient(rgba(255,255,255,.05), rgba(0,0,0,.06)),
    var(--cab-mineral-dark);
}
#board-col {
  background:
    radial-gradient(circle at 50% 42%, rgba(233,226,204,.14), transparent 48%),
    linear-gradient(135deg, rgba(255,255,255,.035), rgba(0,0,0,.07));
}
#board-wrap {
  background: linear-gradient(145deg, #33291f, #17130f);
  border: 3px solid var(--cab-brass);
  outline: 1px solid #0d0b08;
  box-shadow:
    0 10px 26px rgba(20,16,11,.34),
    inset 0 0 0 2px #5b4930,
    inset 0 0 14px rgba(0,0,0,.5);
}

/* The four reference rails are papers, not more machinery. */
#summary,
#right,
#game-events-col,
#inspector-col {
  color: var(--cab-ink);
  background:
    linear-gradient(100deg, rgba(113,91,54,.045), transparent 22%),
    linear-gradient(180deg, var(--cab-vellum-hi), var(--cab-vellum));
  border-color: var(--cab-rule);
  box-shadow: 0 3px 14px var(--cab-paper-shadow);
}
#summary,
#right { padding: 14px; }
#game-events-col { padding: 12px 10px; }
#inspector-col { border-color: var(--cab-rule); }
#inspector-panel { padding: 12px; }

.lbl,
.ge-lbl,
.insp-col-lbl,
.avail-actions-hdr,
.res-inv-hdr {
  color: #584827;
  font-family: Baskerville, "Palatino Linotype", Georgia, serif;
  font-weight: 700;
  letter-spacing: .10em;
  border-color: var(--cab-rule);
}
.insp-col-lbl {
  color: #e8d7ae;
  background: linear-gradient(180deg, var(--cab-wood-raised), var(--cab-ebon));
  border-bottom-color: var(--cab-brass);
}
.dash-captain-card { border-bottom-width: 2px; }
.dash-captain-name,
.avail-action-name,
.dash-ability-name,
.detail-val,
.insp-die-name,
.res-inv-name { color: var(--cab-ink); }
.dash-captain-name.pd,
.detail-val.pd,
.insp-icon.pd,
.res-inv-pd { color: var(--cab-oxblood); }
.dash-captain-name.sm,
.detail-val.sm,
.insp-icon.sm,
.res-inv-sm { color: var(--cab-blue); }

.dash-token-block {
  background: linear-gradient(180deg, #fbf5e7, #ddd0b6);
  border-color: var(--cab-brass);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.7), 0 2px 5px rgba(65,50,31,.18);
}
.dash-token-num,
.dash-token-label {
  color: #58431d;
  font-family: "Segoe UI", Aptos, Arial, sans-serif;
  font-variant-numeric: tabular-nums;
  text-shadow: none;
}

.avail-action-row { border-radius: 3px; }
.avail-action-row:hover { background: rgba(148,118,49,.11); }
.avail-action-row.avail-action-selected {
  background: rgba(148,118,49,.17);
  outline-color: var(--cab-brass);
}
.avail-action-row.avail-action-selected .avail-action-name { color: #513e18; }
.avail-action-sep { color: var(--cab-rule); }
.avail-action-cost { color: #715922; }

.res-inv-row,
.sum-divider,
.insp-header,
.valid-section,
.valid-row { border-color: rgba(120,101,68,.27); }
.res-inv-glyph { color: var(--cab-brass); text-shadow: none; }
.res-inv-counts,
.res-inv-col-legend,
.sum-v {
  font-family: "Segoe UI", Aptos, Arial, sans-serif;
  font-variant-numeric: tabular-nums;
}

#detail-panel { line-height: 1.65; }
.detail-val { font-weight: 650; }
.detail-val.face-highlight { color: #654f1f; }
.face-pip {
  color: var(--cab-ink);
  background: var(--cab-vellum-low);
  border-color: var(--cab-rule);
}
.face-pip.current {
  color: #4d3b18;
  background: #f4e7bd;
  border-color: var(--cab-brass);
}

/* The event ledger is deliberately quieter than the board and commands. */
.ge {
  color: #4f493e;
  border-bottom-color: rgba(120,101,68,.20);
  line-height: 1.55;
}
.ge-separator { color: #725921; }
.ge-claim,
.ge-cultivation { color: #496a55; }
.ge-move { color: var(--cab-blue); }
.ge-blocked { color: var(--cab-oxblood); }

/* Enamel-and-brass instruments.  Their mechanics remain unchanged. */
.infl-panel {
  color: var(--cab-ink);
  background: linear-gradient(180deg, #f2ead8, #d8ccb3);
  border-color: #8f805f;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.72), 0 2px 5px rgba(0,0,0,.25);
}
.infl-pd { border-left-color: var(--cab-oxblood); }
.infl-sm { border-left-color: var(--cab-blue); }
.infl-arc { stroke: #b5a98f; }
.infl-tick { stroke: #726850; }
.infl-target-mark { stroke: var(--cab-brass); }
.infl-needle { stroke: var(--cab-ink); }
.infl-hub { fill: var(--cab-brass); }
.infl-pd .infl-needle,
.infl-pd .infl-name { stroke: var(--cab-oxblood); color: var(--cab-oxblood); }
.infl-sm .infl-needle,
.infl-sm .infl-name { stroke: var(--cab-blue); color: var(--cab-blue); }
.infl-total,
.infl-src b,
.infl-headline,
.infl-req-count { color: var(--cab-ink); }
.infl-of,
.infl-sources,
.infl-sub,
.infl-req,
.infl-req-label,
.infl-req-optional { color: var(--cab-ink-soft); }
.infl-lamp { color: #a69a82; }
.infl-lamp-lit { color: #80621e; text-shadow: none; }
.infl-active { background: linear-gradient(180deg, #fff9eb, #e5d7ba); }
.infl-pd.infl-active,
.infl-sm.infl-active { animation: none; }
.infl-pd.infl-active {
  border-color: var(--cab-oxblood);
  box-shadow: inset 0 0 0 1px #fff8e8, 0 0 0 2px rgba(120,58,62,.28);
}
.infl-sm.infl-active {
  border-color: var(--cab-blue);
  box-shadow: inset 0 0 0 1px #fff8e8, 0 0 0 2px rgba(53,95,118,.28);
}
.infl-pd .infl-active-tag {
  color: #fff4ed; background: var(--cab-oxblood); border-color: var(--cab-oxblood);
}
.infl-sm .infl-active-tag {
  color: #f4fbff; background: var(--cab-blue); border-color: var(--cab-blue);
}

#command-context {
  background: linear-gradient(180deg, #2a241c, #1c1813);
  border-color: #655334;
}
.cs-title { color: #d5bd82; }
.cs-reserve,
.cs-deployed,
.cs-chip-meta,
.infl-banner,
.infl-cond { color: #b7aa91; }
.cs-chip { background: #29231c; border-color: #665434; }

/* Every manual resource choice is the same paper form inside the command tray. */
.rs-selection {
  color: var(--cab-ink);
  background: linear-gradient(180deg, #f3ebd9, #ddd0b7);
  border-color: var(--cab-brass);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.7);
}
.rs-selection-title,
.rs-slot-label,
.rs-choice-label { color: #4c402d; }
.rs-selection-note,
.rs-selection-help { color: var(--cab-ink-soft); }
.rs-selection-head,
.rs-slot-name { color: #4c402d; }
.rs-slot-count,
.rs-slot-tile,
.rs-selection-status,
.rs-candidate-label { color: var(--cab-ink-soft); }
.rs-slot {
  color: var(--cab-ink);
  background: rgba(255,255,255,.42);
  border-color: #ad9b79;
}
.rs-resource-choice {
  color: var(--cab-ink);
  background: #f7f0e1;
  border-color: #9e8c68;
  box-shadow: 0 1px 0 rgba(255,255,255,.7);
}
.rs-resource-choice:hover:not(:disabled),
.rs-resource-choice.selected {
  color: #382b12;
  background: #ead9a9;
  border-color: var(--cab-brass);
}
.rs-selection.rs-selection-ready {
  color: var(--cab-ink);
  background: linear-gradient(180deg, #eef0df, #d8dcc5);
  border-left-color: var(--cab-verdigris);
}
.rs-selection-ready .rs-selection-status,
.rs-slot-filled .rs-slot-count { color: #38564b; }

/* Controls should feel like labelled hardware, but remain comfortably legible. */
.abtn,
button,
select,
input { font-family: "Segoe UI", Aptos, Arial, sans-serif; }
#mode-banner.active {
  color: #f0d6a1;
  background: #32251a;
  border-color: var(--cab-brass);
}
.mode-cancel-btn {
  font-family: "Segoe UI", Aptos, Arial, sans-serif;
  color: #f3ddd5;
  background: var(--cab-oxblood);
  border-color: #b27977;
}

@media (max-width: 1500px) {
  #main { gap: 8px; padding: 8px; }
  #summary,
  #right,
  #game-events-col,
  #inspector-col { border: 1px solid var(--cab-rule); }
}

/* ══════════════════════════════════════════════════════════════════════════
   MATCH RECOVERY PANEL (Persistence Pass 4A)

   A blocking overlay shown only when a saved match exists, and removed the
   moment the player answers. It adds NO persistent vertical footprint to the
   game once the choice is resolved — `#recovery-panel` without `.rec-open` is
   display:none and occupies nothing.

   Deliberately small and unstyled beyond the interface's existing vocabulary:
   this is a door, not a room.
   ══════════════════════════════════════════════════════════════════════════ */

#recovery-panel { display: none; }
#recovery-panel.rec-open {
  display: flex;
  position: fixed;
  inset: 0;
  z-index: 900;
  align-items: center;
  justify-content: center;
  background: rgba(8, 6, 4, .88);
  padding: 20px;
}

.rec-card {
  width: min(460px, 100%);
  border: 1px solid #8b6914;
  border-radius: 4px;
  background: linear-gradient(180deg, #191309 0%, #110e09 100%);
  box-shadow: 0 0 40px rgba(0, 0, 0, .8), 0 0 14px rgba(200, 164, 76, .18);
  padding: 18px 20px;
  color: #d4c5a0;
  font-family: Georgia, serif;
}

.rec-title {
  font-size: 1.05rem;
  font-variant: small-caps;
  letter-spacing: .1em;
  color: #c8a44c;
  margin-bottom: 6px;
}
.rec-lead { font-size: .76rem; color: #9a8a68; line-height: 1.5; margin-bottom: 4px; }

.rec-meta {
  margin: 12px 0 14px;
  border-top: 1px solid #2a2218;
  border-bottom: 1px solid #2a2218;
  padding: 8px 0;
}
.rec-row { display: flex; gap: 10px; font-size: .74rem; line-height: 1.9; }
.rec-k { color: #7a6a4a; min-width: 5.5em; }
.rec-v { color: #d4c5a0; }
/* The established Captain identities, so the saved match is recognisable at a
   glance without the panel having to explain who is who. */
.rec-pd { color: #c05050; }
.rec-sm { color: #5599cc; }
.rec-target { color: #7a6a4a; }

.rec-actions { display: flex; gap: 10px; flex-wrap: wrap; }
.rec-btn {
  flex: 1 1 auto;
  padding: 8px 12px;
  font: inherit;
  font-size: .8rem;
  font-variant: small-caps;
  letter-spacing: .05em;
  border-radius: 3px;
  cursor: pointer;
}
/* Continue is the primary action and looks it. */
.rec-btn-primary {
  border: 1px solid #6ea86e;
  background: linear-gradient(180deg, #4a7a4a 0%, #365c36 100%);
  color: #eaffea;
}
.rec-btn-primary:hover { background: linear-gradient(180deg, #5a8f5a 0%, #427042 100%); }
/* Start New is destructive: outlined in the interface's established warning red
   so it is unmistakable, and never mistakable for the primary choice. */
.rec-btn-danger {
  border: 1px solid #a04030;
  background: rgba(180, 60, 40, .18);
  color: #e07060;
}
.rec-btn-danger:hover { background: rgba(180, 60, 40, .34); color: #f09080; }
/* Keyboard players must be able to see where they are. */
.rec-btn:focus-visible { outline: 2px solid #c8a44c; outline-offset: 2px; }

.rec-warn {
  margin-top: 10px;
  font-size: .66rem;
  font-style: italic;
  color: #8a6a4a;
  text-align: center;
}

/* ─── AI PLAYTEST OBSERVER (Playtest Observer Pass 4B) ─────────────────────────────────────────
   A read-only text mirror of the live match, for an automated playtester.

   HIDDEN UNLESS EXPLICITLY REQUESTED. The panel occupies no space at all
   without ?playtest=1 on the URL — display:none, not merely collapsed — so an
   ordinary match renders exactly as it did before this pass and the board
   never moves. ui/renderPlaytestObserver.js stamps data-playtest on <html>;
   CSS cannot read a query string itself.

   Even when enabled it sits inside the existing right-hand column, below the
   debug panel, collapsed. It is deliberately plain: this is instrumentation,
   not a surface a player is meant to read during play. */
#playtest-observer { display: none; }
:root[data-playtest="1"] #playtest-observer { display: block; }

#playtest-observer > summary {
  cursor: pointer;
  user-select: none;
}

#playtest-observer-output {
  margin: 6px 0 0;
  padding: 6px 8px;
  max-height: 320px;
  /* Both axes scroll INSIDE the panel. The observer emits fixed-width board
     rows and long selector strings, and neither may be allowed to widen the
     page or stretch the column the board shares. */
  overflow: auto;
  background: #0d0b07;
  border: 1px solid #3a3020;
  border-radius: 3px;
  color: #b8ac90;
  font-family: ui-monospace, "Cascadia Mono", Consolas, monospace;
  font-size: .62rem;
  line-height: 1.35;
  /* pre, not pre-wrap: the board rows are positional and must not reflow. */
  white-space: pre;
  tab-size: 2;
}

/* ─── PLAYTEST RECORDER (Playtest Recorder Pass 4C) ───────────────────────────
   Local match recording for playtests. Same activation discipline as the
   Observer above: display:none without ?playtest=1, so it occupies no space at
   all during ordinary play and cannot move the board. */
#playtest-recorder { display: none; }
:root[data-playtest="1"] #playtest-recorder {
  display: block;
  margin-top: 8px;
  padding: 6px 8px;
  background: #0d0b07;
  border: 1px solid #3a3020;
  border-radius: 3px;
}

.ptr-head { display: flex; align-items: baseline; gap: 6px; justify-content: space-between; }
.ptr-title {
  font-size: .62rem; letter-spacing: .08em; text-transform: uppercase; color: #8b7a55;
}
.ptr-state { font-size: .58rem; color: #6a5a40; }
/* The one piece of colour: a recording indicator that reads at a glance.
   Static, not animated — a blinking dot beside a game board is a distraction,
   and prefers-reduced-motion would have to switch it off anyway. */
.ptr-state[data-ptr-state="recording"]::before { content: "● "; color: #b04a3a; }
.ptr-state[data-ptr-state="complete"]::before  { content: "■ "; color: #8b6914; }
.ptr-state[data-ptr-state="recovery-choice-pending"]::before { content: "○ "; }

.ptr-label { font-size: .6rem; color: #c8a44c; margin-top: 3px; }
.ptr-who   { font-size: .58rem; color: #8b7a55; }
.ptr-who span { opacity: .55; }

.ptr-counts {
  display: flex; gap: 8px; margin: 4px 0 5px;
  font-size: .56rem; color: #6a5a40; font-family: ui-monospace, Consolas, monospace;
}

.ptr-actions { display: flex; flex-wrap: wrap; gap: 4px; }
.ptr-btn {
  flex: 1 1 auto; padding: 3px 6px; cursor: pointer;
  font-size: .58rem; font-family: inherit;
  background: #16120b; color: #b8ac90;
  border: 1px solid #3a3020; border-radius: 2px;
}
.ptr-btn:hover:not(:disabled) { border-color: #8b6914; color: #c8a44c; }
.ptr-btn:disabled { opacity: .4; cursor: default; }
.ptr-btn-primary { border-color: #6a5a28; color: #c8a44c; }
/* Keyboard users must be able to see where they are. */
.ptr-btn:focus-visible,
.ptr-form input:focus-visible,
.ptr-form textarea:focus-visible { outline: 2px solid #c8a44c; outline-offset: 1px; }

.ptr-tray:empty { display: none; }
.ptr-form { margin-top: 6px; display: flex; flex-direction: column; gap: 5px; }
.ptr-tags { display: flex; flex-wrap: wrap; gap: 3px 8px; }
.ptr-tag  { font-size: .58rem; color: #b8ac90; cursor: pointer; display: inline-flex; align-items: center; gap: 3px; }
.ptr-field { display: flex; flex-direction: column; gap: 2px; font-size: .56rem; color: #8b7a55; }
.ptr-form input, .ptr-form textarea {
  width: 100%; box-sizing: border-box; padding: 3px 5px;
  font-size: .6rem; font-family: inherit;
  background: #16120b; color: #d8cca8; border: 1px solid #3a3020; border-radius: 2px;
}
.ptr-form textarea { resize: vertical; }
.ptr-form-actions { display: flex; gap: 4px; }
.ptr-ack { margin-top: 5px; font-size: .58rem; color: #7a9a5a; }


/* ─── MATCH CONDITIONS CONSOLE (Variable Victory Conditions Pass 5A) ──────────
   The pre-match dialog where a player sets the three victory conditions.

   Rendered into the Pass 4A recovery overlay (#recovery-panel), so the overlay
   backdrop, stacking and open/close behaviour are inherited rather than
   duplicated. Everything below styles the console itself.

   The look is a Victorian industrial control panel: dark enamelled metal, a
   brass frame, riveted edges, engraved labels and an instrument readout. All of
   it is CSS — no image, no external font, no network request. Colours come from
   the palette the rest of the interface already uses (#c8a44c brass,
   #8b6914 dark brass, #b8ac90 enamel text, #0d0b07 case black). */

.ms-frame {
  position: relative;
  width: min(560px, calc(100vw - 32px));
  max-height: calc(100vh - 48px);
  overflow-y: auto;
  padding: 22px 26px 20px;
  color: #c9bda0;
  font-size: .78rem;
  /* Brushed dark metal: two soft diagonal sheens over an enamel base. */
  background:
    linear-gradient(158deg, rgba(200,164,76,.09) 0%, rgba(200,164,76,0) 42%),
    linear-gradient(#171208, #0d0b07 68%);
  border: 1px solid #6a5a28;
  border-radius: 6px;
  box-shadow:
    0 0 0 3px #14100a,
    0 0 0 4px #4a3d1c,          /* the brass frame */
    0 18px 44px rgba(0,0,0,.72),
    inset 0 1px 0 rgba(200,164,76,.16);
}

/* Rivets, drawn as four corner studs. Decorative only, and hidden from
   assistive technology at the markup level. */
.ms-rivets { position: absolute; inset: 7px; pointer-events: none; }
.ms-rivets::before, .ms-rivets::after {
  content: ""; position: absolute; left: 0; right: 0; height: 7px;
  background-image: radial-gradient(circle, #6a5a28 0 2px, rgba(0,0,0,.5) 2px 3px, transparent 3px);
  background-size: 7px 7px; background-repeat: repeat-x;
  opacity: .5;
}
.ms-rivets::before { top: 0; }
.ms-rivets::after  { bottom: 0; }

.ms-head { text-align: center; margin-bottom: 16px; }
.ms-title {
  margin: 0; font-size: 1.06rem; letter-spacing: .17em; text-transform: uppercase;
  color: #d8b75a;
  text-shadow: 0 1px 0 #000, 0 0 14px rgba(200,164,76,.24);
}
.ms-kicker { margin: 5px 0 0; font-size: .68rem; color: #8b7a55; line-height: 1.45; }

/* ── The Influence target instrument ── */
.ms-instrument {
  margin: 0 0 14px;
  padding: 13px 14px 10px;
  background: linear-gradient(#100d07, #0a0805);
  border: 1px solid #3a3020;
  border-radius: 4px;
  text-align: center;
}
.ms-instrument-label {
  display: block; margin-bottom: 9px;
  font-size: .64rem; letter-spacing: .15em; text-transform: uppercase; color: #8b7a55;
}
.ms-instrument-row {
  display: flex; align-items: center; justify-content: center; gap: 14px;
}

/* The engraved counter window. */
.ms-readout {
  min-width: 118px;
  padding: 5px 10px;
  background: #060504;
  border: 1px solid #4a3d1c;
  border-radius: 3px;
  box-shadow: inset 0 2px 7px rgba(0,0,0,.9), 0 0 12px rgba(200,164,76,.10);
}
.ms-readout-input {
  width: 100%;
  padding: 0;
  background: transparent; border: 0; color: #f0c75a;
  font-family: ui-monospace, "Cascadia Mono", Consolas, monospace;
  font-size: 2.5rem; font-weight: 700; line-height: 1.05;
  text-align: center; letter-spacing: .04em;
  text-shadow: 0 0 16px rgba(240,199,90,.42);
}
/* The spinners are redundant beside the console's own controls, and they break
   the engraved look. Keyboard entry and the arrow keys still work. */
.ms-readout-input::-webkit-outer-spin-button,
.ms-readout-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.ms-readout-input { -moz-appearance: textfield; appearance: textfield; }
.ms-range { margin: 8px 0 0; font-size: .62rem; color: #6a5a40; letter-spacing: .06em; }

/* ── Minus / plus keys ── */
.ms-step {
  flex: 0 0 auto;
  width: 38px; height: 38px;
  display: inline-flex; align-items: center; justify-content: center;
  font-family: inherit; font-size: 1.24rem; line-height: 1;
  color: #e0c887; cursor: pointer;
  background: linear-gradient(#2a2113, #171208);
  border: 1px solid #6a5a28;
  border-radius: 4px;
  box-shadow: 0 2px 0 #0a0805, inset 0 1px 0 rgba(200,164,76,.22);
  transition: transform .06s ease, box-shadow .06s ease, background .12s ease;
}
.ms-step-lg { width: 46px; height: 46px; font-size: 1.5rem; }
.ms-step:hover:not(:disabled) { background: linear-gradient(#332813, #1c1509); color: #f2d78f; }
/* Real key travel: the button moves down onto its shadow. */
.ms-step:active:not(:disabled) {
  transform: translateY(2px);
  box-shadow: 0 0 0 #0a0805, inset 0 2px 5px rgba(0,0,0,.7);
}
.ms-step:disabled { opacity: .32; cursor: default; box-shadow: none; }

/* ── Requirement rows ── */
.ms-rows { display: flex; flex-direction: column; gap: 9px; }
.ms-row {
  padding: 10px 12px;
  background: linear-gradient(#100d07, #0b0906);
  border: 1px solid #3a3020;
  border-radius: 4px;
}
.ms-row-head {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
  margin-bottom: 8px;
}
.ms-row-label {
  font-size: .66rem; letter-spacing: .13em; text-transform: uppercase; color: #b3a179;
}
.ms-row-note { font-size: .63rem; color: #7d6d4c; }
.ms-row-controls { display: flex; align-items: center; gap: 10px; }

/* The lamps. Reinforcement, never the only representation — the exact numeral
   sits beside them and the row note states the requirement in words. */
.ms-lamps {
  flex: 1 1 auto;
  display: flex; align-items: center; flex-wrap: wrap; gap: 5px;
  min-height: 20px;
}
.ms-lamp {
  font-size: .8rem; line-height: 1;
  color: #f0c75a;
  text-shadow: 0 0 8px rgba(240,199,90,.75), 0 0 16px rgba(240,199,90,.32);
  animation: ms-lamp-on .18s ease-out;
}
@keyframes ms-lamp-on { from { opacity: 0; transform: scale(.7); } to { opacity: 1; transform: none; } }
.ms-lamp-overflow { display: inline-flex; align-items: center; gap: 5px; color: #f0c75a;
  text-shadow: 0 0 8px rgba(240,199,90,.7); letter-spacing: .18em; }
.ms-lamp-more { color: #8b7a55; font-size: .66rem; letter-spacing: 0; text-shadow: none; }
.ms-optional {
  font-size: .62rem; letter-spacing: .16em; color: #6f6248;
  border: 1px dashed #3a3020; border-radius: 3px; padding: 2px 8px;
}

/* The exact value. An <output>, so it is announced as the row's value. */
.ms-row-value {
  flex: 0 0 auto; min-width: 2.1ch; text-align: center;
  font-family: ui-monospace, "Cascadia Mono", Consolas, monospace;
  font-size: 1.28rem; font-weight: 700; color: #e8d3a0;
  text-shadow: 0 0 10px rgba(232,211,160,.24);
}

/* ── Summary, timing, warnings ── */
.ms-summary {
  margin: 15px 0 0; padding: 10px 12px;
  background: rgba(200,164,76,.06);
  border-left: 3px solid #8b6914;
  border-radius: 0 3px 3px 0;
  font-size: .74rem; line-height: 1.5; color: #ddd0ac;
}
.ms-timing { margin: 8px 0 0; font-size: .65rem; color: #7d6d4c; line-height: 1.45; }

.ms-warning {
  display: flex; gap: 9px; align-items: flex-start;
  margin: 13px 0 0; padding: 9px 11px;
  background: rgba(176,74,58,.11);
  border: 1px solid #6e3226;
  border-radius: 3px;
  font-size: .68rem; line-height: 1.45; color: #d9a99c;
}
.ms-warning-icon { color: #c8553d; font-size: .85rem; line-height: 1.3; }

.ms-problems {
  margin: 11px 0 0; padding: 8px 11px;
  background: rgba(176,74,58,.14);
  border: 1px solid #6e3226; border-radius: 3px;
  font-size: .68rem; line-height: 1.5; color: #e8b3a6;
}

/* ── Actions ── */
/* Seat dice (Phase C of docs/architecture/built-dice-in-play.md): each Captain
   chooses the standard dice or signs in with a built stash. */
.ms-seats {
  margin-top: 12px; padding: 12px 14px;
  border: 1px solid #3a3018; border-radius: 4px; background: rgba(0,0,0,.22);
}
.ms-seats-note { margin: 4px 0 10px; font-size: .65rem; color: #8b7a55; line-height: 1.45; }
.ms-seat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 10px; }
.ms-seat {
  margin: 0; min-width: 0; padding: 9px 11px 11px;
  border: 1px solid #4a3d1c; border-radius: 4px;
  display: flex; flex-direction: column; gap: 7px;
}
.ms-seat-captain { padding: 0 5px; font-size: .7rem; letter-spacing: .1em; text-transform: uppercase; color: #d8b75a; }
.ms-seat-modes { display: flex; flex-wrap: wrap; gap: 4px 12px; }
.ms-seat-mode { display: inline-flex; align-items: center; gap: 5px; cursor: pointer; }
.ms-seat-mode input { accent-color: #c8a44c; margin: 0; }
.ms-seat-status { margin: 0; font-size: .68rem; color: #b8ac90; line-height: 1.45; }
.ms-seat-ready { color: #9fc27a; }
.ms-seat-problem { color: #e08a72; font-size: .68rem; line-height: 1.45; }
.ms-seat-problem p { margin: 0; }
.ms-seat-problem ul, .ms-seat-dice { margin: 2px 0 0; padding-left: 16px; }
.ms-seat-dice { font-size: .68rem; color: #c9bda0; overflow-wrap: anywhere; }
.ms-seat-form { display: flex; flex-direction: column; gap: 6px; }
.ms-seat-field {
  display: flex; flex-direction: column; gap: 3px;
  font-size: .62rem; letter-spacing: .06em; text-transform: uppercase; color: #8b7a55;
}
.ms-seat-field select, .ms-seat-field input {
  min-width: 0; padding: 5px 7px;
  font: inherit; font-size: .78rem; letter-spacing: 0; text-transform: none;
  color: #e6d9b8; background: #0d0b07; border: 1px solid #6a5a28; border-radius: 3px;
}
.ms-seat-signin, .ms-seat-link { align-self: flex-start; font: inherit; font-size: .7rem; cursor: pointer; }
.ms-seat-signin {
  padding: 5px 12px; color: #1a1408; border-radius: 3px;
  background: linear-gradient(#e0bd62, #a8842f); border: 1px solid #4a3d1c;
}
.ms-seat-signin:hover { background: linear-gradient(#f0cf78, #b8923a); }
.ms-seat-link { padding: 0; color: #d8b75a; background: none; border: 0; text-decoration: underline; }

.ms-actions { display: flex; gap: 10px; margin-top: 17px; }
.ms-btn {
  flex: 1 1 auto; padding: 11px 14px;
  font-family: inherit; font-size: .74rem; letter-spacing: .11em; text-transform: uppercase;
  cursor: pointer; border-radius: 4px;
  transition: transform .06s ease, box-shadow .06s ease, background .12s ease;
}
.ms-btn-start {
  flex: 2 1 auto;
  color: #100d07; font-weight: 700;
  background: linear-gradient(#e0bd63, #a8822c);
  border: 1px solid #f0d68f;
  box-shadow: 0 3px 0 #4a3d1c, 0 0 20px rgba(200,164,76,.26);
}
.ms-btn-start:hover:not(:disabled) { background: linear-gradient(#f0cf78, #b8923a); }
.ms-btn-start:active:not(:disabled) { transform: translateY(3px); box-shadow: 0 0 0 #4a3d1c; }
.ms-btn-start:disabled {
  color: #6a5a40; background: linear-gradient(#2a2113, #1a1409);
  border-color: #3a3020; box-shadow: none; cursor: default;
}
.ms-btn-cancel {
  color: #b8ac90;
  background: linear-gradient(#221b10, #140f08);
  border: 1px solid #4a3d1c;
  box-shadow: 0 2px 0 #0a0805;
}
.ms-btn-cancel:hover { color: #d8cca8; border-color: #6a5a28; }
.ms-btn-cancel:active { transform: translateY(2px); box-shadow: 0 0 0 #0a0805; }

/* Focus must be obvious on every control, including the numeric field. */
.ms-frame :focus-visible {
  outline: 2px solid #f0c75a;
  outline-offset: 2px;
}

/* Decorative motion only. Reduced-motion users keep every state change — the
   colours, the disabled treatment and the focus ring are untouched; only the
   travel and the lamp fade stop. */
@media (prefers-reduced-motion: reduce) {
  .ms-step, .ms-btn { transition: none; }
  .ms-step:active:not(:disabled),
  .ms-btn-start:active:not(:disabled),
  .ms-btn-cancel:active { transform: none; }
  .ms-lamp { animation: none; }
}

/* Narrow widths: the console stays a console. The instrument row keeps its
   shape because the keys and the readout are what the control IS; the
   requirement rows are what wrap. */
@media (max-width: 560px) {
  .ms-frame { padding: 18px 15px 16px; }
  .ms-readout-input { font-size: 2.1rem; }
  .ms-row-head { flex-direction: column; align-items: flex-start; gap: 2px; }
  .ms-actions { flex-direction: column; }
}

/* ─── SCOREBOARD CONDITIONS BAND (Pass 5A) ────────────────────────────────────
   The active match's three conditions, and the statement that they are fixed.
   Sits inside the existing banner rather than claiming a new row, so the
   command deck does not grow and the board does not move. */
.infl-banner { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 12px;
  justify-content: center; }
.infl-cond { display: inline-flex; flex-wrap: wrap; align-items: baseline; gap: 5px;
  font-size: .58rem; color: #8b7a55; letter-spacing: .04em; }
.infl-cond-lock { font-size: .56rem; opacity: .8; }
.infl-cond-dot { opacity: .45; }
.infl-cond-state {
  padding: 1px 6px; border: 1px solid #4a3d1c; border-radius: 2px;
  color: #c8a44c; letter-spacing: .1em; font-size: .55rem;
}

/* Pass 5A refinement: the chip must not cost the command deck a line. The
   values live in data attributes and a screen-reader sentence instead. */
.infl-cond { position: relative; display: inline-flex; align-items: baseline; gap: 4px; }
.infl-sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ══════════════════════════════════════════════════════════════════════════
   READABILITY FOUNDATION — warm charcoal, stronger ink, sturdier type

   This is the safe pre-playtest layer, not the final visual-identity pass.
   It removes absolute black from the large interface fields, strengthens the
   text that carries rules and state, and leaves authored faction/terrain hues
   intact. The later Surveyor's Cabinet pass can move primary information onto
   vellum without entangling that art-direction decision with today's UX fixes.
   ══════════════════════════════════════════════════════════════════════════ */
:root {
  --sr-lacquer: #171410;
  --sr-charcoal: #252019;
  --sr-charcoal-raised: #302920;
  --sr-rule: #665538;
  --sr-text: #eee4d0;
  --sr-text-secondary: #c8baa0;
  --sr-brass: #d3b15c;
}
body {
  background: var(--sr-charcoal);
  color: var(--sr-text);
  font-size: 15px;
  font-weight: 500;
  -webkit-font-smoothing: antialiased;
}
#hdr,
#top-cmd,
#command-deck { background: var(--sr-lacquer); }
#main { background: var(--sr-charcoal); }
#summary,
#right,
#game-events-col,
#inspector-col { background: var(--sr-charcoal-raised); }
#summary,
#game-events-col { border-right-color: var(--sr-rule); }
#right,
#inspector-col { border-left-color: var(--sr-rule); }
#board-wrap {
  background: #1d1913;
  border-color: #a8893c;
}
#hdr h1,
.lbl,
.ge-lbl,
.insp-col-lbl { color: var(--sr-brass); }
#hdr .sub,
.no-sel,
.no-events,
.no-battle,
.ge-empty,
.insp-empty { color: var(--sr-text-secondary); }
.dash-captain-sub,
.avail-action-source,
.avail-action-cost,
.cs-reserve,
.cs-deployed,
.cs-chip-meta,
.infl-sources,
.infl-req,
.infl-sub { color: var(--sr-text-secondary); }
.abtn,
button { font-weight: 600; }
.abtn:focus-visible,
button:focus-visible {
  outline: 2px solid #efd27f;
  outline-offset: 2px;
}
.fa-prompt .rs-selection .rs-slots { justify-content: flex-start; margin: 0; }
.fa-prompt:has(.rs-selection) .fa-prompt-cost { display: none; }
.fa-prompt:has(.rs-selection) { gap: 2px; }

@media (max-width: 620px) {
  body { overflow: auto; }
  #command-deck {
    grid-template-columns: 1fr;
    grid-template-areas: "scores" "actions" "context";
    max-height: none;
  }
  #command-context { max-height: none; }
}

/* At laptop side-panel widths, fixed left/right rails used to squeeze the
   7×7 board into a near-invisible strip. Keep the board as the first, full-width
   task and move reference material beneath it in two readable columns. */
@media (max-width: 1100px) {
  body { height: auto; min-height: 100vh; overflow-y: auto; }
  #main {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-template-areas:
      "board board"
      "summary right"
      "events inspector";
    flex: 0 0 auto;
    overflow: visible;
  }
  #board-col       { grid-area: board; min-height: 570px; }
  #summary         { grid-area: summary; }
  #right           { grid-area: right; }
  #game-events-col { grid-area: events; }
  #inspector-col   { grid-area: inspector; }
  #summary,
  #right,
  #game-events-col,
  #inspector-col {
    width: auto;
    min-width: 0;
    max-height: 430px;
    min-height: 260px;
    overflow-y: auto;
  }
}

@media (max-width: 620px) {
  #main {
    grid-template-columns: 1fr;
    grid-template-areas: "board" "summary" "right" "events" "inspector";
  }
  #board-col { align-items: flex-start; overflow-x: auto; }
}

/* Final cascade lock for the Surveyor's Cabinet foundation.  The transitional
   readability layer immediately above predates the Cabinet and intentionally
   remains in the file as provenance; these are the few equal-specificity
   surfaces whose new material assignment must win after it. */
body { background: var(--cab-ebon); color: var(--cab-ink); }
#hdr {
  background:
    linear-gradient(90deg, rgba(255,255,255,.025), transparent 24%, rgba(0,0,0,.16)),
    linear-gradient(180deg, var(--cab-wood-raised), var(--cab-ebon));
}
#top-cmd,
#command-deck {
  background:
    linear-gradient(90deg, rgba(255,255,255,.02), transparent 35%, rgba(0,0,0,.12)),
    var(--cab-ebon);
}
#main {
  background:
    linear-gradient(rgba(255,255,255,.05), rgba(0,0,0,.06)),
    var(--cab-mineral-dark);
}
#summary,
#right,
#game-events-col,
#inspector-col {
  color: var(--cab-ink);
  background:
    linear-gradient(100deg, rgba(113,91,54,.045), transparent 22%),
    linear-gradient(180deg, var(--cab-vellum-hi), var(--cab-vellum));
  border-color: var(--cab-rule);
}
#board-wrap {
  background: linear-gradient(145deg, #33291f, #17130f);
  border-color: var(--cab-brass);
}
#hdr h1,
.lbl,
.ge-lbl,
.avail-actions-hdr,
.res-inv-hdr { color: #584827; }
#hdr h1 { color: #dfcca0; }
.insp-col-lbl { color: #e8d7ae; }
#hdr .sub { color: #b9ad97; }
.dash-captain-tagline,
.dash-captain-sub,
.avail-action-source,
.avail-action-cost,
.no-sel,
.no-events,
.no-battle,
.ge-empty,
.insp-empty { color: var(--cab-ink-soft); }

@media (max-width: 1500px) {
  body { height: auto; min-height: 100vh; overflow-y: auto; }
  #main {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-template-areas:
      "board board"
      "summary right"
      "events inspector";
    flex: 0 0 auto;
    overflow: visible;
    gap: 8px;
    padding: 8px;
  }
  #board-col       { grid-area: board; min-height: 570px; }
  #summary         { grid-area: summary; }
  #right           { grid-area: right; }
  #game-events-col { grid-area: events; }
  #inspector-col   { grid-area: inspector; }
  #summary,
  #right,
  #game-events-col,
  #inspector-col {
    width: auto;
    min-width: 0;
    max-height: 430px;
    min-height: 260px;
    overflow-y: auto;
    border: 1px solid var(--cab-rule);
  }
}

/* A short screen may compact the passive dashboard, but never an open
   decision.  Resource payment is the current task and therefore earns the
   vertical space it needs until the player confirms or cancels it. */
@media (max-height: 760px) {
  #command-deck:has(#mode-banner.active),
  #command-deck:has(#deploy-select-row[style*="display: flex"]) {
    max-height: 250px;
  }
  #command-deck:has(#mode-banner.active) .deck-side,
  #command-deck:has(#deploy-select-row[style*="display: flex"]) .deck-side {
    max-height: 240px;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
   THE INFLUENCE WHEEL — column 1 of the command deck
   ───────────────────────────────────────────────────────────────────────────
   Replaces the pair of 0–31 pressure gauges. Three parts across the strip:
   one Captain calculation, the wheel, the other Captain calculation.

   THE WHEEL YIELDS SPACE FIRST. It is sized from the deck's height, so it
   shrinks when the viewport is short while the tabular figures beside it keep
   their type size — numbers stop being readable long before a shape does.
   ═══════════════════════════════════════════════════════════════════════ */
.iw-layout {
  display: grid;
  /* Panels are CAPPED and the trio is CENTRED rather than stretched. The host
     column is 1fr under the narrow-viewport rule below, which is over 1100px on
     a wide window — a stretched panel throws its figures to the far right and
     breaks the label/number pairing the calculation depends on. */
  grid-template-columns: minmax(104px, 178px) auto minmax(104px, 178px);
  justify-content: center;
  gap: 16px; align-items: center; min-width: 0; height: 100%;
}
.iw-wheel { height: 100%; display: flex; align-items: center; justify-content: center; }
.iw-svg   { height: 100%; width: auto; max-height: 138px; display: block; }

/* ── the drawing ───────────────────────────────────────────────────────── */
.iw-wedge    { stroke: #100d09; stroke-width: 1.2; }
.iw-spoke    { stroke: #3a332a; stroke-width: .7; }
.iw-ground   { stroke: #8a7a52; stroke-width: .5; }
.iw-occupant { stroke-width: 1.1; }
.iw-abbr     { font-size: 9.5px; font-variant: small-caps; letter-spacing: .06em;
               fill: #8a7a52; dominant-baseline: middle; }
.iw-ring     { fill: none; stroke: #c8a44c; stroke-width: 1.1; stroke-dasharray: 2.5 3.5; opacity: .75; }
.iw-ray      { stroke-width: 1.6; stroke-dasharray: 3 2.5; }
.iw-ray-pierced { stroke-dasharray: none; stroke-width: 2.1; }
.iw-captain-mark { stroke-width: 1.6; }

/* ── the two calculations ──────────────────────────────────────────────── */
.iw-panel { min-width: 0; padding: 2px 6px; border-left: 2px solid transparent; }
.iw-panel-pd { border-left-color: #c0483f; }
.iw-panel-sm { border-left-color: #4a7fa8; }
.iw-who {
  font-size: .5rem; font-variant: small-caps; letter-spacing: .12em;
  color: #8a7a52; line-height: 1.1; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}
.iw-total { font-size: 1.55rem; line-height: 1; font-variant-numeric: tabular-nums; color: #e8dcc0; }
.iw-total-label {
  font-size: .46rem; font-variant: small-caps; letter-spacing: .14em;
  color: #8a7a52; margin-bottom: 3px;
}
.iw-of { opacity: .7; }
.iw-rows { list-style: none; margin: 0; padding: 0; font-variant-numeric: tabular-nums; }
.iw-rows li {
  display: flex; justify-content: space-between; gap: 6px;
  font-size: .52rem; line-height: 1.5; color: #a99d8a; white-space: nowrap;
}
.iw-rows li b { font-weight: 600; color: #d8cdb4; }

/* Reaching the target, and passing it, are stated on the panel as well as drawn
   on the wheel — the ring is an illustration, never the only telling. */
.iw-panel-target .iw-total    { color: #e0b64e; }
.iw-panel-qualified .iw-total { color: #7fc47f; }

.iw-fault { font-size: .55rem; color: #c0483f; padding: 4px 6px; }

@media (max-height: 760px) {
  .iw-svg  { max-height: 104px; }
  .iw-total { font-size: 1.25rem; }
}

/* The slimmed sidebar Captain card. Identity is a single line for orientation
   only — the authoritative identity, tokens and Litigation now live in the
   mirrored command deck. */
.dash-captain-slim-head {
  font-size: .62rem; font-variant: small-caps; letter-spacing: .09em;
  padding: 3px 6px 4px; color: #cbbf9f;
  border-bottom: 1px solid #33291a; margin-bottom: 4px;
}
.dash-captain-slim-head.pd { color: #e08878; }
.dash-captain-slim-head.sm { color: #8fc0e0; }


/* ═══ QUEEN'S DIRECTIVE INTERRUPTION (EVID-0117) ═══════════════════════════
   Shares the Conservatory prompt's geometry deliberately — same slot, same
   fixed overlay, same reason (a decision raised during the OPPONENT's turn that
   halts play until answered). Only the accent differs, so a player can tell the
   two interruptions apart at a glance without learning a second layout.
   The two can never be live at once: a Conservatory pause happens inside a
   mutation, and this window closes before any mutation begins.
   ═══════════════════════════════════════════════════════════════════════════ */
#queens-directive-prompt.qd-live {
  display: block;
  position: fixed;
  top: 96px;
  left: 50%;
  transform: translateX(-50%);
  width: min(720px, 92vw);
  max-height: calc(100vh - 120px);
  overflow-y: auto;
  z-index: 40;
  border: 2px solid #8aa23c;
  border-left-width: 6px;
  border-radius: 3px;
  background: linear-gradient(180deg, #20260f 0%, #161a0b 100%);
  box-shadow: 0 6px 34px rgba(0,0,0,.78), 0 0 0 1px rgba(180,200,90,.18);
  padding: 12px 16px 14px;
  color: #e8e6d4;
}
.qd-prompt-hdr { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
.qd-prompt-icon { font-size: 1.15rem; color: #d7e87a; }
.qd-prompt-title { font-weight: 700; font-size: .92rem; letter-spacing: .02em; color: #e9f2b8; }
.qd-prompt-body { font-size: .78rem; line-height: 1.5; }
.qd-prompt-line { margin: 0 0 6px; }
.qd-prompt-cost { color: #f0e9c0; }
.qd-prompt-note { color: #a8b083; font-size: .73rem; }
.qd-prompt-actions { display: flex; gap: 10px; margin-top: 10px; flex-wrap: wrap; }
.qd-btn-swarm, .qd-btn-allow {
  font: inherit; font-size: .8rem; font-weight: 600;
  padding: 7px 14px; border-radius: 3px; cursor: pointer;
  border: 1px solid #6d7f2e;
}
.qd-btn-swarm { background: #4c5c18; color: #f2f7cf; }
.qd-btn-swarm:hover { background: #5d7020; }
.qd-btn-allow { background: #2a2d20; color: #c9cdb2; border-color: #4a4e38; }
.qd-btn-allow:hover { background: #363a29; }


/* Board integrity readout, moved into Board Controls. It is a development
   assertion — every tile counted against the distribution the generator should
   produce — not player information, and it used to sit permanently under the
   board taking space the board needed. */
#board-stats {
  margin-top: 6px;
  font-family: 'Courier New', monospace;
  font-size: .62rem;
  line-height: 1.7;
  color: #6a5a40;
  text-align: left;
  word-break: break-word;
}

/* Resource medallions in the panels. The board draws the approved art and the
   panels drew bare symbols, so a player saw the Iron Peaks medallion on the
   tile and a triangle in the inventory beside it. Falls back to the glyph for
   any terrain with no approved icon. */
.res-icon {
  display: inline-block;
  vertical-align: middle;
  border-radius: 50%;
  box-shadow: 0 0 0 1px #9a6c15;
  background: #f3ecda;
}
.res-icon-fallback { display: inline-block; vertical-align: middle; text-align: center; }

/* Legend marks. The tile versions are absolutely positioned into a corner; in
   the legend they sit inline, which is why position is overridden there. */
.legend-locus { display: inline-block; width: 15px; height: 15px; color: #9a6c15; flex: none; }
.legend-locus svg { display: block; width: 100%; height: 100%; }
.badge-li .tile-status-mark,
.badge-li .tile-status-chip { flex: none; }
.legend .li .res-icon { margin-right: 2px; }

/* ── Structure token ────────────────────────────────────────────────────────
   The approved octagonal structure glyph, standing at the foot of the tile the
   way a building stands on land. Octagon because faces and resources are discs:
   a structure reads as a structure by outline alone. It covers the name label
   on that tile, deliberately -- the medallion already shows the terrain and the
   tooltip names both.
   Owner is an outline built from stacked drop-shadows on the wrapper, so it
   follows the octagon's own alpha edge. box-shadow would come out square around
   the transparent corners, and clip-path would clip its own outline away. ── */
.tile-structure {
  position: absolute;
  bottom: 1px; left: 50%;
  transform: translateX(-50%);
  width: 24px; height: 24px;
  z-index: 6;
  cursor: help;
  filter: drop-shadow(0 1px 1.5px rgba(0,0,0,.65));
}
.tile-structure img { display: block; width: 100%; height: 100%; }
.tile-structure.owner-pd {
  filter: drop-shadow(1.5px 0 0 #c0392b) drop-shadow(-1.5px 0 0 #c0392b)
          drop-shadow(0 1.5px 0 #c0392b) drop-shadow(0 -1.5px 0 #c0392b)
          drop-shadow(0 1px 1.5px rgba(0,0,0,.65));
}
.tile-structure.owner-sm {
  filter: drop-shadow(1.5px 0 0 #2980b9) drop-shadow(-1.5px 0 0 #2980b9)
          drop-shadow(0 1.5px 0 #2980b9) drop-shadow(0 -1.5px 0 #2980b9)
          drop-shadow(0 1px 1.5px rgba(0,0,0,.65));
}
/* No approved glyph yet: the descriptor's own symbol inside a drawn octagon,
   dark frame around ivory to match the real glyphs. Both clip-paths sit on
   CHILDREN, so the wrapper's outline filter wraps the clipped shape instead of
   being clipped along with it. */
.tile-structure-fb,
.tile-structure-fb > span {
  clip-path: polygon(29.3% 0, 70.7% 0, 100% 29.3%, 100% 70.7%,
                     70.7% 100%, 29.3% 100%, 0 70.7%, 0 29.3%);
}
.tile-structure-fb { display: block; width: 100%; height: 100%; padding: 1.5px; background: #1d1710; }
.tile-structure-fb > span {
  display: flex; align-items: center; justify-content: center;
  width: 100%; height: 100%;
  background: #f3ecda; color: #1d1710;
  font-size: 11px; line-height: 1;
}
/* In the legend the token sits inline rather than at the foot of a tile. */
.legend-structure { display: inline-block; position: relative; width: 18px; height: 18px; flex: none; }
.legend-structure .tile-structure { position: static; transform: none; width: 18px; height: 18px; }
