/* coscryption — UI styles
 *
 * The auth/lobby chrome keeps the original dark/amber/Cinzel look (root
 * tokens below). The run screen uses a separate set of tokens to match the
 * Claude Design mockup (design/coscryption Run Screen.html): warm card
 * stock, dark espresso borders, Special Elite for card names, Manrope
 * everywhere else. Both palettes share the same page background so the
 * transition from lobby → run is seamless.
 */

:root {
  /* Existing auth/lobby palette */
  --bg-dark: #1a1410;
  --bg-medium: #2a1f18;
  --text: #d4c8a8;
  --accent: #b88a3e;

  /* Run-screen palette (mockup) */
  --card-stock: #c7c0ab;       /* face-up card body */
  --card-espresso: #1c1712;    /* name bar bg, borders, stat-pill text */
  --card-cream: #e9dfc9;       /* name text, sigil badge text, stat-pill bg */
  --card-placeholder: #8f9077; /* behind card art when no image */
  --card-shadow: rgba(0, 0, 0, 0.5);

  /* Cost pip colors (mockup) */
  --pip-blood: #8b1e1e;
  --pip-bone: #d8cba9;

  /* Face-down (deep green stripes) */
  --face-down-1: #16211a;
  --face-down-2: #10170f;

  /* Empty slot (translucent over page bg) */
  --empty-border: rgba(184, 147, 90, 0.28);
  --empty-label: rgba(184, 147, 90, 0.4);
}

body {
  margin: 0;
  background: var(--bg-dark);
  color: var(--text);
  font-family: 'Manrope', 'Cinzel', 'Georgia', serif;
}

#app {
  /* No top padding: the topbar sticks flush to the viewport edge (see
     .run-header below) so its own gap doesn't cost the page vertical
     space above it. */
  padding: 0 24px 24px;
}

/* ---- Auth / lobby / shared chrome (existing) ---- */

button {
  background: var(--bg-medium);
  color: var(--text);
  border: 1px solid var(--accent);
  padding: 8px 16px;
  cursor: pointer;
  font-family: inherit;
  font-family: 'Cinzel', serif;
  letter-spacing: 0.02em;
}

button:hover {
  background: var(--accent);
  color: var(--bg-dark);
}

input {
  background: var(--bg-medium);
  color: var(--text);
  border: 1px solid var(--accent);
  padding: 8px;
  font-family: inherit;
}

h1, h2, h3 {
  font-family: 'Cinzel', serif;
  letter-spacing: 0.04em;
}

.chosen-pool {
  display: flex;
  gap: 4px;
  flex-wrap: wrap;
}

.reward-picker {
  background: var(--bg-medium);
  border: 2px solid var(--accent);
  color: var(--text);
  padding: 16px;
  margin-top: 16px;
}

/* ---- Run screen ---- */

.action-error-banner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  background: rgba(139, 30, 30, 0.22);
  border: 1.5px solid rgba(139, 30, 30, 0.6);
  color: #e6b8b8;
  border-radius: 8px;
  padding: 10px 14px;
  margin-bottom: 12px;
  font-family: 'Manrope', sans-serif;
  font-size: 13px;
}

.action-error-dismiss {
  background: transparent;
  border: none;
  color: #e6b8b8;
  cursor: pointer;
  font-size: 14px;
  line-height: 1;
  padding: 2px 4px;
}

.run-header {
  display: grid;
  /* Outer columns equal (1fr each) so the center column — HP scale +
     Trade/End Turn — sits at the true horizontal middle of the bar,
     not just "whatever's left after the title" (which used to leave it
     hugging the right edge, next to the sidebar toggle, since the old
     `1fr auto auto` gave column 1 all the leftover space). Requested:
     "move the end turn and trade button in the topbar to the middle so
     we can more easily reach it". */
  grid-template-columns: 1fr auto 1fr;
  gap: 24px;
  align-items: center;
  /* v0.2.0: padding reduced from `12px 18px` to `4px 12px` to free
     vertical space — the user is still scrolling. Border-radius /
     shadow kept so the header still reads as a distinct bar. */
  padding: 4px 12px;
  background: var(--card-espresso);
  border: 1.5px solid var(--card-espresso);
  border-radius: 6px;
  box-shadow: 0 3px 10px rgba(0, 0, 0, 0.4);
  /* margin-bottom reduced from 18px to 6px */
  margin-bottom: 6px;
  color: var(--card-cream);
  font-family: 'Manrope', sans-serif;
  /* Sticks to the top of the viewport instead of scrolling away with
     the board — requested so the header (turn/HP/actions) stays
     reachable without losing the vertical space it used to cost as
     ordinary top padding on #app. */
  position: sticky;
  top: 0;
  z-index: 10;
}

