/* ============================================================
   CHAIN OF COMMAND — Design System
   A dark-fantasy roguelike deckbuilder UI
   ============================================================ */
@import url('https://fonts.googleapis.com/css2?family=Cinzel:wght@500;600;700;800&family=EB+Garamond:ital@0;1&family=Spectral:wght@400;500;600&display=swap');

:root{
  /* Palette */
  --bg-0:#07070c;
  --bg-1:#0d0e18;
  --bg-2:#141626;
  --bg-3:#1d2036;
  --panel:#161a2b;
  --panel-2:#1e2540;
  --ink:#e9e6f5;
  --ink-dim:#a9a6c4;
  --ink-faint:#6f6c8f;
  --line:#2c2f4d;
  --line-soft:#23263f;

  --gold:#e7c66a;
  --gold-deep:#b8933a;
  --gold-glow:rgba(231,198,106,.35);
  --crimson:#d8484f;
  --crimson-deep:#8f2226;
  --emerald:#3fb984;
  --azure:#59a6f0;
  --violet:#a874e8;
  --amber:#f0ad4e;

  /* Rarity */
  --r-starter:#ffffff;      /* white — the cards you begin with */
  --r-common:#93a4b8;       /* steel grey — pushed off white so starter reads clean */
  --r-uncommon:#3aa8ff;     /* blue */
  --r-rare:#b45cff;         /* purple */
  --r-legendary:#ffb020;    /* gold — the top of the ladder */
  --r-special:#ff6ae0;

  /* Card types */
  --t-attack:#d8484f;
  --t-skill:#59a6f0;
  --t-power:#c88bf0;
  --t-status:#8a8aa0;
  --t-curse:#6a4c93;

  --radius:0.875rem;
  --radius-sm:0.5625rem;
  --shadow-1:0 2px 0.5rem rgba(0,0,0,.4);
  --shadow-2:0 0.5rem 1.875rem rgba(0,0,0,.55);
  --shadow-3:0 1.125rem 3.75rem rgba(0,0,0,.7);

  --font-display:'Cinzel',Georgia,serif;
  --font-body:'Spectral','EB Garamond',Georgia,serif;
}

/* ============================================================
   RENDERED ART PRIMITIVES
   Motif geometry is authored once and painted here. w1..wk resolve to
   multi-stop gradients built per-drawing in art.js (see `material()`), which
   is what gives flat vector shapes believable form. hx/hy are occlusion
   shapes — the shadow side of a form — and ln/lt/lb are edge definition,
   not sketch lines.
   ============================================================ */
