/* ── play_combat.css local palette (6.1 colour hoist) — this file's own colours, named and in ONE
   place so the surface can be re-tinted without hunting through the rules below. ── */
:root {
  --cb-stage-c: #ffcf8a;
  --cb-stage-c2: #ffd84a;
  --cb-stage-c3: #ff7a5a;
  --cb-stage-c4: #7aff8a;
  --cb-stage-c5: #e07070;
  --dead-fg: #000;
  --cb-tk-ready-bg: #2a2014;
  --cb-tk-cond-fg: #1a130a;
  --cb-tk-name-fg: #fff;
  --down-fg: #d8b070;
  --roll-fg: #1b0f04;
  --over-fg: #e87a6a;
  --cb-peerpath-bd: #888;
  --cb-lg-wall-bg: #6c6660;
  --cb-lg-wall-bg2: #444039;
  --cb-lg-wall-bd: #15120d;
  --cb-lg-door-bg: #7a5326;
  --cb-lg-door-bg2: #4f3619;
  --cb-lg-cover-bg: #8a5a2b;
  --cb-lg-cover-bg2: #5e3c1c;
  --cb-lg-cover-bd: #3a2510;
  --cb-lg-diff-bg: #3a342a;
  --cb-lg-diff-bg2: #2a2620;
  --cb-log-dice-fg: #8ab4d8;
  --cb-log-narr-fg: #c8b89a;
  --cb-react-text-fg: #f4e9d0;
  --cb-crop-circle-bd: #6ac8e8;
  --cb-crop-ch-bd: #06222e;
  --cb-crop-prev-bg: #14100a;
  --cb-die3-shape-stroke: #d98a3d;
  --cb-float-miss-fg: #b8b0a0;
  --cb-ter-wall-bg: #2c2620;
  --cb-ter-wall-bg2: #251f19;
  --cb-ter-wall-bd: #3a322a;
  --cb-fog-dark-bg: #060504;
  --atk-bd: #8a4038;
  --atk-fg: #e8a89a;
  --atk-fg2: #f0c0b6;
  --cast-bd: #5a4a8a;
  --cast-fg: #b8a8e8;
  --cast-bd2: #7a5ad0;
  --cast-fg2: #c8b8f0;
  --cb-eco-pip-fg: #1b1304;
}

/* Play screen — SPA-native view (route /play; hosts the combat mode). Replaces the legacy combat.css. See views/play.js.
   NOTE: the .combat-spa / .cb-* class names are KEPT — they describe the combat-mode board, which this screen hosts. */
