/* ══════════════════════════════════════════════════════════════
   Component — Overlays (weapon popup, roll overlay, dice, results)
   Merged from shoot/v0.4/style.css + v0.8a/style.css
   v0.8a versions win where both define the same selector.
══════════════════════════════════════════════════════════════ */

/* ── Overlay panel base ── */
/* Per-unit popup chrome: themed to the OWNING faction (the unit the
   panel is anchored to). Set `.side-a` / `.side-b` on the panel's
   root in JS to override. Defaults to `--active-faction` when no
   side scope is set, so panels for the active player render cleanly
   without explicit tagging.

   "Glass" treatment matches the #phase-header .phase-pill chrome
   (shared/css/battlefield.css): a low-opacity dark gradient layered
   over a backdrop blur, so the board reads through faintly. The
   previous rgba(10,16,22,.96) was effectively opaque — the user
   reported the dice overlay looked like a solid panel instead of
   matching the rest of the in-game chrome. */
.overlay-panel {
  position: absolute; z-index: 70;
  background: linear-gradient(180deg, rgba(8,12,16,.85), rgba(8,12,16,.72));
  border: 1px solid color-mix(in srgb, var(--owning-faction) 22%, transparent);
  border-top: 2px solid var(--owning-faction);
  border-radius: 14px;
  box-shadow: 0 12px 40px rgba(0,0,0,.45);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
.overlay-panel.hidden { display: none; }

/* Modal interaction blocking lives in JS — `game/core/modal-registry.js`
   sets the Pixi stage's `eventMode = 'none'` whenever any modal/overlay is
   visible. Unit pickers (model/hull pointertap) are blocked; camera pan/zoom
   listeners are plain DOM events on the canvas/window and remain live so
   the user can pan/zoom while a dice or pause overlay is up.
   The MutationObserver detects ALL known modal surfaces (overlay-panel,
   pause menu, options modal, strat modal, scoring legend) without needing
   per-element CSS rules. */
.overlay-title {
  padding: 8px 10px 6px;
  color: var(--owning-faction);
  font: 700 10px/1 'Rajdhani', sans-serif;
  letter-spacing: 2px;
  text-transform: uppercase;
}

/* ── Weapon popup (hidden in v0.8a — unified into roll-overlay) ── */
#weapon-popup { display: none !important; }

/* ── Choice grid — shared base for weapon / shooter / transport pickers ── */
.choice-grid {
  display: flex;
  gap: 8px;
  padding: 8px 14px 6px;
  justify-content: center;
}
.choice-grid .choice-card {
  flex: 1;
  min-width: 0;
  max-width: 220px;
}
/* Choice cards (weapon / shooter / transport pickers) — themed to the
   owning popup's faction so cobalt UM and gold Custodes pickers don't
   collide on chrome color. */
.choice-card {
  width: calc(100% - 12px); margin: 0 6px 6px; padding: 9px 10px 8px;
  display: flex; flex-direction: column; justify-content: space-between;
  /* Layered fill: opaque dark base + faint faction tint. The legacy
     `color-mix(... 4%, transparent)` was 96% transparent — board models
     showed through the weapon-pick cards. Stack the faction tint on a
     dark base instead. */
  background:
    linear-gradient(color-mix(in srgb, var(--owning-faction) 4%, transparent), color-mix(in srgb, var(--owning-faction) 4%, transparent)),
    rgba(10,14,20,.92);
  border: 1px solid color-mix(in srgb, var(--owning-faction) 12%, transparent);
  color: var(--text-primary); cursor: pointer; font: 600 12px/1.2 'Rajdhani', sans-serif;
  transition: background .16s ease, border-color .16s ease, box-shadow .16s ease, transform .16s ease;
}
.choice-card:hover:not([disabled]) {
  border-color: color-mix(in srgb, var(--owning-faction) 42%, transparent);
  background: color-mix(in srgb, var(--owning-faction) 9%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--owning-faction) 12%, transparent), 0 0 18px color-mix(in srgb, var(--owning-faction) 8%, transparent);
  transform: translateY(-1px);
}
.choice-card[disabled] {
  opacity: .35; cursor: not-allowed; pointer-events: auto;
}
.choice-card-name { font: 700 13px/1.15 'Rajdhani', sans-serif; letter-spacing: .4px; }
.choice-card-meta {
  color: var(--text-muted); font-size: 10px; letter-spacing: 1px; text-transform: uppercase;
}
.choice-card-fired {
  opacity: 0.35; pointer-events: none;
  border-color: rgba(0,200,80,0.3) !important;
}
.choice-card-fired .choice-card-name { color: var(--text-muted); }
.choice-card-unavailable {
  opacity: 0.25; pointer-events: none;
}