.run-header-left {
  display: flex;
  align-items: baseline;
  gap: 12px;
  flex-wrap: wrap;
}

.run-header-center {
  display: flex;
  align-items: center;
  /* v0.2.0: gap reduced from 12px to 8px to shave another row of
     vertical space. The hp-label / pip-bar / hp-value trio needs to
     fit comfortably without dominating the header height. */
  gap: 8px;
}

.run-header-right {
  display: flex;
  align-items: center;
  /* Column 3 is now 1fr (matches column 1) to center column 2 — pin
     this column's content (just the sidebar toggle) to the far right
     edge instead of letting it drift toward the middle. */
  justify-content: flex-end;
}

.run-title {
  font-family: 'Cinzel', serif;
  /* v0.2.0: font-size reduced from 22px to 16px — the user removed
     the big `<h1>coscryption</h1>` heading and the room code already,
     so this Cinzel title in the top bar is the only title left and
     can afford to be smaller. */
  font-size: 16px;
  font-weight: 700;
  letter-spacing: 0.12em;
  color: var(--card-cream);
  text-transform: uppercase;
}

.run-encounter {
  font-size: 13px;
  color: rgba(233, 223, 201, 0.7);
  letter-spacing: 0.04em;
}

.difficulty-badge {
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.14em;
  padding: 2px 8px;
  border-radius: 4px;
  text-transform: uppercase;
}
.difficulty-easy { background: #6f9b58; color: var(--card-espresso); }
.difficulty-normal { background: #c89a3e; color: var(--card-espresso); }
.difficulty-hard { background: #b53a3a; color: var(--card-cream); }
.difficulty-boss { background: #6b1f1f; color: var(--card-cream); }

/* Balance bar — v0.2.0 (round 5) single-row horizontal pip strip
   that reimplements the visual of the old tilting scale. The old
   scale (150×70px, fulcrum/post/beam/pans/weights/labels) was 70px
   tall — way too much vertical space in the top bar for what it
   conveyed. The new bar's geometry is FIXED:
     [Y Y Y Y Y · B B B B B]    <- max_hp yellow + 1 colorless separator + max_deck brown
   A RED marker pip starts in the separator slot and moves LEFT when
   the players lose HP (rightmost yellows turn empty) and RIGHT when
   the monster loses deck cards (leftmost browns turn empty). Marker
   offset from separator = (deck_lost) - (hp_lost), clamped to
   [0..total-1]. The bar never shrinks — only fills change. */
.pip-bar {
  display: flex;
  flex: 0 0 auto;
  padding: 2px 4px;
  background: rgba(0, 0, 0, 0.25);
  border-radius: 4px;
}

.pip-bar-row {
  display: flex;
  gap: 2px;
  align-items: center;
}

.pip {
  width: 8px;
  height: 8px;
  border-radius: 1px;
  flex: 0 0 auto;
}

/* Shared HP pips (left) — YELLOW-filled when HP remains, empty
   border when HP has been lost from the right edge inward. */
.pip--left {
  background: transparent;
  border: 1px solid #8a7550;
}
.pip--left.is-filled {
  background: #f5c542;
  border-color: #8a6d1f;
}
.pip--left.is-empty {
  background: transparent;
  border-color: rgba(233, 223, 201, 0.18);
}

/* Monster deck pips (right) — brown-filled when card still in deck,
   empty border when played (from the left edge of the deck section
   inward). */
.pip--right {
  background: transparent;
  border: 1px solid #6b5a3c;
}
.pip--right.is-filled {
  background: #3a2a1c;
  border-color: #6b5a3c;
}
.pip--right.is-empty {
  background: transparent;
  border-color: rgba(233, 223, 201, 0.18);
}

/* Separator — colorless slot in the middle of the bar. No fill, just
   a thin border so the layout reads as `[...][ | ][...]` instead of
   one continuous block. */
.pip--separator {
  background: transparent;
  border: 1px dashed rgba(233, 223, 201, 0.18);
  width: 4px;
}

/* Red marker — sits on top of whatever slot it currently occupies
   (yellow/empty/separator/brown/empty). Indicates the cumulative
   scale imbalance since encounter start. Larger than data pips so
   it's visible against any background. */
.pip--marker {
  width: 10px;
  height: 10px;
  background: #d33a3a;
  border: 1px solid #6b1f1f;
  border-radius: 1px;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.3);
}

.phase-status {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: #d8b27a;
  padding: 4px 10px;
  border-radius: 6px;
  background: rgba(216, 178, 122, 0.08);
  border: 1px solid rgba(216, 178, 122, 0.2);
}

.hp-label {
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: rgba(233, 223, 201, 0.7);
  font-weight: 700;
}

.hp-value {
  font-size: 13px;
  font-weight: 800;
  color: var(--card-cream);
  min-width: 64px;
  text-align: right;
}

.phase-badge {
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-weight: 700;
  padding: 4px 10px;
  background: rgba(233, 223, 201, 0.08);
  border: 1px solid rgba(233, 223, 201, 0.25);
  border-radius: 999px;
  color: var(--card-cream);
}

/* ---- Run screen layout: header, board, sidebar, card pool, action panel */

/* The run-main wraps the per-player zones (board) and the sidebar in a
   CSS grid. Sidebar is on the right, board fills the rest. When the
   body carries the 'sidebar-open' class, the sidebar slides into view;
   otherwise it's hidden off-screen (collapsed). */
.run-main {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 16px;
  align-items: start;
  transition: grid-template-columns 200ms ease;
}

body:not(.sidebar-open) .run-sidebar {
  display: none;
}

body.sidebar-open .run-main {
  grid-template-columns: 1fr 280px;
}

.run-sidebar {
  background: var(--card-espresso);
  border: 1.5px solid var(--card-espresso);
  border-radius: 8px;
  padding: 12px;
  color: var(--card-cream);
  font-family: 'Manrope', sans-serif;
  font-size: 12px;
  min-width: 240px;
  max-width: 320px;
  box-shadow: 0 3px 10px rgba(0, 0, 0, 0.4);
}

.sidebar-section {
  margin-bottom: 14px;
}

.sidebar-section h3 {
  font-family: 'Cinzel', serif;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 0 0 6px;
}

.log-list, .opp-list {
  list-style: none;
  margin: 0;
  padding: 0;
  max-height: 200px;
  overflow-y: auto;
}

.log-list li, .opp-list li {
  padding: 3px 6px;
  border-bottom: 1px solid rgba(233, 223, 201, 0.08);
  font-size: 11px;
  color: rgba(233, 223, 201, 0.8);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.log-empty {
  color: rgba(233, 223, 201, 0.4);
  font-style: italic;
}

.opp-item {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.opp-name {
  font-weight: 700;
  color: var(--card-cream);
}

.opp-stats {
  color: rgba(233, 223, 201, 0.6);
  font-size: 10px;
}

/* Card pool area (separate from the hand — draft / swap zone). */
.card-pool {
  margin-top: 16px;
  background: var(--card-espresso);
  border: 1.5px solid var(--card-espresso);
  border-radius: 8px;
  padding: 12px;
  color: var(--card-cream);
  font-family: 'Manrope', sans-serif;
  box-shadow: 0 3px 10px rgba(0, 0, 0, 0.4);
}

.card-pool h3 {
  font-family: 'Cinzel', serif;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 0 0 8px;
}

.card-pool-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  min-height: 80px;
}

.card-pool-empty {
  color: rgba(233, 223, 201, 0.4);
  font-style: italic;
  font-size: 12px;
  align-self: center;
}

/* Sidebar collapse toggle in the header. */
.sidebar-toggle {
  background: rgba(233, 223, 201, 0.08);
  border: 1px solid rgba(233, 223, 201, 0.25);
  color: var(--card-cream);
  border-radius: 6px;
  padding: 4px 10px;
  font-size: 14px;
  cursor: pointer;
  font-family: inherit;
}

.sidebar-toggle:hover {
  background: rgba(233, 223, 201, 0.16);
}

/* Board contains 1-3 player columns side-by-side. Each column is a
   narrow vertical block with monster reserve/front rows + your
   board/reserve rows. */
#board {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 440px));
  justify-content: center;
  gap: 12px;
}

.player-column {
  background: var(--card-espresso);
  border: 1.5px solid var(--card-espresso);
  border-radius: 8px;
  padding: 12px;
  max-width: 440px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  box-shadow: 0 3px 10px rgba(0, 0, 0, 0.4);
}

.player-column.is-you {
  border-color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent), 0 3px 10px rgba(0, 0, 0, 0.4);
}

/* Reserved-but-unjoined seat: same board shape, dimmed and non-interactive
   (pointer-events: none — the empty slots inside have no click handler
   anyway, but this also stops hover affordances from lighting up). */
.player-column.is-waiting {
  opacity: 0.45;
  filter: grayscale(0.5);
  pointer-events: none;
}

.player-column.is-waiting .player-name {
  color: rgba(233, 223, 201, 0.45);
  font-style: italic;
}

.row-section {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.row-label {
  font-family: 'Manrope', sans-serif;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(233, 223, 201, 0.55);
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin-top: 2px;
}

.row-label-sub {
  font-size: 9px;
  font-weight: 400;
  letter-spacing: 0.04em;
  color: rgba(233, 223, 201, 0.4);
  text-transform: none;
}

/* Peek row — the encounter monster's upcoming-play queue. Each peek card
   has a ▼ arrow underneath to indicate "advances into monster front on the
   monster's turn" (queue/descend semantics, like the original game). */
.peek-row {
  background: rgba(120, 160, 120, 0.06);
  border: 1px dashed rgba(120, 160, 120, 0.22);
  border-radius: 6px;
  padding: 4px;
}

.peek-arrow {
  position: absolute;
  left: 50%;
  bottom: -14px;
  transform: translateX(-50%);
  color: rgba(120, 160, 120, 0.7);
  font-size: 10px;
  line-height: 1;
  pointer-events: none;
}

/* YOUR FRONT row — the 2D player board. `player-front-row` lets us tune
   spacing separately from the monster row (e.g. tighter if there are 2
   rows stacked). */
.your-front-row {
  background: rgba(184, 147, 90, 0.06);
  border-radius: 6px;
  padding: 4px;
}

.monster-front-row {
  background: rgba(120, 160, 120, 0.06);
  border-radius: 6px;
  padding: 4px;
}

.zone-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding-bottom: 6px;
  border-bottom: 1px solid rgba(233, 223, 201, 0.12);
}

.column-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding-bottom: 6px;
  border-bottom: 1px solid rgba(233, 223, 201, 0.12);
}

.column-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding-bottom: 6px;
  border-bottom: 1px solid rgba(233, 223, 201, 0.12);
}

