.choice-modal {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: grid;
  place-items: center;
  padding: 24px;
  background: rgba(5, 7, 10, .82);
  backdrop-filter: blur(5px);
}

.choice-panel {
  max-width: min(920px, 100%);
  padding: 22px;
  border: 1px solid var(--gold);
  border-radius: 18px;
  background: var(--lead);
  box-shadow: 0 18px 70px rgba(0, 0, 0, .75), 0 0 24px rgba(212, 161, 58, .18);
}

.choice-title {
  margin: 0 0 18px;
  color: var(--amber);
  text-align: center;
}

.choice-cards {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 18px;
}

.choice-card {
  padding: 0;
  border: 2px solid transparent;
  border-radius: 14px;
  background: transparent;
  color: inherit;
  cursor: pointer;
}

.choice-card:hover,
.choice-card:focus-visible {
  border-color: var(--amber);
  outline: 3px solid rgba(212, 161, 58, .35);
  outline-offset: 3px;
  transform: translateY(-4px);
}

.choice-slot-name {
  padding: 6px 4px 2px;
  color: var(--amber);
  font-size: 12px;
  font-weight: 700;
  text-align: center;
}

@media (max-width: 640px) {
  .choice-modal { padding: 10px; }
  .choice-panel { max-height: calc(100dvh - 20px); padding: 14px; overflow: auto; }
  .choice-cards { flex-wrap: nowrap; justify-content: flex-start; overflow-x: auto; padding: 4px 4px 12px; }
  .choice-card { flex: 0 0 auto; transform: scale(.82); transform-origin: top center; margin: 0 -14px -42px; }
  .choice-card:hover,
  .choice-card:focus-visible { transform: scale(.82) translateY(-4px); }
}
* { box-sizing: border-box; }

/* Layout skeleton (unchanged mechanics): #left-rail/#app/#right-rail are
   real flex siblings; #app claims up to 960px, rails split the rest and
   clip their own overflow on narrow windows. The game reads in one glance,
   never scrolls. */
html, body { height: 100%; overflow: hidden; }
body {
  margin: 0;
  min-height: 100vh;
  font-family: var(--font-body);
  font-weight: 600;
  color: var(--ink);
  /* board art under a LIGHT vignette + faint pools of colored light — the
     stone floor must read as a lit room (reference board), not a black pit;
     the heavy .93-alpha vignette was drowning the whole table */
  background:
    radial-gradient(560px 360px at 12% 6%, rgba(194,57,79,.10), transparent 70%),
    radial-gradient(620px 400px at 88% 10%, rgba(59,107,176,.09), transparent 70%),
    radial-gradient(ellipse at 50% 38%, rgba(8,12,16,.16) 0%, rgba(6,9,12,.32) 60%, rgba(3,5,8,.58) 100%),
    url("../assets/board-bg.webp") center / cover no-repeat fixed,
    radial-gradient(circle at 50% 40%, var(--felt), var(--felt-2));
  display: flex;
}

/* The board backdrop paints the instant this stylesheet parses, but the landing
   screen only mounts once main.js (the last script) runs — so board-bg.webp
   flashed for a frame on every refresh. index.html ships <body class="on-landing">
   so the flat colour wins from the very first paint; main.js drops the class the
   moment the player leaves the landing screen. */
body.on-landing {
  background: #0d1018;
}

/* Step 2 migration seam: empty until the existing battle nodes move here. */
.battle-safe-frame {
  position: fixed;
  top: env(safe-area-inset-top);
  right: env(safe-area-inset-right);
  bottom: env(safe-area-inset-bottom);
  left: env(safe-area-inset-left);
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}
.battle-transform {
  position: absolute;
  top: 0;
  left: 0;
  width: 904px;
  height: 407px;
  transform-origin: top left;
}
.battle-canvas,
.battle-overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 904px;
  height: 407px;
}
.battle-overlay { overflow: hidden; }
body.canvas-mode .battle-transform { outline: 1px dashed rgba(235,187,84,.5); }

/* No padding on the rails (border-box padding sets a hard min width even at
   0% basis) — spacing lives on the children so a rail can shrink to 0. */
#left-rail, #right-rail {
  flex: 1 1 0%; min-width: 0; overflow: hidden; position: relative;
  display: flex; flex-direction: column;
}
#left-rail { justify-content: flex-start; }  /* Herald (announcements): from the top */
#right-rail { justify-content: flex-end; }   /* Chronicle: pinned to the bottom */
/* The tile feed IS the chronicle on every viewport (user, 2026-07-14: one
   composition, no responsive variants). The parchment #log-panel is retired. */