/* ── Shooter variant — centered text, taller padding ── */
.choice-card-shooter { padding: 12px 10px 10px; align-items: center; gap: 4px; }

/* ── Weapon variant — stat row + keyword chips ── */
.choice-card-weapon .choice-card-name { min-height: 30px; }
.weapon-meta-row { display: flex; gap: 6px; flex-wrap: wrap; margin-top: auto; padding-top: 5px; }
.weapon-meta { color: var(--text-muted); font-size: 10px; letter-spacing: 1px; text-transform: uppercase; }
.weapon-meta.ap-hot { color: #ff6b52; font-weight: 700; text-shadow: 0 0 8px color-mix(in srgb, var(--faction-b) 35%, transparent); }
.weapon-meta.dmg-hot { color: var(--owning-faction); font-weight: 700; }
.weapon-kws { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 4px; }

/* ── Transport variant — centered names ── */
.choice-card-transport .choice-card-name { text-align: center; }
.choice-card-transport .choice-card-meta { margin-top: 4px; text-align: center; }
.choice-card-transport .rt-chip { margin-top: 6px; align-self: center; }

/* Legacy aliases — TODO remove once all consumers migrated */
.weapon-grid { display: flex; gap: 8px; padding: 8px 14px 6px; justify-content: center; }
.weapon-grid .weapon-choice { flex: 1; min-width: 0; max-width: 220px; }
.weapon-choice {
  width: calc(100% - 12px); margin: 0 6px 6px; padding: 9px 10px 8px;
  display: flex; flex-direction: column; justify-content: space-between;
  background: color-mix(in srgb, var(--owning-faction) 4%, transparent); border: 1px solid color-mix(in srgb, var(--owning-faction) 12%, transparent);
  color: var(--text-primary); cursor: pointer; font: 600 12px/1.2 'Rajdhani', sans-serif;
  transition: background .16s ease, border-color .16s ease, box-shadow .16s ease, transform .16s ease;
}
.weapon-choice:hover:not([disabled]) {
  border-color: color-mix(in srgb, var(--owning-faction) 42%, transparent); background: color-mix(in srgb, var(--owning-faction) 9%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--owning-faction) 12%, transparent), 0 0 18px color-mix(in srgb, var(--owning-faction) 8%, transparent);
  transform: translateY(-1px);
}
.weapon-choice[disabled] { opacity: .35; cursor: not-allowed; pointer-events: auto; }
.weapon-choice-name { font: 700 13px/1.15 'Rajdhani', sans-serif; letter-spacing: .4px; min-height: 30px; }
.weapon-meta-row { display: flex; gap: 6px; flex-wrap: wrap; margin-top: auto; padding-top: 5px; }
.weapon-meta { color: var(--text-muted); font-size: 10px; letter-spacing: 1px; text-transform: uppercase; }
.weapon-meta.ap-hot { color: #ff6b52; font-weight: 700; text-shadow: 0 0 8px color-mix(in srgb, var(--faction-b) 35%, transparent); }
.weapon-meta.dmg-hot { color: var(--owning-faction); font-weight: 700; }
.weapon-kws { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 4px; }

.shooter-grid { display: flex; gap: 8px; padding: 8px 14px 6px; justify-content: center; }
.shooter-grid .shooter-choice { flex: 1; min-width: 0; max-width: 220px; }
.shooter-choice {
  width: calc(100% - 12px); margin: 0 6px 6px; padding: 12px 10px 10px;
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  background: color-mix(in srgb, var(--owning-faction) 4%, transparent); border: 1px solid color-mix(in srgb, var(--owning-faction) 12%, transparent);
  color: var(--text-primary); cursor: pointer; font: 600 12px/1.2 'Rajdhani', sans-serif;
  transition: background .16s ease, border-color .16s ease, box-shadow .16s ease, transform .16s ease;
}
.shooter-choice:hover {
  border-color: color-mix(in srgb, var(--owning-faction) 42%, transparent); background: color-mix(in srgb, var(--owning-faction) 9%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--owning-faction) 12%, transparent), 0 0 18px color-mix(in srgb, var(--owning-faction) 8%, transparent);
  transform: translateY(-1px);
}
.shooter-choice-name { font: 700 13px/1.15 'Rajdhani', sans-serif; letter-spacing: .4px; }
.shooter-choice-count { color: var(--text-muted); font-size: 10px; letter-spacing: 1px; text-transform: uppercase; }
.shooter-fired { opacity: 0.35; pointer-events: none; border-color: rgba(0,200,80,0.3) !important; }
.shooter-fired .shooter-choice-name { color: var(--text-muted); }
.shooter-unavailable { opacity: 0.25; pointer-events: none; }