.player-ident {
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: 'Manrope', sans-serif;
  color: var(--card-cream);
}

.avatar {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: rgba(233, 223, 201, 0.1);
  border: 1.5px solid var(--card-cream);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 0.04em;
}

.avatar--empty {
  background: rgba(233, 223, 201, 0.08);
  border-style: dashed;
  color: rgba(233, 223, 201, 0.4);
}

.player-name {
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.you-badge {
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 2px 8px;
  background: var(--accent);
  color: var(--card-espresso);
  border-radius: 999px;
}

.pools {
  display: flex;
  align-items: center;
  gap: 10px;
  font-family: 'Manrope', sans-serif;
  font-size: 12px;
  font-weight: 700;
}

.pool {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.35);
  border: 1px solid rgba(233, 223, 201, 0.18);
}

/* v0.2.0 (round 6): .pool-blood and its diamond marker removed —
   blood is transient (created + consumed within one PlaceCard
   action), so showing it persistently in the header confused the
   two pools' roles. Only bones is shown now. */

/* No ::before pip here — the 🦴 emoji is the icon (board.js prepends
   it to the bones count directly), matching the design source
   (Run.dc.html: `🦴 {{ player.bones }}`). A CSS square pip briefly
   replaced it at some point; restored per report: "the bone counter's
   icon has been changed recently it was a bone before". */

