/* Play screen: side panels — match buttons, chat, action groups, battle log, rewind bar, action wheel, rematch, seats panel. */
.game-buttons {
  display: flex;
  flex-direction: row;
  gap: 8px;
  flex-shrink: 0;
}
.game-buttons .btn { flex: 1 1 0; justify-content: center; min-width: 0; }
/* All four are .nl-act-compact (icon-only at every width) and fit one row, so the grouping
   wrappers dissolve into direct flex children. */
.game-btn-group { display: contents; }
.game-buttons .btn-draw { color: var(--text-muted); border-color: var(--border-color); }
.game-buttons .btn-draw:hover { color: var(--accent-gold); border-color: var(--accent-gold); }

.rp-card-note { font-size: 0.72rem; color: var(--ink-3); }
.chat-body { display: flex; flex-direction: column; }
.chat-scroll { max-height: 160px; overflow-y: auto; display: flex; flex-direction: column; gap: 7px; }
.chat-empty { color: var(--ink-3); font-size: 0.8rem; text-align: center; padding: 14px 8px; }
.chat-input {
  display: flex; gap: 6px;
  padding: 8px 0 2px;
  border-top: 1px solid var(--divider);
}
.chat-input input {
  flex: 1 1 auto; min-width: 0; padding: 6px 10px;
  border-radius: var(--radius-s); border: 1px solid var(--border);
  background: var(--bg-0); color: var(--ink); font: inherit; font-size: 0.85rem;
}
.chat-input input:disabled { opacity: 0.6; cursor: not-allowed; }
.chat-input .btn { flex: 0 0 auto; }
.chat-msg { display: flex; flex-direction: column; gap: 1px; font-size: 0.85rem; }
.cm-name { font-size: 0.68rem; font-weight: 600; color: var(--ink-3); }
.chat-msg.me .cm-name  { color: var(--lapis-2); }
.chat-msg.opp .cm-name { color: var(--porphyry-2); }
.cm-text { color: var(--ink); }

/* Width is a rail token (screens/play-layout.css); this is the card stack itself. */
.game-panel { display: flex; flex-direction: column; gap: 8px; max-height: 85vh; overflow-y: auto; transition: width 0.18s ease; }
.left-col-wrap { display: flex; flex-direction: column; transition: width 0.18s ease; }
.left-col-wrap > .settings-row { background: var(--bg-card); border: 1px solid var(--border-color); border-radius: 6px; padding: 6px 10px; margin-bottom: 0px; grid-template-columns: 1fr 1fr; }
.left-panel { max-width: 100%; padding-top: 2px; flex: 1; min-height: 0; }
.right-panel { max-width: 100%; display: flex; flex-direction: column; overflow-y: auto; max-height: 85vh; padding-bottom: 14px; transition: width 0.18s ease; }

.play-panel-toggle {
  width: 26px; height: 26px;
  padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: 6px;
  color: var(--ink-3);
  cursor: pointer;
  font-family: inherit;
  font-size: 1rem;
  line-height: 1;
  flex: 0 0 auto;
  transition: border-color 0.15s ease, color 0.15s ease;
}
.play-panel-toggle:hover {
  border-color: var(--bronze);
  color: var(--ink);
}
.play-panel-toggle-left  { align-self: flex-end; }
.play-panel-toggle-right { align-self: flex-start; }

.left-col-wrap.is-collapsed .left-panel { overflow: hidden; }

/* Width is the rail token, re-pinned by play-layout.css; this is the collapsed card chrome. */
.right-panel.is-collapsed { padding: 6px 2px 0; overflow: hidden; }
/* Collapsed is a re-pin, not a second width: the spectator phantom reads the same variable, so
   collapsing the panel must move the board with it. Set on the SCREEN — a sibling cannot read a
   custom property off .right-panel. */
.right-panel.is-collapsed > *:not(.play-panel-toggle) { display: none; }

/* The left column distributes a MEASURED height (_syncPanelHeights matches it to the board), so
   the two cards that can outgrow it scroll their own bodies and End turn stays pinned at the
   foot. Scrolling the whole panel instead pushed End turn off the bottom the moment two action
   groups were open. Only an OPEN actions card and a NON-EMPTY plan compete for the slack; a
   collapsed header must not grow, and there is no `:has()` at this support floor, so the
   renderers publish `is-open` / `mp-grow`. */
/* `auto`, not `hidden`: the cards shrink first, but both stop at min-height and the unit card and
   End turn do not shrink at all, so a short viewport would otherwise CLIP the very content the
   pinning exists to keep reachable. */