.combat-spa { display: flex; flex-direction: column; height: calc(100dvh - var(--topbar-h, 3.5rem) - 5.75rem); min-height: 32.5rem;
  border: 0.0625rem solid var(--border); border-radius: var(--r-xl); overflow: hidden; background: var(--bg-2, #120d09); }
/* /lab/play bench host: the positioned box the embedded chrome fills (the campaign Play
   shell's board region plays this role live) — keeps the ribbon clear of the fixed topbar */
.cb-benchhost { position: relative; height: calc(100dvh - var(--topbar-h, 3.5rem) - 5.75rem); min-height: 32.5rem; }

/* title card (top-left), legacy ENCOUNTER eyebrow + serif name + hint + flow controls */
/* Combat callout severity palette — ONE set of custom props so the log lines, board toasts
   and damage floats can never drift apart again (they had — audit 2026-07-17). */
.combat-stage, .cb-stage {
  /* BUG FIX 2026-08-08: these were self-referential (`--cb-hit: var(--cb-hit)`) — invalid at
     computed-value time, so log lines and death floats rendered with NO severity colour at all.
     Every value below is taken from something already in this file, nothing invented. */
  --cb-hit:    var(--cb-stage-c);      /* was .cb-float-hit    */
  --cb-crit:   var(--cb-stage-c2);      /* was .cb-float-crit   */
  --cb-damage: var(--cb-stage-c3);      /* was .cb-float-damage */
  --cb-heal:   var(--cb-stage-c4);      /* was .cb-float-heal   */
  --cb-death:  var(--cb-stage-c5);      /* was .cb-sel-flag.dead */
  --cb-cond:   var(--gold);  /* conditions are gold — .cb-tk-cond pills */
}



/* Command card (Phase-5 pivot): Turn (controls + initiative) / Log / Dice / Vision / Key fold into ONE
   tabbed card so combat holds ≤3 chrome objects (full-bleed board + actor card + this). */

.cb-conn { font-family: var(--font-mono); font-size: var(--fs-micro); letter-spacing: 0; text-transform: none; margin-left: var(--sp-4); }
.cb-conn-open { color: var(--good); } .cb-conn-closed { color: var(--bad); } .cb-conn-connecting { color: var(--muted); }
.cb-h1 { font-family: var(--font-display); font-weight: 600; letter-spacing: .005em; line-height: 1.04; font-size: clamp(1.3125rem, .7vw + 1.0625rem, 1.875rem); margin: 0; color: var(--text); cursor: grab; }





/* .cb-cbtn deduped (0.9) — the canonical definition lives below, near .cb-controls. */
   gold-selected; the `.join` gold state stays below. */

/* Play shell: the mode/override bar (chrome above the active mode's stage). */

/* body = board + rail */
/* The board fills the whole area; every panel FLOATS over it as a corner HUD cluster (legacy layout). */
.cb-body { position: relative; flex: 1 1 auto; min-height: 0; }

/* (the shared cb-stage/cb-hud/cb-panel chrome lives in panels.css — ONE home; audit 2026-07-17) */
/* play-specific: the DM tools + combat log panels stack their internals */

.cb-loading { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; gap: var(--sp-6); color: var(--muted); font-size: var(--fs-base); }
.cb-spin { width: 0.875rem; height: 0.875rem; border: 0.125rem solid var(--border); border-top-color: var(--accent); border-radius: var(--r-round); animation: cbspin 0.8s linear infinite; }
@keyframes cbspin { to { transform: rotate(360deg); } }
.cb-world { position: absolute; left: 50%; top: 50%; transform-origin: 0 0; }
.cb-grid { position: absolute; left: 0; top: 0; background-color: rgba(var(--gold-rgb),.035);
  background-image: linear-gradient(to right, var(--border) 0.0625rem, transparent 0.0625rem), linear-gradient(to bottom, var(--border) 0.0625rem, transparent 0.0625rem);
  outline: 0.125rem solid var(--gold); box-shadow: 0 0 0 0.0625rem rgba(0,0,0,.5), var(--glow-gold, 0 0 1rem -0.3125rem rgba(var(--gold-rgb),.5)); }

/* tokens — legacy palette: solid gold (ally/player) / red (enemy) discs, dark initials */
.cb-token { position: absolute; box-sizing: border-box; padding: var(--sp-1); cursor: pointer; -webkit-user-select: none; user-select: none; -webkit-user-drag: none; z-index: 3;
  transition: left .32s cubic-bezier(.2,.8,.2,1), top .32s cubic-bezier(.2,.8,.2,1); }   /* slide between cells instead of teleporting */
.cb-token.dragging { transition: none; }
@media (prefers-reduced-motion: reduce) { .cb-token { transition: none; } }
.cb-token img, .cb-tk-disc img, .cb-ab-disc img{ -webkit-user-drag: none; user-drag: none; -webkit-user-select: none; user-select: none; pointer-events: none; }
.cb-tk-disc { width: 100%; height: 100%; border-radius: var(--r-round); overflow: hidden; border: 0.125rem solid rgba(0,0,0,.45);
  background: var(--side); display: flex; align-items: center; justify-content: center; box-shadow: var(--shadow-drop-sm); }
.cb-tk-disc img { width: 100%; height: 100%; object-fit: cover; object-position: center 22%; }
.cb-tk-ini { font-family: var(--font-mono); font-size: var(--fs-base); font-weight: 700; color: var(--bg); }
/* active turn = gold outline + ember pulse; selected = ember outline; thinking = dashed pulse */
.cb-token.active .cb-tk-disc { outline: 0.125rem solid var(--gold); outline-offset: 0.125rem; animation: cb-active-pulse 1.6s ease-in-out infinite; }
@keyframes cb-active-pulse { 0%,100% { box-shadow: 0 0.25rem 0.625rem -0.25rem rgba(0,0,0,.7), 0 0 0 0 rgba(var(--gold-rgb),0); } 50% { box-shadow: 0 0.25rem 0.625rem -0.25rem rgba(0,0,0,.7), 0 0 0.875rem 0.125rem rgba(var(--gold-rgb),.55); } }
.cb-token.sel .cb-tk-disc { outline: 0.125rem solid var(--accent); outline-offset: 0.125rem; }
.cb-token.planning .cb-tk-disc { outline: 0.125rem dashed var(--accent); outline-offset: 0.1875rem; animation: cb-pickup 1.1s ease-in-out infinite; }
@keyframes cb-pickup { 0%,100% { box-shadow: var(--glow-ember, 0 0 1.125rem -0.25rem rgba(var(--accent-rgb),.55)); } 50% { box-shadow: none; } }
.cb-token.thinking .cb-tk-disc { outline: 0.125rem dashed var(--accent); outline-offset: 0.1875rem; animation: cb-think 1s ease-in-out infinite; }
@keyframes cb-think { 0%,100% { box-shadow: 0 0 0 0 rgba(var(--accent-rgb),0); } 50% { box-shadow: 0 0 0.875rem 0.125rem rgba(var(--accent-rgb),.6); } }
@media (prefers-reduced-motion: reduce) { .cb-token.active .cb-tk-disc, .cb-token.thinking .cb-tk-disc { animation: none; } }
.cb-token.dead .cb-tk-disc, .cb-token.down .cb-tk-disc { filter: grayscale(1) brightness(.6); opacity: .7; }
.cb-token.dead::after { content: "☠"; position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; color: var(--dead-fg); font-size: var(--fs-lg); }
/* HP bar — sits just BELOW the token; solid graded fill */
.cb-tk-hp { position: absolute; left: 0.0625rem; right: 0.0625rem; bottom: -0.4375rem; height: 0.25rem; border-radius: var(--r-xs); background: rgba(0,0,0,.6); overflow: hidden; box-shadow: 0 0 0 0.0625rem rgba(0,0,0,.45); pointer-events: none; }
.cb-token.bloodied .cb-tk-hp { box-shadow: 0 0 0.4375rem -0.0625rem var(--bad), 0 0 0 0.0625rem rgba(0,0,0,.45); }
.cb-tk-hp i { display: block; height: 100%; background: var(--good); transition: width .24s cubic-bezier(.2,.8,.2,1), background .24s; }
.cb-tk-hp i.warn { background: var(--warn, #d29922); } .cb-tk-hp i.bad { background: var(--bad); }
.cb-tk-hp u { position: absolute; left: 0; top: 0; bottom: 0; background: rgba(var(--accent-rgb),.85); border-right: 0.0625rem solid rgba(0,0,0,.5); }
/* concentration / readied markers, top corners */
.cb-tk-conc, .cb-tk-ready { position: absolute; top: -0.25rem; width: 0.875rem; height: 0.875rem; border-radius: var(--r-round); display: flex; align-items: center; justify-content: center;
  font-size: var(--fs-micro); line-height: 1; background: var(--cb-tk-ready-bg); border: 0.0625rem solid var(--gold); color: var(--gold); z-index: 4; }
.cb-tk-conc { right: -0.25rem; } .cb-tk-ready { left: -0.25rem; border-color: var(--accent); color: var(--accent); }
/* condition chips — ABOVE the token, gold on dark */
.cb-tk-conds { position: absolute; left: 50%; top: -0.5625rem; transform: translateX(-50%); display: flex; gap: var(--sp-1); pointer-events: none; white-space: nowrap; z-index: 4; }
.cb-tk-cond { font-family: var(--font-mono); font-size: var(--fs-micro); font-weight: 700; line-height: 1; padding: 0.0625rem var(--sp-1); border-radius: var(--r-xs);
  color: var(--cb-tk-cond-fg); background: var(--gold); border: 0.0625rem solid rgba(0,0,0,.5); box-shadow: var(--shadow-drop-sm); }
.cb-tk-cond.more { background: var(--muted); }
/* death-save pips — BELOW the token */
.cb-tk-ds { position: absolute; left: 50%; bottom: -1rem; transform: translateX(-50%); display: flex; gap: var(--sp-1); pointer-events: none; z-index: 4; }
.cb-ds { width: 0.3125rem; height: 0.3125rem; border-radius: var(--r-round); border: 0.0625rem solid rgba(0,0,0,.6); background: rgba(0,0,0,.45); }
.cb-ds.s.on { background: var(--good); box-shadow: 0 0 0.25rem -0.0625rem var(--good); }
.cb-ds.f.on { background: var(--bad); box-shadow: 0 0 0.25rem -0.0625rem var(--bad); }
/* name label — a small chip on the token's bottom edge (legacy portrait label) */
.cb-tk-name { position: absolute; left: 50%; bottom: -0.1875rem; transform: translateX(-50%); max-width: 150%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  font-family: var(--font-mono); font-size: var(--fs-micro); line-height: 1.1; padding: 0.0625rem var(--sp-3); border-radius: var(--r-md); background: rgba(0,0,0,.62); color: var(--cb-tk-name-fg); pointer-events: none; z-index: 3; }

/* zoom controls — now a "View" panel (header bar + drag + minimize) */

/* panel base + draggable header (.cb-panel/.cb-ph/.cb-layout-reset/.cb-empty) live in panels.css —
   ONE source; only combat-specific extras stay here */

.cb-init { list-style: none; margin: 0; padding: var(--sp-3) 0 0; display: flex; flex-direction: column; gap: var(--sp-1); }
.cb-init-row { display: flex; align-items: center; gap: var(--sp-5); padding: 0.3125rem 0.4375rem; border-radius: var(--r-sm); cursor: pointer; transition: background .14s; }
.cb-init-row::before { content: ""; width: 0.6875rem; height: 0.6875rem; border-radius: var(--r-round); flex: 0 0 auto; background: var(--side); border: 0.0625rem solid rgba(0,0,0,.45); order: 1; }
.cb-init-row:hover { background: var(--panel-2); }
.cb-init-row.active { background: linear-gradient(90deg, rgba(var(--gold-rgb),.16), transparent 90%); box-shadow: inset 0.1875rem 0 0 var(--gold); }
.cb-init-row.dead { opacity: .5; } .cb-init-row.dead .cb-init-name { text-decoration: line-through; }
.cb-init-row.surprised { opacity: .7; } 
/* Remembered-but-unseen foe: stays on the initiative list (you know it's still in the fight) but its dot is
   hollow and its name muted/italic — you can't see WHERE it is or what it's doing. */
.cb-init-row.unseen { opacity: .6; cursor: default; }
.cb-init-row.unseen::before { background: transparent; border-style: dashed; }
.cb-init-row.unseen .cb-init-name { font-style: italic; color: var(--text-dim, #9a8a6e); }

.cb-init-ini { font-family: var(--font-mono); font-size: var(--fs-sm); font-weight: 700; color: var(--gold); width: 1.25rem; text-align: center; flex: 0 0 auto; order: 0; }
.cb-init-name { flex: 1 1 auto; font-size: var(--fs-base); color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; order: 2; }









.cb-sel-tag.t-party{ color: var(--gold); border-color: color-mix(in srgb, var(--gold) 50%, transparent); }
 .cb-sel-tag.t-neutral { color: var(--muted); }


 








.cb-sel-flag.dead { background: rgba(224,80,80,.16); color: var(--cb-stage-c5); } .cb-sel-flag.down { background: rgba(200,160,80,.16); color: var(--down-fg); }
/* dice tray */
.cb-dice-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3); margin-bottom: var(--sp-4); }
.cb-dice-row:last-child { margin-bottom: 0; }
.cb-die { position: relative; background: var(--panel-2); border: 0.0625rem solid var(--border); color: var(--text); border-radius: var(--r-md);
  padding: var(--sp-3) var(--sp-5); font-family: var(--font-mono); font-size: var(--fs-xs); cursor: pointer; transition: border-color .12s, color .12s; }
.cb-die:hover { border-color: var(--accent); color: var(--accent); }
.cb-die.sm { padding: var(--sp-3) var(--sp-5); min-width: 1.625rem; }
.cb-die.roll { background: var(--accent); border-color: var(--accent); color: var(--roll-fg); font-weight: 600; margin-left: auto; }
.cb-die.roll:hover { filter: brightness(1.08); color: var(--roll-fg); }
.cb-die-n { position: absolute; top: -0.375rem; right: -0.375rem; background: var(--gold); color: var(--roll-fg); border-radius: var(--r-lg);
  min-width: 0.9375rem; height: 0.9375rem; display: inline-flex; align-items: center; justify-content: center; font-size: var(--fs-micro); font-weight: 700; padding: 0 var(--sp-2); }
.cb-dice-mod { font-family: var(--font-mono); font-size: var(--fs-2xs); color: var(--muted); }


/* sight-outline cones + move-path preview + clickable doors */
.cb-cone { position: absolute; pointer-events: none; z-index: 1; }

.cb-path.end { background: rgba(var(--gold-rgb),.28); border-style: solid; }
.cb-path.over { border-color: rgba(var(--tint-attack-rgb),.7); background: rgba(var(--tint-attack-rgb),.14); color: var(--over-fg); }
/* SVG move-plan route (legacy drawPath parity): dashed line + dots + ghost target ring + ft label */
.cb-route { position: absolute; left: 0; top: 0; pointer-events: none; z-index: 5; overflow: visible; }
.cb-r-line { fill: none; stroke: var(--gold); stroke-width: 2.5; stroke-dasharray: 4 7; stroke-linecap: round; stroke-linejoin: round; opacity: .95; }
.cb-r-dot { fill: var(--gold); opacity: .9; }
.cb-r-ghost { fill: rgba(var(--gold-rgb),.14); stroke: var(--gold); stroke-width: 2; stroke-dasharray: 3 4; }
.cb-r-ghost.blocked, .cb-route.over .cb-r-ghost, .cb-r-ghost.over { fill: rgba(var(--tint-attack-rgb),.16); stroke: rgb(var(--tint-attack-rgb)); }
.cb-r-cross { stroke: rgb(var(--tint-attack-rgb)); stroke-width: 2.5; stroke-linecap: round; opacity: .95; }

.cb-route.over .cb-r-line { stroke: rgb(var(--tint-attack-rgb)); }
.cb-r-label { fill: var(--gold); font-family: var(--font-mono); font-size: var(--fs-sm); font-weight: 600; paint-order: stroke; stroke: rgba(0,0,0,.75); stroke-width: 0.1875rem; }
.cb-r-label.over { fill: rgb(var(--tint-attack-rgb)); }
.cb-wp { position: absolute; pointer-events: none; z-index: 5; display: flex; align-items: center; justify-content: center; color: var(--gold); font-size: var(--fs-md); text-shadow: 0 0.0625rem 0.125rem var(--dead-fg); }
.cb-peerpath { position: absolute; pointer-events: none; z-index: 3; box-sizing: border-box; border: 0.0625rem dashed color-mix(in srgb, var(--side) 70%, var(--cb-peerpath-bd)); background: color-mix(in srgb, var(--side) 12%, transparent); }
.cb-token.movable { cursor: grab; }
.cb-token.movable:active, .cb-token.dragging { cursor: grabbing; }
.cb-token.dragging { z-index: 11; }
.cb-token.dragging .cb-tk-disc { transform: scale(1.08); box-shadow: 0 0 0 0.125rem var(--gold), 0 0.625rem 1.375rem -0.375rem rgba(0,0,0,.8), 0 0 0.875rem rgba(var(--gold-rgb),.6); }
.cb-ter.door.is-clickable, .cb-ter.door { cursor: pointer; pointer-events: auto; }
.cb-ter.door:hover { box-shadow: inset 0 0 0 0.125rem var(--gold); }

/* vision panel (player / spectator) + map key */
.cb-vis-row { display: flex; gap: var(--sp-7); margin-bottom: var(--sp-4); }
.cb-vis-toggle { margin-top: var(--sp-4); }
.cb-legend-list { list-style: none; margin: var(--sp-4) 0 0; padding: 0; display: flex; flex-direction: column; gap: 0.3125rem; }
.cb-legend-list li { display: flex; align-items: center; gap: 0.5625rem; font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--text); }
.cb-lg-sw { width: 1.0625rem; height: 1.0625rem; border-radius: var(--r-xs); flex: 0 0 1.0625rem; box-sizing: border-box; }
.cb-lg-ally { background: var(--gold); box-shadow: 0 0 0 0.0625rem rgba(0,0,0,.4); }
.cb-lg-enemy { background: var(--bad); box-shadow: 0 0 0 0.0625rem rgba(0,0,0,.4); }
.cb-lg-wall { background: linear-gradient(150deg, var(--cb-lg-wall-bg), var(--cb-lg-wall-bg2)); border: 0.0625rem solid var(--cb-lg-wall-bd); }
.cb-lg-door { background: linear-gradient(180deg, var(--cb-lg-door-bg), var(--cb-lg-door-bg2)); box-shadow: inset 0 0 0 0.09375rem rgba(var(--gold-rgb),.5); }
.cb-lg-cover { background: linear-gradient(180deg, var(--cb-lg-cover-bg), var(--cb-lg-cover-bg2)); border: 0.0625rem solid var(--cb-lg-cover-bd); }
.cb-lg-diff { background: repeating-linear-gradient(45deg, var(--cb-lg-diff-bg), var(--cb-lg-diff-bg) 0.1875rem, var(--cb-lg-diff-bg2) 0.1875rem, var(--cb-lg-diff-bg2) 0.375rem); }
 

/* combat log */

.cb-log { max-height: 30vh; overflow-y: auto; display: flex; flex-direction: column; gap: var(--sp-1); padding-right: var(--sp-1);
  font-family: var(--font-mono); font-size: var(--fs-xs); line-height: 1.45; scroll-behavior: smooth; }
.cb-log-line { color: var(--text); padding: 0.0625rem 0; border-left: 0.125rem solid transparent; padding-left: 0.4375rem; }
.cb-log-turn { color: var(--gold); border-left-color: var(--gold); margin-top: var(--sp-2); }
.cb-log-gold { color: var(--gold); font-weight: 600; }
.cb-log-hit { color: var(--cb-hit); } .cb-log-crit { color: var(--cb-crit); font-weight: 600; }
.cb-log-miss { color: var(--muted); }
.cb-log-damage { color: var(--cb-damage); } .cb-log-death { color: var(--cb-death); font-weight: 600; }
.cb-log-heal { color: var(--cb-heal); }
.cb-log-cond { color: var(--cb-cond); }
.cb-log-dice { color: var(--cb-log-dice-fg); }
.cb-log-narr { color: var(--cb-log-narr-fg); font-style: italic; font-family: var(--font-display); font-size: var(--fs-smplus); padding: var(--sp-2) 0 var(--sp-2) 0.4375rem; }

/* join / character chooser */
.cb-place .cb-react-text b { color: var(--cb-react-text-fg); }
.cb-modal-bg { position: fixed; inset: 0; z-index: 60; background: rgba(8,6,3,.72); backdrop-filter: blur(0.1875rem); display: flex; align-items: center; justify-content: center; }
.cb-modal { width: min(28.75rem, 92vw); max-height: 84vh; overflow-y: auto; background: linear-gradient(180deg, var(--panel), var(--panel-2));
  border: 0.0625rem solid var(--border); border-radius: var(--r-2xl); padding: 1.375rem; box-shadow: var(--shadow-drop-lg); }
.cb-modal h2 { margin: 0 0 var(--sp-3); font-family: var(--font-display); font-size: var(--fs-modal); color: var(--gold); }
.cb-modal-sub { margin: 0 0 var(--sp-9); color: var(--muted); font-size: var(--fs-smplus); }
.cb-choices { display: flex; flex-direction: column; gap: var(--sp-5); margin-bottom: var(--sp-9); }
.cb-choice { display: flex; flex-direction: column; align-items: flex-start; gap: var(--sp-1); text-align: left; cursor: pointer;
  background: var(--panel-2); border: 0.0625rem solid var(--border); border-radius: var(--r-lg); padding: 0.6875rem var(--sp-8); transition: border-color .12s, transform .08s; }
.cb-choice:hover { border-color: var(--accent); transform: translateX(0.125rem); }
.cb-choice-name { font-family: var(--font-display); font-size: var(--fs-md); color: var(--text); }
.cb-choice-detail { font-family: var(--font-mono); font-size: var(--fs-2xs); color: var(--muted); }
/* join / landing modal */
.cb-joincard { position: relative; width: min(27.5rem, 92vw); max-height: 86vh; display: flex; flex-direction: column; text-align: center;
  background: radial-gradient(135% 130% at 50% 0%, rgba(var(--accent-rgb),.08), transparent 60%), linear-gradient(180deg, var(--panel), var(--panel-2));
  border: 0.0625rem solid var(--border); border-radius: var(--r-2xl); padding: 1.375rem var(--sp-11) var(--sp-10); box-shadow: var(--shadow-drop-lg); }
/* Only the character list scrolls — the title, "or" divider and role buttons stay pinned, keeping the
   popup compact no matter how many heroes are claimable. */
.cb-joincard > * { flex: 0 0 auto; }
.cb-join-eyebrow { display: block; font-family: var(--font-mono); font-size: var(--fs-2xs); letter-spacing: .22em; text-transform: uppercase; color: var(--gold); opacity: .85; }
.cb-join-h { margin: var(--sp-3) 0 var(--sp-3); font-family: var(--font-display); font-size: var(--fs-page); color: var(--text); }
.cb-joincard .cb-choices { text-align: left; margin: var(--sp-8) 0 var(--sp-3); flex: 0 1 auto; min-height: 0; max-height: 15.375rem; overflow-y: auto; padding-right: var(--sp-3); }
.cb-join-divider { display: flex; align-items: center; gap: var(--sp-6); color: var(--muted); font-family: var(--font-mono); font-size: var(--fs-2xs); text-transform: uppercase; letter-spacing: .1em; margin: var(--sp-8) var(--sp-1); }
.cb-join-divider::before, .cb-join-divider::after { content: ""; flex: 1; height: 0.0625rem; background: var(--border); }
.cb-join-roles { display: flex; gap: var(--sp-5); justify-content: center; }
.cb-join-roles .cb-cbtn { padding: 0.5625rem 1.125rem; font-size: var(--fs-sm); }
.cb-join-close { position: absolute; top: 0.75rem; right: 0.875rem; font-size: var(--fs-lg); }  /* icon-btn (2.2) */

/* token crop editor */


.cb-crop { width: min(51.25rem, 94vw); max-height: 90vh; overflow-y: auto; background: linear-gradient(180deg, var(--panel), var(--panel-2));
  border: 0.0625rem solid var(--border); border-radius: var(--r-2xl); padding: var(--sp-10); box-shadow: var(--shadow-drop-lg); }
.cb-crop-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--sp-8); }
.cb-crop-head h2 { margin: 0; font-family: var(--font-display); font-size: var(--fs-sub); color: var(--gold); }
.cb-crop-pages { display: flex; align-items: center; gap: var(--sp-5); font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--muted); }
.cb-crop-body { display: flex; gap: 1.125rem; }
.cb-crop-stage { position: relative; flex: 1 1 auto; user-select: none; touch-action: none; line-height: 0; max-width: 35rem; }
.cb-crop-img { max-width: 100%; max-height: 62vh; border-radius: var(--r-lg); display: block; }
.cb-crop-box { position: absolute; border: 0.125rem solid var(--gold); box-shadow: 0 0 0 624.9375rem rgba(8,6,3,.5); cursor: move; }
.cb-crop-h { position: absolute; width: 0.8125rem; height: 0.8125rem; background: var(--gold); border: 0.125rem solid var(--roll-fg); border-radius: var(--r-round); }
.cb-crop-h-nw { left: -0.4375rem; top: -0.4375rem; cursor: nwse-resize; } .cb-crop-h-se { right: -0.4375rem; bottom: -0.4375rem; cursor: nwse-resize; }
.cb-crop-h-ne { right: -0.4375rem; top: -0.4375rem; cursor: nesw-resize; } .cb-crop-h-sw { left: -0.4375rem; bottom: -0.4375rem; cursor: nesw-resize; }
.cb-crop-circle { position: absolute; border: 0.125rem dashed var(--cb-crop-circle-bd); border-radius: var(--r-round); cursor: move; box-shadow: 0 0 0 0.125rem rgba(0,0,0,.35) inset; }
.cb-crop-ch { position: absolute; right: -0.4375rem; bottom: -0.4375rem; width: 0.8125rem; height: 0.8125rem; background: var(--cb-crop-circle-bd); border: 0.125rem solid var(--cb-crop-ch-bd); border-radius: var(--r-round); cursor: nwse-resize; }
.cb-crop-side { flex: 0 0 8.125rem; display: flex; flex-direction: column; gap: 0.5625rem; align-items: center; }
.cb-crop-prevlabel { font-family: var(--font-mono); font-size: var(--fs-micro); letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }
.cb-crop-prev { width: 6.5rem; height: 6.5rem; border-radius: var(--r-round); background: var(--cb-crop-prev-bg) no-repeat; border: 0.125rem solid var(--gold); box-shadow: var(--shadow-drop-sm); }
.cb-crop-bg { display: flex; align-items: center; gap: var(--sp-4); font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--text); cursor: pointer; }
.cb-crop-hint { font-size: var(--fs-2xs); color: var(--muted); line-height: 1.5; text-align: center; }
.cb-crop-foot { display: flex; justify-content: flex-end; gap: var(--sp-5); margin-top: var(--sp-9); }

