/* ─── war.css ─────────────────────────────────────────────────────────────
   War screen: layout columns, board frame, highlight overlays, tracker cubes, reserve/exile dice, sidebar + action buttons, debug overlay.
   Split out of the old style.css as a pure ordered slice. The <link> order
   in index.html (base → menu → online → board → folks → war → overlays →
   mobile → free-mode) preserves the original cascade — do not reorder. ─── */

/* WAR SCREEN */
#screen-war {
  position: relative;
  place-content: center;
  padding-bottom: 5rem;
  min-height: 100vh;
}
#screen-war.active { display: grid; }

#board-assembly {
  display: flex;
  flex-direction: row;
  align-items: stretch;
  gap: 12px;
}

/* Left: two dice TRAYS (top = opponent, bottom = me), anchored to the board's
   top/bottom edges. Warm wooden-tray material so the column belongs to the
   board scene rather than the dark chrome; sections size by content. */
#exile-col {
  display: flex;
  flex-direction: column;
  justify-content: space-between;  /* trays hug the board's corners */
  gap: 10px;
  width: 137px;  /* 2×border(1) + 2×tray pad(7) + 2×area pad(5) + 3×35 dice + 2×2 gaps + 2 slack */
  height: 852px; /* = #board-frame height, like #sidebar */
}
.dice-tray {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 7px;
  /* Bluish chrome tones — the page background (#1a1a2e), a step darker —
     same tray design (bevel, inner shadow), colours match the mobile strips. */
  background: linear-gradient(160deg, #1e1e32 0%, #171726 60%, #141420 100%);
  border: 1px solid #2a2a3a;
  border-radius: 9px;
  box-shadow: inset 0 2px 10px rgba(0,0,0,0.55), 0 1px 3px rgba(0,0,0,0.4);
  min-height: 0;
  transition: box-shadow .18s, border-color .18s;
}
/* Whose-turn indicator: the active player's tray glows in their accent (the
   -onbg vars are luminance-corrected so even a dark P2 accent stays visible). */
.dice-tray.tray-active.p1 {
  border-color: var(--p1-accent-onbg, #e63946);
  box-shadow: inset 0 2px 10px rgba(0,0,0,0.55), 0 0 0 2px var(--p1-accent-onbg, #e63946), 0 0 14px -2px var(--p1-accent-onbg, #e63946);
}
.dice-tray.tray-active.p2 {
  border-color: var(--p2-accent-onbg, #ccd);
  box-shadow: inset 0 2px 10px rgba(0,0,0,0.55), 0 0 0 2px var(--p2-accent-onbg, #ccd), 0 0 14px -2px var(--p2-accent-onbg, #ccd);
}
/* The active tray's title brightens too, so the turn reads at a glance. */
.dice-tray.tray-active .tray-name { color: #eef2fa; }
.tray-title {
  display: flex; flex-direction: column; align-items: center;
  padding: 1px 0 2px;
  text-align: center;
  overflow: hidden;
}
/* Small accent-tinted "Player N" overline — the bridge to history's P1/P2 and
   the board dice colour. -onbg vars are luminance-corrected for the dark tray. */
.tray-title .tray-pnum {
  font-size: 0.56rem; font-weight: bold;
  text-transform: uppercase; letter-spacing: 1px;
  line-height: 1.1;
}
.tray-title.p1 .tray-pnum { color: var(--p1-accent-onbg, #e63946); }
.tray-title.p2 .tray-pnum { color: var(--p2-accent-onbg, #ccc); }
.tray-title .tray-name {
  font-size: 0.72rem; font-weight: bold;
  color: #c4ccdc;
  max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.exile-area {
  display: flex;
  flex-direction: column;
  background: rgba(0,0,0,0.28);
  border-radius: 6px;
  padding: 4px 5px 5px;
}
.reserve-area { background: rgba(0,0,0,0.12); }
.exile-title {
  font-size: 0.58rem;
  color: #8a8aa0;
  text-transform: uppercase;
  letter-spacing: 1px;
  margin-bottom: 3px;
  flex-shrink: 0;
  display: flex; align-items: center; justify-content: space-between; gap: 4px;
}
/* Count badge — readable at a glance on desktop too (mobile restyles its own). */
.exile-title .area-count {
  flex: none;
  font-size: 0.66rem; font-weight: 700; color: #cdd3e2;
  background: rgba(255,255,255,0.08); border-radius: 999px;
  padding: 0 6px; min-width: 16px; text-align: center;
}
.exile-dice { display: flex; flex-wrap: wrap; gap: 2px; align-content: flex-start; }

/* Center: board column */
#board-col {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 4px;
}

/*
 * Board layout — all values match BOARD config object in game.js.
 * Native board.png: 3927 × 5561 px.
 * Display scale: 534 / 3488 ≈ 0.15316.
 *
 * To tweak alignment: adjust left/top on #board-war, or frameW/frameH below.
 * To tweak cube positions: edit BOARD.p1 / BOARD.p2 in game.js.
 */

/* Board frame: board image stretched to fill the fixed 601×852 frame.
   background-size forces any source resolution into the frame, so the grid /
   tracker positions (BOARD config in game.js) are unaffected by the image's
   native size — only its framing matters. board_small.jpg (1045×1500) is a
   ~30x smaller swap-in for the old 18.7MB board.png; its aspect differs by
   ~1%, so marker alignment is approximate and may want minor manual tweaks. */
#board-frame {
  position: relative;
  width: 601px;   /* BOARD.frameW */
  height: 852px;  /* BOARD.frameH */
  background-image: url('../img/board_small.jpg');
  background-size: 601px 852px;
  background-repeat: no-repeat;
  flex-shrink: 0;
}

/* War grid cell overrides */
#board-war .cell { background: transparent; }
#board-war .cell:hover { background: rgba(255,255,255,0.07); }
#board-war .cell.supply-zone { background: rgba(0,50,0,0.05); }
#board-war .cell.supply-zone:hover { background: rgba(255,255,255,0.07); }
/* Highlight overlays — use ::before so they float inside each cell, not aligned
   to the cell edge. This is forgiving of the hand-drawn board.png squares not
   perfectly matching our CSS grid. */
#board-war .cell.highlight-move,
#board-war .cell.highlight-attack,
#board-war .cell.selected,
#board-war .cell.highlight-spell-axis,
#board-war .cell.highlight-spell-preview,
#board-war .cell.highlight-spell-blocked,
#board-war .cell.highlight-blocker,
#board-war .cell.highlight-spell-upgrade,
#board-war .cell.highlight-overflow {
  background: transparent;
  outline: none;
}
#board-war .cell.highlight-move::before,
#board-war .cell.highlight-attack::before,
#board-war .cell.selected::before,
#board-war .cell.highlight-spell-axis::before,
#board-war .cell.highlight-spell-preview::before,
#board-war .cell.highlight-spell-blocked::before,
#board-war .cell.highlight-blocker::before,
#board-war .cell.highlight-spell-upgrade::before,
#board-war .cell.highlight-overflow::before {
  content: '';
  position: absolute;
  inset: 5px;
  border-radius: var(--cell-highlight-radius);
  pointer-events: none;
  z-index: 1;
}

/* Movement = green (matches the Movement action in actions.png) */
#board-war .cell.highlight-move::before {
  background: radial-gradient(circle, rgba(46,204,113,0.35) 0%, rgba(46,204,113,0.08) 70%);
  box-shadow: inset 0 0 0 2px rgba(46,204,113,0.9), 0 0 14px rgba(46,204,113,0.5);
  animation: hl-pulse var(--hl-pulse-duration) ease-in-out infinite;
}

/* Attack = red (matches the Attack action in actions.png) */
#board-war .cell.highlight-attack::before {
  background: radial-gradient(circle, rgba(230,57,70,0.42) 0%, rgba(230,57,70,0.1) 70%);
  box-shadow: inset 0 0 0 2px rgba(230,57,70,0.9), 0 0 16px rgba(230,57,70,0.55);
  animation: hl-pulse var(--hl-pulse-duration) ease-in-out infinite;
}

/* Soul Overflow removal = orange (click to return excess Souls to Reserve) */
#board-war .cell.highlight-overflow::before {
  background: radial-gradient(circle, rgba(240,160,32,0.4) 0%, rgba(240,160,32,0.1) 70%);
  box-shadow: inset 0 0 0 2px rgba(240,160,32,0.9), 0 0 14px rgba(240,160,32,0.5);
  animation: hl-pulse var(--hl-pulse-duration) ease-in-out infinite;
}

/* Symbiosis / upgrade-type target = yellow (same overlay style as attack) */
#board-war .cell.highlight-spell-upgrade::before {
  background: radial-gradient(circle, rgba(244,208,63,0.4) 0%, rgba(244,208,63,0.1) 70%);
  box-shadow: inset 0 0 0 2px rgba(244,208,63,0.9), 0 0 14px rgba(244,208,63,0.5);
  animation: hl-pulse var(--hl-pulse-duration) ease-in-out infinite;
}

/* Selected = neutral white (was yellow, but yellow now belongs to Upgrade) */
#board-war .cell.selected::before {
  background: radial-gradient(circle, rgba(255,255,255,0.18) 0%, rgba(255,255,255,0.03) 70%);
  box-shadow: inset 0 0 0 2px rgba(255,255,255,0.85), 0 0 16px rgba(255,255,255,0.45);
}

/* Brotherhood / Dragon Blood axis end-cells: soft purple = clickable direction */
#board-war .cell.highlight-spell-axis::before {
  background: radial-gradient(circle, rgba(155,89,182,0.22) 0%, rgba(155,89,182,0.05) 70%);
  box-shadow: inset 0 0 0 2px rgba(155,89,182,0.55), 0 0 12px rgba(155,89,182,0.3);
  animation: hl-pulse var(--hl-pulse-duration) ease-in-out infinite;
}
/* Hover preview: saturated purple over every cell that would be affected.
   Uses its own @keyframes name so the animation reliably *restarts* (in sync
   across all preview cells) when the class is added on top of an already-
   animating axis cell. Changing only duration would keep the existing phase. */
#board-war .cell.highlight-spell-preview::before {
  background: radial-gradient(circle, rgba(155,89,182,0.6) 0%, rgba(155,89,182,0.15) 70%);
  box-shadow: inset 0 0 0 3px rgba(155,89,182,0.95), 0 0 22px rgba(155,89,182,0.7);
  animation: hl-pulse-preview var(--hl-pulse-duration) ease-in-out infinite;
}
@keyframes hl-pulse-preview {
  0%, 100% { opacity: 0.85; transform: scale(1); }
  50%      { opacity: 1;    transform: scale(1.04); }
}
/* Direction blocked (opposite side occupied or off-board): subtle red tint */
#board-war .cell.highlight-spell-blocked::before {
  background: radial-gradient(circle, rgba(230,57,70,0.15) 0%, rgba(230,57,70,0.03) 70%);
  box-shadow: inset 0 0 0 2px rgba(230,57,70,0.4);
}
/* Hovering a blocked direction makes the blocker pulse urgently in red */
#board-war .cell.highlight-blocker::before {
  background: radial-gradient(circle, rgba(230,57,70,0.55) 0%, rgba(230,57,70,0.15) 70%);
  box-shadow: inset 0 0 0 3px rgba(230,57,70,1), 0 0 22px rgba(230,57,70,0.85);
  animation: blocker-pulse 0.55s ease-in-out infinite;
}
@keyframes blocker-pulse {
  0%, 100% { opacity: 0.65; transform: scale(0.96); }
  50%      { opacity: 1;    transform: scale(1.07); }
}