.left-panel { overflow-y: auto; }
/* `0 1 auto`, never `1 1`: these may SHRINK when the column runs out, and must not GROW when it
   does not — growing stretched the Actions card down the whole panel on a turn with no plan. */
.left-panel > .actions-card.is-open { flex: 0 1 auto; min-height: 72px; display: flex; flex-direction: column; }
.left-panel > .actions-card.is-open > .rp-card-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; }
/* The one control that must never squash — it is what the shrinking above is protecting. */
.left-panel > .btn-end-turn { flex-shrink: 0; }
/* The plan takes what its CONTENT needs — no cap, so a long line uses every row down to the foot
   of the board — and is the thing that yields when the column runs out. Growing it instead left a
   mostly empty box on a three-step plan. */
.left-panel > .move-plan.mp-grow { flex: 0 1 auto; min-height: 72px; }
.left-panel > .move-plan.mp-grow > .mp-steps { max-height: none; flex: 0 1 auto; min-height: 0; }

/* The strip's own look is in components/move-plan.css; what follows is only where it SITS. */
/* The board is showing a position that has not happened. A pseudo-element frame, not an
   `outline`: an outline inherits the element's own radius, and .game-screen .board-wrap rounds
   its BOTTOM corners only (it closes the fused column), so the frame came out square-cornered
   over the eval bar and rounded under the board. Drawn INSIDE the card: an outset frame crossed
   into the eval bar above and, on a phone, into the last few pixels the board had to spend. */
.game-screen.is-planning .board-wrap::before,
.puzzle-screen.is-planning .board-wrap::before {
  content: '';
  position: absolute; inset: 4px;
  border: 1px dashed var(--bronze);
  border-radius: var(--radius-m);
  pointer-events: none;
}

/* Every play-screen surface on the deepest ground, the tone the move-plan strip already uses. One
   block, so it is one block to pull. Buttons are excluded — a flat fill would erase their skin —
   and the turn banner keeps its own states; only its neutral one joins. */
.game-screen .pbar,
.game-screen .group-status-bar,
.game-screen .eval-wrap,
.game-screen .turn-banner-opponent-turn,
.game-screen .left-panel  > *:not(button),
.game-screen .right-panel > *:not(button) { background: var(--bg-0); }
.game-screen .board-wrap { --board-ground: var(--bg-0); }
/* Inside the cards too — an action group's header and a log row sat a tier above their own card
   and read as boxes on a box once the card itself went to --bg-0. */
.game-screen .action-group-hdr,
.game-screen .btn-action,
.game-screen .log-entry { background: var(--bg-0); }
.game-screen .action-group-hdr:hover { background: var(--bg-2); }
/* Hover and the picked verb still have to read against it. `.active` keeps its bronze fill —
   that is the selection, not a surface. */
.game-screen .btn-action:hover:not(:disabled) { background: var(--bg-2); }

/* Stacked, the left column is a wrapping ROW of cards under the board. WHICH width stacks,
   and where End turn mounts, are screens/play-layout.css's; this is only how the column's own
   contents lay out once it is one. */
@media (max-width: 1440px) {
  /* flex-start, not the default stretch: the cards in a wrapping row have wildly different
     natural heights, and stretching every one to the tallest drew a short card as a tall empty
     box — most visibly the match-button strip, whose icon buttons then ran the full height of
     the battle log beside them. */
  .game-panel { flex-direction: row; flex-wrap: wrap; align-items: flex-start; }
  .game-panel > * { flex: 1; min-width: 200px; }
  /* Its buttons are icon-only and share one row, so it needs a row of its own rather than a
     200px column beside a log card. */
  .game-buttons { flex: 1 0 100%; }
  .left-panel { flex: none; min-height: auto; }
  /* The panel is a wrapping ROW here, so the "flex: 1" above would squeeze a step list in beside
     the cards. Its own row, still directly above End turn. */
  .left-panel > .move-plan,
  .left-panel > .btn-end-turn { flex: 1 0 100%; }
  /* The strip leads the column so it reads as the board's own footer rather than the last card
     of a panel, and End turn follows it directly — the unit and Actions cards must not come
     between the line and the button that commits it. */
  .left-panel > .move-plan { order: -1; }
  .left-col-wrap.plan-live .left-panel > .btn-end-turn { order: -1; }
  /* No measured height to distribute, so nothing grows and the step list keeps its own cap. */
  .left-panel > .actions-card.is-open,
  .left-panel > .move-plan.mp-grow { flex: 1 0 100%; min-height: 0; }
  .left-panel > .actions-card.is-open > .rp-card-body { overflow-y: visible; }
  .left-panel > .move-plan.mp-grow > .mp-steps { max-height: 210px; flex: 0 1 auto; }
}