/* ── Roll overlay — bottom-docked, centered on #battlefield (v0.8a) ──
   Mounted INSIDE #battlefield (see game/index.html) so the same
   `left: 50%; transform: translateX(-50%)` centering trick used by
   #phase-header pins it to the visible battlefield centre. The 220px
   roster column shifts #battlefield right of viewport centre; a
   viewport-centred (`position: fixed; left: 50%`) overlay lands 110px
   LEFT of where the player is looking — that was PR #497's
   "STILL NOT CENTERED" bug.

   Bottom anchor sits above #action-bar (48px). z-index 250 keeps the
   dice above other in-battlefield chrome but BELOW the body-root
   #global-tooltip (--z-tooltip: 260) — keyword tooltips on weapon
   cards must read above the panel. */
#roll-overlay {
  position: absolute;
  z-index: 250;
  bottom: calc(var(--action-bar-height, 48px) + 20px);
  left: 50%;
  right: auto;
  top: auto !important;
  margin: 0;
  min-width: 430px; max-width: 500px; text-align: center; padding: 6px 0 12px;
  transform: translateX(-50%);
  /* Explicit pointer-events on the container blocks board hover events
     from reaching Pixi's canvas underneath. Without this, model hulls
     under the panel highlighted on cursor-over because Pixi's pointer
     hit-test ran against the canvas behind. */
  pointer-events: auto;
}
#roll-overlay .overlay-title {
  padding-top: 10px;
  font-size: 12px;
  letter-spacing: 2.6px;
}
#roll-overlay .dice-row { justify-content: center; padding: 10px 14px 6px; gap: 8px; }
#roll-overlay .dice-summary {
  padding: 0 14px 8px; text-align: center;
  font: 700 12px/1.1 'Rajdhani', sans-serif; letter-spacing: 1.2px; color: #88a2d1;
}
#roll-overlay .dice-modifiers {
  display: flex; flex-wrap: wrap; justify-content: center; gap: 4px;
  padding: 0 14px 8px;
}
#roll-overlay .dice-mod-pill {
  font: 600 10px/1 'Rajdhani', sans-serif; letter-spacing: 0.8px;
  padding: 2px 7px; border-radius: 3px;
}
#roll-overlay .dice-mod-pill.mod-buff { background: rgba(0,200,100,.15); color: #44dd88; border: 1px solid rgba(0,200,100,.3); }
#roll-overlay .dice-mod-pill.mod-debuff { background: rgba(255,80,60,.12); color: #ff6b5a; border: 1px solid rgba(255,80,60,.25); }
#roll-overlay .dice-mod-pill.mod-keyword { background: rgba(0,160,255,.12); color: #4ac4ff; border: 1px solid rgba(0,160,255,.25); }
#roll-overlay .dice-mod-pill.mod-info { background: rgba(180,180,200,.1); color: #a0a8c0; border: 1px solid rgba(180,180,200,.2); }
/* #128 — OVERWATCH pip (reactive-shoot at BS 6+). Orange echoes the
   charge-target-selected ring so the player links the reactive shoot
   to the charge declaration that triggered it. */