/* v0.2.0 (round 6): "prominent" variant of the bones chip — used in
   the player column header. Larger font, more padding, brighter color
   so the user notices when it ticks up (their report: "still not
   seeing the bones counter going up after sacrificing cards"). The
   round-1 flash was too subtle at the original chip size. */
.pool-bones--prominent {
  font-family: 'Cinzel', serif;
  font-size: 16px;
  font-weight: 700;
  letter-spacing: 0.04em;
  padding: 4px 12px;
  background: rgba(245, 197, 66, 0.18);
  border-color: rgba(245, 197, 66, 0.45);
  color: #f5c542;
}

/* v0.2.0: bones pool pulse when the counter ticks up — the user
   reported "not receiving bones for cards that die" because the
   counter was silently updating. The flash makes the change visible.
   Triggered by `.pool-up` class added in board.js renderPlayerColumn
   when app.js's poolUps set contains `bones-${idx}` / `bones-monster`.
   Round 6: stronger flash (brighter, longer, larger scale) so it's
   noticeable on the prominent chip. */
.pool.pool-up {
  animation: pool-up-pulse 900ms ease-out;
}

@keyframes pool-up-pulse {
  0%   { background: rgba(245, 197, 66, 0.85); transform: scale(1.45); box-shadow: 0 0 12px rgba(245, 197, 66, 0.9); }
  40%  { background: rgba(245, 197, 66, 0.65); transform: scale(1.20); box-shadow: 0 0 8px rgba(245, 197, 66, 0.6); }
  100% { background: rgba(245, 197, 66, 0.18); transform: scale(1.00); box-shadow: 0 0 0 rgba(245, 197, 66, 0); }
}

/* v0.2.0: .row-label removed — the row labels (PEEK / MONSTER FRONT /
   YOUR FRONT / SEAT FRONT) were deleted from the JS renderers as part
   of the vertical-space cleanup. The CSS rule is kept for any leftover
   references during the transition but no longer actively styled. */

.card-row {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 96px));
  justify-content: start;
  gap: 6px;
  min-height: 120px;
}

/* Multi-row player board: stacks 3 (or 4) row strips vertically. The
   monster row uses .card-row directly since it's always 1×4. */