/* Seats (admin) reads as a card only here — recruit/deploy strip the chrome. */
.left-panel .ai-mode-panel {
  margin: 0;
  padding: 9px 10px;
  border-radius: var(--radius-m);
  align-items: flex-end;
  gap: 8px;
}
.left-panel .ai-mode-select { padding: 6px 8px; font-size: 0.8rem; border-radius: var(--radius-s); }

.a-bonus { font-size: 0.62rem; font-weight: 700; color: var(--laurel-2); background: rgba(95,143,63,0.15); padding: 1px 5px; border-radius: 8px; }
.pool-badge {
  font-size: 0.58rem; line-height: 1.3; font-weight: 600;
  padding: 1px 6px; border-radius: 5px; white-space: nowrap;
  background: var(--bg-2); border: 1px solid var(--border);
  vertical-align: middle;
}
.pool-avail { color: var(--bronze-2); }
.pool-spent { color: var(--ink-4); opacity: 0.6; }
.btn-action .a-icon { display: inline-flex; flex: 0 0 16px; color: var(--bronze-2); }
.btn-action .a-icon svg { width: 16px; height: 16px; }
.btn-action .a-label { flex: 1; }
.btn-action .a-cost { font-size: 0.72rem; color: var(--ink-3); }
.btn-action.active .a-icon { color: var(--on-bronze); }

.ac-groups { display: flex; flex-direction: column; gap: 5px; }
.action-group { display: flex; flex-direction: column; gap: 3px; }
.action-group-hdr {
  width: 100%; text-align: left; padding: 6px 10px;
  font-family: inherit; font-size: 0.72rem; font-weight: 600;
  background: var(--bg-2); border: 1px solid var(--border);
  border-radius: var(--radius-s); cursor: pointer; color: var(--text-secondary);
  display: flex; justify-content: space-between; align-items: center;
  letter-spacing: 0.05em; text-transform: uppercase;
}
.action-group-hdr:hover { background: var(--bg-3); color: var(--text-primary); }
.action-group-body { padding: 2px 0 4px; display: flex; flex-direction: column; gap: 3px; }
.ui-spec-badge {
  font-size: 0.62rem; font-weight: 700; color: var(--gold);
  background: color-mix(in srgb, var(--gold) 14%, transparent); border: 1px solid color-mix(in srgb, var(--gold) 35%, transparent);
  border-radius: 8px; padding: 1px 7px;
}
.target-hint { padding: 8px; text-align: center; font-size: 0.8rem; color: var(--accent-green); background: var(--bg-card); border-radius: var(--border-radius); }

.log-scroll {
  overflow-y: auto; display: flex; flex-direction: column; gap: 2px;
  max-height: min(240px, 30vh); min-height: 0;
  font-size: 0.8rem;
  background: var(--bg-0); border-radius: var(--radius-s); padding: 8px;
}
/* Over every cap, so max-height clamps it: the box stands at its cap instead of growing per entry. */
.game-screen .log-scroll,
.game-screen .ai-think-body { height: 100vh; }
.log-entry { padding: 3px 8px; background: var(--bg-1); border-radius: 3px; border-left: 3px solid transparent; color: var(--ink-2); }
/* --ink-3, not --ink-4: the "T5.1" seat suffix is the stripe's non-colour channel, so it
   has to be legible (4.56:1 dark / 4.90:1 light, against --ink-4's 2.42 / 2.00). */
.log-entry .le-turn { color: var(--ink-3); margin-right: 6px; }
/* Viewer stripe in the battle log and the replay log — mine/theirs, not seat 0/1. The eval pair
   is tone-matched, so a red-green dichromat cannot separate the two by hue: the turn number in
   .le-turn is what carries the reading for them. Keep it. */
.log-mine { border-left-color: var(--eval-mine); }
.log-them { border-left-color: var(--eval-them); }
.log-sep {
  display: flex; align-items: center; gap: 8px;
  margin: 6px 0 2px; padding: 0 2px;
  font-size: 0.66rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--ink-4);
}
.log-sep::before, .log-sep::after { content: ''; flex: 1; height: 1px; background: var(--divider); }
.log-sep-mine { color: var(--eval-mine); }
.log-sep-them { color: var(--eval-them); }