/* DM tools panel */






  .cb-dm-sel.grow { flex: 1 1 auto; }
/* kit NumberField wrappers: the span keeps the layout slot; the .ui-num inside is the input */

span.cb-dm-in .ui-num { width: 100%; }
span.cb-dice-modin { padding: 0; border: 0; background: none; display: inline-flex; }
span.cb-dice-modin .ui-num { width: 100%; }



.cb-dm-btn.wide { width: 100%; }





/* reaction prompt (opportunity attack / continue-move) */
.cb-react { display: flex; align-items: center; gap: var(--sp-6); padding: 0.5625rem var(--sp-8); border-radius: var(--r-xl);
  background: linear-gradient(180deg, rgba(48,34,14,.97), rgba(34,24,12,.97)); border: 0.0625rem solid var(--gold);
  box-shadow: 0 0.5rem 1.75rem rgba(0,0,0,.55), 0 0 0 0.0625rem rgba(var(--gold-rgb),.25); animation: cbreact .18s ease-out; }
@keyframes cbreact { from { opacity: 0; transform: translateY(0.5rem); } to { opacity: 1; transform: none; } }
.cb-react-text { font-size: var(--fs-smplus); color: var(--cb-react-text-fg); } .cb-react-text b { color: var(--gold); }
.cb-react-yes, .cb-react-no { border-radius: var(--r-md); padding: 0.3125rem 0.8125rem; font-family: var(--font-mono); font-size: var(--fs-xs); cursor: pointer; border: 0.0625rem solid var(--border); }
.cb-react-yes { background: var(--accent); border-color: var(--accent); color: var(--roll-fg); font-weight: 600; }
.cb-react-yes:hover { filter: brightness(1.08); }
.cb-react-no { background: var(--panel-2); color: var(--muted); } .cb-react-no:hover { border-color: var(--accent); color: var(--text); }

