/* Emanation Online — a full-screen table that changes shape between scenes.

   #app[data-mode] is the single switch: lobby, pick, target, lay, resolve,
   results, over. Every region is absolutely positioned against the viewport and
   each mode sets where it sits and how big it is. Because the same elements
   persist across modes, a scene change is a transition rather than a cut.

   What animates between scenes is kept cheap. The hand never changes its
   layout size: it is laid out once at its full (pick) size and scenes move and
   scale it with a transform, which costs no layout and no text reflow. Seats do
   change size, through --seat, but that variable animates on the two seat
   containers only. (It used to animate on #app, where an inherited variable
   restyles every element in the app on every frame of a scene change; on a
   slower laptop that ran at about 20fps.) */

@import url('https://fonts.googleapis.com/css2?family=Crimson+Pro:ital,wght@0,400;0,600;0,700;1,400&family=IBM+Plex+Sans:wght@400;500;600&family=IBM+Plex+Mono:wght@400;500&display=swap');

@property --hand-card { syntax: "<length>"; inherits: true; initial-value: 300px; }
@property --seat { syntax: "<length>"; inherits: true; initial-value: 48px; }
@property --card-h { syntax: "<length>"; inherits: true; initial-value: 240px; }
/* Your seat's height above the floor is one formula in every scene:
   hand height x --me-k + --me-off. Scenes set --me-k-to / --me-off-to on #app
   (a plain jump); .me copies them into the registered pair and animates those,
   so only your seat is restyled while it moves. */
@property --me-k { syntax: "<number>"; inherits: true; initial-value: 1; }
@property --me-off { syntax: "<length>"; inherits: true; initial-value: 58px; }

:root {
  --ink: #0E0B08;
  --ink-2: #17130F;
  --ink-3: #241E17;
  --paper: #F5F1E8;
  --paper-2: #E8E1D2;
  --hairline: #3A3126;
  --gold: #E0B94A;
  --gold-line: #C9931F;
  --gold-dim: #8A6F28;
  --gold-text: #7A5C10;
  --on-ink: #C6BCA8;
  --on-ink-dim: #7E7565;
  --blood: #B4432A;
  --blood-lit: #E0714F;
  --life: #E0B94A;
  --heal: #9FD08A;

  /* Crimson Pro is the brand serif — the launch trailer sets every headline in it. */
  --serif: 'Crimson Pro', Georgia, serif;
  --sans: 'IBM Plex Sans', system-ui, sans-serif;
  --mono: 'IBM Plex Mono', ui-monospace, Menlo, monospace;

  /* Springs from the launch trailer (motion/lib/fx.js), sampled into linear().
     --arrive: stiffness 170, damping 0.62 — overshoots 8% and settles. The
     trailer's rule: "arrivals are springs that settle, so motion always has a
     reason and a destination." --settle is the same idea, gentler, for big
     regions moving between scenes so the whole table never wobbles. */
  --arrive: linear(0, 0.0462, 0.1597, 0.3083, 0.4674, 0.6197, 0.7543, 0.8655, 0.9513, 1.0129, 1.0528, 1.0749, 1.0832, 1.0815, 1.0733, 1.0615, 1.0483, 1.0353, 1.0235, 1.0137, 1.0059, 1.0002, 0.9964, 0.9941, 0.9932, 0.9931, 0.9936, 0.9946, 1);
  --settle: linear(0, 0.0401, 0.1347, 0.2549, 0.3815, 0.5024, 0.6111, 0.7046, 0.782, 0.8441, 0.8926, 0.9294, 0.9566, 0.9759, 0.9892, 0.9979, 1.0033, 1.0062, 1.0075, 1.0077, 1.0073, 1.0065, 1);
  --ease: var(--settle);
  --t: .62s;
  /* One type scale, and nothing set below 13px. Labels are sentence case and
     upright: no tracked capitals, no italics. */
  --fs-cap: 13px;
  --fs-label: 14px;
  --fs-body: 16px;
  --fs-lead: 20px;
  --hud: 58px;
}

* { box-sizing: border-box; }
html, body { height: 100%; margin: 0; }
body {
  background: var(--ink);
  color: var(--on-ink);
  font: 400 15px/1.55 var(--sans);
  overflow: hidden;
  -webkit-font-smoothing: antialiased;
}
button { font: 500 14px var(--sans); cursor: pointer; }
button:disabled { opacity: .4; cursor: not-allowed; }
:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }
[hidden] { display: none !important; }

.btn {
  background: var(--gold-line); border: 1px solid var(--gold-line); color: #17130F;
  border-radius: 6px; padding: 9px 16px; font-weight: 600;
  transition: background .15s, transform .1s;
}
.btn:hover:not(:disabled) { background: var(--gold); }
.btn:active:not(:disabled) { transform: translateY(1px); }
.btn.ghost { background: rgba(0,0,0,.35); color: var(--on-ink); border-color: var(--hairline); }
.btn.ghost:hover:not(:disabled) { background: var(--ink-3); color: var(--paper); }
.btn.big { padding: 13px 22px; font-size: 15px; }

input[type=text], select {
  font: 500 14px var(--sans); color: var(--paper);
  background: rgba(0,0,0,.45); border: 1px solid var(--hairline); border-radius: 6px;
  padding: 11px 13px;
}
input#code { font-family: var(--mono); text-transform: uppercase; letter-spacing: .14em; width: 7.6em; text-align: center; }
input::placeholder { color: var(--on-ink-dim); }

/* ── the room itself ─────────────────────────────────────────────────── */

#app {
  position: fixed; inset: 0; overflow: hidden;
  /* A lit table in a dark room. The pool of light follows the scene: over the
     hand while picking, over the centre while the turn resolves. */
  background:
    radial-gradient(90% 70% at 50% var(--light-y), #2A2117 0%, #16110C 48%, var(--ink) 100%);
  transition: --light-y .9s var(--ease);
}
/* Scene defaults at zero specificity. Set on #app directly they would outrank
   every [data-mode] rule below — an ID beats an attribute selector whatever the
   order — and no scene would ever resize anything. */
:where(#app) {
  --light-y: 72%;
  --hand-card: clamp(220px, 42vh, 400px); /* the hand's one layout size */
  --seat-to: 40px;
  --me-k-to: 0; --me-off-to: 3vh;
}
@property --light-y { syntax: "<percentage>"; inherits: false; initial-value: 72%; }

/* The aether (fx.js) renders here, under every region. If WebGL is missing the
   canvas never appears and the gradient above is the fallback. */
.aether { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 0; display: block; }

/* Every region shares one motion language. (.seats adds --seat further down.) */
.hud, .seats, .stage, .me, .hand, .handhint, .focus, .results, .over, .lobby, .log {
  position: absolute;
  transition:
    opacity var(--t) var(--ease),
    transform var(--t) var(--ease),
    translate var(--t) var(--ease),
    top var(--t) var(--ease),
    bottom var(--t) var(--ease),
    left var(--t) var(--ease),
    padding var(--t) var(--ease),
    filter var(--t) var(--ease),
    visibility 0s linear var(--t);
}

/* ── lobby: a character select ─────────────────────────────────────────
   Roster across the top, the chosen class filling the screen below it, and
   a slim bar for your name and the room. Everything the dossier says comes
   from src/engine/data/classes.ts. */

.lobby {
  --pad: clamp(16px, 3vw, 44px);
  inset: 0; z-index: 20; overflow-y: auto; overflow-x: hidden;
  display: grid; grid-template-rows: auto 1fr auto;
  padding: 16px var(--pad) 0;
  background: radial-gradient(80% 70% at 30% 50%, transparent 0%, rgba(8,6,4,.6) 100%);
}
/* zero specificity, so any component margin below wins */
:where(.lobby) :is(p, h2, h3) { margin: 0; }

.lobby__top { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 20px; }
.lobby__logo { width: clamp(140px, 14vw, 210px); height: auto; justify-self: start; filter: drop-shadow(0 4px 16px rgba(0,0,0,.7)); }