/* Every log row is a rewind handle (match-history.js). The affordance is deliberately quiet —
   the log is read far more often than it is navigated. */
.log-nav { cursor: pointer; }
.log-nav:hover { background: var(--bg-hover); }
.log-nav:focus-visible { outline: 2px solid var(--bronze-2); outline-offset: -2px; }
.log-entry.log-at { background: color-mix(in srgb, var(--bronze-2) 16%, var(--bg-1)); }

/* Says the board is a PAST position, and carries the only way back. Bronze rather than a warning
   colour: browsing history is normal, not an error state. */
/* Foot of the right panel, under the game buttons: a panel slot, so entering and leaving
   history never moves the board. */
.rewind-bar {
  display: flex; align-items: center; justify-content: space-between; gap: 8px; flex-wrap: wrap;
  margin-top: 8px; padding: 6px 8px;
  background: color-mix(in srgb, var(--bronze) 16%, var(--bg-1));
  border: 1px solid var(--bronze); border-radius: var(--radius-s);
  font-size: 0.75rem;
}
.rewind-note { color: var(--ink-2); white-space: nowrap; font-variant-numeric: tabular-nums; }
.rewind-steps { display: flex; gap: 4px; flex: 0 0 auto; }
.rewind-steps .btn { padding: 2px 8px; }
/* The board is inert while browsing (no handlers are emitted at all); the cursor says so. */
.game-screen.is-rewound .board-grid { cursor: default; }


.acpop-root { position: absolute; pointer-events: none; z-index: 80; width: 0; height: 0; }
/* Sized off --cell-size, so the wheel keeps the board's PHYSICAL scale: browser zoom shrinks
   --cell-size to hold the board steady, and a fixed px wedge would balloon against it.
   ACPOP_BASE_PX in action-popup.js is calibrated to the 46px ceiling. */
.acpop-btn {
  --acpop-min: 34px;
  --acpop-size: clamp(var(--acpop-min), var(--cell-size, 46px), 46px);
  position: absolute; transform: translate(-50%, -50%);
  width: var(--acpop-size); height: var(--acpop-size);
  border-radius: 50%; background: color-mix(in srgb, var(--bg-0) 94%, transparent); border: 2px solid color-mix(in srgb, var(--bronze-2) 55%, transparent);
  color: var(--text-primary); cursor: pointer; pointer-events: auto;
  display: flex; align-items: center; justify-content: center;
  transition: background 0.12s, border-color 0.12s, transform 0.1s; font-family: var(--font);
}
.acpop-btn:hover { background: var(--bg-hover); border-color: var(--accent-gold); transform: translate(-50%, -50%) scale(1.15); z-index: 2; }
.acpop-btn.acpop-active { background: var(--bronze-gradient); border-color: var(--bronze-2); color: var(--on-bronze); }
.acpop-btn.acpop-active:hover { transform: translate(-50%, -50%) scale(1.12); }
/* A mouse needs no 34px target, so the floor drops and the wheel tracks zoom the whole way down. */
@media (pointer: fine) { .acpop-btn { --acpop-min: 28px; } }
/* Ratios reproduce the old 1.1rem / 0.44rem exactly at the 46px ceiling. */
/* Same ACTION_ICONS stroke family as the left-panel rows, tinted like them; the SVGs use
   currentColor, so the active wedge needs the same override .btn-action.active does. */
.acpop-icon { display: inline-flex; line-height: 1; color: var(--bronze-2);
  font-size: calc(var(--acpop-size) * 0.5); }
/* Half the wedge: the label used to take the lower third. */
.acpop-icon svg { width: calc(var(--acpop-size) * 0.5); height: calc(var(--acpop-size) * 0.5); }
.acpop-btn.acpop-active .acpop-icon { color: var(--on-bronze); }
.acpop-btn:disabled { opacity: 0.42; cursor: not-allowed; }
.acpop-btn:disabled:hover { background: color-mix(in srgb, var(--bg-0) 94%, transparent);
  border-color: color-mix(in srgb, var(--bronze-2) 55%, transparent); transform: translate(-50%, -50%); }
/* Action cost, bottom-right — the same badge the left-panel rows and the review rail carry.
   Hangs off the circle's box corner, which is clear of the glyph at every wedge size. */