/* ── phase 2: turn controls · action bar · move hint · toast ── */


/* .cb-cbtn folded onto the kit (2.1 look-fold): `btn cb-cbtn`; mono/padding deltas. `.primary` is now `btn-primary`. */
.cb-cbtn { padding: 0.3125rem 0.6875rem; font-family: var(--font-mono); font-size: var(--fs-xs); }
.cb-cbtn.ghost { padding: 0.3125rem 0.5625rem; color: var(--muted); }

.cb-movehint { position: absolute; left: 50%; top: -1.375rem; transform: translateX(-50%); font-family: var(--font-mono);
  font-size: var(--fs-2xs); color: var(--gold); background: rgba(23,18,12,.8); padding: var(--sp-1) var(--sp-5); border-radius: var(--r-xl); white-space: nowrap; pointer-events: none; }

/* action bar (bottom-center of the stage) */
/* ONE docked home for every in-combat decision. play_combat.js renders EITHER the action strip
   OR the reaction prompt into this wrapper — before, each child positioned itself absolutely and
   they landed in different places (strip bottom-centre, reaction prompt TOP-centre), so an
   opportunity-attack ask appeared nowhere near where you take every other combat action. */
.cb-strip { position: absolute; left: 50%; bottom: 0.875rem; transform: translateX(-50%); z-index: 24;
  display: flex; flex-direction: column; align-items: center; gap: var(--sp-4);
  max-width: calc(100% - 2rem); pointer-events: none; }