.card-grid {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-height: 120px;
}

/* Make back-row cards slightly smaller so the front row dominates the
   visual weight (Inscryption-style depth cue). */
.card-grid .card-row:not(:first-child) .card {
  transform: scale(0.9);
  transform-origin: top center;
}
.card-grid .card-row:not(:first-child) {
  min-height: 96px;
}

.hand {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(72px, 96px));
  justify-content: start;
  gap: 6px;
  min-height: 96px;
}

.hand-empty {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: 'Manrope', sans-serif;
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: rgba(233, 223, 201, 0.4);
  border: 1.5px dashed var(--empty-border);
  border-radius: 6px;
  background: rgba(0, 0, 0, 0.18);
  padding: 12px;
}

/* ---- Card (the mockup) ---- */

.card {
  position: relative;
  border-radius: 6px;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  font-family: 'Manrope', sans-serif;
  /* Card-flip animation (Task 33). Uses 2D rotation so the existing art
     <img> stacks correctly without a 3D wrapper. .flipped is added on
     place, removed after 600ms by board.js animatePlace(). */
  transform: rotateY(0deg);
  transition: transform 0.6s ease;
  will-change: transform;
}

.card.flipped {
  transform: rotateY(180deg);
}

.card--slot {
  width: 100%;
  aspect-ratio: 5 / 7;
  background: rgba(0, 0, 0, 0.18);
  border: 1.5px dashed var(--empty-border);
  border-radius: 7px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.card--slot.occupied {
  /* Filled slots use the face-up filled card styling — they look identical
     to in-hand cards but keep the slot grid width. Keep the same 5:7
     ratio as .card--slot/.card--hand: `aspect-ratio: auto` here broke the
     flex-column height chain (.card-art's `flex: 1` + `img { height:
     100% }` had no definite ancestor height to resolve against), letting
     card art balloon to its native pixel size instead of the grid cell. */
  border: 2px solid var(--card-espresso);
  background: var(--card-stock);
  box-shadow: 0 3px 8px var(--card-shadow);
}

.card--hand {
  background: var(--card-stock);
  border: 2px solid var(--card-espresso);
  box-shadow: 0 3px 8px var(--card-shadow);
  aspect-ratio: 5 / 7;
  /* Explicit width: unlike .card--slot (sized by its grid track), this is
     a flex item in .hand-strip-cards with nothing else to give it a
     definite width, so aspect-ratio + the art <img>'s `height: 100%` had
     nothing to resolve against and it rendered near the art's native
     pixel size.
     v0.2.0: width reduced from 130px to 96px — board cards are also
     96px (`.card-row { grid-template-columns: repeat(4, minmax(0, 96px)) }`),
     and the user wants hand cards to match board cards so the hand row
     is the same height as a board row. Saves significant vertical
     space when the hand strip is at the bottom of the page. */
  width: 96px;
}

.card--reward {
  background: var(--card-stock);
  border: 2px solid var(--card-espresso);
  box-shadow: 0 4px 10px var(--card-shadow);
  aspect-ratio: 5 / 7;
  width: 130px;
}

.card--pool {
  background: var(--card-stock);
  border: 2px solid var(--card-espresso);
  box-shadow: 0 3px 8px var(--card-shadow);
  aspect-ratio: 5 / 7;
  width: 96px;
}

.card.is-clickable {
  cursor: pointer;
  transition: transform 100ms ease, box-shadow 100ms ease;
}

.card.is-clickable:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 12px var(--card-shadow);
}