#roll-overlay .dice-mod-pill.mod-overwatch { background: rgba(255,140,0,.15); color: #ffb766; border: 1px solid rgba(255,140,0,.4); }
/* Tooltip is rendered by the global delegated [data-tip] handler in
   shared/state/unit-card.js#_installTooltipDelegation — DO NOT add a
   `:hover::after` pseudo-element tooltip here, it stacks on top of the
   global one and reads as a re-enabled native browser tooltip. */
#roll-overlay .dice-mod-pill[data-tip] { cursor: help; position: relative; }
#roll-overlay .die {
  width: 44px; height: 44px; border-radius: 8px;
  border-width: 2px; font-size: 24px;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.04), 0 6px 14px rgba(0,0,0,.26);
}
/* Dice + CTA inside #roll-overlay theme to the panel's owning faction
   (so an UM target's reactive-shoot dice still render cobalt while the
   roll-overlay sits anchored to the UM unit). */
#roll-overlay .die.rolling {
  color: var(--owning-faction);
  border-color: color-mix(in srgb, var(--owning-faction) 42%, transparent);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.04), 0 0 18px color-mix(in srgb, var(--owning-faction) 18%, transparent), 0 7px 18px rgba(0,0,0,.28);
}
#roll-overlay .die.pre-roll { color: #6e87b4; }
#roll-overlay .die.rolling::before {
  content: '⚅';
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: 22px; color: var(--owning-faction); opacity: .9;
}
#roll-overlay .die.rolling { color: transparent; }

/* ── Roll CTA button ── */
.roll-cta {
  margin-top: 4px; min-width: 186px; height: 40px;
  background: var(--owning-faction); border: 1px solid var(--owning-faction);
  color: #081017; cursor: pointer;
  font: 700 13px/1 'Rajdhani', sans-serif; letter-spacing: 2.4px; text-transform: uppercase;
}
.roll-cta:disabled { opacity: .78; cursor: default; }
/* Secondary CTAs (Cancel, Skip, Re-roll) used to set `background:
   transparent` — that punched a hole through the glass-blur dice panel
   and let the board / model hulls show through the button. With the
   panel's backdrop-filter blur applied, a button with no fill of its
   own renders the unblurred board behind any pointerdown highlights
   (hover ring, drag preview, range rings). Give it the same dark
   gradient as the .overlay-panel so the button reads as a recessed
   chip on the panel rather than a window onto the board. */
.roll-cta-secondary {
  background: linear-gradient(180deg, rgba(8,12,16,.92), rgba(8,12,16,.82));
  border: 1px solid var(--border);
  color: var(--text-sec); margin-top: 4px;
}
.roll-cta-secondary:hover { border-color: var(--text-muted); color: var(--text-primary); }

/* ── Inline CTA pair (e.g. Cancel + Roll on the advance overlay) ── */
.roll-cta-row {
  display: flex; flex-direction: row; gap: 6px;
  align-items: center; justify-content: center; margin-top: 4px;
}
.roll-cta-row .roll-cta,
.roll-cta-row .roll-cta-cancel { margin-top: 0; }
.roll-cta-row .roll-cta-cancel { min-width: 100px; height: 40px; }

/* ── Stacked CTA pair (e.g. OK + RE-ROLL, Activate + Skip) ── */
.roll-cta-stack {
  display: flex; flex-direction: column; gap: 6px;
  align-items: center; margin-top: 4px;
}
.roll-cta-stack .roll-cta { width: 220px; min-width: 0; }

/* ── Roll CTA cancel variant (precision picker) ── */
.roll-cta-cancel {
  margin-top: 8px; background: #1a0e0e; color: #c66;
  border-color: rgba(204,102,102,0.35);
}

/* ── Reroll subtitle (Swift Onslaught sub-label) ── */
.roll-cta-sub {
  display: block; font-size: 10px; letter-spacing: 1.6px;
  opacity: 0.7; margin-top: 1px;
}

/* ── Transport cancel row ── */
.tx-cancel-row { display: flex; justify-content: center; padding: 4px 0 10px; }