.cb-strip > * { pointer-events: auto; }

.cb-actionbar { display: flex; flex-direction: column; gap: 0.4375rem;
  background: radial-gradient(135% 130% at 0% 0%, rgba(var(--accent-rgb),.07), transparent 58%), rgba(18,13,9,.86);
  -webkit-backdrop-filter: blur(0.6875rem) saturate(1.12); backdrop-filter: blur(0.6875rem) saturate(1.12);
  border: 0.0625rem solid var(--border); border-radius: var(--r-xl); padding: 0.5625rem var(--sp-7) 0.6875rem; box-shadow: var(--shadow-card);
  width: min(36.25rem, 60vw); z-index: 22; }
.cb-ab-who { display: flex; align-items: center; gap: 0.5625rem; padding-bottom: var(--sp-1); }
.cb-ab-disc { width: 2.125rem; height: 2.125rem; border-radius: var(--r-round); overflow: hidden; flex: 0 0 auto; border: 0.125rem solid rgba(0,0,0,.45);
  background: var(--side); display: flex; align-items: center; justify-content: center; font-family: var(--font-mono); font-weight: 700; font-size: var(--fs-sm); color: var(--bg); }
.cb-ab-disc img { width: 100%; height: 100%; object-fit: cover; }
.cb-ab-who > div { flex: 1 1 auto; min-width: 0; }
.cb-ab-who b { color: var(--gold); font-family: var(--font-display); font-size: var(--fs-lg); line-height: 1.1; display: block; }
.cb-ab-mv { font-family: var(--font-mono); font-size: var(--fs-2xs); color: var(--muted); }
.cb-ab-acts { display: flex; align-items: center; flex-wrap: wrap; gap: 0.3125rem; }
.cb-ab-btn.sm { padding: 0.3125rem 0.5625rem; font-size: var(--fs-xs); }
.cb-ab-btn:disabled { opacity: .38; cursor: not-allowed; }
.cb-ab-btn.is-on { background: rgba(var(--gold-rgb),.18); border-color: var(--gold); color: var(--gold); opacity: 1; box-shadow: inset 0 0 0 0.0625rem rgba(var(--gold-rgb),.4); }