.card.is-selected {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.card.is-dragging {
  opacity: 0.4;
}

.card--slot.is-drop-target {
  cursor: copy;
}

.card--slot.is-drop-target.drag-over {
  border-color: var(--accent);
  background: rgba(184, 147, 90, 0.18);
  box-shadow: 0 0 0 2px var(--accent) inset;
}

/* A real, empty slot that isn't placeable yet (no-gaps rule: the row in
   front of it isn't filled). Visually distinct from a normal empty slot
   so it doesn't invite a drop that would just get rejected. */
.card--slot.is-blocked-slot {
  opacity: 0.35;
  background: repeating-linear-gradient(
    45deg,
    rgba(0, 0, 0, 0.18),
    rgba(0, 0, 0, 0.18) 6px,
    rgba(0, 0, 0, 0.28) 6px,
    rgba(0, 0, 0, 0.28) 12px
  );
}

/* Attack-lunge animation: the attacker's slot translates to the victim's
   slot and back. --attack-dx/--attack-dy are set inline (in px) by
   app.js's animateOneAttack() from the two slots' actual bounding-rect
   delta, so the lunge lands exactly on the victim regardless of layout.
   The 100% state matches .card's own resting transform (rotateY(0deg) via
   translate(0,0) here) so removing .is-attacking afterward causes no
   snap-back through the base .card transition. */
@keyframes attack-lunge {
  0% { transform: translate(0, 0); }
  35% { transform: translate(var(--attack-dx, 0px), var(--attack-dy, 0px)); }
  60% { transform: translate(var(--attack-dx, 0px), var(--attack-dy, 0px)); }
  100% { transform: translate(0, 0); }
}

.card--slot.is-attacking {
  animation: attack-lunge 600ms ease-in-out;
  z-index: 5;
}

/* Victim feedback at the moment of impact (timed to attack-lunge's 35%
   arrival point by app.js). is-hit for a card that survives, is-hit-killed
   for one that dies — both cleaned up right before the next snapshot
   repaints (or removes) the slot. */
@keyframes hit-flash {
  0%, 100% { filter: none; }
  30% {
    filter: brightness(1.8) saturate(1.4);
    box-shadow: 0 0 0 3px #ff4d4d inset, 0 0 16px 4px rgba(255, 77, 77, 0.7);
  }
}

.card--slot.is-hit {
  animation: hit-flash 400ms ease-out;
}

@keyframes hit-killed {
  0% { transform: scale(1) rotate(0deg); opacity: 1; filter: brightness(1.8); }
  40% { transform: scale(1.1) rotate(-4deg); opacity: 1; filter: brightness(2) saturate(1.6); }
  100% { transform: scale(0.2) rotate(12deg); opacity: 0; }
}

.card--slot.is-hit-killed {
  animation: hit-killed 450ms ease-in forwards;
}

/* An unblocked attack (no defending card in that lane) hits the shared
   HP pool directly — the empty slot itself flashes, since there's no
   card there to flash instead. */
@keyframes direct-hit-flash {
  0%, 100% { box-shadow: none; }
  30% {
    box-shadow: 0 0 0 3px #ff4d4d inset, 0 0 16px 4px rgba(255, 77, 77, 0.7);
    border-color: #c23b3b;
  }
}

.card--slot.is-direct-hit {
  animation: direct-hit-flash 400ms ease-out;
}

/* The monster's peek card sliding forward, down into its monster-front
   slot, on the turn it's actually played — --descend-dx/--descend-dy
   are set inline by app.js's animateOneDescend() from the two slots'
   actual bounding-rect delta. Unlike attack-lunge this doesn't return to
   0,0 — the card is genuinely relocating, not attacking-and-staying —
   so the class is removed right before the next snapshot's real DOM
   swap (same pattern as attack-lunge), leaving no time for .card's own
   transform transition to visibly snap it back. */
@keyframes descend-forward {
  0% { transform: translate(0, 0); }
  100% { transform: translate(var(--descend-dx, 0px), var(--descend-dy, 0px)); }
}

.card--slot.is-descending {
  animation: descend-forward 500ms ease-in;
  z-index: 5;
}

.card-empty-label {
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--empty-label);
}

.card-name {
  padding: 3px 4px;
  background: var(--card-espresso);
  font-family: 'Special Elite', 'Courier New', monospace;
  font-size: 9.5px;
  color: var(--card-cream);
  text-align: center;
  line-height: 1.1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  letter-spacing: 0.02em;
  flex-shrink: 0;
}

.card-art {
  flex: 1;
  min-height: 0;
  overflow: hidden;
  background: var(--card-placeholder);
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
}

.card-art img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  filter: grayscale(0.15) contrast(1.05);
}

.card-art--missing {
  background: var(--card-placeholder);
}

.card-art--missing::after {
  content: 'Art';
  font-family: 'Manrope', sans-serif;
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(28, 23, 18, 0.5);
}

.card-costs {
  position: absolute;
  top: 3px;
  left: 3px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  pointer-events: none;
}

.cost-blood,
.cost-bones {
  display: flex;
  gap: 2px;
}

.cost-blood span,
.cost-bones span {
  width: 9px;
  height: 9px;
  display: block;
  border: 1px solid var(--card-espresso);
}

.cost-blood span {
  background: var(--pip-blood);
  clip-path: polygon(50% 0%, 90% 60%, 50% 100%, 10% 60%);
}

.cost-bones span {
  background: var(--pip-bone);
  border-radius: 2px;
}

.card-sigils {
  position: absolute;
  top: 3px;
  right: 3px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  /* The wrapper itself stays click/hover-through (so the gaps between
     badges don't block the card underneath), but each .sigil badge
     re-enables pointer-events below — otherwise its `title` (the real
     sigil description, fetched from /sigils) can never be hovered at
     all; the mouse always fell through to the card's own tooltip
     instead. Reported: "when i hover a card the sigil description
     doesn't show". */
  pointer-events: none;
  align-items: flex-end;
}