body.playing #log-panel { display: none; }
body.playing #chronicle-feed {
  display: flex; flex-direction: column; align-items: flex-start; gap: 4px;
  width: 150px; max-height: 100%; margin: 4px 0 0 4px;
  overflow-y: auto; pointer-events: none; scrollbar-width: thin;
}
#chronicle-feed { display: none; }
.chron-tile {
  width: 44px; height: 44px; flex: 0 0 44px; position: relative;
  border: 2px solid var(--gold); border-radius: 10px; background-position: center;
  background-size: cover; box-shadow: 0 2px 6px rgba(0,0,0,.7); pointer-events: auto;
}
.chron-tile.side-0 { border-color: #8fc6da; }
.chron-tile.side-1 { border-color: #e28a64; }
.chron-tile.tone-damage { border-color: #c34a36; }
.chron-tile.tone-heal { border-color: #5faf6b; }
.chron-tile.tone-death { border-color: #77624b; }
.chron-tile-icon {
  position: absolute; right: -3px; bottom: -3px; width: 16px; height: 16px;
  display: grid; place-items: center; border-radius: 50%; color: var(--gold-bright);
  background: rgba(10,13,18,.92); border: 1px solid var(--gold); font-size: .62rem;
}
.chron-chip {
  max-width: 142px; min-height: 20px; padding: 2px 6px; display: flex; align-items: center;
  gap: 4px; overflow: hidden; white-space: nowrap; border-radius: 999px;
  color: var(--bone); background: rgba(14,18,24,.9); border: 1px solid rgba(205,174,101,.45);
  font-size: .64rem; line-height: 1; pointer-events: none;
}
.chron-chip .chron-impact { overflow: hidden; text-overflow: ellipsis; }
.chron-divider { align-self: stretch; justify-content: center; color: var(--gold-bright); font-family: var(--font-display); }
/* chronicle entries are click-to-reveal (user, 2026-07-14) — re-enable pointer
   events (the rail + chips are otherwise pointer-events:none) and mark them
   interactive; turn dividers stay inert. */
.chron-tile, .chron-chip { pointer-events: auto; cursor: pointer; }
.chron-divider { pointer-events: none; cursor: default; }
.chron-tile:focus-visible, .chron-chip:focus-visible { outline: 2px solid var(--gold-bright); outline-offset: 2px; }
/* the chronicle's click-to-view detail reuses the announcement's full-screen
   inspect overlay (.announce-inspect / .announce-move) so it's the exact same
   full card view; a small text line is appended only when there's no card. */
.announce-inspect .chron-line { margin-top: 12px; display: flex; flex-wrap: wrap; align-items: center;
  justify-content: center; gap: 6px; font-family: var(--font-chrome); font-size: .9rem; color: var(--bone); }
.announce-inspect .chron-impact { color: var(--gold-bright); font-weight: 700; }
#app {
  flex: 0 1 960px; padding: 10px; align-self: flex-start;
  display: flex; flex-direction: column; gap: 8px; transform-origin: top center;
}

/* ---- In-game "stage": a fixed-width board CENTERED and scaled up/down to
   fill the viewport (a fixed-resolution game fit-to-window), so it never sits
   as a small column in a sea of empty space on large screens. The Chronicle
   and announcement panels become viewport-edge overlays. Menus (mode/class/
   deck-builder) keep the plain flex layout — only body.playing is a stage. */
body.playing { display: block; }
/* Adventure regions retain the stage's vignette/light pools; regional art
   replaces only its stone layer, with the original board retained as fallback. */
body.board-lava {
  background: radial-gradient(560px 360px at 12% 6%, rgba(194,57,79,.10), transparent 70%), radial-gradient(620px 400px at 88% 10%, rgba(59,107,176,.09), transparent 70%), radial-gradient(ellipse at 50% 38%, rgba(8,12,16,.16) 0%, rgba(6,9,12,.32) 60%, rgba(3,5,8,.58) 100%), url("../assets/boards/board_lava.webp") center / cover no-repeat fixed, url("../assets/board-bg.webp") center / cover no-repeat fixed, radial-gradient(circle at 50% 40%, var(--felt), var(--felt-2));
}
body.board-snow {
  background: radial-gradient(560px 360px at 12% 6%, rgba(194,57,79,.10), transparent 70%), radial-gradient(620px 400px at 88% 10%, rgba(59,107,176,.09), transparent 70%), radial-gradient(ellipse at 50% 38%, rgba(8,12,16,.16) 0%, rgba(6,9,12,.32) 60%, rgba(3,5,8,.58) 100%), url("../assets/boards/board_snow.webp") center / cover no-repeat fixed, url("../assets/board-bg.webp") center / cover no-repeat fixed, radial-gradient(circle at 50% 40%, var(--felt), var(--felt-2));
}
body.board-desert {
  background: radial-gradient(560px 360px at 12% 6%, rgba(194,57,79,.10), transparent 70%), radial-gradient(620px 400px at 88% 10%, rgba(59,107,176,.09), transparent 70%), radial-gradient(ellipse at 50% 38%, rgba(8,12,16,.16) 0%, rgba(6,9,12,.32) 60%, rgba(3,5,8,.58) 100%), url("../assets/boards/board_desert.webp") center / cover no-repeat fixed, url("../assets/board-bg.webp") center / cover no-repeat fixed, radial-gradient(circle at 50% 40%, var(--felt), var(--felt-2));
}
/* A single fixed veil sits beneath the stage and never participates in input. */
body.playing.board-lava::before,
body.playing.board-snow::before,
body.playing.board-desert::before {
  content: ''; position: fixed; inset: 0; z-index: 0; pointer-events: none; opacity: .24; background-repeat: repeat;
}
body.playing.board-lava::before {
  background-image: radial-gradient(ellipse at 20% 70%, rgba(255,104,35,.8) 0 1px, transparent 3px), radial-gradient(ellipse at 70% 35%, rgba(255,178,77,.6) 0 1px, transparent 4px), linear-gradient(115deg, transparent 30%, rgba(255,72,22,.16) 50%, transparent 70%);
  background-size: 180px 130px, 250px 190px, 180% 180%; animation: board-lava-shimmer 14s ease-in-out infinite alternate;
}
body.playing.board-snow::before {
  background-image: radial-gradient(circle, rgba(245,251,255,.95) 0 1px, transparent 2px), radial-gradient(circle, rgba(205,228,255,.8) 0 2px, transparent 3px);
  background-size: 110px 110px, 180px 180px; animation: board-snow-drift 18s linear infinite;
}
body.playing.board-desert::before {
  background-image: linear-gradient(105deg, transparent 42%, rgba(245,190,106,.42) 49%, transparent 56%), linear-gradient(105deg, transparent 28%, rgba(201,137,64,.24) 38%, transparent 48%);
  background-size: 230px 150px, 360px 220px; animation: board-desert-drift 16s linear infinite;
}
@keyframes board-lava-shimmer { to { background-position: 60px -45px, -75px 55px, 100% 0; } }
@keyframes board-snow-drift { to { background-position: 95px 160px, -70px 220px; } }
@keyframes board-desert-drift { to { background-position: 300px -100px, 430px -150px; } }
body.playing #app {
  position: absolute; top: 54%; left: 50%;
  /* fill the viewport WIDTH: with a fixed narrow width, a height-limited
     scale left big side margins. A wide box scaled to fit height still fills
     the width. Anchored slightly below centre so the top opponent medallion
     has clearance. */
  flex: none; width: min(94vw, 1600px); padding: 0; align-self: auto; gap: 10px;
  align-items: center; /* centre the medallions/hand over the full-width board */
  transform: translate(-50%, -50%) scale(var(--fit, 1));
  transform-origin: center center;
  z-index: 1;
}
/* on the stage the play rows are just the stone floor — no empty bordered
   box. Only the ACTING side's row lights with a rune glow. */
body.playing .board { background: none; border-color: transparent; box-shadow: none; }
/* no acting-side "pool" on the stage either (user call: the bordered glow
   read as a shadowy puddle under one row) — the active hero's lit medallion
   carries the whose-turn signal */
body.playing .board.active-side { animation: none; box-shadow: none; border-color: transparent; background: none; }
body.playing #left-rail {
  /* the Herald (card announcements) flows from the TOP-left, clear of the
     bottom-left hero block; the Chronicle lives bottom-right */
  position: fixed; left: 0; top: 12px; bottom: auto; transform: none;
  width: auto; max-width: 330px; z-index: 15; height: auto; justify-content: flex-start;
}
/* fixed HEIGHT (not just a cap): early-game the panel shrank to two lines and
   wasted its column. clamp() keeps a solid minimum so the scroll can never
   collapse to ~0 on a short window — the old calc(100vh - 600px) went to zero
   (or negative) under a real browser's chrome, making the log invisible. */
body.playing #log-panel { height: clamp(160px, 30vh, 300px); max-height: none; max-width: 310px; }
body.playing #log-panel .log-scroll { flex: 1; }
/* hero medallions as corner overlays (reference layout): opponent top-centre
   (compact — just the medallion + mana), you bottom-left (full). Sized to read
   clearly without dominating the board or colliding with the Chronicle. */
.hero-overlay { position: fixed; z-index: 16; }
.hero-overlay.foe { top: 8px; left: 50%; transform: translateX(-50%); transform-origin: top center; }
.hero-overlay.foe .hero-name,
.hero-overlay.foe .equipment-row,
.hero-overlay.foe .aura-line,
.hero-overlay.foe .hero-counts { display: none; }
.hero-overlay.me { left: 10px; bottom: 8px; transform: scale(1.05); transform-origin: bottom left; }
body.playing #right-rail {
  /* Chronicle corner: pinned bottom-right, under the End Turn mirror */
  position: fixed; right: 0; bottom: 6px; top: auto; width: auto; max-width: 340px;
  z-index: 15; height: auto; justify-content: flex-end;
}
/* board rows span the full stage width so minions read large and centered */
body.playing .board { width: 100%; }

/* ------------------------------------------------------------ hero plates:
   lead pills in the same three-finish frame language. The acting player's
   plate is LIT. Frame = transparent border + dual background (lead fill in
   the padding box, metal conic in the border box). */
/* Hero = a circular avatar MEDALLION (board redesign reference): portrait
   ring, HP badge, weapon-attack pip and hero-power orb anchored on it, with
   name + crystal-pip mana + gear below. */
.hero {
  /* two side-by-side groups: CORE (medallion+name+mana) and GEAR
     (equipment+auras+counts) — see heroEl in view.js */
  display: flex; flex-direction: row; align-items: flex-end; gap: 14px;
  cursor: pointer; padding: 2px; width: max-content;
}
.hero-core, .hero-gear { display: flex; flex-direction: column; align-items: center; gap: 5px; }
.hero-gear { padding-bottom: 2px; }
/* the foe overlay shows only the core (its gear children are hidden) —
   keep it a single centered column */
.hero-overlay.foe .hero { flex-direction: column; align-items: center; gap: 5px; }
.hero-medallion { position: relative; width: 84px; height: 84px; }
.hero-portrait {
  width: 84px; height: 84px; border-radius: 50%;
  background-size: cover; background-position: center top; background-color: var(--card-bg);
  box-shadow: 0 0 0 3px var(--gold), 0 0 0 5px #08090c, 0 4px 14px rgba(0,0,0,.6);
}
/* Side identity: your hero keeps the warm gold ring; the opponent's is a cool
   steel ring so "which hero is mine" reads without checking position. (Placed
   before the active/selected rules so an active hero still gets the gold glow.) */
.hero-overlay.foe .hero-portrait {
  box-shadow: 0 0 0 3px #9aa3ad, 0 0 0 5px #08090c, 0 4px 14px rgba(0,0,0,.6);
}
.hero.active-hero .hero-portrait,
.hero.can-strike .hero-portrait {
  box-shadow: 0 0 0 3px var(--gold-bright), 0 0 0 5px #08090c, 0 0 24px rgba(255,181,71,.55), 0 4px 14px rgba(0,0,0,.6);
}
.hero.can-strike .hero-portrait { animation: candle-halo 1.6s var(--ease-in-out) infinite alternate; }
.hero.selected .hero-portrait {
  box-shadow: 0 0 0 3px var(--gold-bright), 0 0 0 6px #08090c, 0 0 30px rgba(255,181,71,.75), 0 4px 14px rgba(0,0,0,.6);
}
.hero-name {
  font-family: var(--font-display); font-size: 1.05rem; letter-spacing: .05em;
  color: var(--gold-bright); text-shadow: 0 1px 3px rgba(0,0,0,.85);
}
/* HP badge — ruby lozenge at the medallion's foot */
.hero-health {
  position: absolute; bottom: -7px; left: 50%; transform: translateX(-50%); z-index: 4;
  min-width: 34px; height: 30px; padding: 0 8px; border-radius: 999px;
  display: grid; grid-auto-flow: column; align-items: center; justify-content: center; gap: 2px;
  font-family: var(--font-display); font-size: 1.15rem; line-height: 1; text-align: center; color: #fff;
  background: radial-gradient(circle at 40% 28%, var(--ruby-hi), var(--ruby) 60%, var(--ruby-lo));
  box-shadow: 0 0 0 2px #3a0a12, 0 2px 6px rgba(0,0,0,.65), inset 0 2px 4px rgba(255,255,255,.35);
}
/* the ruby lozenge already reads as health — the "HP" prefix just cluttered
   a small badge, so the number stands alone (Hearthstone-style). */
.hero-armor { font-size: .72rem; color: #cfe0ff; }

/* crystal-pip mana: diamonds, lit up to current mana */
.mana-pips { display: flex; align-items: center; gap: 3px; flex-wrap: wrap; justify-content: center; max-width: 150px; }
.mana-pip {
  width: 11px; height: 11px; transform: rotate(45deg); border-radius: 2px;
  background: linear-gradient(135deg, #1b2740, #0b1220); border: 1px solid #33436b;
}
.mana-pip.filled {
  background: radial-gradient(circle at 38% 30%, var(--lapis-hi), var(--lapis) 60%, var(--lapis-lo));
  border-color: var(--lapis-hi); box-shadow: 0 0 6px rgba(90,150,240,.75);
}
.mana-count {
  font-family: var(--font-display); font-size: .95rem; color: #aac9f4; margin-left: 4px;
  text-shadow: 0 0 8px rgba(47,102,196,.6), 0 1px 2px rgba(0,0,0,.9);
}
.hero-counts { display: flex; align-items: center; gap: 8px; font-size: .72rem; color: #c9c1aa; }

.turn-banner {
  font-family: var(--font-display); font-size: 1.15rem; letter-spacing: .1em;
  color: var(--gold-bright); text-align: center; text-shadow: 0 1px 4px rgba(0,0,0,.85);
}

.board {
  min-height: 120px; display: flex; gap: 8px; justify-content: center;
  align-items: center; padding: 8px;
  /* a light wash so the stone floor shows through — an empty row reads as the
     board, not a black box */
  background: rgba(6,9,14,.24);
  border: 1px solid rgba(227,180,94,.16); border-radius: 12px;
  box-shadow: inset 0 2px 16px rgba(0,0,0,.4);
  transition: border-color .6s var(--ease-in-out), box-shadow .6s var(--ease-in-out);
}
/* the acting side's recess glows with candlelight, breathing slowly */
@keyframes rune-pulse {
  from { box-shadow: inset 0 2px 12px rgba(0,0,0,.5), 0 0 14px rgba(255,181,71,.08), inset 0 0 20px rgba(255,181,71,.04); }
  to   { box-shadow: inset 0 2px 12px rgba(0,0,0,.5), 0 0 24px rgba(255,181,71,.22), inset 0 0 28px rgba(255,181,71,.08); }
}
.board.active-side {
  border-color: rgba(255,181,71,.4);
  animation: rune-pulse 4s var(--ease-in-out) infinite alternate;
}

/* ------------------------------------------------------------------ cards
   & minions: glass panels in the faceted frame. The frame finish IS the
   state; nothing else needs decoding. */
.minion {
  width: 134px; height: 178px;
  border: 5px solid transparent; border-radius: 30px 30px 8px 8px;
  /* frame color: --sframe (playable/spent state) wins, else the default gilt.
     One border, recolored — no overlay. */
  background: linear-gradient(var(--lead), var(--lead)) padding-box, var(--sframe, var(--gilt-dark)) border-box;
  position: relative;
  box-shadow: 0 0 0 1px #08090c, 0 5px 14px rgba(0,0,0,.55);
  display: flex; flex-direction: column; align-items: center; justify-content: flex-end; text-align: center;
  padding: 4px; font-size: .82rem;
  cursor: pointer; transition: transform .28s var(--ease-out), box-shadow .28s var(--ease-out);
}
/* the art fills the whole tile behind the badges/name (breathing layer) */
.minion-art {
  position: absolute; inset: 0; z-index: 0;
  background-size: cover; background-position: center;
  border-radius: inherit;
  filter: brightness(.98) saturate(1);
  animation: art-breathe 7s var(--ease-in-out) infinite alternate;
  animation-delay: var(--breathe-delay, 0s);
}
/* LIT — can attack: bright gilt, candle halo, the glass glows */
@keyframes candle-halo {
  from { box-shadow: 0 0 0 1px #3a2c0e, 0 0 16px rgba(255,181,71,.35), 0 5px 14px rgba(0,0,0,.55); }
  to   { box-shadow: 0 0 0 1px #3a2c0e, 0 0 30px rgba(255,181,71,.6), 0 5px 14px rgba(0,0,0,.55); }
}
.minion.can-attack {
  --sframe: var(--gilt-lit);
  animation: candle-halo 1.6s var(--ease-in-out) infinite alternate;
}
.minion.can-attack .minion-art { filter: brightness(1.05) saturate(1.15); }
/* SMOKED — spent: pewter frame, ashen glass */
.minion.spent {
  --sframe: var(--gilt-smoked);
}
.minion.spent .minion-art { filter: grayscale(.75) brightness(.62); }
.minion.spent .minion-name { color: #7d7a70; }

/* FROZEN — cannot attack this turn: an icy rime over the glass */
.minion.frozen .minion-art { filter: brightness(.9) saturate(.7) hue-rotate(170deg); }
.minion.frozen::after {
  content: ''; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  background: linear-gradient(150deg, rgba(150,205,255,.32), rgba(90,150,220,.12) 55%, rgba(150,205,255,.28));
  box-shadow: inset 0 0 14px rgba(170,215,255,.55); z-index: 3;
}
/* SILENCED — text/keywords stripped: a slate seal and crossed-speech marker.
   The frame/tint stay neutral so this cannot be mistaken for the frozen rime. */
.minion.silenced {
  --sframe: var(--ash);
  box-shadow: 0 0 0 1px var(--came), 0 0 0 3px rgba(167,173,160,.5), 0 5px 14px rgba(0,0,0,.55);
}
.minion.silenced .minion-art { filter: grayscale(.72) contrast(.82) brightness(.78); }
.minion.silenced::before {
  content: ''; position: absolute; inset: 4px; border-radius: 25px 25px 4px 4px; pointer-events: none; z-index: 2;
  background: repeating-linear-gradient(135deg, rgba(167,173,160,.18) 0 2px, transparent 2px 7px);
  box-shadow: inset 0 0 0 1px rgba(34,36,43,.8);
}
.minion.silenced .attr-row, .minion.silenced .attr-badge { opacity: .25; }
.silence-indicator {
  position: absolute; top: 7px; left: 7px; z-index: 5;
  width: 22px; height: 22px; border-radius: 50%;
  display: grid; place-items: center;
  color: var(--ash); background: var(--lead); border: 1px solid var(--ash);
  box-shadow: 0 1px 4px rgba(0,0,0,.8), inset 0 1px rgba(255,255,255,.12);
  font: .78rem/1 "Segoe UI Symbol", "Noto Sans Symbols 2", sans-serif;
}

/* PROVOKE — must be attacked first: a pulsing steel bulwark ring around the
   minion so "these block for me" is unmistakable. A pseudo-element ring
   (not box-shadow) so it coexists with the can-attack halo animation. */
@keyframes provoke-pulse { from { opacity: .55; } to { opacity: 1; } }
.board .minion.provoke::before {
  content: ''; position: absolute; inset: -5px; border-radius: 14px; pointer-events: none; z-index: 2;
  border: 3px solid #94a7bd;
  box-shadow: 0 0 12px rgba(148,167,189,.6), inset 0 0 9px rgba(148,167,189,.4);
  animation: provoke-pulse 1.3s var(--ease-in-out) infinite alternate;
}

/* a live (unbroken) Ward stays a breathing bubble of light */
.minion.shielded { box-shadow: 0 0 0 1px #08090c, 0 0 0 2px rgba(232,236,242,.35), 0 5px 14px rgba(0,0,0,.55); }
.shield-dome {
  position: absolute; inset: -3px; border-radius: inherit;
  pointer-events: none; z-index: 1;
  border: 2px solid rgba(232,236,242,.75);
  background: linear-gradient(115deg,
    transparent 32%, rgba(232,236,242,.38) 48%, rgba(255,255,255,.55) 50%,
    rgba(232,236,242,.38) 52%, transparent 68%);
  background-size: 260% 260%;
  animation: shield-sheen 2.6s linear infinite,
             shield-pulse 2.2s var(--ease-in-out) infinite alternate;
}
@keyframes shield-sheen { from { background-position: 130% 0; } to { background-position: -130% 0; } }
@keyframes shield-pulse {
  from { box-shadow: 0 0 6px rgba(232,236,242,.35), inset 0 0 8px rgba(232,236,242,.2); }
  to   { box-shadow: 0 0 20px rgba(232,236,242,.75), inset 0 0 14px rgba(232,236,242,.4); }
}
/* margin-bottom is load-bearing: without it the name's last line sits in
   the band the atk/hp gems intrude into (measured: 5px overlap at 8px;
   grew to 18px when the gems went 28→32px). */
.minion-name {
  font-family: var(--font-display); font-size: .78rem; letter-spacing: .02em;
  margin-bottom: 18px; color: #efe8d3;
  width: 100%; padding: 2px 3px; border-radius: 3px;
  background: rgba(8,9,12,.72);
  text-shadow: 0 1px 2px rgba(0,0,0,.9);
  position: relative; z-index: 1;
}

/* Board stat orbs occupy the lower corners; reserve their full horizontal
   band so a name never disappears beneath either orb. */
.board .minion .minion-name { width: calc(100% - 42px); margin-bottom: 21px; }

/* --------------------------------------------------------- attributes:
   identical gold cabochons, dark glyph inlay — the glyph is the ONLY
   differentiator. Element crowns the arch apex (absolute, top-center);
   keywords sit in a row under the art. */
.attr-badge {
  width: 24px; height: 24px; border-radius: 50%; flex-shrink: 0;
  display: grid; place-items: center; font-size: .8rem; line-height: 1;
  /* glyphs include alchemical symbols (U+1F70x) — pin fonts that actually
     cover them so Linux/older configs don't render tofu boxes */
  font-family: "Segoe UI Symbol", "Noto Sans Symbols 2", "Noto Sans Symbols", "Segoe UI", sans-serif;
  color: #3a2a08;
  background: radial-gradient(circle at 36% 30%, var(--gold-bright), var(--gold) 55%, #7a5716);
  box-shadow: 0 0 0 2px var(--came), 0 0 0 3px #3a2c0e,
              inset 0 1px 2px rgba(255,255,255,.55), inset 0 -2px 3px rgba(0,0,0,.3),
              0 2px 5px rgba(0,0,0,.6);
  text-shadow: 0 1px 0 rgba(255,246,214,.4);
}
.attr-row {
  display: flex; gap: 5px; justify-content: center; flex-wrap: wrap;
  margin: 5px 0; position: relative; z-index: 1;
}
.board .minion .attr-row { margin: 0 0 3px; }

/* Live statuses use compact charcoal chips rather than the permanent keyword
   cabochons. The row stays within the token frame at every board scale. */
.status-row {
  display: flex; justify-content: center; align-items: center; gap: 3px;
  flex-wrap: wrap; max-width: calc(100% - 8px); margin: 1px auto 3px;
  position: relative; z-index: 4; pointer-events: auto;
}
.status-chip {
  min-width: 16px; height: 16px; padding: 0 2px; border-radius: 5px;
  display: inline-flex; align-items: center; justify-content: center; gap: 1px;
  color: #e8ddc7; background: linear-gradient(145deg, #303640, #11151b);
  border: 1px solid #76808d; box-shadow: inset 0 1px rgba(255,255,255,.16), 0 1px 2px rgba(0,0,0,.7);
  font: .64rem/1 "Segoe UI Symbol", "Noto Sans Symbols 2", "Noto Sans Symbols", "Segoe UI", sans-serif;
}
.status-turns { color: var(--gold-bright); font: 700 .52rem/1 var(--font-body); }
.hero-core > .status-row { width: max-content; max-width: 104px; margin-top: -3px; }

/* Persistent hero interceptors also stain the medallion ring, keeping the
   armed defense readable even when the small chips are not inspected. */
.hero-medallion[class*="status-ring-"] .hero-portrait { box-shadow: 0 0 0 3px #78828d, 0 0 12px rgba(166,181,198,.65); }
.hero-medallion.status-ring-fire_trap .hero-portrait { border-color: #ff783e; box-shadow: 0 0 0 3px #c53c1e, 0 0 14px #ff793c; animation: fire-trap-ring 2s linear infinite; }
.hero-medallion.status-ring-counter .hero-portrait { border-color: #83b5dd; box-shadow: 0 0 0 3px #4b82ad, 0 0 12px #83b5dd; }
.hero-medallion.status-ring-devotion .hero-portrait { border-color: #e8d27f; box-shadow: 0 0 0 3px #b99d43, 0 0 12px #ead277; }
.hero-medallion.status-ring-adamant .hero-portrait { border-color: #d8e1ec; box-shadow: 0 0 0 3px #8b9baa, 0 0 12px #d8e1ec; }
@keyframes fire-trap-ring { 50% { box-shadow: 0 0 0 3px #ff9d42, 0 0 18px #ff5027; } }

/* A bonded hero channels protection from its portrait to the exact minion
   instance. The SVG stays viewport-sized, matching the targeting ray's
   coordinate system, while CSS owns the reduced-motion-safe pulse. */
.devotion-channel { position: fixed; inset: 0; z-index: 18; width: 100vw; height: 100vh; overflow: visible; pointer-events: none; }
.devotion-channel-line {
  stroke: #5fc6ff; stroke-width: 4; stroke-linecap: round; opacity: .9;
  filter: drop-shadow(0 0 3px #63d5ff) drop-shadow(0 0 9px rgba(49,133,255,.8));
  stroke-dasharray: 9 13; animation: devotion-channel-flow 850ms linear infinite;
}
@keyframes devotion-channel-flow { to { stroke-dashoffset: -44; } }

/* Poison is a haze around the holder, never a glyph occupying its health orb.
   drop-shadow survives card overflow clipping and composes with the
   can-attack gold glow — the violet must read at a glance (user, PT-13). */
.poison-aura {
  position: relative; isolation: isolate;
  filter: drop-shadow(0 0 6px var(--venom)) drop-shadow(0 0 16px var(--venom));
}
.poison-aura::after {
  content: ''; position: absolute; inset: -9px; z-index: 3; pointer-events: none;
  border-radius: inherit; border: 2px solid color-mix(in srgb, var(--venom) 72%, white);
  background: radial-gradient(circle, rgba(198,108,255,.10) 34%, rgba(151,56,225,.27) 64%, transparent 73%);
  box-shadow: 0 0 12px var(--venom), inset 0 0 12px rgba(198,108,255,.56);
  animation: poison-aura-breathe 1.8s var(--ease-in-out) infinite alternate;
}
.hero-medallion.poison-aura::after { border-radius: 50%; inset: -8px; }
@keyframes poison-aura-breathe { to { opacity: .58; transform: scale(1.08); } }

/* Adamant Form is an electric skin on the portrait for its live status. */
.hero-adamant-energy {
  position: absolute; inset: -3px; z-index: 2; pointer-events: none; border-radius: 50%;
  background: repeating-conic-gradient(from 20deg, transparent 0 12deg, rgba(226,244,255,.92) 14deg 18deg, transparent 21deg 42deg);
  mix-blend-mode: screen; filter: drop-shadow(0 0 5px #cdeaff); animation: adamant-arcs 760ms linear infinite;
}
@keyframes adamant-arcs { to { transform: rotate(1turn) scale(1.08); } }

/* the hand is a FAN: neighbors overlap ~22px like physically held cards.
   Load-bearing for layout too: a flat 8-card row's min-content inflated
   #app past its 960px basis and strangled the Chronicle's rail. */
/* padding-bottom is load-bearing: the fan pose translates edge cards down by
   up to ~21px and the stat gems intrude 9px past the frame — both OUTSIDE the
   layout box fitAppToViewport measures, so without reserved space the fan's
   bottom edge clips at the viewport. */
.hand { display: flex; justify-content: center; margin-top: 4px; min-height: 200px; padding-bottom: 32px; }
/* -5px (was -11px): the grand-layout font pass made name/text lines reach the
   card edge, and the deeper overlap cropped them under the neighbor card */
.hand .card { margin: 0 -5px; }
/* justify-content:flex-start is load-bearing: hand cards of minion TYPE
   also carry .minion, whose flex-end would bottom-pack low-content cards. */
.card {
  width: 170px; height: 252px;
  border: 6px solid transparent; border-radius: 16px 16px 10px 10px;
  /* frame color via --sframe (state) → default gilt */
  background: linear-gradient(var(--lead), var(--lead)) padding-box, var(--sframe, var(--gilt-dark)) border-box;
  position: relative; padding: 7px; cursor: pointer;
  box-shadow: 0 0 0 1px #08090c, 0 7px 16px rgba(0,0,0,.6);
  display: flex; flex-direction: column; align-items: center; justify-content: flex-start;
}
/* --fx/--fy are the FLIP flight offsets (spring-animated by motion.js);
   --fan is the resting fan pose. No base transform transition — it would
   fight the per-frame spring updates; hover gets its own transition. */
.card { transform: translate(var(--fx, 0px), var(--fy, 0px)) var(--fan, none); }
.card:hover {
  transform: translateY(-14px) scale(1.05); z-index: 2;
  transition: transform .22s var(--ease-out);
}
/* instant press feedback — the render/animation pipeline runs AFTER the
   click resolves, so without this the first visible response to a click
   could be a whole re-render later (perceived input lag) */
.card:active { transform: translateY(-14px) scale(1.01); transition-duration: .06s; }
.minion:active { transform: scale(.96); }
.end-turn:active:not(:disabled), .hero-power:active:not(:disabled),
.new-game:active, .play-again:active, .audio-btn:active {
  transform: scale(.95);
}
/* dark (unplayable) glass is only slightly dim; the tarnished frame carries
   the state — art stays readable (the old .74 read as a black hole) */
.card .card-art { filter: brightness(.92) saturate(.96); }
/* UNAFFORDABLE — can't pay for it this turn: desaturated but still clearly
   legible, with the cost pip flagged red so the mana gap is what you notice */
.card.unaffordable { filter: grayscale(.4) brightness(.88); cursor: default; }
.card.unaffordable .card-art { filter: grayscale(.55) brightness(.78) saturate(.75); }
.card.unaffordable .cost {
  box-shadow: 0 0 0 2px #4a1018, 0 0 0 4px #8e1830, 0 0 8px rgba(196,31,63,.7),
              inset 0 2px 5px rgba(255,255,255,.35), inset 0 -3px 6px rgba(0,0,0,.4);
}
/* LIT — playable: bright gilt + halo; the glass glows warm */
.card.playable, .card.static {
  --sframe: var(--gilt-lit);
  box-shadow: 0 0 0 1px #3a2c0e, 0 0 26px rgba(255,181,71,.55), 0 7px 16px rgba(0,0,0,.6);
}
.card.playable .card-art, .card.static .card-art { filter: brightness(1.06) saturate(1.12); }
/* travelling sheen on lit frames, masked to the metal ring only */
.card.playable::after, .card.static::after {
  content: ''; position: absolute; inset: -6px; border-radius: 16px 16px 10px 10px;
  padding: 6px; pointer-events: none;
  background: linear-gradient(115deg, transparent 38%, rgba(255,252,235,.9) 50%, transparent 62%);
  background-size: 300% 300%; background-repeat: no-repeat;
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
  animation: sheen 4.6s var(--ease-out) infinite;
}
@keyframes sheen { 0% { background-position: 220% 0; } 55%, 100% { background-position: -140% 0; } }
.card.static { opacity: 1; cursor: default; transform: none; }
.card.static:hover { transform: none; }
.card.selected, .minion.selected {
  transform: translateY(-6px) scale(1.06);
  z-index: 3; /* above overlapped fan neighbors and hovered cards */
  background: linear-gradient(var(--lead), var(--lead)) padding-box, var(--gilt-lit) border-box;
  box-shadow: 0 0 0 1px #3a2c0e, 0 0 0 2px var(--gold-bright), 0 0 24px rgba(251,238,192,.5),
              0 7px 18px rgba(0,0,0,.6);
  animation: none; /* selected outranks the can-attack halo pulse */
}

/* --- living glass: the art breathes slowly; hover quickens it --- */
@keyframes art-breathe {
  from { transform: scale(1.06) translateY(0); }
  to   { transform: scale(1.14) translateY(-3px); }
}
/* NB: hand cards of minion type also carry .minion — scope to .board */
.card-art, .board .minion, .hero-portrait, .preview-art { overflow: hidden; position: relative; }
.card-art::before, .hero-portrait::before, .preview-art::before {
  content: ''; position: absolute; inset: 0; z-index: 0;
  background: inherit; background-size: cover; background-position: center;
  border-radius: inherit;
  animation: art-breathe 7s var(--ease-in-out) infinite alternate;
  animation-delay: var(--breathe-delay, 0s);
}
.card:hover .card-art::before, .board .minion:hover .minion-art { animation-duration: 2.8s; }
.board .minion .minion-name { position: relative; z-index: 1; }
/* the arched pane: art seen through a round-topped window in a lead ring.
   ::before is the breathing art; ::after carries the candle wash when lit —
   plain low-alpha amber, NOT a screen blend (additive light washed bright
   artwork to white). No tracery lines over the art: full-box diagonals
   crossed every portrait like an X, and the art's legibility wins. */
.card-art {
  /* flex-shrink 0 is load-bearing: .card is a fixed-height flex column, and
     without it a long .card-text squashes the art (user, 2026-07-13) */
  flex-shrink: 0;
  width: 100%; height: 88px; margin: 0 0 6px; position: relative; z-index: 0;
  background-size: cover; background-position: center;
  border-radius: 64px 64px 4px 4px;
  box-shadow: inset 0 0 0 2px var(--came);
}
.card-art::after {
  content: ''; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  border-radius: inherit;
}
.card.playable .card-art::after, .card.static .card-art::after {
  background: radial-gradient(circle at 50% 42%, rgba(255,181,71,.22), transparent 72%);
}
.card.spell .card-art { box-shadow: inset 0 0 0 2px #2a3140; }
.card-name {
  font-family: var(--font-display); font-size: .88rem; letter-spacing: .04em;
  text-align: center; line-height: 1.2; color: var(--bone);
  width: 100%; background: var(--lead-2); padding: 4px 2px; margin-bottom: 4px;
  border-top: 2px solid var(--came); border-bottom: 2px solid var(--came);
}
/* padding-bottom is load-bearing: .card-text sits flush against the card's
   bottom edge (margin-top:auto), exactly where the atk/hp gems and the
   socket button intrude. 14px clears both with margin to spare. */
.card-text {
  font-family: var(--font-body); font-weight: 600;
  font-size: .92rem; color: #ded6bf; text-align: center;
  margin-top: auto; padding-bottom: 18px; line-height: 1.3;
  text-shadow: 0 1px 2px rgba(0,0,0,.8);
  /* clamp instead of squeezing the art; the reading contexts (hold preview,
     compendium viewer) lift the clamp and grow the card instead */
  overflow: hidden;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 5;
}
/* READING CARDS — hover-zoom preview, compendium viewer, mulligan (user pick,
   2026-07-14). ONE fixed, larger, real-card layout: NO vertical growth. It is
   WIDER than the in-hand card so the pool's longest description needs fewer
   lines, the art is a fixed ~48% so every card matches, and the rules text is
   vertically centered in its box so short cards read as a balanced text panel
   (not a gap floated to the bottom). Sized to clear the 904x407 viewport. */
#card-preview .card, .compendium-viewer .card, .card.mull-card {
  width: 212px; height: 336px; padding: 9px;
}
#card-preview .card .card-art,
.compendium-viewer .card .card-art,
.card.mull-card .card-art { height: 158px; flex-shrink: 0; }
#card-preview .card .card-name,
.compendium-viewer .card .card-name,
.card.mull-card .card-name { font-size: 1.02rem; }
#card-preview .card .card-text,
.compendium-viewer .card .card-text,
.card.mull-card .card-text {
  font-size: .92rem; -webkit-line-clamp: 7; /* fits the longest at this width */
  margin-top: auto; margin-bottom: auto;    /* centered in the text box */
  padding-bottom: 6px;
}
#card-preview .card .cost,
.compendium-viewer .card .cost,
.card.mull-card .cost { width: 44px; height: 44px; font-size: 1.4rem; top: -12px; left: -12px; }
#card-preview .card .stat,
.compendium-viewer .card .stat,
.card.mull-card .stat { width: 40px; height: 40px; font-size: 1.3rem; bottom: -11px; }
#card-preview .card .stat.atk,
.compendium-viewer .card .stat.atk,
.card.mull-card .stat.atk { left: -12px; }
#card-preview .card .stat.hp,
.compendium-viewer .card .stat.hp,
.card.mull-card .stat.hp { right: -12px; }

/* equipment: slot name + socket pips, shown on the card face and preview */
.equip-meta {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 4px;
  font-family: var(--font-body); font-weight: 700; font-size: .74rem;
  color: var(--gold-bright); text-align: center; margin: 3px 4px 0;
  text-shadow: 0 1px 2px rgba(0,0,0,.85);
}
.equip-meta-sockets { opacity: .85; }
.equip-meta .socket-pips { margin-top: 0; }

/* Attribute tag under the name: "✦ Spell". */
.card-tags { display: flex; gap: 4px; justify-content: center; flex-wrap: wrap; margin: 3px 0 0; }
.card-type-tag {
  padding: 1px 9px; border-radius: 999px; font-family: var(--font-display);
  font-size: .6rem; letter-spacing: .06em; text-shadow: 0 1px 2px rgba(0,0,0,.8);
}
.card-type-tag.spell { color: #e6d6ff; background: rgba(88,48,150,.55); border: 1px solid rgba(178,138,255,.7); }
/* arcane frame glow on spell cards (layers over the gilt frame, both states) */
.card.spell { box-shadow: 0 0 0 1px #08090c, 0 0 15px rgba(150,90,230,.4), 0 7px 16px rgba(0,0,0,.6); }
.card.spell.playable { box-shadow: 0 0 0 1px #3a2c0e, 0 0 15px rgba(150,90,230,.5), 0 0 18px rgba(255,181,71,.3), 0 7px 16px rgba(0,0,0,.6); }
.card.spell .card-name { color: #e6d6ff; }

/* -------------------------------------------------------------- gems:
   cut stones in gold bezels — sapphire cost, amber attack, ruby health.
   Bone numerals over a specular catch-light.
   z-index is load-bearing: the positioned art layers would otherwise paint
   over the cost (equal auto z-index falls back to document order). */
.cost, .stat {
  font-family: var(--font-display); color: #fbf5e2;
  text-shadow: 0 1px 2px rgba(0,0,0,.9), 0 0 3px rgba(0,0,0,.7);
  border-radius: 50%;
  box-shadow: 0 0 0 2px #2e2409, 0 0 0 4px var(--gold), 0 0 0 5px #3a2c0e,
              0 4px 10px rgba(0,0,0,.65),
              inset 0 2px 5px rgba(255,255,255,.45), inset 0 -3px 6px rgba(0,0,0,.4);
  display: grid; place-items: center; position: absolute; z-index: 4;
}
.cost::before, .stat::before {
  content: ''; position: absolute; width: 36%; height: 20%; border-radius: 50%;
  background: rgba(255,255,255,.6); top: 13%; left: 17%;
  transform: rotate(-24deg); filter: blur(1px);
}
.cost {
  top: -10px; left: -10px; width: 34px; height: 34px; font-size: 1.1rem;
  background: radial-gradient(circle at 36% 30%, var(--lapis-hi), var(--lapis) 58%, var(--lapis-lo));
}
.stat { bottom: -9px; width: 32px; height: 32px; font-size: 1.05rem; }
.stat.atk { left: -10px; background: radial-gradient(circle at 36% 30%, var(--amber-hi), var(--amber) 58%, var(--amber-lo)); }
.stat.hp  { right: -10px; background: radial-gradient(circle at 36% 30%, var(--ruby-hi), var(--ruby) 58%, var(--ruby-lo)); }
.minion.hurt .stat.hp { background: radial-gradient(circle at 36% 30%, #d95f70, #8e1830 58%, #43050f); }
/* On the BOARD, tuck the attack/health gems INSIDE the frame so they read
   clearly and never hang off the edge (where neighbours / the fit-scale clip
   them). Hand cards keep the classic overhanging gems. */
.board .minion .stat { bottom: 3px; width: 30px; height: 30px; }
.board .minion .stat.atk { left: 3px; }
.board .minion .stat.hp  { right: 3px; }

/* --- M1 interactivity --- */
/* (hero-portrait styling now lives in the medallion block above) */
.counts { font-size: .98rem; opacity: .85; }
.hero-power {
  position: absolute; top: -6px; right: -10px; z-index: 5;
  width: 32px; height: 32px; border-radius: 50%;
  font-size: .95rem; cursor: pointer;
  background: radial-gradient(circle at 35% 30%, #34383f, #17191e);
  color: var(--gold-bright); border: 2px solid var(--gold);
  transition: box-shadow .28s var(--ease-out);
}
.hero-power:hover:not(:disabled) { box-shadow: 0 0 12px rgba(255,181,71,.7); }
.hero-power:disabled { opacity: .35; cursor: default; }
.hero-power.passive:disabled { opacity: .85; cursor: default; border-style: dashed; }
.hero-power-icon { display: block; line-height: 1; }
.hero-spirit-orb {
  position: absolute; bottom: -7px; left: -13px; z-index: 5; width: 24px; height: 24px;
  display: grid; place-items: center; border-radius: 50%; color: #edfbff; font: 700 .78rem/1 var(--font-display);
  background: radial-gradient(circle at 34% 28%, #d6f8ff, #5eb8d9 54%, #1f5278);
  border: 2px solid #bceeff; box-shadow: 0 0 8px rgba(102,216,255,.85), inset 0 1px 2px rgba(255,255,255,.7);
}
/* styled hover card for the hero power (replaces the browser title tooltip) */
.hero-power-tip {
  position: absolute; bottom: calc(100% + 10px); left: 50%;
  transform: translateX(-50%) translateY(4px);
  width: min(220px, calc(100vw - 20px)); max-width: 220px; padding: 8px 12px; border-radius: 10px; z-index: 50;
  background: linear-gradient(180deg, rgba(20,22,28,.97), rgba(12,14,18,.97)) padding-box, var(--gilt-lit) border-box;
  border: 1.5px solid transparent; box-shadow: 0 6px 20px rgba(0,0,0,.6);
  opacity: 0; pointer-events: none; text-align: center;
  transition: opacity .14s var(--ease-out), transform .14s var(--ease-out);
}
.hero-power-tip.show { opacity: 1; transform: translateX(-50%) translateY(0); }
.hero-overlay.foe .hero-power-tip {
  top: calc(100% + 10px); bottom: auto;
}
.hero-overlay.me .hero-power-tip {
  bottom: 0; left: calc(100% + 10px);
  transform: translateX(0) translateY(4px);
}
.hero-overlay.me .hero-power-tip.show { transform: translateX(0) translateY(0); }
.hp-tip-name { font-family: var(--font-display); color: var(--gold-bright); font-size: .82rem; letter-spacing: .03em; margin-bottom: 2px; }
.hp-tip-text { font-family: var(--font-body); color: var(--ink); font-size: .78rem; line-height: 1.3; }

.deck-pile {
  width: 44px; height: 60px; border-radius: 5px; position: relative;
  background: url("../assets/card-back.webp") center / cover, var(--card-bg);
  border: 1px solid var(--gold);
  box-shadow: 2px 2px 0 -1px #101116, 2px 2px 0 0 rgba(227,180,94,.55),
              4px 4px 0 -1px #101116, 4px 4px 0 0 rgba(227,180,94,.35);
}
.deck-pile.empty { opacity: .35; box-shadow: none; }
.deck-count {
  position: absolute; inset: 0; display: grid; place-items: center;
  font-size: .9rem; color: var(--bone); font-family: var(--font-display);
  background: rgba(8,10,14,.5); border-radius: 4px;
  text-shadow: 0 1px 2px rgba(0,0,0,.9);
}
/* No minion hover-scale (tried, reverted): board rows are tightly packed;
   the hover-zoom parity is #card-preview (inspect.js), a fixed overlay. */

/* the midbar IS the center divider (reference board): a gold hairline across
   the full stage, with the turn banner + hint riding it as a dark chip on the
   RIGHT — pointing at the End Turn orb fixed just past it on the screen edge */
.midbar {
  position: relative; width: 100%; min-height: 38px;
  display: flex; align-items: center; justify-content: flex-end; gap: 10px;
  /* clears the fixed End Turn orb (~120px of screen at the right edge) */
  padding-right: 170px;
  color: var(--gold); font-size: .85rem;
}
/* The hairline is no longer drawn by the midbar (which lives in the scaled
   stage and drifted with stage height): body.playing::after draws it at the
   exact vertical center of the SCREEN — the same anchor the End Turn orb
   uses, so the two can never misalign again (user, 2026-07-14). Interim
   until CANVAS-1 makes divider-y a canonical token. */
body.playing::after {
  /* spans board-to-orb, not edge-to-edge (user: it sliced through the rail
     and the mirror art) */
  content: ''; position: fixed; left: 170px; right: var(--divider-right, 100px); top: var(--orb-cy, 50%); height: 2px;
  transform: translateY(-50%); pointer-events: none; z-index: 4;
  background: linear-gradient(90deg, transparent, rgba(227,180,94,.55) 10%,
      rgba(251,238,192,.75) 50%, rgba(227,180,94,.55) 90%, transparent);
  box-shadow: 0 0 12px rgba(255,181,71,.35);
}
body.playing #app { z-index: 5; } /* stage pieces paint above the divider */
/* The two divider labels split (user, 2026-07-14): the TURN banner is pinned to
   the centre of the screen (== the centre of the divider); the hint takes the
   right-hand space, ending before the End Turn orb so it never overlaps it. */
.divider-chips {
  position: fixed; top: var(--orb-cy, 50%); left: 0; right: 0; transform: translateY(-50%);
  z-index: 15; pointer-events: none; color: var(--gold); font-size: .72rem;
}
.divider-chips .turn-banner {
  position: absolute; left: 50vw; top: 0; transform: translate(-50%, -50%);
  font-size: .78rem; padding: 3px 9px; white-space: nowrap;
}
.divider-chips .hint {
  position: absolute; right: var(--orb-right-gap, 100px); top: 0; transform: translateY(-50%);
  white-space: normal; max-width: 230px; line-height: 1.2; text-align: center;
}
.divider-chips .hint:empty { display: none; } /* no stray pill on the line */
.divider-chips .turn-banner, .divider-chips .hint,
.midbar .turn-banner, .midbar .hint {
  z-index: 1;
  background: rgba(10,12,17,.88); border: 1px solid rgba(227,180,94,.4);
  border-radius: 8px; padding: 5px 14px;
  box-shadow: 0 3px 10px rgba(0,0,0,.5);
}
/* in-stage midbar labels stay in flow (position:relative for stacking); the
   divider-chips labels keep their own absolute placement (centre / right). */
.midbar .turn-banner, .midbar .hint { position: relative; }
.midbar .hint { min-width: 0; }
.midbar .hint:empty { display: none; }
.end-turn {
  font-family: var(--font-display); font-size: .95rem; letter-spacing: .1em;
  color: #14151a; cursor: pointer;
  background: linear-gradient(180deg, #f0c568, #c98f2e);
  border: none; border-radius: 999px; padding: 8px 26px;
  box-shadow: 0 0 0 2px var(--came), 0 0 0 3px #08090c, 0 0 20px rgba(255,181,71,.35),
              inset 0 1px 0 rgba(255,252,235,.6);
}
.end-turn:hover:not(:disabled) { filter: brightness(1.08); }
.end-turn:disabled { opacity: .4; cursor: default; box-shadow: 0 0 0 2px var(--came), 0 0 0 3px #08090c; }
.hint {
  min-width: 180px; color: var(--bone); font-style: italic; font-size: 1.05rem;
  text-shadow: 0 1px 3px rgba(0,0,0,.8);
}

/* ------------------------------------------------------ the Herald:
   #left-rail's stack of every card played this turn — the REAL card
   component (View.cardFaceEl → .card.static, always LIT: a played card is
   an event, it burns bright then smokes out via announce.js's ~4s
   dissolve). The 14px padding exists for the gems, which intrude 10px past
   the frame — the rail's overflow:hidden would shave them. */
.announce-stack {
  /* ONE column, newest under oldest — row-wrap crammed two announcements
     side by side in the narrow rail (user note, 2026-07-14) */
  display: flex; flex-direction: column; align-items: flex-start; margin: 4px;
  padding: 10px; gap: 10px; pointer-events: none;
}
.card-announce { display: flex; flex-direction: column; align-items: center; gap: 7px; }
.announce-puff {
  position: fixed; z-index: 5; pointer-events: none; border-radius: 50%;
  background: radial-gradient(circle, rgba(184,188,196,.55), rgba(184,188,196,0) 70%);
  filter: blur(2px);
}
.card-announce-who {
  font-family: var(--font-display); font-size: .72rem; letter-spacing: .12em;
  white-space: nowrap;
  background: rgba(8,10,14,.95); border: 1px solid var(--gold); border-radius: 999px;
  padding: 3px 12px; color: var(--gold-bright);
  box-shadow: 0 2px 8px rgba(0,0,0,.6);
}
.card-announce.owner-0 .card-announce-who { color: #b8e4c5; border-color: rgba(134,199,154,.65); }
.card-announce.owner-1 .card-announce-who { color: #f0b39a; border-color: rgba(217,107,63,.65); }

/* --------------------------------------------------- the Chronicle:
   the duel's written record, pinned to the bottom of #left-rail. Lead
   panel, gold spine, engraved title; turn numerals as candle-gold verses.
   No explicit width on purpose: the rail's align-items:stretch sizes it
   (a fixed width used to clip lines mid-word at intermediate widths). */
/* Chronicle: an aged PARCHMENT scroll with rolled ends and ink text (board
   redesign reference), replacing the old dark lead panel. */
#log-panel {
  max-width: 290px; max-height: 60vh; min-width: 0;
  margin: 22px 16px; overflow: visible; display: flex; flex-direction: column; position: relative;
  color: #3a2c15; border-radius: 5px; border: 1px solid #b0925c;
  background: linear-gradient(180deg, #efe4c6 0%, #e6d5ad 52%, #ddca9d 100%);
  box-shadow: 0 10px 28px rgba(0,0,0,.55), inset 0 0 36px rgba(120,88,42,.26), inset 0 0 3px rgba(90,63,28,.55);
}
/* the two rolled dowels at top and bottom */
#log-panel::before, #log-panel::after {
  content: ''; position: absolute; left: -7px; right: -7px; height: 15px; border-radius: 9px;
  background: linear-gradient(180deg, #c2a468 0%, #9c7c46 55%, #7c6034 100%);
  box-shadow: 0 2px 7px rgba(0,0,0,.5), inset 0 1px 2px rgba(255,240,205,.5), inset 0 -2px 4px rgba(70,48,20,.7);
}
#log-panel::before { top: -9px; }
#log-panel::after { bottom: -9px; }
.log-panel-title {
  font-family: var(--font-display); letter-spacing: .18em; color: #4a3414;
  font-size: .84rem; text-transform: uppercase; text-align: center; padding: 12px 12px 6px;
  border-bottom: 1px solid rgba(110,80,38,.35); text-shadow: 0 1px 0 rgba(255,250,228,.55);
}
/* history scrolls under the pinned title, so it never scrolls away */
.log-scroll {
  overflow-y: auto; overflow-wrap: break-word; padding: 8px 16px 12px;
  font-family: var(--font-body); font-weight: 600; font-size: .9rem; line-height: 1.42;
  color: #4a3a1e;
  scrollbar-width: thin; scrollbar-color: rgba(120,88,42,.55) transparent;
}
.log-line { padding: 1px 0; }
.log-line.turn-marker {
  font-family: var(--font-display); color: #6d4a15; font-size: .72rem;
  letter-spacing: .14em; text-transform: uppercase;
  margin: 8px 0 3px; padding-top: 7px; text-align: center;
  border-top: 1px solid rgba(110,80,38,.3); text-shadow: 0 1px 0 rgba(255,250,228,.45);
}
.log-line.turn-marker::before { content: '✦  '; }
.log-line.turn-marker:first-child { margin-top: 0; padding-top: 2px; border-top: none; }

/* --- structured chronicle: "{actor} {glyph} {target} = {impact}" --- */
.chron-line {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: .28em;
  padding: 2px 0; font-size: .86rem; line-height: 1.34;
}
.chron-actor, .chron-target { font-weight: 700; }
.chron-actor.side-0, .chron-target.side-0 { color: #2f4f6b; } /* you — slate blue */
.chron-actor.side-1, .chron-target.side-1 { color: #94381f; } /* opponent — rust */
.chron-icon { font-weight: 700; opacity: .9; }
.chron-eq { color: #8a7448; opacity: .7; }
.chron-impact { font-weight: 700; font-variant-numeric: tabular-nums; }
/* tone colours the interaction glyph + its impact (names keep their side tint) */
.tone-damage   .chron-icon, .tone-damage   .chron-impact { color: #ab2a19; }
.tone-heal     .chron-icon, .tone-heal     .chron-impact { color: #2f7a37; }
.tone-buff     .chron-icon, .tone-buff     .chron-impact { color: #9a6a0e; }
.tone-summon   .chron-icon, .tone-play     .chron-icon   { color: #2c6070; }
.tone-shield   .chron-icon, .tone-shield   .chron-impact { color: #1f6b6b; }
.tone-death { opacity: .72; font-style: italic; }
.tone-death .chron-actor { color: #6a5a3e; }
.tone-death .chron-icon  { color: #4a3a24; }
/* turn separator + victory banner reuse the parchment display face */
.chron-turn {
  font-family: var(--font-display); color: #6d4a15; font-size: .72rem;
  letter-spacing: .12em; text-transform: uppercase; justify-content: center;
  margin: 9px 0 3px; padding-top: 7px; border-top: 1px solid rgba(110,80,38,.3);
  text-shadow: 0 1px 0 rgba(255,250,228,.45);
}
.chron-line.chron-turn:first-child { margin-top: 0; padding-top: 2px; border-top: none; }
.chron-victory {
  justify-content: center; gap: .3em; margin-top: 8px; padding-top: 8px;
  border-top: 1px solid rgba(110,80,38,.35); font-family: var(--font-display);
}
.chron-victory .chron-icon { color: #b8860b; }
.chron-victory .chron-impact { color: #6d4a15; text-transform: uppercase; letter-spacing: .1em; }

/* --- End Turn medallion, seated exactly in the background art's carved
   stone mirror. --orb-x/y/d are computed per-viewport by view.js's
   positionEndTurnOrb (the art is center/cover fixed, so the mirror moves
   with the window). left/top via calc (not translate) so hover's scale()
   doesn't fight an anchor transform. */
.end-turn-orb {
  position: fixed; z-index: 30;
  left: calc(var(--orb-x, calc(100vw - 90px)) - var(--orb-d, 94px) / 2);
  top: calc(var(--orb-y, 50vh) - var(--orb-d, 94px) / 2);
  width: var(--orb-d, 94px); height: var(--orb-d, 94px); border-radius: 50%; cursor: pointer;
  font-family: var(--font-display); font-size: calc(var(--orb-d, 94px) * .14);
  line-height: 1.1; letter-spacing: .04em;
  color: #5c3104; border: 4px solid transparent; overflow: hidden; isolation: isolate;
  background: radial-gradient(circle at 34% 27%, #fff4b6 0 4%, #f7ca58 14%, #bd7515 61%, #77400a 100%) padding-box,
    repeating-conic-gradient(from 4deg, #ffe89a 0deg 4deg, #8e510b 4deg 8deg) border-box;
  box-shadow: 0 0 0 1px #3c2107, 0 0 22px rgba(255,181,71,.42), 0 8px 22px rgba(0,0,0,.6), inset 0 1px 3px rgba(255,255,220,.8), inset 0 -4px 7px rgba(83,42,4,.48);
  text-shadow: 0 1px 0 #ffe6a0, 0 -1px 0 rgba(83,42,4,.38);
  transition: transform .15s var(--ease-out), box-shadow .2s var(--ease-out);
}
.end-turn-orb::before {
  content: ''; position: absolute; inset: 5px; z-index: -1; border: 2px dotted rgba(102,54,5,.72); border-radius: 50%;
  box-shadow: inset 0 0 0 2px rgba(255,236,151,.36), 0 0 0 1px rgba(97,49,3,.38);
}
.end-turn-orb::after {
  content: ''; position: absolute; inset: 8% 16% 54% 20%; z-index: -1; border-radius: 50%; pointer-events: none;
  background: radial-gradient(ellipse at center, rgba(255,255,232,.72), rgba(255,255,232,0) 68%); transform: rotate(-22deg);
}
.end-turn-orb:hover:not(:disabled) { transform: scale(1.06); box-shadow: 0 0 0 1px #5d3506, 0 0 32px rgba(255,211,83,.7), 0 8px 22px rgba(0,0,0,.6), inset 0 1px 3px rgba(255,255,220,.8); }
.end-turn-orb:active:not(:disabled) { transform: scale(.97); }
.end-turn-orb:disabled {
  opacity: .5; cursor: default; color: #8a8474;
  background: radial-gradient(circle at 40% 32%, #75613a, #302717) padding-box, var(--gilt-smoked) border-box;
  box-shadow: 0 0 0 1px #08090c, 0 8px 22px rgba(0,0,0,.6);
}

/* --- settings gear + panel (top-right) --- */
.settings { position: fixed; top: 18px; right: 22px; z-index: 40; }
.settings-gear {
  width: 42px; height: 42px; border-radius: 50%; cursor: pointer; font-size: 1.25rem;
  color: var(--gold-bright); border: 2px solid var(--gold);
  background: radial-gradient(circle at 35% 30%, #34383f, #17191e);
  transition: transform .3s var(--ease-out), box-shadow .2s;
}
.settings-gear:hover { box-shadow: 0 0 12px rgba(255,181,71,.7); transform: rotate(45deg); }
/* landing-page settings gear (mode-select is position:fixed inset:0) */
.menu-gear { position: fixed; top: 20px; right: 24px; z-index: 6; }
/* Global settings cog — ONE persistent control, top-right on every screen
   (user, 2026-07-14). Opens the shared settings modal (window.Settings). */
.app-settings-cog {
  position: fixed; top: 16px; right: 18px; z-index: 45;
  width: 42px; height: 42px; border-radius: 50%; cursor: pointer; font-size: 1.25rem;
  color: var(--gold-bright); border: 2px solid var(--gold);
  background: radial-gradient(circle at 35% 30%, #34383f, #17191e);
  box-shadow: 0 2px 10px rgba(0,0,0,.5);
  transition: transform .3s var(--ease-out), box-shadow .2s;
}
.app-settings-cog:hover { box-shadow: 0 0 12px rgba(255,181,71,.7); transform: rotate(45deg); }
body.game-over-active .app-settings-cog { display: none; }
/* Consistent top-right Back button, just left of the cog, on sub-screens
   (user #3). Menu screens use this instead of a bottom-centered Back. */
.app-back-btn {
  position: fixed; top: 16px; right: 70px; z-index: 45; height: 42px;
  display: inline-flex; align-items: center; gap: 5px; padding: 0 16px;
  border-radius: 21px; cursor: pointer;
  font-family: var(--font-display); font-size: .95rem; letter-spacing: .04em;
  color: var(--gold-bright); border: 2px solid var(--gold);
  background: radial-gradient(circle at 35% 20%, #34383f, #17191e);
  box-shadow: 0 2px 10px rgba(0,0,0,.5);
  transition: box-shadow .2s var(--ease-out);
}
.app-back-btn[hidden] { display: none; }
.app-back-btn:hover { box-shadow: 0 0 12px rgba(255,181,71,.6); }
body.game-over-active .app-back-btn { display: none; }
.settings-panel {
  position: absolute; top: 50px; right: 0; width: 194px; display: none;
  flex-direction: column; gap: 6px; padding: 12px;
  border: 3px solid transparent; border-radius: 12px;
  background: linear-gradient(var(--lead-2), var(--lead-2)) padding-box, var(--gilt-dark) border-box;
  box-shadow: 0 0 0 1px #08090c, 0 10px 26px rgba(0,0,0,.6);
}
.settings.open .settings-panel { display: flex; }
.settings-title {
  font-family: var(--font-display); color: var(--gold-bright); font-size: .95rem;
  letter-spacing: .05em; margin-bottom: 2px;
}
.settings-viewport {
  color: var(--ash);
  font-family: var(--font-body);
  font-size: .64rem;
  font-weight: 500;
  line-height: 1.25;
  white-space: nowrap;
}
.settings-row {
  font-family: var(--font-body); font-weight: 600; font-size: .82rem; text-align: left; cursor: pointer;
  padding: 7px 10px; border-radius: 7px; color: #cfc7b2;
  border: 1px solid rgba(227,180,94,.3); background: rgba(4,6,9,.4);
  transition: background .15s var(--ease-out), border-color .15s var(--ease-out);
}
.settings-row.on { color: #14151a; background: var(--gold); border-color: var(--gold); }
.settings-row:disabled { opacity: .38; cursor: default; }
.settings-row:hover { border-color: var(--gold); }
.settings-row.concede { color: #ffb3b3; border-color: rgba(196,31,63,.5); margin-top: 4px; }
.settings-row.concede:hover { background: rgba(196,31,63,.25); }

/* bleed guard: at real-world scaled-desktop widths the rails run narrow —
   shrink the Herald's cards and the Chronicle's margins BEFORE anything
   touches the screen edge. zoom (not transform) so layout space shrinks. */
@media (max-width: 1680px) {
  .announce-stack { margin: 4px; padding: 12px; gap: 14px 12px; }
  .card-announce { zoom: .82; }
  #log-panel { margin: 12px; max-width: 255px; }
}
@media (max-width: 1280px) {
  .card-announce { zoom: .68; }
  .log-scroll { font-size: .84rem; }
}

.game-over {
  position: fixed; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 18px;
  background: rgba(3,4,6,.88); z-index: 60; /* above hero overlays, log, orb, settings */
}
/* transition-in: stay invisible for a beat so the finishing blow plays on the
   still-visible board, then fade the result screen up as the heroes hide. */
.game-over.deferred { animation: game-over-in .5s var(--ease-out) .42s both; }
@keyframes game-over-in { from { opacity: 0; } to { opacity: 1; } }
/* the in-game body-level chrome hides behind the result screen so it can't
   punch through (each of these sits on <body> at its own z-index) */
body.game-over-active .hero-overlay,
body.game-over-active .gear-overlay,
body.game-over-active .counts-overlay,
body.game-over-active #log-panel,
body.game-over-active .end-turn-orb,
body.game-over-active .settings { display: none; }
.sigil-slot { width: 216px; height: 216px; }
.game-over-title {
  font-family: var(--font-display); color: var(--gold-bright);
  font-size: 2.6rem; letter-spacing: .08em;
  text-shadow: 0 2px 12px rgba(0,0,0,.8), 0 0 44px rgba(255,181,71,.4);
}
/* defeat matches the ash of the cracked sigil */
.game-over.defeat .game-over-title { color: #8a93a3; text-shadow: 0 2px 12px rgba(0,0,0,.8); }
.play-again, .new-game {
  font-family: var(--font-display); letter-spacing: .08em; cursor: pointer;
  border: 1px solid var(--gold); border-radius: 999px;
  background: rgba(8,10,14,.6); color: var(--gold-bright);
}
.play-again { font-size: 1.05rem; padding: 10px 30px; }
.play-again:hover, .new-game:hover { background: var(--gold); color: #14151a; }
.new-game { font-size: .74rem; padding: 5px 14px; opacity: .85; }
.game-over-btns { display: flex; gap: 14px; align-items: stretch; }
/* both buttons identical size (shared width + inherited padding/font); Main
   Menu only dimmed a touch as the secondary action */
.game-over-btns .play-again { min-width: 170px; text-align: center; }
.play-again.menu { opacity: .8; }
.seed-tag { font-size: .68rem; opacity: .55; font-family: var(--font-frame); text-shadow: 0 1px 2px rgba(0,0,0,.8); }
.audio-btn {
  font-family: var(--font-chrome); font-size: .74rem; padding: 3px 9px; cursor: pointer;
  background: rgba(8,10,14,.4); border: 1px solid rgba(227,180,94,.4);
  border-radius: 999px; color: var(--bone); opacity: .55;
}
.audio-btn:hover { opacity: .9; }
.audio-btn.on { opacity: 1; border-color: var(--gold); color: var(--gold-bright); }

/* --- animation layer --- */
.float-num {
  z-index: 20; pointer-events: none;
  font-family: var(--font-display); font-size: 1.55rem;
  text-shadow: 0 2px 4px rgba(0,0,0,.9);
}
.float-num.dmg  { color: #ff5f74; }
.float-num.heal { color: #9fdcb2; }
.ghost-minion {
  z-index: 15; pointer-events: none;
  border-radius: 24px 24px 8px 8px; border: 2px solid #7c6a3a;
  background: linear-gradient(160deg, #26282f, #14151a);
}

/* --- hover-zoom inspector: the same glass-and-gilt card, larger, always
   lit (inspection is illumination) --- */
/* The preview is now just a positioned container holding the REAL card
   component (View.cardFaceEl), scaled up. No frame/background of its own — the
   card supplies all of that, so the preview can't diverge from the card. */
#card-preview {
  position: fixed; z-index: 30; pointer-events: none;
  filter: drop-shadow(0 14px 44px rgba(0,0,0,.75));
  opacity: 0; transform: scale(.96); transform-origin: top left;
  transition: opacity .22s var(--ease-out), transform .22s var(--ease-out);
}
#card-preview.visible { opacity: 1; transform: scale(1); }
/* the reading card is already sized (212x336); a light zoom lifts it above the
   board without overflowing the 407px viewport (336 * 1.1 = 370). */
#card-preview .card { zoom: 1.1; cursor: default; }
/* buffed/hurt stat coloring in the preview's live board-minion stats */
.stat.buffed { background: radial-gradient(circle at 36% 30%, #b6f0a0, #3f9e3f 58%, #14520f); }
.stat.hp.hurt { background: radial-gradient(circle at 36% 30%, #d95f70, #8e1830 58%, #43050f); }
.preview-cost, .preview-atk, .preview-hp {
  font-family: var(--font-display); color: #fbf5e2;
  text-shadow: 0 1px 2px rgba(0,0,0,.9), 0 0 3px rgba(0,0,0,.7);
  border-radius: 50%; position: absolute; z-index: 4;
  box-shadow: 0 0 0 2px #2e2409, 0 0 0 4.5px var(--gold), 0 0 0 6px #3a2c0e,
              0 5px 12px rgba(0,0,0,.65),
              inset 0 3px 6px rgba(255,255,255,.45), inset 0 -4px 7px rgba(0,0,0,.4);
  display: grid; place-items: center;
}
.preview-cost {
  top: -15px; left: -15px; width: 42px; height: 42px; font-size: 1.3rem;
  background: radial-gradient(circle at 36% 30%, var(--lapis-hi), var(--lapis) 58%, var(--lapis-lo));
}
.preview-art {
  width: 100%; height: 140px;
  border-radius: 96px 96px 4px 4px;
  background-size: cover; background-position: center;
  box-shadow: inset 0 0 0 3px var(--came);
}
.preview-name {
  font-family: var(--font-display); font-size: 1.12rem; text-align: center;
  letter-spacing: .05em; color: var(--bone);
  width: 100%; background: var(--lead-2); padding: 5px 2px;
  border-top: 2px solid var(--came); border-bottom: 2px solid var(--came);
}
.preview-text {
  font-family: var(--font-body); font-weight: 600; font-size: .98rem;
  color: #d5cdb6; text-align: center; line-height: 1.35;
}
.preview-atk, .preview-hp { bottom: -15px; width: 40px; height: 40px; font-size: 1.2rem; }
.preview-atk { left: -15px; background: radial-gradient(circle at 36% 30%, var(--amber-hi), var(--amber) 58%, var(--amber-lo)); }
.preview-hp  { right: -15px; background: radial-gradient(circle at 36% 30%, var(--ruby-hi), var(--ruby) 58%, var(--ruby-lo)); }
.preview-atk.buffed, .preview-hp.buffed { background: radial-gradient(circle at 36% 30%, #a8e2ba, #3f8a58 58%, #17462a); }
.preview-hp.hurt { background: radial-gradient(circle at 36% 30%, #d95f70, #8e1830 58%, #43050f); }

/* --- socket action button on socketable hand cards ---
   A large labelled pill sitting on top near the card's bottom. It only renders
   when the player actually has an open socket (see hasOpenSocket in view.js),
   so it can't steal clicks in the common case, and it's big enough that a click
   can't slip onto the card body (which would play the minion to the board). */
.socket-btn {
  position: absolute; bottom: 7px; left: 50%; transform: translate(-50%, 0);
  padding: 4px 11px; border-radius: 999px; font-size: .62rem; line-height: 1;
  font-family: var(--font-display); letter-spacing: .04em; white-space: nowrap; z-index: 6;
  background: rgba(8,10,14,.94); color: var(--gold); border: 1.5px solid var(--gold);
  cursor: pointer; box-shadow: 0 2px 8px rgba(0,0,0,.7);
  transition: background .12s var(--ease-out);
}
.socket-btn:hover { background: var(--gold); color: #14151a; }
.socket-btn.armed { background: var(--gold); color: #14151a; box-shadow: 0 0 12px rgba(227,180,94,.9); }
.socket-btn:active { transform: translate(-50%, 0) scale(.95); }

/* --- socket target picker: equipped gear cards on the left to click into --- */
.socket-picker {
  position: fixed; left: 16px; top: 50%; transform: translateY(-50%); z-index: 25;
  display: flex; flex-direction: column; gap: 8px; align-items: center; padding: 12px 14px;
  border: 2px solid transparent; border-radius: 12px;
  background: linear-gradient(rgba(6,8,12,.9), rgba(6,8,12,.9)) padding-box, var(--gilt-lit) border-box;
  box-shadow: 0 0 0 1px #08090c, 0 0 24px rgba(255,181,71,.22), 0 10px 26px rgba(0,0,0,.6);
  max-height: 94vh; overflow-y: auto;
}
.socket-picker-title { font-family: var(--font-display); color: var(--gold-bright); font-size: .88rem; letter-spacing: .04em; margin-bottom: 2px; }
.socket-pick-item { position: relative; width: 134px; height: 216px; cursor: pointer; transition: transform .14s var(--ease-out); }
.socket-pick-item:hover { transform: translateY(-3px); }
.socket-pick-item .card { position: absolute; top: 0; left: 50%; transform: translateX(-50%) scale(.7); transform-origin: top center; pointer-events: none; }
.socket-pick-label { position: absolute; bottom: 0; left: 0; right: 0; text-align: center; font-size: .68rem; color: var(--gold-bright); text-shadow: 0 1px 2px rgba(0,0,0,.8); }

/* --- socket contents reveal (click a filled slot) --- */
.socket-reveal {
  position: fixed; inset: 0; z-index: 40; cursor: pointer;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 26px;
  background: radial-gradient(ellipse at center, rgba(6,8,12,.72), rgba(3,4,7,.92));
  backdrop-filter: blur(3px); animation: reveal-fade .16s var(--ease-out);
}
@keyframes reveal-fade { from { opacity: 0; } to { opacity: 1; } }
/* short cross-fade when a menu screen mounts, so screen swaps feel of one cloth */
@keyframes screen-fade { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
.class-select { animation: screen-fade .2s var(--ease-out); }
/* keyboard affordance everywhere (specific menu tiles add their own glow) */
button:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }
.socket-reveal-title { font-family: var(--font-display); color: var(--gold-bright); font-size: 1.35rem; letter-spacing: .04em; text-shadow: 0 2px 8px rgba(0,0,0,.8); }
/* generous gutters so the cards read as distinct objects, not a merged strip.
   No transform scale here — scaling grew each card past its layout box and ate
   the gap, making frames touch; a real gap keeps them cleanly separated. */
.socket-reveal-cards { display: flex; gap: 52px; flex-wrap: wrap; justify-content: center; max-width: 94vw; padding: 6px; }
/* whole-loadout view can hold many items — tighter gutters + a scroll cap */
.socket-reveal.loadout .socket-reveal-cards { gap: 30px; max-height: 74vh; overflow-y: auto; }
.socket-reveal-cards .card { pointer-events: none; }
.socket-reveal-hint { font-size: .84rem; color: var(--ink); opacity: .8; letter-spacing: .03em; }

/* --- equipment grid + sockets (8 RO-style slots, 4×2) --- */
.equipment-row { display: grid; grid-template-columns: repeat(4, 46px); gap: 5px; margin-right: 4px; }
.equip-slot {
  width: 46px; min-height: 46px; border-radius: 9px; cursor: pointer;
  border: 1px dashed rgba(227,180,94,.4); display: flex; flex-direction: column;
  align-items: center; justify-content: center; padding: 2px; font-size: 1rem;
  background: rgba(4,6,9,.35); transition: box-shadow .2s var(--ease-out);
}
.equip-slot.empty { opacity: .5; }
.equip-slot.blocked { opacity: .32; cursor: default; border-style: dotted; }
.equip-slot.filled { border-style: solid; border-color: var(--gold); background: rgba(227,180,94,.12); }
.equip-slot:hover:not(.blocked) { box-shadow: 0 0 10px rgba(227,180,94,.5); }
/* the weapon slot spans a touch wider read via a warmer tint */
.equip-slot.weapon.filled { border-color: var(--amber-hi); }
.equip-icon { font-size: 1.05rem; }
.equip-name { font-size: .58rem; text-align: center; line-height: 1.05; margin-top: 1px; }
.socket-pips { display: flex; gap: 2px; margin-top: 2px; }
.pip { width: 6px; height: 6px; border-radius: 50%; border: 1px solid var(--gold); background: transparent; }
.pip.filled { background: var(--gold); }

/* weapon slot: an attack (amber) and durability (lapis) pip like a real
   CCG weapon, so a worn weapon reads as "hero has N attack, M swings left" */
.equip-slot.weapon .weapon-stats { display: flex; gap: 3px; margin-top: 2px; }
.weapon-atk, .weapon-dur {
  min-width: 13px; height: 13px; padding: 0 1px; border-radius: 4px;
  font-family: var(--font-display); font-size: .6rem; line-height: 13px; text-align: center;
  color: #fbf5e2; text-shadow: 0 1px 1px rgba(0,0,0,.9);
}
.weapon-atk { background: radial-gradient(circle at 40% 30%, var(--amber-hi), var(--amber-lo)); }
.weapon-dur { background: radial-gradient(circle at 40% 30%, var(--lapis-hi), var(--lapis-lo)); }

/* persistent aura summary under the equipment row */
.aura-line {
  font-size: .72rem; letter-spacing: .02em; color: var(--gold-bright);
  opacity: .9; text-shadow: 0 1px 2px rgba(0,0,0,.85); text-align: center;
}

/* the hero's own attack value (from its weapon), on the medallion like a
   minion's attack pip — anchored top-left so it clears the HP badge below */
.hero-attack {
  position: absolute; left: -6px; top: -6px; width: 28px; height: 28px;
  display: grid; place-items: center; border-radius: 50%; z-index: 5;
  font-family: var(--font-display); font-size: .9rem; color: #fbf5e2;
  background: radial-gradient(circle at 36% 30%, var(--amber-hi), var(--amber) 58%, var(--amber-lo));
  box-shadow: 0 0 0 2px #2e2409, 0 0 0 3px var(--gold), 0 3px 8px rgba(0,0,0,.6);
}

/* --- class-select screen (M8): ART-DOMINANT grid (user, 2026-07-14). The
   classes ARE the screen — each tile is a full portrait with the name banded
   over the bottom, no role tag or blurb. A 6×2 grid that fills the height so
   all 12 fit one screen with NO scroll at the canonical 904x407. --- */
.class-select {
  position: fixed; inset: 0; z-index: 5; overflow: hidden;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 8px; padding: 12px 20px 16px; text-align: center;
}
.class-select .brand { font-size: clamp(1.3rem, 5vh, 2.4rem); }
.class-select .class-select-title { font-size: clamp(.72rem, 1.7vh, 1rem); margin-bottom: 2px; }
.brand {
  font-family: var(--font-display); font-size: 3.1rem; letter-spacing: .2em;
  color: var(--gold-bright);
  text-shadow: 0 2px 16px rgba(255,181,71,.4), 0 1px 2px rgba(0,0,0,.9);
}
.class-select-title { font-family: var(--font-display); font-size: 1.05rem; letter-spacing: .1em; opacity: .9; }
.class-grid {
  display: grid; grid-template-columns: repeat(6, 1fr); grid-auto-rows: 1fr;
  gap: 10px; width: min(96vw, 1400px);
  flex: 1 1 auto; min-height: 0; /* fill the space between the title and Back */
}
.class-option {
  position: relative; overflow: hidden; min-width: 0; min-height: 0; cursor: pointer;
  border: 3px solid transparent; border-radius: 14px;
  background: linear-gradient(var(--lead), var(--lead)) padding-box, var(--gilt-dark) border-box;
  box-shadow: 0 0 0 1px #08090c, 0 6px 18px rgba(0,0,0,.5);
  transition: transform .2s var(--ease-out), box-shadow .2s var(--ease-out);
}
.class-option:hover, .class-option:focus-visible {
  transform: translateY(-5px); outline: none;
  background: linear-gradient(var(--lead), var(--lead)) padding-box, var(--gilt-lit) border-box;
  box-shadow: 0 0 0 1px #3a2c0e,
    0 0 24px color-mix(in srgb, var(--class-accent, var(--candle)) 60%, transparent),
    0 12px 28px rgba(0,0,0,.6);
}
.class-art {
  position: absolute; inset: 0; width: 100%; height: 100%;
  border-radius: inherit;
  background-size: cover; background-position: center top; background-color: var(--card-bg);
}
.class-option-name {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 1;
  padding: 20px 4px 7px;
  font-family: var(--font-display); font-size: clamp(.8rem, 1.95vh, 1.08rem); letter-spacing: .05em;
  color: var(--gold-bright); text-shadow: 0 1px 4px rgba(0,0,0,.95);
  background: linear-gradient(transparent, rgba(6,8,11,.55) 45%, rgba(6,8,11,.92));
}
.class-option:hover .class-option-name,
.class-option:focus-visible .class-option-name { color: var(--class-accent, var(--gold-bright)); }

/* --- mode select (Quick Game vs Deck Builder) --- */
.mode-tagline {
  font-family: var(--font-body); font-style: italic; color: var(--ink);
  opacity: .78; font-size: clamp(.85rem, 1.9vh, 1.02rem); letter-spacing: .02em; margin-top: -2px;
}
/* Landing menu: a VERTICAL stack of two-line buttons */
.mode-grid { display: flex; flex-direction: column; gap: 14px; align-items: center; margin-top: 6px; }
.mode-option {
  width: 264px; padding: 12px 20px; cursor: pointer; text-align: center;
  display: flex; flex-direction: column; gap: 2px; align-items: center;
  color: #fff3d6; border: 3px solid transparent; border-radius: 10px;
  /* warm gilt-toned fill (not solemn gray), lit gold frame */
  background: linear-gradient(155deg, #5a451e, #33270f) padding-box, var(--gilt-lit) border-box;
  box-shadow: 0 0 0 1px #3a2c0e, 0 4px 12px rgba(0,0,0,.5);
  transition: transform .18s var(--ease-out), background .18s var(--ease-out), box-shadow .18s var(--ease-out);
}
.mode-option-name { font-family: var(--font-display); font-size: 1.15rem; letter-spacing: .05em; }
.mode-option-sub { font-family: var(--font-body); font-size: .74rem; opacity: .8; letter-spacing: .02em; }
/* Quick Game is the recommended first action — filled gold, clear hierarchy */
.mode-option.primary {
  color: #17150e; background: linear-gradient(180deg, var(--gold-bright), var(--gold)) padding-box, var(--gilt-lit) border-box;
}
.mode-option.primary .mode-option-sub { opacity: .72; }
.mode-option:hover, .mode-option:focus-visible {
  transform: translateY(-3px) scale(1.03); outline: none;
  box-shadow: 0 0 0 1px #3a2c0e, 0 0 22px rgba(255,181,71,.5), 0 6px 16px rgba(0,0,0,.6);
}
.mode-option:not(.primary):hover, .mode-option:not(.primary):focus-visible {
  background: linear-gradient(155deg, #7a5f27, #493715) padding-box, var(--gilt-lit) border-box;
}

/* --- saved-deck overview cards (Saved Decks + Quick Match deck source) --- */
.deck-source-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(236px, 1fr));
  gap: 12px; width: min(92vw, 860px); align-content: start;
  max-height: 60vh; overflow-y: auto; padding: 4px;
}
/* Quick Match deck source: Auto Deck fixed on the LEFT, saved decks on the
   RIGHT, horizontally aligned (user). */
.deck-source-split { display: flex; gap: 20px; align-items: flex-start; justify-content: center;
  width: min(94vw, 880px); }
.deck-source-auto { flex: 0 0 246px; }
.deck-source-auto .deck-tile { height: 100%; }
.deck-source-saved { flex: 1 1 auto; min-width: 0; display: flex; flex-wrap: wrap; gap: 12px;
  align-content: flex-start; max-height: 60vh; overflow-y: auto; padding: 2px; }
.deck-source-saved .deck-tile { flex: 1 1 236px; max-width: 320px; }
.deck-source-empty { align-self: center; color: var(--ash); font-family: var(--font-body);
  font-style: italic; opacity: .75; padding: 20px; }
.deck-tile {
  display: flex; align-items: center; gap: 12px; text-align: left;
  padding: 10px 12px; border: 2px solid transparent; border-radius: 12px; color: #f0e6cf;
  background: linear-gradient(155deg, #43351a, #241b0d) padding-box, var(--gilt-dark) border-box;
  box-shadow: 0 0 0 1px #08090c, 0 4px 12px rgba(0,0,0,.45);
  transition: transform .16s var(--ease-out), box-shadow .16s var(--ease-out), border-color .16s;
}
.deck-tile.clickable { cursor: pointer; }
.deck-tile.clickable:hover, .deck-tile.clickable:focus-visible {
  transform: translateY(-3px); outline: none; border-color: var(--class-accent, var(--gold));
  box-shadow: 0 0 0 1px #3a2c0e,
    0 0 20px color-mix(in srgb, var(--class-accent, var(--candle)) 45%, transparent), 0 6px 16px rgba(0,0,0,.6);
}
.deck-tile.primary { background: linear-gradient(155deg, #6a5124, #40300f) padding-box, var(--gilt-lit) border-box; }
.deck-crest {
  flex-shrink: 0; width: 52px; height: 52px; border-radius: 50%;
  background-size: cover; background-position: center top; background-color: var(--card-bg);
  border: 2px solid var(--class-accent, var(--gold));
}
.deck-crest-auto { display: grid; place-items: center; font-size: 1.4rem; color: var(--gold-bright);
  background: radial-gradient(circle at 35% 30%, #34383f, #17191e); }
.deck-tile-body { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
/* full name visible — wrap instead of truncating (user #5) */
.deck-tile-name { font-family: var(--font-display); font-size: 1rem; letter-spacing: .03em; color: var(--gold-bright);
  white-space: normal; overflow-wrap: anywhere; line-height: 1.15; }
.deck-tile-class { font-family: var(--font-body); font-size: .78rem; opacity: .78; }
.deck-tile-stats { display: flex; gap: 12px; margin-top: 4px; }
.deck-tile-stat { display: inline-flex; align-items: center; gap: 3px; font-family: var(--font-body); font-size: .82rem; }
.deck-tile-stat-glyph { opacity: .8; }
.deck-tile-stat-n { font-weight: 700; color: var(--gold-bright); }
.deck-tile-actions { display: flex; flex-direction: column; gap: 6px; flex-shrink: 0; }
/* icon-only Edit/Delete (user #5) */
.deck-tile-btn {
  cursor: pointer; font-size: 1rem; line-height: 1; width: 34px; height: 30px; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 7px; border: 1px solid rgba(227,180,94,.4);
  color: var(--bone); background: rgba(4,6,9,.4); transition: background .15s, border-color .15s;
}
.deck-tile-btn.edit:hover { border-color: var(--gold); color: var(--gold-bright); }
.deck-tile-btn.delete { border-color: rgba(196,31,63,.5); }
.deck-tile-btn.delete:hover { background: rgba(196,31,63,.25); }
/* Saved Decks: class filter row */
.saved-decks-filter { display: flex; flex-wrap: wrap; justify-content: center; gap: 6px; margin: 2px 0 4px; max-width: min(92vw, 860px); }
.deck-name-error { min-height: 1em; color: #ff9d9d; font-family: var(--font-body); font-size: .9rem; }

/* name-your-deck dialog + delete confirm (Modal bodies) */
.deck-name-form { display: flex; flex-direction: column; gap: 12px; }
.deck-name-input {
  width: 100%; box-sizing: border-box; padding: 10px 12px; border-radius: 8px;
  border: 1px solid var(--came); background: var(--lead); color: var(--bone); font: 600 1.05rem var(--font-body);
}
.deck-name-input:focus { outline: 1px solid var(--gold); border-color: var(--gold); }
.deck-name-save {
  align-self: flex-end; cursor: pointer; padding: 8px 22px; border-radius: 8px; border: 2px solid var(--gold);
  color: #14151a; background: linear-gradient(180deg, var(--gold-bright), var(--gold));
  font-family: var(--font-display); font-size: 1rem; letter-spacing: .04em;
}
.deck-name-save:hover { box-shadow: 0 0 14px rgba(255,181,71,.6); }
.modal-confirm-row { display: flex; justify-content: flex-end; gap: 10px; margin-top: 6px; }
.modal-confirm { cursor: pointer; padding: 8px 18px; border-radius: 8px; font-family: var(--font-chrome); font-size: .85rem; }
.modal-confirm.no { border: 1px solid var(--came); color: var(--bone); background: rgba(4,6,9,.4); }
.modal-confirm.yes { border: 1px solid rgba(196,31,63,.6); color: #ffd0d0; background: rgba(196,31,63,.3); }
.modal-confirm.yes:hover { background: rgba(196,31,63,.5); }

/* settings screen (from the landing menu) + shared back button */
.settings-screen .settings-menu { display: flex; flex-direction: column; gap: 12px; width: 280px; }
.settings-menu .settings-row {
  font-family: var(--font-display); font-size: 1.05rem; letter-spacing: .04em; cursor: pointer;
  padding: 12px 16px; border-radius: 10px; color: var(--gold-bright); text-align: center;
  border: 2px solid transparent;
  background: linear-gradient(155deg, #43351a, #241b0d) padding-box, var(--gilt-dark) border-box;
}
.settings-menu .settings-row.on { color: #14151a; background: var(--gold); border-color: var(--gold); }
.settings-menu .settings-row:hover { background: linear-gradient(155deg, #5a451e, #33270f) padding-box, var(--gilt-lit) border-box; }
.settings-menu .settings-row.on:hover { background: var(--gold-bright); }
/* The language row matches its sibling pills instead of a naked native
   <select> glued to a bare label (user, 2026-07-14: "horrible shape"). */
.settings-language {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 10px 14px; border-radius: 10px;
  font-family: var(--font-display); font-size: 1.02rem; letter-spacing: .04em;
  color: var(--gold-bright);
  border: 2px solid transparent;
  background: linear-gradient(155deg, #43351a, #241b0d) padding-box, var(--gilt-dark) border-box;
}
.settings-locale {
  appearance: none; -webkit-appearance: none; cursor: pointer;
  min-width: 128px; padding: 6px 30px 6px 10px; border-radius: 8px;
  font: 600 .9rem var(--font-body); letter-spacing: .02em;
  color: var(--bone); border: 1px solid var(--came);
  background:
    linear-gradient(45deg, transparent 50%, var(--gold) 50%) calc(100% - 17px) 52% / 7px 7px no-repeat,
    linear-gradient(135deg, var(--gold) 50%, transparent 50%) calc(100% - 10px) 52% / 7px 7px no-repeat,
    var(--lead);
}
.settings-locale:focus { outline: 1px solid var(--gold); border-color: var(--gold); }
.settings-locale option { background: var(--lead); color: var(--bone); font-family: var(--font-body); }
.menu-back {
  margin-top: 22px; cursor: pointer; font-family: var(--font-display); letter-spacing: .05em;
  font-size: .95rem; color: var(--gold-bright); padding: 8px 20px; border-radius: 9px;
  border: 2px solid transparent;
  background: linear-gradient(var(--lead-2), var(--lead-2)) padding-box, var(--gilt-dark) border-box;
}
.menu-back:hover { background: linear-gradient(var(--lead-2), var(--lead-2)) padding-box, var(--gilt-lit) border-box; }

/* --- deck builder (Phase 3) --- */
.deck-builder { display: flex; flex-direction: column; height: 100vh; padding: 10px 14px; gap: 10px; box-sizing: border-box; }
.db-head { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.db-title { font-family: var(--font-display); font-size: 1.25rem; letter-spacing: .06em; color: var(--gold-bright); }
.db-count {
  font-family: var(--font-display); font-size: 1.05rem; padding: 2px 12px; border-radius: 999px;
  border: 1px solid rgba(227,180,94,.5); color: #d7c49a;
}
.db-count.valid { color: #14151a; background: var(--gold); border-color: var(--gold); }
.db-btn {
  font-family: var(--font-display); letter-spacing: .05em; cursor: pointer;
  padding: 5px 14px; border-radius: 8px; color: var(--gold-bright);
  border: 2px solid transparent;
  background: linear-gradient(var(--lead-2), var(--lead-2)) padding-box, var(--gilt-dark) border-box;
}
.db-btn:hover { background: linear-gradient(var(--lead-2), var(--lead-2)) padding-box, var(--gilt-lit) border-box; }
.db-btn.play { color: #14151a; background: var(--gold); border-color: var(--gold); }
.db-btn.play.disabled, .db-btn.play:disabled { opacity: .4; cursor: default; }
/* action group (Auto-fill · Clear · Save) sits together at the right; the
   header reserves space so Save never slips under the top-right chrome
   (Back + settings cog) — user #2. */
.db-actions { display: flex; align-items: center; gap: 12px; margin-left: auto; }
.db-head { padding-right: 172px; }
/* deck-builder filter bar */
.db-filters { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 14px; margin: 2px 0 4px; }
.db-filter-group { display: flex; align-items: center; gap: 4px; }
.db-filter-label { font-family: var(--font-display); font-size: .72rem; letter-spacing: .06em; color: var(--gold-bright); margin-right: 2px; }
.db-chip {
  cursor: pointer; font-family: var(--font-body); font-weight: 600; font-size: .74rem;
  padding: 3px 9px; border-radius: 999px; color: #cfc7b2;
  border: 1px solid rgba(227,180,94,.35); background: rgba(4,6,9,.4);
  transition: background .12s var(--ease-out), color .12s var(--ease-out), border-color .12s var(--ease-out);
}
.db-chip:hover { border-color: var(--gold); color: var(--gold-bright); }
.db-chip.active { color: #14151a; background: var(--gold); border-color: var(--gold); }
.db-body { display: flex; gap: 12px; flex: 1; min-height: 0; }
.db-deck-strip {
  width: 230px; flex-shrink: 0; overflow-y: auto; padding: 6px;
  border: 1px solid rgba(227,180,94,.25); border-radius: 10px; background: rgba(4,6,9,.4);
}
.db-deck-row {
  display: flex; align-items: center; gap: 8px; padding: 3px 6px; cursor: pointer;
  border-radius: 6px; font-size: .82rem;
}
.db-deck-row:hover { background: rgba(196,31,63,.22); } /* hover = "click to remove" */
.db-row-cost {
  width: 20px; height: 20px; flex-shrink: 0; display: grid; place-items: center; border-radius: 50%;
  font-family: var(--font-display); font-size: .72rem; color: #fbf5e2;
  background: radial-gradient(circle at 36% 30%, var(--lapis-hi), var(--lapis-lo));
}
.db-row-name { flex: 1; color: #e6dcc4; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.db-row-count { color: var(--gold-bright); font-family: var(--font-display); }
.db-empty { opacity: .6; font-size: .82rem; padding: 10px; line-height: 1.4; }
.db-pool {
  flex: 1; overflow-y: auto; display: grid; gap: 8px;
  grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); align-content: start; padding: 4px;
}
.pool-tile {
  position: relative; cursor: pointer; border: 3px solid transparent; border-radius: 10px;
  background: linear-gradient(var(--lead), var(--lead)) padding-box, var(--gilt-dark) border-box;
  padding: 5px; display: flex; flex-direction: column; gap: 2px; align-items: center;
  transition: transform .15s var(--ease-out);
}
/* signal hover with a lift + glow, and in-deck with a gold selection ring. */
.pool-tile:hover { transform: translateY(-3px); box-shadow: 0 0 0 1px #3a2c0e, 0 0 14px rgba(255,181,71,.4); }
.pool-tile.in-deck { box-shadow: 0 0 0 2px var(--gold), 0 0 12px rgba(255,181,71,.45); }
.pool-art {
  width: 100%; height: 60px; border-radius: 6px; background-size: cover; background-position: center top;
  background-color: var(--card-bg);
}
.pool-tile .cost {
  position: absolute; top: -8px; left: -8px; width: 24px; height: 24px; font-size: .78rem;
}
.pool-name { font-size: .62rem; text-align: center; line-height: 1.05; color: #e6dcc4; }
.pool-type { font-size: .52rem; text-transform: uppercase; letter-spacing: .04em; opacity: .6; }
.pool-count {
  position: absolute; top: -8px; right: -8px; background: var(--gold); color: #14151a;
  font-family: var(--font-display); font-size: .72rem; padding: 1px 6px; border-radius: 999px;
}
.pool-remove {
  position: absolute; bottom: 4px; right: 4px; width: 20px; height: 20px; border-radius: 50%;
  border: none; cursor: pointer; background: rgba(196,31,63,.85); color: #fff; font-size: 1rem; line-height: 1;
}
.pool-remove:hover { background: #c41f3f; }

/* --- mulligan screen (Phase 3) --- */
.mulligan {
  min-height: 90vh; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 18px;
}
.mull-title { font-family: var(--font-display); font-size: 2rem; letter-spacing: .1em; color: var(--gold-bright); }
.mull-sub { opacity: .85; font-size: .95rem; }
.mull-hand { display: flex; gap: 18px; flex-wrap: wrap; justify-content: center; }
.mull-card { position: relative; cursor: pointer; transition: transform .18s var(--ease-out); }
/* mulligan uses the shared fixed reading-card size, scaled down so the 3-card
   opening hand + title + confirm button all fit the 407px viewport height. */
.card.mull-card { zoom: .7; }
.mull-card:hover { transform: translateY(-8px); }
.mull-card .mull-stamp {
  position: absolute; inset: 0; display: none; place-items: center; z-index: 6; border-radius: inherit;
  font-family: var(--font-display); font-size: 1.4rem; letter-spacing: .1em; color: #fff;
  background: rgba(120,20,30,.55); text-shadow: 0 2px 6px rgba(0,0,0,.9);
}
.mull-card.replacing { filter: grayscale(.5) brightness(.7); }
.mull-card.replacing .mull-stamp { display: grid; }
.mull-confirm {
  font-family: var(--font-display); font-size: 1.15rem; letter-spacing: .06em; cursor: pointer;
  padding: 10px 28px; border-radius: 10px; color: #14151a; background: var(--gold); border: 2px solid var(--gold);
}
.mull-confirm:hover { box-shadow: 0 0 16px rgba(255,181,71,.6); }

/* quality floor: reduced motion kills the CSS loops; the can-attack signal
   survives as a static bright frame + steady halo */
@media (prefers-reduced-motion: reduce) {
  .devotion-channel-line, .poison-aura::after, .hero-adamant-energy { animation: none !important; }
  .card-art::before, .hero-portrait::before, .preview-art::before,
  .minion-art, .board.active-side, .shield-dome,
  .card.playable::after, .card.static::after,
  .minion.can-attack,
  body.playing.board-lava::before, body.playing.board-snow::before,
  body.playing.board-desert::before { animation: none !important; }
  .minion.can-attack {
    box-shadow: 0 0 0 1px #3a2c0e, 0 0 24px rgba(255,181,71,.5), 0 5px 14px rgba(0,0,0,.55);
  }
  /* menus: no entrance fade or hover lift */
  .class-select, .deck-builder, .socket-reveal, .announce-inspect { animation: none !important; }
  .mode-option, .class-option { transition: none !important; }
  .mode-option:hover, .mode-option:focus-visible,
  .class-option:hover, .class-option:focus-visible { transform: none !important; }
}

/* --- Adventure mode: worldmap / region panel / collection / spoils --------- */
/* The worldmap is its own full-viewport stage over the generated continent
   art; its town gallery and town pages scroll independently below the header. */
.worldmap {
  position: fixed; inset: 0; z-index: 40;
  display: flex; flex-direction: column;
  background:
    radial-gradient(ellipse at 50% 40%, rgba(8,12,16,.10) 0%, rgba(6,9,12,.28) 65%, rgba(3,5,8,.55) 100%),
    url("../assets/worldmap.webp") center / cover no-repeat,
    radial-gradient(circle at 50% 40%, var(--felt), var(--felt-2));
  animation: screen-fade .2s var(--ease-out);
}
.wm-head {
  display: flex; align-items: center; gap: 16px; padding: 10px 18px;
  background: linear-gradient(rgba(10,11,14,.82), rgba(10,11,14,.55) 80%, transparent);
}
.wm-brand { font-size: 1.6rem; margin: 0; }
.wm-progress {
  position: relative; flex: 1 1 auto; max-width: 460px; height: 18px;
  border: 1px solid var(--came); border-radius: 9px; overflow: hidden;
  background: rgba(12,13,17,.8);
}
.wm-progress-fill {
  height: 100%; border-radius: 8px;
  background: linear-gradient(90deg, #6d5626, var(--gold), var(--gold-bright));
  transition: width .4s var(--ease-out);
}
.wm-progress-label {
  position: absolute; inset: 0; display: grid; place-items: center;
  font-family: var(--font-chrome); font-size: .68rem; letter-spacing: .08em;
  color: var(--bone); text-shadow: 0 1px 2px #000;
}
.wm-btns { margin-left: auto; display: flex; gap: 8px; }
.wm-town-list, .wm-town-page {
  flex: 1 1 auto; min-width: 0; min-height: 0; overflow-y: auto; overflow-x: hidden;
  padding: 12px clamp(18px, 5vw, 72px) 40px;
}
/* the intro sits on raw map art — it needs its own scrim to read
   (personal sweep review, 2026-07-14) */
.wm-town-intro {
  max-width: 720px; margin: 0 auto 14px; text-align: center;
  padding: 8px 20px 10px; border-radius: 12px;
  background: rgba(8, 10, 14, .74); box-shadow: 0 0 0 1px rgba(227, 180, 94, .25);
}
.wm-town-eyebrow {
  display: block; font-family: var(--font-chrome); font-size: .68rem;
  letter-spacing: .18em; text-transform: uppercase; color: var(--amber);
}
.wm-town-heading {
  margin: 3px 0; font-family: var(--font-display); font-size: clamp(1.6rem, 3vw, 2.5rem);
  font-weight: 500; color: var(--gold-bright); text-shadow: 0 2px 12px #000;
}
.wm-town-copy { margin: 0; color: #cfc7b2; text-shadow: 0 1px 2px #000; }
.wm-town-grid {
  width: min(1180px, 100%); margin: 0 auto;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(min(260px, 100%), 1fr)); gap: 12px;
}
.wm-town-card {
  min-width: 0; display: flex; flex-direction: column; text-align: left;
  cursor: pointer; color: var(--bone); overflow: hidden;
  background: linear-gradient(135deg, rgba(27,29,34,.94), rgba(12,13,17,.88));
  border: 1px solid var(--came); border-radius: 12px;
  box-shadow: 0 5px 18px rgba(0,0,0,.38); transition: border-color .15s, transform .15s;
}
.wm-town-card:hover:not(:disabled) { transform: translateY(-3px); border-color: var(--gold); }
.wm-town-card.locked { opacity: .5; cursor: default; }
.wm-town-card.locked .wm-town-thumb { filter: grayscale(.7) brightness(.5); }
.wm-town-card.cleared {
  border-color: var(--gold-bright);
  background: linear-gradient(135deg, rgba(81,64,27,.94), rgba(18,17,13,.9));
  box-shadow: 0 0 0 1px rgba(244,203,99,.35), 0 5px 18px rgba(0,0,0,.38);
}
.wm-town-card.cleared .wm-town-thumb::after {
  background: linear-gradient(180deg, rgba(201,154,49,.2), rgba(12,13,17,.88));
}
.wm-town-thumb {
  position: relative; display: block; height: 118px; background-repeat: no-repeat;
  border-bottom: 1px solid var(--came);
}
.wm-town-thumb::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(12,13,17,0) 32%, rgba(12,13,17,.85));
}
.wm-town-glyph {
  position: absolute; top: 8px; left: 9px; z-index: 1; font-size: 1.2rem;
  color: var(--gold-bright); text-shadow: 0 2px 6px rgba(0,0,0,.9);
}
.wm-town-complete {
  position: absolute; top: 8px; right: 9px; z-index: 2; display: block;
  padding: 4px 7px; border: 1px solid var(--gold-bright); border-radius: 3px;
  background: rgba(27,24,15,.88); color: var(--gold-bright);
  font-family: var(--font-chrome); font-size: .58rem; font-weight: 700;
  letter-spacing: .09em; line-height: 1; text-transform: uppercase;
  text-shadow: 0 1px 2px #000; box-shadow: 0 1px 5px rgba(0,0,0,.65);
}
.wm-town-card-mid { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; padding: 11px 13px; }
.wm-town-name {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-family: var(--font-display); font-size: 1.05rem; color: var(--gold-bright);
}
.wm-town-region { font-family: var(--font-chrome); font-size: .62rem; letter-spacing: .06em; color: var(--ash); }
.wm-town-progress { font-family: var(--font-chrome); font-size: .64rem; letter-spacing: .06em; color: var(--amber); }
.wm-town-page { display: flex; flex-direction: column; }
.wm-town-page-head {
  width: min(1120px, 100%); margin: 0 auto 18px; display: grid;
  grid-template-columns: 1fr auto 1fr; align-items: center; gap: 18px;
}
.wm-town-back { justify-self: start; }
.wm-town-page-title { display: flex; align-items: center; justify-content: center; gap: 14px; }
.wm-town-page-banner {
  position: relative; flex: 0 0 auto; width: 88px; height: 58px; border-radius: 8px;
  background-repeat: no-repeat; border: 1px solid var(--gold); box-shadow: 0 3px 12px rgba(0,0,0,.5);
}
.wm-town-page-glyph { position: absolute; inset: 0; display: grid; place-items: center; font-size: 1.5rem; color: var(--gold-bright); text-shadow: 0 2px 6px rgba(0,0,0,.9); }
.wm-town-page-title-text { min-width: 0; text-align: left; }
.wm-town-page-title .wm-town-heading { white-space: nowrap; }
.wm-town-page-progress {
  justify-self: end; font-family: var(--font-chrome); font-size: .72rem;
  letter-spacing: .08em; color: var(--amber);
}
.wm-map-grid {
  width: min(1120px, 100%); min-height: 0; margin: 0 auto; padding: 4px;
  overflow-y: auto; display: grid; gap: 12px;
  grid-template-columns: repeat(auto-fill, minmax(min(210px, 100%), 1fr));
}
.wm-map-tile {
  min-width: 0; display: flex; flex-direction: column; text-align: left; cursor: pointer;
  color: var(--bone); overflow: hidden;
  background: linear-gradient(135deg, rgba(22,24,29,.92), rgba(12,13,17,.9));
  border: 1px solid var(--came); border-radius: 10px;
  box-shadow: 0 4px 14px rgba(0,0,0,.4); transition: border-color .15s, transform .15s;
}
.wm-map-tile:hover:not(:disabled) { transform: translateY(-2px); border-color: var(--gold); }
.wm-map-tile.locked { opacity: .5; cursor: default; }
.wm-map-tile.locked .wm-map-tile-thumb { filter: grayscale(.7) brightness(.5); }
.wm-map-tile.cleared { border-color: var(--gold); }
.wm-map-tile.boss { border-color: var(--ruby); }
.wm-map-tile.boss.cleared { border-color: var(--came); }
.wm-map-tile-thumb {
  position: relative; display: block; height: 92px; background-repeat: no-repeat;
  border-bottom: 1px solid var(--came);
}
.wm-map-tile-thumb::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(12,13,17,0) 35%, rgba(12,13,17,.82));
}
.wm-map-tile-kind { position: absolute; top: 6px; left: 8px; z-index: 1; font-size: 1rem; color: var(--gold-bright); text-shadow: 0 2px 5px rgba(0,0,0,.9); }
.wm-map-tile-state { position: absolute; top: 6px; right: 8px; z-index: 1; font-size: .85rem; color: var(--bone); text-shadow: 0 2px 5px rgba(0,0,0,.9); }
.wm-map-tile.cleared .wm-map-tile-state { color: var(--gold); }
.wm-map-tile-info { flex: 1 1 auto; display: flex; flex-direction: column; gap: 2px; min-width: 0; padding: 9px 11px; }
.wm-map-name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-family: var(--font-display); font-size: .92rem; color: var(--gold-bright); }
.wm-map-boss { font-family: var(--font-chrome); font-size: .6rem; letter-spacing: .05em; color: var(--ruby-hi); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.wm-map-tier { font-size: .55rem; color: var(--amber); letter-spacing: .1em; }

/* collection reuses the deck-builder shell; cells add a copies badge */
.collection-grid { display: flex; flex-wrap: wrap; gap: 14px; align-content: flex-start; }
.coll-cell { position: relative; }
.coll-count {
  position: absolute; right: -6px; top: -6px; z-index: 2;
  font-family: var(--font-display); font-size: .8rem; color: var(--gold-bright);
  background: rgba(12,13,17,.9); border: 1px solid var(--gold); border-radius: 999px;
  padding: 2px 8px;
}

/* spoils cards flip up one after another */
.rewards {
  position: fixed; inset: 0; z-index: 60;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 18px;
  background: radial-gradient(ellipse at 50% 40%, rgba(20,22,28,.9), rgba(5,7,10,.97));
  animation: screen-fade .25s var(--ease-out);
}
.rewards-sub { font-family: var(--font-chrome); color: var(--ash); letter-spacing: .06em; }
.rewards-essence {
  font-family: var(--font-display); font-size: .9rem; letter-spacing: .06em;
  color: var(--gold); background: var(--lead-2); border: 1px solid var(--came);
  border-radius: 999px; padding: 4px 12px;
}
.rewards-row {
  display: flex; flex-wrap: wrap; justify-content: center; gap: 16px 18px;
  width: min(1760px, calc(100vw - 48px));
}
.reward-card { opacity: 0; animation: reward-flip .5s var(--ease-out) forwards; }
@keyframes reward-flip {
  from { opacity: 0; transform: translateY(26px) rotateY(80deg) scale(.9); }
  60%  { opacity: 1; transform: translateY(-6px) rotateY(-8deg) scale(1.03); }
  to   { opacity: 1; transform: translateY(0) rotateY(0) scale(1); }
}
@media (prefers-reduced-motion: reduce) {
  .worldmap, .rewards { animation: none !important; }
  .reward-card { animation: none !important; opacity: 1; }
}

@media (max-width: 700px) {
  .wm-head { flex-wrap: wrap; }
  .wm-progress { order: 3; flex-basis: 100%; max-width: none; }
  .wm-btns { gap: 4px; }
  .wm-town-page-head { grid-template-columns: 1fr auto; }
  .wm-town-page-title { grid-column: 1 / -1; grid-row: 1; }
  .wm-town-back { grid-column: 1; grid-row: 2; }
  .wm-town-page-progress { grid-column: 2; grid-row: 2; }
}

/* Responsive board pass: the stage still fits as one proportional object, but
   smaller natural cards/minions keep its fit scale high enough to read on a
   1366px laptop instead of shrinking the whole table into the centre. */
@media (max-width: 1366px) {
  body.playing #app { width: min(96vw, 1280px); gap: 8px; }
  body.playing #left-rail { max-width: 280px; }
  body.playing #right-rail { max-width: 290px; }
  body.playing #log-panel { height: clamp(145px, 27vh, 250px); max-width: 270px; }

  .board { min-height: 104px; gap: 6px; padding: 6px; }
  .board .minion {
    width: 116px; height: 154px; padding: 3px; border-width: 4px;
    border-radius: 26px 26px 7px 7px; font-size: .76rem;
  }
  .board .minion .minion-name { font-size: .72rem; margin-bottom: 17px; }
  .board .minion .attr-row { margin-bottom: 2px; }
  .board .minion .stat { width: 27px; height: 27px; font-size: .9rem; }

  .hand { min-height: 172px; padding-bottom: 28px; }
  .hand .card { margin-right: -10px; margin-left: -10px; }
  .card { width: 142px; height: 210px; padding: 6px; border-width: 5px; }
  .card-art { height: 74px; margin-bottom: 5px; }
  .card-name { font-size: .8rem; padding-top: 3px; padding-bottom: 3px; }
  .card-text { font-size: .84rem; padding-bottom: 15px; }
  .cost { width: 30px; height: 30px; font-size: 1rem; }
  .stat { width: 29px; height: 29px; font-size: .95rem; }

  .hero-overlay.me { transform: scale(.92); }
  .hero-overlay.foe { transform: translateX(-50%) scale(.92); }
  .equipment-row { grid-template-columns: repeat(4, 42px); gap: 4px; }
  .equip-slot { width: 42px; min-height: 42px; }

  .db-deck-strip { width: 210px; }
}

/* Tablet chrome keeps the playing surface central while the persistent hero,
   log, action orb, and builder panels stay within the viewport. */
@media (max-width: 1024px) {
  body.playing #app { width: 98vw; top: 52%; gap: 6px; }
  body.playing #left-rail { max-width: 220px; }
  body.playing #right-rail { max-width: 230px; bottom: 4px; }
  body.playing #log-panel { height: clamp(130px, 25vh, 210px); max-width: 220px; }

  .board { min-height: 88px; gap: 4px; padding: 4px; }
  .board .minion {
    width: 92px; height: 126px; padding: 3px; border-width: 3px;
    border-radius: 21px 21px 6px 6px; font-size: .7rem;
  }
  .board .minion .minion-name { font-size: .7rem; margin-bottom: 15px; }
  .board .minion .attr-row { gap: 3px; margin-bottom: 1px; }
  .board .minion .attr-badge { width: 19px; height: 19px; font-size: .66rem; }
  .board .minion .stat { bottom: 2px; width: 24px; height: 24px; font-size: .78rem; }
  .board .minion .stat.atk { left: 2px; }
  .board .minion .stat.hp { right: 2px; }

  .hand { min-height: 148px; padding-bottom: 24px; }
  .hand .card { margin-right: -14px; margin-left: -14px; }
  .card { width: 118px; height: 176px; padding: 5px; border-width: 4px; }
  .card-art { height: 60px; margin-bottom: 4px; }
  .card-name { font-size: .74rem; line-height: 1.1; padding: 2px 1px; margin-bottom: 2px; }
  .card-text { font-size: .75rem; line-height: 1.2; padding-bottom: 12px; }
  .card-tags { margin-top: 2px; }
  .card-type-tag { font-size: .7rem; padding: 1px 6px; }
  .equip-meta { font-size: .7rem; margin-top: 2px; }
  .cost { top: -8px; left: -8px; width: 27px; height: 27px; font-size: .88rem; }
  .stat { bottom: -7px; width: 26px; height: 26px; font-size: .82rem; }
  .stat.atk { left: -8px; }
  .stat.hp { right: -8px; }

  .hero-overlay.me { left: 8px; bottom: 6px; transform: none; }
  .hero-overlay.me .hero { flex-direction: column; align-items: center; gap: 6px; }
  .hero-medallion, .hero-portrait { width: 72px; height: 72px; }
  .hero-health { min-width: 30px; height: 27px; font-size: 1rem; }
  .hero-power { width: 29px; height: 29px; font-size: .84rem; }
  .hero-name { font-size: .95rem; }
  .mana-pips { max-width: 120px; gap: 2px; }
  .mana-pip { width: 9px; height: 9px; }
  .equipment-row { grid-template-columns: repeat(4, 36px); gap: 3px; margin-right: 0; }
  .equip-slot { width: 36px; min-height: 36px; font-size: .84rem; }
  .equip-icon { font-size: .88rem; }
  .equip-name { font-size: .52rem; }
  .aura-line { font-size: .7rem; }

  .midbar { min-height: 32px; gap: 6px; padding-right: 88px; font-size: .78rem; }
  .midbar .hint { display: none; }
  .midbar .turn-banner { font-size: .95rem; padding: 4px 10px; }
  .end-turn-orb {
    /* was capped at 78px — half the art's painted socket on a phone; the orb
       should fill it (user, 2026-07-13: +50% on mobile) */
    left: calc(var(--orb-x, calc(100vw - 90px)) - min(var(--orb-d, 94px), 120px) / 2);
    top: calc(var(--orb-y, 50vh) - min(var(--orb-d, 94px), 120px) / 2);
    width: min(var(--orb-d, 94px), 120px); height: min(var(--orb-d, 94px), 120px);
    font-size: clamp(.78rem, 2.4vw, 1rem);
  }
  .settings { top: 10px; right: 12px; }
  .settings-gear { width: 36px; height: 36px; font-size: 1.05rem; }

  /* class-select keeps its base art-dominant 6x2 grid at every width (user,
     2026-07-14: all 12 on one screen, no scroll) — no column/height override. */
  .mode-option { width: 246px; padding: 10px 16px; }

  .deck-builder { padding: 8px; gap: 8px; }
  .db-body { gap: 8px; }
  .db-deck-strip { width: 180px; }
  .db-pool { min-width: 0; gap: 6px; grid-template-columns: repeat(auto-fill, minmax(82px, 1fr)); }
}

/* Phone and small-tablet chrome stays clear of display cutouts. These rules
   remain queried so the approved desktop composition is unchanged. */
@media (max-width: 900px) {
  html, body { width: 100%; max-width: 100%; overflow-x: hidden; }
  * { -webkit-tap-highlight-color: transparent; }
  button, [role="button"], .card, .minion, .hero, .equip-slot,
  .end-turn-orb, .settings-gear { touch-action: manipulation; }

  body.playing #app { width: 98vw; top: 50%; gap: 4px; }
  body.playing #left-rail { left: 0; top: env(safe-area-inset-top); max-width: 150px; }
  body.playing #right-rail { right: env(safe-area-inset-right); bottom: env(safe-area-inset-bottom); max-width: 160px; }
  body.playing #log-panel {
    width: 136px; height: clamp(90px, 24vh, 130px);
    margin: calc(10px + env(safe-area-inset-top)) 6px 10px calc(8px + env(safe-area-inset-left));
  }
  .log-panel-title { padding: 8px 7px 4px; font-size: .66rem; }
  .log-scroll { padding: 5px 8px 8px; font-size: .72rem; line-height: 1.25; }

  .board { min-height: 72px; gap: 3px; padding: 3px; }
  .board .minion {
    width: 76px; height: 104px; padding: 2px; border-width: 3px;
    border-radius: 18px 18px 5px 5px; font-size: .62rem;
  }
  .board .minion .minion-name { font-size: .6rem; margin-bottom: 13px; padding: 1px 2px; }
  .board .minion .attr-row { gap: 2px; margin-bottom: 1px; }
  .board .minion .attr-badge { width: 16px; height: 16px; font-size: .56rem; }
  .board .minion .stat { width: 21px; height: 21px; font-size: .68rem; }

  .hand { min-height: 116px; padding-bottom: 18px; margin-top: 0; }
  .hand .card { margin-right: -13px; margin-left: -13px; }
  .card { width: 86px; height: 128px; padding: 3px; border-width: 3px; }
  .card-art { height: 43px; margin-bottom: 2px; }
  .card-name { font-size: .6rem; line-height: 1; padding: 1px; margin-bottom: 1px; }
  .card-text { font-size: .6rem; line-height: 1.08; padding-bottom: 9px; }
  .card-tags, .equip-meta { display: none; }
  .cost { top: -6px; left: -6px; width: 23px; height: 23px; font-size: .72rem; }
  .stat { bottom: -5px; width: 22px; height: 22px; font-size: .7rem; }
  .stat.atk { left: -6px; }
  .stat.hp { right: -6px; }

  .hero-overlay.foe { top: calc(4px + env(safe-area-inset-top)); }
  .hero-overlay.me {
    left: calc(4px + env(safe-area-inset-left));
    bottom: calc(4px + env(safe-area-inset-bottom)); transform: none;
  }
  .hero-overlay.me .hero { gap: 4px; }
  .hero-medallion, .hero-portrait { width: 56px; height: 56px; }
  .hero-health { min-width: 25px; height: 23px; font-size: .82rem; }
  .hero-power { width: 25px; height: 25px; font-size: .72rem; }
  .hero-name { font-size: .75rem; }
  .mana-pips { max-width: 90px; gap: 1px; }
  .mana-pip { width: 7px; height: 7px; }
  .equipment-row { grid-template-columns: repeat(4, 29px); gap: 2px; }
  .equip-slot { width: 29px; min-height: 29px; }
  .aura-line, .hero-counts { font-size: .58rem; }

  .midbar {
    min-height: 28px; gap: 4px;
    padding-left: env(safe-area-inset-left);
    padding-right: calc(70px + env(safe-area-inset-right)); font-size: .68rem;
  }
  .midbar .turn-banner { font-size: .76rem; padding: 3px 7px; }
}

/* Short landscape phones need a shallower natural stage before view.js fits it
   into the vertical clearance between the two fixed hero plates. */
@media (max-width: 900px) and (orientation: landscape) and (max-height: 500px) {
  body.playing #app { gap: 2px; }
  .board { min-height: 58px; gap: 2px; padding: 2px; }
  .board .minion { width: 66px; height: 88px; }
  .board .minion .minion-name { font-size: .56rem; margin-bottom: 12px; }
  /* half a card (112px/2) further down — rides the stage scale (user, 2026-07-13) */
  .hand { min-height: 94px; padding-bottom: 14px; transform: translateY(56px); }

  .card { width: 78px; height: 112px; }
  .card-art { height: 36px; }
  .card-text { font-size: .56rem; }
  .midbar { min-height: 24px; }
  body.playing #log-panel { height: 88px; margin-top: calc(8px + env(safe-area-inset-top)); }
}

@media (max-width: 640px) {
  body.playing #app { width: 100vw; }
  .board .minion { width: 60px; height: 82px; }
  .hand .card { margin-right: -16px; margin-left: -16px; }
  .hero-medallion, .hero-portrait { width: 50px; height: 50px; }
  body.playing #log-panel { width: 116px; }
}

/* The builder is a menu, so portrait phones reflow its independent panels
   instead of inheriting the board's landscape-oriented proportions. */
@media (max-width: 390px) {
  .deck-builder { height: 100dvh; }
  .db-head { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px; }
  .db-title { grid-column: 1 / -1; }
  .db-count, .db-btn {
    min-height: 44px; box-sizing: border-box; display: flex; align-items: center; justify-content: center;
  }
  .db-btn { padding: 5px 8px; }
  .db-btn:last-child { grid-column: 1 / -1; margin-left: 0; }

  .db-filters { gap: 6px; }
  .db-filter-group { flex-wrap: wrap; gap: 4px; }
  .db-chip { min-height: 44px; box-sizing: border-box; }

  .db-body { flex-direction: column; gap: 8px; min-width: 0; }
  .db-deck-strip { width: auto; flex: 0 0 96px; }
  .db-pool { width: 100%; grid-template-columns: repeat(auto-fit, minmax(82px, 1fr)); }
}

/* Touch devices: the duel surface is game UI, not a document — stray drags
   must not select text, and taps must not double-tap zoom. Menus keep normal
   browser behavior. */
body.in-duel {
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}
body.in-duel .card, body.in-duel .minion, body.in-duel .hero,
body.in-duel .hand, body.in-duel .board { touch-action: manipulation; }
/* Draggables must own their touches outright or the browser pans instead of
   letting touch-drag.js track the finger. */
body.playing .hand .card, body.playing .board .minion,
body.playing .hero-medallion { touch-action: none; }

/* touch-drag.js: the ghost card riding above the finger, and the live drop
   target under it. */
.touch-drag-ghost {
  position: fixed; z-index: 1200; pointer-events: none;
  opacity: .92; will-change: transform;
  filter: drop-shadow(0 10px 18px rgba(0, 0, 0, .55));
}
body.touch-dragging .drag-origin { opacity: .35; }
.drop-hover { box-shadow: 0 0 0 3px var(--gold-bright), 0 0 18px rgba(235, 187, 84, .8) !important; }

/* Herald + Chronicle column (user, 2026-07-14): one canonical left rail.
   Above the hero medallion (z 16→17: announcements must never hide behind
   the avatar), announcements OVERLAY the chronicle (absolute, no layout
   push) and announce.js drops each card down into the feed when it leaves.
   The rail itself never eats taps; only the chron tiles do. */
body.playing #left-rail {
  /* wider for paired announcements; BOUNDED above the hero corner so
     announcements can never overlay the avatar (user, 2026-07-14) */
  width: 230px; max-width: none; z-index: 17;
  top: 8px; bottom: 140px; height: auto;
  pointer-events: none; position: fixed; overflow: hidden;
}
.announce-stack {
  position: fixed; top: 12px; left: 12px; z-index: 38;
  display: flex; flex-direction: column; align-items: flex-start; gap: 10px;
  max-height: calc(100vh - 24px); overflow: hidden;
  pointer-events: auto;
}
.card-announce { cursor: zoom-in; outline: none; }
.card-announce:focus-visible { outline: 2px solid var(--gold-bright); outline-offset: 4px; }
.announce-move { display: flex; align-items: center; gap: 12px; }
.announce-impact {
  flex: 0 0 auto; min-width: 38px; height: 38px; padding: 0 7px; border-radius: 999px;
  display: grid; place-items: center;
  font-family: var(--font-display); font-size: .95rem; letter-spacing: .02em;
  color: var(--gold-bright); background: rgba(10,13,18,.94); border: 1px solid var(--gold);
  box-shadow: 0 2px 8px rgba(0,0,0,.6);
}
.announce-impact.damage { color: #ff9d7a; border-color: #c34a36; }
.announce-impact.heal { color: #8fe3a1; border-color: #3f9e3f; }
.announce-hero-face {
  flex: 0 0 auto; width: 112px; height: 112px; border-radius: 50%;
  background-size: cover; background-position: center top;
  border: 2px solid var(--gold); box-shadow: 0 0 0 2px #08090c, 0 2px 8px rgba(0,0,0,.6);
}
.announce-inspect {
  position: fixed; inset: 0; z-index: 1300; display: grid; place-items: center;
  padding: 28px; cursor: zoom-out; background: radial-gradient(ellipse at center, rgba(6,8,12,.72), rgba(3,4,7,.94));
  backdrop-filter: blur(4px); animation: reveal-fade .16s var(--ease-out);
}
.announce-inspect-panel { cursor: default; max-width: 100%; outline: none; }
.announce-inspect .announce-move { justify-content: center; gap: 28px; }
.announce-inspect .announce-impact { min-width: 48px; height: 48px; font-size: 1.12rem; }
.announce-inspect .announce-hero-face { width: 164px; height: 164px; }
body.playing #chronicle-feed { position: relative; z-index: 1; }

/* The stage rides the divider, not the other way around: its vertical
   anchor is derived so the seam between the two board rows sits ON the
   fixed 50% hairline (--stage-seam-shift, view.js fitAppToViewport).
   Late in the file to beat the per-width top:5x% tier rules. The hand also
   drops half a card so the player's row gets clear air under the divider
   (user, 2026-07-14; promoted out of the phone media block). */
body.playing #app { top: calc(50svh - var(--stage-seam-shift, 4vh)); }
body.playing .hand { transform: translateY(0px); } /* lowered ~10% of screen from -40px — user */

/* The player's corner, fully SEPARATED (user, 2026-07-14): the hero overlay
   holds ONLY the avatar core (medallion/name/mana); equipment and the
   hand+deck counts are their own body-level overlays, so a tap on gear or
   the deck can never bubble into the hero's click handler and nothing drags
   or highlights as a cluster. Late in the file to out-cascade the per-width
   overlay rules until CANVAS-1 deletes them. */
.hero-overlay.me { transform: none; bottom: calc(env(safe-area-inset-bottom) + 2px); }
/* canonical medallion size at every width — the 84/72/56/50 tier ladder made
   the fixed gear-overlay anchor overlap the avatar at some widths (user,
   2026-07-14) */
.hero-medallion, .hero-portrait { width: 56px; height: 56px; }
.player-mana-overlay {
  position: fixed; z-index: 16;
  left: 70px; bottom: calc(env(safe-area-inset-bottom) + 30px);
  width: 150px;
}
.player-mana-overlay .mana-pips { max-width: 150px; gap: 2px; justify-content: flex-start; }
.player-mana-overlay .mana-pip { width: 7px; height: 7px; }
.player-mana-overlay .mana-count { margin-left: 2px; font-size: .75rem; }
.gear-overlay {
  position: fixed; z-index: 16;
  left: 70px; bottom: calc(env(safe-area-inset-bottom) + 3px);
  width: 180px; height: 22px;
}
.gear-overlay .hero-gear { position: relative; width: 180px; padding-bottom: 0; }
.gear-overlay .aura-line { position: absolute; bottom: 26px; left: 0; width: 180px; }
.gear-overlay .equipment-row { grid-template-columns: repeat(8, 19px); gap: 4px; width: 180px; height: 22px; margin: 0; }
.gear-overlay .equip-slot {
  width: 19px; min-height: 19px; height: 19px; padding: 0; border-radius: 50%;
  font-size: .68rem; line-height: 1; flex: 0 0 19px;
}
.gear-overlay .equip-slot.empty { opacity: .28; }
.gear-overlay .equip-slot.filled { color: var(--gold-bright); background: radial-gradient(circle at 35% 28%, #fff0a4, #b57718 62%, #513108); box-shadow: 0 0 7px rgba(255,190,66,.72); }
.gear-overlay .equip-slot.blocked { color: #817a69; }
.counts-overlay {
  position: fixed; z-index: 16;
  right: calc(150px + env(safe-area-inset-right));
  bottom: calc(env(safe-area-inset-bottom) + 8px);
}

/* End Turn orb — seated in the board art's carved oval socket, like a glove
   (user, 2026-07-14). The art paints `center / cover fixed`, which is pure
   math, so CSS replays it: --art-s is the cover scale, and the socket's
   image-space circle (measured per board, 1280x768 space) maps to viewport
   coordinates with NO JavaScript. svh keeps it stable under mobile browser
   chrome. Divider + chips end where the orb begins (--orb-right-gap). */
body.playing {
  --art-s: max(calc(100vw / 1280), calc(100svh / 768));
  --sock-x: 1147; --sock-y: 382; --sock-r: 82;
  /* End Turn orb is 20% smaller than the socket (user, 2026-07-14). */
  --orb-d: calc(var(--sock-r) * 2 * var(--art-s) * 0.8);
  --orb-cx: calc(50vw + (var(--sock-x) - 640) * var(--art-s));
  --orb-cy: calc(50svh + (var(--sock-y) - 384) * var(--art-s));
  --orb-right-gap: calc(100vw - var(--orb-cx) + var(--orb-d) / 2 + 12px);
  /* the hairline STOPS just before the orb's near edge — it must not bleed
     behind the End Turn button (user, 2026-07-14). */
  --divider-right: calc(100vw - var(--orb-cx) + var(--orb-d) / 2 + 18px);
}
body.playing.board-lava { --sock-x: 1128; --sock-y: 382; --sock-r: 100; }
body.playing.board-snow { --sock-x: 1164; --sock-y: 386; --sock-r: 98; }
body.playing.board-desert { --sock-x: 1167; --sock-y: 378; --sock-r: 95; }
.end-turn-orb {
  left: calc(var(--orb-cx) - var(--orb-d) / 2);
  top: calc(var(--orb-cy) - var(--orb-d) / 2);
  width: var(--orb-d); height: var(--orb-d);
  font-size: calc(var(--orb-d) * .14); border-width: 3px;
}

/* Portrait blocker REINSTATED (user, 2026-07-14 later: with it removed the
   whole game became playable vertically — 'a whole mess'. Browsers cannot
   truly force landscape, so touch portrait shows the rotate screen again;
   main.js still attempts fullscreen + landscape lock on the first tap).
   Untested by design: the smoke matrix stays 904x407 landscape only. */
@media (orientation: portrait) {
  body.touch-device .rotate-screen {
    position: fixed; inset: 0; z-index: 1001;
    display: grid; grid-template-rows: 1fr auto 1fr; justify-items: center; align-items: center;
    box-sizing: border-box;
    padding: max(32px, env(safe-area-inset-top)) max(24px, env(safe-area-inset-right)) max(32px, env(safe-area-inset-bottom)) max(24px, env(safe-area-inset-left));
    color: var(--bone); background: radial-gradient(circle at center, var(--lead-2), var(--lead));
    border: 12px solid var(--came); box-shadow: inset 0 0 0 2px var(--gold);
    text-align: center;
  }
  .rotate-screen-brand { align-self: start; }
  .rotate-wordmark {
    margin: 0; color: var(--gold); font-family: 'Almendra SC', var(--font-display), serif;
    font-size: clamp(2.2rem, 12vw, 4.2rem); line-height: .9; letter-spacing: .14em;
    text-shadow: 0 3px 20px rgba(0, 0, 0, .8), 0 0 16px rgba(235, 187, 84, .24);
  }
  .rotate-tagline { margin: 12px 0 0; font-family: 'Cormorant Garamond', var(--font-body), serif; font-size: clamp(1.05rem, 5vw, 1.45rem); font-style: italic; }
  .rotate-instructions { display: grid; gap: 12px; }
  .rotate-title { margin: 0; color: var(--gold-bright); font-family: var(--font-display); font-size: clamp(1.4rem, 6.5vw, 2.1rem); letter-spacing: .06em; }
  .rotate-fullscreen-tip { max-width: 22rem; margin: 0; font-family: var(--font-display); font-size: clamp(1rem, 4.6vw, 1.35rem); line-height: 1.35; letter-spacing: .03em; }
  .rotate-device-icon {
    align-self: end; width: min(34vw, 148px); fill: none; stroke: var(--gold-bright); stroke-linecap: round; stroke-linejoin: round; stroke-width: 4;
    filter: drop-shadow(0 0 9px rgba(227, 180, 94, .4)); transform-origin: center;
    animation: rotate-device-prompt 2.8s var(--ease-out, ease-out) infinite;
  }
  .rotate-device-icon circle { fill: var(--gold-bright); stroke: none; }
}

.rotate-screen { display: none; }
@keyframes rotate-device-prompt {
  0%, 20%, 100% { transform: rotate(0); }
  45%, 70% { transform: rotate(90deg); }
}
@media (prefers-reduced-motion: reduce) { .rotate-device-icon { animation: none; } }