@keyframes hl-pulse {
  0%, 100% { opacity: 0.85; transform: scale(1); }
  50%      { opacity: 1;    transform: scale(1.04); }
}

/* Setup "Done" button pulses to invite the click once PL hits 10. When online
   and already ready it's :disabled ("Ready ✓ — waiting…"), so it won't pulse. */
#btn-setup-done:not(:disabled) { animation: done-pulse 1.2s ease-in-out infinite; }
@keyframes done-pulse {
  0%, 100% { transform: scale(1);    box-shadow: 0 0 0 0 rgba(76,175,80,0.5); }
  50%      { transform: scale(1.03); box-shadow: 0 0 10px 2px rgba(76,175,80,0.55); }
}

/* VP/TP tracker cubes — positioned on the board.png tracker rows */
.tracker-cube {
  position: absolute;
  width: 20px;
  height: 20px;
  border-radius: 3px;
  box-sizing: border-box;
  pointer-events: none;
  transition: left 0.35s cubic-bezier(0.34, 1.56, 0.64, 1),
              top  0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
}
/* Marker borders match their fill colour (no contrasting border) for every folk/player. */
.p1-cube { background: var(--p1-accent, #97dc66); box-shadow: 0 1px 4px rgba(0,0,0,0.7); }
.p2-cube { background: var(--p2-accent, #1c1c1c); box-shadow: 0 1px 4px rgba(0,0,0,0.7); }

/* Hollow VP+virtualVP total marker — same square, just an outline (no fill); the
   outline uses the player's own accent (same colour as the solid marker's fill). */
.tracker-cube.cube-hollow { background: transparent; box-shadow: none; }
.cube-hollow.p1-cube { border: 2px solid var(--p1-accent, #97dc66); }
.cube-hollow.p2-cube { border: 2px solid var(--p2-accent, #1c1c1c); }

@keyframes cube-pulse {
  0%   { transform: scale(1); }
  50%  { transform: scale(1.35); }
  100% { transform: scale(1); }
}
.tracker-cube.cube-pulse { animation: cube-pulse 0.5s ease; }

/* Shared die — used in exile and reserve areas. A soft top-light gradient +
   drop shadow make it read as a physical die lying in the tray; the colour
   comes from background-COLOR (folk accents) underneath the shared gradient. */
.reserve-die {
  width: 35px; height: 35px; border-radius: 6px; flex-shrink: 0;
  background-image: linear-gradient(145deg, rgba(255,255,255,0.22), rgba(255,255,255,0.03) 45%, rgba(0,0,0,0.18));
  box-shadow: 0 2px 3px rgba(0,0,0,0.5), inset 0 1px 1px rgba(255,255,255,0.12);
}
/* Exile colors: muted (dice are in a bag, out of play) — muted folk accents */
.reserve-die.filled.p1 { background-color: color-mix(in srgb, var(--p1-accent, #97dc66) 42%, #14140f); border: 1px solid rgba(255,255,255,0.14); }
.reserve-die.filled.p2 { background-color: color-mix(in srgb, var(--p2-accent, #1c1c1c) 42%, #14140f); border: 1px solid rgba(255,255,255,0.14); }
/* Reserve colors: bright (dice are available to deploy) — each player's folk accent */
.reserve-area .reserve-die.filled.p1 { background-color: var(--p1-accent, #97dc66); border: 1px solid rgba(255,255,255,0.3); }
.reserve-area .reserve-die.filled.p2 { background-color: var(--p2-accent, #1c1c1c); border: 1px solid rgba(255,255,255,0.3); }

/* Right: sidebar — six fixed zones (identity / prompt / context / log /
   session / connection), same order in every mode; see index.html.
   Height is pinned to the board frame so the inner log can flex to fill the
   middle without the column ever outgrowing the board. */
#sidebar {
  width: 200px;
  height: 852px;  /* = #board-frame height (BOARD.frameH) */
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
/* Zone hosts are structural only — their children join #sidebar's flex flow
   directly (so hidden members don't leave double gaps). */
#sb-identity, #sb-prompt { display: contents; }
/* ① identity: the shared slot shows only the active phase's banner. */
body.phase-setup #turn-banner { display: none; }
body.phase-war   #setup-info  { display: none; }
/* Desktop war: the active player's TRAY (left column) shows whose turn it is, so
   the sidebar banner no longer repeats the player name — hide its label, and hide
   the whole bar on a plain turn (no chips). Chips (Sandbox / EoW / winner) still
   show. Mobile keeps the banner+label: it lives in the top bar, not #sidebar. */
#sidebar #turn-banner .tb-label { display: none; }
#sidebar #turn-banner.tb-plain  { display: none; }
/* Reference shelf: the rulebook / creature-card viewers (shared, both phases).
   Plain .btn-history sizing — same height/style as history row + Save game. */
#sb-reference { display: flex; gap: 4px; }
#sb-reference button { flex: 1; }
/* ② prompt: the sidebar gap provides spacing — no extra margins. */
#sb-prompt .undo-banner { margin-bottom: 0; }
#prompt-status:empty { display: none; }
/* The setup Done button lives in the phase-shared prompt zone — never in war. */
body.phase-war #btn-setup-done { display: none !important; }
#war-controls {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  flex: 1;
  min-height: 0;  /* allow the inner log to shrink instead of overflowing */
}
#setup-controls {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  flex: 1;
  min-height: 0;
}

/* ③ context actions: compact controls — sized to the sidebar, not the menu.
   (The big 1rem default is for menu/overlay primaries.) */
#action-panel { display: flex; flex-direction: column; gap: 0.4rem; }
#action-panel button { width: 100%; padding: 0.4rem 0.7rem; font-size: 0.85rem; }
#action-panel kbd { font-size: 0.6rem; }
/* When a creature is selected the panel reads as ITS card — a framed box with an
   art + name + power-level header, the action buttons living inside it (so they
   no longer float loose in the corner). No selection = no box. */
#action-panel.has-card {
  background: rgba(120,140,200,0.06);
  border: 1px solid #2a3a5c;
  border-radius: 8px;
  padding: 7px;
}
#action-card-head { display: flex; align-items: center; gap: 9px; padding-bottom: 6px; }
#action-card-head:empty { display: none; }
#action-panel.has-card #action-card-head:not(:empty) {
  border-bottom: 1px solid #2a3a5c; margin-bottom: 1px;
}
#action-card-head .ac-art {
  width: 44px; height: 44px; flex: 0 0 auto;
  object-fit: contain; border-radius: 6px;
  background: rgba(0,0,0,0.28); padding: 2px;
}
#action-card-head .ac-meta { min-width: 0; }
#action-card-head .ac-name { font-weight: bold; font-size: 0.95rem; line-height: 1.15; }
#action-card-head .ac-pl { font-size: 0.72rem; color: #9aa3bd; margin-top: 2px; }
/* Multi-spell creatures: each spell its own purple button (matches #btn-spell). */
#action-spells { display: flex; flex-direction: column; gap: 0.4rem; }
.btn-spell-multi { background: #9b59b6; color: #fff; font-weight: bold; }
.btn-spell-multi:hover { background: #7d3c98; }
.btn-spell-multi:disabled { background: #26262f; color: #5b5b6b; cursor: default; }
/* Empty helper hosts must not leave phantom gaps/boxes in the flex column. */
#action-extra:empty, #spell-panel:empty, #action-spells:empty { display: none; }
/* A spell/action step renders as ONE card: header line + its buttons —
   not a floating hint box with loose buttons under it. */
#spell-panel { display: flex; flex-direction: column; gap: 0.3rem; }
#spell-panel:not(:empty) {
  background: rgba(120,140,200,0.06);
  border: 1px solid #2a3a5c;
  border-radius: 6px;
  padding: 5px;
}
/* Inside the step card the hint is the card's HEADER, not a second box. */
#spell-panel .action-hint, #spell-panel .overflow-prompt {
  background: none; border: none; padding: 1px 2px 3px;
  font-size: 0.78rem;
}
/* Cancel: same compact height, red-tinted — it aborts the step it belongs to
   (defined after .btn-history in the cascade, so the tint wins). */
.btn-cancel-spell { background: #38222a; border: 1px solid #5a3340; color: #e2a9b3; }
.btn-cancel-spell:hover { background: #452a34; color: #f0c2cb; }
/* Prompt-banner family — ONE shape for everything that addresses the player
   (hints, mandatory steps, undo requests); only the tint is semantic:
   blue = info/hint, orange = pending/trim step, red = forced demand. */
.overflow-prompt, .action-hint {
  font-size: 0.8rem; border-radius: 6px; padding: 0.5rem 0.6rem; line-height: 1.35;
  border: 1px solid;
}
.overflow-prompt { color: #f0c040; background: rgba(240,160,32,0.1); border-color: #7a5c00; }
.action-hint { color: #cbd5e8; background: rgba(120,140,200,0.1); border-color: #3a4a7c; }
/* Warning variant — forced/mandatory demands (e.g. a forced attack) */
.action-hint.hint-warn { color: #f4a6ad; background: rgba(230,57,70,0.10); border-color: #7c2a33; }

/* Action buttons themed to match actions.png — yellow=upgrade, purple=spell */
#btn-upgrade { background: #f1c40f; color: #1a1a2e; font-weight: bold; }
#btn-upgrade:hover { background: #d4a90a; }
#btn-spell   { background: #9b59b6; color: #fff; font-weight: bold; }
#btn-spell:hover   { background: #7d3c98; }
/* Non-spell ability buttons (e.g. Symbiosis) — yellow like Upgrade (movement/upgrade type) */
#action-extra { display: flex; flex-direction: column; gap: 0.4rem; }
.btn-action-upgrade { background: #f1c40f; color: #1a1a2e; font-weight: bold; }
.btn-action-upgrade:hover { background: #d4a90a; }
.btn-action-upgrade:disabled { background: #26262f; color: #5b5b6b; cursor: default; }

.bt-step {
  font-size: 0.8rem;
  font-weight: bold;
  color: #e63946;
  padding-bottom: 0.2rem;
  border-bottom: 1px solid #2a3a5c;
  margin-bottom: 0.2rem;
}

.btn-skip-fire {
  background: #f4a261;
  color: #1a1a2e;
  font-weight: bold;
}
.btn-skip-fire:hover { background: #e08a45; }

/* Declaring End of War is a weighty, deliberate act — dark chrome with an
   amber accent (matches the EoW banner chip), not a casual gray. */
#btn-end-of-war { background: #2a2a3a; border: 1px solid #5a4a2a; color: #d9b96a; font-size: 0.85rem; }
#btn-end-of-war:hover:not(:disabled) { background: #3a3a4a; }
/* Disabled (sandbox, or already declared): mute it — the ID styling above
   would otherwise beat the global button:disabled look. */
#btn-end-of-war:disabled { background: #232331; border-color: #3a3a4a; color: #777; }

/* Setup Done = confirm-green (the id outranks the player-colour .btn-p2). */
#btn-setup-done:not(:disabled) { background: #2ecc71; color: #14210a; font-weight: bold; }
#btn-setup-done:not(:disabled):hover { background: #28b765; }

/* ③ setup context (desktop sidebar): one form family — stacked micro-labels
   over full-width dark inset fields, matching the connection panel's share
   block. Scoped to #sidebar: the mobile sheet/drawer keep their own layout. */
#sidebar #setup-hint { font-size: 0.72rem; text-align: left; padding: 0; color: #8a93a8; }
#sidebar #setup-folk { display: flex; flex-direction: column; align-items: stretch; gap: 2px; margin: 0; }
#sidebar #setup-folk .menu-label { margin: 0; font-size: 0.62rem; font-weight: bold; text-transform: uppercase; letter-spacing: 0.08em; color: #7c87a0; }
#sidebar #setup-folk select { width: 100%; background: #10131d; color: #dde3f2; border: 1px solid #2a3450; border-radius: 5px; padding: 4px 6px; font-size: 0.8rem; }
#sidebar #setup-names { margin: 0; gap: 5px; }
#sidebar .setup-name-row { flex-direction: column; align-items: stretch; gap: 2px; }
#sidebar .setup-name-row .setup-name-label { font-size: 0.62rem; text-transform: uppercase; letter-spacing: 0.08em; }
#sidebar .setup-name-row input { background: #10131d; border: 1px solid #2a3450; border-radius: 5px; padding: 4px 6px; font-size: 0.8rem; }

.log-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 0.7rem;
  font-weight: bold;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #666;
  border-top: 1px solid #2a3a5c;
  padding-top: 0.4rem;
  margin-top: 0.4rem;
}

/* ④ history nav: tiny hint buttons (undo / redo / latest) on the History
   header so it's discoverable that the timeline can be walked. They mirror
   the timeline dot clicks — disabled (dimmed) when the step isn't available. */
.tl-nav { display: flex; gap: 2px; }
.tl-nav-btn {
  width: 18px; height: 18px;
  padding: 0; line-height: 1;
  display: flex; align-items: center; justify-content: center;
  font-size: 0.85rem; font-weight: bold;
  color: #9fb2d4;
  background: #1a2236;
  border: 1px solid #2a3a5c;
  border-radius: 4px;
  cursor: pointer;
}
.tl-nav-btn:hover:not(:disabled) { background: #25304a; color: #d7e3f6; border-color: #3a4d75; }
.tl-nav-btn:disabled { opacity: 0.3; cursor: default; }

/* ④ notices: the current move's prompt messages — an amber attention card
   that blinks (it disappears by itself once the next action changes the seq). */
.notice-board {
  background: rgba(240,192,64,0.08);
  border: 1px solid #6b5a26;
  border-radius: 6px;
  padding: 5px 7px;
  font-size: 0.75rem;
  line-height: 1.4;
}
.notice-title {
  font-size: 0.6rem; font-weight: bold;
  text-transform: uppercase; letter-spacing: 0.08em;
  color: #c9a43c; margin-bottom: 2px;
}
.notice-board .notice-msg {
  color: #f0e3bb;
  border-radius: 3px; padding: 1px 3px; margin: 0 -3px;
  animation: notice-blink 2s ease-in-out infinite;
}
@keyframes notice-blink {
  0%, 100% { background: rgba(240,192,64,0);    }
  50%      { background: rgba(240,192,64,0.28); }
}

/* The flexible spacer (above the notices + history block) is what fills the
   sidebar's leftover middle now — so the history keeps a FIXED height and never
   shifts when zone-3 (the action/spell panel) grows or the Request-Undo banner
   appears. Those changes are absorbed up here instead. */
.sb-spacer { flex: 1 1 0; min-height: 0; }

/* ④ history timeline: a FIXED-height box anchored to the bottom of the column
   (the spacer above does the flexing). It never grows or shrinks as the context
   above changes — only its own contents scroll. One .tl-entry per tracked move,
   newest on top, dots on a vertical rail; click = navigate (src/ui/timeline.js).
   flex-shrink stays on as a last resort if the column ever genuinely overflows. */
#log, #setup-log {
  background: rgba(0,0,0,0.3);
  border: 1px solid #2a3a5c;
  border-radius: 6px;
  padding: 0.25rem 0.3rem;
  font-size: 0.75rem;
  line-height: 1.45;
  color: #aab3c8;
  flex: 0 1 auto;
  height: 220px;
  min-height: 80px;
  overflow-y: auto;
}
.tl-entry {
  display: flex; gap: 7px;
  padding: 0.18rem 0.25rem 0.18rem 0.15rem;
  border-radius: 4px;
  cursor: pointer;
}
.tl-entry:hover { background: rgba(255,255,255,0.06); }
/* The rail: a continuous vertical line (overlapping each entry's box) with the
   move's dot on it. First/last entries trim the line at the dot so the rail
   doesn't poke past the ends of the history. */
.tl-rail { flex: 0 0 10px; position: relative; display: flex; align-items: flex-start; justify-content: center; }
.tl-rail::before {
  content: ''; position: absolute;
  left: 50%; transform: translateX(-50%);
  /* Extend past the entry's content box (it has top/bottom padding) so adjacent
     segments overlap into the gap and the rail reads as ONE continuous line. */
  top: -0.3rem; bottom: -0.3rem; width: 1px;
  background: #2e3a58;
}
/* Trim the rail at the dot for the first/last entries so the line doesn't poke
   past the ends. The dot sits on the FIRST line; 0.725em = half the 1.45
   line-height = that line's centre. */
.tl-entry:first-child .tl-rail::before { top: 0.725em; }
.tl-entry:last-child  .tl-rail::before { bottom: calc(100% - 0.725em); }
.tl-dot {
  position: relative; z-index: 1;       /* horizontally centred by the rail's flexbox; sits over the line */
  margin-top: calc(0.725em - 4px);      /* align to the first text line, not the whole entry */
  width: 8px; height: 8px; border-radius: 50%;
  box-sizing: border-box;
  background: #161a28; border: 2px solid #4a5878;
}
.tl-entry:hover .tl-dot { border-color: #8fb8d8; }
.tl-body { flex: 1; min-width: 0; }
.tl-msg + .tl-msg { color: #8a93a8; }
/* The viewed position: filled glowing dot + highlighted text */
.tl-entry.tl-current { background: rgba(76,201,240,0.10); }
.tl-entry.tl-current .tl-dot {
  background: #4cc9f0; border-color: #4cc9f0;
  box-shadow: 0 0 5px rgba(76,201,240,0.6);
}
.tl-entry.tl-current .tl-msg { color: #fff; }
.tl-entry.tl-current .tl-msg + .tl-msg { color: #bdc7d8; }
/* Moves AHEAD of the viewed position (you stepped back): dimmed until you
   return — clicking one (or the newest) is the new "Redo"/"Latest". Dim the
   dot + text only, NOT the whole entry: dimming the entry made its translucent
   rail segment stack with the next one in the overlap and read brighter there.
   The rail line stays full-opacity (solid colour), so overlaps never brighten. */
.tl-entry.tl-ahead .tl-dot,
.tl-entry.tl-ahead .tl-body { opacity: 0.45; }
.tl-entry.tl-ahead:hover .tl-dot,
.tl-entry.tl-ahead:hover .tl-body { opacity: 0.8; }
/* Asides: automatic between-turn effects (Fellowship, Ruins, Craters, …) —
   small event rows with a tiny tick on the rail, sitting between the move
   dots (they share the preceding move's history step / click target). */
.tl-entry.tl-aside { padding-top: 0; padding-bottom: 0; font-size: 0.68rem; }
.tl-entry.tl-aside .tl-msg { color: #7f8aa3; }
.tl-entry.tl-aside .tl-dot {
  width: 6px; height: 6px;
  margin-top: calc(0.725em - 3px);   /* first-line centre for the smaller (6px) aside dot */
  border-width: 1px; border-color: #3c4666;
}


/* DEBUG overlay */
.debug-grid #board-war .cell {
  border: 1px solid rgba(255,255,0,0.45) !important;
  background: rgba(255,255,0,0.04) !important;
}