.sigil {
  pointer-events: auto;
  font-family: 'Manrope', sans-serif;
  font-size: 7.5px;
  font-weight: 700;
  letter-spacing: 0.03em;
  background: var(--card-espresso);
  color: var(--card-cream);
  border: 1px solid rgba(233, 223, 201, 0.4);
  border-radius: 8px;
  padding: 1px 5px;
  white-space: nowrap;
}

/* Custom whole-card hover tooltip (static/board.js's _showCardTooltip)
   — a single shared element positioned under the hovered card. Not the
   native `title` attribute: that only showed name/power/toughness, has
   a ~1s hover delay, and — when this info lived on the tiny per-sigil
   badge instead of the card — needed pixel-precise aiming a normal
   hover never landed on ("only seeing the name and attack/HP score").
   Attaching it to the whole card and showing instantly fixes both. */
.sigil-tooltip {
  position: fixed;
  z-index: 40;
  max-width: 240px;
  background: var(--card-espresso);
  color: var(--card-cream);
  border: 1.5px solid var(--accent);
  border-radius: 6px;
  padding: 6px 10px;
  font-family: 'Manrope', sans-serif;
  font-size: 11px;
  line-height: 1.4;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.5);
  display: flex;
  flex-direction: column;
  gap: 4px;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 80ms ease-out;
}

.sigil-tooltip.is-visible {
  opacity: 1;
  visibility: visible;
}

.sigil-tooltip > strong {
  color: var(--card-cream);
  font-size: 11px;
  letter-spacing: 0.03em;
}

.sigil-tooltip-row {
  display: block;
  padding-top: 2px;
  border-top: 1px solid rgba(233, 223, 201, 0.2);
}

.sigil-tooltip-row b {
  color: var(--accent);
}

.card-stat {
  position: absolute;
  bottom: 2px;
  min-width: 16px;
  height: 16px;
  padding: 0 2px;
  border-radius: 50%;
  background: var(--card-cream);
  border: 1.5px solid var(--card-espresso);
  color: var(--card-espresso);
  font-family: 'Manrope', sans-serif;
  font-size: 9px;
  font-weight: 800;
  display: flex;
  align-items: center;
  justify-content: center;
}

.card-power { left: 2px; }
.card-toughness { right: 2px; }

/* A board card's toughness pip once it's taken damage and survived —
   otherwise a hit that doesn't kill has no visible trace at all beyond
   the attack animation's brief flash. */
.card-toughness.is-damaged {
  background: #ffe0e0;
  border-color: #c23b3b;
  color: #8a1f1f;
}

/* Face-down state — when a card is in the monster's hand/deck and revealed
   only as a striped back. Currently unused (all cards face up) but kept
   for the future "hidden monster hand" feature. */
.card--facedown {
  width: 100%;
  height: 100%;
  border-radius: 6px;
  background: repeating-linear-gradient(
    45deg,
    var(--face-down-1) 0,
    var(--face-down-1) 5px,
    var(--face-down-2) 5px,
    var(--face-down-2) 10px
  );
  border: 2px solid var(--card-espresso);
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.5) inset;
  display: flex;
  align-items: center;
  justify-content: center;
}

.card--facedown::after {
  content: '';
  width: 55%;
  height: 65%;
  border: 1px solid rgba(120, 160, 120, 0.35);
  border-radius: 4px;
}

/* ---- Bottom strip: turn order, hands, decks ---- */

.run-bottom {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: 12px;
  align-items: stretch;
  margin-top: 16px;
  padding: 12px;
  background: var(--card-espresso);
  border: 1.5px solid var(--card-espresso);
  border-radius: 8px;
  box-shadow: 0 3px 10px rgba(0, 0, 0, 0.4);
  min-height: 140px;
}

.run-bottom-left {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 4px 8px;
}

.turn-order {
  display: flex;
  flex-direction: column;
  gap: 4px;
  align-items: center;
}

.turn-avatar {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: rgba(233, 223, 201, 0.1);
  border: 1.5px solid var(--card-cream);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 0.04em;
  color: var(--card-cream);
}

.turn-avatar.is-active {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--card-espresso);
}

.turn-avatar.is-clickable {
  cursor: pointer;
}

/* Whose hand the strip below currently shows — independent of whose
   turn it is (.is-active), since you can look at a teammate's hand
   without it being their turn. */
.turn-avatar.is-viewed {
  box-shadow: 0 0 0 2px var(--card-cream);
}

.hand-strip {
  display: flex;
  gap: 6px;
  align-items: center;
  overflow-x: auto;
}

.hand-strip-cards {
  display: flex;
  gap: 4px;
}

.decks {
  display: flex;
  gap: 8px;
  align-items: stretch;
}

.deck {
  width: 80px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
}