/* ── Cleanup leak debug banner ── */
.cleanup-leak-banner { background: rgba(200,0,200,0.9); }
/* Fired weapon (disabled, checked) */
.weapon-fired {
  opacity: 0.35; pointer-events: none;
  border-color: rgba(0,200,80,0.3) !important;
}
.weapon-fired .weapon-choice-name { color: var(--text-muted); }

/* Out-of-range / no-LoS weapon — shown disabled with tooltip explaining why,
 * rather than hidden. Slightly less faded than .weapon-fired so it reads as
 * "not eligible right now" instead of "already used". */
.weapon-choice.out-of-range {
  opacity: 0.45;
  border-color: rgba(255,140,80,0.45);
}
.weapon-choice.out-of-range .weapon-choice-name { color: var(--text-muted); }

/* ── Result panel ── */
.result-main {
  display: flex; flex-direction: column; gap: 5px;
  padding: 8px 12px 2px;
}
.result-row {
  display: flex; align-items: center; gap: 8px;
  padding: 7px 10px; border-radius: 4px;
  background: rgba(255,255,255,.03); border: 1px solid rgba(255,255,255,.06);
}
.result-row.has-kills {
  background: rgba(204,32,32,.08); border-color: rgba(204,32,32,.22);
}
.result-icon {
  font-size: 20px; color: var(--text-muted);
  flex-shrink: 0; width: 24px; text-align: center;
}
.result-row.wounds .result-icon { color: #ff6060; }
.result-row.has-kills .result-icon { color: #ff5050; }
.result-row.wounds .result-num {
  color: #ff6060;
  text-shadow: 0 0 16px color-mix(in srgb, var(--faction-b) 35%, transparent);
}
.result-num {
  font: 400 34px/1 'Anton', sans-serif;
  color: var(--text-primary); flex-shrink: 0;
}
.result-row.has-kills .result-num { color: #ff6060; text-shadow: 0 0 16px color-mix(in srgb, var(--faction-b) 35%, transparent); }
.result-label {
  font: 700 10px/1.25 'Rajdhani', sans-serif;
  letter-spacing: 1.8px; text-transform: uppercase;
  color: var(--text-muted);
}
.result-row.wounds .result-label { color: #ff8080; }
.result-row.has-kills .result-label { color: #ff8080; }

/* ── v0.4 shoot tooling + combat log (hidden in v0.8a) ── */
#shoot-tools,
#combat-log-panel { display: none !important; } /* v0.8a override */

/* ── Responsive ── */
@media (max-width: 1200px) {
  #roll-overlay { min-width: 390px; max-width: 460px; }
}

/* ── Manual wound-allocation stage ── */
.save-alloc-stage {
  /* Match other overlay panels (.weapon-grid uses 8px 14px 6px). */
  padding: 10px 14px 12px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-width: 520px;
}
.save-alloc-title {
  font: 700 12px/1 'Rajdhani', sans-serif;
  letter-spacing: 2px;
  text-transform: uppercase;
  /* Title themed to the OWNING (defending) unit — matches the tier-card
     borders that surround it (var(--owning-faction)). */
  color: var(--owning-faction);
}
.save-alloc-subtitle {
  font: 600 14px/1 'Rajdhani', sans-serif;
  color: var(--text-primary);
}
.save-alloc-tiers {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}
.save-alloc-tier {
  flex: 1 1 180px;
  min-width: 160px;
  /* Save-allocation tier card themed to the OWNING (defending) unit. */
  background: color-mix(in srgb, var(--owning-faction) 4%, transparent);
  border: 1px solid color-mix(in srgb, var(--owning-faction) 22%, transparent);
  border-radius: 4px;
  padding: 8px 10px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  transition: opacity 0.15s, border-color 0.15s;
}
.save-alloc-tier.save-alloc-locked {
  opacity: 0.35;
  border-color: rgba(255, 120, 90, 0.3); /* alloc-palette-ok: semantic warning/lock indicator, faction-independent */
}
.save-alloc-tier.save-alloc-dimmed {
  opacity: 0.55;
}
.save-alloc-tier-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
}
.save-alloc-tier-name {
  font: 700 11px/1 'Rajdhani', sans-serif;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  color: var(--text-primary);
}
.save-alloc-tier-save {
  font: 700 14px/1 'Rajdhani', sans-serif;
  color: var(--owning-faction);
}
.save-alloc-tier-stats {
  font: 500 10px/1.2 'Rajdhani', sans-serif;
  color: var(--text-muted);
  letter-spacing: 0.5px;
}
/* Allocation log — one row per [+] click. Scrollable inside the tier card
   so high-attack-count units don't blow the overlay vertically. Auto-scroll
   to bottom is handled in JS. */
.save-alloc-log {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-height: 36px;
  max-height: 140px;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 4px;
  background: rgba(0,0,0,0.18);
  border: 1px solid rgba(255,255,255,0.05);
  border-radius: 3px;
}
.save-alloc-log::-webkit-scrollbar { width: 5px; }
.save-alloc-log::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.18); border-radius: 2px; }
.save-alloc-log::-webkit-scrollbar-track { background: rgba(0,0,0,0.18); }
/* Tabular grid: fixed icon + 4 fr cells (save / dmg / fnp / applied).
   `applied` is explicitly anchored to col 5 so saved rows (icon + save
   only, 2 cells) and failed-without-fnp rows (icon + save + dmg + applied,
   4 cells) all line up the right-most column with failed-with-fnp rows.
   Whole row never wraps. */
.save-alloc-log-row {
  display: grid;
  grid-template-columns: 14px 1.4fr 1fr 1fr 1fr;
  align-items: stretch;
  column-gap: 4px;
  padding: 3px 4px;
  font: 600 11px/1.3 'Rajdhani', sans-serif;
  color: var(--text-primary);
  white-space: nowrap;
}
/* applied always lands in col 5 — no empty placeholder cells needed when
   FNP / dmg are absent from the row. */
.alr-applied { grid-column: 5; }
.save-alloc-log-saved { color: #5acc8c; opacity: 0.7; } /* alloc-palette-ok: semantic "saved" green (paired with .save-alloc-discard red) */
.alr-icon {
  font-weight: 700;
  text-align: center;
  font-size: 11px;
}
.alr-icon-pass { color: #5acc8c; }
.alr-icon-fail { color: #ff7a5e; }
.alr-cell {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  padding: 2px 6px;
  background: rgba(255,255,255,0.04);
  border-radius: 2px;
  font-size: 10.5px;
  letter-spacing: 0.3px;
  min-width: 0;
}
.alr-cell b { font-weight: 700; color: #fff; }
.alr-cell i {
  font-style: normal;
  color: rgba(255,255,255,0.65);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0;
}
.alr-vs {
  color: rgba(255,255,255,0.35);
  font-size: 9px;
  font-weight: 500;
  letter-spacing: 0.3px;
}
.alr-cell-label {
  color: rgba(255,255,255,0.40);
  font-size: 9.5px;
  letter-spacing: 0.3px;
  text-transform: lowercase;
}
.alr-applied b { color: #ff7a5e; font-size: 11.5px; }
.alr-wound-icon {
  font-size: 8px;
  color: rgba(255, 90, 70, 0.7);
  margin: 0 2px 0 1px;
}
.alr-skull { color: #ff7a5e; font-size: 11px; }
/* FnP negation count — muted when 0 negated, gold when at least one wound
   was saved. The per-die history lives in the tooltip on the parent cell. */
.alr-neg-active { color: #fdd97f; }
.alr-neg-zero   { color: rgba(255,255,255,0.30); }
/* ── Per-model picker chips (#502) — shown when the tier has mixed loadouts.
   Replaces the [+] button: defender clicks the specific model that takes
   the next wound. Focus-fire + wounded-model locks dim non-eligible chips. */
.save-alloc-chips {
  margin-top: auto;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
  gap: 4px;
  padding-top: 4px;
}
.save-alloc-model-chip {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 5px 7px;
  background: rgba(40, 50, 65, 0.7); /* alloc-palette-ok: structural dark-panel fill, not faction-tinted */
  color: var(--text-primary);
  border: 1px solid rgba(255, 255, 255, 0.18); /* alloc-palette-ok: idle border is a neutral edge; faction tint kicks in on hover/focus/wounded */
  border-radius: 4px;
  font: 600 11px/1.1 'Rajdhani', sans-serif;
  text-align: left;
  cursor: pointer;
  transition: background 0.12s, border-color 0.12s, box-shadow 0.12s, transform 0.08s, opacity 0.12s;
  min-width: 0;
}
/* Hover and canvas-hover share the panel-surface lift; the border /
   ring escalates from a soft glow (hover) → solid owning-faction
   (canvas-hover) → full fill (focus). The white-border hardcode that
   used to live here predated the ALLOC-B1 owning-faction-glow cascade
   and ignored the defender's palette. */
.save-alloc-model-chip:hover:not(:disabled),
.save-alloc-model-chip.save-alloc-canvas-hover:not(.save-alloc-model-locked) {
  background: rgba(60, 75, 95, 0.85); /* alloc-palette-ok: structural dark-panel hover, not faction-tinted (focus state owns the owning-faction fill) */
  border-color: var(--owning-faction-glow);
}
/* Canvas-hover promotes the edge to solid + adds an outer ring so the
   user can pick out the matched chip when the cursor is on the Pixi
   side. */
.save-alloc-model-chip.save-alloc-canvas-hover:not(.save-alloc-model-locked) {
  border-color: var(--owning-faction);
  box-shadow: 0 0 0 2px var(--owning-faction);
}
.save-alloc-model-chip:active:not(:disabled) { transform: scale(0.97); }
.save-alloc-model-chip:disabled,
.save-alloc-model-chip.save-alloc-model-locked {
  opacity: 0.32;
  cursor: not-allowed;
}
.save-alloc-model-chip.save-alloc-model-focus {
  background: var(--owning-faction);
  color: var(--bg-primary);
  border-color: var(--owning-faction);
  opacity: 1;
}
.save-alloc-model-chip.save-alloc-model-wounded:not(.save-alloc-model-locked) {
  border-color: var(--owning-faction);
  box-shadow: inset 0 0 0 1px var(--owning-faction-tint-strong);
}

/* Chip hover tooltip: full per-model loadout shown as a stack of
   weapon-profile cards (same shape as the SELECT WEAPON popup). The
   global tooltip is sized for short text strings — widen it when it
   carries a `.weapon-tip-stack` so the cards don't squeeze. */
#global-tooltip:has(.weapon-tip-stack) {
  width: 280px;
  max-height: 360px;
  white-space: normal;
  padding: 8px 10px;
}
.weapon-tip-stack {
  display: flex; flex-direction: column; gap: 6px;
}
.weapon-tip-head {
  font: 700 11px/1.2 'Rajdhani', sans-serif; letter-spacing: 1.2px;
  text-transform: uppercase; color: var(--text-primary);
}
.weapon-tip-lock {
  font: 500 11px/1.35 'Rajdhani', sans-serif;
  color: #ff8a6e;
  background: color-mix(in srgb, #ff6b52 14%, transparent);
  border-left: 2px solid #ff6b52;
  padding: 4px 8px;
}
.weapon-tip-empty {
  color: var(--text-muted); font-size: 11px; font-style: italic;
}
/* Tooltip cards: drop the click-affordance bits and tighten spacing. The
   underlying `.weapon-choice` styles handle layout + meta-row colours. */
.weapon-tip-card {
  cursor: default !important;
  margin: 0 !important;
  width: 100% !important;
  padding: 6px 8px !important;
}
.weapon-tip-card .weapon-choice-name {
  min-height: 0 !important;
  font-size: 12px;
}
/* Chip children inherit chip color by default; the .id/.hp/.weapon
   variants shade up/down via alpha. All four collapse to --bg-primary
   when the focus state inverts the fill (rule below). */
.save-alloc-model-glyph {
  flex: 0 0 auto;
  font-size: 13px;
  color: inherit;
  opacity: 0.85;
}
.save-alloc-model-id {
  flex: 0 0 auto;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: inherit;
}
.save-alloc-model-hp {
  flex: 0 0 auto;
  font-size: 10px;
  color: inherit;
  opacity: 0.65;
}
.save-alloc-model-weapon {
  flex: 1 1 0;
  /* min-width: 0 overrides the implicit min-width: auto on flex
     items so the nowrap text actually truncates instead of forcing
     the chip wider than its grid track. */
  min-width: 0;
  font-size: 10px;
  color: inherit;
  opacity: 0.75;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Focus state inverts the fill — children inherit --bg-primary from the
   chip and reset opacity so the dark text reads cleanly on the bright
   owning-faction background. */
.save-alloc-model-chip.save-alloc-model-focus .save-alloc-model-glyph,
.save-alloc-model-chip.save-alloc-model-focus .save-alloc-model-hp,
.save-alloc-model-chip.save-alloc-model-focus .save-alloc-model-weapon {
  opacity: 1;
}

.save-alloc-plus {
  /* Anchor button to the bottom of the tier card so it stays aligned across
     all tiers regardless of how tall each tier's allocation log is. */
  margin-top: auto;
  padding: 6px 0;
  /* Allocate-wound [+] button themed to the OWNING (defending) unit so it
     reads as the defender's action across all faction palettes. */
  background: var(--owning-faction);
  color: var(--bg-primary);
  border: 1px solid var(--owning-faction);
  border-radius: 4px;
  font: 700 16px/1 'Rajdhani', sans-serif;
  cursor: pointer;
  transition: transform 0.08s, opacity 0.12s;
}
.save-alloc-plus:hover:not(:disabled) { transform: scale(1.04); }
.save-alloc-plus:active:not(:disabled) { transform: scale(0.96); }
.save-alloc-plus:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}
.save-alloc-footer {
  display: flex;
  justify-content: center;
  gap: 8px;
  margin-top: 4px;
}
/* .btn-cta carries `margin-left: auto` for action-bar contexts; cancel that
   here so the auto-allocate button stays centered in the footer. */
.save-alloc-footer .btn-cta { margin-left: 0; }
/* .btn-cta defaults to --active-faction (the attacker's palette) but the
   manual-alloc overlay is DEFENDER-driven — the wound chips, hover glow,
   and AI ALLOCATING button must all read the defender's faction colour.
   Override to --owning-faction so the .side-a/.side-b cascade we set on
   #roll-overlay in renderManualAllocationStage actually drives the button.
   See `applyAllocOverlayDefenderSideClass` in game/core/combat-ui.js for
   the dedicated entry point. */
.save-alloc-auto {
  background: var(--owning-faction);
  border-color: var(--owning-faction);
}
.save-alloc-auto:hover:not(:disabled) {
  background: var(--owning-faction);
  border-color: var(--owning-faction);
  /* .btn-cta:hover sets box-shadow to var(--active-faction-glow); the
     manual-alloc modal is defender-driven so the hover halo must follow
     --owning-faction too. Without this override the bottom button glows
     in the attacker's faction tone (Custodes gold while UM is allocating). */
  box-shadow: 0 4px 14px var(--owning-faction-glow);
}
.save-alloc-auto:active:not(:disabled) {
  /* .btn-cta:active rebases background on --active-faction — override to
     --owning-faction so the press-state tone matches the defender. */
  background: color-mix(in srgb, var(--owning-faction) 60%, #000);
  border-color: var(--owning-faction);
}
/* Auto-allocate styling inherited from .btn-cta (action-bar.css). This rule
   only handles the disabled state during the final auto-advance. */
.save-alloc-auto:disabled {
  opacity: 0.3;
  cursor: not-allowed;
  transform: none;
  /* Dimmed owning-faction tone — ~55% saturation against black,
     matching the legacy mockup dim ratio without a dedicated -dim token. */
  background: color-mix(in srgb, var(--owning-faction) 55%, #000);
  box-shadow: none;
}
.save-alloc-discard {
  font: 500 11px/1 'Rajdhani', sans-serif;
  color: #ff7a5e; /* alloc-palette-ok: semantic "discarded wound" red, faction-independent */
  letter-spacing: 0.5px;
  text-align: center;
}
/* Hide the discard slot when it has no text — was leaving a blank strip
   under the footer button. */
.save-alloc-discard:empty { display: none; }