.cb-ab-rx.used { background: var(--border); box-shadow: none; opacity: .55; }
.cb-ab-nl { display: inline-flex; align-items: center; gap: var(--sp-3); font-family: var(--font-mono); font-size: var(--fs-2xs); color: var(--muted); cursor: pointer; }
/* .cb-ab-btn folded onto the kit (2.1 look-fold): `btn cb-ab-btn`; mono/padding deltas. `.end` is now `btn-primary`;
   `.is-on` gold-selected + `.atk`/`.cast` action-type tints stay below. */
.cb-ab-btn { padding: 0.4375rem var(--sp-6); font-family: var(--font-mono); font-size: var(--fs-xs); font-weight: 600; }
.cb-ab-btn.spent { opacity: .45; }
/* .cb-ab-btn.end (End turn) is now a filled `btn-primary` (ember action). */
.cb-ab-wait { font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--muted); font-style: italic; padding: 0.3125rem var(--sp-3); letter-spacing: .02em; }
.cb-ab-textin { width: 12.5rem; font-size: var(--fs-xs); padding: 0.3125rem var(--sp-4); }

/* dice pad — tumbling hexagon dice land center-board on a roll, then fade */
.cb-dicepad { position: absolute; left: 50%; top: 15%; transform: translate(-50%, -50%); z-index: 28; display: flex; gap: var(--sp-7); pointer-events: none;
  animation: cb-dice-fade 2.4s ease-out forwards; }
@keyframes cb-dice-fade { 0%,72% { opacity: 1; } 100% { opacity: 0; } }
.cb-die3 { position: relative; width: 3.125rem; height: 3.125rem; filter: drop-shadow(0 0.375rem 0.5625rem rgba(0,0,0,.6)); animation: cb-die-drop .34s cubic-bezier(.2,.72,.25,1); }
@keyframes cb-die-drop { from { transform: translateY(2.5rem) scale(.5); opacity: 0; } 55% { transform: translateY(-0.5rem) scale(1.06); opacity: 1; } to { transform: none; opacity: 1; } }
.cb-die3 svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
/* d20 silhouette + interior facet lines → reads as a real die, matching the legacy board */
.cb-die3-shape { fill: rgba(18,13,9,.94); stroke: rgba(var(--gold-rgb),.55); stroke-width: 2; stroke-linejoin: round; }
.cb-die3-facet { fill: none; stroke: rgba(var(--gold-rgb),.3); stroke-width: 1; stroke-linejoin: round; }
.cb-die3-v { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; font-family: var(--font-mono); font-weight: 700; font-size: var(--fs-modal); color: var(--text); text-shadow: 0 0.0625rem 0.125rem var(--dead-fg); }
/* spin only the SHAPE while rolling, so the number stays upright and readable */
.cb-die3.rolling svg { animation: cb-die-spin .5s linear infinite; transform-origin: 50% 50%; }
@keyframes cb-die-spin { to { transform: rotate(360deg); } }
.cb-die3.max .cb-die3-shape { stroke: var(--gold); stroke-width: 2.6; } .cb-die3.max { filter: drop-shadow(0 0 0.6875rem rgba(var(--gold-rgb),.75)); } .cb-die3.max .cb-die3-v { color: var(--gold); }
.cb-die3.min .cb-die3-shape { stroke: var(--bad); } .cb-die3.min { filter: drop-shadow(0 0 0.625rem rgba(248,81,73,.7)); } .cb-die3.min .cb-die3-v { color: var(--bad); }
/* advantage / disadvantage pair: tint + label; the dropped die is dimmed & struck through */
.cb-die3--adv .cb-die3-shape { stroke: var(--gold); }
.cb-die3--dis .cb-die3-shape { stroke: var(--cb-die3-shape-stroke); }
.cb-die3--adv::after, .cb-die3--dis::after { position: absolute; top: -0.625rem; left: 50%; transform: translateX(-50%);
  font-family: var(--font-mono); font-size: var(--fs-micro); letter-spacing: .08em; text-transform: uppercase; opacity: .9; }
.cb-die3--adv::after { content: "adv"; color: var(--gold); }
.cb-die3--dis::after { content: "dis"; color: var(--cb-die3-shape-stroke); }
.cb-die3--dropped { opacity: .4; }
.cb-die3--dropped .cb-die3-v { text-decoration: line-through; color: var(--muted); }
.cb-die3--dropped .cb-die3-shape { stroke: var(--muted); }
@media (prefers-reduced-motion: reduce) { .cb-die3, .cb-die3.rolling svg, .cb-dicepad { animation: none; } }