.deck-art {
  width: 70px;
  height: 96px;
  border: 2px solid var(--card-espresso);
  border-radius: 4px;
  background:
    repeating-linear-gradient(
      45deg,
      #1c2820 0px,
      #1c2820 5px,
      #14201a 5px,
      #14201a 10px
    );
}

.deck--side .deck-art {
  background:
    repeating-linear-gradient(
      45deg,
      #2a2238 0px,
      #2a2238 5px,
      #211b2e 5px,
      #211b2e 10px
    );
}

.deck-label {
  font-family: 'Manrope', sans-serif;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.06em;
  color: var(--card-cream);
  text-align: center;
}

.deck-count {
  color: var(--accent);
}

.deck.is-clickable {
  cursor: pointer;
  transition: transform 100ms ease;
}

.deck.is-clickable:hover .deck-art {
  border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--accent);
  transform: translateY(-2px);
}

.deck:not(.is-clickable) .deck-art {
  opacity: 0.4;
}

.deck.is-empty-deck .deck-art {
  opacity: 0.2;
}

/* ---- Action panel ---- */

.action-panel {
  display: flex;
  gap: 6px;
  margin-top: 16px;
  padding: 10px 12px;
  background: var(--card-espresso);
  border-radius: 8px;
  border: 1.5px solid var(--card-espresso);
  box-shadow: 0 3px 10px rgba(0, 0, 0, 0.4);
}

.action-button {
  background: rgba(233, 223, 201, 0.06);
  color: var(--card-cream);
  border: 1px solid rgba(233, 223, 201, 0.25);
  border-radius: 6px;
  padding: 6px 12px;
  font-family: 'Manrope', sans-serif;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background 100ms ease;
}

.action-button:hover {
  background: rgba(233, 223, 201, 0.14);
}

.action-button.is-selected {
  background: var(--accent);
  color: var(--card-espresso);
  border-color: var(--accent);
}

.action-button:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}

.action-button:disabled:hover {
  background: rgba(233, 223, 201, 0.06);
}

/* v0.2.0: inline variant of .action-button — used in the topbar
   middle (renderHeader appends Trade / End Turn next to the pip-bar).
   Slightly tighter padding so the buttons fit next to the HP readout
   without forcing the topbar to grow. */
.action-button--inline {
  padding: 4px 10px;
  font-size: 11px;
}

/* ---- Reward picker (overlaid on the run screen) ---- */

.reward-picker {
  background: var(--card-espresso);
  border: 1.5px solid var(--accent);
  color: var(--card-cream);
  padding: 18px;
  margin-top: 16px;
  border-radius: 8px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.5);
}

.reward-picker h3 {
  font-family: 'Cinzel', serif;
  font-size: 16px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 0 0 12px;
}

.reward-picker .chosen-pool {
  gap: 12px;
  justify-content: center;
}

/* ---- Trade / Donate + Sacrifice-to-pay modals ---- */

.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(8, 6, 4, 0.72);
  z-index: 30;
  display: flex;
  align-items: center;
  justify-content: center;
}

.modal-box {
  width: 320px;
  max-width: 90vw;
  max-height: 80vh;
  overflow-y: auto;
  background: var(--card-espresso);
  border: 1.5px solid var(--accent);
  border-radius: 10px;
  padding: 18px;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.6);
  color: var(--card-cream);
  font-family: 'Manrope', sans-serif;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.modal-box h3 {
  font-family: 'Cinzel', serif;
  font-size: 15px;
  font-weight: 700;
  color: var(--accent);
  margin: 0 0 4px;
}

.modal-tabs {
  display: flex;
  gap: 6px;
}

.modal-tab {
  flex: 1;
  text-align: center;
  padding: 6px 4px;
  border-radius: 5px;
  cursor: pointer;
  background: transparent;
  border: 1px solid rgba(233, 223, 201, 0.25);
  font-size: 11px;
  font-weight: 600;
  color: var(--card-cream);
}

.modal-tab.is-selected {
  background: rgba(184, 147, 90, 0.22);
  border-color: var(--accent);
  color: var(--accent);
}

.modal-box select,
.modal-box input[type="number"] {
  width: 100%;
  background: rgba(0, 0, 0, 0.3);
  border: 1px solid rgba(184, 147, 90, 0.3);
  color: var(--card-cream);
  font-size: 12px;
  padding: 6px 8px;
  border-radius: 5px;
  box-sizing: border-box;
  font-family: inherit;
}

.modal-box button {
  background: transparent;
  border: 1px solid rgba(184, 147, 90, 0.4);
  color: var(--card-cream);
  font-family: 'Manrope', sans-serif;
  font-weight: 600;
  font-size: 12px;
  padding: 8px;
  border-radius: 5px;
  cursor: pointer;
}

.modal-box button:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

.modal-box button:not(:disabled):hover {
  border-color: var(--accent);
  color: var(--accent);
}