.acpop-cost {
  position: absolute; bottom: -2px; right: -2px;
  display: flex; align-items: center; justify-content: center;
  min-width: calc(var(--acpop-size) * 0.34); height: calc(var(--acpop-size) * 0.34);
  padding: 0 calc(var(--acpop-size) * 0.06); box-sizing: border-box;
  border-radius: calc(var(--acpop-size) * 0.17);
  background: var(--ink); color: var(--bg-0);
  border: 1px solid color-mix(in srgb, var(--bg-0) 45%, transparent);
  font-size: calc(var(--acpop-size) * 0.24); font-weight: 700;
  font-variant-numeric: tabular-nums; line-height: 1;
}
.acpop-btn.acpop-active .acpop-cost { background: var(--on-bronze); color: var(--bronze-2); }

.rematch-offered {
  margin: 16px auto;
  max-width: 420px;
  padding: 14px 18px;
  background: var(--bg-1);
  border: 1px solid var(--bronze);
  border-radius: var(--radius-l);
  text-align: center;
  box-shadow: 0 2px 12px color-mix(in srgb, var(--accent-gold) 15%, transparent);
  animation: fadeIn 0.2s ease;
}
.rematch-offered strong { color: var(--accent-gold); }
.rematch-offered-buttons {
  display: flex;
  gap: 10px;
  justify-content: center;
  margin-top: 12px;
}
.rematch-status {
  margin: 14px auto;
  max-width: 360px;
  padding: 10px 16px;
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: 8px;
  color: var(--text-muted);
  font-style: italic;
  text-align: center;
  font-size: 0.92rem;
}
@media (max-width: 640px) {
  .rematch-offered-buttons { flex-direction: column; }
  .rematch-offered-buttons .btn { width: 100%; }
}

.ai-mode-panel {
  /* reconcile() defers re-render while _aiPanelIsInteracting so the dropdown stays clickable across AI-vs-AI ticks. */
  background: transparent;
  border: 1px solid var(--border);
  border-radius: var(--radius-l);
  padding: 9px 12px;
  font-size: 0.82rem;
  color: var(--text-primary);
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 6px;
  margin-bottom: 8px;
  box-sizing: border-box;
}
.ai-mode-selects { display: flex; flex-direction: row; gap: 8px; width: 100%; }
.ai-mode-panel .ai-mode-select {
  flex: 1 1 0;
  min-width: 0;
}
/* Hide the "Seats" header on the tight deploy/play screens — dropdowns fill the panel. */
.left-panel .ai-mode-header,
.deploy-board-header .ai-mode-header { display: none; }
.ai-mode-header {
  font-size: 0.66rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--gold);
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  white-space: nowrap;
}
.ai-mode-badge {
  font-size: 0.55rem;
  background: color-mix(in srgb, var(--gold) 18%, transparent);
  color: var(--gold);
  padding: 1px 6px;
  border-radius: 8px;
  font-weight: 700;
  letter-spacing: 0.08em;
}
.ai-mode-pick {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  white-space: nowrap;
}
.ai-mode-pick-label {
  color: var(--text-muted);
  font-weight: 600;
}
@media (max-width: 640px) {
  .ai-mode-panel {
    flex-direction: column;
    align-items: stretch;
    gap: 4px;
  }
}/* Chat unavailable — names the cause, so "blocked" and "broken" don't look identical. */
.chat-off {
  margin: 0 0 8px; padding: 8px 10px;
  background: var(--bg-2); border: 1px solid var(--border); border-radius: var(--radius-s);
  color: var(--ink-3); font-size: 0.78rem; line-height: 1.5;
}


/* Where End turn MOUNTS and how the play columns stack are screens/play-layout.css's, which is
   the one owner of the play grid. Only the button's own look stays here. */
.game-end-turn-mobile { padding: 0; margin-top: 6px; }
.game-end-turn-mobile .btn-end-turn {
  width: 100%;
  margin-top: 0;
  padding: 12px 16px;
  font-size: 1rem;
}

@media (max-width: 640px) {
  .game-end-turn-mobile { padding: 0 4px; }

  /* Cap scrollable panel cards to ~1/3 viewport so they can't dominate. */
  .game-main > .right-panel .ai-think-body,
  .game-main > .right-panel .log-scroll {
    max-height: 30vh;
  }

  .left-panel .actions-card {
    width: 100%;
    box-sizing: border-box;
  }

  /* Drop desktop min-height so the collapsed log card isn't needlessly tall. */
  .game-main > .right-panel .log-card {
    min-height: 0;
  }
  .game-main > .right-panel .log-card .log-scroll {
    max-height: 35vh;
  }
}