/* toast feed — a stack of color-coded combat callouts, top-right of the board */
/* (combat event toasts fire the ONE kit toast system — views/_toast.js + theme.css .toast) */
@media (prefers-reduced-motion: reduce) { .cb-float, .cb-float-damage, .cb-float-heal { animation: none; } }
.cb-token:focus-visible { outline: 0.125rem solid var(--text); outline-offset: 0.125rem; }

/* floating numbers that rise over a token's cell when it's hit / healed / rolls */
.cb-float { position: absolute; z-index: 8; transform: translate(-50%, 0); font-family: var(--font-mono); font-weight: 700; font-size: var(--fs-md);
  text-shadow: 0 0.0625rem 0.1875rem var(--dead-fg), 0 0 0.25rem var(--dead-fg); pointer-events: none; white-space: nowrap; animation: cb-float-rise 1.3s ease-out forwards; }
@keyframes cb-float-rise { 0% { opacity: 0; transform: translate(-50%, 0.375rem) scale(.7); } 18% { opacity: 1; transform: translate(-50%, -0.25rem) scale(1.1); }
  100% { opacity: 0; transform: translate(-50%, -2.125rem) scale(1); } }
.cb-float-damage { color: var(--cb-damage); } .cb-float-heal { color: var(--cb-heal); }
.cb-float-crit { color: var(--cb-crit); font-size: var(--fs-sub); } .cb-float-dice { color: var(--cb-react-text-fg); }
.cb-float-hit { color: var(--cb-hit); } .cb-float-miss { color: var(--cb-float-miss-fg); font-weight: 500; } .cb-float-death { color: var(--cb-death); }

/* ── terrain + fog of war ── */
.cb-ter { position: absolute; box-sizing: border-box; display: flex; align-items: center; justify-content: center;
  font-size: var(--fs-modal); color: rgba(220,200,160,.55); pointer-events: none; }
.cb-ter-wall { background: repeating-linear-gradient(45deg, var(--cb-ter-wall-bg), var(--cb-ter-wall-bg) 0.375rem, var(--cb-ter-wall-bg2) 0.375rem, var(--cb-ter-wall-bg2) 0.75rem); border: 0.0625rem solid var(--cb-ter-wall-bd); box-shadow: inset 0 0 0.375rem rgba(0,0,0,.6); }
.cb-ter-cover_half, .cb-ter-cover_full { color: rgba(200,170,120,.7); }
.cb-ter-difficult { background: rgba(120,90,50,.16); color: rgba(200,160,110,.5); }
.cb-ter-water { background: rgba(70,110,150,.26); color: rgba(140,190,230,.7); }
.cb-ter-hazard { background: rgba(160,60,40,.22); color: rgba(230,120,90,.85); }
.cb-ter-brush { background: rgba(var(--tint-veg-rgb),.16); color: rgba(var(--tint-veg-hi-rgb),.6); }
.cb-ter-foliage_dense { background: rgba(var(--tint-veg-dense-rgb),.34); color: rgba(var(--tint-veg-dense-hi-rgb),.75); }
/* Dense foliage IN SIGHT: the thicket's surface is visible (tile art shows through) while its
   contents stay hidden — a translucent green-dark shroud, clearly distinct from unexplored dark. */
.cb-fog-veil { background: rgba(16,26,12,.52); box-shadow: inset 0 0 0.75rem -0.1875rem rgba(0,0,0,.6); }
.cb-lg-brush, .cb-lg-dense { display: inline-flex; align-items: center; justify-content: center; font-size: var(--fs-2xs); }
.cb-lg-brush { background: rgba(var(--tint-veg-rgb),.3); color: rgba(var(--tint-veg-hi-rgb),.9); }
.cb-lg-dense { background: rgba(var(--tint-veg-dense-rgb),.5); color: rgba(var(--tint-veg-dense-hi-rgb),.95); }
.cb-ter-door_closed, .cb-ter-door_open { color: rgba(210,180,130,.85); }

.cb-fog { position: absolute; pointer-events: none; }
.cb-fog-dark { background: var(--cb-fog-dark-bg); }
.cb-fog-dim { background: rgba(6,5,4,.62); }
/* a cell you CAN see but that lies in dim/dark light — a bluish shadow tint, not a sight blocker */
.cb-fog-shadow { background: rgba(20,28,48,.34); box-shadow: inset 0 0 0.875rem -0.25rem rgba(0,0,0,.5); }
.cb-fog-shadow.dark { background: rgba(10,14,28,.55); }

/* ── attack target mode ── */
.cb-token.target { cursor: crosshair; }
.cb-token.target .cb-tk-disc { box-shadow: 0 0 0 0.125rem rgb(var(--tint-attack-rgb)), 0 0 0.75rem rgba(var(--tint-attack-rgb),.7); animation: cbtarget 1s ease-in-out infinite; }
@keyframes cbtarget { 0%,100% { box-shadow: 0 0 0 0.125rem rgb(var(--tint-attack-rgb)), 0 0 0.5rem rgba(var(--tint-attack-rgb),.5); } 50% { box-shadow: 0 0 0 0.1875rem rgb(var(--tint-attack-rgb)), 0 0 1rem rgba(var(--tint-attack-rgb),.9); } }
.cb-ab-btn.atk { background: rgba(200,80,70,.18); border-color: var(--atk-bd); color: var(--atk-fg); }
.cb-ab-btn.atk:hover { border-color: rgb(var(--tint-attack-rgb)); color: var(--atk-fg2); }
.cb-ab-btn.cast { background: rgba(120,90,200,.18); border-color: var(--cast-bd); color: var(--cast-fg); }
.cb-ab-btn.cast:hover { border-color: var(--cast-bd2); color: var(--cast-fg2); }
.cb-ab-spells { flex-wrap: wrap; max-width: min(40rem, 70vw); }
.cb-ab-prompt { font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--gold); }

/* ============================================================================
   UI refinement pass — "tactical battle map by torchlight"
   Sharpens the existing ember/brass/vellum identity: lights the board, raises
   type hierarchy, models the action economy, and improves token legibility.
   Scoped to the combat SPA only (no theme.css changes). Appended last so these
   override earlier rules at equal specificity.
   ============================================================================ */

/* ── 1. Light the board ──────────────────────────────────────────────────────
   The map is the hero. Layer a warm torch-glow over the play area and let the
   edges fall into shadow (vignette), so the battlefield reads as a lit table in
   the dark rather than a small grid lost in a void. */
.cb-stage {
  background:
    radial-gradient(circle at 50% 44%, rgba(var(--accent-rgb),.13), rgba(var(--accent-rgb),.04) 34%, transparent 64%),
    radial-gradient(ellipse 130% 120% at 50% 46%, transparent 52%, rgba(0,0,0,.62) 100%),
    var(--bg-deep);
}
/* The bordered play area = inked, faintly-lit parchment, distinct from the void.
   Warmer hairlines + a soft inner glow give the grid the feel of a battle-map
   drawn on a lit surface (still subtle — restraint). */