/* the roster */
.classpick { grid-column: 2; display: flex; gap: clamp(4px, 1.1vw, 16px); }
.classpick button {
  display: grid; justify-items: center; gap: 7px; padding: 4px 2px; border: 0; background: none;
  color: var(--on-ink-dim); cursor: pointer; border-radius: 10px;
}
.classpick img {
  width: clamp(44px, 4.4vw, 62px); aspect-ratio: 1; border-radius: 50%; object-fit: cover; display: block;
  border: 1.5px solid var(--hairline); background: var(--ink-2);
  filter: saturate(.55) brightness(.75);
  transition: filter .25s, transform .5s var(--arrive), border-color .25s, box-shadow .35s;
}
.classpick span { font: 500 var(--fs-cap) var(--sans); transition: color .25s; }
.classpick button:hover img { filter: none; transform: translateY(-2px); }
.classpick button:hover span { color: var(--on-ink); }
.classpick button[aria-checked="true"] img {
  filter: none; border-color: var(--gold); transform: translateY(-3px) scale(1.08);
  box-shadow: 0 0 0 3px rgba(224,185,74,.16), 0 0 28px rgba(224,185,74,.38);
}
.classpick button[aria-checked="true"] span { color: var(--gold); }
/* one Class per player: someone else's is shown with their name, and locked */
.classpick button { position: relative; }
/* under the name, out of the layout, so the roster keeps its height */
.classpick__who {
  position: absolute; top: 100%; left: 50%; translate: -50% -3px;
  font: 500 var(--fs-cap) var(--sans); color: var(--on-ink-dim); max-width: 7em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.classpick button.locked img { filter: grayscale(.7) brightness(.6); }
.classpick button.locked:hover img, .classpick button.viewing img { filter: grayscale(.3) brightness(.85); }
.classpick button.viewing span { color: var(--on-ink); }
.dossier__locked {
  margin: 0 0 14px; padding: 10px 14px; border: 1px solid var(--gold-dim); border-radius: 4px;
  font: 400 var(--fs-body)/1.45 var(--sans); color: var(--on-ink); background: rgba(14, 11, 8, .55);
}
.dossier__locked b { color: var(--gold); font-weight: 600; }
.classpick button.taken { cursor: not-allowed; }
.classpick button.taken img { filter: grayscale(1) brightness(.45); transform: none; }
.classpick button.taken span { color: var(--on-ink-dim); text-decoration: line-through; text-decoration-color: rgba(198,188,168,.4); }

/* the select: stage and path on the left, dossier on the right */
.select {
  /* no min-height: 0 here — if the class outgrows the screen, the lobby
     scrolls rather than letting it slide under the bar */
  display: grid; width: min(1320px, 100%); margin: 0 auto; padding: 6px 0 18px;
  grid-template-columns: minmax(0, .95fr) minmax(0, 1.05fr);
  grid-template-rows: minmax(0, 1fr) auto;
  grid-template-areas: "stage dossier" "path dossier";
  column-gap: clamp(24px, 4.5vw, 72px); row-gap: 10px; align-items: center;
}

.select__stage { grid-area: stage; position: relative; height: 100%; min-height: clamp(220px, 36vh, 460px); }
/* one full-size cell, so the art's height can be a percentage of the stage */
.select__hero, .select__preview { position: absolute; inset: 0; display: grid; grid-template: 100% / 100%; place-items: center; }
.select__hero { transition: opacity .35s ease, filter .35s ease, scale .5s var(--settle); }
/* a pool of light the figure stands in */
.select__hero::before {
  content: ""; grid-area: 1 / 1; height: 112%; max-width: 100%; aspect-ratio: 1; border-radius: 50%;
  background: radial-gradient(closest-side, rgba(224,185,74,.3), rgba(224,185,74,.09) 52%, transparent 74%);
  animation: breathe 6s ease-in-out infinite;
}
.select__hero img {
  grid-area: 1 / 1; height: 100%; width: 100%; object-fit: contain;
  filter: drop-shadow(0 26px 40px rgba(0,0,0,.7));
  animation: hero-in .9s var(--arrive) both, hover-float 7s ease-in-out .9s infinite;
}
.select__hero img.out { animation: hero-out .45s ease forwards; }
@keyframes hero-in { from { opacity: 0; scale: .84; translate: 0 18px; } }
@keyframes hero-out { to { opacity: 0; scale: 1.08; } }
@keyframes hover-float { 50% { translate: 0 -9px; } }
@keyframes breathe { 50% { scale: 1.06; opacity: .8; } }

/* reading a card from the path: the art steps back, the card steps up */
.select__preview { pointer-events: none; --card-h: min(44vh, 440px); }
.select__preview .card { box-shadow: 0 26px 60px rgba(0,0,0,.85); animation: preview-in .42s var(--arrive) both; }
.select__stage:not([data-preview]) .select__preview { opacity: 0; transition: opacity .15s; }
.select__stage[data-preview] .select__hero { opacity: .14; filter: blur(4px); scale: .96; }
@keyframes preview-in { from { opacity: 0; scale: .9; translate: 0 14px; } }

/* the dossier */
.dossier { grid-area: dossier; align-self: center; display: flex; flex-direction: column; gap: 12px; max-width: 640px; text-align: left; }
.dossier > * { animation: dossier-in .6s var(--arrive) both; }
.dossier > :nth-child(2) { animation-delay: .04s; } .dossier > :nth-child(3) { animation-delay: .08s; }
.dossier > :nth-child(4) { animation-delay: .12s; } .dossier > :nth-child(5) { animation-delay: .16s; }
.dossier > :nth-child(6) { animation-delay: .2s; } .dossier > :nth-child(7) { animation-delay: .24s; }
@keyframes dossier-in { from { opacity: 0; translate: 14px 0; } }

.dossier__epithet { font: 400 16px/1.4 var(--serif); color: var(--on-ink-dim); }
.dossier__name {
  font: 600 clamp(48px, 5.4vw, 82px)/.95 var(--serif); letter-spacing: -.01em; color: var(--paper);
  text-shadow: 0 0 44px rgba(224,185,74,.2), 0 4px 24px rgba(0,0,0,.6); margin-top: -2px;
}
.dossier__tagline { font: 500 clamp(20px, 1.7vw, 24px)/1.3 var(--serif); color: var(--gold); margin-top: -4px; }

.facts { display: flex; margin: 2px 0 0; padding: 10px 0; border-block: 1px solid var(--hairline); }
.facts > div { flex: 1; padding: 0 18px; border-left: 1px solid var(--hairline); min-width: 0; }
.facts > div:first-child { padding-left: 0; border-left: 0; }
.facts dt { font: 500 var(--fs-label) var(--sans); color: var(--gold-dim); }
.facts dd { margin: 6px 0 0; display: flex; align-items: baseline; gap: 7px; font: 400 var(--fs-label) var(--sans); color: var(--on-ink); }
.facts dd b { font: 600 26px/1 var(--mono); color: var(--paper); font-variant-numeric: tabular-nums; }
.facts dd b.word { font: 600 25px/1 var(--serif); }

.dossier__play { font: 400 var(--fs-body)/1.55 var(--sans); color: var(--on-ink); max-width: 62ch; text-wrap: pretty; }
.dossier__mech { font: 400 15px/1.55 var(--sans); color: var(--on-ink); max-width: 62ch; }
.dossier__mech b { font: 600 17px var(--serif); color: var(--gold); margin-right: .35em; }

/* the deck profile: one cell per level-up card */
.profile { --k: 104px; --gap: 12px; margin-top: 2px; }
.profile h3, .path h3 { font: 600 15px var(--sans); color: var(--paper); margin-bottom: 8px; }
.meter { display: grid; grid-template-columns: var(--k) minmax(0, 290px) 2ch; align-items: center; column-gap: var(--gap); height: 23px; }
.meter__k { font: 500 var(--fs-label) var(--sans); color: var(--on-ink); }
.meter__cells { display: grid; grid-template-columns: repeat(10, 1fr); gap: 3px; }
.meter__cells i { height: 8px; border-radius: 2px; background: rgba(245,241,232,.08); }
.meter__cells i.on { background: var(--gold); box-shadow: 0 0 9px rgba(224,185,74,.38); animation: cell-on .45s var(--arrive) both; animation-delay: calc(var(--i) * 26ms + .18s); }
@keyframes cell-on { from { background: rgba(245,241,232,.08); box-shadow: none; scale: 1 .3; } }
.meter b { font: 600 13px var(--mono); color: var(--paper); text-align: right; font-variant-numeric: tabular-nums; }

.mixrow { height: auto; margin-top: 8px; }
.mix i { height: 13px; width: auto; border-radius: 2px; animation: cell-on .45s var(--arrive) both; animation-delay: calc(var(--i) * 26ms + .3s); }
.mix .t, .mix__legend .k-t::before { background: #E6DCC6; }
.mix .m, .mix__legend .k-m::before { background: #97A3D9; }
.mix .p, .mix__legend .k-p::before { background: var(--gold-dim); }
.mix .x { background: rgba(245,241,232,.08); }
.mix__legend { display: flex; flex-wrap: wrap; gap: 2px 16px; margin: 8px 0 0 calc(var(--k) + var(--gap)); font: 500 var(--fs-cap) var(--sans); color: var(--on-ink); }
.mix__legend span::before { content: ""; display: inline-block; width: 8px; height: 8px; border-radius: 2px; margin-right: 7px; }
.mix__legend em { flex-basis: 100%; font: 400 var(--fs-cap) var(--sans); font-style: normal; color: var(--on-ink-dim); }

/* the level path */
.path { grid-area: path; align-self: start; justify-self: center; width: min(580px, 100%); text-align: left; container-type: inline-size; }
.path__list > li, .pc { min-width: 0; }
@container (max-width: 500px) {
  .path__list { grid-template-columns: minmax(0, 1fr); grid-template-rows: none; grid-auto-flow: row; }
}
.path h3 span { font: 400 var(--fs-label) var(--sans); color: var(--on-ink-dim); margin-left: .6em; }
/* the cards you start with, as a sentence of links rather than a row of chips */
.path__core { margin: 0 0 10px; font: 400 var(--fs-label)/1.5 var(--sans); color: var(--on-ink-dim); }
.path__core .pc.inline { display: inline; width: auto; padding: 0; border-radius: 0; font: 500 var(--fs-label) var(--sans); color: var(--paper); text-decoration: underline; text-decoration-color: var(--gold-dim); text-underline-offset: 3px; }
.path__core .pc.inline:hover, .path__core .pc.inline.on { background: none; color: var(--gold); text-decoration-color: var(--gold); }
.path__core > span { font: 500 var(--fs-label) var(--sans); color: var(--on-ink-dim); }
.path__list { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: 1fr 1fr; grid-template-rows: repeat(5, auto); grid-auto-flow: column; column-gap: 16px; }
.pc {
  width: 100%; display: flex; align-items: center; gap: 10px; padding: 5px 8px; border: 0; border-radius: 6px;
  background: none; color: var(--paper); text-align: left; cursor: pointer; font: 500 15px var(--sans);
  transition: background .15s;
}
.pc:hover, .pc.on { background: rgba(224,185,74,.11); }
.pc.sig .pc__n { background: var(--gold-dim); color: var(--ink); }
.path__list .pc { border-radius: 4px; }
.pc__n {
  flex: none; width: 24px; height: 24px; border-radius: 50%; display: grid; place-items: center;
  font: 600 var(--fs-cap) var(--serif); color: var(--gold); background: var(--ink-3); border: 1px solid var(--gold-dim);
}
.pc__name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pc.sig .pc__name { color: var(--gold); }
.pc__lv { font: 500 var(--fs-cap) var(--mono); color: var(--on-ink-dim); }
.d20g { flex: none; width: 15px; height: 15px; fill: none; stroke: var(--gold-dim); stroke-width: 11; stroke-linejoin: round; }
.path__hint { margin-top: 10px; font: 400 var(--fs-cap) var(--sans); color: var(--on-ink-dim); }
.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

/* on touch, a card from the path opens over everything */
.cardsheet {
  position: fixed; inset: 0; z-index: 90; --card-h: min(70vh, 124vw);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 14px;
  background: rgba(8,6,4,.88); backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
  animation: fade-in .2s ease;
}
.cardsheet .card { animation: preview-in .42s var(--arrive) both; box-shadow: 0 24px 60px rgba(0,0,0,.85); }
.cardsheet p { margin: 0; font: 400 var(--fs-label) var(--sans); color: var(--on-ink-dim); }
.cardsheet.out { opacity: 0; transition: opacity .2s; }

/* the bar: your name, then the room */
.lobby__bar {
  position: sticky; bottom: 0; z-index: 2; margin: 0 calc(var(--pad) * -1);
  padding: 12px var(--pad) calc(12px + env(safe-area-inset-bottom));
  display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 12px 26px;
  background: linear-gradient(0deg, rgba(10,8,6,.97), rgba(10,8,6,.84));
  border-top: 1px solid var(--hairline);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
}
.lobby__name { display: flex; align-items: center; gap: 10px; }
.lobby__name span, .lobby__or, .lobby__room span {
  font: 500 var(--fs-label) var(--sans); color: var(--on-ink-dim); white-space: nowrap;
}
.lobby__name input { width: 16em; font-size: 15px; }
.lobby__join, .lobby__wait { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 10px 12px; }
.lobby[data-step="join"] .lobby__wait, .lobby[data-step="wait"] .lobby__join { display: none; }
.lobby__room { display: flex; align-items: baseline; gap: 10px; }
.lobby__room b { font: 600 26px var(--mono); letter-spacing: .16em; color: var(--gold); }
.lobby__seated { display: flex; flex-wrap: wrap; gap: 6px; }
.lobby__seated { gap: 16px; }
.lobby__seated .who { display: flex; align-items: center; gap: 9px; animation: rise .6s var(--arrive) both; }
.lobby__seated img { width: 34px; height: 34px; border-radius: 50%; object-fit: cover; border: 1px solid var(--gold-dim); }
.lobby__seated .who span { display: grid; line-height: 1.2; }
.lobby__seated b { font: 600 var(--fs-label) var(--sans); color: var(--paper); max-width: 9em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lobby__seated small { font: 400 var(--fs-cap) var(--sans); color: var(--gold); }
@keyframes rise { from { opacity: 0; transform: translateY(12px) scale(.94); } }
#newRoom .sm, .hud__btn .sm { display: none; }
.lobby__help { grid-column: 3; justify-self: end; }
.lobby__seated .who.away { opacity: .5; }
.who__x {
  margin-left: 2px; width: 24px; height: 24px; border-radius: 4px; border: 1px solid var(--hairline); background: none;
  color: var(--on-ink-dim); font: 400 18px/1 var(--sans); cursor: pointer;
}
.who__x:hover { color: var(--paper); border-color: var(--blood); background: rgba(180,67,42,.2); }
.who__class {
  margin-left: 2px; height: 24px; border-radius: 4px; border: 1px solid var(--hairline); background: none;
  color: var(--on-ink-dim); font: 400 12px/1 var(--sans); cursor: pointer; max-width: 9em;
  padding: 0 6px; /* the page's select padding would hide the text at this height */
}
.who__class option { color: initial; }
.lobby[data-practice] #addBot { display: none; }

/* ── HUD ─────────────────────────────────────────────────────────────── */

.hud {
  top: 0; left: 0; right: 0; height: var(--hud); z-index: 30;
  display: flex; align-items: center; gap: 14px; padding: 0 18px;
  background: linear-gradient(180deg, rgba(0,0,0,.6), transparent);
}
.hud__logo { height: 24px; width: auto; }
.hud__btn {
  background: transparent; border: 1px solid var(--hairline); color: var(--on-ink-dim);
  border-radius: 4px; padding: 5px 12px; font: 500 var(--fs-label) var(--sans);
}
.hud__btn[aria-expanded="true"] { color: var(--gold); border-color: var(--gold-dim); }
.hud__scene {
  flex: 1; text-align: center;
  font: 600 15px var(--sans); color: var(--gold);
}
.hud__turn { font: 500 var(--fs-label) var(--sans); color: var(--on-ink-dim); font-variant-numeric: tabular-nums; }

.timer { position: relative; width: 44px; height: 44px; flex: none; transition: opacity var(--t); }
.timer svg { transform: rotate(-90deg); width: 100%; height: 100%; }
.timer__track { fill: none; stroke: rgba(224,185,74,.14); stroke-width: 4; }
.timer__arc { fill: none; stroke: var(--gold); stroke-width: 4; stroke-linecap: round; transition: stroke-dashoffset .25s linear, stroke .3s; }
.timer.urgent .timer__arc { stroke: var(--blood-lit); }
.timer.urgent { animation: pulse 1s ease-in-out infinite; }
.timer__n { position: absolute; inset: 0; display: grid; place-items: center; font: 600 14px var(--mono); color: var(--paper); font-variant-numeric: tabular-nums; }
@keyframes pulse { 50% { transform: scale(1.08); } }

/* ── log drawer ──────────────────────────────────────────────────────── */

.log {
  top: var(--hud); left: 0; bottom: 0; width: min(300px, 80vw); z-index: 25;
  background: rgba(10,8,6,.94); border-right: 1px solid var(--hairline);
  backdrop-filter: blur(6px); transform: translateX(-102%);
  display: flex; flex-direction: column;
}
.log.open { transform: none; }
.log__head { padding: 14px 16px 8px; font: 600 15px var(--sans); color: var(--paper); }
#log { flex: 1; overflow: auto; padding: 0 16px 14px; font: 400 var(--fs-cap)/1.55 var(--sans); }
#log div .t { color: var(--on-ink-dim); font-variant-numeric: tabular-nums; margin-right: .6em; }
#log div { padding: 3px 0; border-bottom: 1px solid rgba(255,255,255,.05); color: var(--on-ink-dim); }
#log div.k-damage { color: var(--blood-lit); }
#log div.k-heal { color: var(--heal); }
#log div.k-roll { color: var(--gold); }
#log div.k-reveal, #log div.k-level_up { color: var(--paper); }
#log div.k-execute, #log div.k-game_over { color: var(--gold); font-weight: 500; }

.banner {
  position: absolute; left: 50%; translate: -50% 0; top: calc(var(--hud) + 8px); z-index: 40;
  background: rgba(20,16,12,.96); border: 1px solid var(--gold-dim); border-radius: 8px;
  padding: 9px 16px; font: 400 var(--fs-label) var(--sans); color: var(--on-ink); cursor: pointer;
  box-shadow: 0 8px 24px rgba(0,0,0,.6); animation: rise .3s var(--ease);
}
.banner b { color: var(--gold); font: 600 14px var(--mono); letter-spacing: .1em; }
.banner.err { border-color: var(--blood); color: var(--blood-lit); }

/* ── seats ───────────────────────────────────────────────────────────── */

.seats, .me { --seat: var(--seat-to); }
.seats {
  left: 0; right: 0; top: calc(var(--hud) + 8px); z-index: 10;
  display: flex; justify-content: center; align-items: flex-start; flex-wrap: wrap;
  gap: calc(var(--seat) * .45); padding: 0 3vw;
}

.seats {
  transition:
    opacity var(--t) var(--ease), translate var(--t) var(--ease), top var(--t) var(--ease), bottom var(--t) var(--ease),
    padding var(--t) var(--ease), visibility 0s linear var(--t), --seat var(--t) var(--ease);
}

/*
 * A seat is one fixed shape — portrait | who | Life Sparks, over one row of
 * effects — whatever lands on it. (It used to be as wide as its name and its
 * chips made it, and grew a row for every few effects; the table reflowed each
 * time. Jon, 2026-09-29.)
 */
.seat {
  --w: min(calc(var(--seat) * 5.6), 46vw);
  position: relative; display: grid; box-sizing: border-box; width: var(--w);
  grid-template-columns: var(--seat) minmax(0, 1fr) auto; grid-template-rows: auto auto;
  column-gap: calc(var(--seat) * .24); row-gap: calc(var(--seat) * .16); align-items: center;
  padding: calc(var(--seat) * .18) calc(var(--seat) * .24);
  background: linear-gradient(180deg, rgba(40,33,25,.92), rgba(20,16,12,.92));
  border: 1px solid var(--hairline); border-radius: calc(var(--seat) * .26);
  transition: border-color .3s, box-shadow .3s, transform .3s var(--ease), opacity .3s, filter .3s;
}
.seat.is-you { border-color: var(--gold-dim); }
.seat.is-out { opacity: .35; filter: grayscale(1); }
/* lost their connection: still in the match, so dimmed rather than greyed out */
.seat.is-away .seat__portrait { filter: grayscale(1) brightness(.7); }
.seat__away { margin-left: .4em; padding: 0 6px; border-radius: 4px; font: 500 var(--fs-cap) var(--sans); color: var(--on-ink); background: rgba(255,255,255,.08); border: 1px solid var(--hairline); }
.seat.targetable { cursor: pointer; border-color: var(--gold); box-shadow: 0 0 0 1px var(--gold), 0 0 34px rgba(224,185,74,.28); }
.seat.targetable:hover { transform: translateY(-4px) scale(1.03); }
/* While choosing, whatever can be chosen pulses and says so; everything else steps back. */
[data-mode="target"] .seat.targetable { animation: aim 1.6s ease-in-out infinite; }
/*
 * Your own seat, lifted into the enemy row while a card that helps is held up.
 *
 * Green rather than the targeting gold, because the whole point is that this
 * seat is not like the others around it: the row is enemies, and this one is
 * you. Jacob kept healing his opponents because his seat was at the bottom of
 * the screen while his cursor was up here.
 */
.seat.is-promoted {
  border-color: var(--heal);
  box-shadow: 0 0 0 1px var(--heal), 0 0 34px rgba(159, 208, 138, .30);
}
.seat.is-promoted .seat__name::before {
  content: "You · ";
  color: var(--heal);
  font-weight: 700;
}
[data-mode="target"] .seat.targetable::before {
  content: "Choose"; position: absolute; left: 50%; bottom: 100%; translate: -50% -8px;
  padding: 3px 10px; border-radius: 4px; white-space: nowrap;
  font: 600 var(--fs-label) var(--sans); color: var(--ink); background: var(--gold);
  box-shadow: 0 4px 14px rgba(0,0,0,.6); pointer-events: none;
}
[data-mode="target"] .seat:not(.targetable):not(.picked):not(:has(.targetable)) { opacity: .4; filter: grayscale(.7); }
@keyframes aim {
  50% { box-shadow: 0 0 0 3px var(--gold), 0 0 60px rgba(224,185,74,.55); }
}
.seat.picked { border-color: var(--gold); box-shadow: 0 0 0 3px var(--gold), 0 0 44px rgba(224,185,74,.4); }

/* Aiming after the reveal: a Defending Character is still a legal target, but
   the shot is stopped. Shown as shielded rather than removed, because Brutality
   and a banked Assault both want a Defender. */
.seat.is-defending { border-color: var(--ice, #8fb6d8); }
.seat.is-defending .seat__portrait { filter: brightness(.82) saturate(.7); }
/* A real element, not a pseudo: ::after is the hit sweep and ::before is the
   "Choose" chip, and a Defending seat is usually still choosable. */
.seat__shield {
  position: absolute; inset-inline: 0; bottom: -1.05rem;
  font: 600 .62rem/1 var(--sans); letter-spacing: .08em; text-transform: uppercase;
  color: var(--ice, #8fb6d8); text-align: center; opacity: .9; pointer-events: none;
}
/* ── combat (combat.js draws the strikes; these are what a seat does) ── */
.combat { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 58; pointer-events: none; overflow: visible; }
/* a sweep of colour through the seat: up and green for a heal, down and red for a status */
.seat::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none; opacity: 0;
  background: linear-gradient(0deg, transparent 0%, var(--sweep, transparent) 50%, transparent 100%) 0 0 / 100% 300% no-repeat;
}
.seat.mending { --sweep: rgba(159,208,138,.55); }
.seat.afflicted { --sweep: rgba(224,113,79,.55); }
.seat.mending::after { animation: sweep-up .85s ease-out; }
.seat.afflicted::after { animation: sweep-down .85s ease-out; }
@keyframes sweep-up { 0% { opacity: 1; background-position: 0 0; } 100% { opacity: 0; background-position: 0 100%; } }
@keyframes sweep-down { 0% { opacity: 1; background-position: 0 100%; } 100% { opacity: 0; background-position: 0 0; } }
.seat.hit.struck { animation: seat-hit .45s ease, struck .52s ease-out; }
@keyframes struck { 0% { box-shadow: inset 0 0 0 2px var(--blood-lit), 0 0 40px rgba(224,113,79,.6); border-color: var(--blood-lit); } 100% { box-shadow: none; } }
.seat.blocked { animation: blocked .6s var(--arrive); }
@keyframes blocked { 0% { box-shadow: 0 0 0 4px var(--gold), 0 0 50px rgba(224,185,74,.7); scale: 1.04; } 100% { scale: 1; } }
/* at 0 Life Sparks: the seat drains of colour and sinks */
.seat.falling { animation: falling 1.1s ease-in forwards; }
@keyframes falling { 0% { filter: none; } 40% { filter: grayscale(1) brightness(1.3); rotate: -2deg; } 100% { filter: grayscale(1) brightness(.6); opacity: .45; translate: 0 10px; rotate: 0deg; } }
/* Defend: the shield comes up over the portrait and stays for the turn */
.seat__ward {
  position: absolute; left: calc(var(--seat) * .2 - 4px); top: calc(var(--seat) * .2 - 4px); z-index: 2;
  width: calc(var(--seat) + 8px); height: calc(var(--seat) + 8px); border-radius: 50%; pointer-events: none;
  background: radial-gradient(circle, rgba(20,16,12,.55) 40%, rgba(224,185,74,.25) 100%), url("/art/sym-defend.webp") center / 72% no-repeat;
  box-shadow: 0 0 0 2px var(--gold), 0 0 26px rgba(224,185,74,.55);
  animation: ward-up .6s var(--arrive) both;
}
@keyframes ward-up { from { opacity: 0; scale: 1.7; } }
@media (prefers-reduced-motion: reduce) { .seat::after, .seat__ward { animation: none !important; } }

.seat.hit { animation: seat-hit .45s ease; }
@keyframes seat-hit {
  0%,100% { translate: 0 0; } 20% { translate: -6px 2px; } 45% { translate: 5px -2px; } 70% { translate: -2px 1px; }
}

.seat__portrait {
  grid-row: 1; grid-column: 1; width: var(--seat); height: var(--seat); border-radius: 50%;
  border: 2px solid var(--gold-dim); object-fit: cover; background: var(--ink-3);
}
.seat__id { grid-row: 1; grid-column: 2; min-width: 0; line-height: 1.15; }
.seat__name {
  font: 600 max(14px, calc(var(--seat) * .28)) var(--sans); color: var(--paper);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.seat__class {
  display: flex; align-items: center; gap: 6px; min-width: 0; white-space: nowrap;
  font: 400 max(12px, calc(var(--seat) * .18)) var(--sans); color: var(--gold);
}
.seat__tag {
  padding: 0 5px; border-radius: 3px; font: 500 max(10px, calc(var(--seat) * .14)) / 1.4 var(--sans);
  color: var(--on-ink-dim); background: rgba(255,255,255,.06); border: 1px solid var(--hairline);
}
/* Life Sparks: the number that matters most, so it has a column of its own. */
.sparks {
  grid-row: 1; grid-column: 3; display: flex; align-items: center; gap: 4px;
  padding-left: calc(var(--seat) * .18); border-left: 1px solid var(--hairline);
}
.sparks img { width: max(11px, calc(var(--seat) * .26)); height: auto; }
.sparks b {
  min-width: 2ch; text-align: right;
  font: 600 max(18px, calc(var(--seat) * .5)) var(--mono); color: var(--life);
  font-variant-numeric: tabular-nums; line-height: 1; transition: color .2s, transform .2s;
}
.sparks.drain b { color: var(--blood-lit); transform: scale(1.18); }
.sparks.gain b { color: var(--heal); transform: scale(1.18); }

.badges { grid-column: 1 / -1; display: flex; flex-wrap: wrap; gap: 4px; margin-top: calc(var(--seat) * .14); }
.badges:empty { display: none; }
.badge {
  font: 500 var(--fs-cap) var(--sans); text-transform: capitalize;
  padding: 2px 7px; border-radius: 4px;
  background: rgba(180,67,42,.2); border: 1px solid var(--blood); color: var(--blood-lit);
}
.badge.res { background: rgba(224,185,74,.14); border-color: var(--gold-dim); color: var(--gold); }
.badge.imm { background: rgba(120,160,120,.14); border-color: #5E7F5E; color: var(--heal); }

/* The effects row: one line, always there, chips that shrink to share it.
   Statuses first (red), then protection (green), then what they have going
   (gold). Hover or hold a chip to read it in full. */
.fx {
  --chip-h: max(20px, calc(var(--seat) * .36));
  grid-row: 2; grid-column: 1 / -1; display: flex; flex-wrap: nowrap; gap: 4px;
  min-width: 0; height: var(--chip-h); overflow: hidden;
}
.chip {
  flex: none; height: var(--chip-h); box-sizing: border-box;
  display: inline-flex; align-items: center; gap: 5px; padding: 0 7px; border-radius: calc(var(--chip-h) / 2);
  font: 500 max(11px, calc(var(--seat) * .17))/1 var(--sans); white-space: nowrap; cursor: help;
  border: 1px solid var(--hairline); background: rgba(10,8,6,.78); color: var(--on-ink);
}
/* A long card name is trimmed; a status never needs to be. */
.chip b { font-weight: 600; max-width: 8.5em; overflow: hidden; text-overflow: ellipsis; }
.chip[hidden] { display: none; }
.chip i {
  flex: none; font-style: normal; font-variant-numeric: tabular-nums; font-weight: 600;
  padding-left: 5px; border-left: 1px solid currentColor; opacity: .75;
}
.chip__ls { display: inline-flex; align-items: center; gap: 2px; }
.chip__ls img { height: .95em; width: auto; }
/* "+N more": a fixed little pill at the end of the row, never squeezed. */
.chip.more { flex: none; color: var(--on-ink-dim); }
.chip.t-bad { border-color: #8A3322; background: rgba(62,20,13,.82); color: #F2A38C; }
.chip.t-good { border-color: #50704F; background: rgba(20,38,22,.82); color: #AFD8AE; }
.chip.t-boost { border-color: var(--gold-dim); background: rgba(40,31,14,.82); color: var(--gold); }
/* a passive switched off (Dazed) keeps its place but reads as off */
.chip.off { border-style: dashed; opacity: .5; }
button.chip.targetable { cursor: pointer; flex-shrink: 0; border-color: var(--gold); box-shadow: 0 0 0 1px var(--gold), 0 0 16px rgba(224,185,74,.35); }
button.chip.targetable:hover { background: rgba(80,62,24,.9); }
/* A strip with something to click grows to show it all, only while choosing. */
[data-mode="target"] .fx:has(.targetable) { height: auto; flex-wrap: wrap; overflow: visible; }

/* The commitment slot. A tucked-in card back while picking; a full slot on the
   table once everyone is laying cards down. */
.seat__slot {
  /* Tucked over the top edge, clear of the Life Spark number below it. */
  position: absolute; top: -12px; right: 10px;
  width: max(15px, calc(var(--seat) * .42)); height: max(21px, calc(var(--seat) * .59)); border-radius: 3px;
  background: rgba(0,0,0,.35) center / cover no-repeat;
  border: 1px dashed var(--hairline);
  opacity: 0; transition: all var(--t) var(--ease);
}
.seat__slot.filled { opacity: 1; border: 1px solid var(--gold-dim); box-shadow: 0 3px 8px rgba(0,0,0,.6); transform: rotate(7deg); }
.seat__slot span { display: none; }

/* ── your own seat ───────────────────────────────────────────────────── */

/* max-content: pinned near an edge, an absolute box otherwise only gets the
   leftover width to lay out in, and the seat collapses. */
.me {
  z-index: 12; left: 20px; width: max-content;
  --me-k: var(--me-k-to); --me-off: var(--me-off-to);
  bottom: calc(var(--hand-card) * var(--me-k) + var(--me-off));
  /* no transition on bottom: it is moved by the three variables animating here */
  transition: opacity var(--t) var(--ease), translate var(--t) var(--ease), left var(--t) var(--ease), visibility 0s linear var(--t),
    --seat var(--t) var(--ease), --me-k var(--t) var(--ease), --me-off var(--t) var(--ease);
}

/* ── stage ───────────────────────────────────────────────────────────── */

.stage {
  left: 0; right: 0; top: 30vh; bottom: 24vh; z-index: 5;
  display: flex; align-items: center; justify-content: center;
  --card-h: clamp(170px, 32vh, 320px);
}
.stage__band {
  position: absolute; top: -6px; left: 50%; translate: -50% 0;
  font: 600 15px var(--sans);
  color: var(--gold); opacity: 0; transition: opacity .3s;
}
.stage__band.on { opacity: 1; }
.stage__cards { display: flex; gap: 2vw; align-items: flex-start; justify-content: center; flex-wrap: wrap; }

/*
 * What just happened, said once per beat.
 *
 * Jacob, 2026-09-18: "spend the time saved on faster dice showing what actually
 * happened, in resolution order." The engine already writes a line for every
 * event; the turn simply never read them out. Below the cards rather than above
 * them, because the eye is on the table and the band label already owns the top.
 */
.stage__say {
  position: absolute; bottom: -12px; left: 50%; translate: -50% 0;
  margin: 0; width: max-content; max-width: min(620px, 88vw);
  font: 500 var(--fs-lead) var(--serif); color: var(--on-ink);
  text-align: center; text-wrap: balance; text-shadow: 0 2px 12px #000;
  opacity: 0;
}
.stage__say.on { animation: say-in .34s var(--arrive) forwards; }
@keyframes say-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) {
  .stage__say.on { animation: none; opacity: 1; }
}
.stage__quiet { font: 400 var(--fs-lead) var(--serif); color: var(--on-ink-dim); animation: fade-in .5s ease; }
.stage__owner { text-align: center; font: 500 var(--fs-label) var(--sans); color: var(--gold-dim); margin-top: 10px; }
.pending { animation: deal .7s var(--arrive); text-align: center; }
.pending__card { box-shadow: 0 0 0 1px var(--gold-dim), 0 16px 40px rgba(0,0,0,.75); }
.pending__undo { display: block; margin: 10px auto 0; }
:not([data-mode="lay"]) > .stage .pending__undo { display: none; }
@keyframes deal { from { transform: translateY(40vh) rotate(-10deg) scale(.7); opacity: 0; } }
@keyframes fade-in { from { opacity: 0; } }

/* ── cards ─────────────────────────────────────────────────────────────
   Jacob's printed frame (art/frame-*.webp, by class type) over a parchment
   window. Positions are fractions of the card, measured off the 1500x2100
   frame: the window runs 8–92% across and 11–70% down; the plate under it
   carries the class, then the type line; Lv and the class emblem sit in the
   two bottom sockets. Every size is a fraction of --card-h, so one card reads
   the same in the hand, on the stage and in the zoom. */

.card {
  --floor: 0px;             /* raised to 13px wherever a card is for reading */
  width: calc(var(--card-h) * 5 / 7); height: var(--card-h);
  border-radius: calc(var(--card-h) * .032); position: relative; flex: none; overflow: hidden;
  background: #09090C; box-shadow: 0 4px 14px rgba(0,0,0,.55);
  color: #2B241D; text-align: center; font-family: var(--sans); padding: 0; border: 0;
  contain: layout style;
}
/* the frame, over everything but the lettering that sits on it */
.card::after {
  content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: var(--frame) center / 100% 100% no-repeat;
}
/* plain white behind the rules: nothing competes with the text */
.card__win { position: absolute; left: 6.5%; right: 6.5%; top: 10%; bottom: 28.5%; background: #FFFFFF; }
.card__name, .card__text { position: absolute; z-index: 0; }
.card__num, .card__plate, .card__type, .card__lv, .card__emblem, .card__socket, .card__counter, .card__gap { position: absolute; z-index: 2; }

.card__num {
  left: 3.6%; top: 2.6%; width: 14.5%; aspect-ratio: 1; border-radius: 50%;
  display: grid; place-items: center;
  background: radial-gradient(circle at 50% 38%, #2A2419, #0B0906 70%);
  border: calc(var(--card-h) * .005) solid var(--gold-line);
  box-shadow: 0 0 0 calc(var(--card-h) * .003) rgba(0,0,0,.8), 0 2px 8px rgba(0,0,0,.7);
  font: 600 calc(var(--card-h) * .05) var(--serif); color: var(--gold); font-variant-numeric: lining-nums;
}
/* card names are capitals because the printed cards are */
.card__name {
  left: 12%; right: 12%; top: 12.6%; height: 7%;
  display: flex; align-items: center; justify-content: center;
  font: 700 calc(var(--card-h) * .047)/1.05 var(--serif); letter-spacing: .02em; text-transform: uppercase; color: #1B1510;
  border-bottom: 1px solid rgba(60,45,25,.25);
}
.card[data-name="m"] .card__name { font-size: calc(var(--card-h) * .039); }
.card[data-name="l"] .card__name { font-size: calc(var(--card-h) * .032); }
.card__text {
  left: 11%; right: 11%; top: 20.5%; bottom: 31%;
  display: flex; flex-direction: column; justify-content: safe center;
  overflow: auto; scrollbar-width: thin; color: #2E2720;
  font: 400 max(var(--floor), calc(var(--card-h) * var(--fs, .044) * var(--fit, 1)))/1.36 var(--serif);
}
.card[data-len="m"] { --fs: .037; }
.card[data-len="l"] { --fs: .032; }
.card[data-len="xl"] { --fs: .0285; }
.card__text::-webkit-scrollbar { width: 3px; }
.card__text::-webkit-scrollbar-thumb { background: rgba(0,0,0,.2); border-radius: 2px; }

.card__plate {
  left: 18%; right: 18%; top: 71.6%; height: 5.2%;
  display: grid; place-items: center; white-space: nowrap;
  font: 600 max(var(--floor), calc(var(--card-h) * .042)) var(--serif); color: var(--paper);
  text-shadow: 0 1px 6px #000;
}
/* the type line sits between the two symbol sockets, as printed */
.card__type {
  left: 19%; right: 19%; top: 86.2%; height: 9%;
  display: flex; align-items: center; justify-content: center; text-align: center;
  font: 500 max(var(--floor), calc(var(--card-h) * .031))/1.2 var(--serif); color: var(--gold);
  text-shadow: 0 1px 6px #000, 0 0 2px #000;
}
/* the flex box above centres it; this inner clamp keeps it to two lines */
.card__type { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; overflow: hidden; align-content: center; }
/* level and class emblem flank the class name bar */
.card__lv, .card__emblem, .card__socket {
  width: 12.6%; aspect-ratio: 1; border-radius: 50%;
  border: calc(var(--card-h) * .004) solid var(--gold-line);
  box-shadow: 0 2px 8px rgba(0,0,0,.7);
}
.card__lv, .card__emblem { top: 69.7%; }
.card__lv {
  left: 4.4%; display: grid; place-items: center;
  background: radial-gradient(circle at 50% 38%, #2A2419, #0B0906 70%);
  font: 600 calc(var(--card-h) * .03) var(--serif); color: var(--gold); font-variant-numeric: lining-nums;
}
.card__emblem { right: 4.4%; background: var(--art) center / cover no-repeat, #0B0906; }
/* the foot sockets: what kind of Action (left), what happens after (right) */
.card__socket { top: 86.2%; background: radial-gradient(circle at 50% 38%, #2A2419, #0B0906 70%); }
.card__socket--l { left: 4.4%; }
.card__socket--r { right: 4.4%; }
/*
 * Priority: the dragon, top right.
 *
 * It gets a socket of its own because Priority is about *when* a card resolves,
 * not what kind it is — every Priority card is also a Defend, a Magic or a
 * Tactic, so sharing the left socket meant the dragon never showed at all.
 *
 * Top right rather than the middle of the foot, which it was first given: the
 * type line runs across there, and the dragon sat straight on top of "Core
 * Mechanic, Defend, Priority, Recharge". Up here it mirrors the level number
 * in the opposite corner and covers nothing.
 */
.card__socket--p { right: 4.4%; top: 3.2%; border-color: var(--gold); }

/*
 * The yellow ring the printed card wears.
 *
 * On the frame rather than the element's own border, which the frame art
 * already owns, so this reads as part of the card instead of a box round it.
 */
.card--priority {
  /* Thick enough to read at hand size: at .006 Jacob took it for missing (v3). */
  box-shadow: 0 0 0 calc(var(--card-h) * .018) var(--gold), 0 0 22px rgba(224,185,74,.4);
  border-radius: calc(var(--card-h) * .045);
}
.card__sym { position: absolute; inset: 12%; background: var(--sym) center / contain no-repeat; filter: drop-shadow(0 1px 2px rgba(0,0,0,.6)); }

.card__counter {
  /* the recharge count sits over the right socket's Recharge symbol */
  right: 4.4%; top: 86.2%;
  width: 12.6%; aspect-ratio: 1; border-radius: 50%; display: grid; place-items: center;
  font: 600 calc(var(--card-h) * .045) var(--mono); color: var(--ink);
  background: var(--gold); border: calc(var(--card-h) * .004) solid var(--gold-line);
  box-shadow: 0 0 0 calc(var(--card-h) * .006) rgba(224,185,74,.25), 0 2px 8px rgba(0,0,0,.7);
}
.card__gap { top: 4%; right: 5.5%; width: 3.2%; aspect-ratio: 1; border-radius: 50%; background: var(--blood); border: 1px solid rgba(0,0,0,.4); }

/* a card meant to be read keeps its type at 13px or more */
:is(.hand, .focus__card, .zoom, .select__preview, .cardsheet, .choice) .card { --floor: 13px; }

.card.back { background: center / cover no-repeat; border-color: var(--gold-dim); }
.card.back::before, .card.back::after, .card.back > * { display: none; }

/* flip */
.flip { perspective: 1200px; width: calc(var(--card-h) * 5 / 7); height: var(--card-h); flex: none; transition: transform .35s var(--ease), filter .35s; }
.flip__inner { position: relative; width: 100%; height: 100%; transform-style: preserve-3d; transform: rotateY(180deg); transition: transform .6s var(--ease); }
.flip.revealed .flip__inner { transform: rotateY(0deg); }
.flip__face, .flip__back { position: absolute; inset: 0; backface-visibility: hidden; }
.flip__back { transform: rotateY(180deg); }
.flip.acting { transform: translateY(-18px) scale(1.07); z-index: 4; transition: transform .6s var(--arrive), filter .35s; }
.flip.acting .flip__face .card { box-shadow: 0 0 0 2px var(--gold), 0 22px 50px rgba(0,0,0,.75); }
.flip.spent { filter: brightness(.6) saturate(.7); }

/* ── hand ────────────────────────────────────────────────────────────── */

.hand {
  left: 0; right: 0; bottom: 0; z-index: 15;
  /* the scene's card size, unless a full hand would not fit the width even
     at the deepest overlap; then the cards shrink to fit (--n is set by game.js) */
  --card-h: min(var(--hand-card), calc((100vw - 48px) / (1 + .3 * (var(--n, 1) - 1)) * 7 / 5));
  --cw: calc(var(--card-h) * 5 / 7);
  display: flex; justify-content: safe center; align-items: flex-end;
  padding: 28px 24px max(18px, env(safe-area-inset-bottom));
}
/* The fan is pure CSS: overlap only as much as the row needs to fit, and never
   more than 70% of a card. */
.hand > .card + .card {
  margin-left: clamp(calc(var(--cw) * -.7), calc((100vw - 48px - var(--n, 1) * var(--cw)) / max(1, var(--n, 1) - 1)), 14px);
}
.hand > .card { transform-origin: 50% 100%; }
.hand { transform-origin: 50% 100%; will-change: transform; }
button.card { cursor: pointer; transition: transform .5s var(--arrive), box-shadow .25s, filter .25s, margin .5s var(--settle); }
button.card:hover:not(:disabled) { transform: translateY(-7%) scale(1.03); box-shadow: 0 18px 38px rgba(0,0,0,.65); z-index: 5; }
button.card.selected { transform: translateY(-9%) scale(1.04); box-shadow: 0 0 0 2px var(--gold), 0 20px 42px rgba(0,0,0,.7); z-index: 6; }
button.card:disabled { filter: grayscale(.6) brightness(.72); }
.card.illegal { filter: grayscale(.8) brightness(.55); }
.card.new { animation: new-card 1.1s var(--arrive); }
@keyframes new-card {
  0% { transform: translateY(60%) rotate(4deg); box-shadow: 0 0 0 0 rgba(224,185,74,0); }
  40% { transform: translateY(-10%); box-shadow: 0 0 0 3px var(--gold), 0 0 50px rgba(224,185,74,.55); }
  100% { transform: none; }
}

.handhint {
  left: 50%; translate: -50% 0; width: fit-content; max-width: min(92vw, 62ch);
  z-index: 16; margin: 0; text-align: center;
  /* clear of a hovered card, which lifts about a tenth of its height */
  bottom: calc(var(--hand-card) * 1.12 + 40px);
  transition: opacity var(--t) var(--ease), visibility 0s linear var(--t);
  font: 400 var(--fs-label) var(--sans); color: var(--on-ink); pointer-events: none;
  text-shadow: 0 1px 3px #000, 0 0 14px rgba(0,0,0,.9);
}
.handhint b { color: var(--gold); font-weight: 600; }

/* ── focus (target mode) ─────────────────────────────────────────────── */

.focus {
  z-index: 18; left: 5vw; top: calc(50% + var(--hud) / 2); translate: 0 -50%;
  --card-h: min(62vh, 480px);
  display: flex; flex-direction: column; align-items: center; gap: 14px;
}
.focus__card .card { box-shadow: 0 0 0 2px var(--gold), 0 30px 70px rgba(0,0,0,.8); }
/* the one instruction in this scene, so it reads first */
/* A benefit about to land on an enemy: said in the heal colour, not the alarm
   colour, because nothing has gone wrong yet — it is one more tap away. */
.focus__hint.warn { color: var(--heal); }
.focus__hint { order: -1; margin: 0; max-width: min(420px, 90vw); font: 600 26px/1.2 var(--serif); color: var(--gold); text-align: center; text-wrap: balance; text-shadow: 0 2px 10px #000; }
.focus__btns { display: flex; gap: 10px; }
.focus__modes { display: flex; flex-direction: column; gap: 8px; width: min(340px, 90vw); }
/* stacks to spend on the held-up card (Lethality on Assassinate) */
.focus__spend {
  display: grid; grid-template-columns: 1fr auto; align-items: center; gap: 4px 14px; width: min(340px, 90vw);
  padding: 10px 14px; border-radius: 4px; background: rgba(20,16,12,.92); border: 1px solid var(--gold-dim);
  font: 500 var(--fs-label) var(--sans); color: var(--paper);
}
.focus__spend[hidden] { display: none; }
.spend__max {
  grid-column: 1 / -1; justify-self: start; padding: 4px 10px; border-radius: 4px; cursor: pointer;
  border: 1px solid var(--gold-dim); background: none; color: var(--paper); font: 500 var(--fs-label) var(--sans);
}
.spend__max:disabled { opacity: .45; cursor: default; }
.focus__spend small { grid-column: 1 / -1; font: 400 var(--fs-cap) var(--sans); color: var(--gold); }
.stepper { display: flex; align-items: center; gap: 10px; }
.stepper b { min-width: 2ch; text-align: center; font: 600 20px var(--mono); color: var(--gold); font-variant-numeric: tabular-nums; }
.stepper button { width: 32px; height: 32px; border-radius: 4px; border: 1px solid var(--gold-dim); background: rgba(0,0,0,.35); color: var(--paper); font: 600 18px/1 var(--sans); cursor: pointer; }
.stepper button:disabled { opacity: .35; cursor: default; }
.focus__modes .mode:disabled { opacity: .5; cursor: not-allowed; }
/* a card that asks how to play it: the list needs the room more than the card does */
.focus:has(.focus__modes:not([hidden])) { --card-h: min(40vh, 480px); }

/* Soothing Rains / Vested Power: the caster's private pick */
.choice {
  position: absolute; left: 50%; top: 50%; translate: -50% -50%; z-index: 60; width: min(1100px, 94vw);
  display: flex; flex-direction: column; align-items: center; gap: 12px; padding: 22px 24px;
  background: rgba(14,11,8,.96); border: 1px solid var(--gold-dim); border-radius: 6px;
  box-shadow: 0 30px 80px rgba(0,0,0,.8); --card-h: min(36vh, 320px);
}
.choice__title { margin: 0; font: 600 22px var(--serif); color: var(--paper); text-align: center; text-wrap: balance; }
.choice__sub { margin: 0; font: 400 var(--fs-label) var(--sans); color: var(--on-ink-dim); text-align: center; }
.choice__cards { display: flex; flex-wrap: wrap; justify-content: center; gap: 12px; max-height: 60vh; overflow: auto; padding: 8px; }
.choice__btns { display: flex; gap: 10px; }
.choice__reopen {
  position: absolute; left: 50%; translate: -50% 0; top: calc(var(--hud) + 6px); z-index: 45;
  padding: 7px 14px; border-radius: 4px; font: 600 var(--fs-label) var(--sans);
  color: var(--ink); background: var(--gold); border: 0; cursor: pointer; box-shadow: 0 6px 18px rgba(0,0,0,.6);
}
.focus__modes .mode {
  padding: 12px 16px; border-radius: 4px; text-align: left;
  font: 500 var(--fs-body) var(--sans); color: var(--paper);
  background: rgba(20,16,12,.92); border: 1px solid var(--gold-dim); cursor: pointer;
  transition: background .15s, border-color .15s;
}
.focus__modes .mode:hover, .focus__modes .mode:focus-visible { background: rgba(60,46,20,.95); border-color: var(--gold); }
.focus__modes .mode small { display: block; margin-top: 3px; font: 400 var(--fs-cap)/1.4 var(--sans); color: var(--on-ink-dim); }
/* an Instant set face down as a reaction, still in hand: tap to take it back */
.card.armed { box-shadow: 0 0 0 2px var(--gold), 0 0 26px rgba(224,185,74,.45); }
.card__armed {
  position: absolute; z-index: 3; left: 50%; top: 45%; translate: -50% -50%; rotate: -8deg;
  padding: .3em .8em; border-radius: 4px; font: 700 max(13px, calc(var(--card-h) * .045)) var(--sans);
  color: var(--ink); background: var(--gold); box-shadow: 0 4px 14px rgba(0,0,0,.6); pointer-events: none;
}

/* ── level up ────────────────────────────────────────────────────────── */

.levelup {
  position: absolute; inset: 0; z-index: 50; display: grid; place-items: center; padding: 16px;
  opacity: 0; transition: opacity .45s ease; cursor: pointer;
}
/* The backdrop is its own layer: it clears while the card flies, and the card
   stays solid all the way into the hand. */
.levelup::before {
  content: ""; position: absolute; inset: 0;
  background: radial-gradient(ellipse at 50% 46%, rgba(12,9,6,.5), rgba(5,4,3,.94) 70%);
  transition: opacity .6s ease;
}
.levelup.on { opacity: 1; }
.levelup.settle::before { opacity: .55; }
.levelup.leave::before { opacity: 0; }
.levelup.settle .levelup__inner > :not(.levelup__card) { opacity: 0; transition: opacity .3s ease; }
.levelup__inner { position: relative; display: flex; flex-direction: column; align-items: center; gap: 18px; text-align: center; --card-h: min(46vh, 420px); }
.levelup__title {
  margin: 0; font: 600 clamp(56px, 12vh, 120px)/1 var(--serif); color: var(--gold);
  text-shadow: 0 0 48px rgba(224,185,74,.5), 0 4px 20px #000;
  opacity: 0; transform: scale(1.4); filter: blur(10px);
  transition: opacity .5s ease, transform 1s var(--arrive), filter .7s ease;
}
.levelup.on .levelup__title { opacity: 1; transform: none; filter: none; }
.levelup__card {
  position: relative; opacity: 0; transform: translateY(45vh) scale(.55) rotate(-8deg);
  transition: transform .9s var(--arrive), opacity .3s ease;
}
.levelup.deal .levelup__card { opacity: 1; transform: none; }
.levelup.leave .levelup__card { opacity: 1; transition: transform .64s cubic-bezier(.5, 0, .2, 1); will-change: transform; }
.levelup.settle .levelup__card::before { opacity: 0; animation: none; transition: opacity .3s; }
/* a gold swell behind the card as it turns over */
.levelup__card::before {
  content: ""; position: absolute; inset: -18%; border-radius: 50%; z-index: -1;
  background: radial-gradient(closest-side, rgba(224,185,74,.55), rgba(224,185,74,0));
  opacity: 0; transform: scale(.6);
}
.levelup.shown .levelup__card::before { animation: level-swell 1.8s ease-out forwards; }
.levelup.leave .levelup__card::before { display: none; }
@keyframes level-swell { 0% { opacity: 0; transform: scale(.6); } 30% { opacity: 1; transform: scale(1.1); } 100% { opacity: .35; transform: scale(1); } }
.levelup .flip .card { box-shadow: 0 0 0 2px var(--gold), 0 30px 70px rgba(0,0,0,.85); }
.levelup__sub, .levelup__others { margin: 0; opacity: 0; transform: translateY(8px); transition: opacity .4s ease, transform .5s var(--settle); }
.levelup.shown :is(.levelup__sub, .levelup__others) { opacity: 1; transform: none; }
.levelup__sub { font: 400 var(--fs-lead) var(--sans); color: var(--paper); text-shadow: 0 2px 10px #000; }
.levelup__sub b { color: var(--gold); font-weight: 600; }
.levelup__others { font: 400 var(--fs-label) var(--sans); color: var(--on-ink); max-width: 60ch; }

/* in the hand: held open while the card flies in, then a gold ring as it lands */
.hand > .card.landing { opacity: 0; }
.hand > .card.landed { animation: card-landed 1.4s ease-out both; }
/* only the light fades: the card is already exactly where the flying one arrived */
@keyframes card-landed {
  0% { box-shadow: 0 0 0 2px var(--gold), 0 0 60px rgba(224,185,74,.8); }
  100% { box-shadow: 0 0 0 0 rgba(224,185,74,0), 0 4px 14px rgba(0,0,0,.55); }
}

/* ── results ─────────────────────────────────────────────────────────── */

.results {
  z-index: 22; left: 50%; top: 50%; translate: -50% -50%;
  width: min(680px, 92vw); max-height: 78vh; overflow: auto;
  background: linear-gradient(180deg, rgba(34,28,21,.97), rgba(16,13,10,.97));
  border: 1px solid var(--gold-dim); border-radius: 14px;
  box-shadow: 0 30px 80px rgba(0,0,0,.8);
  padding: 22px 24px 18px;
}
.results__title { margin: 0 0 14px; font: 600 26px var(--serif); color: var(--paper); text-align: center; }
.results__rows { display: flex; flex-direction: column; gap: 8px; }
.rrow {
  display: grid; grid-template-columns: 44px 1fr auto; gap: 14px; align-items: center;
  padding: 10px 12px; border-radius: 9px; background: rgba(0,0,0,.28); border: 1px solid rgba(255,255,255,.05);
  animation: rise .7s var(--arrive) both;
}
.rrow img { width: 44px; height: 44px; border-radius: 50%; border: 2px solid var(--gold-dim); object-fit: cover; }
.rrow__who b { display: block; font: 600 15px var(--sans); color: var(--paper); }
.rrow__who span { font: 400 var(--fs-label) var(--sans); color: var(--on-ink-dim); }
.rrow__who span em { font-style: normal; color: var(--gold); }
.rrow__ls { font: 600 20px var(--mono); color: var(--life); text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.rrow__ls small { display: block; font: 600 var(--fs-cap) var(--sans); font-variant-numeric: tabular-nums; }
.rrow__ls .down { color: var(--blood-lit); }
.rrow__ls .up { color: var(--heal); }
.rrow__ls .same { color: var(--on-ink-dim); }
.rrow.out { opacity: .55; }
.rrow .badges { grid-column: 2 / -1; margin-top: 0; }
.results__go {
  display: block; margin: 16px auto 10px; background: transparent; border: 0;
  color: var(--gold); font: 600 var(--fs-label) var(--sans);
}
.results__bar { height: 2px; background: rgba(224,185,74,.15); border-radius: 2px; overflow: hidden; }
.results__bar i { display: block; height: 100%; width: 100%; background: var(--gold); transform-origin: left; }

/* ── game over ───────────────────────────────────────────────────────── */

.over {
  inset: 0; z-index: 35; display: flex; flex-direction: column; align-items: center; justify-content: safe center; gap: 14px;
  overflow-y: auto;
  /* near-solid, so the result reads over whatever the table was doing */
  background: radial-gradient(60% 50% at 50% 38%, rgba(70,52,16,.35), transparent 70%), rgba(7,6,4,.93);
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
  text-align: center; padding: 5vh 5vw;
}
.over h2 { margin: 0; font: 600 clamp(44px, 8vw, 84px) var(--serif); color: var(--gold); text-shadow: 0 6px 40px rgba(224,185,74,.3); }
.over p { margin: 0 0 12px; font-size: 16px; color: var(--on-ink); }
/* a full table of six scrolls inside the panel rather than pushing the button off screen */
.over__rows { width: min(520px, 90vw); max-height: 50vh; overflow-y: auto; flex: none; display: flex; flex-direction: column; gap: 8px; margin-bottom: 14px; padding: 2px; }

.over__btns { display: flex; flex-wrap: wrap; justify-content: center; gap: 10px; }

/* ── the tutorial's coach (tutorial.js) ──────────────────────────────── */

/* The ring is a spotlight: a hole in a dim sheet, drawn as one huge shadow. It
   sits under the hover preview, so reading a card is never dimmed. */
.coach__ring {
  position: fixed; left: 0; top: 0; z-index: 62; pointer-events: none; border-radius: 10px;
  border: 2px solid var(--gold); box-shadow: 0 0 0 9999px rgba(4,3,2,.55), 0 0 28px rgba(224,185,74,.45);
  /* never slides or resizes: it fades out, is put down in the new place, and fades in */
  opacity: 0; transition: opacity .26s ease;
}
.coach__ring.in { opacity: 1; }
.coach__tip {
  position: fixed; left: 0; top: 0; z-index: 86; width: min(340px, calc(100vw - 24px));
  padding: 14px 16px 12px; border-radius: 8px; text-align: left;
  background: linear-gradient(180deg, #2B2318, #17120D); border: 1px solid var(--gold);
  box-shadow: 0 18px 50px rgba(0,0,0,.8);
  opacity: 0; transition: opacity .26s ease;
}
.coach__tip.in { opacity: 1; }
.coach__text { margin: 0 0 10px; font: 400 var(--fs-body)/1.5 var(--sans); color: var(--on-ink); }
.coach__text b { color: var(--paper); font-weight: 600; }
.coach__row { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.coach__skip { padding: 4px 0; border: 0; background: none; cursor: pointer; font: 400 var(--fs-label) var(--sans); color: var(--on-ink-dim); text-decoration: underline; text-underline-offset: 3px; }
.coach__skip:hover { color: var(--on-ink); }
.coach__next { margin-left: auto; }
.coach__arrow { position: absolute; width: 14px; height: 14px; rotate: 45deg; background: #2B2318; border: 1px solid var(--gold); }
.coach__arrow[data-side="below"] { top: -8px; margin-left: -7px; border-right: 0; border-bottom: 0; }
.coach__arrow[data-side="above"] { bottom: -8px; margin-left: -7px; border-left: 0; border-top: 0; background: #17120D; }
.coach__arrow[data-side="right"] { left: -8px; margin-top: -7px; border-right: 0; border-top: 0; }
.coach__arrow[data-side="left"] { right: -8px; margin-top: -7px; border-left: 0; border-bottom: 0; }
@media (prefers-reduced-motion: reduce) { .coach__ring, .coach__tip { transition: none; } }

/* nothing in hand can be played (Locked, say): the turn can be passed rather than waited out */
.passbtn { position: absolute; left: 50%; translate: -50% 0; bottom: calc(var(--hand-card) * 1.12 + 34px); z-index: 17; }
.passbtn[hidden] { display: none; }
/* a practice table has no clock and nobody to invite */
.lobby[data-practice] :is(#copyLink, #turnLen) { display: none; }

/* ── how to play ─────────────────────────────────────────────────────── */

.help {
  position: fixed; inset: 0; z-index: 95; display: grid; place-items: center; padding: 16px;
  background: rgba(6,5,4,.8); backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
  animation: fade-in .2s ease;
}
.help[hidden] { display: none; }
.help__panel {
  width: min(680px, 100%); max-height: calc(100vh - 32px); overflow-y: auto; padding: 24px 26px;
  background: linear-gradient(180deg, rgba(34,28,21,.98), rgba(16,13,10,.98));
  border: 1px solid var(--gold-dim); border-radius: 8px; box-shadow: 0 30px 80px rgba(0,0,0,.8);
  text-align: left; color: var(--on-ink);
}
.help__panel h2 { margin: 0 0 12px; font: 600 28px var(--serif); color: var(--paper); }
.help__panel h3 { margin: 18px 0 8px; font: 600 var(--fs-body) var(--sans); color: var(--paper); }
.help__steps { margin: 0; padding-left: 1.3em; display: grid; gap: 8px; font: 400 var(--fs-body)/1.5 var(--sans); }
.help__steps b { color: var(--paper); font-weight: 600; }
.help__terms { margin: 0; display: grid; gap: 6px; }
.help__terms > div { display: grid; grid-template-columns: 9.5em minmax(0, 1fr); gap: 12px; font: 400 15px/1.45 var(--sans); }
.help__terms dt { color: var(--gold); font-weight: 600; }
.help__terms dd { margin: 0; }
/* the first-visit welcome: three ways in, as three rows */
.intro .help__panel { max-width: 34rem; }
.intro__ways { margin: 4px 0 20px; padding: 0; list-style: none; display: grid; gap: 14px; }
.intro__ways li { display: grid; grid-template-columns: 44px minmax(0, 1fr); gap: 14px; align-items: start; }
.intro__ways img { width: 44px; height: 44px; border-radius: 4px; object-fit: cover; }
.intro__ways b { display: block; font: 600 20px/1.2 var(--serif); color: var(--paper); margin-bottom: 2px; }
.intro__ways p { margin: 0; font: 400 15px/1.5 var(--sans); }
.intro__btns { display: flex; flex-wrap: wrap; gap: 10px; }
.help__tip { margin: 16px 0 18px; font: 400 15px/1.5 var(--sans); color: var(--on-ink); }
@media (max-width: 520px) {
  .help__panel { padding: 18px 16px; }
  .help__terms > div { grid-template-columns: 1fr; gap: 0; }
}

/* ── floating numbers ────────────────────────────────────────────────── */

.float {
  position: fixed; z-index: 60; pointer-events: none;
  font: 600 40px var(--mono); font-variant-numeric: tabular-nums;
  text-shadow: 0 3px 14px rgba(0,0,0,.95);
  animation: float-up 1.15s var(--ease) forwards;
}
.float.dmg { color: var(--blood-lit); }
.float.heal { color: var(--heal); }
.float.word { font: 700 20px var(--sans); text-transform: capitalize; color: var(--gold); }
@keyframes float-up {
  0% { transform: translate(-50%, 0) scale(.5); opacity: 0; }
  18% { transform: translate(-50%, -14px) scale(1.2); opacity: 1; }
  100% { transform: translate(-50%, -80px) scale(1); opacity: 0; }
}

/* ── dice ────────────────────────────────────────────────────────────── */

.dice { position: absolute; left: 50%; top: 50%; translate: -50% -50%; z-index: 45; display: none; flex-direction: column; align-items: center; gap: 10px; }
.dice.on { display: flex; }
.dice svg { width: min(170px, 26vmin); height: auto; filter: drop-shadow(0 14px 30px rgba(0,0,0,.75)); }
.dice[data-rolling="true"] svg { animation: tumble .34s linear infinite; }
@keyframes tumble { 0% { transform: rotate(0) scale(1); } 25% { transform: rotate(-9deg) scale(.96); } 50% { transform: rotate(6deg) scale(1.03); } 75% { transform: rotate(-4deg) scale(.98); } 100% { transform: rotate(0) scale(1); } }
.d-face { fill: #1C1814; } .d-face--lit { fill: #262019; } .d-face--top { fill: #2E2620; }
.d-edge { fill: none; stroke: var(--gold-dim); stroke-width: 1.4; stroke-linejoin: round; }
.d-edge--out { stroke: var(--gold); stroke-width: 3; }
.d-num { fill: var(--paper); font: 700 42px var(--serif); text-anchor: middle; font-variant-numeric: tabular-nums; }
.dice__need { font: 500 var(--fs-label) var(--sans); color: var(--on-ink-dim); background: rgba(0,0,0,.7); border: 1px solid var(--hairline); border-radius: 4px; padding: 5px 12px; }
.dice.hit .dice__need { color: var(--gold); border-color: var(--gold-dim); }
.dice.hit .d-num { fill: var(--gold); }
.dice.crit svg { animation: crit 1s var(--arrive); }
.dice.crit .dice__need { color: var(--ink); background: var(--gold); border-color: var(--gold); }
@keyframes crit { 0% { transform: scale(1); } 30% { transform: scale(1.22); } 100% { transform: scale(1); } }

/* ── the thrown die (die.js) ─────────────────────────────────────────
   A 3D d20 on its own canvas above the table. The panel names the card and
   lays out 1–20 with the success range in gold; while the die tumbles, the
   number on top runs along the track, so everyone can read the throw as it
   happens. */

.die-canvas { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 46; pointer-events: none; display: block; }
/* the table steps back while a die is out; the card that asked for it stays lit */
.roll-scrim { position: absolute; inset: 0; z-index: 40; background: rgba(6,5,4,.7); pointer-events: none; animation: fade-in .3s ease; }
[data-roll] .stage { z-index: 41; }
.die-shadow {
  position: absolute; left: 0; top: 0; z-index: 44; border-radius: 50%; pointer-events: none; will-change: transform;
  background: radial-gradient(closest-side, rgba(0,0,0,.8), rgba(0,0,0,.4) 55%, transparent);
}

/* The grab target is the die itself, a little larger than it looks. The ring
   around it is the time left before the die throws itself. */
.die-grab {
  position: absolute; left: 0; top: 0; z-index: 47; border: 0; padding: 0; border-radius: 50%;
  background: transparent; cursor: grab; touch-action: none; will-change: transform; --p: 1;
}
.die-grab::before, .die-grab::after { content: ""; position: absolute; inset: 0; border-radius: 50%; pointer-events: none; }
.die-grab::before {
  background: conic-gradient(var(--gold) calc(var(--p) * 360deg), rgba(224,185,74,.12) 0);
  -webkit-mask: radial-gradient(closest-side, transparent calc(100% - 3px), #000 calc(100% - 2px));
          mask: radial-gradient(closest-side, transparent calc(100% - 3px), #000 calc(100% - 2px));
}
.die-grab::after { box-shadow: 0 0 0 0 rgba(224,185,74,.35); animation: grab-call 1.6s ease-out infinite; }
.die-grab.held { cursor: grabbing; }
.die-grab.held::before, .die-grab.held::after { opacity: 0; }
.die-grab:focus-visible { outline: 2px solid var(--gold); outline-offset: 4px; }
@keyframes grab-call { 0% { box-shadow: 0 0 0 0 rgba(224,185,74,.34); } 100% { box-shadow: 0 0 0 22px rgba(224,185,74,0); } }

.die-hint {
  position: absolute; left: 0; top: 0; z-index: 47; margin: 0; pointer-events: none; white-space: nowrap;
  font: 500 17px var(--sans); color: var(--paper); text-shadow: 0 2px 12px #000, 0 0 2px #000;
  animation: fade-in .4s ease both;
}

.die-result {
  position: absolute; z-index: 48; translate: -50% -100%; pointer-events: none;
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  animation: result-in .7s var(--arrive) both;
}
.die-result.below { translate: -50% 0; }
.die-result b {
  font: 700 clamp(46px, 8vmin, 76px)/1 var(--serif); font-variant-numeric: lining-nums tabular-nums;
  color: var(--gold); text-shadow: 0 0 26px rgba(224,185,74,.55), 0 4px 18px #000;
}
.die-result span { font: 600 16px var(--sans); color: var(--gold); text-shadow: 0 2px 8px #000; }
.die-result.miss b { color: var(--on-ink); text-shadow: 0 4px 18px #000; }
.die-result.miss span { color: var(--on-ink-dim); }
.die-result.crit span { background: var(--gold); color: var(--ink); padding: 3px 9px; border-radius: 4px; text-shadow: none; }
.die-result.out { opacity: 0; transition: opacity .3s; }
@keyframes result-in { from { scale: .3; opacity: 0; } 40% { opacity: 1; } }

.roll {
  position: absolute; left: 50%; top: 21vh; translate: -50% 0; z-index: 42; width: min(620px, 94vw);
  display: flex; flex-direction: column; align-items: center; gap: 4px; text-align: center; pointer-events: none;
  padding: 12px 18px 14px; border-radius: 6px; background: rgba(12,10,7,.92); border: 1px solid var(--hairline);
  box-shadow: 0 18px 50px rgba(0,0,0,.7);
  animation: roll-in .55s var(--arrive) both;
}
.roll p { margin: 0; }
.roll.out { opacity: 0; transition: opacity .3s; }
@keyframes roll-in { from { opacity: 0; translate: -50% -14px; } }
.roll__who { font: 500 15px var(--sans); color: var(--gold); text-shadow: 0 2px 10px #000; }
.roll__card { font: 600 clamp(24px, 3.6vmin, 34px)/1.15 var(--serif); color: var(--paper); text-shadow: 0 2px 12px #000; }
.roll__track { display: grid; grid-template-columns: repeat(20, 1fr); gap: 3px; width: 100%; margin: 8px 0 2px; }
.pip {
  height: 28px; border-radius: 3px; display: grid; place-items: center; font-style: normal;
  font: 500 var(--fs-cap) var(--mono); font-variant-numeric: tabular-nums; color: var(--on-ink-dim);
  background: rgba(14,11,8,.72); border: 1px solid rgba(255,255,255,.08);
  transition: background .1s, color .1s, transform .1s, border-color .1s;
}
.pip.in { border-color: var(--gold-dim); color: var(--gold); background: rgba(40,31,14,.85); }
.pip.live { background: #4a4238; color: var(--paper); transform: translateY(-3px); }
.pip.in.live { background: #8a6f28; color: var(--paper); }
.pip.result { transform: translateY(-5px) scale(1.28); z-index: 1; animation: pip-land .55s var(--arrive); }
.pip.result.hit { background: var(--gold); border-color: var(--gold); color: var(--ink); box-shadow: 0 0 20px rgba(224,185,74,.65); }
.pip.result.miss { background: #3a1a12; border-color: var(--blood); color: var(--paper); }
@keyframes pip-land { from { transform: translateY(-16px) scale(1.6); } }

/* While a die is in the air the table steps back; only the card that asked
   for the roll stays lit. */
[data-roll] .stage__band { opacity: 0; }
[data-roll] .stage .pending:not(:has(.acting)) { opacity: .28; filter: saturate(.6); }
[data-roll] .stage__cards { transform: translateY(9vh) scale(.84); }
.stage .pending { transition: opacity .35s ease, filter .35s ease; }
.stage__cards { transition: transform .6s var(--settle); }

@media (max-width: 560px) {
  .roll { top: calc(var(--hud) + 8px); }
  .roll__track { gap: 2px; }
  /* two rows of ten, so every number stays readable on a phone */
  .roll__track { grid-template-columns: repeat(10, 1fr); }
  .pip { height: 26px; }
  .die-hint { font-size: 16px; }
}
@media (prefers-reduced-motion: reduce) {
  .die-grab::after { animation: none; }
}

/* a seat that Defends wears a brief ward */
.seat.guarding { box-shadow: 0 0 0 2px var(--gold-dim), 0 0 0 7px rgba(224,185,74,.12), 0 0 36px rgba(224,185,74,.25); }

/* ── zoom preview ────────────────────────────────────────────────────── */

.zoom {
  --card-h: min(70vh, 520px, 128vw);
  position: fixed; z-index: 80; top: 50%; left: 50%; transform: translate(-50%, -50%);
  pointer-events: none; display: flex; flex-direction: column; align-items: center; gap: 10px;
  animation: zoom-in .16s ease-out;
}
.zoom .card { box-shadow: 0 24px 60px rgba(0,0,0,.85); transform: none !important; filter: none !important; }
.zoom__why { font: 500 var(--fs-label) var(--sans); color: var(--blood-lit); background: rgba(10,8,6,.92); border: 1px solid var(--blood); border-radius: 4px; padding: 5px 12px; }
/* what a chip means, under the card it came from (or on its own) */
.zoom__note {
  max-width: min(34ch, 80vw); padding: 9px 14px; border-radius: 4px; text-align: center;
  font: 400 15px/1.45 var(--sans); color: var(--paper);
  background: rgba(14,11,8,.95); border: 1px solid var(--hairline); box-shadow: 0 12px 30px rgba(0,0,0,.7);
}
@keyframes zoom-in { from { transform: translate(-50%, -50%) scale(.94); } }

/* ════════════════════════════════════════════════════════════════════
   SCENES — where each region sits, and how big things are, per mode.
   ════════════════════════════════════════════════════════════════════ */

/* lobby: only the lobby exists */
[data-mode="lobby"] :is(.hud, .seats, .stage, .me, .hand, .handhint, .focus, .results, .over) { opacity: 0; pointer-events: none; visibility: hidden; }
[data-mode="lobby"] .seats { top: 0; }
[data-mode="lobby"] .hand { transform: translateY(100%); }
:not([data-mode="lobby"]) > .lobby { opacity: 0; pointer-events: none; visibility: hidden; transform: scale(1.04); }

/* pick: your hand is the scene. Opponents shrink to a strip; the stage is empty. */
[data-mode="pick"] { --seat-to: 38px; --light-y: 86%; --me-k-to: 1; --me-off-to: 58px; }
[data-mode="pick"] .stage { opacity: 0; transform: scale(.94); pointer-events: none; }

/* target: the chosen card held up on the left; targets grow into the space. */
[data-mode="target"] { --seat-to: 58px; --light-y: 50%; }
[data-mode="target"] .seats { top: 50%; translate: 0 -50%; padding-left: calc(min(62vh, 480px) * 5 / 7 + 10vw); }
[data-mode="target"] { --me-k-to: 0; --me-off-to: 3vh; }
[data-mode="target"] .me { left: calc(100% - 3vw); translate: -100% 0; }
[data-mode="target"] .hand { transform: translateY(44%) scale(.57); opacity: .45; pointer-events: none; }
[data-mode="target"] .handhint { opacity: 0; }
[data-mode="target"] .stage { opacity: 0; pointer-events: none; }

/* lay: pull back to the table. Your card lies face down in the middle. */
[data-mode="lay"] { --seat-to: 58px; --light-y: 52%; }
[data-mode="lay"] .seats { top: calc(var(--hud) + 14px); }
[data-mode="lay"] { --me-k-to: .16; --me-off-to: 28px; }
[data-mode="lay"] .me { left: 50%; translate: -50% 0; }
[data-mode="lay"] .hand { transform: translateY(36%) scale(.52); }
[data-mode="lay"] .handhint { opacity: 0; }
[data-mode="lay"] .seat__slot {
  position: static; grid-column: 1 / -1; justify-self: center; margin-top: calc(var(--seat) * .2);
  width: calc(var(--seat) * .8); height: calc(var(--seat) * 1.12); transform: none;
}
[data-mode="lay"] .seat__slot { opacity: 1; }
[data-mode="lay"] .seat__slot:not(.filled) { position: relative; border-style: dashed; animation: breathe 2s ease-in-out infinite; }
[data-mode="lay"] .seat.is-you .seat__slot { display: none; }
@keyframes breathe { 50% { border-color: var(--gold-dim); } }

/* resolve: the turn plays out full size in the centre. Nothing else competes. */
[data-mode="resolve"] { --seat-to: 56px; --light-y: 50%; }
[data-mode="resolve"] .seats { top: calc(var(--hud) + 10px); }
[data-mode="resolve"] { --me-k-to: 0; --me-off-to: 3vh; }
[data-mode="resolve"] .me { left: 50%; translate: -50% 0; }
[data-mode="resolve"] .hand { transform: translateY(112%) scale(.52); pointer-events: none; }
[data-mode="resolve"] .handhint { opacity: 0; }
[data-mode="resolve"] .stage { top: 22vh; bottom: 18vh; }
[data-mode="resolve"] .timer { opacity: .25; }

/* results: the summary rises over a dimmed table */
[data-mode="results"] { --seat-to: 56px; --light-y: 50%; }
[data-mode="results"] .seats { top: calc(var(--hud) + 10px); opacity: .35; }
[data-mode="results"] { --me-k-to: 0; --me-off-to: 3vh; }
[data-mode="results"] .me { left: 50%; translate: -50% 0; opacity: .35; }
[data-mode="results"] .hand { transform: translateY(112%) scale(.52); pointer-events: none; }
[data-mode="results"] .handhint { opacity: 0; }
[data-mode="results"] .stage { opacity: .25; filter: blur(2px); }
[data-mode="results"] .timer { opacity: .25; }

/* level up: the table steps back; the moment is drawn over it (.levelup) */
[data-mode="levelup"] { --seat-to: 56px; --light-y: 46%; }
[data-mode="levelup"] .seats { top: calc(var(--hud) + 10px); opacity: .2; }
[data-mode="levelup"] { --me-k-to: 0; --me-off-to: 3vh; }
[data-mode="levelup"] .me { left: 50%; translate: -50% 0; opacity: .2; }
[data-mode="levelup"] .hand { transform: translateY(112%) scale(.52); pointer-events: none; }
[data-mode="levelup"] :is(.handhint, .stage) { opacity: 0; }

/* spectating: you are out, the table plays on */
[data-mode="spectate"] { --seat-to: 58px; --light-y: 52%; }
[data-mode="spectate"] { --me-k-to: 0; --me-off-to: 3vh; }
[data-mode="spectate"] .me { left: 50%; translate: -50% 0; }
[data-mode="spectate"] .hand { transform: translateY(112%) scale(.52); }

/* focus and results only exist in their own scene */
:not([data-mode="target"]) > .focus { opacity: 0; pointer-events: none; visibility: hidden; translate: -40px -50%; }
:not([data-mode="results"]) > .results { opacity: 0; pointer-events: none; visibility: hidden; translate: -50% -44%; }
:not([data-mode="over"]) > .over { opacity: 0; pointer-events: none; visibility: hidden; }
[data-mode="over"] :is(.hand, .handhint, .focus, .results) { opacity: 0; pointer-events: none; }

/* When a region is in-scene, make it visible immediately — only its exit waits
   for the fade before hiding. */
[data-mode="lobby"] > .lobby,
[data-mode="target"] > .focus,
[data-mode="results"] > .results,
[data-mode="over"] > .over,
#app:not([data-mode="lobby"]) > :is(.hud, .seats, .me, .hand, .handhint) { visibility: visible; transition-delay: 0s; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* small screens: the same scenes, tighter */
@media (max-width: 720px) {
  /* On a phone the hand is a swipeable row, not a fan: overlapping cards on a
     375px screen leave nothing readable. About two and a half cards show at
     once, each snaps to centre, and press-and-hold reads one in full. */
  :where(#app) { --hand-card: min(44vh, 64vw); }
  .hand {
    --card-h: var(--hand-card); /* a row scrolls; it never shrinks to fit */
    justify-content: flex-start;
    scroll-snap-type: x mandatory; overscroll-behavior-x: contain;
    padding-inline: 19vw; scroll-padding-inline: 19vw;
    -webkit-overflow-scrolling: touch;
    /* The row has to be allowed to scroll, or it cannot be swiped at all —
       Jacob, 2026-09-25: "you can't drag Cards left or right to see all Cards
       available", so the only way to see the hand was to turn the phone. */
    overflow-x: auto; overflow-y: hidden; touch-action: pan-x; scrollbar-width: none;
  }
  .hand::-webkit-scrollbar { display: none; }
  .hand > .card + .card { margin-left: 10px; }
  .hand > .card { scroll-snap-align: center; }
  /* the hint sits to the right of your seat, not across it */
  .handhint { left: auto; right: 12px; translate: none; max-width: calc(100vw - 200px); text-align: right; }
  .hand.fanned > .card { box-shadow: 0 4px 14px rgba(0,0,0,.55); }
  /* the character select stacks: roster, art, dossier, path — the bar stays put */
  .lobby { --pad: 14px; padding: 12px var(--pad) 0; }
  .lobby__top { grid-template-columns: 1fr; justify-items: center; gap: 12px; }
  .lobby__logo { justify-self: center; width: 150px; }
  .classpick { grid-column: 1; gap: 2px; }
  .classpick img { width: 46px; }
  .classpick span { font-size: var(--fs-cap); }
  .select { grid-template-columns: minmax(0, 1fr); grid-template-rows: auto; grid-template-areas: "stage" "dossier" "path"; row-gap: 18px; padding-bottom: 22px; }
  .select__stage { min-height: 0; }
  .dossier { align-self: start; gap: 12px; }
  .dossier__name { font-size: clamp(46px, 14vw, 64px); }
  .facts > div { padding: 0 10px; }
  .facts dd { flex-wrap: wrap; row-gap: 2px; }
  .facts dd b { font-size: 23px; } .facts dd b.word { font-size: 20px; }
  .profile { --k: 92px; --gap: 8px; }
  .path__list { grid-template-columns: minmax(0, 1fr); grid-template-rows: none; grid-auto-flow: row; }
  .select__stage { height: min(58vw, 28vh); }
  /* two rows, thumb-sized: your name, then new room · code · join */
  .lobby__bar { gap: 8px; padding-top: 10px; padding-bottom: calc(10px + env(safe-area-inset-bottom)); }
  .lobby__name { width: 100%; }
  .lobby__name span, .lobby__or { display: none; }
  .lobby__name input { flex: 1; width: auto; min-width: 0; }
  .lobby__join, .lobby__wait { width: 100%; flex-wrap: nowrap; gap: 8px; }
  .lobby__bar .btn.big { padding: 11px 14px; font-size: 14px; }
  .lobby__join #newRoom { flex: 1; }
  .lobby__join #code { width: 6.6em; min-width: 0; }
  #newRoom .lg { display: none; } #newRoom .sm { display: inline; }
  .lobby__wait { flex-wrap: wrap; justify-content: space-between; }
  .lobby__wait #start { flex: 1 1 100%; }
  .hud__logo, .hud__turn { display: none; }
  .hud__btn .lg { display: none; } .hud__btn .sm { display: inline; }
  .lobby__help { position: absolute; top: 12px; right: var(--pad); grid-column: auto; }
  /* targets: the opponents in a row above your own seat, both at the foot of
     the screen; the card you are playing fills the space above */
  [data-mode="target"] { --seat-to: 54px; --me-off-to: calc(var(--hand-card) * .12 + 12px); }
  [data-mode="target"] .seats {
    top: auto; bottom: calc(var(--hand-card) * .12 + 12px + var(--seat) * 1.45 + 10px); translate: none;
    padding-left: 3vw; justify-content: flex-start; gap: 8px;
  }
  [data-mode="target"] .seat.targetable::before { left: auto; right: 8px; bottom: auto; top: 50%; translate: 0 -50%; }
  [data-mode="target"] .seat.targetable .seat__id { padding-right: 68px; }
  [data-mode="target"] .focus { left: 50%; top: calc(var(--hud) + 10px); translate: -50% 0; --card-h: min(42vh, 380px); gap: 10px; }
  [data-mode="target"] .focus:has(.focus__modes:not([hidden])) { --card-h: min(22vh, 380px); }
}

/* ── narrow phones: six medallions across 360px leave no room for six names ── */
@media (max-width: 430px) {
  .classpick { gap: 0; width: 100%; justify-content: space-between; }
  .classpick button { padding: 4px 0; flex: 1 1 0; min-width: 0; }
  .classpick img { width: min(46px, 12vw); }
  /* the chosen name reads in the dossier below; the rest go to screen readers */
  .classpick button > span { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .classpick__who { max-width: 180%; }
}

/* ── short screens (a phone on its side): everything shorter, the focus column goes sideways ── */
@media (max-height: 520px) {
  :root { --hud: 46px; }
  .hud { padding: 0 12px; gap: 10px; }
  .hud__logo { display: none; }
  .timer { width: 36px; height: 36px; }
  .banner { padding: 6px 12px; }

  :where(#app) { --hand-card: clamp(140px, 46vh, 220px); }
  [data-mode="pick"] { --seat-to: 32px; --me-off-to: 30px; }
  .hand { padding-top: 10px; }
  .handhint { bottom: calc(var(--hand-card) * 1.08 + 12px); }

  [data-mode="target"] { --seat-to: 44px; }
  .focus { --card-h: min(52vh, 480px); left: 3vw; gap: 8px; }
  .focus__hint { font-size: 20px; }
  [data-mode="target"] .seats { padding-left: calc(min(52vh, 480px) * 5 / 7 + 8vw); }
  /* the card on the left; the question, the list and the buttons beside it */
  .focus:has(.focus__modes:not([hidden])) {
    --card-h: min(52vh, 480px);
    display: grid; grid-template-columns: auto minmax(0, 320px); grid-template-areas: "card hint" "card modes" "card btns";
    column-gap: 16px; row-gap: 8px; align-items: center; justify-items: start;
  }
  .focus:has(.focus__modes:not([hidden])) .focus__card { grid-area: card; }
  .focus:has(.focus__modes:not([hidden])) .focus__hint { grid-area: hint; text-align: left; }
  .focus:has(.focus__modes:not([hidden])) .focus__modes { grid-area: modes; width: 100%; }
  .focus:has(.focus__modes:not([hidden])) .focus__btns { grid-area: btns; }
  .focus__modes .mode { padding: 8px 12px; }
  [data-mode="target"]:has(.focus__modes:not([hidden])) .seats { padding-left: calc(min(52vh, 480px) * 5 / 7 + 340px + 8vw); }

  [data-mode="lay"], [data-mode="resolve"], [data-mode="results"], [data-mode="levelup"], [data-mode="spectate"] { --seat-to: 36px; }
  .stage { --card-h: clamp(120px, 34vh, 320px); }
  [data-mode="resolve"] .stage { top: 19vh; bottom: 13vh; }
  .stage__owner { margin-top: 4px; }

  .levelup__title { font-size: clamp(34px, 10vh, 120px); }
  .levelup__inner { --card-h: min(40vh, 420px); gap: 10px; }
  .roll { top: calc(var(--hud) + 6px); padding: 8px 14px 10px; }
  .roll__track { margin: 4px 0 0; }
  .pip { height: 22px; }
  .zoom { --card-h: min(84vh, 520px); }
  .results { max-height: calc(100vh - var(--hud) - 16px); top: calc(50% + var(--hud) / 2); padding: 14px 16px 12px; }
  .results__title { margin-bottom: 8px; font-size: 22px; }
  .over { gap: 8px; }
  .over h2 { font-size: clamp(32px, 9vh, 84px); }

  /* the lobby bar: one tight row, so the class still has the screen */
  .lobby__bar { gap: 8px 16px; padding-top: 8px; padding-bottom: calc(8px + env(safe-area-inset-bottom)); }
  .lobby__bar .btn.big { padding: 9px 14px; font-size: 14px; }
  .lobby__name input { width: 11em; }
  .lobby__seated .who small { display: none; }
  .select__stage { min-height: 200px; }
}

/* ── big desktops: the same scenes, with the room they have ── */
@media (min-width: 1800px) and (min-height: 1000px) {
  :root { --hud: 64px; }
  :where(#app) { --hand-card: clamp(220px, 42vh, 500px); }
  [data-mode="pick"] { --seat-to: 46px; }
  .handhint { font-size: var(--fs-body); }
  [data-mode="target"] { --seat-to: 68px; }
  .focus { --card-h: min(62vh, 600px); }
  .focus:has(.focus__modes:not([hidden])) { --card-h: min(40vh, 600px); }
  [data-mode="target"] .seats { padding-left: calc(min(62vh, 600px) * 5 / 7 + 10vw); }
  [data-mode="lay"], [data-mode="resolve"], [data-mode="results"], [data-mode="levelup"], [data-mode="spectate"] { --seat-to: 68px; }
  .stage { --card-h: clamp(170px, 32vh, 420px); }
  .zoom { --card-h: min(70vh, 660px); }
  .levelup__inner { --card-h: min(46vh, 520px); }
  .results { width: min(760px, 92vw); }
  .roll { width: min(720px, 94vw); }
  .pip { height: 32px; }
}


/* ── An Instant's moment ───────────────────────────────────────────────
   Jacob: "a flashing icon that shows up for a few seconds (maybe 5) — maybe a
   hot key etc. — dont give them long." So: loud, central, keyboard-first, and
   visibly running out. */
.instant {
  position: fixed; left: 50%; bottom: 12vh; translate: -50% 0; z-index: 90;
  display: grid; gap: .55rem; justify-items: center;
  padding: 1rem 1.15rem 1.15rem; border-radius: 12px;
  background: rgba(14, 12, 10, .94); border: 1px solid var(--gold);
  box-shadow: 0 0 0 1px rgba(0,0,0,.6), 0 18px 60px rgba(0,0,0,.7), 0 0 60px rgba(224,185,74,.22);
  animation: instant-in .18s ease-out, instant-pulse 1s ease-in-out infinite .18s;
  max-width: min(92vw, 34rem);
}
@keyframes instant-in { from { opacity: 0; translate: -50% 14px; } }
@keyframes instant-pulse {
  50% { box-shadow: 0 0 0 1px rgba(0,0,0,.6), 0 18px 60px rgba(0,0,0,.7), 0 0 78px rgba(224,185,74,.42); }
}
.instant__clock { width: 100%; height: 3px; border-radius: 2px; background: rgba(224,185,74,.18); overflow: hidden; }
.instant__clock i { display: block; height: 100%; width: 100%; background: var(--gold); transform-origin: left; }
.instant__why { margin: 0; font: 600 var(--fs-body) var(--sans); color: var(--parch); text-align: center; }
.instant__cards { display: flex; flex-wrap: wrap; gap: .5rem; justify-content: center; }
.instant__card {
  display: grid; gap: .1rem; justify-items: start; text-align: left;
  padding: .5rem .7rem; border-radius: 8px; cursor: pointer;
  background: var(--gold); color: var(--ink); border: 0;
  font: 700 var(--fs-body) var(--sans);
}
.instant__card:hover, .instant__card:focus-visible { filter: brightness(1.08); outline: 2px solid var(--parch); }
.instant__card small { font: 500 var(--fs-label) var(--sans); opacity: .78; }
.instant__card kbd {
  font: 700 var(--fs-label) var(--mono, var(--sans)); background: rgba(0,0,0,.22);
  border-radius: 4px; padding: 0 .3rem; margin-right: .35rem;
}
.instant__pass kbd { font: 600 var(--fs-label) var(--sans); opacity: .7; margin-left: .3rem; }
@media (prefers-reduced-motion: reduce) {
  .instant { animation: none; }
}

@keyframes instant-drain { to { transform: scaleX(0); } }

/* A summon is aimed at from its chip, so the chip carries the same
   targetable/chosen states a seat does. */
.chip.targetable { cursor: pointer; border-color: var(--gold); }
[data-mode="target"] .chip.targetable { box-shadow: 0 0 0 1px var(--gold), 0 0 14px rgba(224,185,74,.3); }
.chip.picked { background: var(--gold); color: var(--ink); border-color: var(--gold); }
.chip.picked b, .chip.picked i { color: inherit; }


/* ── The convention gate ───────────────────────────────────────────────
   A booth queue is the whole design brief: one field that matters, a big
   button, and the keyboard already in the right place. */
/* `display` on the element beats the hidden attribute, so say so explicitly. */
.gate[hidden] { display: none; }
.gate {
  position: fixed; inset: 0; z-index: 120;
  display: grid; place-items: center; padding: 6vh 1rem;
  background: radial-gradient(60% 50% at 50% 40%, rgba(40,30,12,.6), rgba(8,7,6,.97));
  overflow: auto;
}
.gate__panel {
  width: min(28rem, 100%); display: grid; gap: .55rem; justify-items: center; text-align: center;
  padding: 1.6rem 1.4rem 1.2rem; border-radius: 14px;
  background: rgba(14, 12, 10, .96); border: 1px solid var(--gold);
  box-shadow: 0 24px 80px rgba(0,0,0,.7), 0 0 70px rgba(224,185,74,.16);
}
.gate__mark { width: 4.5rem; height: auto; opacity: .95; margin-bottom: .2rem; }
.gate__title { margin: 0; font: 400 var(--fs-h1, 2rem) var(--display, var(--sans)); color: var(--parch); }
.gate__sub { margin: 0 0 .5rem; font: 400 var(--fs-body) var(--sans); color: var(--parch); opacity: .8; }
.gate__form { display: grid; gap: .3rem; width: 100%; text-align: left; }
.gate__label { font: 600 var(--fs-label) var(--sans); color: var(--parch); opacity: .75; }
.gate__label span { opacity: .6; font-weight: 400; }
.gate__input {
  width: 100%; padding: .7rem .8rem; margin-bottom: .45rem;
  font: 400 1rem var(--sans); color: var(--parch);
  background: rgba(0,0,0,.45); border: 1px solid rgba(224,185,74,.35); border-radius: 8px;
}
.gate__input:focus-visible { outline: 2px solid var(--gold); outline-offset: 1px; border-color: var(--gold); }
.gate__go { width: 100%; margin-top: .35rem; }
.gate__err { margin: 0 0 .3rem; font: 600 var(--fs-label) var(--sans); color: var(--ember, #e0714f); }
.gate__fine { margin: .5rem 0 0; font: 400 var(--fs-label) var(--sans); color: var(--parch); opacity: .55; }

/* The owner sign-in reuses the gate's panel, over the lobby rather than before it. */
.signin { z-index: 125; }
.signin .gate__panel { position: relative; }
.signin__x {
  position: absolute; top: .4rem; right: .5rem; width: 2.2rem; height: 2.2rem;
  font: 400 1.5rem/1 var(--sans); color: var(--parch); background: none; border: 0; cursor: pointer; opacity: .7;
}
.signin__x:hover, .signin__x:focus-visible { opacity: 1; }
.signin .gate__sub b { color: var(--gold); font-weight: 600; word-break: break-all; }
.dossier__signin {
  padding: 0; font: inherit; color: var(--gold); background: none; border: 0;
  text-decoration: underline; text-underline-offset: 2px; cursor: pointer;
}

/* ── v2 (2026-09-25) ─────────────────────────────────────────────────── */

/* A summon struck on its own chip, so the table can see it was the summon. */
.chip.struck { animation: chip-struck .9s ease-out; box-shadow: 0 0 0 2px var(--blood-lit), 0 0 18px rgba(200, 60, 40, .55); }
@keyframes chip-struck { 0% { transform: scale(1); } 18% { transform: scale(1.28) rotate(-3deg); } 40% { transform: scale(.94); } 100% { transform: none; } }

/* Aim tools: "Target all", and Taciturnity's Blinded-or-Silenced per target. */
.focus__modes .mode--row { display: flex; align-items: center; gap: 8px; cursor: default; }
.focus__modes .mode--row > span { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mode__pick { padding: 5px 10px; border-radius: 4px; border: 1px solid var(--hairline); background: transparent; color: var(--on-ink-dim); }
.mode__pick.on { border-color: var(--gold); color: var(--paper); background: rgba(224, 185, 74, .14); }

/* Taunted, said loudly where the hand is. */
.hint__warn { display: inline-block; margin-right: 6px; padding: 3px 10px; border-radius: 4px; color: var(--paper); background: rgba(150, 30, 20, .55); border: 1px solid var(--blood-lit); }

/* ── a phone held upright: the turn plays out in a row, under the seats ──
   Jacob, 2026-09-25: after every play he had to turn the phone sideways "to
   actually see what happens" — upright, the played cards stacked full size down
   the screen, over the seats. They sit in one row now, sized so every card
   played this turn fits across (--n is set by timeline.js). */
@media (max-width: 720px) and (orientation: portrait) {
  [data-mode="resolve"], [data-mode="lay"], [data-mode="results"], [data-mode="levelup"], [data-mode="spectate"] { --seat-to: 34px; }
  :is([data-mode="resolve"], [data-mode="lay"], [data-mode="results"], [data-mode="spectate"]) .seats { gap: 6px; }
  .stage { --card-h: min(24vh, calc((100vw - 24px) / var(--n, 3) * 1.4 - 12px)); }
  .stage__cards { flex-wrap: nowrap; gap: 6px; }
  :is([data-mode="resolve"], [data-mode="lay"]) .stage { top: 34vh; bottom: 16vh; }
  .stage__owner { font-size: 12px; margin-top: 4px; }
  .stage__say { font-size: 17px; bottom: -34px; }
}

/* ── one thing at a time (2026-09-29) ────────────────────────────────────
   Jon: "where not absolutely necessary, hide anything that shouldn't be
   there." Each scene keeps only what it is about. */

/* Playing a card: the card and its buttons, alone and in the middle. */
[data-hold="play"] :is(.seats, .me, .stage, .hand, .handhint) { opacity: 0 !important; pointer-events: none; }
@media (min-width: 721px) and (min-height: 521px) {
  [data-hold="play"] .focus { left: 50%; translate: -50% -50%; }
}
/* Aiming: the card, and who it can go to. The hand has no part in it; your
   own seat only when you are one of the choices. */
[data-mode="target"] :is(.hand, .handhint) { opacity: 0 !important; pointer-events: none; }
[data-hold="aim"]:not([data-self-aim]) .me { opacity: 0; pointer-events: none; }
/* An Instant's moment: the offer, and the seats it can be aimed at. */
[data-hold="instant"] :is(.me, .stage, .focus) { opacity: 0 !important; pointer-events: none; }
/* Waiting on the others: your card face down, and who is still choosing. */
[data-mode="lay"] :is(.hand, .handhint) { opacity: 0; pointer-events: none; }
/* A die in the air: the die and its panel. Everything under it steps out, and
   comes back the moment it lands. */
[data-roll] :is(.seats, .me, .stage, .hand, .handhint) { opacity: 0 !important; transition: opacity .25s ease; }
/* The summary and the level-up sit over an empty table. */
[data-mode="results"] :is(.seats, .me, .stage) { opacity: 0 !important; filter: none; }
[data-mode="levelup"] :is(.seats, .me, .stage, .hud) { opacity: 0 !important; }
.levelup__go { margin: 0; font: 500 var(--fs-label) var(--sans); color: var(--on-ink-dim); opacity: 0; transition: opacity .4s ease .6s; }
.levelup__go.on { opacity: 1; }
@media (max-width: 720px) {
  /* With nothing else on screen, the card can be read at full size. */
  [data-hold="play"] .focus { top: calc(50% + var(--hud) / 2); translate: -50% -50%; --card-h: min(56vh, calc(88vw * 7 / 5)); }
}
@media (max-width: 720px) {
  /* Aiming on a phone: who you can choose along the top, the question and its
     buttons along the bottom. The card itself is left out — the question names
     it, and on a narrow screen it covered the very seats being chosen. */
  [data-hold="aim"] .focus__card { display: none; }
  [data-hold="aim"] .focus { top: auto; bottom: calc(14px + env(safe-area-inset-bottom)); translate: -50% 0; width: min(92vw, 420px); }
  [data-hold="aim"] .focus__hint { font-size: 20px; }
  [data-hold="aim"] .seats { top: calc(var(--hud) + 12px); bottom: auto; justify-content: center; padding-left: 3vw; }
  [data-hold="aim"]:not([data-self-aim]) .me { display: none; }
}
@media (max-width: 720px) {
  /* The "tap to play" line sat over your own seat. On a phone it only shows
     when it has something to warn about (Taunted); the tutorial teaches the rest. */
  .handhint:not(:has(.hint__warn)) { opacity: 0 !important; }
  .handhint:has(.hint__warn) { left: 50%; right: auto; translate: -50% 0; max-width: 92vw; text-align: center; }
}
/* The match is over: the result, over an empty table. */
[data-mode="over"] :is(.seats, .me, .stage) { opacity: 0 !important; pointer-events: none; }

@media (max-width: 720px) {
  /* A phone: two seats to a row, each exactly half the width, so a full table
     is three tidy rows rather than a tall column. */
  .seats { gap: 8px; padding-inline: 10px; }
  .seats .seat, .me .seat, .seat { --w: calc((100vw - 28px) / 2); padding: 6px 8px; column-gap: 7px; row-gap: 6px; }
  .seat__tag { display: none; } /* "CPU" and "you" — the portrait and your position say it */
  .fx { --chip-h: 20px; }
  .chip { padding: 0 6px; font-size: 11px; }
  .chip b { max-width: 6.5em; }
}

/* The opposing row always fits on one line: each seat takes its share of the
   width when the scene's own size would not fit them all (--n from game.js). */
@media (min-width: 721px) {
  /* Only where the row sits over the table (not while aiming: that scene has
     room of its own), and never so narrow the name has nowhere to go. */
  #app:not([data-mode="target"]) .seats .seat {
    --w: max(calc(var(--seat) * 3.6), min(calc(var(--seat) * 5.6),
      calc((100vw - 6vw - (var(--n, 1) - 1) * var(--seat) * .45) / var(--n, 1))));
  }
}

@media (min-width: 721px) {
  /* Aiming: three seats across the space beside the held-up card. */
  [data-mode="target"] .seats .seat {
    --avail: calc(87vw - min(62vh, 480px) * 5 / 7);
    --w: max(calc(var(--seat) * 3.8), min(calc(var(--seat) * 5.4), calc((var(--avail) - 2 * var(--seat) * .45) / 3 - 1px)));
  }
}
.seat.is-promoted .seat__tag { display: none; } /* it already says "You" */

/* ── the expo's mobile pass (2026-09-30) ─────────────────────────────── */

/* The type line's short form (cardview.js) is for a hand card on a phone only. */
.card__type .t-short { display: none; }
@media (max-width: 720px) {
  .hand .card__type .t-full { display: none; }
  .hand .card__type .t-short { display: inline; }
}

/* Read a card full size. Touch only: a mouse reads by hovering. Top right, on
   the frame's corner; a Priority card's dragon gives up that corner in the hand
   (its gold ring and type line still say Priority). */
.card__read { display: none; }
@media (pointer: coarse) {
  .hand .card__socket--p { display: none; }
  .hand .card__read {
    position: absolute; z-index: 3; top: 1.4%; right: 2.2%;
    width: max(32px, 14%); aspect-ratio: 1; border-radius: 50%;
    display: grid; place-items: center; cursor: zoom-in;
    background: radial-gradient(circle at 50% 38%, #2A2419, #0B0906 72%);
    border: 1px solid var(--gold); box-shadow: 0 2px 10px rgba(0,0,0,.8), 0 0 12px rgba(224,185,74,.25);
  }
  .hand .card__read svg { width: 58%; height: 58%; fill: none; stroke: var(--gold); stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
  /* chips and table cards open on a tap, so say they can be pressed */
  :is(.chip, .stage .flip.revealed .card) { cursor: pointer; }
}
.zoom .card__read { display: none !important; }

/* A read opened by a tap stays until the next tap, and a long card scrolls. */
.zoom.sticky { pointer-events: auto; inset: 0; transform: none; justify-content: center; background: rgba(6,5,4,.72); animation: fade-in .16s ease; }
.zoom.sticky .card__text { overscroll-behavior: contain; }
.zoom__close { font: 500 var(--fs-cap) var(--sans); color: var(--on-ink-dim); }

/* The hand's arrows: a phone shows two and a half cards of it. */
.handnav { display: none; }
@media (max-width: 720px) {
  .handnav {
    position: absolute; z-index: 16; bottom: calc(var(--hand-card) / 2); translate: 0 50%;
    display: inline-flex; align-items: center; gap: 2px; height: 44px; min-width: 44px; padding: 0 8px;
    border-radius: 4px; border: 1px solid var(--gold-dim); background: rgba(14,11,8,.9); color: var(--gold);
    font: 600 15px var(--sans); box-shadow: 0 6px 18px rgba(0,0,0,.7);
    transition: opacity var(--t) var(--ease);
  }
  .handnav[hidden] { display: none; }
  .handnav svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; }
  .handnav--prev { left: 6px; }
  .handnav--next { right: 6px; }
  /* only while the hand is up and yours to play from */
  #app:not([data-mode="pick"]) .handnav, [data-hold]:not([data-hold=""]) .handnav { opacity: 0; pointer-events: none; }
}

/* ── the step the turn is on, as a title card ──
   It used to be a small gold word. Each step now arrives: its symbol, its name
   in its own colour, and a rule drawn out either side. */
.stage__band {
  --band: var(--gold);
  top: -22px; display: flex; align-items: center; gap: 12px; white-space: nowrap; z-index: 6;
  padding: 10px 28px; border-radius: 50%;
  font: 700 clamp(30px, 4.4vh, 44px)/1 var(--serif); color: var(--band);
  text-shadow: 0 0 22px color-mix(in srgb, var(--band) 70%, transparent), 0 2px 10px #000;
  background: radial-gradient(closest-side, color-mix(in srgb, var(--band) 24%, transparent), transparent) center / 100% 100% no-repeat;
  pointer-events: none;
}
.stage__band::before, .stage__band::after {
  content: ""; width: clamp(28px, 10vw, 110px); height: 2px; transform: scaleX(0);
  background: linear-gradient(90deg, transparent, var(--band));
}
.stage__band::after { background: linear-gradient(90deg, var(--band), transparent); }
.band__sym {
  width: 1.4em; height: 1.4em; flex: none; order: -1;
  background: var(--sym) center / contain no-repeat;
  filter: drop-shadow(0 0 10px color-mix(in srgb, var(--band) 70%, transparent));
}
.stage__band::before { order: -2; }
.stage__band.on > * { animation: band-in .55s var(--arrive) both; }
.stage__band.on .band__sym { animation: band-sym .7s var(--arrive) both, band-glow 1.6s ease-in-out .7s infinite alternate; }
.stage__band.on { animation: band-wash .9s ease-out both; }
.stage__band.on::before { animation: band-rule .6s var(--settle) .12s both; transform-origin: right; }
.stage__band.on::after { animation: band-rule .6s var(--settle) .12s both; transform-origin: left; }
@keyframes band-in { from { opacity: 0; transform: translateY(8px) scale(.94); letter-spacing: -.02em; } }
@keyframes band-sym { from { opacity: 0; transform: scale(.4) rotate(-40deg); } }
@keyframes band-rule { to { transform: scaleX(1); } }
@keyframes band-glow { to { filter: drop-shadow(0 0 18px var(--band)) brightness(1.25); } }
@keyframes band-wash { from { background-size: 30% 30%; } to { background-size: 100% 100%; } }
.stage__band[data-band="heal"] { --band: var(--heal); }
.stage__band[data-band="passive"] { --band: #C6A6F0; }
.stage__band[data-band="lag"] { --band: var(--blood-lit); }
.stage__band[data-band="defend"] { --band: #A8C8E8; }
.stage__band[data-band="priority"] { --band: var(--gold); }
.stage__band[data-band="second"], .stage__band[data-band="simultaneous"] { --band: var(--paper); }
@media (prefers-reduced-motion: reduce) {
  .stage__band.on, .stage__band.on > *, .stage__band.on .band__sym { animation: none; }
  .stage__band.on::before, .stage__band.on::after { animation: none; transform: none; }
}

/* ── a phone held upright, while the turn plays out ──
   Six seats (yours included, game.js) in three rows of two; the stage starts
   under them, whatever they add up to; the played cards go in two rows once
   there are four or more, so none of them runs off the screen; and with your
   seat out of the way the narration has the foot of the screen to itself. */
@media (max-width: 720px) and (orientation: portrait) {
  :is([data-mode="lay"], [data-mode="resolve"], [data-mode="spectate"]) .seats { justify-content: flex-start; }
  :is([data-mode="lay"], [data-mode="resolve"], [data-mode="spectate"]) .stage {
    top: calc(var(--hud) + 10px + var(--seats-h, 30vh) + 40px);
    bottom: calc(64px + env(safe-area-inset-bottom));
  }
  .stage { --card-h: 24vh; }
  .stage__cards {
    --card-h: min(calc(40vh / var(--rows, 1)), 26vh, calc((100vw - 24px) / var(--per, 3) * 1.4 - 12px));
    flex-wrap: wrap; row-gap: 10px;
    max-width: calc(var(--per, 3) * (var(--card-h) * 5 / 7 + 6px));
  }
  .stage__say {
    bottom: calc(-52px - env(safe-area-inset-bottom) / 2); max-width: 94vw; font-size: 18px;
    padding: 6px 12px; border-radius: 4px; background: rgba(10,8,6,.72);
  }
  .stage__say:empty { padding: 0; }
}

/* Choosing on a phone: the seat itself glows and pulses; the "Choose" tag sat
   over the Life Sparks and cut the names short, so it goes. */
@media (max-width: 720px) {
  [data-mode="target"] .seat.targetable::before { display: none; }
  [data-mode="target"] .seat.targetable .seat__id { padding-right: 0; }
}
@media (max-width: 720px) and (orientation: portrait) {
  .stage__cards:has(.stage__quiet) { max-width: none; }
}
@media (max-width: 720px) and (orientation: portrait) {
  /* Waiting on the others: who has put a card down is the tucked card in each
     seat's corner, not a full slot under it. Six seats with slots made three
     tall rows that ran into your own face-down card. */
  [data-mode="lay"] .seat__slot, [data-mode="lay"] .seat__slot:not(.filled) {
    position: absolute; top: -14px; right: 8px; margin: 0; grid-column: auto;
    width: 16px; height: 22px;
  }
  [data-mode="lay"] .seat__slot.filled { transform: rotate(7deg); }
}
@media (max-width: 720px) {
  /* Aiming on a phone: the same two columns as the rest of the match. The
     row's left padding (3vw) left it two pixels short of two seats, so it fell
     to one narrow column with the names cut to a letter. Seats at the table's
     size, and if Summons and Passives open up the chip rows, the list scrolls
     above the question rather than running under it. */
  [data-mode="target"] { --seat-to: 40px; }
  [data-mode="target"] .seats, [data-hold="aim"] .seats { padding-inline: 10px; }
  [data-hold="aim"] .seats {
    bottom: calc(118px + env(safe-area-inset-bottom)); align-content: flex-start;
    overflow-y: auto; overscroll-behavior: contain; padding-top: 16px; padding-bottom: 8px;
  }
}
@media (max-width: 720px) {
  /* Choosing who: one seat to a row, the full width of the screen, so every
     name and every effect reads in full while you decide (Jon, 2026-09-30:
     "the widths feel needlessly narrow and truncate the names"). */
  [data-hold="aim"] .seats .seat { --w: calc(100vw - 20px); }
  [data-hold="aim"] .seats .chip b { max-width: 14em; }
  [data-hold="aim"] .seats { gap: 8px; }
  /* the question sits on its own panel, never over a seat */
  [data-hold="aim"] .focus {
    padding: 10px 12px 12px; border-radius: 4px;
    background: rgba(14,11,8,.94); border: 1px solid var(--hairline); box-shadow: 0 -8px 24px rgba(0,0,0,.6);
  }
}

/* Everywhere but an upright phone (which has its own layout above): the stage
   starts under however many rows the seats make, and ends above your own seat,
   so the step title never sits under a seat and the narration never under
   yours. (--seats-h and --me-h are measured in game.js.) */
@media (min-width: 721px), (orientation: landscape) {
  :is([data-mode="lay"], [data-mode="resolve"]) .stage { top: max(22vh, calc(var(--hud) + 10px + var(--seats-h, 0px) + 44px)); }
  [data-mode="resolve"] .stage { bottom: calc(3vh + var(--me-h, 80px) + 60px); }
  [data-mode="lay"] .stage { bottom: calc(var(--hand-card) * .16 + 28px + var(--me-h, 80px) + 60px); }
  :is([data-mode="lay"], [data-mode="resolve"]) .stage__say { bottom: -40px; }
}

/* ── Character Races (RACES "on") ─────────────────────────────────────── */

/* the Race rail sits under the Class rail, in the same column */
.racepick {
  grid-column: 2; display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: 4px 6px;
}
.racepick[hidden] { display: none; }
.racepick__label { font: 500 var(--fs-cap) var(--sans); color: var(--on-ink-dim); margin-right: 4px; text-transform: none; }
.racepick button {
  padding: 4px 10px; border-radius: 999px; border: 1px solid var(--hairline); background: none;
  color: var(--on-ink-dim); font: 500 var(--fs-cap) var(--sans); cursor: pointer; min-height: 28px;
  transition: color .15s, border-color .15s, background .15s;
}
.racepick button:hover, .racepick button:focus-visible { color: var(--paper); border-color: var(--gold-dim); }
.racepick button[aria-checked="true"] { color: var(--ink); background: var(--gold); border-color: var(--gold); }
@media (max-width: 720px) {
  .racepick { grid-column: 1; gap: 4px; }
  .racepick button { padding: 3px 8px; }
}

/* a CPU's Race, beside its Class menu */
.lobby__seated .who__race {
  margin-left: 2px; height: 24px; border-radius: 4px; border: 1px solid var(--hairline); background: none;
  color: var(--on-ink-dim); font: 400 12px/1 var(--sans); cursor: pointer; max-width: 8em; padding: 0 6px;
}
.who__race option { color: initial; }

/* a Race card wears the Mix frame with the Eternity mark behind its text */
.card--race { --art: url("/art/logo.webp"); }

/* the Race chip leads the seat's row */
.chip--race { border-color: var(--gold-dim); }

/* Juggernaut, opening the turn: offered over the hand */
.hint__first {
  margin-left: 8px; padding: 3px 10px; border-radius: 999px; border: 1px solid var(--gold-dim); background: none;
  color: var(--gold); font: 500 var(--fs-cap) var(--sans); cursor: pointer;
}
.hint__first[aria-pressed="true"] { background: var(--gold); color: var(--ink); }

/* Esper, Celestial Vision */
.vision {
  /* under the row of seats, so it never covers one */
  position: fixed; right: 14px; top: calc(var(--hud) + var(--seats-h, 120px) + 14px); z-index: 40; width: min(260px, calc(100vw - 32px));
  padding: 10px 12px; border-radius: 10px; background: rgba(14, 12, 10, .92); border: 1px solid var(--gold-dim);
  box-shadow: 0 12px 40px rgba(0,0,0,.6);
}
.vision[hidden] { display: none; }
.vision__title { margin: 0 0 2px; font: 600 var(--fs-label) var(--serif); color: var(--gold); }
.vision__note { margin: 0 0 6px; font: 400 var(--fs-cap) var(--sans); color: var(--on-ink-dim); }
.vision__list { list-style: none; margin: 0; padding: 0; display: grid; gap: 3px; font: 400 var(--fs-label) var(--sans); color: var(--paper); }
.vision__list b { font-weight: 600; }
.vision__list .wait { color: var(--on-ink-dim); font-style: italic; }
@media (max-width: 720px) {
  .vision { top: auto; bottom: calc(var(--me-h, 160px) + 12px); right: 16px; left: 16px; width: auto; }
}