svg .w1{fill:var(--w1)}
svg .w2{fill:var(--w2)}
svg .w3{fill:var(--w3)}
svg .w4{fill:var(--w4)}
svg .wk{fill:var(--wk)}
/* contact / form shadows */
svg .hx,svg .hxC{fill:var(--occ,rgba(6,4,14,.30))}
svg .hy,svg .hxB,svg .hxD{fill:var(--occ2,rgba(6,4,14,.44))}
/* edges: a thin darker contour keeps shapes crisp against busy backdrops */
svg .lf{fill:var(--edge,#0b0812);stroke:none}
svg .ln{fill:none;stroke:var(--edge,#0b0812);stroke-width:1.05;stroke-linecap:round;stroke-linejoin:round;opacity:.85}
svg .lt{fill:none;stroke:var(--edge,#0b0812);stroke-width:.6;stroke-linecap:round;stroke-linejoin:round;opacity:.5}
svg .lb{fill:none;stroke:var(--edge,#0b0812);stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round;opacity:.9}
/* cel / anime mode: flat colour, hard shadow shapes, fine ink line.
   Line weight is deliberately light — the silhouette contour comes from the
   feMorphology pass in art.js, so interior lines only need to describe detail,
   not carry the shape. */
svg .cel .ln{stroke-width:0.85;opacity:.95;stroke:var(--edge)}
svg .cel .lt{stroke-width:0.5;opacity:.7;stroke:var(--edge)}
svg .cel .lb{stroke-width:1.25;opacity:1;stroke:var(--edge)}
svg .cel .hx,svg .cel .hxC{fill:var(--occ);opacity:.92}
svg .cel .hy,svg .cel .hxB,svg .cel .hxD{fill:var(--occ2);opacity:.92}
/* third tone: the lit plane. Base + shadow + highlight is what reads as cel. */
svg .hl{fill:var(--hl,rgba(255,255,255,.19));stroke:none}
svg .hl2{fill:var(--hl2,rgba(255,255,255,.10));stroke:none}
svg .gl{fill:var(--glow,#fff);stroke:none}
/* rim light: a thin bright stroke along the key-light edge of a form */
svg .rim{fill:none;stroke:var(--rim,rgba(255,255,255,.7));stroke-width:.9;opacity:.5;stroke-linecap:round}
/* bosses smoulder: slow embers drifting up through the aura */
svg .boss-ember{animation:bossEmber 4.2s linear infinite}
svg .boss-ember.be2{animation-delay:1.4s}
svg .boss-ember.be3{animation-delay:2.7s}
@keyframes bossEmber{0%{opacity:0;transform:translateY(0)}14%{opacity:.85}70%{opacity:.4}100%{opacity:0;transform:translateY(-1.875rem) translateX(2px)}}
/* aerial perspective for anything tagged as scenery */
svg .far{opacity:.62}
svg .far .ln,svg .far .lb{stroke-width:.7;opacity:.4}
svg .far .lt{stroke-width:.45;opacity:.28}
svg .mid{opacity:.85}

*{box-sizing:border-box;margin:0;padding:0}
html,body{height:100%}
/* ============================================================
   FLUID SCALE
   The whole sheet is authored in rem, so the root font-size IS the UI scale.
   Design reference is a 1440x810 viewport (1rem = 16px there); both axes are
   measured and the tighter one wins, so the layout scales uniformly and never
   changes shape. Clamped so phones stay usable and huge monitors stay sane.
   ============================================================ */
html{font-size:clamp(8.5px, min(1.1111vw, 1.9753vh), 20px)}
/* touch: no double-tap zoom, no long-press callout, no rubber-banding */
html{touch-action:manipulation}
body{-webkit-tap-highlight-color:transparent;-webkit-touch-callout:none;overscroll-behavior:none}
body{
  font-family:var(--font-body);
  color:var(--ink);
  background:
    radial-gradient(75rem 43.75rem at 50% -10%, #1a1c34 0%, transparent 60%),
    radial-gradient(56.25rem 37.5rem at 90% 110%, #201530 0%, transparent 55%),
    var(--bg-0);
  overflow:hidden;
  user-select:none;
  -webkit-font-smoothing:antialiased;
}
#app{position:fixed;inset:0}
#screen-root{position:absolute;inset:0}

button{font-family:var(--font-display);cursor:pointer;color:inherit;border:none;background:none}
h1,h2,h3,.disp{font-family:var(--font-display);letter-spacing:.02em}
::selection{background:var(--gold-glow)}

/* Scrollbars */
*::-webkit-scrollbar{width:0.625rem;height:0.625rem}
*::-webkit-scrollbar-thumb{background:var(--line);border-radius:0.5rem}
*::-webkit-scrollbar-track{background:transparent}

/* ---------- Reusable buttons ---------- */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:.5em;
  padding:.7em 1.3em;border-radius:0.625rem;font-size:0.9375rem;font-weight:600;
  background:linear-gradient(180deg,var(--panel-2),var(--panel));
  border:1px solid var(--line);color:var(--ink);
  box-shadow:var(--shadow-1), inset 0 1px 0 rgba(255,255,255,.05);
  transition:transform .12s ease, box-shadow .2s, border-color .2s, filter .2s;
}
.btn:hover{transform:translateY(-1px);border-color:var(--gold-deep);filter:brightness(1.08)}
.btn:active{transform:translateY(0)}
.btn.gold{
  background:linear-gradient(180deg,#f0d78a,#c39a3f);color:#20160a;border-color:#e7c66a;
  text-shadow:0 1px 0 rgba(255,255,255,.25)
}
.btn.gold:hover{box-shadow:0 0 1.5rem var(--gold-glow),var(--shadow-2)}
.btn.danger{background:linear-gradient(180deg,#c94a51,#7d1e22);border-color:#d8484f;color:#fff}
.btn.ghost{background:rgba(255,255,255,.03)}
.btn:disabled{opacity:.4;pointer-events:none;filter:grayscale(.4)}
.btn.big{font-size:1.125rem;padding:.85em 1.7em}

/* ============================================================
   TITLE / MENU
   ============================================================ */
.menu{position:absolute;inset:0;display:grid;place-items:center;overflow:hidden;
  background:url('../art/bg_title.png') center bottom/cover no-repeat #0b0a09}
.menu .aurora{display:none}
.menu .vignette{background:radial-gradient(90% 80% at 50% 42%, transparent 30%, rgba(5,4,3,.55) 78%, rgba(5,4,3,.8) 100%)}
.menu .aurora{position:absolute;inset:-20%;filter:blur(3.75rem);opacity:.5;
  background:
    radial-gradient(37.5rem 25rem at 30% 30%, #3a2a6b, transparent 60%),
    radial-gradient(43.75rem 31.25rem at 70% 60%, #6b2a4a, transparent 60%),
    radial-gradient(31.25rem 31.25rem at 50% 90%, #234f6b, transparent 60%);
  animation:drift 18s ease-in-out infinite alternate}
@keyframes drift{to{transform:translate3d(4%,3%,0) scale(1.08)}}
.menu .vignette{position:absolute;inset:0;background:radial-gradient(circle at 50% 45%, transparent 40%, rgba(0,0,0,.7) 100%)}
.menu-inner{position:relative;text-align:center;z-index:2;max-width:35rem;margin:0 auto;padding:0 1.25rem}
.menu h1.title{
  font-size:clamp(2rem,4.5vw,3.25rem);font-weight:800;line-height:1;
  background:linear-gradient(180deg,#fbeec0 0%,#e7c66a 45%,#9c7626 100%);
  -webkit-background-clip:text;background-clip:text;color:transparent;
  filter:drop-shadow(0 0.1875rem 1rem rgba(231,198,106,.3));
  letter-spacing:.05em;
}
.menu .actions{margin-top:2.2em;display:flex;flex-direction:column;gap:0.875rem;align-items:center}
.menu .actions.menu-col{flex-direction:column;align-items:stretch;gap:0.6875rem;width:20.625rem;margin-left:auto;margin-right:auto}
.menu .actions.menu-col .btn{width:100%;justify-content:center}
.menu .runemark{width:4rem;height:4rem;margin:0 auto 0.625rem}

/* ============================================================
   CHARACTER SELECT
   ============================================================ */
.select-screen{position:absolute;inset:0;display:flex;flex-direction:column;padding:1.75rem 2.5rem;
  background:
    radial-gradient(56.25rem 30rem at 50% -10%, rgba(231,198,106,.06), transparent 60%),
    radial-gradient(75rem 43.75rem at 50% 110%, #171226 0%, transparent 70%)}
.screen-head{display:flex;align-items:center;gap:1rem;margin-bottom:0.5rem}
.screen-head .back{font-size:0.875rem;color:var(--ink-dim)}
.screen-title{font-size:1.625rem;font-weight:700;color:var(--gold)}
/* centered banner title (matches the map's act banner treatment) */
.select-banner{text-align:center;margin:-0.375rem 0 1.625rem}
.select-banner .sb-title{font-family:var(--font-display);font-weight:700;font-size:2.125rem;
  background:linear-gradient(180deg,#fbeec0,#e7c66a 60%,#9c7626);-webkit-background-clip:text;background-clip:text;color:transparent;
  filter:drop-shadow(0 2px 0.75rem rgba(231,198,106,.3))}
.select-banner .sb-sub{font-family:var(--font-display);font-style:italic;font-size:0.875rem;color:var(--ink-dim);margin-top:0.25rem}
.screen-sub{color:var(--ink-faint);font-style:italic;margin-bottom:1.125rem}

/* Six champions + the random tile, laid out as two rows of four (the last cell
   sits empty). Width is capped so the cards stay portrait-shaped instead of
   stretching wide on a big monitor — the bust art is cropped to fill, so a
   short wide frame would cut off heads. */
.char-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:1rem;
  flex:0 0 auto;margin-top:2vh;width:100%;max-width:63.75rem;margin-inline:auto}
/* below this the four columns get too narrow for the strategy tags, so drop to
   two wider ones rather than letting the labels ellipsise */
@media (max-width:880px){.char-grid{grid-template-columns:repeat(2,minmax(0,1fr))}}
.char-card.random .random-portrait{display:grid;place-items:center;background:
  radial-gradient(120% 90% at 50% 20%,rgba(231,198,106,.16),transparent 60%),
  linear-gradient(180deg,#1a1626,#0d0b14)}
.char-card.random .rq{font-family:var(--font-display);font-size:5.5rem;color:var(--gold);
  text-shadow:0 0 1.875rem var(--gold-glow);opacity:.85}
.char-card.random:hover .rq{opacity:1}
.char-card{
  position:relative;border-radius:var(--radius);overflow:hidden;cursor:pointer;
  --cc:var(--gold);
  background:linear-gradient(180deg,var(--panel-2),var(--bg-1));
  border:1px solid var(--line);box-shadow:var(--shadow-2);
  transition:transform .18s cubic-bezier(.2,.8,.3,1.1), border-color .2s, box-shadow .2s;min-height:17rem;
}
/* class-color wash rising from behind the portrait */
.char-card .char-portrait::after{content:'';position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(180deg,transparent 55%, color-mix(in srgb, var(--cc) 22%, transparent) 100%);
  opacity:.65;transition:opacity .25s}
.char-card:hover{transform:translateY(-0.4375rem);
  border-color:color-mix(in srgb, var(--cc) 70%, transparent) !important;
  box-shadow:0 0.875rem 2.125rem rgba(0,0,0,.55), 0 0 1.875rem color-mix(in srgb, var(--cc) 30%, transparent)}
.char-card:hover .char-portrait::after{opacity:1}
.char-card:hover .cc-name{color:var(--cc)}
.char-card:hover .char-portrait svg{transform:scale(1.06)}
.char-portrait{height:12.5rem;position:relative;overflow:hidden}
.char-portrait svg{position:absolute;inset:0;width:100%;height:100%;transition:transform .35s cubic-bezier(.2,.8,.3,1)}
img.raster-portrait{width:100%;height:100%;object-fit:cover;object-position:center top;display:block;background:radial-gradient(80% 60% at 50% 30%, #1c1712, #0c0b0a)}
.char-portrait img.raster-portrait{position:absolute;inset:0;transition:transform .35s cubic-bezier(.2,.8,.3,1)}
.char-card:hover .char-portrait img.raster-portrait{transform:scale(1.06)}
.char-card .cc-body{padding:0.6875rem 0.8125rem 0.875rem;position:relative}
.char-card .cc-body::before{content:'';position:absolute;top:0;left:0.875rem;right:0.875rem;height:1px;
  background:linear-gradient(90deg,transparent, color-mix(in srgb, var(--cc) 55%, transparent), transparent)}
.char-card .cc-name{font-family:var(--font-display);font-size:1.0625rem;font-weight:700;transition:color .2s}
.char-card .cc-title{color:var(--ink-faint);font-style:italic;font-size:0.75rem;margin-bottom:0.4375rem;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* one-line playstyle blurb — never truncated; fixed three-line space keeps
   every champion card the same height */
.char-card .cc-blurb{color:var(--ink-faint);font-size:0.6875rem;line-height:1.4;font-style:italic;
  margin-top:2px;min-height:2.9375rem}
/* ascension record: one star per level completed, anchored bottom-left of the
   portrait. Metal = starter-pack coverage: 1 pack won = bronze, 2 = silver,
   all 3 = gold. */
.char-card .cc-ascstars{position:absolute;left:0.4375rem;bottom:0.3125rem;z-index:2;
  font-size:0.6875rem;letter-spacing:1px;
  text-shadow:0 0 0.25rem rgba(0,0,0,.9),0 1px 2px rgba(0,0,0,.8);
  max-width:calc(100% - 0.875rem);overflow:hidden;white-space:nowrap;pointer-events:none}
.char-card .cc-ascstars.tier-bronze{color:#d08a4e}
.char-card .cc-ascstars.tier-silver{color:#cfd4e4}
.char-card .cc-ascstars.tier-gold{color:#ffd76a;text-shadow:0 0 0.375rem rgba(255,215,106,.45),0 1px 2px rgba(0,0,0,.85)}
.chip{font-family:var(--font-body);font-size:0.6875rem;padding:0.1875rem 0.5625rem;border-radius:1.25rem;
  background:rgba(255,255,255,.05);border:1px solid var(--line);color:var(--ink-dim)}
.char-hpblock{position:absolute;top:0.75rem;right:0.75rem;background:rgba(0,0,0,.55);
  border:1px solid var(--line);border-radius:1.25rem;padding:0.1875rem 0.6875rem;font-size:0.8125rem}
.char-hpblock b{color:var(--crimson)}

/* Detail / starter packs */
.char-detail{margin-top:1.375rem;background:linear-gradient(180deg,var(--panel),var(--bg-1));
  border:1px solid var(--line);border-radius:var(--radius);padding:1.375rem 1.625rem;flex:1;overflow:auto}
.char-detail h2{font-size:1.5rem;color:var(--gold)}
/* description is capped at 2 lines so selecting a champion never reflows the pack grid */
.char-detail .desc{color:var(--ink-dim);max-width:47.5rem;margin:0.5rem 0 1.125rem;line-height:1.5;
  display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden;
  height:calc(1.5em * 2)}

/* character info modal (opened from the select grid) */
.char-modal-body{width:min(55rem,90vw)}
.cm-head{display:flex;gap:1.125rem;align-items:flex-start;margin:0.25rem 0 1rem}
.cm-pcol{display:flex;flex-direction:column;align-items:center;gap:0.375rem;flex:0 0 auto}
.cm-portrait{width:6rem;height:6rem;border-radius:0.75rem;overflow:hidden;border:1px solid var(--line)}
.cm-headbody{flex:1;display:flex;flex-direction:column;justify-content:center;gap:0.5rem;text-align:left;min-height:6rem}
.cm-hp{font-family:var(--font-display);color:#ff8c94;font-size:0.875rem}
.cm-desc{color:var(--ink-dim);line-height:1.5;font-size:max(0.875rem,13px);
  display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;overflow:hidden}
/* The modal's close X is absolutely positioned in the top-right corner and the
   blurb ran straight under it. The clearance has to be in PX as well as rem:
   the X is a fixed 42px touch target, while 2.25rem is only 19px once the fluid
   scale drops the root to 8.5px on a phone — the exact case that needs it most. */
.char-modal-body .cm-head{padding-right:max(2.25rem, 46px)}
.char-modal-body .screen-sub{text-align:left;margin-bottom:0.75rem}
.char-modal-body .packs{text-align:left}
.btn.cm-btn{min-width:11.5625rem;height:3.5rem;padding:0 1.4em}
/* the gold Embark's extra outer ring made it render larger than View Cards — drop the ring */
.btn.gold.cm-btn{box-shadow:inset 0 1px 0 rgba(255,225,150,.45), 0 0 1.25rem rgba(231,198,106,.3), 0 0.25rem 0.625rem rgba(0,0,0,.5) !important}
/* class-color accents inside the modal */
.char-modal-body .cm-portrait{border-color:color-mix(in srgb, var(--cc,#e7c66a) 55%, transparent)}
.char-modal-body .pk-style{color:var(--cc,#e7c66a)}
/* exactly one pack is always selected — the glow border alone marks it */
.char-modal-body .pack{position:relative;border-width:2px}
/* Selection tints and rings the card — it does NOT lift it. The old
   translateY(-3px) pushed the chosen pack's title, style line, blurb and relic
   row three pixels above its two neighbours, so the row never read as a set of
   three comparable options: one column was always out of register. */
.char-modal-body .pack.selected{border-color:var(--cc,#e7c66a) !important;
  background:linear-gradient(180deg, color-mix(in srgb, var(--cc,#e7c66a) 11%, transparent), rgba(255,255,255,.02));
  box-shadow:0 0 0 1px var(--cc,#e7c66a), 0 0 1.75rem color-mix(in srgb, var(--cc,#e7c66a) 26%, transparent), 0 0.5rem 1.25rem rgba(0,0,0,.4)}
/* a corner tick, so the choice survives being read in greyscale or by someone
   who cannot pick the tinted column out of three */
.char-modal-body .pack.selected::after{content:'✓';position:absolute;top:0.5rem;right:0.6rem;
  font-size:max(0.75rem,11px);line-height:1;color:var(--cc,#e7c66a);opacity:.9}
.packs{display:grid;grid-template-columns:repeat(3,1fr);gap:1rem}
.pack{border:1px solid var(--line);border-radius:0.75rem;padding:1rem;background:rgba(255,255,255,.02);
  cursor:pointer;transition:.15s;display:flex;flex-direction:column}
.pack:hover{border-color:var(--gold-deep);transform:translateY(-0.1875rem)}
.pack.selected{border-color:var(--gold);box-shadow:0 0 1.875rem var(--gold-glow)}
.pack h3{font-size:max(1.0625rem,15px);line-height:1.15}
.pack .pk-style{color:var(--gold);font-size:max(0.75rem,11px);letter-spacing:.08em;text-transform:uppercase;margin:2px 0 0.55rem}
/* three lines, and a floor of three lines, so the three packs are the same
   shape whatever they say. At two lines the longer blurbs were cut mid-word
   ("let your powers pay you ba...") while the short one had room to spare. */
.pack .pk-desc{color:var(--ink-dim);font-size:max(0.8125rem,12px);line-height:1.5;
  display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;overflow:hidden;
  min-height:calc(1.5em * 3)}
.pack .pk-cards{margin-top:0.625rem;font-size:0.75rem;color:var(--ink-faint)}
/* the pack's starter relic: its own icon plus what it actually does. No
   cursor:help — inside a clickable pack a help cursor read as "unclear". */
/* margin-top:auto pins the relic to the FOOT of the pack, so the three relic
   rows sit on one line across the row however tall the blurbs above them are */
.pack .pk-relic-row{margin-top:auto;padding-top:0.7rem;border-top:1px solid var(--line-soft);
  display:flex;gap:0.5625rem;align-items:flex-start;cursor:inherit}
.pack .pk-relic-icon{width:2.125rem;height:2.125rem;flex:0 0 2.125rem;border-radius:0.5rem;overflow:hidden;
  background:rgba(0,0,0,.28);box-shadow:inset 0 0 0 1px rgba(255,255,255,.08)}
.pack .pk-relic-icon svg{width:100%;height:100%;display:block}
.pack .pk-relic-text{min-width:0}
.pack .pk-relic-name{display:block;color:var(--gold);font-family:var(--font-display);
  font-size:max(0.7813rem,12px);letter-spacing:.02em;line-height:1.3}
/* A FIXED two-line box. The relic row is pinned to the foot of the pack, so a
   relic whose blurb wrapped to two lines started 16px higher than its
   neighbours' one-liners and the three rows lost their shared baseline —
   measured across all seven champions, this was the only thing still out of
   register (Seer, Dancer and Mage each have exactly one two-line relic).
   The full text is always one hover/tap away in the relic tooltip. */
.pack .pk-relic-desc{color:var(--ink-faint);font-size:max(0.7188rem,11px);line-height:1.45;margin-top:2px;
  display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden;
  min-height:calc(1.45em * 2)}
.pack .pk-relic-row:hover .pk-relic-name{color:var(--gold-edge,#f5d78a)}
.select-foot{display:flex;justify-content:flex-end;gap:0.75rem;margin-top:1.125rem}

/* ============================================================
   MAP
   ============================================================ */
.map-screen{position:absolute;inset:0;display:flex;flex-direction:column}
.topwrap{position:relative;background:linear-gradient(180deg,rgba(20,22,38,.97),rgba(13,14,24,.9));border-bottom:1px solid var(--line);z-index:6}
/* single-line top bar */
.topbar{display:flex;align-items:center;gap:0.875rem;padding:0.4375rem 1.25rem;height:3.25rem;white-space:nowrap}
.topbar .tb-portrait{width:2.375rem;height:2.375rem;border-radius:0.5625rem;overflow:hidden;border:1px solid var(--line);flex:0 0 auto}
.topbar .tb-name{font-family:var(--font-display);font-weight:700;font-size:1rem;flex:0 0 auto}
.stat{display:flex;align-items:center;gap:0.375rem;font-size:0.875rem;padding:0.25rem 0.625rem;border-radius:0.5rem;background:rgba(0,0,0,.25);flex:0 0 auto}
/* the icon slot must centre BOTH svg icons and text glyphs (⏱) — a bare
   inline glyph sits on its baseline and reads as off-centre */
.stat .ic{width:1rem;height:1rem;display:inline-flex;align-items:center;justify-content:center;line-height:1}
/* same tube as the battlefield gauges: sunken trough, fill lit from above,
   gloss on the top half — the two must not read as different widgets */
.hpbar{width:10.75rem;height:1.25rem;border-radius:0.625rem;overflow:hidden;position:relative;flex:0 0 auto;
  background:linear-gradient(180deg,#180809,#301218);border:1px solid rgba(0,0,0,.8);
  box-shadow:inset 0 0.0625rem 0.1875rem rgba(0,0,0,.85),0 0 0 1px rgba(231,198,106,.3)}
.hpbar > i{display:block;height:100%;transition:width .3s cubic-bezier(.4,0,.2,1);
  background:linear-gradient(180deg,#ff8f8f 0%,#e0575d 40%,#a3242a 66%,#791419 100%)}
.hpbar::after{content:'';position:absolute;left:0;right:0;top:0;height:46%;pointer-events:none;
  border-radius:0.625rem 0.625rem 0 0;
  background:linear-gradient(180deg,rgba(255,255,255,.24),rgba(255,255,255,.02))}
.hpbar span{position:absolute;inset:0;z-index:2;display:flex;align-items:center;justify-content:center;font-size:0.75rem;font-family:var(--font-body);font-weight:600;color:#fff;text-shadow:0 1px 2px #000,0 0 0.1875rem #000;line-height:1;letter-spacing:.02em}
.tb-spacer{flex:1}
/* floating relic overlay (on top of the game UI, not a dedicated row) */
.relic-overlay{position:absolute;top:100%;left:1rem;margin-top:0.5rem;display:flex;align-items:center;gap:0.5rem;z-index:20;
  max-width:70vw;flex-wrap:wrap}
/* deck button in the top bar — a stat chip that happens to be clickable */
.deck-chip{border:1px solid var(--bronze);cursor:pointer;font-family:var(--font-body);
  color:var(--ink);transition:border-color .15s,color .15s,transform .15s}
.deck-chip:hover{border-color:var(--bronze-edge);color:#fff6e0;transform:translateY(-1px);
  box-shadow:0 0 0.75rem var(--gold-glow)}
.deck-chip .ic{width:0.9375rem;height:0.9375rem;color:var(--bronze-edge)}
.deck-chip .deck-n{font-family:var(--font-display);font-size:0.875rem;font-weight:700;letter-spacing:.02em}
.relic-tray{display:flex;gap:0.4375rem;align-items:center;flex-wrap:wrap}
.relic{width:2.125rem;height:2.125rem;border-radius:0.5rem;overflow:hidden;border:1px solid var(--line);
  background:var(--bg-2);cursor:inherit;transition:.15s;flex:0 0 auto}
.relic:hover{transform:translateY(-2px);border-color:var(--gold);box-shadow:0 0 0.75rem var(--gold-glow)}
/* a relic firing: one soft gold pulse, no layout shift. prefers-reduced-motion
   gets the glow without the movement. */
@keyframes relic-fire{
  0%  {transform:translateY(0)    scale(1);   box-shadow:0 0 0 0 var(--gold-glow); border-color:var(--line)}
  30% {transform:translateY(-3px) scale(1.14);box-shadow:0 0 0.9rem 0.15rem var(--gold-glow); border-color:var(--gold)}
  100%{transform:translateY(0)    scale(1);   box-shadow:0 0 0 0 transparent; border-color:var(--line)}
}
.relic.relic-fire{animation:relic-fire .6s cubic-bezier(.3,1.4,.5,1)}
@media (prefers-reduced-motion:reduce){
  @keyframes relic-fire{0%,100%{box-shadow:0 0 0 0 transparent}40%{box-shadow:0 0 0.9rem 0.15rem var(--gold-glow)}}
  .relic.relic-fire{animation:relic-fire .6s ease}
}
.potion-slot{width:2.125rem;height:2.125rem;border-radius:50%;border:1px dashed var(--line);display:grid;place-items:center;cursor:pointer;color:var(--ink-faint)}
.potion-slot.filled{border-style:solid;border-color:var(--violet)}
/* filled potion slots: transparent behind the bottle art */
.relic.potion-live{background:transparent !important;border-color:transparent !important;box-shadow:none !important}
/* in battle the relic row is chrome-free: emblems float on the scene, no boxes */
.combat-topbar .relic-overlay .relic{width:2.375rem;height:2.375rem;border:none;background:transparent;border-radius:0;
  filter:drop-shadow(0 2px 0.25rem rgba(0,0,0,.85))}
.combat-topbar .relic-overlay .relic:hover{transform:translateY(-0.1875rem) scale(1.08);border-color:transparent;
  box-shadow:none;filter:drop-shadow(0 0 0.625rem var(--gold-glow)) drop-shadow(0 2px 0.25rem rgba(0,0,0,.8))}
.combat-topbar .relic-overlay .relic svg{width:100%;height:100%}
.relic.potion-live:hover{filter:drop-shadow(0 0 0.5rem rgba(199,154,240,.6))}
.relic.potion-live svg{transform:scale(1.15)}
.btn.sm{padding:.4em .9em;font-size:0.8125rem}

.map-scroll{flex:1;overflow:auto;position:relative;background:#06060c}
/* Full-screen backdrop behind the trail on wide windows: the act painting
   again, blurred and pulled far down, static while the canvas scrolls over
   it. Oversized so the blur never bleeds the black edge into view. */
.map-backdrop{position:absolute;inset:0;z-index:0;overflow:hidden;pointer-events:none;background:#06060c}
.map-backdrop img{width:106%;height:106%;margin:-3% 0 0 -3%;object-fit:cover;object-position:center 30%;
  filter:blur(0.875rem) saturate(.35) brightness(.4)}
.map-backdrop::after{content:'';position:absolute;inset:0;
  background:radial-gradient(115% 85% at 50% 42%, rgba(6,6,12,.05), rgba(6,6,12,.55) 75%, rgba(6,6,12,.8))}
.map-screen.on-backdrop .map-scroll{background:transparent}
/* past the canvas cap the sharp painting hands off to the blurred backdrop
   at its sides instead of ending on a hard seam; below the cap the canvas
   spans the window and there is no seam to hide */
@media (min-width:1281px){
  .map-screen.on-backdrop .map-bg.raster{
    -webkit-mask-image:linear-gradient(90deg,transparent,#000 3.5rem,#000 calc(100% - 3.5rem),transparent);
    mask-image:linear-gradient(90deg,transparent,#000 3.5rem,#000 calc(100% - 3.5rem),transparent)}
}
.map-canvas{position:relative;margin:0 auto}
.map-bg{position:absolute;inset:0;z-index:0;pointer-events:none;overflow:hidden}
.map-bg svg{display:block;width:100%;height:100%}
/* The painting is the SET, not the subject: desaturated and pulled down so
   the nodes, roads and figurine carry the color on a phone screen. */
.map-bg img.map-raster{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:center;
  filter:saturate(.4) brightness(.72) contrast(.95)}
.map-raster-shade{position:absolute;inset:0;
  background:linear-gradient(to bottom, rgba(6,5,4,.48), rgba(6,5,4,.22) 18%, rgba(6,5,4,.22) 82%, rgba(6,5,4,.5) 100%)}
.map-node .mn-icon img.mn-raster{width:100%;height:100%;object-fit:contain;
  filter:drop-shadow(0 0.3125rem 0.5625rem rgba(0,0,0,.75))}
.map-figurine{position:absolute;width:4.75rem;transform:translate(-50%,-88%);z-index:5;pointer-events:none;
  filter:drop-shadow(0 0.625rem 0.75rem rgba(0,0,0,.7));animation:figBob 3.6s ease-in-out infinite}
@keyframes figBob{0%,100%{transform:translate(-50%,-88%)}50%{transform:translate(-50%,-92%)}}
.map-startlabel{position:absolute;transform:translate(-50%,0);z-index:4;pointer-events:none;
  font-family:var(--serif,serif);font-size:0.75rem;letter-spacing:.28em;color:var(--gold,#e7c66a);
  text-shadow:0 2px 0.5rem #000, 0 0 1.125rem rgba(231,198,106,.35);white-space:nowrap}
.map-deckfab{position:absolute;right:1.625rem;bottom:1.375rem;z-index:30;width:5.25rem;cursor:pointer;text-align:center;
  transition:transform .15s}
.map-deckfab:hover{transform:scale(1.08)}
.map-deckfab img{width:4.625rem;height:4.625rem;object-fit:contain;filter:drop-shadow(0 0.5rem 0.75rem rgba(0,0,0,.8))}
.map-deckfab .mdf-label{font-family:var(--serif,serif);font-size:0.75rem;letter-spacing:.14em;color:var(--gold,#e7c66a);
  text-transform:uppercase;text-shadow:0 2px 0.375rem #000;margin-top:2px}
.map-legend .ml-dot.raster{background:none;border:none;box-shadow:none}
.map-legend .ml-dot.raster img{width:1.375rem;height:1.375rem;object-fit:contain}
.map-canvas svg.edges{position:absolute;inset:0;width:100%;height:100%;pointer-events:none;z-index:1;overflow:visible}

/* act banner at the summit */
.map-actbanner{position:absolute;top:1rem;left:0;right:0;z-index:2;text-align:center;pointer-events:none}
.map-actbanner .mab-act{font-family:var(--font-display);font-weight:800;letter-spacing:.24em;font-size:0.8125rem;color:var(--gold);opacity:.9}
.map-actbanner .mab-name{font-family:var(--font-display);font-weight:700;font-size:1.625rem;
  background:linear-gradient(180deg,#fbeec0,#e7c66a 60%,#9c7626);-webkit-background-clip:text;background-clip:text;color:transparent;
  filter:drop-shadow(0 2px 0.625rem rgba(231,198,106,.3));margin-top:2px}
/* the Act's General, left of the act number; the name ellipsizes rather than
   ever pushing the bar's chips off the line */
.topbar .tb-boss{color:#d8484f}
.topbar .tb-boss .ic{color:#d8484f}
.topbar .tb-boss .tb-bossart{width:2.375rem;height:2.375rem;display:block;overflow:hidden}
.topbar .tb-boss .tb-bossart img,.topbar .tb-boss .tb-bossart svg{width:100%;height:100%;object-fit:contain;display:block}

/* edges — faint stone trail; traveled turns to solid gold */
.edges .edge{fill:none;stroke:rgba(233,223,196,.42);stroke-width:2.4;stroke-linecap:round;stroke-dasharray:2 7}
.edges .edge.traveled{stroke:rgba(233,223,196,.5);stroke-width:2.4;stroke-dasharray:none}
.edges .edge.active{stroke:var(--gold);stroke-width:3.5;stroke-dasharray:6 8;filter:drop-shadow(0 0 0.3125rem var(--gold-glow));animation:edgeFlow 1s linear infinite}
@keyframes edgeFlow{to{stroke-dashoffset:-28}}

/* medallion nodes — bronze bezel, type-tinted disc, engraved icon plate */
.map-node{position:absolute;width:3rem;height:3rem;transform:translate(-50%,-50%);z-index:3;
  border-radius:50%;display:grid;place-items:center;cursor:pointer;transition:transform .15s, box-shadow .2s, filter .2s;
  background:radial-gradient(circle at 50% 28%, color-mix(in srgb, var(--nt,#666) 30%, #1c1626), #0b0c15 74%);
  border:2px solid color-mix(in srgb, var(--nt,#666) 80%, #fff0);
  box-shadow:
    0 0 0 0.1875rem #241a0e,
    0 0 0 0.25rem color-mix(in srgb, var(--nt,#666) 30%, #000),
    0 0.375rem 0.875rem rgba(0,0,0,.65),
    inset 0 2px 0.1875rem rgba(255,255,255,.16),
    inset 0 -0.3125rem 0.5625rem rgba(0,0,0,.55);}
.map-node::before{content:'';position:absolute;inset:-0.4375rem;border-radius:50%;
  border:1px dashed color-mix(in srgb, var(--nt,#666) 45%, transparent);opacity:.45}
.map-node .mn-icon{width:1.8125rem;height:1.8125rem;border-radius:50%;display:grid;place-items:center;
  background:radial-gradient(circle at 50% 30%, rgba(0,0,0,.15), rgba(0,0,0,.55));
  box-shadow:inset 0 1px 0.25rem rgba(0,0,0,.75), inset 0 -1px 0 rgba(255,255,255,.07);
  filter:drop-shadow(0 1px 2px #000)}
.map-node .mn-icon svg{width:1.25rem;height:1.25rem}
.map-node .mn-check{position:absolute;inset:0;border-radius:50%;display:grid;place-items:center;
  font-size:1.25rem;color:color-mix(in srgb, var(--nt,#888) 70%, #fff);
  background:rgba(6,6,10,.5);text-shadow:0 1px 0.1875rem #000}
.map-node.done{transform:translate(-50%,-50%) scale(.92)}
.map-node.done .mn-icon{opacity:1}
.map-node.locked{opacity:1}
/* reachable: gold bezel + slowly spinning dashed halo + breathing glow */
.map-node.reachable{border-color:var(--gold);
  box-shadow:
    0 0 0 0.1875rem #241a0e, 0 0 0 0.25rem #6a5220,
    0 0.375rem 1rem rgba(0,0,0,.65), 0 0 1.375rem var(--gold-glow),
    inset 0 2px 0.1875rem rgba(255,255,255,.2), inset 0 -0.3125rem 0.5625rem rgba(0,0,0,.5);
  animation:nodePulse 1.8s ease-in-out infinite}
.map-node.reachable::before{inset:-0.5rem;border:2px dashed var(--gold);opacity:.75;animation:spinHalo 10s linear infinite}
.map-node.reachable:hover{transform:translate(-50%,-50%) scale(1.16)}
@keyframes spinHalo{to{transform:rotate(360deg)}}
@keyframes nodePulse{50%{box-shadow:
  0 0 0 0.1875rem #241a0e, 0 0 0 0.25rem #6a5220,
  0 0.375rem 1rem rgba(0,0,0,.65), 0 0 2.25rem var(--gold-glow),
  inset 0 2px 0.1875rem rgba(255,255,255,.2), inset 0 -0.3125rem 0.5625rem rgba(0,0,0,.5)}}
/* current = you are here: bright ivory core in a gold bezel + bobbing marker */
.map-node.current{border-color:#fff;
  box-shadow:0 0 0 0.1875rem var(--gold), 0 0 0 0.3125rem #4a3814, 0 0 1.625rem var(--gold-glow),
    inset 0 2px 0.1875rem rgba(255,255,255,.25), inset 0 -0.3125rem 0.5625rem rgba(0,0,0,.5)}
.map-node.current::before{opacity:0}
.map-node.current::after{content:'';position:absolute;top:-1.5rem;left:50%;transform:translateX(-50%);
  border-left:0.5rem solid transparent;border-right:0.5rem solid transparent;border-top:0.6875rem solid var(--gold);
  filter:drop-shadow(0 2px 0.1875rem rgba(0,0,0,.5));animation:hereBob 1.2s ease-in-out infinite}
@keyframes hereBob{50%{transform:translateX(-50%) translateY(-0.25rem)}}
/* boss node — bigger, ominous, ember-lit */
.map-node.boss{width:4.25rem;height:4.25rem;border-width:0.1875rem;
  background:radial-gradient(circle at 50% 26%, rgba(216,72,79,.35), #170a0e 74%);
  box-shadow:
    0 0 0 0.1875rem #2a0f12, 0 0 0 0.3125rem #5c1a20,
    0 0.5rem 1.375rem rgba(0,0,0,.7), 0 0 1.625rem rgba(216,72,79,.4),
    inset 0 2px 0.1875rem rgba(255,120,120,.2), inset 0 -0.375rem 0.75rem rgba(0,0,0,.6)}
.map-node.boss::before{inset:-0.5625rem;border-width:2px}
.map-node.boss .mn-icon{width:2.625rem;height:2.625rem}
.map-node.boss .mn-icon svg{width:1.75rem;height:1.75rem}
.map-node.boss.reachable{animation:bossPulse 1.6s ease-in-out infinite}
@keyframes bossPulse{50%{box-shadow:
  0 0 0 0.1875rem #2a0f12, 0 0 0 0.3125rem #7d2e32,
  0 0.5rem 1.375rem rgba(0,0,0,.7), 0 0 2.875rem rgba(216,72,79,.65),
  inset 0 2px 0.1875rem rgba(255,120,120,.25), inset 0 -0.375rem 0.75rem rgba(0,0,0,.6)}}

.map-legend{position:absolute;top:4rem;right:1.25rem;display:flex;flex-direction:column;gap:0.4375rem;z-index:6;
  background:linear-gradient(180deg,rgba(14,16,28,.94),rgba(8,9,16,.9));padding:0.75rem 0.9375rem;border-radius:0.75rem;
  border:1px solid var(--line);font-size:0.75rem;box-shadow:var(--shadow-2);backdrop-filter:blur(0.25rem)}
.map-legend .ml-title{font-family:var(--font-display);font-size:0.75rem;letter-spacing:.16em;text-transform:uppercase;color:var(--gold);margin-bottom:2px}
.map-legend > div{display:flex;align-items:center;gap:0.5625rem;color:var(--ink-dim)}
.map-legend .ml-dot{width:1.625rem;height:1.625rem;border-radius:50%;display:grid;place-items:center;flex:0 0 auto;
  background:radial-gradient(circle at 50% 40%,#23273f,#0c0e18);border:1.5px solid var(--nt,#666)}
.map-legend .ml-dot svg{width:0.9375rem;height:0.9375rem}

/* ============================================================
   COMBAT
   ============================================================ */
/* second column is 0: the log is an overlay on the arena now, not a panel —
   the column only survives so every grid-column:1/3 span stays valid */
.combat{position:absolute;inset:0;display:grid;grid-template-columns:1fr 0;grid-template-rows:auto 1fr 14.5rem}
.combat-topbar{grid-column:1/3;grid-row:1;position:relative;z-index:10}
.arena{grid-column:1;grid-row:2;position:relative;overflow:hidden;
  background:
    radial-gradient(45rem 25rem at 18% 12%, rgba(231,150,80,.12), transparent 58%),
    radial-gradient(45rem 25rem at 82% 12%, rgba(214,96,70,.10), transparent 58%),
    radial-gradient(68.75rem 38.75rem at 50% -12%, #2b1f33 0%, transparent 62%),
    linear-gradient(180deg,#181022 0%,#0c0812 100%)}
/* the drawn environment fills the pane behind everything */
.arena .arena-bg{position:absolute;inset:0;z-index:0;pointer-events:none;overflow:hidden}
.arena .arena-bg svg{position:absolute;inset:0;width:100%;height:100%;display:block}
.arena .arena-bg img.raster-bg{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:center bottom}
.arena .arena-bg .raster-bg-shade{position:absolute;inset:0;
  background:linear-gradient(to bottom, rgba(6,5,4,.30), transparent 26%, transparent 60%, rgba(6,5,4,.50) 100%)}
.arena .floor,.arena .entities{z-index:1}
/* The floor plane is drawn by the backdrop scene itself now (battleSceneMin
   puts its ground edge exactly on the feet line) — this decorative layer only
   ever added a second, colored floor that fought it. Kept for layout safety. */
.arena .floor{display:none}

/* Entities — feet share one baseline on the ground plane:
   player ~left quarter, enemies spread over the right half */
.entities{position:absolute;inset:0;display:flex;align-items:flex-end;justify-content:space-between;padding:0 3.5rem 6.5rem}
.player-slot{display:flex;align-items:flex-end;padding-left:4%}
.enemy-row{display:flex;justify-content:flex-end;gap:2.375rem;align-items:flex-end;padding-right:1%}
.entity{position:relative;width:15rem;display:flex;flex-direction:column;align-items:center;transition:transform .12s}
.entity .sprite-wrap{position:relative;display:flex;justify-content:center;align-items:flex-end}
.entity .eshadow{position:absolute;bottom:-0.5rem;left:50%;transform:translateX(-50%);width:76%;height:1.5rem;border-radius:50%;
  background:radial-gradient(50% 50% at 50% 50%, rgba(0,0,0,.6), transparent 70%);z-index:0;transition:.2s}
/* Cast size, DESKTOP ONLY — every phone breakpoint restates all four of these
   (see the <=640px and phone-landscape blocks), so this set never reaches a
   phone. `--cast` is the ONE knob: the four base sizes below are the original
   proportions (normal 1 · elite 1.15 · player 1.27 · boss 1.46 — what makes a
   boss read as a boss before you have looked at its HP bar) and the variable
   scales all four together. 1 was the original, 0.85 was still too big, 0.7 is
   where it landed (user, 2026-08-03). Sprites are bottom-aligned in
   .sprite-wrap, so shrinking them leaves every pair of feet on the ground line
   the backdrop is painted to. */
/* on :root, not on .combat — .entity is also rendered outside a combat screen
   (the enemy review / art dev pages), and an undefined var would collapse the
   calc to an invalid width there */
:root{--cast:0.7}
.entity .sprite{width:calc(16.25rem * var(--cast));height:calc(16.25rem * var(--cast));position:relative;z-index:1;
  filter:drop-shadow(0 0.75rem 0.875rem rgba(0,0,0,.55))}
.entity.player .sprite{width:calc(20.625rem * var(--cast));height:calc(20.625rem * var(--cast))}
.entity.tier-elite .sprite{width:calc(18.75rem * var(--cast));height:calc(18.75rem * var(--cast))}
.entity.tier-boss .sprite{width:calc(23.75rem * var(--cast));height:calc(23.75rem * var(--cast))}
.entity .sprite svg{width:100%;height:100%}
.entity .sprite img.raster-sprite{width:100%;height:100%;object-fit:contain;object-position:center bottom}
@keyframes idleBob{0%,100%{transform:translateY(0)}50%{transform:translateY(-0.3125rem)}}
.entity.dead .sprite{animation:none}
.entity.targetable{cursor:crosshair}
/* Targeting feedback must NOT move the enemy. Scaling it up shifted the sprite
   under the cursor and, because the scaled box changes the hit area, the hover
   could toggle on and off and jitter. All the feedback is now light: a stronger
   glow, a brighter sprite and the ring below, none of which affect layout. */
.entity.targeting-hover{transform:none}
.entity.targeting-hover .sprite{filter:drop-shadow(0 0 1.6rem var(--crimson)) drop-shadow(0 0 0.5rem var(--crimson)) brightness(1.24) saturate(1.2)}
.entity.targeting-hover .eshadow{background:radial-gradient(50% 50% at 50% 50%, rgba(224,87,93,.4), transparent 72%);
  box-shadow:0 0 1.375rem 0.3125rem rgba(224,87,93,.35), inset 0 0 0 2px rgba(224,87,93,.75)}
.entity.dead{opacity:0;transform:translateY(1.25rem) scale(.9);transition:.5s}
.entity.hit{animation:hitShake .32s}
@keyframes hitShake{0%,100%{transform:translateX(0)}20%{transform:translateX(-0.5625rem)}40%{transform:translateX(0.4375rem)}60%{transform:translateX(-0.3125rem)}80%{transform:translateX(0.1875rem)}}
/* combat speed: engine waits scale via G.wait; these keep CSS fx in step */
:root[data-speed="1.5"] .card.deal{animation-duration:.33s}
:root[data-speed="1.5"] .card.fly-out{animation-duration:.3s}
:root[data-speed="1.5"] .slash-fx{animation-duration:.21s}
:root[data-speed="1.5"] .entity.hit{animation-duration:.21s}
/* the lunge is timed to just fill the gap between blows (HIT_GAP in
   ui/combat.js, which scales the same way), so each strike gets a whole one */
:root[data-speed="1.5"] .entity.atk-right,
:root[data-speed="1.5"] .entity.atk-left{animation-duration:.28s}
:root[data-speed="2"] .card.deal{animation-duration:.25s}
:root[data-speed="2"] .card.fly-out{animation-duration:.23s}
:root[data-speed="2"] .slash-fx{animation-duration:.16s}
:root[data-speed="2"] .entity.hit{animation-duration:.16s}
:root[data-speed="2"] .entity.atk-right,
:root[data-speed="2"] .entity.atk-left{animation-duration:.21s}
/* collapsible combat log — collapsing leaves only the round toggle in the
   corner and hands the battlefield the full width */
.log-collapse{pointer-events:auto;flex:0 0 auto;cursor:pointer;
  width:1.625rem;height:1.625rem;border-radius:50%;display:grid;place-items:center;
  font-size:0.6875rem;line-height:1;color:#ffe9b0;
  background:radial-gradient(circle at 40% 35%,#3a2c16,#14100a);
  border:1px solid rgba(231,198,106,.55);
  box-shadow:inset 0 1px 0 rgba(231,198,106,.25),0 2px 0.375rem rgba(0,0,0,.5);
  transition:border-color .15s,box-shadow .15s}
.log-collapse:hover{border-color:var(--gold);color:#fff;
  box-shadow:inset 0 1px 0 rgba(231,198,106,.4),0 0 0.75rem var(--gold-glow,rgba(231,198,106,.4))}
.combat.log-closed .log-body,.combat.log-closed .log-head h3,.combat.log-closed .turnpill{display:none}
.combat.log-closed .log-rail{width:auto}
/* the battlefield keeps clear of the overlay while the log is open; phones
   never see the rail at all (<=900px hides it) so the reserve is desktop-only */
@media (min-width:901px){.combat:not(.log-closed) .entities{padding-right:16.5rem}}
/* per-card effect accents painted over the scene */
.card .art{position:relative;overflow:hidden}
.card .art-accents{position:absolute;inset:0;width:100%;height:100%;pointer-events:none}
/* division chip: which corps of the Warhost this soldier belongs to */
.fam-chip{font-size:0.5938rem;letter-spacing:.12em;text-transform:uppercase;opacity:.85;margin:-1px 0 2px;cursor:default}
/* incoming-damage summary under the champion's HP bar */
/* Incoming damage — every telegraphed attack summed into one badge beside the
   champion, in the same medal language the enemies telegraph with. It hangs
   off the sprite box (not the info plate) so it costs the HP bar no width and
   the status row no height; on a phone the strip below the feet is the most
   contested space on screen. */
.threat{--tc:#c8323c;position:absolute;right:100%;top:50%;transform:translateY(-50%);margin-right:0.25rem;
  display:flex;flex-direction:row;align-items:center;gap:0.2rem;z-index:5;cursor:inherit;white-space:nowrap}
.threat.safe{--tc:#3f7fc8}
.threat .th-medal{width:max(1.8rem,19px);height:max(1.8rem,19px);flex:0 0 auto;border-radius:50%;display:grid;place-items:center;
  background:radial-gradient(circle at 50% 30%, color-mix(in srgb, var(--tc) 92%, #fff) 0%, var(--tc) 44%, color-mix(in srgb, var(--tc) 40%, #000) 100%);
  border:1px solid color-mix(in srgb, var(--tc) 55%, #fff);
  box-shadow:0 0 0.5rem color-mix(in srgb, var(--tc) 55%, transparent),0 2px 6px rgba(0,0,0,.55),inset 0 -2px 0.25rem rgba(0,0,0,.4)}
.threat .th-medal svg{display:block;filter:drop-shadow(0 1px 1px rgba(0,0,0,.6))}
.threat .th-num{font-family:var(--font-display);font-size:max(1.25rem,14px);font-weight:700;line-height:1;
  color:#ffd7d1;text-shadow:0 1px 2px #000,0 0 0.375rem rgba(0,0,0,.95)}
.threat.safe .th-num{color:#cfe6ff}
/* unblocked damage breathes; damage you have already answered sits still */
.threat:not(.safe) .th-medal{animation:threatPulse 1.7s ease-in-out infinite}
@keyframes threatPulse{
  0%,100%{box-shadow:0 0 0.375rem rgba(216,72,79,.4),0 2px 6px rgba(0,0,0,.55),inset 0 -2px 0.25rem rgba(0,0,0,.4)}
  50%{box-shadow:0 0 1rem rgba(216,72,79,.9),0 2px 6px rgba(0,0,0,.55),inset 0 -2px 0.25rem rgba(0,0,0,.4)}}
/* Dancer hand geography: the live edges glow */
.hand .card.edge-lead .card-inner{box-shadow:var(--shadow-2),0 0 0 1px #000,-0.3125rem 0 1rem rgba(231,198,106,.55)}
.hand .card.edge-follow .card-inner{box-shadow:var(--shadow-2),0 0 0 1px #000,0.3125rem 0 1rem rgba(231,198,106,.55)}
.hand .card.edge-lead::before,.hand .card.edge-follow::before{
  content:'LEAD';position:absolute;top:-1.0625rem;left:50%;transform:translateX(-50%);z-index:5;
  font-size:0.5938rem;letter-spacing:.22em;color:#e7c66a;text-shadow:0 0 0.5rem rgba(231,198,106,.8);pointer-events:none}
.hand .card.edge-follow::before{content:'FOLLOW'}
.hand .card.edge-lead.edge-follow::before{content:'LEAD · FOLLOW'}
/* Clockmaster timeline strip — the scheduled future, above the hand */
.tl-strip{position:absolute;left:50%;transform:translateX(-50%);bottom:18.25rem;z-index:40;display:flex;gap:0.4375rem;align-items:center;
  background:rgba(12,10,22,.78);border:1px solid rgba(127,220,230,.35);border-radius:0.75rem;padding:0.3125rem 0.75rem;pointer-events:auto}
.tl-title{color:#7fdce6;font-size:0.9375rem}
.tl-chip{font-size:0.7813rem;color:#cfe9ee;background:rgba(127,220,230,.1);border:1px solid rgba(127,220,230,.25);
  border-radius:0.5rem;padding:2px 0.5rem;white-space:nowrap}
.tl-chip b{color:#7fdce6;margin-right:0.25rem}
.tl-chip i{color:#9be9a0;font-style:normal;margin-left:0.1875rem;font-size:0.6875rem}
.tl-chip.due{border-color:rgba(231,198,106,.65);box-shadow:0 0 0.625rem rgba(231,198,106,.25)}
.tl-chip.k-damage,.tl-chip.k-aoe{color:#ffc9c2}
.tl-chip.k-block{color:#cfe0ff}
/* turn transition banner */
.turn-banner{position:absolute;left:0;right:0;top:34%;z-index:80;text-align:center;pointer-events:none;
  font-family:var(--serif,serif);font-size:2.125rem;letter-spacing:.34em;font-weight:700;
  animation:turnSweep 1.4s cubic-bezier(.2,.7,.3,1) forwards}
.turn-banner.tb-enemy{color:#ff8a8a;text-shadow:0 0 1.5rem rgba(216,72,79,.6)}
.turn-banner.tb-player{color:#e7c66a;text-shadow:0 0 1.5rem rgba(231,198,106,.6)}
@keyframes turnSweep{0%{opacity:0;transform:translateX(-2.5rem)}18%{opacity:1;transform:translateX(0)}
  78%{opacity:1;transform:translateX(0)}100%{opacity:0;transform:translateX(2.5rem)}}
/* map: roads not taken fade back */
.map-node.off-path{opacity:1}

/* map legend collapse */
.map-legend .ml-title{cursor:pointer;user-select:none}
.map-legend .ml-caret{margin-left:0.375rem;font-size:0.6875rem;color:var(--gold,#e7c66a)}
.map-legend.collapsed .ml-row{display:none}
/* how-to-play primer */
.howto{max-width:35rem;max-height:62vh;overflow-y:auto;padding-right:0.5rem;text-align:left}
.howto-h{font-family:var(--serif,serif);color:var(--gold,#e7c66a);font-size:0.9375rem;letter-spacing:.08em;text-transform:uppercase;margin:0.875rem 0 0.375rem}
.howto-h:first-child{margin-top:0}
.howto-b{font-size:0.8438rem;line-height:1.55;color:#d8d3e6}
.howto-b ol{margin:0.25rem 0 0 1.125rem;padding:0}
.howto-b li{margin-bottom:0.3125rem}
.howto-kw{display:flex;flex-direction:column;gap:0.3125rem}
.howto-kw-row{font-size:0.7813rem;line-height:1.45;color:#b9b3cc;border-left:2px solid rgba(231,198,106,.35);padding-left:0.5rem}
.howto-kw-row b{color:#e8e2f4}
/* class difficulty chips on character select */
.chip.diff-easy{background:rgba(127,230,160,.14);color:#7fe6a0;border-color:rgba(127,230,160,.4)}
.chip.diff-mid{background:rgba(231,198,106,.14);color:#e7c66a;border-color:rgba(231,198,106,.4)}
.chip.diff-hard{background:rgba(239,106,216,.12);color:#ef8ade;border-color:rgba(239,106,216,.4)}
/* slash streak over a struck entity (spawned in #fx-layer by G.fx.attackAnim) */
.slash-fx{position:fixed;pointer-events:none;z-index:60;filter:drop-shadow(0 0 0.375rem rgba(255,255,255,.85)) drop-shadow(0 0 0.875rem rgba(255,220,160,.45));animation:slashSweep .32s cubic-bezier(.2,.7,.3,1) forwards}
.slash-fx.flip{transform:scaleX(-1);animation-name:slashSweepFlip}
@keyframes slashSweep{0%{opacity:0;transform:scale(.45) rotate(-14deg)}18%{opacity:1}55%{opacity:1;transform:scale(1.08) rotate(0deg)}100%{opacity:0;transform:scale(1.22) rotate(5deg)}}
@keyframes slashSweepFlip{0%{opacity:0;transform:scaleX(-1) scale(.45) rotate(-14deg)}18%{opacity:1}55%{opacity:1;transform:scaleX(-1) scale(1.08) rotate(0deg)}100%{opacity:0;transform:scaleX(-1) scale(1.22) rotate(5deg)}}
/* class resources — big orbs beside the champion, always visible for the class */
.class-res{position:absolute;left:calc(100% - 0.5rem);top:4%;display:flex;flex-direction:column;gap:0.75rem;z-index:6}
.res-badge{width:3.125rem;text-align:center;cursor:default}
.res-badge .rb-orb{width:2.875rem;height:2.875rem;margin:0 auto;border-radius:50%;position:relative;display:grid;place-items:center;
  background:radial-gradient(circle at 50% 32%, color-mix(in srgb, var(--rc,#e7c66a) 42%, #14121e), #0b0a12 76%);
  border:2px solid var(--rc,#e7c66a);
  box-shadow:0 0 0.875rem color-mix(in srgb, var(--rc,#e7c66a) 38%, transparent), inset 0 0 0.625rem rgba(0,0,0,.55), inset 0 1px 0 rgba(255,255,255,.15)}
.res-badge .rb-ic{position:absolute;top:0.1875rem;left:50%;transform:translateX(-50%);font-size:0.625rem;opacity:.75;color:var(--rc,#e7c66a)}
.res-badge b{font-family:var(--font-display);font-size:1.25rem;line-height:1;color:#fff;margin-top:0.3125rem;
  text-shadow:0 0 0.625rem color-mix(in srgb, var(--rc,#e7c66a) 80%, transparent), 0 1px 2px #000}
.res-badge .rb-lbl{font-family:var(--font-display);font-size:0.5625rem;letter-spacing:.14em;text-transform:uppercase;
  color:var(--rc,#e7c66a);margin-top:0.25rem;text-shadow:0 1px 2px #000}
.res-badge.zero .rb-orb{opacity:.5;box-shadow:inset 0 0 0.625rem rgba(0,0,0,.55)}
.res-badge.zero .rb-lbl{opacity:.6}

/* construct companions — little units on the ground beside the champion */
.construct-row{display:flex;align-items:flex-end;gap:0.25rem;margin-left:0.75rem;padding-bottom:6rem}
.construct-unit{position:relative;width:3.5rem;display:flex;flex-direction:column;align-items:center}
.construct-unit .cu-shadow{position:absolute;bottom:0.5rem;left:50%;transform:translateX(-50%);width:64%;height:0.625rem;border-radius:50%;
  background:radial-gradient(50% 50% at 50% 50%, rgba(0,0,0,.55), transparent 70%)}
.construct-unit .cu-sprite{width:3.25rem;height:3.25rem;position:relative;z-index:1;
  filter:drop-shadow(0 0.3125rem 0.375rem rgba(0,0,0,.5));animation:idleBob 2.8s ease-in-out infinite}
.construct-unit .cu-sprite svg{width:100%;height:100%}
.construct-unit .cu-power{position:absolute;top:-0.5rem;right:0;z-index:2;min-width:1.1875rem;height:1.1875rem;border-radius:50%;
  display:grid;place-items:center;font-family:var(--font-display);font-size:0.6875rem;font-weight:700;color:#fff;
  background:radial-gradient(circle at 50% 35%, #3a5a8a, #16243c);border:1.5px solid #6cb4f5;
  box-shadow:0 0 0.5rem rgba(108,180,245,.4);text-shadow:0 1px 2px #000}
.construct-unit .cu-name{font-family:var(--font-body);font-size:0.5313rem;letter-spacing:.04em;color:var(--ink-faint);
  margin-top:1px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:3.5rem}

/* fixed-height info plate below the feet so every sprite shares the baseline */
.entity .einfo{height:5.375rem;display:flex;flex-direction:column;align-items:center;margin-top:0.625rem}
/* names are gone from the battlefield (user call) — the silhouette, HP bar
   and intent medals identify a foe; the Compendium still names everyone */
.entity .ename{display:none}
.ehp{width:9.375rem;margin-top:0.25rem;position:relative}
/* The bar is a tube, not a swatch: a sunken trough (inner shadow, black rim),
   a fill lit from above, and a gloss across the top. Flat-shaded rectangles
   read as placeholder UI against painted backdrops. */
.ehp .bar{height:0.9375rem;border-radius:0.5rem;overflow:hidden;position:relative;
  background:linear-gradient(180deg,#180809,#301218);
  border:1px solid rgba(0,0,0,.8);
  box-shadow:0 0.125rem 0.3125rem rgba(0,0,0,.5),inset 0 0.0625rem 0.1875rem rgba(0,0,0,.85),0 0 0 1px rgba(255,255,255,.06)}
.ehp .bar > i{display:block;height:100%;transition:width .35s cubic-bezier(.4,0,.2,1);
  background:linear-gradient(180deg,#ff8f8f 0%,#e0575d 40%,#a3242a 66%,#791419 100%)}
.ehp .bar > i.hp-fill{position:relative;z-index:1}
/* the vacated slice, catching up a beat behind the fill — its timing is set
   inline by hpBar(), which has to resume the sweep across re-renders */
.ehp .bar > i.hp-trail{position:absolute;left:0;top:0;z-index:0;
  background:linear-gradient(180deg,#fff0c4,#f2a24a)}
/* glass highlight — sits over the fill but under the label */
.ehp .bar::after{content:'';position:absolute;left:0;right:0;top:0;height:46%;z-index:2;pointer-events:none;
  border-radius:0.5rem 0.5rem 0 0;
  background:linear-gradient(180deg,rgba(255,255,255,.24),rgba(255,255,255,.02))}
.ehp .bar.blocked{border-color:#3d5a7d;box-shadow:0 0 0.5rem rgba(90,150,220,.4),inset 0 0.0625rem 0.1875rem rgba(0,0,0,.85)}
/* the champion's own gauge wears the run's gold, so "which bar is mine" is
   answered by colour and not by position */
.entity.player .ehp .bar{box-shadow:0 0.125rem 0.3125rem rgba(0,0,0,.5),inset 0 0.0625rem 0.1875rem rgba(0,0,0,.85),0 0 0 1px rgba(231,198,106,.35)}
/* flex, not grid: the label carries inline spans (dot tick, block, poison
   preview) that a single-column grid would stack into rows and clip */
.ehp .txt{position:absolute;inset:0;z-index:3;display:flex;align-items:center;justify-content:center;gap:0.3125rem;
  white-space:nowrap;font-family:var(--font-body);font-size:0.6875rem;color:#fff;
  text-shadow:0 1px 2px #000,0 0 0.25rem rgba(0,0,0,.85)}
/* damage-over-time slices painted onto the bar — the HP each DoT eats next tick */
/* z-index 2: above the fill (1) so the slice it will eat is visible, below the
   label (3) so the numbers still read */
.dot-seg{position:absolute;top:0;bottom:0;z-index:2;pointer-events:none;
  background:linear-gradient(180deg,#8ff0b4,#31a862);box-shadow:inset 0 0 0 1px rgba(0,0,0,.28);
  animation:dotBreathe 1.9s ease-in-out infinite}
.dot-seg.dot-burn{background:linear-gradient(180deg,#ffc98a,#e07a25)}
.dot-seg.dot-bleed{background:linear-gradient(180deg,#ff9fb2,#c8324a)}
@keyframes dotBreathe{0%,100%{filter:brightness(1)}50%{filter:brightness(1.28)}}
.ehp .bar .txt .dot-tick{color:#9ff0bf;font-weight:700;margin-left:0.25rem;text-shadow:0 1px 2px #000}
.ehp .bar.dot-lethal{border-color:#4fd08a;box-shadow:0 0 0.75rem rgba(80,220,140,.55)}
.ehp .bar.dot-lethal .txt .dot-tick{color:#c6ffdd}
.ehp .txt.previewing b{color:#ffd36b}
.ehp .txt .pv-blk{color:#8fd0ff}
/* drag-preview: the chunk of HP the card would remove pulses on the bar */
.hp-ghost{position:absolute;top:0;bottom:0;z-index:1;pointer-events:none;
  background:repeating-linear-gradient(-45deg, rgba(255,214,107,.85) 0 0.375rem, rgba(255,170,60,.75) 0.375rem 0.75rem);
  animation:ghostPulse .8s ease-in-out infinite}
.hp-ghost.kill{background:repeating-linear-gradient(-45deg, rgba(255,90,90,.9) 0 0.375rem, rgba(200,40,40,.85) 0.375rem 0.75rem)}
.hp-ghost.dot{background:repeating-linear-gradient(-45deg, rgba(127,230,160,.8) 0 0.375rem, rgba(60,170,100,.7) 0.375rem 0.75rem)}
.ehp .txt .pv-psn{color:#7fe6a0}
.ehp .txt .pv-vul{color:#ff8a8a;font-weight:700}
.ehp .txt .pv-bld{color:#ff6f8a;font-weight:700}
@keyframes ghostPulse{0%,100%{opacity:.95}50%{opacity:.45}}
/* lethal: the whole bar screams */
.ehp .bar.lethal{border-color:#ff5a5a;box-shadow:0 0 1rem rgba(255,60,60,.7);animation:lethalPulse .7s ease-in-out infinite}
.ehp .bar.lethal .txt{color:#ffdcdc;font-weight:700;letter-spacing:.08em}
@keyframes lethalPulse{0%,100%{box-shadow:0 0 0.625rem rgba(255,60,60,.5)}50%{box-shadow:0 0 1.375rem rgba(255,60,60,.95)}}
.entity.will-die .sprite{filter:drop-shadow(0 0 1.5rem rgba(255,60,60,.85)) brightness(1.2) saturate(1.2)}
/* applied-debuff preview chip under the bar */
.debuff-chip{position:absolute;top:100%;left:50%;transform:translateX(-50%);margin-top:0.1875rem;white-space:nowrap;
  font-family:var(--font-body);font-size:0.6563rem;color:#d9a6e8;background:rgba(8,9,16,.85);
  border:1px solid #5a3d6a;border-radius:0.5rem;padding:1px 0.5rem;z-index:5}
/* block shield hugs the left end of the HP bar */
.block-badge{position:absolute;left:-1.0625rem;top:50%;transform:translateY(-50%);width:2rem;height:2rem;display:grid;place-items:center;z-index:3}
.block-badge svg{width:2rem;height:2rem;position:absolute;inset:0}
.block-badge span{position:relative;font-family:var(--font-body);font-size:0.75rem;font-weight:600;color:#dff}
/* Intent */
/* intent stack sits above the enemy's head: detail line + icon badge */
.intent-wrap{position:absolute;bottom:100%;left:50%;transform:translateX(-50%);
  display:flex;flex-direction:column;align-items:center;gap:0.3125rem;margin-bottom:0.3125rem;z-index:4}
/* intent icon row: bare colored medals, one per thing the move does — sword
   for attack, shield for block, up-glyph for a self buff, down-glyph for
   something done TO the player. No boxes, no numbers: everything the move
   will actually do lives in each medal's tooltip (hover / tap). */
/* top-aligned, uniform height: every medal shares one line whether or not a
   number hangs under it. The row always reserves the number line (the plate is
   bottom-anchored above the head, so without the reservation a numberless
   medal sat lower by exactly the number's height). */
.intent-icons{display:flex;gap:0.45rem;align-items:flex-start;justify-content:center;width:max-content;
  min-height:calc(max(1.7rem,20px) + 0.05rem + max(1rem,13px))}
/* medal stacked over its number, matching the player's threat badge. The number
   used to overlap the medal's corner, where a white glyph and white digits sat
   on top of each other and a multi-hit string like "1×3" ran clean across the
   sword. Below it, any width fits and both shapes stay readable. */
.int-ic{--ic:#8f8aa8;display:flex;flex-direction:column;align-items:center;gap:0.05rem;
  cursor:inherit;position:relative}
/* boxless, like every other number on the battlefield: a stacked black halo is
   what carries it over the art */
.int-ic .ii-num{line-height:1;
  font-family:var(--font-display);font-size:max(1rem,13px);font-weight:700;
  color:#fff;letter-spacing:.01em;pointer-events:none;
  text-shadow:0 1px 2px #000,0 0 0.1875rem rgba(0,0,0,.95),0 0 0.375rem rgba(0,0,0,.85)}
.int-ic.t-attack .ii-num{color:#ffd9d0}
.int-ic.t-defend .ii-num{color:#cfe6ff}
.intent-icons.stopped .ii-num{opacity:.45}
.int-ic .ii-medal{width:max(1.7rem,20px);height:max(1.7rem,20px);border-radius:50%;display:grid;place-items:center;
  background:radial-gradient(circle at 50% 30%, color-mix(in srgb, var(--ic) 92%, #fff) 0%, var(--ic) 44%, color-mix(in srgb, var(--ic) 40%, #000) 100%);
  box-shadow:0 0 0.5rem color-mix(in srgb, var(--ic) 50%, transparent), 0 2px 6px rgba(0,0,0,.55), inset 0 -2px 0.25rem rgba(0,0,0,.45);
  border:1px solid color-mix(in srgb, var(--ic) 60%, #fff)}
.int-ic .ii-medal svg{display:block;filter:drop-shadow(0 1px 1px rgba(0,0,0,.6))}
/* An intent that will not happen — entangled, frozen or unravelled: the row
   greys out; its tooltip names the reason. */
.intent-icons.stopped{opacity:.7;filter:saturate(.3)}
/* Painted status emblems. The PNG supplies only its alpha channel — the
   visible colour is background-color, so a single file tints to any status
   hue and never has to be regenerated to change colour. */
/* --ms is the per-file optical correction Art.statusEmblem computes: each PNG
   bakes in a different margin, so "contain" alone renders them at visibly
   different sizes next to the vector glyphs. */
.st-emblem{display:block;flex:0 0 auto;
  -webkit-mask:var(--m) center/var(--ms,contain) no-repeat;
          mask:var(--m) center/var(--ms,contain) no-repeat}
/* Status pips */
/* wider gap BETWEEN pips than inside them: without plates to separate the
   statuses, spacing is what groups each number with its own emblem */
.statuses{display:flex;gap:0.5rem;flex-wrap:wrap;justify-content:center;margin-top:0.3125rem;max-width:14.375rem}
/* Boxless: the emblem and its number ARE the pip. No plate, no border — the
   art carries the meaning and a text shadow keeps the count legible over any
   backdrop. The count sits tight against the glyph it belongs to, so a row of
   statuses reads as icon-number pairs rather than an undifferentiated strip. */
.pip{display:flex;align-items:center;gap:0.15rem;background:none;border:none;
  padding:0 0.1rem;font-family:var(--font-body);font-size:0.875rem;font-weight:700;
  color:#fff;text-shadow:0 1px 2px #000,0 0 0.25rem rgba(0,0,0,.9);cursor:inherit}
/* one place sets the glyph size for all three kinds (drawn SVG, painted mask,
   procedural fallback) — the phone blocks below scale it up from here */
/* the emblem gets the same black halo the number does, or a pale glyph
   vanishes into a pale patch of the backdrop art */
.pip svg,.pip .st-emblem,.pip .st-emblem-svg{width:1.3rem;height:1.3rem;flex:0 0 auto;
  filter:drop-shadow(0 1px 1px rgba(0,0,0,.9)) drop-shadow(0 0 2px rgba(0,0,0,.75))}
/* Frozen at or past its threshold: this foe loses its next turn */
.pip.primed{animation:pipPrimed 1.1s ease-in-out infinite;border-radius:0.375rem}
@keyframes pipPrimed{50%{box-shadow:0 0 0.75rem rgba(155,233,240,.75)}}

/* Floating numbers */
.floatnum{position:absolute;font-family:var(--font-display);font-weight:800;font-size:2rem;
  pointer-events:none;z-index:40;text-shadow:0 2px 0.375rem #000;animation:floatUp 1s ease-out forwards}
.floatnum.dmg{color:#ff6b6b}
.floatnum.block{color:#8fd0ff}
.floatnum.heal{color:#7fe6a0}
.floatnum.crit{font-size:2.75rem;color:#ffd36b}
@keyframes floatUp{0%{opacity:0;transform:translateY(0) scale(.6)}15%{opacity:1;transform:translateY(-0.625rem) scale(1.1)}100%{opacity:0;transform:translateY(-4.375rem) scale(1)}}

/* Bottom bar: energy, hand, end turn, piles */
.combat-bottom{grid-column:1/3;grid-row:3;position:relative;height:14.5rem;z-index:6;
  background:linear-gradient(180deg,transparent,rgba(6,7,14,.6) 40%,rgba(6,7,14,.85))}
.hand-zone{position:absolute;left:0.5rem;right:17.5rem;bottom:0;height:16.125rem;display:flex;justify-content:center;align-items:flex-end;pointer-events:none}
.hand{display:flex;justify-content:center;align-items:flex-end;height:100%;pointer-events:none;padding-bottom:1.25rem}
/* ENERGY — a live ember orb seated in the pile row, immediately right of Draw.
   No word "energy": the number + the ring of flame licks say it. Its vertical
   centre lines up with the pile card icons. */
.energy-orb{position:absolute;left:7rem;bottom:3.25rem;width:4.75rem;height:4.75rem;z-index:8;border-radius:50%;
  border:2px solid #b8933a;
  background:
    radial-gradient(circle at 50% 28%, rgba(255,214,140,.42), transparent 56%),
    radial-gradient(circle at 50% 58%, #7a3f10 0%, #2e1708 66%, #100904 100%);
  box-shadow:
    0 0 1.375rem rgba(255,150,60,.30), 0 0 0 0.25rem rgba(12,8,4,.75),
    inset 0 2px 0 rgba(255,225,160,.28), inset 0 -0.5rem 1rem rgba(0,0,0,.6)}
/* rotating corona of flame licks around the rim */
.energy-orb .eo-ring{position:absolute;inset:-0.5625rem;border-radius:50%;pointer-events:none;
  background:conic-gradient(from 0deg,
    rgba(255,160,60,.55) 0deg, transparent 26deg, rgba(255,190,90,.5) 46deg, transparent 74deg,
    rgba(255,140,50,.5) 96deg, transparent 128deg, rgba(255,200,110,.45) 150deg, transparent 186deg,
    rgba(255,150,60,.5) 214deg, transparent 250deg, rgba(255,180,80,.5) 276deg, transparent 312deg,
    rgba(255,150,60,.5) 336deg, transparent 360deg);
  -webkit-mask:radial-gradient(circle, transparent 56%, #000 62%, #000 78%, transparent 84%);
  mask:radial-gradient(circle, transparent 56%, #000 62%, #000 78%, transparent 84%);
  filter:blur(1.4px);animation:emberSpin 9s linear infinite;opacity:.9}
@keyframes emberSpin{to{transform:rotate(360deg)}}
.energy-orb.flash{animation:orbFlash .45s}
@keyframes orbFlash{0%,100%{filter:none}30%{filter:brightness(1.5) drop-shadow(0 0 1.25rem rgba(255,80,80,.8))}}
.energy-orb .etext{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;line-height:1}
.energy-orb .etext b{font-family:var(--font-display);font-weight:700;font-size:1.875rem;line-height:.9;color:#fff3d8;
  text-shadow:0 2px 0.3125rem #3a1200, 0 0 0.875rem rgba(255,175,80,.85)}
.energy-orb .etext b i{font-style:normal;font-size:0.9375rem;opacity:.62;margin-left:1px}
.energy-orb.drained{border-color:#7d2e32;filter:saturate(.5) brightness(.85)}
.energy-orb.drained .eo-ring{opacity:.35;animation-duration:16s}
.energy-orb.drained .etext b{color:#ffb3ac;text-shadow:0 2px 0.3125rem #000}

/* pile cluster bottom-right: Draw, Discard, Exhaust in a row */
.pile{position:absolute;bottom:2.4375rem;width:4.125rem;text-align:center;z-index:8;cursor:pointer;transition:transform .12s}
.pile:hover{transform:translateY(-0.1875rem)}
.pile .pile-icon{width:3.125rem;height:4.25rem;margin:0 auto;border-radius:0.5rem;border:1px solid var(--line);
  background:linear-gradient(160deg,var(--panel-2),var(--bg-2));position:relative;box-shadow:var(--shadow-1),inset 0 0 0 1px rgba(255,255,255,.03)}
.pile .pile-icon::before{content:'';position:absolute;inset:0.25rem;border:1px solid var(--line-soft);border-radius:0.3125rem}
.pile .pile-icon::after{content:'';position:absolute;inset:0.5rem 0.5rem auto 0.5rem;height:2px;background:var(--line);border-radius:2px;box-shadow:0 0.3125rem 0 var(--line),0 0.625rem 0 var(--line)}
/* The count sits ON the pile face, dead centre — bare numerals, no plate. The
   face carries a ruled card-back pattern, but those lines are up at the top of
   the box and the number is centred below them, so a shadow is all it needs to
   stay legible. z-index clears the ::before/::after decoration drawn inside the
   same box. */
.pile .pile-icon{display:grid;place-items:center}
.pile .pile-count{position:relative;z-index:2;font-family:var(--font-display);font-size:1.125rem;
  line-height:1;font-weight:700;color:var(--ink);
  text-shadow:0 1px 0.1875rem rgba(0,0,0,.95),0 0 0.5rem rgba(0,0,0,.7)}
.pile .pile-lbl{font-size:0.5625rem;color:var(--ink-faint);text-transform:uppercase;letter-spacing:.12em;margin-top:0.25rem}
/* draw pile anchors the left cluster; the energy orb sits directly right of it */
.pile.draw{left:2rem;right:auto}
.pile.discard{right:7.75rem}
.pile.exhaust{right:3rem}

.endturn{position:absolute;right:2.25rem;bottom:9.5rem;z-index:9}

/* attacker lunge */
.entity.atk-right{animation:atkLungeR .42s cubic-bezier(.2,.8,.3,1)}
.entity.atk-left{animation:atkLungeL .42s cubic-bezier(.2,.8,.3,1)}
@keyframes atkLungeR{30%{transform:translateX(3.375rem)}100%{transform:none}}
@keyframes atkLungeL{30%{transform:translateX(-3.375rem)}100%{transform:none}}
.endturn .btn{padding:.85em 1.7em;font-size:1.125rem;box-shadow:0 0 1.625rem rgba(231,198,106,.4),var(--shadow-2)}
.endturn .btn.waiting{filter:grayscale(.5);opacity:.7}

/* ============================================================
   CARD (the star of the show)
   ============================================================ */
.card{
  position:relative;width:12rem;height:16.875rem;border-radius:0.9375rem;flex:0 0 auto;
  transform-origin:bottom center;transition:transform .34s cubic-bezier(.25,.9,.3,1.05), box-shadow .3s, filter .3s;
  will-change:transform;
  --frame:#4a5178;--frameDk:#2a2f4d;--plate:#191c30;--gloss:rgba(255,255,255,.06);
}
.hand .card{pointer-events:auto;margin:0 -2.875rem}
/* cards physically fly out of the draw pile — turn deal AND mid-turn draws.
   --dx/--dy are set in JS from the pile's real screen position. */
.card.deal{animation:dealIn .5s cubic-bezier(.16,.86,.28,1.02) backwards}
@keyframes dealIn{
  0%{opacity:0;transform:translate(var(--dx,-26.25rem),var(--dy,9.375rem)) rotate(-26deg) scale(.34)}
  22%{opacity:1}
  70%{transform:translate(calc(var(--dx,-26.25rem) * .1), calc(var(--dy,9.375rem) * .1 - 1rem)) rotate(-4deg) scale(1.02)}
}
/* the mirror of dealIn — a card that leaves the hand flies into whichever pile
   swallowed it. Ghosts live in their own fixed layer so the hand can rebuild
   underneath them. --fx/--fy are set in JS from the pile's real position. */
#card-fly-layer{position:fixed;inset:0;pointer-events:none;z-index:900}
.card.fly-out{position:fixed;pointer-events:none;transform-origin:50% 50%;
  animation:flyOut .46s cubic-bezier(.42,.02,.72,.4) forwards}
@keyframes flyOut{
  0%{opacity:1;transform:translate(0,0) rotate(0) scale(1)}
  35%{opacity:.95;transform:translate(calc(var(--fx,0px) * .2), calc(var(--fy,0px) * .2 - 1.625rem)) rotate(6deg) scale(1.04)}
  100%{opacity:0;transform:translate(var(--fx,0px),var(--fy,0px)) rotate(28deg) scale(.3)}
}
/* exhaust is a different fate from discard, and should read as one */
.card.fly-out.to-exhaust{animation:flyExhaust .58s cubic-bezier(.3,.1,.5,1) forwards;
  filter:saturate(.25) brightness(1.5)}
@keyframes flyExhaust{
  0%{opacity:1;transform:translate(0,0) scale(1);filter:saturate(1) brightness(1)}
  30%{opacity:.9;transform:translate(calc(var(--fx,0px) * .12), calc(var(--fy,0px) * .12 - 2.125rem)) scale(1.1);
      filter:saturate(.2) brightness(2.1)}
  100%{opacity:0;transform:translate(var(--fx,0px),var(--fy,0px)) scale(.22);
       filter:saturate(0) brightness(2.6) blur(0.1875rem)}
}
/* the pile recoils as it feeds the hand — and as it swallows one */
.pile.dealing .pile-icon{animation:pileFeed .42s cubic-bezier(.3,.9,.3,1)}
@keyframes pileFeed{0%{transform:none}35%{transform:translateY(0.1875rem) scale(.94) rotate(-3deg)}100%{transform:none}}
/* can't afford: quick head-shake */
.card.nope{animation:cardNope .4s}
@keyframes cardNope{0%,100%{transform:translateX(0)}20%{transform:translateX(-0.625rem) rotate(-2deg)}45%{transform:translateX(0.5rem) rotate(1.6deg)}70%{transform:translateX(-0.3125rem)}}
/* dragging states */
.card.dragging{transition:none;cursor:grabbing}
/* commit glow: the etch turns gold rather than painting a second ring */
.card.dragging.in-playzone .card-inner{box-shadow:var(--shadow-2),0 0 0 1px #000,0 0 2.125rem var(--gold-glow)}
.card.dragging.in-playzone .frame-etch{color:var(--gold)}
.card.dragging.in-playzone{filter:brightness(1.1)}
.playzone-hint{position:fixed;left:50%;transform:translateX(-50%);z-index:920;pointer-events:none;
  font-family:var(--font-display);font-size:0.8125rem;letter-spacing:.14em;text-transform:uppercase;
  color:var(--ink-faint);background:rgba(8,9,16,.72);border:1px solid var(--line);border-radius:1.25rem;padding:0.4375rem 1.125rem;
  transition:color .15s,border-color .15s,box-shadow .15s}
.playzone-hint.ok{color:var(--gold);border-color:var(--gold-deep);box-shadow:0 0 1.125rem var(--gold-glow)}
/* One clean panel + one engraved vector frame — no stacked shadow rings.
   The etch SVG carries the double rule, the corner brackets and the mid-edge
   diamonds, all in the class colour, all pixel-aligned. */
.card .card-inner{position:absolute;inset:0;border-radius:0.875rem;overflow:hidden;
  background:
    radial-gradient(120% 62% at 50% -6%, var(--gloss), transparent 46%),
    linear-gradient(180deg, var(--plate) 0%, #12141f 46%, #0a0c14 100%);
  box-shadow:var(--shadow-2), 0 0 0 1px #000}
.card .frame-etch{position:absolute;inset:0;z-index:6;pointer-events:none;color:var(--frame);
  filter:drop-shadow(0 1px 1px rgba(0,0,0,.7))}
.card .frame-etch svg{width:100%;height:100%;display:block}
/* painted per-class border art: stretched to the card box (its aspect is
   drawn to match), no class-colour tinting — the paint IS the class colour */
.card .frame-etch img{width:100%;height:100%;display:block;object-fit:fill}
.card .frame-etch.raster-border{filter:none}
/* The frame is the CLASS's colour and only the class's — rarity never repaints
   it. Rare/legendary still earn a faint aura, but in their own frame colour. */
.card[data-rarity="rare"] .frame-etch{
  filter:drop-shadow(0 1px 1px rgba(0,0,0,.7)) drop-shadow(0 0 0.375rem color-mix(in srgb, var(--r-rare) 42%, transparent))}
/* deep bronze, not the old light gold — the title now sits on cream parchment */
.card[data-rarity="legendary"] .cname{background:linear-gradient(180deg,#a8720e,#8a5a10 62%,#5f3c08);
  -webkit-background-clip:text;background-clip:text;color:transparent}
.card[data-rarity="legendary"] .frame-etch{
  filter:drop-shadow(0 1px 1px rgba(0,0,0,.7)) drop-shadow(0 0 0.5rem color-mix(in srgb, var(--r-legendary) 48%, transparent))}

/* title — centred at the top, inside the frame, clear of the cost lozenge */
/* block + text-align (NOT centered flex): a centered flex box hides its own
   overflow from scrollWidth, which blinds the auto-fitter */
/* Reference layout (2026-08-03): art fills the top, the name sits mid-card on
   a parchment banner with the rarity gem set into its top edge, rules text
   below. Interior offsets clear the PAINTED border band (~13px). */
.card .banner{position:absolute;left:0.4375rem;right:0.4375rem;top:9.375rem;height:2.75rem;z-index:4;
  background:linear-gradient(180deg,#f2e8ca 0%,#e4d5ae 55%,#cdb98c 100%);
  border-top:1px solid #6b5636;border-bottom:1px solid #4a3a1c;
  box-shadow:0 0.1875rem 0.5rem rgba(0,0,0,.55), inset 0 1px 0 rgba(255,255,255,.55), inset 0 -0.1875rem 0.25rem rgba(90,70,40,.30)}
/* the gem is CENTRED on the banner's top line (half over the art, half on the
   parchment); the title starts below its lower tip so they never collide */
.card .banner .rgem{position:absolute;top:-0.53125rem;left:50%;transform:translateX(-50%);
  width:1.0625rem;height:1.0625rem;filter:drop-shadow(0 1px 2px rgba(0,0,0,.8))}
.card .banner .rgem svg{width:100%;height:100%;display:block}
.card .cname{position:absolute;top:9.9375rem;left:1.25rem;right:1.25rem;height:1.1875rem;z-index:5;
  text-align:center;line-height:1.1875rem;
  font-family:var(--font-display);font-size:0.9688rem;font-weight:700;
  color:#241a0c;text-shadow:0 1px 0 rgba(255,255,255,.4);
  white-space:nowrap;overflow:hidden;letter-spacing:.02em}
/* type caption under the title: · ATTACK · with tiny flanking diamonds — dark
   ink on the parchment, not the rarity colour (unreadable on cream) */
/* raised off the banner's bottom edge so the caption doesn't crowd it */
.card .typecap{position:absolute;top:11.0625rem;left:1.875rem;right:1.875rem;height:0.6875rem;z-index:5;
  display:flex;align-items:center;justify-content:center;gap:0.375rem;
  font-family:var(--font-display);font-size:0.5313rem;font-weight:600;
  letter-spacing:.26em;text-indent:.26em;text-transform:uppercase}
.card .typecap i{width:0.2125rem;height:0.2125rem;background:currentColor;transform:rotate(45deg);flex:0 0 auto;opacity:.75}
.card .typecap span{line-height:1}
.card .typecap{color:#5a4720}

/* cost lozenge hung over the top-left frame corner, like a seal */
.card .cost{position:absolute;top:-0.1875rem;left:-0.1875rem;width:2.75rem;height:3rem;z-index:7;
  filter:drop-shadow(0 2px 0.25rem rgba(0,0,0,.7))}
.card .cost svg{width:100%;height:100%}
.card .cost b{display:none}
.card .cost--legacy b{position:absolute;left:0;top:0;width:2.75rem;height:2.625rem;display:grid;place-items:center;
  font-family:var(--font-display);font-size:1.0625rem;color:#fff;text-shadow:0 1px 0.1875rem #000}

/* the illustration plate */
.card .art{position:absolute;left:0.8125rem;right:0.8125rem;top:0.8125rem;height:8.9375rem;border-radius:0.375rem 0.375rem 0 0;overflow:hidden;
  box-shadow:inset 0 0 0 1px rgba(0,0,0,.85);background:#08090f;z-index:1}
.card .art svg{width:100%;height:100%;display:block}
.card .art .art-frame{position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(180deg,rgba(0,0,0,.26) 0%,transparent 15%,transparent 74%,rgba(2,3,10,.5) 100%);
  box-shadow:inset 0 0 0 1px rgba(0,0,0,.7), inset 0 1px 0 rgba(255,255,255,.08), inset 0 0 1rem rgba(0,0,0,.4)}

/* rules text — an open panel; the fitter shrinks the type before it can spill */
.card .textbox{position:absolute;left:0.875rem;right:0.875rem;top:12.4375rem;bottom:0.9375rem;padding:2px 0.25rem;overflow:hidden;
  display:flex;align-items:center;justify-content:center;text-align:center;z-index:2}
.card .ctext{font-family:var(--font-body);font-size:0.8125rem;line-height:1.36;color:#e9e5f2}
.card .ctext b{color:#fff;font-weight:600}
/* standardized: EVERY number is bright white bold — damage and Block spans
   included; yellow is reserved for keywords/special words (user 2026-08-03) */
.card .ctext .num{color:#fff;font-weight:700}
.card .ctext .kw{color:var(--gold);font-weight:600;cursor:inherit}
.card .ctext .dmg{color:#fff;font-weight:700}
.card .ctext .blk{color:#fff;font-weight:700}
.card .ctext .up{color:#8fe6a0}

/* Frame palettes are keyed to the CHAMPION the card belongs to, so a hand
   reads at a glance as "mine" vs "anyone's". Card type is already carried by
   the type band and the cost gem, so it does not need the frame too. */
.card[data-cls="generic"]{--frame:#8b93a8;--frameDk:#3a4152;--plate:#191d2a;--gloss:rgba(255,255,255,.06)}
.card[data-cls="vanguard"]{--frame:#e08a52;--frameDk:#6b3418;--plate:#33170c;--gloss:rgba(255,196,150,.09)}
.card[data-cls="shade"]{--frame:#5fc98a;--frameDk:#1d5236;--plate:#0e2a1c;--gloss:rgba(170,255,210,.08)}
.card[data-cls="artificer"]{--frame:#5aa8e0;--frameDk:#1d4a6e;--plate:#0d2436;--gloss:rgba(175,220,255,.08)}
.card[data-cls="seer"]{--frame:#b17fe0;--frameDk:#472d68;--plate:#221338;--gloss:rgba(220,190,255,.09)}
.card[data-cls="ritualist"]{--frame:#dcb45c;--frameDk:#6a5017;--plate:#2e230a;--gloss:rgba(255,230,160,.09)}
.card[data-cls="horologist"]{--frame:#63c8d8;--frameDk:#1c5464;--plate:#0c2a33;--gloss:rgba(180,244,255,.08)}
.card[data-cls="mage"]{--frame:#e46ad0;--frameDk:#5e1f5c;--plate:#2a0d2c;--gloss:rgba(255,190,245,.09)}
/* statuses and curses are nobody's — they keep their own grim livery */
.card[data-type="status"]{--frame:#7a8098;--frameDk:#343949;--plate:#161a26;--gloss:rgba(255,255,255,.05)}
.card[data-type="curse"]{--frame:#8a63c0;--frameDk:#3a2858;--plate:#190f2e;--gloss:rgba(200,160,255,.08)}

/* hand fanning handled inline via JS transforms; hover pop */
.hand .card:hover{z-index:50}
/* playable = soft golden glow around the card border; unplayable cards stay
   fully readable (never grayed out) */
.card.playable-hi .card-inner{box-shadow:var(--shadow-2),0 0 0 1px #000,
  0 0 0.875rem rgba(231,198,106,.5), 0 0 1.875rem rgba(231,198,106,.22)}
.card.playable-hi .frame-etch{color:var(--gold-deep)}
.card.dragging{pointer-events:none;z-index:999}
/* permanently unplayable: readable, but unmistakably not a play */
.card.no-play .card-inner{filter:saturate(.6) brightness(.86)}

.card.no-play .cost svg{filter:grayscale(.75) brightness(.8)}
.card.no-play .art::after{content:'';position:absolute;inset:0;pointer-events:none;
  background:repeating-linear-gradient(-45deg,rgba(0,0,0,.22) 0 0.4375rem,transparent 0.4375rem 0.875rem)}
/* mini — same layout scaled to 140×197 (the aspect ratio is identical, so the
   etch overlay stretches without visible distortion) */
.card.mini{width:8.75rem;height:12.3125rem;transform:none!important}
.card.mini .cname{top:7.0625rem;left:0.875rem;right:0.875rem;height:0.875rem;font-size:0.6563rem;line-height:0.875rem}
.card.mini .typecap{top:7.875rem;font-size:0.4125rem;letter-spacing:.2em;text-indent:.2em;height:0.5625rem;gap:0.25rem}
.card.mini .typecap i{width:0.1625rem;height:0.1625rem}
.card.mini .cost{top:-2px;left:-2px;width:2.0625rem;height:2.25rem}

.card.mini .art{top:0.5625rem;height:6.25rem;left:0.5625rem;right:0.5625rem}
.card.mini .banner{top:6.625rem;height:1.9375rem;left:0.3125rem;right:0.3125rem}
.card.mini .banner .rgem{width:0.8125rem;height:0.8125rem;top:-0.40625rem}
.card.mini .textbox{top:8.625rem;bottom:0.625rem;left:0.5625rem;right:0.5625rem}
.card.mini .ctext{font-size:0.6rem;line-height:1.28}
.card.mini .cost{width:1.875rem;height:1.875rem}


/* upgraded name marker */
.card.upgraded .cname{color:#a7f0bd}
/* the + is part of the title text now (G.cardTitle), not a pseudo-element */

/* ============================================================
   COMBAT LOG (right rail)
   ============================================================ */
/* The log is a chromeless overlay: no panel, no border — the arena art runs
   underneath and the text carries itself on stacked black halos, like every
   other number on the battlefield. The rail ignores the pointer except for
   the head controls and the scrollable body, so the empty strip around them
   never eats a click. */
.log-rail{grid-column:1/3;grid-row:2;justify-self:end;width:15.5rem;
  display:flex;flex-direction:column;min-height:0;z-index:8;pointer-events:none}
.log-head{padding:0.5rem 0.75rem 0.25rem;display:flex;align-items:center;justify-content:flex-end;gap:0.375rem}
.log-head h3{font-size:0.75rem;color:var(--gold);letter-spacing:.16em;text-transform:uppercase;margin-right:auto;
  text-shadow:0 1px 2px #000,0 0 0.375rem rgba(0,0,0,.85)}
.log-head .turnpill{font-family:var(--font-display);font-size:0.6875rem;font-weight:700;letter-spacing:.08em;
  text-transform:uppercase;color:#ffe9b0;white-space:nowrap;pointer-events:auto;
  background:linear-gradient(180deg,rgba(88,62,26,.9),rgba(32,22,10,.9));
  padding:0.1875rem 0.625rem;border-radius:1rem;border:1px solid rgba(231,198,106,.5);
  box-shadow:inset 0 1px 0 rgba(255,225,150,.3),0 2px 0.375rem rgba(0,0,0,.5);text-shadow:0 1px 2px #000}
.log-body{flex:1;overflow-y:auto;padding:0.25rem 0.625rem 0.75rem;display:flex;flex-direction:column;gap:1px;
  pointer-events:auto;
  /* old lines dissolve toward the top instead of hitting an invisible edge */
  -webkit-mask-image:linear-gradient(180deg,transparent 0,#000 12%);
  mask-image:linear-gradient(180deg,transparent 0,#000 12%)}
.log-body::-webkit-scrollbar{width:0.25rem}
.log-body::-webkit-scrollbar-thumb{background:rgba(255,255,255,.22)}
.log-line{font-family:var(--font-body);font-size:0.8125rem;font-weight:600;line-height:1.4;padding:0.125rem 0.4375rem;border-radius:0.25rem;
  color:#fff;border-left:2px solid transparent;animation:logIn .25s ease;
  text-shadow:0 1px 1px #000,0 1px 3px #000,0 0 0.375rem rgba(0,0,0,.95),0 0 0.75rem rgba(0,0,0,.8)}
@keyframes logIn{from{opacity:0;transform:translateX(0.5rem)}}
.log-line .who{font-weight:700;color:#fff}
.log-line .kw{color:#ffd98a;font-weight:600}
/* turn marker reads as a divider, not another line: centered small caps
   between a pair of fading rules */
.log-line.turn{margin:0.4375rem 0 0.125rem;padding:0.0625rem 0;color:var(--gold);border-left-color:transparent;
  background:none;font-family:var(--font-display);font-size:0.6875rem;letter-spacing:.14em;text-transform:uppercase;
  display:flex;align-items:center;justify-content:center;gap:0.5rem;text-align:center}
.log-line.turn::before,.log-line.turn::after{content:"";flex:1;height:1px;opacity:.55;
  background:linear-gradient(90deg,transparent,var(--gold));box-shadow:0 1px 1px rgba(0,0,0,.8)}
.log-line.turn::after{background:linear-gradient(90deg,var(--gold),transparent)}
/* the tick carries the who-did-it color — the words themselves stay white
   for contrast over the art */
.log-line.player{border-left-color:#5a89b8}
.log-line.enemy{border-left-color:#c05a60}
.log-line.dmg .n{color:#ffa898;font-weight:700}
.log-line.block .n{color:#aadcff;font-weight:700}
.log-line.sys{color:rgba(255,255,255,.78);font-style:italic}
.log-line.buff{border-left-color:#5fa878}
.log-line.debuff{border-left-color:#c8894a}

/* ============================================================
   OVERLAYS / MODALS  (rewards, card picker, tooltips)
   ============================================================ */
/* Above EVERY combat layer. The hand sets inline z-indices up to 500 and the
   drag/fly layers sit at 900+, so a modal opened mid-combat (the end-of-run
   summary above all) was being punched through by the cards underneath it. */
.overlay{position:absolute;inset:0;background:rgba(4,4,10,.72);backdrop-filter:blur(0.1875rem);
  display:grid;place-items:center;z-index:1200;animation:fade .25s}
/* Run chrome lifted clear of a modal's dim (G.modal cfg.clearTop): the top bar
   and the relic tray under it stay readable and hoverable while a dialog — the
   spoils screen — is open. Above the overlay's 1200, below a tooltip. */
.above-overlay{position:relative;z-index:1300}
@keyframes fade{from{opacity:0}}
.modal{background:linear-gradient(180deg,var(--panel),var(--bg-1));border:1px solid var(--line);
  border-radius:1rem;box-shadow:var(--shadow-3);padding:1.625rem 1.875rem;max-width:min(65.625rem,94vw);max-height:90vh;overflow:auto}
.modal h2{font-size:1.5rem;color:var(--gold);text-align:center;margin-bottom:0.25rem}
.modal .msub{text-align:center;color:var(--ink-faint);font-style:italic;margin-bottom:1.25rem}

.reward-list{display:flex;flex-direction:column;gap:0.75rem;min-width:26.25rem}
.reward-row{display:flex;align-items:center;gap:0.875rem;padding:0.75rem 1rem;border:1px solid var(--line);border-radius:0.75rem;
  background:rgba(255,255,255,.02);cursor:pointer;transition:.15s}
.reward-row:hover{border-color:var(--gold);transform:translateX(0.25rem);background:rgba(231,198,106,.05)}
.reward-row.taken{opacity:.4;pointer-events:none;text-decoration:line-through}
.reward-row.blocked{opacity:.45;cursor:default;filter:saturate(.4)}
.reward-row .ric{width:2.75rem;height:2.75rem;flex:0 0 auto}
.reward-row .rtxt{flex:1}
.reward-row .rtxt b{font-family:var(--font-display);font-size:1rem}
.reward-row .rtxt div{color:var(--ink-dim);font-size:0.8125rem}

/* dev-only battle-difficulty readout */
.combat-topbar{position:relative}
.diff-btn{position:absolute;right:0.4rem;top:calc(100% + 0.5rem);z-index:30;width:max(2.2rem,30px);height:max(2.2rem,30px);
  border-radius:50%;border:1px solid var(--line);background:rgba(20,18,26,.85);color:var(--gold);
  font-size:max(1.05rem,15px);cursor:pointer;line-height:1}
.diff-btn:hover{border-color:var(--gold)}
.diff-body{min-width:min(40rem,92vw);font-size:max(0.875rem,12px)}
.diff-body .dp-line,.diff-body .dp-chain{margin:0.3rem 0;color:var(--ink-dim)}
.diff-body b{color:var(--ink)}
.diff-table{width:100%;border-collapse:collapse;margin:0.6rem 0}
.diff-table th,.diff-table td{text-align:left;padding:0.3rem 0.5rem;border-bottom:1px solid var(--line-soft);font-size:max(0.8125rem,11px)}
.diff-table th{color:var(--ink-faint);font-family:var(--font-display);font-size:max(0.6875rem,9px);letter-spacing:.1em;text-transform:uppercase}

/* card-zoom browse arrows (compendium): finger-sized, hugging the modal edges */
.cz-nav{position:absolute;top:50%;transform:translateY(-50%);z-index:12;
  width:max(2.75rem,44px);height:max(2.75rem,44px);border-radius:50%;
  border:1px solid var(--line);background:rgba(16,14,22,.85);color:var(--gold);
  font-size:max(1.2rem,18px);line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center}
.cz-nav:hover{border-color:var(--gold);background:rgba(231,198,106,.12)}
.cz-nav.prev{left:0.4rem}
.cz-nav.next{right:0.4rem}

.card-choice{display:flex;gap:1.25rem;flex-wrap:wrap;justify-content:center}
.card-choice .card{cursor:pointer;transition:transform .15s}
.card-choice .card:hover{transform:translateY(-0.625rem) scale(1.05)}

.deck-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(9.25rem,100%),1fr));gap:0.875rem;
  justify-items:center;max-height:66vh;overflow:auto;padding:0.375rem}
.deck-grid .card{transform:none!important}

/* tooltip */
/* Above .overlay (1200) — a tooltip raised from inside a modal (shop, deck
   view, rewards) was painting behind the modal and read as "no tooltip". */
.tooltip{position:fixed;z-index:2000;max-width:17.5rem;background:linear-gradient(180deg,#1b1f34,#12131f);
  border:1px solid var(--gold-deep);border-radius:0.625rem;padding:0.625rem 0.8125rem;box-shadow:var(--shadow-3);
  font-family:var(--font-body);font-size:0.8125rem;color:var(--ink);pointer-events:none;line-height:1.4}
.tooltip h4{font-family:var(--font-display);font-size:0.875rem;color:var(--gold);margin-bottom:0.25rem}
.tooltip .kw{color:var(--gold);font-weight:600}
.tooltip em{color:var(--ink-faint)}
/* Relic tooltips explain their own jargon: rules text left, the keywords it
   references in a column to the right. The tooltip widens only when there is
   a second column to hold. */
/* ---- relic / potion popover -------------------------------------------------
   One column, one object. Header (icon + name + rarity chip), rules text, then
   the glossary for any keyword the text uses — each a compact row, clearly
   subordinate to the rules above it. */
.tooltip:has(.tip-card){max-width:20.5rem;padding:0}
/* the frame takes the rarity too, so the border, chip, icon ring and glossary
   accent all read as one object instead of a gold box around a purple card */
.tooltip:has(.tip-card.rar-starter){border-color:color-mix(in srgb, var(--r-starter) 34%, transparent)}
.tooltip:has(.tip-card.rar-common){border-color:color-mix(in srgb, var(--r-common) 40%, transparent)}
.tooltip:has(.tip-card.rar-uncommon){border-color:color-mix(in srgb, var(--r-uncommon) 46%, transparent)}
.tooltip:has(.tip-card.rar-rare){border-color:color-mix(in srgb, var(--r-rare) 48%, transparent)}
.tooltip:has(.tip-card.rar-legendary){border-color:color-mix(in srgb, var(--r-legendary) 52%, transparent)}
.tip-card{--rar-col:var(--r-common);padding:0.75rem 0.8125rem 0.8125rem}
.tip-card.rar-starter{--rar-col:var(--r-starter)}
.tip-card.rar-common{--rar-col:var(--r-common)}
.tip-card.rar-uncommon{--rar-col:var(--r-uncommon)}
.tip-card.rar-rare{--rar-col:var(--r-rare)}
.tip-card.rar-legendary{--rar-col:var(--r-legendary)}

.tip-head{display:flex;align-items:center;gap:0.5625rem;margin-bottom:0.5rem;
  padding-bottom:0.5rem;border-bottom:1px solid color-mix(in srgb, var(--rar-col) 20%, transparent)}
.tip-icon{width:2.375rem;height:2.375rem;flex:0 0 auto;border-radius:0.5rem;overflow:hidden;
  border:1px solid color-mix(in srgb, var(--rar-col) 42%, transparent);
  background:radial-gradient(70% 70% at 50% 35%, color-mix(in srgb, var(--rar-col) 13%, transparent), rgba(255,255,255,.03));
  box-shadow:inset 0 0 0.75rem color-mix(in srgb, var(--rar-col) 16%, transparent)}
.tip-icon svg{width:100%;height:100%;display:block}
.tip-id{min-width:0;display:flex;flex-direction:column;gap:0.1875rem}
.tip-card h4{font-family:var(--font-display);font-size:0.9375rem;color:var(--gold);
  margin:0;line-height:1.1;letter-spacing:.01em}
.tip-rar{font-size:0.5938rem;letter-spacing:.14em;text-transform:uppercase;font-weight:600;
  color:var(--rar-col);opacity:.9}
.tip-body{font-size:0.8125rem;line-height:1.5;color:var(--ink)}

/* glossary: a quiet block, not a second panel competing with the header */
.tip-kws{margin-top:0.625rem;border-top:1px solid rgba(255,255,255,.07);padding-top:0.5rem;
  display:flex;flex-direction:column;gap:0.375rem}
.tip-kw{font-size:0.7188rem;line-height:1.42;color:var(--ink-faint);
  padding-left:0.5rem;border-left:2px solid color-mix(in srgb, var(--rar-col) 30%, transparent)}
.tip-kw b{color:var(--gold);font-weight:600;font-family:var(--font-display);
  font-size:0.75rem;letter-spacing:.02em;margin-right:0.3125rem}

/* dev-tool links on the title screen — intentionally quiet chrome, not a
   player-facing menu item. Sits under the buttons and stays out of the way. */
.dev-links{display:flex;gap:0.6875rem;align-items:center;justify-content:center;margin:1.625rem auto 0;
  font-size:0.6875rem;letter-spacing:.08em;text-transform:uppercase;width:fit-content;
  /* the title art behind this is bright and busy — it needs its own plate to stay readable */
  background:rgba(8,10,16,.62);border:1px solid rgba(231,198,106,.16);border-radius:6.1875rem;
  padding:0.375rem 0.9375rem;backdrop-filter:blur(0.1875rem);opacity:.72;transition:opacity .2s,border-color .2s}
.dev-links:hover{opacity:1;border-color:rgba(231,198,106,.4)}
.dev-links span{color:#8b7f63;font-size:0.5938rem;letter-spacing:.18em}
.dev-links a{color:#c9bfa6;text-decoration:none;padding-bottom:1px;border-bottom:1px dotted rgba(201,191,166,.4)}
.dev-links a:hover{color:var(--gold);border-bottom-color:var(--gold)}

/* toast */
#toast-layer{position:absolute;top:4.375rem;left:50%;transform:translateX(-50%);z-index:400;display:flex;flex-direction:column;gap:0.5rem;align-items:center;pointer-events:none}
.toast{background:rgba(10,12,20,.92);border:1px solid var(--gold-deep);border-radius:0.625rem;padding:0.625rem 1.125rem;
  font-family:var(--font-display);font-size:0.9375rem;color:var(--gold);box-shadow:var(--shadow-2);animation:toastIn .3s}
@keyframes toastIn{from{opacity:0;transform:translateY(-0.625rem)}}

/* drag ghost target line */
#drag-layer{position:absolute;inset:0;pointer-events:none;z-index:900}
.target-arrow{position:absolute;inset:0;pointer-events:none}

/* generic reveal */
.rise{animation:rise .4s ease both}
@keyframes rise{from{opacity:0;transform:translateY(1rem)}}
.fadein{animation:fade .4s ease both}

/* victory / defeat banners */
.bigbanner{position:absolute;inset:0;display:grid;place-items:center;z-index:300;background:rgba(2,2,6,.8);animation:fade .4s}
.bigbanner .bb{text-align:center}
.bigbanner h1{font-size:5rem;font-weight:800;letter-spacing:.06em}
.bigbanner.win h1{background:linear-gradient(180deg,#fbeec0,#e7c66a,#9c7626);-webkit-background-clip:text;background-clip:text;color:transparent}
.bigbanner.lose h1{color:#c94a51;filter:drop-shadow(0 0 1.875rem rgba(201,74,81,.4))}
.bigbanner.phase{background:rgba(2,2,6,.55);pointer-events:none}
.bigbanner.phase h1{font-size:3.5rem;color:#c9a8ff;filter:drop-shadow(0 0 1.875rem rgba(185,140,255,.45))}
.bigbanner p{color:var(--ink-dim);margin-top:0.625rem;font-style:italic;font-family:var(--font-body)}

.empty-hint{color:var(--ink-faint);font-style:italic;text-align:center;padding:2.5rem}

/* small helpers */
.row{display:flex;align-items:center;gap:0.625rem}
.wrap{flex-wrap:wrap}
.spacer{flex:1}
.center{display:grid;place-items:center}
.muted{color:var(--ink-faint)}
.gold{color:var(--gold)}
.hidden{display:none!important}

/* ============================================================
   ADDITIONS: settings, timer, pile-row, combat topbar, search, history
   ============================================================ */
/* gear / icon buttons in bars */
.icon-btn{width:2.375rem;height:2.375rem;border-radius:0.5625rem;display:grid;place-items:center;flex:0 0 auto;
  background:linear-gradient(180deg,var(--panel-2),var(--panel));border:1px solid var(--line);
  color:var(--ink-dim);font-size:1.125rem;cursor:pointer;transition:.15s}
.icon-btn:hover{border-color:var(--gold-deep);color:var(--gold);transform:translateY(-1px)}

/* run timer stat */
.stat .run-timer{font-variant-numeric:tabular-nums;letter-spacing:.02em}
.stat.timer{color:var(--ink)}
.stat.timer .ic{color:var(--gold)}

/* combat topbar overlay (slim) */
/* combat top bar sits in grid row 1 (see .combat-topbar above) */

/* card count badge (starter deck / shop) */
.card-wrap{position:relative;display:inline-block}
.count-badge{position:absolute;top:-0.5625rem;right:-0.5625rem;min-width:1.75rem;height:1.75rem;padding:0 0.4375rem;border-radius:0.9375rem;z-index:8;
  background:linear-gradient(180deg,#f2dc94,#c39a3f);color:#241706;font-family:var(--font-display);font-weight:700;font-size:0.9375rem;
  display:flex;align-items:center;justify-content:center;box-shadow:var(--shadow-1),0 0 0 2px rgba(0,0,0,.5)}

/* compendium */
.comp-tabs{display:flex;flex-wrap:wrap;gap:0.5rem;justify-content:center;margin-bottom:0.75rem}
.comp-tabs .btn.active{background:linear-gradient(180deg,#f0d78a,#c39a3f);color:#20160a;border-color:#e7c66a}

/* compendium header — ONE opaque sticky panel (tabs + controls); content
   scrolling beneath can never bleed through */
.comp-head{position:sticky;top:0;z-index:14;margin:0 0 0.875rem;
  background:linear-gradient(180deg,#221a10 0%,#1b140c 100%);
  border:1px solid rgba(231,198,106,.16);border-radius:0.875rem;
  padding:0.625rem 0.75rem 0.6875rem;box-shadow:0 0.625rem 1.5rem rgba(0,0,0,.5), inset 0 1px 0 rgba(231,198,106,.08)}
.sec-tabs{display:flex;flex-wrap:wrap;gap:0.625rem;justify-content:center}
.comp-slot:not(:empty){margin-top:0.625rem;padding-top:0.625rem;border-top:1px solid rgba(231,198,106,.12)}
.comp-controls{display:flex;flex-wrap:wrap;gap:0.5rem;justify-content:center;align-items:center}
.search-wrap{position:relative;margin-left:0.625rem;display:inline-flex;align-items:center}
.search-wrap .search-ic{position:absolute;left:0.75rem;width:0.875rem;height:0.875rem;color:var(--ink-faint);pointer-events:none}
.comp-input{font-family:var(--font-body);font-size:0.8125rem;color:var(--ink);background:rgba(0,0,0,.35);
  border:1px solid var(--line);border-radius:1.25rem;padding:0.375rem 0.875rem 0.375rem 2rem;width:11.875rem;outline:none;transition:border-color .15s}
.comp-input:focus{border-color:var(--gold-deep);box-shadow:0 0 0 2px var(--gold-glow)}
.comp-controls .comp-count{margin-left:0.625rem;color:var(--ink-faint);font-size:0.75rem;white-space:nowrap;
  width:4.625rem;text-align:left;flex:0 0 auto}
/* rarity group headers span the full card grid; cards lift on hover */
.comp-cardgrid .cx-sechead{grid-column:1/-1;margin:0.625rem 2px 2px}
.comp-cardgrid .card{transition:transform .18s cubic-bezier(.2,.8,.3,1.1)}
.comp-cardgrid .card:hover{transform:translateY(-0.375rem) scale(1.04);z-index:5}
.sec-tab{display:flex;align-items:center;gap:0.5rem;padding:0.5625rem 1.125rem;border-radius:1.5rem;cursor:pointer;
  font-family:var(--font-display);font-size:0.875rem;letter-spacing:.03em;color:var(--ink-dim);
  background:linear-gradient(180deg,#1f1810,#130e08);border:1px solid #5a4520;transition:.15s}
.sec-tab i{font-style:normal;font-size:0.9375rem;color:var(--gold);opacity:.65;transition:.15s}
.sec-tab em{font-style:normal;font-family:var(--font-body);font-size:0.6875rem;color:var(--ink-faint);
  background:rgba(0,0,0,.4);border:1px solid rgba(255,255,255,.07);border-radius:0.75rem;padding:1px 0.5rem}
.sec-tab:hover{border-color:#8a6a2a;color:var(--ink);transform:translateY(-1px)}
.sec-tab.active{background:linear-gradient(180deg,#8a6528,#4a3418);color:#ffe9b0;border-color:#b8933a;
  box-shadow:inset 0 1px 0 rgba(255,225,150,.4), 0 0 1rem var(--gold-glow)}
.sec-tab.active i{color:#ffe9b0;opacity:1}
.sec-tab.active em{color:#ffe9b0;border-color:rgba(255,233,176,.3);background:rgba(0,0,0,.25)}

/* class filter pills tinted per class, with champion portrait faces */
.cls-pill{display:inline-flex;align-items:center;gap:0.4375rem;font-family:var(--font-body);font-size:0.7813rem;
  padding:0.25rem 0.875rem 0.25rem 0.3125rem;border-radius:1.25rem;cursor:pointer;
  background:rgba(255,255,255,.04);border:1px solid var(--line);color:var(--ink-dim);transition:.15s}
.cls-pill:hover{border-color:var(--cc,#e7c66a);color:var(--cc,#e7c66a)}
.cls-pill.on{background:color-mix(in srgb, var(--cc,#e7c66a) 15%, transparent);
  border-color:var(--cc,#e7c66a);color:var(--cc,#e7c66a)}
.cls-pill .pill-face{width:1.625rem;height:1.625rem;border-radius:50%;overflow:hidden;flex:0 0 auto;
  border:1.5px solid color-mix(in srgb, var(--cc,#e7c66a) 65%, transparent);background:#0c0a12}
.cls-pill .pill-face svg{width:100%;height:100%;display:block;transform:scale(1.25);transform-origin:50% 30%}
.cls-pill .pill-glyph{display:grid;place-items:center;font-size:0.75rem;color:var(--cc,#e7c66a);
  background:color-mix(in srgb, var(--cc,#e7c66a) 12%, #0c0a12)}

/* grouped codex sections */
.codex-scroll{max-height:64vh;overflow:auto;padding:0.25rem}
.modal.fullscreen .codex-scroll{max-height:none;flex:1;min-height:0}
.cx-sechead{font-family:var(--font-display);font-size:0.8125rem;letter-spacing:.14em;text-transform:uppercase;
  color:var(--sc,var(--gold));margin:1rem 2px 0.5625rem;display:flex;align-items:center;gap:0.625rem}
.cx-sechead:first-child{margin-top:2px}
.cx-sechead::after{content:'';flex:1;height:1px;
  background:linear-gradient(90deg, color-mix(in srgb, var(--sc,#e7c66a) 40%, transparent), transparent)}
.codex-grid.nogroup{max-height:none;overflow:visible;padding:0}

/* foe tiles — grouped by act, tier-badged */
.foe-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(12.5rem,100%),1fr));gap:0.75rem;margin-bottom:0.5rem}
.foe-card{position:relative;display:flex;flex-direction:column;align-items:center;padding:0.875rem 0.75rem 0.75rem;border-radius:0.75rem;
  border:1px solid var(--line);background:linear-gradient(180deg,rgba(255,255,255,.03),rgba(0,0,0,.2));transition:.15s}
.foe-card:hover{transform:translateY(-0.1875rem);border-color:#8a6a2a}
.foe-card .foe-art{width:6.875rem;height:6.875rem}
/* Ten enemies use painted PNGs instead of the procedural rig (Art.enemy returns
   an <img class="raster-sprite">). Only the battlefield sized those, so in the
   compendium they rendered at the file's natural size — ~500x650 in a 6.875rem
   slot. Every place that draws an enemy must size BOTH shapes. */
.foe-card .foe-art svg,.foe-card .foe-art img{width:100%;height:100%;object-fit:contain;object-position:center bottom}
.foe-card .foe-info{text-align:center;margin-top:0.375rem}
.foe-card .foe-info b{font-family:var(--font-display);font-size:0.875rem;display:block;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:11.25rem}
.foe-card .foe-hp{color:#ff9a9a;font-size:0.75rem;margin-top:2px}
.foe-card .foe-tier{position:absolute;top:0.5rem;right:0.5rem;font-family:var(--font-display);font-size:0.625rem;
  letter-spacing:.1em;text-transform:uppercase;color:var(--tc,#9aa4b2);border-radius:0.75rem;padding:2px 0.5rem;
  border:1px solid color-mix(in srgb, var(--tc,#9aa4b2) 55%, transparent);background:rgba(0,0,0,.45)}
.foe-card.t-elite{border-color:#5e5030}
.foe-card.t-boss{border-color:#7d2e32}
.comp-search{display:flex;gap:0.625rem;justify-content:center;align-items:center;margin-bottom:0.875rem;flex-wrap:wrap}
.comp-search input{font-family:var(--font-body);font-size:0.875rem;color:var(--ink);background:rgba(0,0,0,.35);
  border:1px solid var(--line);border-radius:0.5625rem;padding:0.5625rem 0.875rem;width:min(26.25rem,60vw);outline:none}
.comp-search input:focus{border-color:var(--gold-deep);box-shadow:0 0 0 2px var(--gold-glow)}
.comp-search .filter-pill{font-family:var(--font-body);font-size:0.75rem;padding:0.375rem 0.75rem;border-radius:1.25rem;
  background:rgba(255,255,255,.04);border:1px solid var(--line);color:var(--ink-dim);cursor:pointer;transition:.12s}
.comp-search .filter-pill.on{background:rgba(231,198,106,.16);border-color:var(--gold-deep);color:var(--gold)}
.comp-count{text-align:center;color:var(--ink-faint);font-size:0.75rem;margin-bottom:0.625rem}
.comp-empty{text-align:center;color:var(--ink-faint);font-style:italic;padding:3.125rem}

/* codex rows for relics/potions/foes */
/* min(...,100%) keeps every grid narrower than its container: on a screen too
   narrow for the ideal column the tiles shrink and wrap into MORE ROWS — the
   compendium never scrolls horizontally */
.codex-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(16.25rem,100%),1fr));gap:0.75rem;max-height:64vh;overflow:auto;padding:0.25rem}
.codex-row{display:flex;gap:0.75rem;align-items:center;padding:0.6875rem 0.8125rem;border:1px solid var(--line);border-radius:0.6875rem;background:rgba(255,255,255,.02)}
.codex-row .cx-icon{width:3.25rem;height:3.25rem;border-radius:0.5625rem;overflow:hidden;flex:0 0 auto;border:1px solid var(--line)}
.codex-row .cx-icon svg{width:100%;height:100%}
.codex-row .cx-icon img.foe3d{width:100%;height:100%;object-fit:contain;image-rendering:pixelated;display:block}
.codex-row .cx-body b{font-family:var(--font-display);font-size:0.875rem}
.codex-row .cx-body .cx-tag{font-size:0.625rem;text-transform:uppercase;letter-spacing:.1em;color:var(--gold);margin-left:0.375rem}
.codex-row .cx-body div{color:var(--ink-dim);font-size:0.75rem;line-height:1.4;margin-top:0.1875rem}

/* run history */
.history-list{display:flex;flex-direction:column;gap:0.5rem;min-width:min(35rem,80vw);max-height:64vh;overflow:auto}
.history-row{display:flex;align-items:center;gap:0.875rem;padding:0.6875rem 0.9375rem;border:1px solid var(--line);border-radius:0.6875rem;background:rgba(255,255,255,.02)}
.history-row .h-icon{width:2.625rem;height:2.625rem;border-radius:0.5625rem;overflow:hidden;flex:0 0 auto;border:1px solid var(--line)}
.history-row .h-body{flex:1}
.history-row .h-body b{font-family:var(--font-display);font-size:0.9375rem}
.history-row .h-body .h-sub{color:var(--ink-dim);font-size:0.75rem;margin-top:2px}
.history-row .h-out{font-family:var(--font-display);font-size:0.8125rem;padding:0.25rem 0.75rem;border-radius:1.25rem;letter-spacing:.05em}
.history-row .h-out.win{color:#7fe6a0;background:rgba(63,185,132,.12);border:1px solid #2f6b4d}
.history-row .h-out.lose{color:#f2999d;background:rgba(200,74,80,.12);border:1px solid #7d2e32}
.history-empty{text-align:center;color:var(--ink-faint);font-style:italic;padding:2.5rem}
.history-row .h-score{font-family:var(--font-display);color:var(--ink-dim);font-size:0.6875rem;letter-spacing:.06em;white-space:nowrap}
.history-row .h-score span{color:var(--gold);font-size:1rem;margin-right:0.1875rem}

/* run summary detail */
.run-detail{min-width:min(47.5rem,86vw);max-height:70vh;overflow-y:auto;padding-right:0.375rem}
.rd-banner{position:relative;display:flex;flex-direction:column;gap:0.25rem;padding:1rem 1.25rem;border-radius:0.75rem;border:1px solid var(--line);margin-bottom:0.875rem}
.rd-banner.win{background:linear-gradient(160deg,rgba(63,185,132,.14),rgba(63,185,132,.03));border-color:#2f6b4d}
.rd-banner.lose{background:linear-gradient(160deg,rgba(200,74,80,.14),rgba(200,74,80,.03));border-color:#7d2e32}
.rd-outcome{font-family:var(--font-display);font-size:1.25rem;letter-spacing:.08em}
.rd-banner.win .rd-outcome{color:#7fe6a0}
.rd-banner.lose .rd-outcome{color:#f2999d}
.rd-prog{color:var(--ink-dim);font-size:0.75rem}
.rd-score{position:absolute;right:1.25rem;top:50%;transform:translateY(-50%);text-align:center}
.rd-score b{display:block;font-family:var(--font-display);font-size:1.875rem;color:var(--gold);line-height:1}
.rd-score span{font-size:0.625rem;text-transform:uppercase;letter-spacing:.14em;color:var(--ink-faint)}
.rd-stats{display:grid;grid-template-columns:repeat(auto-fill,minmax(8rem,1fr));gap:0.5rem;margin-bottom:1rem}
.rd-stat{border:1px solid var(--line);border-radius:0.625rem;padding:0.625rem 0.75rem;background:rgba(255,255,255,.02);text-align:center}
.rd-stat b{display:block;font-family:var(--font-display);font-size:1.1875rem;color:var(--ink)}
.rd-stat span{font-size:0.625rem;text-transform:uppercase;letter-spacing:.1em;color:var(--ink-faint)}
.rd-sec{font-family:var(--font-display);font-size:0.8125rem;letter-spacing:.1em;text-transform:uppercase;color:var(--gold);margin:0.875rem 0 0.5rem;border-bottom:1px solid var(--line);padding-bottom:0.3125rem}
/* the run chronicle shows artifacts the way combat does — chrome-free emblems
   floating in a tray, named on hover, rather than bordered name-chips */
.rd-relic-tray{gap:0.625rem;margin:2px 0 0.375rem}
.rd-relic-tray .relic{width:2.625rem;height:2.625rem;border:none;background:transparent;border-radius:0;
  cursor:pointer;filter:drop-shadow(0 2px 0.25rem rgba(0,0,0,.85))}
.rd-relic-tray .relic:hover{transform:translateY(-0.1875rem) scale(1.08);border-color:transparent;
  box-shadow:none;filter:drop-shadow(0 0 0.625rem var(--gold-glow)) drop-shadow(0 2px 0.25rem rgba(0,0,0,.8))}
.rd-relic-tray .relic svg{width:100%;height:100%;display:block}
.rd-deck{grid-template-columns:repeat(auto-fill,minmax(8rem,1fr));gap:0.625rem}
.store-tag{position:fixed;bottom:0.5rem;right:0.625rem;font-size:0.625rem;color:var(--ink-faint);font-family:var(--font-body);z-index:2;opacity:.6}

/* settings menu — cohesive list of rows */
.settings-menu{display:flex;flex-direction:column;gap:0.5rem;min-width:22.5rem;margin-top:0.25rem}
.settings-item{display:flex;align-items:center;gap:0.875rem;width:100%;text-align:left;padding:0.6875rem 0.875rem;border-radius:0.75rem;
  background:linear-gradient(180deg,rgba(255,255,255,.035),rgba(255,255,255,.012));
  border:1px solid var(--line);color:var(--ink);cursor:pointer;font-family:var(--font-body);
  transition:border-color .15s,background .15s,transform .15s}
.settings-item:hover{border-color:var(--gold-deep);background:rgba(231,198,106,.06);transform:translateX(2px)}
.settings-item .si-icon{width:2.375rem;height:2.375rem;border-radius:0.625rem;display:grid;place-items:center;font-size:1rem;flex:0 0 auto;
  background:rgba(0,0,0,.32);border:1px solid var(--line);color:var(--ink-dim)}
.settings-item .si-text{flex:1;display:flex;flex-direction:column;gap:2px;min-width:0}
.settings-item .si-text b{font-family:var(--font-display);font-size:0.9375rem;font-weight:600;letter-spacing:.02em;color:var(--ink)}
.settings-item .si-sub{font-size:0.75rem;color:var(--ink-faint);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.settings-item .si-arrow{color:var(--ink-faint);font-size:1.375rem;line-height:1;transition:color .15s,transform .15s}
.settings-item:hover .si-arrow{color:var(--gold);transform:translateX(0.1875rem)}
/* primary (Resume) — softly highlighted, not a loud gold fill */
.settings-item.primary{border-color:var(--gold-deep)}
.settings-item.primary .si-icon{background:linear-gradient(180deg,#f0d78a,#c39a3f);color:#20160a;border-color:#e7c66a}
/* destructive (Abandon) — neutral until hovered */
.settings-item.danger:hover{border-color:var(--crimson);background:rgba(216,72,79,.08)}
.settings-item.danger:hover .si-icon{color:var(--crimson);border-color:var(--crimson)}
.settings-item.danger:hover .si-arrow{color:var(--crimson)}

/* fullscreen modals + corner X (refinement #7) */
.modal{position:relative}
.modal.fullscreen{width:96vw;height:94vh;max-width:none;max-height:none;display:flex;flex-direction:column}
.modal.fullscreen > h2{margin-top:2px}
.modal.fullscreen .deck-grid,.modal.fullscreen .codex-grid{max-height:none;flex:1;min-height:0}
.modal-x{position:absolute;top:0.75rem;right:0.875rem;width:2.375rem;height:2.375rem;border-radius:0.5625rem;z-index:10;
  display:grid;place-items:center;font-size:1.625rem;line-height:1;color:var(--ink-dim);
  background:rgba(255,255,255,.04);border:1px solid var(--line);cursor:pointer;transition:.15s;font-family:var(--font-body)}
.modal-x:hover{color:var(--crimson);border-color:var(--crimson);background:rgba(216,72,79,.12)}

/* live card values (refinement: buffed = green, reduced = amber) */
.card .ctext .dmg.up,.card .ctext .blk.up{color:#7fe6a0}
.card .ctext .dmg.down,.card .ctext .blk.down{color:#e0894a}
/* what a scaling attack (Last Rites, Railgun…) is adding right now, printed
   next to its base so the card reads "6 (+9)" rather than a bare total */
.card .ctext .scale-bonus{font-size:.92em}

/* drag preview badge on enemies */
.dmg-preview{position:absolute;top:-2.875rem;left:50%;transform:translateX(-50%);z-index:30;
  display:flex;flex-direction:column;align-items:center;gap:2px;pointer-events:none;
  background:rgba(8,9,16,.9);border:1px solid var(--crimson-deep);border-radius:0.625rem;padding:0.3125rem 0.625rem;
  box-shadow:0 0.25rem 0.875rem rgba(0,0,0,.5)}
.dmg-preview .dp-num{font-family:var(--font-display);font-weight:800;font-size:1.375rem;color:#ff6b6b;line-height:1;text-shadow:0 1px 0.1875rem #000}
.dmg-preview .dp-hp{font-family:var(--font-body);font-size:0.6875rem;color:var(--ink-dim);white-space:nowrap}
.dmg-preview .dp-tag{font-family:var(--font-body);font-size:0.625rem;color:#d0b0ff;background:rgba(168,116,232,.14);
  border:1px solid #6a3d8f;border-radius:0.5rem;padding:0 0.375rem;white-space:nowrap}

/* scry: cards marked for discard */
.card.scry-discard{filter:grayscale(.55) brightness(.6)}
.card.scry-discard .card-inner{box-shadow:var(--shadow-2),inset 0 0 0 1px #000,inset 0 0 0 0.25rem var(--crimson-deep),inset 0 0 0 0.3125rem rgba(0,0,0,.6)}
.card.scry-discard::after{content:'DISCARD';position:absolute;top:50%;left:50%;transform:translate(-50%,-50%) rotate(-12deg);
  z-index:9;font-family:var(--font-display);font-weight:700;font-size:0.9375rem;letter-spacing:.1em;color:#fff;
  background:rgba(160,30,36,.9);border:1px solid var(--crimson);border-radius:0.375rem;padding:0.1875rem 0.625rem;pointer-events:none}

/* log hover card preview */
.card.log-card-preview{box-shadow:0 1.125rem 3.75rem rgba(0,0,0,.75);animation:fade .12s ease}

/* right-aligned fullscreen modal footer (e.g. merchant Continue) */
.modal.fullscreen .modal-foot{margin-top:auto;padding-top:0.875rem}

/* relic rarity coloring in codex — palette lives in the :root block up top */
.codex-row.rar-common .cx-tag{color:var(--r-common)}
.codex-row.rar-uncommon .cx-tag{color:var(--r-uncommon)}
.codex-row.rar-rare .cx-tag{color:var(--r-rare)}
.codex-row.rar-legendary .cx-tag{color:var(--r-legendary)}
.codex-row.rar-starter .cx-tag{color:var(--r-starter)}

/* relic entries in the compendium: borderless, transparent — rarity is shown
   purely by the name's color (white=starter, grey=common, blue=uncommon,
   purple=rare, orange=legendary). Names stay on a single row. */
.codex-row.relic-row{border-color:transparent!important;background:transparent!important;box-shadow:none!important;padding:0.5rem 0.625rem}
.codex-row.relic-row .cx-icon{border-color:transparent;background:transparent}
.codex-row.relic-row .cx-body{min-width:0}
.codex-row.relic-row .cx-body b{display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.codex-row.relic-row.rar-starter   .cx-body b{color:var(--r-starter)}
.codex-row.relic-row.rar-common    .cx-body b{color:var(--r-common)}
.codex-row.relic-row.rar-uncommon  .cx-body b{color:var(--r-uncommon)}
.codex-row.relic-row.rar-rare      .cx-body b{color:var(--r-rare)}
.codex-row.relic-row.rar-legendary .cx-body b{color:var(--r-legendary)}

/* ============================================================
   CUSTOM GAME CURSOR
   ============================================================ */
:root{
  --cur: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='28' height='28'><path d='M4 2 L4 22 L9.5 17.5 L13 25 L16.5 23.4 L13 16 L20 16 Z' fill='%23e7c66a' stroke='%231a1206' stroke-width='1.5' stroke-linejoin='round'/></svg>") 4 2;
  --cur-active: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='28' height='28'><path d='M4 2 L4 22 L9.5 17.5 L13 25 L16.5 23.4 L13 16 L20 16 Z' fill='%23fff2c8' stroke='%235c3a10' stroke-width='1.5' stroke-linejoin='round'/></svg>") 4 2;
}
html,body,#app{cursor:var(--cur), auto}
button,.btn,.card,.pack,.char-card,.reward-row,.pile,.icon-btn,.relic,.potion-slot,.settings-item,
.codex-row,.modal-x,.history-row,.map-node.reachable,.comp-tabs .btn,.comp-search .filter-pill,
input,select,a,.intent,.pip{cursor:var(--cur-active), pointer}
.entity.targetable{cursor:var(--cur-active), crosshair}

/* fullscreen modal: scrollable body so header X + footer Continue are always reachable */
.modal.fullscreen{padding:1.25rem 1.625rem}
.modal.fullscreen > h2{flex:0 0 auto}
.modal.fullscreen > .msub{flex:0 0 auto}
.modal.fullscreen .modal-scroll{flex:1 1 auto;min-height:0;overflow:auto;padding-right:0.25rem}
.modal.fullscreen .modal-foot{flex:0 0 auto;margin-top:0.875rem;padding-top:0.75rem;border-top:1px solid var(--line-soft)}
.modal-x{z-index:30}

/* ============================================================
   ORNATE AESTHETIC RESKIN — carved bronze frames, parchment
   combat log, flaming energy orb, torch-lit dungeon atmosphere.
   ============================================================ */
:root{
  --bronze-lo:#3a2c16; --bronze:#7a5a2c; --bronze-hi:#c99a4e; --bronze-edge:#e7c66a;
  --parch-0:#efe0bd; --parch-1:#e3cf9e; --parch-2:#cbb075; --parch-ink:#3f2c14; --parch-line:#8a6a3a;
}
/* reusable carved bronze frame */
.tb-frame,.combat-topbar .topwrap,.endturn .btn,.pile .pile-icon,.energy-orb{
  --f:0;
}
/* --- top bar: carved bronze banner (all screens) --- */
.topwrap{
  background:
    linear-gradient(180deg,rgba(60,44,22,.6),rgba(24,18,10,.7)),
    linear-gradient(180deg,#241d13,#14100a) !important;
  border-bottom:none !important;
  box-shadow:0 0.1875rem 0 #0a0906, inset 0 1px 0 rgba(231,198,106,.28), inset 0 -0.1875rem 0.5rem rgba(0,0,0,.6);
  position:relative;
}
/* carved bronze rails top & bottom + faint repeating stud pattern */
.topwrap::before{content:"";position:absolute;left:0;right:0;top:0;height:2px;
  background:linear-gradient(90deg,transparent,var(--bronze-edge),transparent);opacity:.6}
.topwrap::after{content:"";position:absolute;left:0;right:0;bottom:0;height:0.1875rem;
  background:linear-gradient(90deg,transparent,var(--bronze-edge),var(--bronze-hi),var(--bronze-edge),transparent);opacity:.85}
.topbar{position:relative}
/* (the decorative corner flourishes were removed — they read as a stray icon) */
.topbar .tb-portrait{border:2px solid var(--bronze-hi);box-shadow:0 0 0 1px #0a0906,inset 0 0 0.5rem rgba(0,0,0,.6),0 0 0.625rem var(--gold-glow)}
.topbar .tb-name{color:var(--bronze-edge);text-shadow:0 1px 0.1875rem #000,0 0 0.625rem rgba(231,198,106,.3)}
.topbar .stat{background:linear-gradient(180deg,rgba(40,30,16,.7),rgba(16,12,7,.75));border:1px solid var(--bronze);
  box-shadow:inset 0 1px 0 rgba(231,198,106,.15)}
.hpbar{background:linear-gradient(180deg,#1c0a03,#341407);border:1px solid rgba(0,0,0,.8);
  box-shadow:inset 0 0.0625rem 0.1875rem rgba(0,0,0,.85),0 0 0 1px #6b3a18}
.hpbar > i{background:linear-gradient(180deg,#ff9d80 0%,#ff7a5a 34%,#c0392a 66%,#7a1e0c 100%)}
.icon-btn{background:radial-gradient(circle at 40% 35%,#3a2c16,#14100a);border:1px solid var(--bronze);
  box-shadow:inset 0 1px 0 rgba(231,198,106,.25),0 2px 0.25rem rgba(0,0,0,.5);color:var(--bronze-edge)}
.icon-btn:hover{border-color:var(--bronze-edge);color:#fff;box-shadow:inset 0 1px 0 rgba(231,198,106,.4),0 0 0.75rem var(--gold-glow)}

/* --- flaming energy orb --- */
.energy-orb svg{filter:drop-shadow(0 0 1.375rem rgba(255,140,60,.65)) !important}
.energy-orb .etext b{color:#fff6e0 !important;text-shadow:0 2px 0.375rem #4a0e00,0 0 0.875rem rgba(255,180,90,.9) !important}
.energy-orb .etext small{color:#ffd9a0 !important}

/* --- ornate End Turn button --- */
.endturn .btn.gold{
  background:linear-gradient(180deg,#8a6528 0%,#5a3f18 55%,#3a2810 100%) !important;
  color:#ffe9b0 !important;border:1px solid #2a1c0a !important;
  box-shadow:inset 0 1px 0 rgba(255,225,150,.45),inset 0 -0.1875rem 0.5rem rgba(0,0,0,.5),
    0 0 0 2px #b8933a, 0 0 1.375rem rgba(231,198,106,.35),0 0.375rem 0.875rem rgba(0,0,0,.55) !important;
  text-shadow:0 1px 2px #000;border-radius:0.5rem;letter-spacing:.06em}
.endturn .btn.gold:hover{box-shadow:inset 0 1px 0 rgba(255,225,150,.6),inset 0 -0.1875rem 0.5rem rgba(0,0,0,.4),
    0 0 0 2px var(--bronze-edge),0 0 1.875rem rgba(255,180,90,.5),0 0.375rem 0.875rem rgba(0,0,0,.55) !important;filter:brightness(1.06)}

/* --- ornate piles --- */
.pile .pile-icon{border:1px solid var(--bronze) !important;
  background:linear-gradient(160deg,#2a2114,#14100a) !important;
  box-shadow:inset 0 1px 0 rgba(231,198,106,.2),0 0.1875rem 0.375rem rgba(0,0,0,.5),0 0 0 1px #0a0906}
.pile .pile-count{color:var(--bronze-edge)}
.pile:hover .pile-icon{border-color:var(--bronze-edge) !important;box-shadow:inset 0 1px 0 rgba(231,198,106,.35),0 0 0.75rem var(--gold-glow)}

/* --- torch-lit dungeon arena --- */
.arena{
  background:
    radial-gradient(56% 50% at 10% 80%, rgba(255,130,50,.15), transparent 60%),
    radial-gradient(56% 50% at 90% 80%, rgba(255,130,50,.15), transparent 60%),
    radial-gradient(68.75rem 38.75rem at 50% -12%, #33243a 0%, transparent 62%),
    linear-gradient(180deg,#1b1324 0%,#0e0913 62%,#0a0709 100%) !important;
}
.arena::after{content:"";position:absolute;inset:0;pointer-events:none;
  background:radial-gradient(120% 90% at 50% 42%, transparent 52%, rgba(0,0,0,.55) 100%)}
/* the ground is part of the drawn scene (battleSceneMin) — no second floor */
.arena .floor{display:none !important}
.combat-bottom{background:
    linear-gradient(180deg,transparent,rgba(20,14,8,.55) 42%,rgba(14,10,6,.92)) !important;
  box-shadow:inset 0 0.1875rem 0 rgba(231,198,106,.10)}

/* --- ornate card frames --- */
.card .card-inner{box-shadow:var(--shadow-2),inset 0 0 0 1px #000,inset 0 0 0 2px rgba(120,90,40,.5),
    inset 0 0 0 0.1875rem rgba(0,0,0,.5) !important}
/* ...but NOT under a painted border. The rings above are the engraved vector
   frame's bedding — a black rule, a bronze rule and a black rule, inset from
   the card edge. A card whose frame is a painted PNG (art/borders/<cls>.png)
   draws its own outer rule on top of them, so both were visible at once and the
   card read as double-framed: the new border with the old one showing behind.
   The painted art IS the frame, so the bedding comes off. Same for the art
   window's ring — the painting already draws that edge; its vignette gradient
   stays, since that is shading, not a frame. */
/* The plate is shaped to the PAINTED ART, not to the vector frame's box.
   Measured off art/borders/*.png (527x746): a transparent margin of 7-8px on
   the left, right and top — 1.1-1.5% of the image — and NONE at the bottom,
   where the frame runs flush to the edge; top corners rounded (~6.4% of the
   width), bottom corners square. The plate used to be a uniform 0.9375rem
   rounded rect at full card size, so it stood proud of the painted frame on
   every side and its own black rule read as a second border showing through.
   Inset to the art's margin and shaped to its corners, it now sits entirely
   behind the painting, and no ring is drawn at all — the paint IS the frame. */
.card.raster-framed .card-inner{
  inset:0.2rem 0.2rem 0 0.2rem;
  border-radius:0.65rem 0.65rem 0 0;
  box-shadow:var(--shadow-2) !important}
.card.raster-framed .art .art-frame{
  box-shadow:inset 0 1px 0 rgba(255,255,255,.06), inset 0 0 1rem rgba(0,0,0,.4)}
/* the border image is a sibling of the plate now (see cards.js), so it owns the
   full card box and nothing clips its square bottom corners */
.card.raster-framed > .frame-etch.raster-border{position:absolute;inset:0;z-index:6;pointer-events:none}
/* FULL-BLEED ART (2026-08-04, user directive): the illustration runs to the
   card's very edge and the painted frame OVERLAYS it — the border band and its
   top-centre ornament sit on the picture. No mat/padding between art and
   frame; card-inner's rounded clip shapes the corners. Bottom edge unchanged
   (the banner still covers the seam). */
.card.raster-framed .art{left:0;right:0;top:0;height:9.75rem;border-radius:0}
.card.raster-framed.mini .art{left:0;right:0;top:0;height:6.8125rem}
/* titles sit on the cream banner now — dark ink with a light emboss, never
   the old gold-on-dark treatment */
.card .cname{color:#241a0c !important;text-shadow:0 1px 0 rgba(255,255,255,.4) !important}
/* ...but an upgraded card must never be mistakable for its base version: this
   reskin's !important was silently eating the green tint set back at .card.upgraded,
   leaving a 0.375rem '+' as the only difference between "Gain 5 Block" and "Gain 8 Block". */
.card.upgraded .cname{color:#1d6e3c !important;text-shadow:0 1px 0 rgba(255,255,255,.35) !important}

/* ============================================================
   ORNATE RESKIN — extended to buttons, modals, map, menu
   ============================================================ */
/* generic ornate bronze buttons (game-wide) */
.btn{background:linear-gradient(180deg,#2a2114,#171009) !important;border:1px solid var(--bronze) !important;
  color:#e9d9b0 !important;box-shadow:inset 0 1px 0 rgba(231,198,106,.22),0 2px 0.3125rem rgba(0,0,0,.5) !important;
  border-radius:0.5625rem;letter-spacing:.03em}
.btn:hover{border-color:var(--bronze-edge) !important;color:#fff6e0 !important;
  box-shadow:inset 0 1px 0 rgba(231,198,106,.38),0 0 0.875rem var(--gold-glow),0 2px 0.3125rem rgba(0,0,0,.5) !important;transform:translateY(-1px)}
.btn.active{background:linear-gradient(180deg,#6a4d22,#3a2810) !important;border-color:var(--bronze-edge) !important;color:#ffe9b0 !important}
.btn.gold,.btn.big.gold{background:linear-gradient(180deg,#8a6528,#5a3f18 55%,#3a2810) !important;color:#ffe9b0 !important;
  box-shadow:inset 0 1px 0 rgba(255,225,150,.45),0 0 0 2px #b8933a,0 0 1.25rem rgba(231,198,106,.3),0 0.25rem 0.625rem rgba(0,0,0,.5) !important;border-color:#2a1c0a !important}
.btn.ghost{background:rgba(30,22,12,.5) !important;border-color:var(--bronze-lo) !important}

/* modals → dark panel in a carved bronze frame */
.modal{background:
    radial-gradient(120% 80% at 50% 0%, rgba(60,44,22,.4), transparent 60%),
    linear-gradient(180deg,#1a150e,#100c07) !important;
  border:none !important;
  box-shadow:0 0 0 2px var(--bronze),0 0 0 0.25rem #0a0906, inset 0 1px 0 rgba(231,198,106,.2),
    0 1.5rem 4.375rem rgba(0,0,0,.7) !important;border-radius:0.5rem;position:relative}
.modal::before{content:"";position:absolute;inset:0.375rem;border:1px solid rgba(120,90,40,.35);border-radius:0.25rem;pointer-events:none}
.modal h2{color:var(--bronze-edge) !important;text-shadow:0 2px 0.25rem #000,0 0 0.75rem rgba(231,198,106,.25)}
.modal .msub,.modal .msub *{color:#c9b487 !important}
/* the victory ledger — every point of the ascent, itemized */
.score-sheet{max-width:23.75rem;margin:1rem auto 0.25rem;padding:0.75rem 1.125rem;border-radius:0.75rem;
  background:linear-gradient(180deg,rgba(30,26,44,.8),rgba(16,14,26,.85));
  border:1px solid rgba(220,180,110,.25);text-align:left}
.ss-row{display:flex;justify-content:space-between;gap:1rem;padding:0.1875rem 0;
  font-size:0.8438rem;color:var(--ink-dim)}
.ss-row .ss-pts{font-family:var(--font-display);color:#d9d2e8;font-weight:600}
.ss-mult{border-top:1px dashed rgba(220,180,110,.25);margin-top:0.25rem;padding-top:0.4375rem}
.ss-mult .ss-pts{color:#c9a0ef}
.ss-total{border-top:1px solid rgba(220,180,110,.4);margin-top:0.375rem;padding-top:0.5rem;font-size:0.9375rem}
.ss-total .ss-label{color:var(--gold);font-family:var(--font-display);letter-spacing:.06em}
.ss-total .ss-pts{color:var(--gold);font-size:1.1875rem}
.ss-best{text-align:center;margin-top:0.5rem;color:#f5d78a;font-size:0.7813rem;letter-spacing:.08em;
  font-family:var(--font-display)}

/* class-locked event options wear their champion's tag */
.reward-row .ev-cls{margin-top:0.1875rem;font-family:var(--font-display);font-size:0.625rem;
  letter-spacing:.12em;text-transform:uppercase;color:var(--gold)}
/* event results card: the choice made, then what came of it */
.ev-outcome .ev-choice{font-family:var(--font-display);font-size:0.6875rem;letter-spacing:.14em;
  text-transform:uppercase;color:var(--gold);margin-bottom:0.5rem}
.ev-outcome .ev-result{font-size:1rem;line-height:1.6;color:var(--ink);margin:0 0 0.25rem}
.reward-row,.history-row,.codex-row,.settings-item,.pack,.char-card,.map-legend{
  border:1px solid var(--bronze-lo) !important;
  background:linear-gradient(180deg,rgba(40,30,16,.5),rgba(16,12,7,.6)) !important}
.reward-row:hover,.settings-item:hover,.pack:hover,.char-card:hover{border-color:var(--bronze) !important;
  box-shadow:0 0 0.875rem var(--gold-glow) !important}
.comp-tabs .btn.active{background:linear-gradient(180deg,#8a6528,#4a3418) !important}
.modal-x{background:radial-gradient(circle at 40% 35%,#3a2c16,#14100a) !important;border:1px solid var(--bronze) !important;color:var(--bronze-edge) !important;transition:.15s}
.modal-x:hover{background:radial-gradient(circle at 40% 35%,#5a4322,#241a0c) !important;border-color:#ffd98a !important;color:#fff0c0 !important;
  box-shadow:0 0 0.875rem var(--gold-glow);transform:scale(1.08)}

/* map: bronze act banner + legend + reachable node rings */
.map-actbanner{background:linear-gradient(180deg,rgba(40,30,16,.85),rgba(16,12,7,.9)) !important;
  border:1px solid var(--bronze) !important;box-shadow:inset 0 1px 0 rgba(231,198,106,.25),0 0.25rem 0.875rem rgba(0,0,0,.6) !important;border-radius:0.5rem}
.map-actbanner .mab-act,.map-actbanner .mab-name{color:var(--bronze-edge) !important;text-shadow:0 1px 0.1875rem #000}
.map-legend{border-radius:0.5rem;box-shadow:inset 0 1px 0 rgba(231,198,106,.2),0 0.25rem 0.875rem rgba(0,0,0,.6) !important}
.map-legend .ml-title{color:var(--bronze-edge) !important}
.map-node.reachable{border-color:var(--bronze-edge) !important;
  box-shadow:0 0.25rem 1rem rgba(0,0,0,.6),inset 0 0 0.75rem rgba(0,0,0,.5),0 0 1.375rem rgba(231,198,106,.4),0 0 0 0.1875rem rgba(200,154,78,.25) !important}
.map-node.current{border-color:#fff !important;box-shadow:0 0 0 0.1875rem var(--bronze-edge),0 0 1.5rem rgba(255,180,90,.5) !important}

/* menu: warm title + ornate frame on the runemark */
.menu .title{color:var(--bronze-edge) !important;text-shadow:0 0.1875rem 0.625rem #000,0 0 1.875rem rgba(255,170,80,.35)}
.runemark{filter:drop-shadow(0 0 1.125rem rgba(255,150,70,.4))}


/* ============================================================
   DELAY — choose when the effect lands
   ============================================================ */
.delay-choice{display:flex;gap:0.875rem;justify-content:center;flex-wrap:wrap;min-width:min(38.75rem,86vw)}
.dc-opt{flex:1 1 10.625rem;max-width:13.75rem;display:flex;flex-direction:column;align-items:center;gap:0.5rem;
  padding:1.125rem 1rem 1rem;border-radius:0.875rem;cursor:pointer;text-align:center;
  border:1px solid var(--bronze-lo);
  background:linear-gradient(180deg,rgba(40,30,16,.5),rgba(16,12,7,.6));
  transition:transform .15s cubic-bezier(.2,.8,.3,1.1), border-color .15s, box-shadow .2s}
.dc-opt:hover{transform:translateY(-0.3125rem);border-color:var(--bronze-edge);
  box-shadow:0 0 1.375rem var(--gold-glow),0 0.5rem 1.25rem rgba(0,0,0,.5)}
.dc-opt .dc-when{font-family:var(--font-display);font-size:0.75rem;letter-spacing:.16em;
  text-transform:uppercase;color:var(--ink-dim)}
.dc-opt .dc-dial{width:3.5rem;height:3.5rem;border-radius:50%;display:grid;place-items:center;
  font-family:var(--font-display);font-size:1.5rem;font-weight:700;color:#eaf6ff;
  background:radial-gradient(circle at 50% 32%, #2a4a5e, #0d1720 74%);
  border:2px solid #7fdce6;box-shadow:0 0 1rem rgba(127,220,230,.3), inset 0 -0.25rem 0.625rem rgba(0,0,0,.5);
  text-shadow:0 1px 0.1875rem #000}
.dc-opt.now .dc-dial{background:radial-gradient(circle at 50% 32%, #5e4a1a, #201607 74%);
  border-color:var(--gold);box-shadow:0 0 1rem var(--gold-glow), inset 0 -0.25rem 0.625rem rgba(0,0,0,.5);color:#ffe9b0}
.dc-opt .dc-what{font-family:var(--font-body);font-size:0.8438rem;line-height:1.35;color:var(--ink)}
.dc-opt:hover .dc-what{color:#fff}

/* ============================================================
   BESTIARY ENTRY
   ============================================================ */
.foe-detail{width:min(35rem,88vw)}
.fd-head{display:flex;gap:1.125rem;align-items:center;margin-bottom:1rem}
.fd-art{width:8rem;height:8rem;flex:0 0 auto}
.fd-art svg,.fd-art img{width:100%;height:100%;object-fit:contain;object-position:center bottom}
.fd-vitals{display:flex;flex-direction:column;gap:0.4375rem}
.fd-tier{align-self:flex-start;font-family:var(--font-display);font-size:0.6875rem;letter-spacing:.14em;
  text-transform:uppercase;color:var(--tc,#9aa4b2);border:1px solid color-mix(in srgb,var(--tc,#9aa4b2) 55%,transparent);
  background:rgba(0,0,0,.4);border-radius:0.75rem;padding:0.1875rem 0.6875rem}
.fd-hp{font-family:var(--font-display);font-size:1.25rem;color:#ff9a9a}
.fd-act{font-size:0.75rem;color:var(--ink-faint);letter-spacing:.1em;text-transform:uppercase}
.fd-fam{align-self:flex-start;font-family:var(--font-display);font-size:0.6875rem;letter-spacing:.1em;
  text-transform:uppercase;cursor:help;opacity:.92}
.fd-flavor{font-style:italic;color:var(--ink-dim);line-height:1.55;margin:-0.25rem 0 1rem;
  padding-left:0.75rem;border-left:2px solid var(--bronze-lo)}
.fd-sec{font-family:var(--font-display);font-size:0.75rem;letter-spacing:.14em;text-transform:uppercase;
  color:var(--gold);margin:0.25rem 0 0.625rem;padding-bottom:0.375rem;border-bottom:1px solid var(--line)}
.fd-moves{display:flex;flex-direction:column;gap:0.5rem;max-height:46vh;overflow:auto;padding-right:0.25rem}
.fd-move{display:flex;align-items:flex-start;gap:0.6875rem;padding:0.5625rem 0.75rem;border-radius:0.625rem;
  border:1px solid var(--bronze-lo);background:linear-gradient(180deg,rgba(40,30,16,.4),rgba(16,12,7,.5))}
.fd-move.signature{border-color:#a3562a;background:linear-gradient(180deg,rgba(90,36,16,.42),rgba(30,12,6,.5))}
.fd-mic{width:1.75rem;height:1.75rem;flex:0 0 auto;border-radius:50%;display:grid;place-items:center;
  background:radial-gradient(circle at 50% 34%, color-mix(in srgb,var(--mc) 88%,#fff), color-mix(in srgb,var(--mc) 70%,#000));
  border:1px solid color-mix(in srgb,var(--mc) 60%,#fff);box-shadow:0 0 0.5rem color-mix(in srgb,var(--mc) 45%,transparent)}
.fd-mtxt{flex:1;min-width:0}
.fd-mtxt b{font-family:var(--font-display);font-size:0.875rem;color:#f6f2ff}
.fd-mdesc{font-family:var(--font-body);font-size:0.7813rem;color:var(--ink-dim);line-height:1.4;margin-top:2px}
.fd-mdesc .dmg{color:#ff9a9a;font-weight:700}
.fd-mdesc .blk{color:#8fd0ff;font-weight:700}
.fd-mdesc .kw{color:var(--gold)}
.fd-mdesc em{color:var(--ink-faint)}
.fd-sigtag{align-self:center;font-family:var(--font-display);font-size:0.5625rem;letter-spacing:.12em;
  text-transform:uppercase;color:#ffb98a;border:1px solid #a3562a;border-radius:0.625rem;padding:2px 0.4375rem;white-space:nowrap}
.foe-card{cursor:pointer}

/* ============================================================
   SMITH — upgrade preview + before/after confirmation
   ============================================================ */
.upg-tile{position:relative;cursor:pointer;line-height:0}
.upg-tile .card{transition:transform .18s cubic-bezier(.2,.8,.3,1.1)}
/* the upgraded version sits exactly on top and fades in on hover */
.upg-tile .upg-after{position:absolute;inset:0;opacity:0;transition:opacity .18s ease;pointer-events:none}
.upg-tile:hover .upg-after{opacity:1}
.upg-tile:hover .card{transform:translateY(-0.375rem) scale(1.04)}
.upg-tile .upg-flag{position:absolute;left:50%;bottom:-0.5625rem;transform:translateX(-50%) translateY(0.25rem);
  opacity:0;transition:opacity .18s ease, transform .18s ease;pointer-events:none;z-index:6;
  font-family:var(--font-display);font-size:0.5938rem;letter-spacing:.14em;text-transform:uppercase;
  color:#0f1c10;background:linear-gradient(180deg,#a7f0bd,#4fae72);border-radius:0.625rem;padding:2px 0.625rem;
  box-shadow:0 0.1875rem 0.625rem rgba(0,0,0,.5)}
.upg-tile:hover .upg-flag{opacity:1;transform:translateX(-50%) translateY(0)}

.upg-confirm{display:flex;flex-direction:column;align-items:center;gap:0.875rem}
.upg-pair{display:flex;align-items:center;gap:1.375rem}
.upg-col{display:flex;flex-direction:column;align-items:center;gap:0.5625rem}
.upg-col .card{transform:none!important}
.upg-lbl{font-family:var(--font-display);font-size:0.6875rem;letter-spacing:.18em;text-transform:uppercase;color:var(--ink-faint)}
.upg-col.after .upg-lbl{color:#8fe6a0}
.upg-col.after .card{filter:drop-shadow(0 0 0.875rem rgba(120,230,150,.28))}
.upg-arrow{font-size:2.125rem;color:var(--gold);opacity:.8;line-height:1}
.upg-diff{font-family:var(--font-body);font-size:0.8125rem;color:var(--ink-dim);text-align:center}
.upg-diff b{color:#8fe6a0}

/* ============================================================
   RELIC OFFER — treasure chest / boss spoils, pick one of three
   ============================================================ */
.relic-offer{display:flex;gap:1rem;justify-content:center;flex-wrap:wrap;min-width:min(45rem,88vw)}
.ro-opt{--rc:var(--r-common);flex:1 1 12.5rem;max-width:14.75rem;display:flex;flex-direction:column;align-items:center;
  gap:0.375rem;padding:1.125rem 0.9375rem 1rem;border-radius:0.875rem;cursor:pointer;text-align:center;
  border:1px solid color-mix(in srgb,var(--rc) 45%,transparent);
  background:linear-gradient(180deg,color-mix(in srgb,var(--rc) 10%,rgba(20,15,8,.6)),rgba(14,10,6,.7));
  transition:transform .16s cubic-bezier(.2,.8,.3,1.1),border-color .16s,box-shadow .2s}
.ro-opt:hover{transform:translateY(-0.375rem);border-color:var(--rc);
  box-shadow:0 0 1.625rem color-mix(in srgb,var(--rc) 38%,transparent),0 0.625rem 1.5rem rgba(0,0,0,.55)}
.ro-opt.rar-common{--rc:var(--r-common)}
.ro-opt.rar-uncommon{--rc:var(--r-uncommon)}
.ro-opt.rar-rare{--rc:var(--r-rare)}
.ro-opt.rar-legendary{--rc:var(--r-legendary)}
.ro-icon{width:5.125rem;height:5.125rem}
.ro-icon svg{width:100%;height:100%}
.ro-rar{font-family:var(--font-display);font-size:0.5938rem;letter-spacing:.16em;text-transform:uppercase;color:var(--rc)}
.ro-name{font-family:var(--font-display);font-size:1rem;color:#f6f2ff}
.ro-desc{font-family:var(--font-body);font-size:0.7813rem;line-height:1.4;color:var(--ink-dim)}
.ro-opt:hover .ro-desc{color:var(--ink)}

/* merchant relic stock — rarity-tinted so the good one is spottable */
.shop-relic{--rc:var(--r-common);padding:0.375rem 0.5rem;border-radius:0.625rem;
  border:1px solid color-mix(in srgb,var(--rc) 35%,transparent);transition:.15s}
.shop-relic:hover{border-color:var(--rc);box-shadow:0 0 0.875rem color-mix(in srgb,var(--rc) 30%,transparent)}
.shop-relic.rar-uncommon{--rc:var(--r-uncommon)}
.shop-relic.rar-rare{--rc:var(--r-rare)}
.shop-relic.rar-legendary{--rc:var(--r-legendary)}

/* machine battery — one pip per remaining turn of power */
.construct-unit .cu-batt{display:flex;gap:2px;align-items:center;justify-content:center;margin-top:2px}
.construct-unit .cu-batt i{width:0.3125rem;height:0.4375rem;border-radius:1.5px;background:#7fe6a0;
  box-shadow:0 0 0.25rem rgba(127,230,160,.6)}
.construct-unit .cu-batt.low i{background:#ff9a6a;box-shadow:0 0 0.3125rem rgba(255,140,90,.7);
  animation:battLow 1s ease-in-out infinite}
.construct-unit .cu-batt span{font-size:0.5rem;color:#7fe6a0;line-height:1}
@keyframes battLow{50%{opacity:.4}}

/* ============ meta progression: ascension, achievements ============ */
/* The ascension strip used to be a narrow slate-blue panel floating inside a
   warm modal: 47.5rem wide against the 55rem pack row, its own cold palette and
   its own drop shadow, so it read as a foreign widget dropped on the screen
   rather than the last line of the same form. It is now the same width as the
   packs above it, in the modal's own colours, with one hairline to separate it.
   The 17.5rem fixed-width label was also holding the stepper buttons a long way
   apart with nothing between them; the row is intrinsically sized now. */
.asc-bar{max-width:none;margin:1rem 0 0.25rem;padding:0.75rem 1rem 0.85rem;border-radius:0.75rem;
  background:linear-gradient(180deg,rgba(255,255,255,.04),rgba(255,255,255,.015));
  border:1px solid var(--line-soft);box-shadow:none}
.asc-head{display:flex;align-items:center;justify-content:center;gap:0.9rem}
.asc-label{min-width:min(17.5rem,42vw);text-align:center;font-size:max(0.9375rem,13px);letter-spacing:.4px}
.asc-label b{color:var(--gold)}
.asc-step{width:2rem;height:2rem;padding:0;font-size:1.125rem;line-height:1;border-radius:0.5rem;flex:0 0 auto}
.asc-row{display:flex;gap:0.25rem;justify-content:center;margin:0.7rem 0 0}
/* taller and pill-shaped: at 6px tall in a 5px gap the track read as a broken
   progress bar rather than a row of choices you can click */
.asc-pip{width:1.35rem;height:0.5rem;border-radius:999px;background:rgba(255,255,255,.14);
  cursor:pointer;transition:background .18s,box-shadow .18s,transform .18s}
.asc-pip:hover{transform:scaleY(1.5)}
.asc-pip.on{background:linear-gradient(90deg,#e0a44a,#f5d78a);box-shadow:0 0 0.5rem rgba(240,190,110,.5)}
/* the pip you are actually sitting on, so the current level is readable at a
   glance instead of having to count the lit run */
.asc-pip.at{box-shadow:0 0 0.625rem rgba(245,215,138,.85),0 0 0 2px rgba(245,215,138,.5)}
/* pip 0 is the rest position — narrower, and never part of the lit RUN, so it
   never reads as Ascension 1. It still lights when it is the current choice,
   so "Ascension 0" looks selected rather than looking like nothing is. */
.asc-pip:first-child{width:0.7rem;background:rgba(255,255,255,.07)}
.asc-pip:first-child.at{background:linear-gradient(90deg,#e0a44a,#f5d78a);
  box-shadow:0 0 0.625rem rgba(245,215,138,.85),0 0 0 2px rgba(245,215,138,.5)}
.asc-pip.locked{background:rgba(255,255,255,.05);cursor:not-allowed}
.asc-pip.locked:hover{transform:none}
/* the rule list is a popover on the gold "Ascension N" name (hover / tap) —
   the dotted underline is the only hint it opens, so it must be visible */
.asc-label{cursor:help}
.asc-label b{border-bottom:1px dotted rgba(231,198,106,.65);padding-bottom:1px}

.char-card{position:relative}
.cc-record{position:absolute;top:0.5rem;left:0.5rem;display:flex;gap:0.3125rem;align-items:center;
  padding:0.1875rem 0.5rem;border-radius:1.25rem;background:rgba(10,8,16,.72);
  border:1px solid rgba(255,255,255,.12);font-size:0.6875rem;letter-spacing:.3px;backdrop-filter:blur(0.1875rem)}
.cc-record .ccr-win{color:#f5d78a;font-weight:600}
.cc-record .ccr-run{color:#9d95ad}
.cc-record .ccr-asc{color:#7fdce6;font-weight:600}

.ach-screen{padding-bottom:3.75rem}
.ach-progress{width:16.25rem;height:0.375rem;margin:0.625rem auto 0;border-radius:0.25rem;
  background:rgba(255,255,255,.1);overflow:hidden}
.ach-progress i{display:block;height:100%;border-radius:0.25rem;
  background:linear-gradient(90deg,#c78a3c,#f5d78a);box-shadow:0 0 0.625rem rgba(240,190,110,.5);
  transition:width .5s ease}
.ach-stats{display:flex;flex-wrap:wrap;justify-content:center;gap:0.625rem;max-width:56.25rem;margin:0 auto 1.5rem}
.ach-stat{min-width:7rem;padding:0.5625rem 0.75rem;border-radius:0.625rem;text-align:center;
  background:rgba(255,255,255,.035);border:1px solid rgba(255,255,255,.07)}
.ach-stat b{display:block;font-size:1.1875rem;color:var(--gold);line-height:1.2}
.ach-stat span{font-size:0.6563rem;color:#9d95ad;letter-spacing:.3px}
.ach-cat{max-width:67.5rem;margin:1.625rem auto 0.625rem;padding-left:0.25rem;font-size:0.875rem;
  letter-spacing:1.6px;text-transform:uppercase;color:#b9b2c8}
.ach-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(16.25rem,1fr));
  gap:0.75rem;max-width:67.5rem;margin:0 auto}
.ach-card{display:flex;gap:0.75rem;align-items:flex-start;padding:0.6875rem 0.8125rem;border-radius:0.6875rem;
  background:rgba(255,255,255,.028);border:1px solid rgba(255,255,255,.06);
  opacity:.5;filter:grayscale(1);transition:opacity .2s,filter .2s,border-color .2s,transform .15s}
.ach-card.on{opacity:1;filter:none;border-color:rgba(220,180,110,.34);
  background:linear-gradient(180deg,rgba(58,44,22,.36),rgba(255,255,255,.03))}
.ach-card.on:hover{transform:translateY(-2px);border-color:rgba(240,200,130,.55)}
.ach-icon{width:2.625rem;height:2.625rem;flex:0 0 2.625rem}
.ach-icon svg{width:100%;height:100%;display:block}
.ach-name{font-size:0.8438rem;font-weight:600;color:#efe9f6;margin-bottom:2px}
.ach-card.on .ach-name{color:var(--gold)}
.ach-desc{font-size:0.7188rem;color:#a49cb4;line-height:1.42}
.ach-when{font-size:0.625rem;color:#7c7489;margin-top:0.25rem;letter-spacing:.3px}

.ach-toast{display:flex;gap:0.75rem;align-items:center;padding:0.75rem 1rem;min-width:18.125rem;
  background:linear-gradient(135deg,rgba(62,46,20,.97),rgba(26,20,34,.97));
  border:1px solid rgba(240,200,130,.5);box-shadow:0 0.5rem 1.875rem rgba(0,0,0,.5),0 0 1.375rem rgba(240,190,110,.2)}
.ach-toast .at-icon{width:2.5rem;height:2.5rem;flex:0 0 2.5rem}
.ach-toast .at-icon svg{width:100%;height:100%;display:block}
.ach-toast .at-kicker{font-size:0.5938rem;letter-spacing:2px;text-transform:uppercase;color:#d9b976}
.ach-toast .at-name{font-size:0.9375rem;font-weight:600;color:var(--gold);margin:1px 0 2px}
.ach-toast .at-desc{font-size:0.6875rem;color:#b5adc4;line-height:1.35}
#ach-layer{position:fixed;right:1.125rem;bottom:1.125rem;z-index:420;display:flex;flex-direction:column-reverse;
  gap:0.5625rem;align-items:flex-end;pointer-events:none;max-height:70vh;overflow:hidden}
#ach-layer .ach-toast{animation:achIn .45s cubic-bezier(.2,.9,.3,1.3)}
@keyframes achIn{from{opacity:0;transform:translateX(2.5rem) scale(.94)}}
.ach-tabs{display:flex;flex-wrap:wrap;gap:0.375rem;justify-content:center;max-width:67.5rem;margin:0 auto 0.75rem}
.ach-tab{display:flex;align-items:center;gap:0.4375rem;padding:0.375rem 0.8125rem;border-radius:1.25rem;cursor:pointer;
  background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.09);color:#b9b2c8;
  font-family:var(--font-display);font-size:0.7813rem;letter-spacing:.4px;transition:all .16s}
.ach-tab:hover{background:rgba(255,255,255,.08);color:#efe9f6}
.ach-tab.on{background:linear-gradient(180deg,rgba(90,68,26,.6),rgba(50,38,16,.6));
  border-color:rgba(230,190,120,.5);color:var(--gold)}
.ach-tab .at-count{font-size:0.6563rem;opacity:.7;font-variant-numeric:tabular-nums}
.ach-toggle{display:flex;justify-content:center;margin:0 auto 1.125rem}
.ach-toggle .btn.on{color:var(--gold);border-color:rgba(230,190,120,.45)}
.ach-empty{text-align:center;padding:2.5rem 0;font-style:italic}

/* ---- map stops: one token art, tinted to the kind of stop it is ----
   The tokens are a single cream parchment disc, so the colour is applied as a
   MULTIPLY wash clipped to the disc: dark ink stays dark, the parchment takes
   the hue, and nothing needs redrawing per type. `isolation` keeps the blend
   inside the token — without it the wash would reach the painted map beneath.
   Ordinary fights are deliberately left bare: they are the most common stop
   and the neutral the other colours read against. */
.map-node{width:2.875rem;height:2.875rem;border-radius:50%;background:none;border:none;box-shadow:none}
.map-node::before{display:none}
.map-node .mn-icon{width:100%;height:100%;background:none;box-shadow:none;border-radius:0;filter:none;
  position:relative;isolation:isolate}
.map-node .mn-icon::after{content:'';position:absolute;inset:7%;border-radius:50%;
  background:var(--nt,#e9dfc4);mix-blend-mode:multiply;opacity:.7;pointer-events:none}
.map-node.t-combat .mn-icon::after{opacity:0}
.map-node .mn-icon img.mn-raster{width:100%;height:100%;object-fit:contain;
  filter:drop-shadow(0 0 0.4375rem color-mix(in srgb,var(--nt,#000) 45%, transparent))
         drop-shadow(0 0.1875rem 0.3125rem rgba(0,0,0,.5))}
.map-node .mn-check{z-index:2}
.map-node.boss{width:4.625rem;height:4.625rem}
.map-node.reachable{border:none;box-shadow:none}
.map-node.reachable::before{display:block;content:'';position:absolute;inset:-0.375rem;border-radius:50%;
  border:1px dashed var(--gold);opacity:.8;animation:mnSpin 14s linear infinite}
@keyframes mnSpin{to{transform:rotate(360deg)}}
.map-node.reachable img.mn-raster{filter:drop-shadow(0 0 0.5625rem rgba(231,198,106,.7)) drop-shadow(0 0.1875rem 0.3125rem rgba(0,0,0,.5))}
.map-node.current{border:none;box-shadow:none}
.map-node .mn-check{background:rgba(6,6,10,.38);border-radius:50%;font-size:1.125rem;color:#fdf3dd}
.map-legend .ml-dot.raster{width:1.5rem;height:1.5rem;background:none;border:none;box-shadow:none;display:grid;place-items:center;
  position:relative;isolation:isolate}
.map-legend .ml-dot.raster img{width:1.5rem;height:1.5rem;object-fit:contain}
.map-legend .ml-dot.raster::after{content:'';position:absolute;inset:7%;border-radius:50%;
  background:var(--nt,#e9dfc4);mix-blend-mode:multiply;opacity:.7;pointer-events:none}
.map-legend .ml-row.t-combat .ml-dot.raster::after{opacity:0}
/* the label takes the stop's colour too, so the key works at a glance */
.map-legend .ml-row .ml-name{color:color-mix(in srgb, var(--nt,#d8d2c4) 72%, #fff)}

/* ---- standing on the ground ----
   Sprite PNGs are trimmed to their alpha box, so a sprite's bottom edge is
   literally the character's feet. Those feet are the entity's baseline: the
   name/HP block hangs BELOW it (absolutely placed) instead of levering the
   whole figure up off the painted road, and every combatant — whatever its
   box size or how many chips it carries — plants on the same line. */
/* The reserve must hold name + HP bar + TWO full rows of status pips; at 6.25rem
   the second row slid under the arena's clip edge and read as "cut off by the
   End Turn / pile buttons". */
.entities{padding-bottom:8rem}
.entity .einfo{position:absolute;top:100%;left:50%;transform:translateX(-50%);
  width:100%;height:auto;margin-top:0.375rem;pointer-events:none}
.entity .einfo > *{pointer-events:auto}
.entity .sprite-wrap{margin-bottom:0}
/* contact shadow: a wider, darker pool right under the feet sells the footing */
.entity .eshadow{bottom:-0.375rem;width:82%;height:1.625rem;
  background:radial-gradient(50% 50% at 50% 50%, rgba(0,0,0,.72), rgba(0,0,0,.28) 55%, transparent 74%)}
.entity.player .eshadow{width:70%}

/* ---- peeking at the board from an encounter ----
   The overlay is faded, NOT removed and NOT given pointer-events:none — it
   must go on swallowing clicks, or a peek at the map would let you walk to
   another stop in the middle of one. */
.overlay.peeking{opacity:0;transition:opacity .18s ease}
.overlay.peeking .modal{visibility:hidden}
.peek-return{position:fixed;left:50%;bottom:1.75rem;transform:translateX(-50%);z-index:1400}

/* ---- shop: hover highlighting ----
   The hover TARGET's own box never moves — only its inner art lifts. A target
   that transforms itself can slide out from under the cursor and flicker
   :hover on and off, which is exactly the loop the hand cards used to hit. */
.shop-item{border:1px solid transparent;border-radius:0.625rem;padding:0.375rem 0.5rem;
  transition:background .15s, border-color .15s, box-shadow .15s}
.shop-item .relic{transition:transform .15s, filter .15s}
.shop-item:hover{background:rgba(231,198,106,.08);
  box-shadow:0 0 0 1px rgba(231,198,106,.22), 0 0.5rem 1.25rem rgba(0,0,0,.45)}
.shop-item:hover .relic{transform:translateY(-0.25rem) scale(1.08);
  filter:brightness(1.12) drop-shadow(0 0 0.625rem rgba(231,198,106,.45))}
.shop-item:hover .gold,.shop-card:hover .gold{color:var(--gold);text-shadow:0 0 0.625rem var(--gold-glow)}
/* potions carry their rarity the same way relics do, so a rare potion on the
   shelf is as legible as a rare relic beside it */
.shop-potion{--rc:var(--r-common)}
.shop-potion.rar-uncommon{--rc:var(--r-uncommon)}
.shop-potion.rar-rare{--rc:var(--r-rare)}
.shop-item .si-name{color:var(--rc,var(--ink))}
.shop-potion:hover,.shop-relic:hover{border-color:var(--rc)}
/* the services shelf has no rarity of its own — it keeps the bronze edge */
.shop-item:not(.shop-relic):not(.shop-potion):hover{border-color:var(--bronze)}

/* The merchant lists five cards, not a whole deck, so it never needs to scroll
   — and .deck-grid's overflow:auto was shearing the top off every card the
   moment it lifted on hover. Room is left in the padding for the lift+scale. */
.deck-grid.shop-grid{max-height:none;overflow:visible;padding:1.25rem 0.75rem 0.625rem}
/* One highlight per hover: the shop-item box owns it. The relic icon inside
   must not ALSO light its own border, which read as two nested outlines. */
.shop-item .relic:hover{border-color:var(--line);box-shadow:none}
.shop-item.shop-relic:hover .relic{border-color:var(--line)}

.shop-card .card{transition:transform .16s cubic-bezier(.2,.8,.3,1), filter .16s, box-shadow .16s}
/* beats `.deck-grid .card{transform:none!important}` on specificity */
.deck-grid .shop-card:hover .card{transform:translateY(-0.625rem) scale(1.05)!important;
  filter:brightness(1.07);box-shadow:0 0.875rem 1.625rem rgba(0,0,0,.6), 0 0 0 1px rgba(231,198,106,.35)}

/* ---- who a card belongs to vs how rare it is ----
   CLASS owns the frame and the cost gem; RARITY owns the type caption, the
   divider rules and the gem set into them. The two never borrow each other's
   colour, so a glance reads "whose card" and "how rare" independently. */
.card{--rar:var(--r-common)}
.card[data-rarity="starter"]{--rar:var(--r-starter)}
.card[data-rarity="common"]{--rar:var(--r-common)}
.card[data-rarity="uncommon"]{--rar:var(--r-uncommon)}
.card[data-rarity="rare"]{--rar:var(--r-rare)}
.card[data-rarity="legendary"]{--rar:var(--r-legendary)}
.card[data-rarity="special"]{--rar:var(--r-special)}
/* let the rarity colour carry on the GEM (a soft halo in its own hue); the
   type caption is flat dark ink on the parchment — no shadow */
.card .typecap{text-shadow:none}
.card .banner .rgem{filter:drop-shadow(0 1px 2px rgba(0,0,0,.85))
  drop-shadow(0 0 0.375rem color-mix(in srgb, var(--rar) 75%, transparent))}

/* ---- right-click feedback (src/ui/feedback.js) ---- */
.ctx-menu{position:fixed;z-index:9000;min-width:11.625rem;background:#151a22;border:1px solid #2f3a48;
  border-radius:0.5rem;padding:0.3125rem;box-shadow:0 0.75rem 1.875rem rgba(0,0,0,.6);font-family:'Inter',system-ui,sans-serif}
.ctx-head{font-size:0.625rem;letter-spacing:.09em;text-transform:uppercase;color:#7d8b9e;
  padding:0.3125rem 0.5625rem 0.375rem;border-bottom:1px solid #232c38;margin-bottom:0.25rem;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ctx-item{display:block;width:100%;text-align:left;background:none;border:0;color:#dfe6f0;
  font:inherit;font-size:0.8125rem;padding:0.4375rem 0.5625rem;border-radius:0.375rem;cursor:pointer}
.ctx-item:hover{background:#233042;color:#ffd77a}

.fb-body{display:flex;flex-direction:column;gap:0.75rem;min-width:min(26.875rem,74vw)}
.fb-preview{display:flex;gap:0.75rem;align-items:center;justify-content:center;
  background:rgba(0,0,0,.22);border:1px solid rgba(255,255,255,.07);border-radius:0.625rem;padding:0.75rem}
.fb-preview .card{transform:scale(.82);transform-origin:center;pointer-events:none}
.fb-icon{width:4rem;height:4rem;flex:0 0 4rem}
.fb-text{min-width:0}
.fb-desc{font-size:0.7813rem;color:#a9b6c7;margin-top:0.1875rem;line-height:1.45}
.fb-input{width:100%;box-sizing:border-box;background:#10141b;border:1px solid #2b3542;color:#dfe6f0;
  border-radius:0.5rem;padding:0.625rem 0.75rem;font:inherit;font-size:0.8438rem;line-height:1.5;resize:vertical}
.fb-input:focus{outline:none;border-color:#4b6b8f}
.fb-status{font-size:0.75rem;color:#e9c46a;min-height:1rem}

/* the outstanding notes listed under the box you type into (feedback.js).
   Only unaddressed ones appear, so an empty list means nothing is waiting. */
.fb-open:empty{display:none}
.fb-open-head{font-size:0.625rem;letter-spacing:.09em;text-transform:uppercase;color:#7d8b9e;
  border-top:1px solid rgba(255,255,255,.07);padding-top:0.5625rem;margin-bottom:0.4375rem}
.fb-open-list{display:flex;flex-direction:column;gap:0.4375rem;max-height:11.875rem;overflow-y:auto;padding-right:0.25rem}
.fb-open-note{background:#101821;border:1px solid #1f3040;border-left:2px solid #2f6d52;
  border-radius:0.375rem;padding:0.4375rem 0.5625rem}
.fb-open-text{font-size:0.7813rem;line-height:1.45;color:#c6d3e2;white-space:pre-wrap}
.fb-open-when{font-size:0.5938rem;color:#61708a;margin-top:0.25rem;text-transform:uppercase;letter-spacing:.06em}
.fb-open-more{font-size:0.7188rem;color:#7d8b9e;padding:2px 0 0}

/* ============================================================
   NAMES CARRY THEIR RARITY
   A card/relic/potion's NAME is now coloured by rarity everywhere it appears,
   so "how rare is this" is readable before you get to the pip or the tag.
   This block sits at the end of the sheet deliberately: the ornate reskin
   above sets .cname colour with !important, and order is what settles it.
   ============================================================ */
/* Titles sit on the cream parchment banner (2026-08-03), so the light rarity
   hues washed out — same hue families, darkened to parchment-legible INKS */
.card .cname{color:#241a0c !important}
.card[data-rarity="starter"] .cname{color:#3a3226 !important}
.card[data-rarity="common"] .cname{color:#46525e !important}
.card[data-rarity="uncommon"] .cname{color:#14577e !important}
.card[data-rarity="rare"] .cname{color:#57297e !important}
.card[data-rarity="special"] .cname{color:#8a2470 !important}
/* legendary keeps its bronze gradient (background-clip:text needs a
   transparent colour) — the reskin's !important had been silently killing it */
.card[data-rarity="legendary"] .cname{color:transparent !important}
/* an upgraded card must still be unmistakable at a glance: the green wins */
.card.upgraded .cname{color:#1d6e3c !important}

/* reward screens: relic/potion choice tiles name themselves in their rarity */
.ro-name{color:var(--rc)}
.ro-opt.rar-starter{--rc:var(--r-starter)}

/* the loot list after a fight (relic / potion rows) */
.reward-row.rar-starter   .rtxt b{color:var(--r-starter)}
.reward-row.rar-common    .rtxt b{color:var(--r-common)}
.reward-row.rar-uncommon  .rtxt b{color:var(--r-uncommon)}
.reward-row.rar-rare      .rtxt b{color:var(--r-rare)}
.reward-row.rar-legendary .rtxt b{color:var(--r-legendary)}

/* ---- spoils of battle ----
   The old screen was five identical rows that dimmed and struck themselves
   out on claim, so a prize you had just taken looked exactly like one you had
   missed. Each row now carries a chip saying what it wants from you — Take,
   Choose, or Claimed — and claimed rows stay fully legible in a quiet green. */
.reward-list.spoils{min-width:min(35rem,86vw);gap:0.625rem}
.spoils-row{gap:1rem;padding:0.875rem 1rem}
.spoils-row .ric{width:3.375rem;height:3.375rem}
.spoils-row .rkind{font-family:var(--font-display);font-size:0.625rem;letter-spacing:.14em;
  text-transform:uppercase;color:var(--ink-faint);margin:2px 0 0.1875rem}
.spoils-row .rdesc{color:var(--ink-dim);font-size:0.8125rem}
.spoils-row .rchip{flex:0 0 auto;align-self:center;font-family:var(--font-display);font-size:0.6875rem;
  letter-spacing:.12em;text-transform:uppercase;padding:0.375rem 0.75rem;border-radius:62.4375rem;
  border:1px solid var(--line);color:var(--ink-faint);white-space:nowrap;
  transition:color .15s, border-color .15s, background .15s}
.spoils-row:hover .rchip{border-color:var(--gold);color:var(--gold);background:rgba(231,198,106,.08)}
/* Unclaimed rows must read as "waiting on you", not decoration: their chips
   sit brighter than the faint default, and a row that opens a picker — the
   real decision on this screen — wears a FILLED gold chip that breathes. */
.spoils-row:not(.taken):not(.blocked) .rchip{color:var(--ink);border-color:#565179}
.spoils-row.k-card:not(.taken),.spoils-row.k-relicChoice:not(.taken){border-color:rgba(231,198,106,.4)}
.spoils-row.k-card:not(.taken) .rchip,.spoils-row.k-relicChoice:not(.taken) .rchip{
  color:#181223;background:var(--gold);border-color:var(--gold);font-weight:700;
  animation:chip-breathe 1.8s ease-in-out infinite}
@keyframes chip-breathe{
  0%,100%{box-shadow:0 0 0 0 rgba(231,198,106,.5)}
  50%{box-shadow:0 0 0 0.4rem rgba(231,198,106,0)}}
.spoils-row.taken{opacity:1;pointer-events:none;text-decoration:none;
  background:rgba(127,230,160,.05);border-color:rgba(127,230,160,.28)}
.spoils-row.taken .ric{filter:saturate(.55) brightness(.85)}
.spoils-row.taken .rchip{border-color:rgba(127,230,160,.5);color:#7fe6a0;background:rgba(127,230,160,.08)}
.spoils-row.taken .rkind,.spoils-row.taken .rdesc{opacity:.55}
.spoils-row.blocked .rchip{border-color:rgba(255,138,138,.45);color:#ff8a8a}

/* ============================================================
   RESPONSIVE / MOBILE
   The rem scale above already shrinks every asset uniformly; this section
   handles what scaling can't — structure. Breakpoints are real device
   shapes: <=900px loses the combat log rail, <=760px lets the top bar
   wrap, <=640px is the phone layout proper, and short landscape heights
   compress the combat rows.
   ============================================================ */

/* drags must never turn into page scrolls */
.hand .card,.card.dragging{touch-action:none}

/* landscape-only in the installed app: a full-screen gate covers portrait.
   display-mode:standalone limits it to the PWA — a browser tab is left alone
   (Safari in-page play, dev windows). Purely CSS: rotating hides it. */
#rotate-gate{display:none}
@media all and (display-mode:standalone) and (orientation:portrait){
  #rotate-gate{position:fixed;inset:0;z-index:5000;display:flex;flex-direction:column;
    align-items:center;justify-content:center;gap:0.5rem;text-align:center;
    background:radial-gradient(120% 90% at 50% 30%,#221b31,#110e18);
    padding:2rem calc(1.5rem + env(safe-area-inset-left)) 2rem calc(1.5rem + env(safe-area-inset-right))}
  #rotate-gate .rg-icon{font-size:3.5rem;color:var(--gold);
    animation:rg-spin 2.4s ease-in-out infinite}
  #rotate-gate .rg-title{font-family:var(--font-display);font-size:max(1.4rem,20px);color:var(--gold)}
  #rotate-gate .rg-sub{color:var(--ink-dim);font-size:max(0.9rem,14px)}
}
@keyframes rg-spin{0%,100%{transform:rotate(0)}50%{transform:rotate(90deg)}}

/* a game surface, not a document: nothing highlights on tap-hold or drag.
   Real text entry (feedback notes, seed fields) opts back in. */
html{-webkit-user-select:none;user-select:none}
input,textarea,select,[contenteditable="true"]{-webkit-user-select:text;user-select:text}
.map-scroll{overscroll-behavior:contain;-webkit-overflow-scrolling:touch}

/* prose floors: card innards scale with the card (the fitter guards them),
   but free-standing UI text must never shrink past legibility */
.tooltip{font-size:max(.8125rem,12px)}
.tooltip h4{font-size:max(.875rem,13px)}
.tip-kw,.tip-kw b{font-size:max(.7188rem,11px)}
.btn{font-size:max(.9375rem,12px)}
.btn.big{font-size:max(1.125rem,14px)}
.btn.sm{font-size:max(.8125rem,11px)}
.toast{font-size:max(.9375rem,12px)}
.reward-row .rtxt div,.spoils-row .rdesc{font-size:max(.8125rem,11px)}
.settings-item .si-sub,.howto-b,.ro-desc,.fd-mdesc,.ach-desc{font-size:max(.7813rem,11px)}
.log-line{font-size:max(.8125rem,11px)}
.menu .actions .btn{font-size:max(.9375rem,13px)}

/* notch / home-indicator clearance (viewport-fit=cover) */
.topwrap{padding-top:env(safe-area-inset-top)}
.combat{padding-bottom:env(safe-area-inset-bottom)}
.map-screen,.select-screen{padding-bottom:calc(env(safe-area-inset-bottom))}

/* ---- <=900px: even as an overlay the log costs too much battlefield; the
   collapse button dies with it (combatlog still records — the rail is
   view-only) ---- */
@media (max-width:900px){
  .log-rail{display:none}
}

/* ---- <=760px: top bar wraps into rows instead of overflowing ---- */
@media (max-width:760px){
  .topbar{flex-wrap:wrap;height:auto;min-height:2.6rem;padding:0.3rem 0.75rem;row-gap:0.2rem;white-space:normal}
  .hpbar{width:8.5rem}
  .topbar .tb-name{font-size:0.85rem}
  .relic-overlay{max-width:94vw;left:0.5rem}
  .stat{font-size:0.8rem;padding:0.2rem 0.5rem}
  .topbar .tb-boss .tb-bossart{width:1.9rem;height:1.9rem}
}

/* ---- phone (either orientation): a narrow portrait OR a short landscape.
   An iPhone held sideways is ~874x402 — wider than any width breakpoint, so
   height is the real phone-landscape signal. Shared phone chrome lives here;
   orientation-specific sizing follows. ---- */
@media (max-width:640px), (max-height:480px){
  /* the hand takes the full width; orb and piles shrink into the corners,
     clear of the Dynamic Island / home indicator */
  /* corner HUD hugs the screen: the safe-area inset is honoured at less than
     half strength — the full ~59px landscape inset shoved everything toward
     the centre, and the corner radius only actually claims the outer sliver */
  /* The champion sits at the left edge, which in landscape is exactly where the
     Dynamic Island / camera cutout lives. Corner HUD only needs a fraction of
     the inset (it hugs the rounded corner), but the character is tall enough to
     run straight into the cutout, so it takes the FULL inset plus a little. */
  .player-slot{padding-left:calc(4% + env(safe-area-inset-left) + 0.5rem)}
  .hand-zone{left:0;right:0}
  /* 0.8rem base, not 0.1: the partial inset alone parked the outermost
     buttons inside the display's corner-radius arc, which clipped them */
  .energy-orb{left:calc(0.8rem + env(safe-area-inset-left)*0.45);width:4.4rem;height:4.4rem}
  .energy-orb .etext b{font-size:max(1.7rem,19px)}
  .pile{width:3.8rem;bottom:0.4rem}
  .pile .pile-icon{width:3rem;height:4rem}
  .pile.draw{left:calc(0.8rem + env(safe-area-inset-left)*0.45)}
  .pile.discard{right:calc(5rem + env(safe-area-inset-right)*0.45)}
  .pile.exhaust{right:calc(0.8rem + env(safe-area-inset-right)*0.45)}
  .endturn{right:calc(0.9rem + env(safe-area-inset-right)*0.45)}
  .endturn .btn{padding:.6em 1em;font-size:max(.875rem,13px)}
  /* combat HUD text: floors so the battlefield stays readable at phone scale */
  .ehp .txt{font-size:max(.8rem,12px)}
  /* statuses are the densest information on a phone battlefield — the glyph
     gets a real px floor rather than shrinking with the rem scale */
  .pip{font-size:max(.95rem,13px)}
  .pip svg,.pip .st-emblem,.pip .st-emblem-svg{width:max(1.8rem,24px);height:max(1.8rem,24px)}
  /* The champion's own statuses are the same size as the enemies' — one pip
     size on the board, so nothing reads as more or less important than it is.
     What keeps a dozen of them out of a puddle in the crowded bottom-left
     corner is the fixed GRID, not shrinking them: aligned columns stay
     countable where a centred ragged wrap does not. */
  /* max-content columns and a max-content width, NOT auto/minmax: .einfo is
     only as wide as the entity (85px), so auto columns collapsed to 25px and
     clipped the count off every pip. The grid is allowed to be wider than the
     champion and overflow to the right, where there is nothing to hit. */
  .entity.player .statuses{display:grid;grid-template-columns:repeat(3,max-content);
    width:max-content;max-width:none;justify-content:start;justify-items:start;gap:0.1rem 0.55rem}
  .fam-chip{display:none}
  .floatnum{font-size:max(2rem,20px)}
  .floatnum.crit{font-size:max(2.75rem,26px)}
  /* the threat badge lives in the strip between the screen edge and the
     champion's shoulder — icon then number on one line, so the strip has to be
     wide enough for both (see the .entities padding-left below) */
  .threat{margin-right:0.15rem;gap:0.15rem}
  .threat .th-medal{width:max(1.7rem,21px);height:max(1.7rem,21px)}
  .threat .th-num{font-size:max(1.25rem,15px)}
  .debuff-chip{font-size:max(.6563rem,9px)}
  .dmg-preview .dp-num{font-size:max(1.2rem,15px)}
  .dmg-preview .dp-hp,.dmg-preview .dp-tag{font-size:max(.6563rem,9px)}
  .turn-banner{font-size:max(1.6rem,18px)}
  /* the labels are wider than the shrunken piles and collide — position
     carries the meaning on a phone (draw left, discard/exhaust right) */
  .pile .pile-lbl{display:none}
  .pile .pile-count{font-size:max(1.3rem,16px)}
  /* fingers, not cursors: the settings gear is a 44px-class target, boxless
     (the border box crowded the potion belt) and set a step apart from it */
  .icon-btn{width:max(2.7rem,40px);height:max(2.7rem,40px);font-size:max(1.25rem,18px)}
  .topbar .icon-btn{border:none;background:transparent;box-shadow:none;margin-left:0.7rem}
  /* relics: bigger than stock and starting at the very edge — px floors,
     because 2.9rem at phone scale is a 23px speck (34px read as too chunky) */
  .relic{width:max(2.3rem,26px);height:max(2.3rem,26px)}
  .combat-topbar .relic-overlay .relic{width:max(2.6rem,30px);height:max(2.6rem,30px)}
  .res-badge{width:2.6rem}
  .res-badge .rb-orb{width:2.4rem;height:2.4rem}
  .res-badge b{font-size:max(1rem,13px)}
  .res-badge .rb-lbl{font-size:max(.5625rem,8px)}
  .playzone-hint{font-size:max(.7188rem,10px)}
  /* modals leave finger room at the edges — the corner X must be tappable
     without fighting the screen bezel or the Dynamic Island */
  .modal{padding:1rem 0.9rem;
    max-width:min(94vw, calc(100vw - 44px - env(safe-area-inset-left) - env(safe-area-inset-right)));
    max-height:calc(100vh - 1.6rem)}
  .modal.fullscreen{
    width:calc(100vw - 44px - env(safe-area-inset-left) - env(safe-area-inset-right));
    height:calc(100vh - 20px);border-radius:12px}
  /* Apple-HIG-size touch target for the close X */
  .modal-x{width:max(2.5rem,42px);height:max(2.5rem,42px);font-size:max(1.5rem,22px);top:6px;right:6px}
  .reward-list,.reward-list.spoils,.settings-menu,.delay-choice,.relic-offer,
  .history-list,.run-detail,.fb-body,.foe-detail{min-width:0;width:100%}
  .store-tag{display:none}
  .map-legend{top:4.2rem;right:calc(0.3rem + env(safe-area-inset-right)*0.45);font-size:0.7rem;padding:0.5rem 0.6rem;gap:0.3rem}
  .map-legend .ml-dot{width:1.3rem;height:1.3rem}
  .map-deckfab{right:calc(0.4rem + env(safe-area-inset-right)*0.45);bottom:4rem;width:4rem}
  .map-deckfab img{width:3.4rem;height:3.4rem}
  .relic-overlay{left:calc(0.15rem + env(safe-area-inset-left)*0.45)}
  /* champion modal: fill the phone screen instead of centring a narrow column */
  .char-modal-body{width:calc(100vw - 72px - env(safe-area-inset-left) - env(safe-area-inset-right))}
}

/* ---- <=640px: portrait phone ---- */
@media (max-width:640px){
  /* battlefield: tighter ranks, smaller figures, info plates that fit */
  /* left padding carries the threat badge, same as the landscape block: at the
     old 0.4rem the badge hung off the screen edge entirely (x -28..2) */
  .entities{padding:0 1.1rem 7.5rem 4.2rem}
  /* matched to the landscape bump above, so rotating the phone does not
     change how big the cast reads */
  .entity{width:9.5rem}
  .entity .sprite{width:13.5rem;height:13.5rem}
  .entity.player .sprite{width:16.5rem;height:16.5rem}
  .entity.tier-elite .sprite{width:15.3rem;height:15.3rem}
  .entity.tier-boss .sprite{width:18.9rem;height:18.9rem}
  .enemy-row{gap:0.4rem;padding-right:0}
  /* portrait has no left cutout, so this is 0 there — but a narrow device held
     in landscape would otherwise lose the inset the rule above grants */
  .player-slot{padding-left:env(safe-area-inset-left)}
  .ehp{width:8.8rem}
  .ehp .bar{height:max(1.05rem,15px)}
  .statuses{max-width:9.5rem}
  .class-res{left:calc(100% - 1.4rem)}
  .construct-row{padding-bottom:5.4rem;margin-left:0.2rem}
  .hand .card{margin:0 -3.6rem}
  .energy-orb{bottom:8.6rem}
  .endturn{bottom:8.6rem}
  .tl-strip{bottom:15rem;max-width:96vw;overflow-x:auto}
  /* select screen breathes on a phone */
  .select-screen{padding:0.9rem 1rem}
  .select-banner{margin:0 0 0.8rem}
  .select-banner .sb-title{font-size:1.6rem}
  /* the bust art fills by cover-crop — a too-short window shows only the top
     of a head, so the frame keeps a px floor no matter how small rem gets */
  .char-portrait{height:max(8.5rem,118px)}
  .char-card{min-height:0}
  .char-detail{padding:0.9rem 1rem}
  .packs{grid-template-columns:1fr;gap:0.7rem}
  .cm-head{flex-direction:column;align-items:center;text-align:center}
  .cm-headbody{text-align:center;min-height:0}
  .menu .actions.menu-col{width:min(20.6rem,86vw)}
}

/* ---- short landscape (a phone held sideways): compress the vertical stack
   and shrink the figures — height is the scarce axis ---- */
@media (max-height:480px){
  .menu h1.title{font-size:clamp(1.2rem,3.2vh,2rem)}
  .menu .runemark{width:2rem;height:2rem;margin-bottom:0.2rem}
  .menu .actions{margin-top:0.7em;gap:0.35rem}
  .menu .actions.menu-col{gap:0.35rem}
  .menu .actions .btn{padding:.34em 1.3em}
  .dev-links{margin-top:0.7rem}
  /* no bottom BAR at all: the arena art runs to the screen's bottom edge and
     the hand / orb / piles / End Turn overlay it directly (the reference is
     Slay the Spire's phone HUD). Row 3 collapses; the strip goes absolute. */
  .combat{grid-template-rows:auto 1fr 0}
  .combat-bottom{position:absolute;left:0;right:0;bottom:0;height:10.5rem;
    background:none;border:none;box-shadow:none}
  /* with no bar behind it the HUD sits straight on the painted arena, and a
     bright backdrop swallows the orb, the piles and the End Turn button. A
     soft scrim — a gradient, not a panel — restores the contrast without
     putting the bar back. It is the first child, so it paints under the HUD. */
  .combat-bottom::before{content:'';position:absolute;left:0;right:0;bottom:0;height:100%;pointer-events:none;
    background:linear-gradient(180deg,transparent,rgba(6,5,12,.26) 48%,rgba(6,5,12,.6))}
  .hand-zone{height:12rem}
  .hand .card{margin:0 -2.2rem}
  /* The resting fan sinks below the bottom edge (à la Slay the Spire, less
     extreme) — a held or dragged card rises back into full view. 3.2rem hid
     roughly a fifth of every card, which on a 16.875rem card is most of the
     rules text; 1.7rem keeps the peeking-deck look while leaving the whole
     text box readable without touching anything (user, 2026-08-04). */
  .hand{padding-bottom:0;transform:translateY(1.7rem)}
  /* the cast at phone-landscape scale: figures well under half the arena,
     raised off the floor so name + HP + status chips fit BELOW the feet
     instead of clipping at the arena's bottom edge */
  /* 19.5rem: the old 9rem standing line PLUS the 10.5rem the arena grew when
     the bottom bar collapsed — the figures keep their screen position */
  /* 4.6rem of left padding, not 0.8: the champion stands one threat-badge width
     in from the edge so the badge itself gets that strip. It also keeps the
     badge clear of the Dynamic Island, which sits over exactly this band of the
     screen in landscape and is invisible in the iframe test ground. */
  .entities{padding:0 calc(1.6rem + env(safe-area-inset-right)*0.45) 19.5rem calc(4.6rem + env(safe-area-inset-left)*0.45)}
  /* the cast runs ~18% larger than the first phone-landscape pass. Feet stay
     planted (sprite-wrap is bottom-aligned), so the extra height goes UP —
     which is why the boss is the one to check: it is the tallest, and its
     intent stack has to clear the top bar above its head. */
  .entity{width:10rem}
  .entity .sprite{width:11.2rem;height:11.2rem}
  .entity.player .sprite{width:13.6rem;height:13.6rem}
  .entity.tier-elite .sprite{width:12.4rem;height:12.4rem}
  .entity.tier-boss .sprite{width:15.3rem;height:15.3rem}
  .enemy-row{gap:2.75rem}
  .ehp{width:9.2rem}
  .ehp .bar{height:max(1.1rem,16px)}
  /* intent plates: smaller type and wrapping lines, so a full plate fits over
     its enemy without colliding with a neighbour or the screen edge */
  /* bigger glyphs need more room before wrapping; enemies are spaced 2.75rem
     apart so a slightly wider status block still clears its neighbour */
  .statuses{max-width:12.5rem}
  .entity .einfo{margin-top:0.15rem}
  .class-res{left:calc(100% - 1.2rem);top:0;gap:0.4rem}
  .construct-row{padding-bottom:14.7rem;margin-left:0.2rem}
  /* the bar is a slim strip (the reference is Slay the Spire's phone HUD):
     small content, tight edges, the arena gets the height back */
  .topbar{min-height:2.7rem;height:auto;gap:0.5rem;padding:0.2rem calc(0.8rem + env(safe-area-inset-right)*0.45) 0.2rem calc(0.8rem + env(safe-area-inset-left)*0.45)}
  /* portrait: its frame drops from 2px bronze to the same 1px hairline every
     other chip wears */
  .topbar .tb-portrait{width:2.2rem;height:2.2rem;border-radius:0.4rem;border-width:1px}
  .topbar .tb-name{font-size:max(.85rem,12px)}
  /* one shared chip geometry: an EXPLICIT height for gold, act, timer and
     deck — the deck chip is a <button> and real button UA metrics made it
     taller than its neighbours no matter how the padding matched */
  .stat{font-size:max(.75rem,11px);padding:0 0.5rem;height:max(1.7rem,23px);line-height:1;gap:0.3rem}
  .stat .ic{width:0.95rem;height:0.95rem}
  .deck-chip .ic{width:0.9rem;height:0.9rem}
  .deck-chip .deck-n{font-size:max(.8rem,12px)}
  .hpbar{width:9.5rem;height:max(1.05rem,15px)}
  .hpbar span{font-size:max(.68rem,10px)}
  /* the gear glyph keeps its size; only its invisible box slims down so it
     stops dictating the bar's height */
  .topbar .icon-btn{width:max(2.2rem,32px);height:max(2.2rem,32px);font-size:max(1.2rem,17px)}
  /* bottom corners, Slay-the-Spire order: [draw][energy] on the left,
     [End Turn][discard][exhaust] on the right, all on one baseline */
  .hand-zone{left:10.5rem;right:20rem}
  /* 0.85rem centres the pile icons on the energy orb / End Turn baseline —
     at 0.25rem they rode ~5px lower than everything else in the corner row */
  .pile{bottom:0.85rem}
  /* a clear step between the pile icons and the orb / End Turn — at 0.3rem of
     gap the corner clusters read as one clump (user 2026-08-08) */
  .energy-orb{left:calc(5.7rem + env(safe-area-inset-left)*0.45);bottom:0.35rem;
    width:5.2rem;height:5.2rem}
  .energy-orb .etext b{font-size:max(2rem,22px)}
  .endturn{right:calc(10rem + env(safe-area-inset-right)*0.45);bottom:1rem}
  .endturn .btn{padding:.5em .9em;font-size:max(.8125rem,12px)}
  .tl-strip{bottom:11rem;max-width:96vw;overflow-x:auto}
  #toast-layer{top:2.8rem}
  /* character select must scroll, not clip, at 400px of height */
  .select-screen{overflow-y:auto;padding:0.6rem 1.2rem}
  .select-banner{margin:0 0 0.6rem}
  .select-banner .sb-title{font-size:1.4rem}
  .select-banner .sb-sub{font-size:max(.6875rem,10px)}
  /* cover-cropped bust art needs a window no wider than ~1.7:1 or only the
     scalp survives the crop. 874px wide falls under the 880px two-column
     rule, whose 390px-wide cells are hopeless — keep four narrow columns
     and floor the height instead; the screen already scrolls */
  .char-grid{grid-template-columns:repeat(4,minmax(0,1fr))}
  .char-portrait{height:max(7rem,120px)}
  .char-card{min-height:0}
  .char-card .cc-blurb{min-height:0}
  .btn.cm-btn{height:2.6rem;min-width:9rem}
  /* The champion is the subject of this screen and was the smallest thing on
     it — a 4rem thumbnail beside three big pack panels. Bigger portrait, and
     the packs give up the room: tighter padding, smaller type, and blurbs held
     to TWO lines (user, 2026-08-04). Two lines is also what makes the tallest
     champion — the Mage, whose pack names and blurbs run longest — fit inside
     402px of landscape instead of running off the bottom. */
  .cm-portrait{width:5.6rem;height:5.6rem}
  .cm-head{margin:0 0 8px;gap:0.8rem}
  .cm-hp{font-size:max(0.8125rem,11px)}
  .char-modal-body .pack{padding:0.62rem 0.7rem}
  .pack h3{font-size:max(0.95rem,13px)}
  .pack .pk-style{font-size:max(0.6875rem,10px);margin:1px 0 0.35rem}
  .pack .pk-desc{font-size:max(0.75rem,11px);line-height:1.45;
    -webkit-line-clamp:2;min-height:calc(1.45em * 2)}
  .pack .pk-relic-row{padding-top:0.45rem}
  .pack .pk-relic-icon{width:1.7rem;height:1.7rem;flex:0 0 1.7rem}
  .pack .pk-relic-name{font-size:max(0.7188rem,11px)}
  .pack .pk-relic-desc{font-size:max(0.6875rem,10px);line-height:1.4;min-height:calc(1.4em * 2)}
  .asc-bar{margin:0.6rem 0 0.15rem;padding:0.5rem 0.8rem 0.6rem}
  .asc-row{margin:0.45rem 0 0}
  .packs{gap:0.7rem}
}

/* mobile hold preview: the enlarged copy of the held card, anchored above the
   card itself (JS sets left/top), keyword panel riding to the right — the
   hand card itself never changes size */
.card-touch-preview{position:fixed;z-index:1500;pointer-events:none;
  display:flex;align-items:flex-start;gap:0.5rem}
.card-touch-preview .ctp-card{flex:0 0 auto}
.card-touch-preview .card{margin:0!important;box-shadow:0 18px 60px rgba(0,0,0,.8)}
.ctp-kws{flex:0 0 auto;max-width:13rem;min-width:7rem;
  background:rgba(10,10,18,.94);border:1px solid var(--gold-deep);border-radius:0.5rem;
  padding:0.5rem 0.6rem;box-shadow:0 10px 30px rgba(0,0,0,.6)}
.ctp-kws h4{font-family:var(--font-display);font-size:max(.75rem,11px);color:var(--gold);margin:0 0 2px}
.ctp-kws h4~h4{margin-top:0.5rem}
.ctp-kws div{font-size:max(.7rem,10px);color:var(--ink-dim);line-height:1.35}

/* tap/click-to-inspect: an enlarged card in a centred modal (deck and pile
   viewers). The wrapper carries the scaled size so the modal fits it exactly;
   the scale itself is set inline by G.cardZoom from the live rem. */
.deck-grid .card{cursor:zoom-in}
.card-zoom-body{display:flex;gap:1.25rem;align-items:center;padding:0.5rem 0.25rem 0}
.card-zoom{flex:0 0 auto}
.card-zoom .card{transition:none}
.card-zoom-kws{flex:0 1 auto;max-width:14rem;min-width:8rem;border-left:1px solid var(--gold-deep);padding-left:0.875rem}
.card-zoom-kws h4{font-family:var(--font-display);font-size:max(.8rem,12px);color:var(--gold);margin:0 0 2px}
.card-zoom-kws h4~h4{margin-top:0.6rem}
.card-zoom-kws div{font-size:max(.75rem,11px);color:var(--ink-faint);line-height:1.4}

/* relic / potion inspect modal (touch tap on the tray) — same content as the
   hover tooltip, but centred and dismissed by the X */
/* The touch modal reuses the popover markup, so these only bump sizes for a
   finger and leave room for the close X. They must track .tip-card / .tip-body /
   .tip-kw — the old rules still named .tip-main and .tip-kws h5, which the
   single-column redesign removed, so none of them applied any more. */
.item-modal-body{max-width:min(26rem,84vw);padding-top:0.25rem}
.item-modal-body .tip-card{padding:0}
/* keep the title clear of the close button */
.item-modal-body .tip-head{padding-right:2.75rem}
.item-modal-body .tip-icon{width:2.875rem;height:2.875rem}
/* shop purchase popup: the ware's picture is the subject, not a thumbnail */
.item-modal-big .tip-icon{width:max(5.5rem,64px);height:max(5.5rem,64px)}
.item-modal-body h4{font-size:max(1.0625rem,15px);line-height:1.15}
.item-modal-body .tip-rar{font-size:max(0.625rem,10px)}
.item-modal-body .tip-body{font-size:max(0.875rem,13px);line-height:1.5}
.item-modal-body .tip-kws{gap:0.5rem;margin-top:0.75rem;padding-top:0.625rem}
.item-modal-body .tip-kw{font-size:max(0.8125rem,12px);line-height:1.45;padding-left:0.625rem}
.item-modal-body .tip-kw b{font-size:max(0.8438rem,12px)}
/* the close X is a 38px square, under the 44px minimum a finger wants — give it
   the extra on coarse pointers only, so the desktop chrome stays as designed */
@media (pointer:coarse){
  .modal-x{width:2.875rem;height:2.875rem;top:0.625rem;right:0.625rem;font-size:1.375rem}
  .item-modal-body .tip-head{padding-right:3.25rem}
}