.cb-grid {
  background-color: rgba(var(--gold-rgb),.05);
  background-image:
    linear-gradient(to right, rgba(var(--gold-rgb),.16) 0.0625rem, transparent 0.0625rem),
    linear-gradient(to bottom, rgba(var(--gold-rgb),.16) 0.0625rem, transparent 0.0625rem);
  box-shadow:
    0 0 0 0.0625rem rgba(0,0,0,.5),
    inset 0 0 4.375rem -0.625rem rgba(var(--accent-rgb),.16),
    var(--glow-gold, 0 0 1rem -0.3125rem rgba(var(--gold-rgb),.5));
}

/* ── 2. The round counter is the combat clock — make it legible ───────────────
   It was clipping to "RND…". Let the title shrink first; never truncate the
   round, and give it a touch more presence. */
.cb-h1 { min-width: 0; }


/* ── 3. The action bar is the live control surface — let it lead ──────────────
   Among identical HUD cards, the bar where the active creature acts should read
   as the focal surface: a brass top edge + a stronger lift. */
.cb-actionbar {
  border-top-color: rgba(var(--gold-rgb),.55);
  box-shadow:
    0 1rem 2.375rem -1.125rem rgba(0,0,0,.9),
    0 0 1.375rem -0.625rem rgba(var(--accent-rgb),.4),
    inset 0 0.0625rem 0 rgba(255,255,255,.05);
}
/* Active combatant's name carries the personality face at a confident size. */
.cb-ab-who b { font-size: var(--fs-sub); letter-spacing: .005em; }

/* ── 4. Model the action economy (Action / Bonus / Reaction) ──────────────────
   D&D players track three resources each turn. Show them as three labelled pips
   that go dark when spent — replacing the lone reaction dot. */
.cb-ab-eco { margin-left: auto; display: inline-flex; gap: var(--sp-3); flex: 0 0 auto; }
.cb-eco-pip {
  width: 1.0625rem; height: 1.0625rem; border-radius: var(--r-sm); display: inline-flex;
  align-items: center; justify-content: center; font-family: var(--font-mono);
  font-size: var(--fs-micro); font-weight: 700; color: var(--cb-eco-pip-fg); background: var(--gold);
  border: 0.0625rem solid rgba(0,0,0,.4); box-shadow: 0 0 0.5rem -0.125rem rgba(var(--gold-rgb),.7);
  transition: background .14s, color .14s, box-shadow .14s, opacity .14s;
}
.cb-eco-pip.r { background: var(--accent); box-shadow: 0 0 0.5rem -0.125rem rgba(var(--accent-rgb),.7); }
.cb-eco-pip.used {
  background: transparent; color: var(--muted);
  border-color: var(--border); box-shadow: none; opacity: .6;
}

/* ── 5. Token legibility ─────────────────────────────────────────────────────
   Condition chips were 7px (unreadable). Bump size + contrast. */
.cb-tk-cond { font-size: var(--fs-micro); padding: 0.0625rem var(--sp-2); letter-spacing: .02em; }
/* Distinguish a player-controlled token from an AI ally: a thin brass ring. */
.cb-token.pc .cb-tk-disc { box-shadow: 0 0 0 0.125rem rgba(var(--gold-rgb),.55), 0 0.25rem 0.625rem -0.25rem rgba(0,0,0,.7); }
/* A slightly taller HP bar reads at a glance without dominating the disc. */
.cb-tk-hp { height: 0.3125rem; bottom: -0.5rem; }

/* ── 6. Quiet the repeated reticle on secondary panels ───────────────────────
   Reserve the full brass L-bracket signature for the focal cards; soften it on
   the rest so the decoration doesn't compete everywhere at once (Chanel rule). */

/* ── 7. Type rebalance — mono for DATA, sans for WORDS ────────────────────────
   The panels leaned on JetBrains Mono for everything, which read as a debug
   terminal rather than a designed game UI. Split typography by what the text IS:
     • mono  → DATA only: numbers, dice, ft, stat rows, ids, the A/B/R pips,
               and the letter-spaced KPI eyebrows / section labels (kept — they
               are the theme's signature and removing them would gut the
               identity, not refine it). Untouched above.
     • Cormorant → proper names. Already applied in the refinement pass
               (.cb-h1 / .cb-sel-head b / .cb-ab-who b / .cb-dm-sub / choices).
     • sans  → everything else in the panel BODY: interactive control labels,
               action-bar buttons, prose/status/hints, and word-tags (faction,
               conditions, attack names). That is this block.
   Appended so these single-class rules override the mono declarations above at
   equal specificity via source order — the same mechanism the refinement pass
   relies on. Data rules above are deliberately NOT listed here. */

/* interactive controls (buttons & toggles) — UI chrome, align with the app's sans */
.cb-cbtn{ font-family: var(--font-sans); }

/* Action labels are the focal surface — at sans they want a touch less tracking
   and a hair more size than the mono they replaced, to read as confident words. */
.cb-ab-btn { letter-spacing: .005em; font-size: var(--fs-xs); min-height: 0; }  /* dense combat: keep content-height, not the kit 2rem floor */

/* ── The Gem HUD (left-hand gem menu): account-bound progress / stats / fast-travel ── */

/* Tile-art backdrop behind the tactical grid (Play combat mode). The canvas renders the combat Map's
   tiles in the same camera space as .cb-world; the faint grid + tokens sit on top. */
.cb-stage .cb-tilebg { position: absolute; inset: 0; z-index: 0; pointer-events: none; }
.cb-stage .cb-world { z-index: 1; }
/* U2: shared-renderer token canvas — drawn OVER the DOM board (z above .cb-world's tokens) so a screenshot
   shows the canvas reproduction to compare; never intercepts pointers (the DOM tokens own interaction). */

/* AUDIT 2026-07-17 — law-compliant control replacements */
.cb-dice-mod { display: inline-flex; align-items: center; gap: 0.3125rem; }
.cb-dice-modin { width: 3.25rem; }
/* mode seg in the mode bar (matches the DM card's .seg) */
.cb-dm-row .ui-switch { margin-right: var(--sp-5); }


/* the seated player's character card — a self-managed window docked bottom-right of the stage */
.cb-charcard { position: absolute; right: 0.75rem; bottom: 0.75rem; z-index: 29; }
.cb-dmcard { position: absolute; right: 0.75rem; bottom: 0.75rem; z-index: 29; }
/* the DM card's Act section hosts the old action bar's rows */
.dmc-actwrap .cb-ab-acts { display: flex; flex-wrap: wrap; gap: var(--sp-3); }
.dmc-sideSel { flex: 0 0 auto; min-width: 6.5rem; }
