:root{--bg:#1e1e19;--panel:#2a2a24;--ink:#eee;--dim:#8d8d82;--acc:#d6ff2e;--hot:#ff5f8a;--gold:#ffc94d;--blue:#4fc3f7}
*{box-sizing:border-box}html{overscroll-behavior-y:none;overflow-x:hidden;overflow-x:clip}body{overscroll-behavior-y:none;margin:0;background:var(--bg);color:var(--ink);font:16px/1.35 -apple-system,system-ui,sans-serif;min-height:100vh;min-height:100dvh;min-height:-webkit-fill-available;display:flex;flex-direction:column;align-items:center;overflow-x:hidden;overflow-x:clip}
/* ---- header: app bar (menu · title · character) + run rail (XP/Gold/Match/Set) + tab switcher ---- */
header{width:100%;max-width:1240px;display:flex;flex-direction:column;gap:10px;padding:10px 18px 0;padding-top:calc(10px + env(safe-area-inset-top))}
.appbar{position:relative;display:flex;align-items:center;gap:12px;min-height:44px}
/* A double tap anywhere used to zoom the whole page — and the end of a battle is exactly when a
   thumb taps twice in a row. manipulation keeps panning and the tree's own pinch, and drops the
   double-tap zoom the game never wanted. */
body{touch-action:manipulation}
button,.die,.card,.fig,a{touch-action:manipulation}
h1{font-size:16px;font-weight:800;letter-spacing:.07em;margin:0;flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.charchip{display:flex;align-items:center;gap:8px;background:var(--panel);border:1px solid #3d3d34;color:var(--ink);font:inherit;font-size:13px;font-weight:700;border-radius:12px;padding:3px 12px 3px 3px;min-height:42px;flex:0 0 auto;max-width:46%;white-space:nowrap;overflow:hidden}
.charchip .ava{display:flex;align-items:center;justify-content:center;background:#1e1e19;border-radius:9px;padding:2px 5px;line-height:0;flex:0 0 auto}
.charchip:hover{border-color:#5a5a4c}
/* the portrait is a status badge, not a settings button: the ring is the class */
.charchip[data-c]{border-color:color-mix(in srgb,var(--cls,#5a5a4c) 55%,#3d3d34);
 box-shadow:0 0 0 2px var(--cls,#5a5a4c),0 0 16px -5px var(--cls,#5a5a4c)}
.charchip[data-c="cleric"]{--cls:#ffd98a}
.charchip[data-c="wizard"]{--cls:#9b8cff}
.charchip[data-c="barbarian"]{--cls:#ff7a5f}
.charchip[data-c="ranger"]{--cls:#6ddf8f}
.charchip[data-c="paladin"]{--cls:#7fd0f5}
.charchip[data-c="rogue"]{--cls:#c17aff}
.charchip.bump{animation:statbump .35s ease-out}@keyframes statbump{40%{transform:scale(1.08)}}
.runrail{display:flex;align-items:stretch;gap:1px;background:#3a3a32;border:1px solid #3a3a32;border-radius:12px;overflow:hidden;font-variant-numeric:tabular-nums}
.runrail .cell{background:var(--panel);padding:5px 10px 6px;min-width:0;flex:0 0 auto}
/* set progress lives here as pips, not as another label+number cell */
.pips{flex:1 1 auto;display:flex;align-items:center;justify-content:flex-end;gap:5px;background:var(--panel);padding:5px 12px;min-width:0}
.pips i{flex:0 0 auto;width:9px;height:9px;border-radius:50%;background:#3f3f36;box-shadow:inset 0 1px 0 rgba(255,255,255,.06)}
.pips i.on{background:#c17aff}
.pips i.cur{background:#efe2ff;box-shadow:0 0 9px rgba(193,122,255,.85)}
.runrail .cell span{display:block;font-size:12px;letter-spacing:.07em;color:var(--dim);line-height:1.15}
.runrail .cell b{font-size:20px;font-weight:800;color:var(--ink);line-height:1.15;display:inline-block}
.runrail .cell i{font-style:normal;font-size:13px;color:var(--dim)}
.runrail .cell:first-child b{color:var(--acc)}
.runrail .cell.g b{color:var(--gold)}
.runrail b.pop{animation:scorepop .45s ease-out}
.hamburger{background:var(--panel);border:1px solid #3d3d34;width:44px;height:44px;min-width:44px;border-radius:12px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;flex:0 0 auto}
.hamburger i{display:block;width:18px;height:2px;background:var(--ink);border-radius:2px;transition:transform .18s,opacity .18s}
.hamburger:hover{border-color:#5a5a4c}
.hamburger[aria-expanded="true"]{background:#3a3a32;border-color:var(--acc)}
.hamburger[aria-expanded="true"] i:nth-child(1){transform:translateY(6px) rotate(45deg)}
.hamburger[aria-expanded="true"] i:nth-child(2){opacity:0}
.hamburger[aria-expanded="true"] i:nth-child(3){transform:translateY(-6px) rotate(-45deg)}
#navScrim{position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:24}
.navmenu{position:absolute;left:0;top:calc(100% + 6px);background:var(--panel);border:1px solid #444;border-radius:14px;padding:6px;z-index:25;display:flex;flex-direction:column;gap:2px;min-width:190px;box-shadow:0 12px 32px rgba(0,0,0,.5)}
.navmenu.hidden,#navScrim.hidden{display:none}
.nmhead{font-size:12px;letter-spacing:.09em;text-transform:uppercase;color:var(--dim);padding:6px 12px 4px}
.navmenu button{background:transparent;color:var(--ink);text-align:left;padding:0 12px;border-radius:9px;min-height:46px;font-size:15px;font-weight:600;width:100%}
.navmenu button:hover{background:#3a3a32}
.navmenu button.on{color:var(--acc);background:#33332c}
/* abandoning a run has no undo, so the item asks twice and turns the colour of the answer */
.navmenu button.nmwarn{color:var(--hot)}
.navmenu button.nmwarn.arm{background:color-mix(in srgb,var(--hot) 18%,transparent);font-weight:800}
/* your own portrait in the party sheet is a button: it opens the class picker */
/* ---------- the armoury: a second counter under the companions ----------
   Same card shape as a companion so nothing new has to be learned, with a warm forge rule above it
   so the eye knows it has crossed into a different kind of purchase. */
.armoury{margin-top:14px;padding-top:12px;border-top:1px solid #3d3a30}
.armoury .pshophead{color:var(--gold)}
.gearrack{grid-template-columns:minmax(0,1fr) !important;max-width:280px;margin-inline:auto}
.card.gear{border-color:#5a4a28}
.card.gear .r{color:var(--gold);border-color:#5a4a28}
.card.gear .pr{color:var(--gold)}
.card.gear button.pr{background:none;border:1px solid var(--gold);border-radius:8px;padding:4px 8px;
 font:inherit;font-size:12px;font-weight:800;letter-spacing:.04em;width:100%;margin-top:6px}
.card.gear button.pr:disabled{opacity:.45;border-color:#5a4a28}
.card.gear.uncommon{border-color:#4f8c5e}.card.gear.uncommon .r{color:#7fd39a;border-color:#4f8c5e}
.card.gear.rare{border-color:#4f7fd6}.card.gear.rare .r{color:#8fc4ff;border-color:#4f7fd6}
.gnone{color:var(--dim);font-size:12px;text-align:center;padding:14px 10px;line-height:1.5}
.shelfrow.gearworn .fig{border-color:#5a4a28}
/* A mystery is a mystery: no name, no art, no effect, and no hint at what would unlock it. What is
   left is the shape of the collection — how many, at what rarity — so the grid still reads as a set
   with gaps rather than a blank wall. */
.pcard.mystery .ic.q{opacity:.5}
.pcard.mystery .tx b{color:var(--dim)}
.pcard.mystery .a{color:var(--faint,#6c705a);font-size:11px}
.hcard .a{color:var(--dim);font-size:11px}
/* the Artifacts page: fifty-four pieces, by class, and what the locked ones want */
.gclshead{font-size:12px;font-weight:800;letter-spacing:.12em;text-transform:uppercase;color:var(--dim);
 margin:22px 0 8px;padding-top:12px;border-top:1px solid #33332c}
.gclshead.mine{color:var(--gold)}
.collnote{color:var(--dim);font-size:13px;line-height:1.5;margin:0 0 6px;max-width:62ch}
.pcard.gcard .gstate{display:block;font-size:11px;font-weight:700;letter-spacing:.04em;margin-top:4px;color:var(--dim)}
.pcard.gcard .gstate.had{color:var(--acc)}
.pcard.gcard .gstate.open{color:var(--gold)}
.pcard.gcard.had{border-color:#4a5a28}
/* whose companion this is, on the party shelf */
.pshop .fig .pwho{display:block;font-style:normal;font-size:10px;font-weight:700;letter-spacing:.09em;
 text-transform:uppercase;color:var(--pc,var(--dim));margin-top:3px}
.pme .pav.tap{cursor:pointer}
.pme .pav.tap:hover{box-shadow:0 0 0 2px var(--acc)}
main{width:100%;max-width:1240px;padding:6px 18px calc(40px + env(safe-area-inset-bottom));display:grid;grid-template-columns:240px minmax(0,1fr) 240px;gap:18px;align-items:start}
main.treeMode{grid-template-columns:1fr}main.treeMode #partySide,main.treeMode #feed{display:none}main.treeMode #game{width:100%}
#game{display:flex;flex-direction:column;align-items:center;gap:14px;min-width:0}
#feed{display:flex;flex-direction:column;gap:6px;font-size:13px;position:sticky;top:12px;max-height:calc(100vh - 24px);overflow:hidden}
#feed .t{background:var(--panel);border-left:3px solid var(--gold);padding:7px 10px;border-radius:6px;color:#ddd;animation:tin .25s ease-out}#feed .t.boss{border-left-color:var(--hot)}#feed .t.good{border-left-color:var(--acc)}#feed .t.dim{opacity:.55}
@keyframes tin{0%{opacity:0;transform:translateX(8px)}100%{opacity:1;transform:none}}
/* below 900px the layout is one column, so the feed drops under the play UI and reads as
   a standing list there: newest on top, 8 deep, older entries dim, nothing auto-dismisses */
/* The feed is a log, and it used to be an unbounded one: eight messages after a battle stretched
   the page by four hundred pixels, so every round end reflowed the whole phone — which reads as
   the interface reloading itself. It is a fixed box now and scrolls inside; the page height does
   not move whatever happens in it. */
@media(max-width:99999px){main{grid-template-columns:1fr}#partySide{display:none}#feed{position:static;margin:14px 0 10px;padding-top:12px;border-top:1px solid #33332c;height:118px;max-height:none;overflow-y:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch}}
#play{display:flex;flex-direction:column;align-items:center;gap:14px;width:100%}
.hidden{display:none!important}
.shelf{display:flex;gap:8px;flex-wrap:wrap;justify-content:center;max-width:760px}.shelf:empty{display:none}
.fig{background:var(--panel);border:1px solid #444;border-radius:10px;padding:5px 10px;font-size:12px;display:flex;gap:8px;align-items:center;position:relative}.fig .ic{font-size:20px}.fig b{display:block;font-size:12px}.fig span{color:var(--dim)}.fig .x{position:absolute;top:-6px;right:-6px;background:#333;color:#ccc;border-radius:50%;width:18px;height:18px;font-size:11px;line-height:18px;text-align:center;cursor:pointer;display:none}.fig:hover .x{display:block}
.fig.rare{border-color:var(--blue)}.fig.legendary{border-color:var(--gold)}
.fig.pulse{animation:figpulse .5s ease-out}@keyframes figpulse{0%{transform:scale(1)}40%{transform:scale(1.14)}100%{transform:scale(1)}}
.fig.dim2{opacity:.45}
.fig .stag{position:absolute;left:50%;bottom:-16px;transform:translateX(-50%);background:#222;border:1px solid var(--blue);color:var(--blue);font-size:11px;font-weight:700;padding:1px 6px;border-radius:8px;animation:flup 1.1s ease-out forwards;white-space:nowrap;z-index:6}
.fig .stag.m{border-color:var(--hot);color:var(--hot)}
/* Sheets stand above the sticky header (40): draft 60, death 75, character picker 80.
   #draft used to sit at 20, so the header covered its heading and the page — not the sheet —
   took the scroll, which on a phone is a pull-to-refresh away from throwing the run out. */
#draft{position:fixed;inset:0;background:rgba(0,0,0,.75);display:flex;align-items:center;justify-content:center;z-index:60;overflow:auto;overscroll-behavior:contain}
.draftbox{background:var(--panel);padding:22px 26px;border-radius:16px;text-align:center;max-width:760px;margin:auto}.draftbox h2{margin:0 0 4px;font-size:20px}.draftbox .next{color:var(--dim);font-size:13px;margin:0 0 14px}
.cards{display:flex;gap:14px;justify-content:center;flex-wrap:wrap}.card{width:200px;background:#33332c;border:2px solid #555;border-radius:14px;padding:16px 12px;cursor:pointer;transition:transform .12s,border-color .12s}.card:hover{transform:translateY(-6px);border-color:var(--acc)}.card .ic{font-size:44px;line-height:1.2}.card b{display:block;margin:8px 0 4px;font-size:15px}.card span{font-size:13px;color:var(--dim)}.card .r{font-size:10px;letter-spacing:.1em;text-transform:uppercase;color:var(--dim);margin-top:8px}.card.rare{border-color:#2a7fa6}.card.legendary{border-color:#8a6d1f}
.card.sel{border-color:var(--acc);transform:translateY(-6px)}.shelfrow{display:flex;gap:8px;flex-wrap:wrap;justify-content:center}.shelfrow .fig{padding:6px 10px}.shelfrow .fig.pickable{cursor:pointer;border-color:var(--acc)}.sell{background:#3a3a32;color:var(--gold);font-size:11px;padding:3px 7px;border-radius:6px;margin-left:4px}.fig .ic img{display:block}.card .ic{line-height:0;display:flex;justify-content:center;margin-bottom:6px}
.unlrow{display:flex;gap:6px;flex-wrap:wrap;justify-content:center;max-width:700px;margin:0 auto}.unl-b{background:#33332c;color:var(--ink);font-size:12px;padding:6px 10px;border-radius:8px;border:1px solid #555}.unl-b b{color:var(--gold)}.unl-b.poor{opacity:.4}
/* run over: its own owned screen. Opaque, tappable, dismissed only by the
   player — the next run's board is not painted until they say go. */
#died{position:fixed;inset:0;background:radial-gradient(120% 70% at 50% 8%,#2c1a20 0%,#191914 52%,#101010 100%);
 display:flex;align-items:center;justify-content:center;z-index:75;overflow:auto;overscroll-behavior:contain;
 padding:24px 20px calc(24px + env(safe-area-inset-bottom));animation:diedin .3s ease-out}
@keyframes diedin{from{opacity:0}to{opacity:1}}
.diedbox{width:100%;max-width:460px;margin:auto;display:flex;flex-direction:column;align-items:stretch;gap:16px;text-align:center}
#died b.dt{font-size:min(15vw,86px);font-weight:900;letter-spacing:.08em;line-height:1;color:var(--hot);text-shadow:0 0 34px rgba(255,95,138,.55);animation:diedpop .5s cubic-bezier(.2,1.4,.4,1)}
#died.won{background:radial-gradient(120% 70% at 50% 8%,#29331d 0%,#191914 52%,#101010 100%)}
#died.won b.dt{font-size:min(11vw,64px);color:var(--gold);text-shadow:0 0 34px rgba(232,190,72,.4)}
#died .runline{color:var(--dim);font-size:14px;letter-spacing:.06em;text-transform:uppercase;font-weight:700}
.dstats{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}
.dstat{background:linear-gradient(170deg,#2b2b24,#212119);border:1px solid #3a3a32;border-radius:12px;padding:10px 12px;text-align:left}
.dstat span{display:block;font-size:11px;font-weight:800;letter-spacing:.11em;color:var(--dim)}
.dstat b{display:block;font-size:22px;font-weight:800;color:var(--ink);line-height:1.2;font-variant-numeric:tabular-nums}
.dstat.w b{color:var(--acc)}
.dstat.g b{color:var(--gold)}
#diedGo{width:100%;min-height:56px;font-size:19px;font-weight:900;letter-spacing:.08em;border-radius:14px;
 background:var(--acc);color:#191905;box-shadow:0 5px 0 #8aa800}
@keyframes diedpop{0%{transform:scale(.3);opacity:0}100%{transform:scale(1);opacity:1}}
.skip{margin-top:14px;background:transparent;color:var(--dim);text-decoration:underline}.rr{margin-top:14px;background:#3a3a32;color:var(--gold);padding:8px 14px}.card .pr{margin-top:6px;color:var(--gold);font-weight:700}.card.poor{opacity:.45;cursor:default}.card.poor:hover{transform:none;border-color:#555}
/* score HUD: one panel. The live score is the only loud number on the screen;
   target and rolls are secondary type beside it, and the progress bar is the
   panel's bottom edge instead of a separate stacked bar. */
.hud{position:relative;display:flex;align-items:center;gap:12px;width:100%;max-width:640px;overflow:hidden;
 background:linear-gradient(175deg,#2f2f27 0%,#232320 100%);border:1px solid #3a3a32;border-radius:14px;
 padding:5px 14px 13px;overflow:hidden;font-variant-numeric:tabular-nums;
 box-shadow:inset 0 1px 0 rgba(255,255,255,.05)}
#scored{font-size:calc(var(--sfz,52px)*var(--sk,1));font-weight:900;min-width:1.6ch;line-height:1.04;letter-spacing:-.02em;color:var(--blue);transition:color .2s,text-shadow .2s;flex:0 0 auto}
#scored[data-len='5']{--sk:.9}#scored[data-len='6']{--sk:.8}#scored[data-len='7']{--sk:.72}#scored[data-len='8']{--sk:.64}#scored[data-len='9']{--sk:.56}
#scored.over{color:#6f6;text-shadow:0 0 22px rgba(110,255,110,.5)}
#scored.must{color:var(--gold);text-shadow:0 0 20px rgba(255,201,77,.45)}
.hsub{display:flex;flex-direction:column;line-height:1.12;flex:0 0 auto;min-width:0}
.hsub span{font-size:11px;font-weight:800;letter-spacing:.11em;color:var(--dim)}
.hsub b{font-size:20px;font-weight:800;color:#d3d3c4}
.hsub.hr{margin-left:auto;text-align:right;flex:0 1 auto;min-width:0}
.hud>*{min-width:0}
.hud .mg{font-style:normal;font-size:12px;font-weight:800;color:#6f6;flex:0 0 auto;white-space:nowrap}
#scored.pop,.hsub b.pop{animation:scorepop .45s ease-out}
@keyframes scorepop{0%{transform:scale(1)}40%{transform:scale(1.35)}100%{transform:scale(1)}}
#scored{transform-origin:left center}   /* it sits at the left edge: pop into the room, not off the page */
.bar i.over{background:#6f6}
.hud .bar{position:absolute;left:0;right:0;bottom:0;width:auto;max-width:none;height:8px;border-radius:0;background:#191914}
.bar{width:100%;max-width:640px;height:10px;background:#333;border-radius:5px;overflow:hidden;position:relative}.bar i{display:block;height:100%;background:var(--blue);width:0;transition:width .4s}
.bar .tick{position:absolute;top:0;bottom:0;width:3px;pointer-events:none}.bar .tick.t1{left:50%;background:rgba(255,255,255,.95)}
.board{display:grid;grid-template-columns:repeat(4,1fr);gap:14px;width:100%;max-width:640px}
.die{aspect-ratio:1;border-radius:12px;background:#4a4a3e;display:flex;align-items:center;justify-content:center;font-size:30px;font-weight:800;position:relative;user-select:none;cursor:pointer;transition:transform .15s,background .2s,border-color .2s;border:3px solid #5b5b4c;box-shadow:inset 0 2px 0 rgba(255,255,255,.09),inset 0 -4px 0 rgba(0,0,0,.28),0 4px 8px rgba(0,0,0,.35);text-shadow:0 2px 2px rgba(0,0,0,.4)}
.die small{position:absolute;right:7px;top:4px;font-size:10px;color:#a6a696;font-weight:600;text-shadow:none}
.die:hover{transform:translateY(-3px)}
.die.held{border-color:var(--gold);background:#5a4a22;transform:translateY(-4px)}
.die.held::after{content:'HOLD';position:absolute;bottom:4px;left:0;right:0;text-align:center;font-size:9px;color:var(--gold);letter-spacing:.1em}
.die.rolling{animation:tumble .45s ease-out}
@keyframes tumble{0%{transform:rotate(-25deg) scale(.7)}50%{transform:rotate(15deg) scale(1.1)}100%{transform:none}}

.die.scoring{background:var(--acc);color:#111;border-color:#fff;animation:pop .4s ease-out}
@keyframes pop{0%{transform:scale(.7)}60%{transform:scale(1.18)}100%{transform:scale(1)}}
.die.target-pick{border-color:var(--blue)}
/* --- flat dice: one solid face, a thin size accent, states shown by fill not depth --- */
.die{--dt:#9a9a86;background:#4a4a3e;border-color:#5c5c4c;box-shadow:none}
.die[data-f="20"]{--dt:#7fd0f5}
.die[data-f="12"]{--dt:#c17aff}
.die[data-f="10"]{--dt:#6ddf8f}
.die[data-f="8"]{--dt:#ffc94d}
.die[data-f="6"]{--dt:#ff8f6a}
.die[data-f="4"]{--dt:#d6ff2e}

.die small{color:var(--dt);opacity:.85;font-weight:700}
.die.inhand{border-color:#4fc3f7;background:#31505e;box-shadow:none}
.die.held{border-color:#ffc94d;background:#5a4a22;box-shadow:none;transform:translateY(-4px)}
.die.inhand.held{border-color:#ffc94d;background:#5a4a22;box-shadow:inset 0 0 0 2px rgba(79,195,247,.55)}
.die.scoring::before{opacity:0}
.die.frozen{background:#2a1d1d;color:#a55;border-color:#a33;cursor:not-allowed}.die.eaten{opacity:.3;text-decoration:line-through}
.die .fl{position:absolute;left:50%;top:-10px;transform:translateX(-50%);font-size:16px;font-weight:800;color:var(--blue);animation:flup 1s ease-out forwards;pointer-events:none;z-index:5;text-shadow:0 1px 3px #000}
.die .fl.m{color:var(--hot);top:-30px}
@keyframes flup{0%{opacity:0;transform:translate(-50%,6px)}20%{opacity:1}100%{opacity:0;transform:translate(-50%,-20px)}}
.fig.boss{border-color:var(--hot);background:#3a2228}
/* The boss arrives. It used to arrive by starting at scale(1.7) — on a row that is already the
   full width of the column, which made the DOCUMENT 506px wide on a 390px phone for 1.3 seconds.
   The page swung sideways and snapped back on every boss battle. Nothing that spans the column may
   ever scale above 1: the row fades and rises, and the scale lives on the portrait, which is 40px
   wide and nowhere near an edge. */
.fig.boss.intro{animation:bossin 1.3s cubic-bezier(.2,1.2,.3,1)}
@keyframes bossin{
 0%{opacity:0;transform:translateY(12px);box-shadow:0 0 44px rgba(255,95,138,.85)}
 55%{opacity:1;transform:translateY(0);box-shadow:0 0 30px rgba(255,95,138,.6)}
 100%{opacity:1;transform:translateY(0);box-shadow:none}}
.fig.boss.intro .ic{animation:bossart 1.3s cubic-bezier(.2,1.2,.3,1);transform-origin:left center}
@keyframes bossart{0%{transform:scale(1.7)}55%{transform:scale(1.25)}100%{transform:scale(1)}}
@media(prefers-reduced-motion:reduce){.fig.boss.intro,.fig.boss.intro .ic{animation:none}}.fig .life{font-size:11px;color:var(--dim);background:#222;border-radius:6px;padding:2px 6px;margin-left:4px}
/* near-expiry: pulsing red badge + a crack drawn over the sprite, readable without the number */
/* the sets-left badge on a fading companion holds still — the crack and the red say enough,
   and a pulse next to the dice pulls the eye off the board every second */
.fig.cracking .life{color:#fff;background:#8a2230;font-weight:800}
.fig.cracking{border:2px dashed var(--hot)}
.fig.cracking .ic{position:relative}
.fig.cracking .ic::after{content:'';position:absolute;inset:-2px;background:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 32'%3E%3Cpath d='M12 0 L10 7 L14 13 L9 20 L13 26 L11 32' fill='none' stroke='%23ff5f8a' stroke-width='1.6' opacity='.9'/%3E%3Cpath d='M10 7 L5 10 M14 13 L19 15 M9 20 L4 23 M13 26 L18 29' stroke='%23ff5f8a' stroke-width='1.1' fill='none' opacity='.65'/%3E%3C/svg%3E") center/contain no-repeat;pointer-events:none}
.fig.boss b{color:var(--hot)}
button{font:inherit;cursor:pointer;border:0;border-radius:12px}
.actions{display:flex;gap:12px;align-items:center;flex-wrap:wrap;justify-content:center}
#roll{background:var(--acc);color:#111;font-size:24px;font-weight:900;padding:14px 40px;box-shadow:0 6px 0 #8aa800;transition:transform .05s}
#roll:active{transform:translateY(4px);box-shadow:0 2px 0 #8aa800}
#score{background:#5a2a33;color:#caa;font-size:24px;font-weight:900;padding:14px 40px;box-shadow:0 6px 0 #3a1a20;transition:background .2s,color .2s}
#score.yellow{background:var(--gold);color:#111;box-shadow:0 6px 0 #a37f20}
#score.green{background:#6f6;color:#111;box-shadow:0 6px 0 #2e8f2e;animation:pulse 1s infinite}
@keyframes pulse{50%{filter:brightness(1.15)}}
#score:disabled{opacity:1!important;background:#7a2733;color:#dfa1ab;box-shadow:0 6px 0 #4c161f!important;cursor:default}
#score:active{transform:translateY(4px);box-shadow:0 2px 0 #2a7fa6}
button:disabled{opacity:.35;cursor:default;box-shadow:none!important;transform:none!important}
.card.sinkcard{border-color:#6a5a2a}.card.sinkcard:hover{border-color:var(--gold)}
.hand{min-height:52px;text-align:center}.hand .name{font-size:20px;font-weight:800}.hand .calc{color:var(--dim);font-size:14px}.hand .calc b{color:var(--ink)}.hand .calc .c{color:var(--blue)}.hand .calc .m{color:var(--hot)}
.hand .calc b.tick{animation:scorepop .3s ease-out}
.powers{display:flex;gap:8px;flex-wrap:wrap;justify-content:center;max-width:720px}
.pw{background:var(--panel);color:var(--ink);padding:8px 12px;border-radius:10px;border:1px solid #444;font-size:13px;text-align:left;max-width:230px}.pw b{color:var(--gold)}.pw i{display:block;color:var(--hot);font-style:normal;font-size:12px}
.tree{width:100%;max-width:1100px;display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;align-items:start}.branch.wide{grid-column:1/-1}.branch h3{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.branch{background:var(--panel);border-radius:12px;padding:12px}.branch h3{margin:0 0 8px;font-size:13px;color:var(--dim);text-transform:uppercase;letter-spacing:.06em}
.node{display:grid;grid-template-columns:1fr auto auto;align-items:center;gap:10px;padding:6px 10px;margin:4px 0;border-radius:8px;background:#33332c;font-size:13px;white-space:nowrap}.node .nm{overflow:hidden;text-overflow:ellipsis}.node .lv{display:inline-flex;gap:3px;margin-left:8px;vertical-align:middle}.node .lv i{width:7px;height:7px;border-radius:50%;background:#555;display:inline-block}.node .lv i.on{background:var(--acc)}.node .lv i.act{box-shadow:0 0 0 2px rgba(214,255,46,.35)}.node .st{color:var(--dim);font-size:11px;min-width:0}.node .st.act{color:var(--acc)}.node .uses{color:var(--dim);font-size:11px;margin-left:8px}.node.hrow{grid-template-columns:minmax(0,1fr) 90px 60px auto 150px}.node.hrow .lvpill{margin-left:0;text-align:center}.node.hrow .uses{margin-left:0}.node.hrow button{justify-self:end}.node.hrow .st{justify-self:end}
.lvpill{display:inline-block;margin-left:10px;padding:1px 7px;border-radius:10px;font-size:11px;font-weight:800;letter-spacing:.04em;background:#444;color:#bbb;vertical-align:middle}.lvpill.up{background:var(--acc);color:#111}.lvpill.idle{background:#4a4a2a;color:var(--gold)}
.node.owned{background:#3d4a1a}.node.hdr{background:transparent;color:var(--dim);font-size:11px;text-transform:uppercase;letter-spacing:.06em;padding:2px 10px;margin:0}.node.hdr span{text-align:center}.node.hdr .nm{text-align:left}.node .cost{color:var(--acc);font-weight:700;white-space:nowrap}.node.far{opacity:.4}
.node button{background:var(--acc);color:#111;font-weight:700;padding:4px 8px;border-radius:6px}.node button.act{background:var(--gold)}
/* segmented switcher: two halves of one control, not two floating pills */
.tabs{display:flex;gap:4px;background:#23231e;border:1px solid #34342c;border-radius:12px;padding:4px}
.tabs button{flex:1 1 0;min-width:0;background:transparent;color:var(--dim);border:1px solid transparent;border-radius:9px;min-height:38px;font-size:13px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}
.tabs button.on{color:var(--ink);background:#3a3a32;box-shadow:inset 0 1px 0 rgba(255,255,255,.07)}
.tabs button.glow{border-color:rgba(255,201,77,.55);box-shadow:0 0 14px rgba(255,201,77,.25);color:var(--gold)}
.hands{color:var(--dim);font-size:12px;max-width:560px;text-align:center;line-height:1.6}
.gameover{background:var(--panel);padding:18px 24px;border-radius:14px;text-align:center;max-width:560px}.gameover h2{margin:0 0 6px}
/* per-trunk banners: an accent top edge + colored marker so the five trunks read as distinct zones */
.branch{border-top:3px solid #444}
.branch h3::before{content:'';display:inline-block;width:8px;height:8px;border-radius:2px;margin-right:7px;vertical-align:baseline;background:#666}
.branch.b-faces{border-top-color:var(--acc)}.branch.b-faces h3::before{background:var(--acc)}
.branch.b-weight{border-top-color:var(--hot)}.branch.b-weight h3::before{background:var(--hot)}
.branch.b-rolls{border-top-color:var(--blue)}.branch.b-rolls h3::before{background:var(--blue)}
.branch.b-figs{border-top-color:var(--gold)}.branch.b-figs h3::before{background:var(--gold)}
.branch.b-hands{border-top-color:#b48cff}.branch.b-hands h3::before{background:#b48cff}
/* mid-set gold buys wait for the next set: labeled, not just dimmed like an empty purse */
.node button.act.wait{background:#3a3a32;color:#c9b061;border:1px dashed #6a5a2a;opacity:.85}
/* ---- spatial skill-tree graph: five 72° trunks, depth rings r1–r6, pan/zoom, hover card ---- */
#treeSec{width:100%;max-width:1100px;display:flex;flex-direction:column;gap:14px;margin:0 auto}
#treeView{position:relative;width:100%;height:min(70vh,640px);background:#20201b;border:1px solid #3a3a32;border-radius:14px;overflow:hidden;cursor:grab;touch-action:none}
#treeView.drag{cursor:grabbing}
#treeWorld{position:absolute;left:0;top:0;transform-origin:0 0;z-index:1}
#treeEdges{position:absolute;left:0;top:0}
#treeEdges circle.ring{fill:none;stroke:#2b2b24;stroke-width:2}
#treeEdges path.wedge{opacity:.04}
#treeEdges text.trunkword{font-size:72px;font-weight:900;letter-spacing:.3em;opacity:.11;text-anchor:middle;dominant-baseline:middle;font-family:inherit}
/* Roads read at the weight of what they lead to. The one you lit this battle is the bright one;
   everything else is structure, drawn so the map is legible and no louder than that. */
#treeEdges line.edge{stroke:#45453a;stroke-width:3;opacity:.35}
#treeEdges line.edge.unl{stroke-width:4;opacity:.3}
#treeEdges line.edge.lit{stroke-width:5;opacity:1;filter:drop-shadow(0 0 4px rgba(255,255,255,.35))}
#treeEdges line.edge.cross{stroke:#6a5a2a;stroke-width:2;stroke-dasharray:7 5;opacity:.3}
#treeEdges line.edge.cross.usable{stroke:var(--gold);stroke-dasharray:none;opacity:.35}
#treeEdges line.edge.cross.lit{opacity:1}
#treeEdges line.edge.excl{stroke:#a03040;stroke-width:2;stroke-dasharray:4 6;opacity:.3}
/* a branch this run did not pick: its roads go quiet too, or the map still reads as full */
#treeEdges line.edge.shut{opacity:.08;stroke-width:2}
#treeEdges text.trunkword.shut{opacity:.035}
.mouthcls{position:absolute;transform:translate(-50%,-50%);opacity:.5;pointer-events:none;line-height:0}
.mouthcls.me{opacity:1;filter:drop-shadow(0 0 6px rgba(255,255,255,.4))}
.tnode{position:absolute;transform:translate(-50%,-50%);width:64px;height:64px;border-radius:50%;background:#2b2b24;border:3px solid #4c4c40;display:flex;align-items:center;justify-content:center;cursor:pointer;user-select:none;transition:border-color .15s,box-shadow .15s,opacity .15s}
.tnode .ic{font-size:15px;font-weight:900;color:#bdbdb0}
.tnode .lbl{position:absolute;top:66px;left:50%;transform:translateX(-50%);width:118px;text-align:center;font-size:10px;line-height:1.25;color:#a5a599;pointer-events:none;text-shadow:0 1px 2px #000}
.tnode .price{display:none;position:absolute;bottom:-8px;left:50%;transform:translateX(-50%);background:#1e1e19;border:1px solid #55554a;border-radius:8px;padding:0 6px;font-size:10px;font-weight:700;color:#bdbdb0;white-space:nowrap;pointer-events:none}
.tnode .pad{position:absolute;top:-8px;right:-5px;font-size:13px}
.tnode .chev{position:absolute;top:-15px;left:50%;transform:translateX(-50%) rotate(90deg);color:var(--tc);font-size:11px;font-weight:900;opacity:.9}
.tnode.locked{opacity:.45}
/* Only what you can act on right now carries any weight. A node you cannot buy or light yet is
   still drawn — the map has to read as a map — but it steps back, and its XP price does not show
   at all until you are zoomed right in on it. */
.tnode{opacity:.4}                       /* owned, not the frontier: it is behind you */
.tnode.lit{opacity:.62}                  /* the road you lit this battle still reads */
.tnode.quiet{opacity:.2;filter:saturate(.45)}   /* not yours yet and not reachable now */
.tnode.frontier{opacity:1;filter:none}   /* the edge of what you can reach: the only thing lit up */
.tnode.root{opacity:1}
.tnode:hover,.tnode.sel{opacity:1;filter:none}
#treeView.closezoom .tnode .price{display:block}
/* the four branches you did not light this run: still on the map, well out of the way */
.tnode.shut{opacity:.16;filter:saturate(.25)}
.tnode.shut:hover{opacity:.5}

.tnode.afford{border-color:var(--tc)} /* affordable to unlock: solid trunk-color ring… */
.tnode.afford .price{color:#111;background:var(--tc);border-color:var(--tc)} /* …+ filled XP pill */
.tnode.owned{border-color:var(--tc)}.tnode.owned .ic{color:var(--tc)} /* unlocked-unlit: ring */
.tnode.glow{box-shadow:0 0 18px rgba(255,201,77,.55)}.tnode.glow .price{color:var(--gold);border-color:var(--gold)} /* affordable to light: gold glow */
.tnode.lit{background:color-mix(in srgb,var(--tc) 30%,#2b2b24);box-shadow:0 0 20px color-mix(in srgb,var(--tc) 55%,transparent)} /* lit: bright core */
.tnode.lit .ic{color:#fff}.tnode.lit .price{color:var(--tc);border-color:var(--tc)}
.tnode.cap{width:84px;height:84px;border-width:4px}.tnode.cap .lbl{top:86px;font-weight:700}.tnode.cap .ic{font-size:24px}
.tnode.mastery{border-radius:16px}
.tnode.sel{border-color:#fff;box-shadow:0 0 0 3px rgba(255,255,255,.25),0 0 18px color-mix(in srgb,var(--tc) 50%,transparent)}
.tnode.root{width:56px;height:56px}
#nodeCard{position:absolute;left:12px;bottom:12px;max-width:340px;background:var(--panel);border:1px solid var(--tc,#555);border-left:4px solid var(--tc,#555);border-radius:12px;padding:12px 14px;z-index:40;pointer-events:auto;touch-action:auto}
#nodeCard b{display:block;font-size:14px;margin-bottom:2px}
#nodeCard .d{display:block;color:var(--dim);font-size:12px}
#nodeCard .row{margin-top:8px}
#nodeCard .warn{color:var(--hot);font-size:12px}
#nodeCard button{background:var(--acc);color:#111;font-weight:700;padding:6px 12px;border-radius:8px}
#nodeCard button.act{background:var(--gold)}
#nodeCard button.open{background:#ff5f8a}
#nodeCard .st{color:var(--dim);font-size:12px}#nodeCard .st.act{color:var(--acc)}
#treeClose{display:none}
#treeCenter{position:absolute;right:12px;top:12px;background:#33332c;color:var(--dim);font-size:16px;width:36px;height:36px;border-radius:10px;z-index:5}
/* hand-levels panel: the ONLY tabular part of the tree, opened from the Handbook node */
#handPanel{position:absolute;inset:12px;background:rgba(30,30,25,.97);border:1px solid rgba(255,95,138,.4);border-radius:12px;z-index:8;overflow-y:auto;padding:14px;-webkit-overflow-scrolling:touch}
#handPanelClose{position:absolute;right:10px;top:10px;background:#33332c;color:var(--dim);width:32px;height:32px;border-radius:8px;z-index:2}
#handPanel .hphead{display:flex;gap:14px;align-items:center;margin-bottom:8px;padding-right:44px}
#handPanel .hphead h3{margin:0;font-size:13px;color:#ff5f8a;letter-spacing:.06em}
#handPanel .hphead .st.act{color:var(--acc);font-size:12px}
#handPanel .hphead button{background:var(--gold);color:#111;font-weight:700;padding:5px 10px;border-radius:8px}
/* ---- lifetime stats page ---- */
.lgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:10px;margin-bottom:18px}
.ltile{background:var(--panel);border:1px solid #3a3a32;border-radius:10px;padding:12px}
.ltile b{display:block;font-size:22px;font-variant-numeric:tabular-nums}
.ltile span{font-size:11px;color:var(--dim)}
.lhands{display:grid;grid-template-columns:repeat(auto-fill,minmax(210px,1fr));gap:6px;margin-top:4px}
.lhand{display:flex;justify-content:space-between;background:var(--panel);border-radius:8px;padding:6px 10px;font-size:12px}
.lhand b{color:var(--gold);font-variant-numeric:tabular-nums}.lhand.zero{opacity:.45}
.lhandtable{display:flex;flex-direction:column;gap:4px;margin-top:4px}
.lhrow{display:grid;grid-template-columns:1fr 60px 70px;align-items:center;background:var(--panel);border-radius:8px;padding:6px 10px;font-size:12px}
.lhrow.lhhdr{background:transparent;color:var(--dim);text-transform:uppercase;letter-spacing:.06em;font-size:10px;padding:2px 10px}
.lhrow .nm{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.lhrow b{color:var(--gold);font-variant-numeric:tabular-nums;text-align:right}
.lhrow .pct{color:var(--dim);text-align:right;font-variant-numeric:tabular-nums}
.lhrow.zero{opacity:.4}
/* ---- collection pages: hands found + companion pool ---- */
.coll{width:100%;max-width:1100px;margin:0 auto}
.collhead{font-size:13px;color:var(--dim);letter-spacing:.06em;margin:4px 0 12px}
.hgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(190px,1fr));gap:10px}
.hcard{background:var(--panel);border:1px solid #3a3a32;border-radius:10px;padding:10px 12px;min-height:74px;display:flex;flex-direction:column;gap:3px}
.hcard b{font-size:13px}.hcard span{font-size:11px;color:var(--dim)}.hcard .u{color:var(--gold)}
.hcard:not(.found){opacity:.5}.hcard:not(.found) b{color:var(--dim)}
.hcard.found{border-color:#4a4a3e;border-left:3px solid #b48cff}
.pgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:10px}
.pcard{background:var(--panel);border:1px solid #444;border-radius:10px;padding:10px;display:flex;gap:10px;align-items:center}
.pcard .ic{flex:0 0 auto;line-height:0}.pcard .ic.q{width:48px;height:64px;display:flex;align-items:center;justify-content:center;font-size:28px;font-weight:900;color:#555;line-height:1}
.pcard .tx b{display:block;font-size:13px}.pcard .tx span{display:block;font-size:11px;color:var(--dim)}
.pcard .tx .r{text-transform:uppercase;letter-spacing:.08em;font-size:9px;margin-top:3px}
.pcard .tx .a{color:var(--gold)}
.pcard.rare{border-color:var(--blue);box-shadow:0 0 16px -7px var(--blue)}
.pcard.legendary{border-color:var(--gold);box-shadow:0 0 18px -6px var(--gold)}
.pcard{background:linear-gradient(165deg,#31312a 0%,#26261f 100%)}
.pcard.locked{opacity:.65;border-style:dashed}

/* desktop keeps the old shape: title left, stats right, switcher centred on its own line */
@media(min-width:99999px){
 header{flex-direction:row;flex-wrap:wrap;align-items:center;gap:10px 16px;padding-bottom:4px}
 .appbar{flex:1 1 300px}
 h1{flex:0 1 auto;font-size:18px}
 .charchip{margin-left:auto}
 .runrail{flex:0 0 auto}
 .pips{flex:0 0 auto;padding:5px 14px}
 .runrail .cell b{font-size:18px}
 .tabs{flex:1 0 100%;justify-content:center;background:transparent;border:0;padding:0;gap:12px}
 .tabs button{flex:0 0 auto;padding:0 22px;background:var(--panel)}
 .tabs button.on{background:#3a3a32}
 #navScrim{background:transparent}
}

/* ================================================================
   MOBILE PASS
   A) full-screen sheets for the modals (also fires on short desktop windows)
   B) the phone app shell: sticky header, hero board, thumb action bar
   Kept last so both blocks win the cascade over the desktop rules above.
   ================================================================ */
@media(max-width:99999px){
 #draft{align-items:stretch;justify-content:flex-start;padding:0}
 .draftbox{width:100%;max-width:none;height:100%;max-height:none;border-radius:0;padding:calc(14px + env(safe-area-inset-top)) 14px calc(14px + env(safe-area-inset-bottom));display:flex;flex-direction:column;overflow:hidden;margin:0}
 .draftbox h2{flex:0 0 auto;font-size:17px;line-height:1.3;margin:0 0 8px}
 .draftbox .next{flex:0 0 auto;font-size:13px;margin-bottom:12px}
 .draftbody{flex:1 1 auto;min-height:0;overflow-y:auto;-webkit-overflow-scrolling:touch;overscroll-behavior:contain;
  display:flex;flex-direction:column;align-content:flex-start}
 /* the character picker is a grid on its own: let it claim the whole sheet */
 .draftbody>.cards:only-child{flex:1 1 auto;align-content:stretch;grid-auto-rows:minmax(150px,1fr)}
 .draftbody>.cards{flex:0 0 auto}
 /* the shop's real decision is the shelf: the rows take the space the sheet had
    been leaving black between the last row and Done. It GROWS but never SHRINKS —
    shrinking is how the shelf once spilled onto the armoury counter below it; the
    sheet body scrolls instead. */
 .draftbody>.owned{flex:1 0 auto;display:flex;flex-direction:column}
 .draftbody>.owned .shelfrow{flex:1 1 auto;justify-content:flex-start}
 .draftbody>.owned .shelfrow .fig{flex:1 1 auto;min-height:56px;max-height:120px}
 .draftbody>.armoury{flex:0 0 auto}
 .draftbody::after{content:'';display:block;position:sticky;bottom:-1px;height:36px;margin-top:-36px;background:linear-gradient(rgba(42,42,36,0),var(--panel));opacity:0;transition:opacity .25s;pointer-events:none}
 .draftbody.more::after{opacity:1}
 .cards{display:grid;grid-template-columns:repeat(2,1fr);gap:10px}
 .cards .card:last-child:nth-child(odd){grid-column:1/-1}
 /* the shop's three offers ride in one row of narrow cards: the shelf — where
    the sheet's actual decision is made — has to be on screen without scrolling */
 .cards.offers{grid-template-columns:repeat(3,minmax(0,1fr));gap:7px}
 .cards.offers .card{padding:9px 6px 10px}
 .cards.offers .card:last-child:nth-child(odd){grid-column:auto}
 .cards.offers .card .ic{margin-bottom:2px}
  .cards.offers .card .ic img{max-width:48px;height:auto}
 .cards.offers .card .ic::before{width:56px;height:56px}
 .cards.offers .card b{font-size:13px;line-height:1.2;margin:6px 0 3px}
 .cards.offers .card span{font-size:12px;line-height:1.25}
 .cards.offers .card .r{font-size:11px;letter-spacing:.09em;margin-top:5px}
 .cards.offers .card .pr{font-size:14px;margin-top:4px}
 .card{width:auto;min-width:0;padding:12px 10px}
 .card:hover{transform:none;border-color:#555}
 .card.sel{border-color:var(--acc);transform:none;box-shadow:0 0 0 2px rgba(214,255,46,.3)}
 .card .ic img{max-width:68px;width:100%;height:auto}
 .card b{font-size:14px}
 .card span{font-size:13px;line-height:1.3}
 .card .r{font-size:12px;letter-spacing:.12em;margin-top:6px}
 .card .pr{margin-top:6px;font-size:15px}
 .owned{margin-top:6px}
 .shelfrow{flex-direction:column;align-items:stretch}
 .shelfrow .fig{width:100%}
 .fig{min-height:44px;padding:8px 10px}
 .sell{min-height:44px;padding:0 14px;font-size:13px;display:inline-flex;align-items:center;margin-left:auto;border-radius:9px}
 /* sheet footer: one full-width primary action, in the thumb arc */
 .skip{flex:0 0 auto;width:100%;margin:12px 0 0;padding:0;font-size:16px;font-weight:800;letter-spacing:.06em;min-height:54px;background:#3f3f36;color:var(--ink);border:1px solid #5a5a4c;border-radius:12px;text-decoration:none}
 #died{padding:18px 14px calc(18px + env(safe-area-inset-bottom))}
 #died .runline{font-size:13px}
 /* on a phone the sheet owns the screen: recap up top, one primary action in the thumb arc */
 .diedbox{gap:13px;min-height:100%}
 #diedGo{margin-top:auto}
 .dstat b{font-size:20px}
 .dstats{flex:1 1 auto;max-height:330px;grid-auto-rows:minmax(66px,1fr);align-content:stretch}
 .dstat{display:flex;flex-direction:column;justify-content:center;gap:3px}
}

@media(max-width:99999px){
 :root{--chrome:158px;--abar:calc(76px + env(safe-area-inset-bottom))}

 /* --- header: one sticky block, three tiers of loudness --- */
 header{position:sticky;top:0;z-index:40;background:var(--bg);gap:8px;padding:8px 12px 8px;padding-top:calc(8px + env(safe-area-inset-top));box-shadow:0 6px 14px -8px rgba(0,0,0,.8)}
 .appbar{min-height:44px;gap:8px}
 h1{font-size:12px;letter-spacing:.05em;color:#c8c8ba}
 .hamburger{width:44px;height:44px;min-width:44px;border-radius:12px;gap:3.5px}
 .hamburger i{width:17px}
 .charchip{min-height:44px;font-size:12px;max-width:42%;padding:3px 9px 3px 4px;gap:6px}
 .charchip .ava{padding:2px 3px;border-radius:8px}
 .charchip .ava img{width:16px!important;height:21px!important}
 .tabs{padding:3px;gap:3px}
 .tabs button{min-height:44px;font-size:12px;letter-spacing:.1em}

 /* --- menu: hamburger up top (standard, always on screen), the list itself
        opens as a bottom sheet so every row lands in the thumb arc --- */
 .navmenu{position:fixed;left:0;right:0;bottom:0;top:auto;min-width:0;border:0;border-top:1px solid #46463c;border-radius:18px 18px 0 0;padding:6px 10px calc(14px + env(safe-area-inset-bottom));box-shadow:0 -16px 44px rgba(0,0,0,.6);animation:sheetup .2s ease-out}
 @keyframes sheetup{from{transform:translateY(100%)}to{transform:none}}
 .navmenu::before{content:'';display:block;width:38px;height:4px;border-radius:2px;background:#55554a;margin:6px auto 2px}
 .nmhead{padding:6px 14px 4px}
 .navmenu button{min-height:54px;font-size:16px;padding:0 14px;display:flex;align-items:center}
 .navmenu button::after{content:'\203A';margin-left:auto;color:var(--dim);font-size:20px;line-height:1}
 .navmenu button+button{border-top:1px solid #33332c;border-radius:0}
 .navmenu button:last-child{border-radius:0 0 9px 9px}

 /* --- shell --- */
 main{padding:0 12px var(--abar);gap:0}
 main.treeMode{padding-left:0;padding-right:0;padding-bottom:0}
 #game{gap:0;width:100%}
 /* The tray asks for the height its rows need, so the column no longer fills the screen. It sits
    at the TOP: the readout belongs under the HUD, and floating the block down the screen left a
    band of nothing above it. */
 #play{gap:10px;align-items:stretch;justify-content:flex-start;min-height:calc(100dvh - var(--chrome) - var(--abar));padding-top:11px}

 /* --- score HUD --- */
 .hud{max-width:none}

 /* --- companion shelf: a one-row rail that scrolls sideways instead of
        wrapping and pushing the board off screen --- */
 /* companions wrap and stay centered. The sideways rail hid half the row off-screen
    AND its overflow clipped the info card, so a tap looked like it did nothing. */
 .shelf{display:flex;flex-wrap:wrap;justify-content:center;max-width:none;gap:8px;overflow:visible;margin:0;padding:1px 4px 4px}
 .shelf .fig{flex:0 0 auto;min-height:0;padding:6px 9px;gap:7px;border-radius:12px}
 .shelf .fig .ic img{width:24px!important;height:auto!important}
 .shelf .fig b{font-size:12px;line-height:1.2}
 .shelf .fig span{font-size:12px;line-height:1.2;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
 .shelf .fig .life{font-size:12px;padding:2px 7px}

 /* --- board is the hero: a play tray that takes every spare pixel, dice centred in it --- */
 .board{flex:1 1 auto;align-content:center;gap:10px;max-width:none;margin:0;padding:16px 12px;border-radius:20px;background:radial-gradient(125% 90% at 50% 32%,#2e2e25 0%,#25251e 55%,#1d1d18 100%);border:1px solid #36362d;box-shadow:inset 0 2px 0 rgba(255,255,255,.045),inset 0 -34px 56px -34px #000,0 10px 24px -16px #000}
 .die{border-radius:15px;font-size:33px}
 .die:hover{transform:none}
 .die.held:hover{transform:translateY(-6px)}
 .die small{font-size:12px;right:6px;top:4px;font-weight:700}
 .die.held::after{font-size:12px;bottom:4px;letter-spacing:.08em}
 /* hand readout gets HUD weight: name loud, points and mult as their own chips */
 .hand{min-height:60px;margin:0;display:flex;flex-direction:column;justify-content:center;gap:4px}
 .hand .name{font-size:22px;letter-spacing:.01em}
 .hand .calc{font-size:14px}
 .hand .calc b{padding:2px 9px;border-radius:8px;background:#33332c;font-weight:800}
 .hand .calc b.c{color:var(--blue);background:rgba(79,195,247,.14)}
 .hand .calc b.m{color:var(--hot);background:rgba(255,95,138,.14)}

 /* --- action bar: pinned to the bottom edge, two 56px targets --- */
 .actions{position:fixed;left:0;right:0;bottom:0;z-index:15;gap:10px;flex-wrap:nowrap;padding:10px 12px calc(10px + env(safe-area-inset-bottom));background:linear-gradient(rgba(30,30,25,0),var(--bg) 38%)}
 .actions button{flex:1 1 0;min-width:0;min-height:56px;padding:0 8px;font-size:21px;border-radius:14px}
 #roll{box-shadow:0 5px 0 #8aa800}
 #score{box-shadow:0 5px 0 #3a1a20}
 #score:disabled{box-shadow:0 5px 0 #4c161f!important}
 #score.yellow{box-shadow:0 5px 0 #a37f20}
 #score.green{box-shadow:0 5px 0 #2e8f2e}

 /* --- feed: the standing column below the play UI (scroll past the board to read it).
        Nothing floats over the board, nothing auto-dismisses — only the phone sizing
        differs from the shared rule above. --- */
 #feed{gap:6px;font-size:13px}
 #feed .t{padding:9px 11px;border-radius:9px}

 /* --- skill tree: full-bleed graph, floating controls, card as a bottom sheet --- */
 #treeSec{max-width:none;gap:0}
 #treeView{width:100%;height:calc(100dvh - var(--chrome));min-height:0;border:0;border-radius:0}
 .tnode .lbl{font-size:13px;width:132px;top:68px;color:#c2c2b4}
 .tnode.cap .lbl{top:88px}
 .tnode .price{font-size:12px;padding:1px 7px}
 .tnode .pad{font-size:15px}
 .tnode .chev{font-size:12px}
 #treeClose{display:flex;align-items:center;justify-content:center;position:absolute;left:12px;top:12px;width:44px;height:44px;border-radius:14px;background:rgba(42,42,36,.94);border:1px solid #4c4c40;color:var(--ink);font-size:16px;z-index:6;box-shadow:0 6px 18px rgba(0,0,0,.45)}
 #treeCenter{left:auto;right:12px;top:12px;width:44px;height:44px;border-radius:14px;background:rgba(42,42,36,.94);border:1px solid #4c4c40;color:var(--ink);font-size:21px;box-shadow:0 6px 18px rgba(0,0,0,.45)}
 #nodeCard{left:10px;right:10px;bottom:calc(10px + env(safe-area-inset-bottom));max-width:none;border-radius:16px;padding:13px 14px 14px;box-shadow:0 -10px 34px rgba(0,0,0,.55)}
 #nodeCard b{font-size:16px}
 #nodeCard .d,#nodeCard .st,#nodeCard .warn{font-size:13px}
 #nodeCard .row{margin-top:10px;display:flex;flex-wrap:wrap;gap:8px;align-items:center}
 #nodeCard button{min-height:46px;min-width:44px;padding:0 18px;font-size:14px;border-radius:11px}

 /* --- hand levels: the one table in the tree, as a full sheet of 2-line rows --- */
 #handPanel{inset:0;background:var(--bg);border:0;border-radius:0;padding:12px 12px calc(18px + env(safe-area-inset-bottom));overscroll-behavior:contain}
 #handPanelClose{right:12px;top:12px;width:44px;height:44px;border-radius:12px;background:#3a3a32;color:var(--ink);font-size:16px}
 #handPanel .hphead{flex-wrap:wrap;gap:8px;padding-right:56px;margin-bottom:12px;align-items:center}
 #handPanel .hphead h3{font-size:13px;flex:1 1 100%;line-height:1.3}
 #handPanel .hphead button{min-height:44px;padding:0 16px;font-size:13px;border-radius:10px}
 #handPanel .branch{padding:8px;border-radius:14px}
 #handPanel .branch.wide{grid-column:auto}
 #handPanel .tree{grid-template-columns:1fr}
 .node{white-space:normal;grid-template-columns:1fr auto;row-gap:6px;padding:8px 10px;font-size:13px}
 .node .nm{grid-column:1/-1}
 .node button{min-height:44px;padding:0 14px;font-size:13px}
 .node .st,.node .uses{font-size:12px}
 .node.hrow{display:flex;flex-wrap:wrap;gap:6px 10px;align-items:center;white-space:normal}
 .node.hrow .nm{flex:1 1 100%;font-size:14px;font-weight:700}
 .node.hrow .lvpill{margin-left:0}
 .node.hrow button,.node.hrow .st{margin-left:auto}
 .node.hrow button{min-height:44px}
 .node.hrow.hdr{display:none}
 .lvpill{font-size:12px;padding:2px 8px}

 /* --- collections --- */
 .coll{max-width:none;padding:12px 12px 4px}
 .collhead{font-size:13px;margin:0 0 10px}
 .hgrid{grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}
 .hcard{padding:9px 10px;min-height:0;gap:2px;border-radius:12px}
 .hcard b{font-size:13px;line-height:1.25}
 .hcard span{font-size:12px;line-height:1.25}
 .hcard:not(.found) span{display:none}
 .hcard:not(.found){align-items:center;justify-content:center}
 .hcard:not(.found) b{font-size:20px}
 .pgrid{grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}
 .pcard{flex-direction:column;align-items:stretch;gap:7px;padding:10px;border-radius:12px}
 .pcard .ic{align-self:center}
 .pcard .ic img{width:36px!important;height:auto!important}
 .pcard .ic.q{width:36px;height:48px;font-size:26px;align-self:center}
 .pcard .tx b{font-size:13px;line-height:1.25}
 .pcard .tx span{font-size:12px;line-height:1.25}
 .pcard .tx .r{font-size:12px;letter-spacing:.1em;margin-top:4px}
 .lgrid{grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}
 .ltile{padding:10px 11px;border-radius:12px}
 .ltile b{font-size:20px;line-height:1.2}
 .ltile span{font-size:12px}
 .lhands{grid-template-columns:1fr}
 .lhand{font-size:13px;padding:9px 11px}
 .lhrow{grid-template-columns:minmax(0,1fr) 50px 62px;padding:9px 11px;font-size:13px}
 .lhrow.lhhdr{font-size:12px;padding:2px 11px}

 /* touch: nothing depends on hover */
 .fig:hover .x,.fig .x{display:block;width:26px;height:26px;line-height:26px;font-size:12px;top:-8px;right:-8px}
 .shelf .fig .x{display:none}
 .navmenu button:hover{background:transparent}
}

/* transient message where the eye already is — on phones the feed sits below the fold */
#sayBar{position:fixed;left:50%;bottom:calc(18px + env(safe-area-inset-bottom));transform:translate(-50%,14px);
  background:#2a2a24;color:#eee;border:1px solid #555;border-left:3px solid var(--gold,#ffc94d);
  padding:10px 14px;border-radius:10px;font-size:14px;max-width:min(92vw,420px);text-align:center;
  opacity:0;pointer-events:none;z-index:60;transition:opacity .18s ease,transform .18s ease}
#sayBar.show{opacity:1;transform:translate(-50%,0)}
/* on a phone the bar must clear the fixed action bar — never sit on top of ROLL/SCORE.
   This block follows the base rule so it wins on source order. */
@media(max-width:99999px){
  #sayBar{left:12px;right:12px;max-width:none;bottom:calc(var(--abar) + 12px);transform:translate(0,12px)}
  #sayBar.show{transform:translate(0,0)}
}

/* the burger must stay tappable while its own scrim is up, so it can toggle closed */
.hamburger{position:relative;z-index:26}

/* narrow phones (≤360pt): the character chip drops to portrait only so the title still fits */
@media(max-width:379px){
 .charchip{width:44px;padding:3px;max-width:none;justify-content:center}
 .charchip span{display:none}
}

/* ================================================================
   MOBILE GAUNTLET ROUND 1
   Header instruments, hero board, semantic-zoom tree, card depth,
   denser collections. Kept last so it wins the cascade.
   ================================================================ */

/* --- icons: solid single-path masks, painted in each chip's accent --- */
:root{
 --ic-xp:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 1.8l3 6.4 6.8.9-5 4.8 1.3 6.8L12 17.4 5.9 20.7l1.3-6.8-5-4.8 6.8-.9z' fill='%23fff'/%3E%3C/svg%3E");
 --ic-gold:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 2.5a9.5 9.5 0 100 19 9.5 9.5 0 000-19zm0 3.6a5.9 5.9 0 110 11.8 5.9 5.9 0 010-11.8z' fill='%23fff' fill-rule='evenodd'/%3E%3C/svg%3E");
 --ic-match:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 1.7l8.4 3.1v6.4c0 5.2-3.5 9.7-8.4 11.4-4.9-1.7-8.4-6.2-8.4-11.4V4.8z' fill='%23fff'/%3E%3C/svg%3E");
 --ic-part:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M4 3.4h6.6c.9 0 1.6.5 1.6 1.2v15c0-.6-.7-1.1-1.6-1.1H4zM20 3.4h-6.6c-.9 0-1.6.5-1.6 1.2v15c0-.6.7-1.1 1.6-1.1H20z' fill='%23fff'/%3E%3Cpath d='M2.6 5.1h1.7v14.6H2.6zM19.7 5.1h1.7v14.6h-1.7z' fill='%23fff' opacity='.75'/%3E%3C/svg%3E");
 --ic-set:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M3.5 4.2h17v3.9h-17zM3.5 10.05h17v3.9h-17zM3.5 15.9h17v3.9h-17z' fill='%23fff'/%3E%3C/svg%3E");
 --ic-play:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M5.5 2.5h13a3 3 0 013 3v13a3 3 0 01-3 3h-13a3 3 0 01-3-3v-13a3 3 0 013-3zM8.7 6.4a2 2 0 100 4 2 2 0 000-4zm6.6 7.2a2 2 0 100 4 2 2 0 000-4z' fill='%23fff' fill-rule='evenodd'/%3E%3C/svg%3E");
 --ic-tree:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M11 6.5h2v4.2h-2zM6.9 17.2l4.2-5 1.6 1.3-4.2 5zM17.1 17.2l-4.2-5-1.6 1.3 4.2 5z' fill='%23fff'/%3E%3Ccircle cx='12' cy='4.4' r='3.1' fill='%23fff'/%3E%3Ccircle cx='5.3' cy='19' r='3.1' fill='%23fff'/%3E%3Ccircle cx='18.7' cy='19' r='3.1' fill='%23fff'/%3E%3C/svg%3E");
}

/* --- header shell: real depth instead of one flat slab --- */
header{background:
  radial-gradient(120% 160% at 14% -40%,rgba(214,255,46,.11) 0%,transparent 56%),
  radial-gradient(115% 150% at 88% -30%,rgba(167,101,255,.14) 0%,transparent 58%),
  linear-gradient(180deg,#2b2b23 0%,#212119 62%,#1e1e19 100%);
 box-shadow:inset 0 1px 0 rgba(255,255,255,.07),0 3px 10px -4px rgba(0,0,0,.65)}

/* --- run rail: four distinct instruments, each with its own icon and accent --- */
.runrail{background:#15150f;border-color:#15150f;gap:2px}
.runrail .cell{position:relative;border-left:3px solid var(--accent,#666);
 background:linear-gradient(170deg,color-mix(in srgb,var(--accent,#666) 15%,#2f2f27) 0%,#26261f 62%,#212119 100%);
 box-shadow:inset 0 1px 0 rgba(255,255,255,.06)}
.runrail .cell.c-xp{--accent:var(--acc)}
.runrail .cell.c-gold{--accent:var(--gold)}
.runrail .cell.c-part{--accent:#c17aff}
.runrail .cell.c-match{--accent:#7aa2ff}
.runrail .cell.c-set{--accent:#c17aff}
.runrail .cell span{color:color-mix(in srgb,var(--accent) 42%,#9a9a8c);font-weight:700}
.runrail .cell span::before{content:'';display:inline-block;width:10px;height:10px;margin-right:5px;vertical-align:-1px;
 background:var(--accent);-webkit-mask:var(--ico) center/contain no-repeat;mask:var(--ico) center/contain no-repeat}
.runrail .cell.c-xp span::before{--ico:var(--ic-xp)}
.runrail .cell.c-gold span::before{--ico:var(--ic-gold)}
.runrail .cell.c-part span::before{--ico:var(--ic-part)}
.runrail .cell.c-match span::before{--ico:var(--ic-match)}
.runrail .cell.c-set span::before{--ico:var(--ic-set)}
.runrail .cell.c-part b{color:#d6b0ff}
.runrail .cell.c-match b{color:#a9c2ff}
.runrail .cell.c-set b{color:#d6b0ff}

/* --- segmented switcher: the live tab is a lit pill, not a lighter grey --- */
.tabs button{position:relative;display:flex;align-items:center;justify-content:center;gap:7px}
.tabs button::before{content:'';display:block;width:15px;height:15px;flex:0 0 auto;background:currentColor;
 -webkit-mask:var(--ico) center/contain no-repeat;mask:var(--ico) center/contain no-repeat}
#tabPlay{--ico:var(--ic-play)}
#tabTree{--ico:var(--ic-tree)}
#tabPlay.on{color:#191905;background:linear-gradient(180deg,#e6ff6b 0%,#c8ef22 100%);
 box-shadow:0 2px 0 rgba(0,0,0,.35),0 0 16px rgba(214,255,46,.3),inset 0 1px 0 rgba(255,255,255,.5)}
/* the tree tab wears the tree's own purple, so the switcher reads by colour
   before it reads by fill */
#tabTree{color:#9d90b8}
#tabTree.on{color:#1b0f2a;background:linear-gradient(180deg,#dcc0ff 0%,#a765ff 100%);
 box-shadow:0 2px 0 rgba(0,0,0,.35),0 0 16px rgba(167,101,255,.35),inset 0 1px 0 rgba(255,255,255,.45)}
.tabs button.glow{color:var(--gold);border-color:rgba(255,201,77,.55);box-shadow:0 0 16px rgba(255,201,77,.3)}
.tabs button.on.glow{color:#191905}

/* --- sheets: cards that sit above the sheet, rarity as light not just a hairline --- */
.card{background:linear-gradient(160deg,#3d3d34 0%,#2c2c25 100%);box-shadow:0 7px 16px -6px rgba(0,0,0,.6),inset 0 1px 0 rgba(255,255,255,.06)}
.card:hover{box-shadow:0 12px 22px -8px rgba(0,0,0,.65),inset 0 1px 0 rgba(255,255,255,.08)}
.card.rare{box-shadow:0 7px 16px -6px rgba(0,0,0,.6),0 0 22px -6px var(--blue),inset 0 1px 0 rgba(255,255,255,.06)}
.card.legendary{box-shadow:0 7px 16px -6px rgba(0,0,0,.6),0 0 24px -5px var(--gold),inset 0 1px 0 rgba(255,255,255,.08)}
.card .ic{position:relative}
.card .ic::before{content:'';position:absolute;left:50%;top:50%;width:96px;height:96px;transform:translate(-50%,-50%);border-radius:50%;
 background:radial-gradient(circle,rgba(255,255,255,.13) 0%,rgba(255,255,255,.03) 55%,transparent 72%)}
.card.rare .ic::before{background:radial-gradient(circle,color-mix(in srgb,var(--blue) 34%,transparent) 0%,transparent 70%)}
/* rarity is a real ladder, not two glowing exceptions: every tier gets its own
   edge, its own light and its own colour on the rarity word */
.card.uncommon{border-color:#3f8a72;box-shadow:0 7px 16px -6px rgba(0,0,0,.6),0 0 18px -8px #4fd3ae,inset 0 1px 0 rgba(255,255,255,.06)}
.card.uncommon .ic::before{background:radial-gradient(circle,rgba(79,211,174,.22) 0%,transparent 70%)}
.card .r{color:#9a9a8c}
.card.uncommon .r{color:#79d8bb}
.card.rare .r{color:#7fd0f5}
.card.legendary .r{color:var(--gold)}
.card.uncommon:hover{border-color:#5bb79a}
.fig.uncommon,.shelfrow .fig.uncommon{border-color:#3a6f5e}
.card.legendary .ic::before{background:radial-gradient(circle,color-mix(in srgb,var(--gold) 34%,transparent) 0%,transparent 70%)}
.card .ic img{position:relative}
.draftbox{background:radial-gradient(120% 70% at 50% 0%,#35352c 0%,#2a2a24 48%,#232320 100%)}
.shelfrow .fig,.shelf .fig{background:linear-gradient(160deg,#33332c 0%,#26261f 100%);box-shadow:0 5px 12px -6px rgba(0,0,0,.6),inset 0 1px 0 rgba(255,255,255,.05)}
.shelfrow .fig.rare,.shelf .fig.rare{box-shadow:0 5px 12px -6px rgba(0,0,0,.6),0 0 16px -6px var(--blue)}
.shelfrow .fig.legendary,.shelf .fig.legendary{box-shadow:0 5px 12px -6px rgba(0,0,0,.6),0 0 16px -5px var(--gold)}

/* --- collection cards: rarity is the card's own colour, not a hairline. A
       common and an uncommon must not read as the same object. --- */
.pcard{--rc:#6f6f5f}
.pcard.uncommon{--rc:#4fd3ae}
.pcard.rare{--rc:#4fc3f7}
.pcard.legendary{--rc:#ffc94d}
.pcard.locked{--rc:#45453c}
.pcard,.pcard.rare,.pcard.legendary{
 border-color:color-mix(in srgb,var(--rc) 46%,#3a3a32);
 background:linear-gradient(165deg,color-mix(in srgb,var(--rc) 14%,#31312a) 0%,#282821 58%,#232320 100%);
 box-shadow:0 0 20px -9px var(--rc),inset 0 1px 0 rgba(255,255,255,.06)}
.pcard.legendary{box-shadow:0 0 24px -7px var(--gold),inset 0 1px 0 rgba(255,255,255,.09)}
.pcard .tx .r{color:var(--rc)}
.pcard.locked .tx .r{color:#6d6d60}
.pcard .ic{position:relative}
.pcard:not(.locked) .ic::before{content:'';position:absolute;left:50%;top:50%;width:56px;height:56px;transform:translate(-50%,-50%);
 border-radius:50%;background:radial-gradient(circle,color-mix(in srgb,var(--rc) 26%,transparent) 0%,transparent 68%)}

/* --- skill tree: semantic zoom. Dots keep a floor size (and a tap target);
       labels only appear once there is room for them. --- */
.tnode{transform:translate(-50%,-50%) scale(var(--node-s,1))}
.tnode::before{content:'';position:absolute;inset:-14px;border-radius:50%;pointer-events:none}
.tnode .lbl{transform:translateX(-50%) scale(var(--inv-s,1));transform-origin:top center;pointer-events:none}
.tnode .price{transform:translateX(-50%) scale(var(--inv-s,1));transform-origin:center top;pointer-events:none}
/* Zoomed out, the NAME goes first — it is the widest thing and the one that overlaps its
   neighbours. The icon and the price stay until the nodes are too small to hold them, because a
   map of blank circles tells you nothing about where to spend. */
#treeView.lowzoom .tnode .lbl,#treeView.lowzoom .tnode .chev{display:none}
/* Every price at once is a wall of pills that collide. Zoomed out, only the nodes you can act on
   right now carry their price — the map answers "where can I spend?" at a glance. */
#treeView.farzoom .tnode .ic{font-size:0}
#treeView.lowzoom .tnode .pad{font-size:16px;top:-6px;right:-3px}
#treeView.lowzoom #treeEdges text.trunkword{opacity:.17}
#treeView.lowzoom #treeEdges text.trunkword.shut{opacity:.05}
#treeView.lowzoom #treeEdges line.edge.shut{stroke-width:2}
#treeView.lowzoom #treeEdges line.edge{stroke-width:4}
#treeView.lowzoom .mouthcls{display:none}

@media(max-width:99999px){
 /* ---------- header: two rows, not three. The switcher takes the row the
       static app name used to spend on itself. ---------- */
 header{display:grid;grid-template-columns:44px minmax(0,1fr) 44px;grid-template-areas:"burger tabs char" "rail rail rail";gap:7px;align-items:center}
 .appbar{display:contents}
 .hamburger{grid-area:burger}
 /* the wordmark cannot fit, but the mark can: the top bar keeps its identity at
    every phone width instead of going anonymous below 700px */
 h1{display:none}
 .charchip{grid-area:char;width:44px;min-width:44px;max-width:none;padding:3px;justify-content:center;gap:0}
 .charchip span{display:none}
 .charchip .ava{padding:2px 4px}
 .charchip .ava img{width:20px!important;height:26px!important}
 .tabs{grid-area:tabs;background:#16160f;border-color:#2e2e26;padding:3px;gap:3px}
 .tabs button{min-height:38px;font-size:11px;letter-spacing:.06em;gap:6px}
 .tabs button::before{width:14px;height:14px}
 /* run stats are corner badges, not a second HUD: icon + number on one short
    line, no label text, so the whole header is two rows and ~92px */
 .runrail{grid-area:rail;background:#15150f;border-color:#26261f;border-radius:10px}
 .runrail .cell{display:flex;align-items:center;gap:4px;padding:3px 9px;border-left-width:2px}
 .runrail .cell span{font-size:0;line-height:0;letter-spacing:0}
 .runrail .cell span::before{width:13px;height:13px;margin-right:0;vertical-align:middle}
 .runrail .cell b{font-size:16px;line-height:1.2}
 .runrail .cell i{font-size:11px}
 .pips{padding:3px 10px;gap:4px;justify-content:flex-end}
 .pips i{width:8px;height:8px}

 /* ---------- play screen: the dice are the hero, the readout is a panel ---------- */
 #play{gap:9px}
 .hud{gap:10px;padding:4px 12px 26px}
 #scored{--sfz:54px}
 .hsub b{font-size:19px}
 .hud .bar{height:6px}

 /* The tray's HEIGHT IS FIXED. Four dice or twelve, the board occupies the same band and
    nothing above or below it moves — the dice shrink to fit instead. --bh is the band, and it
    does not mention --r; --r only sets how far the tray's WIDTH has to be pulled in so that
    --r square rows, four across, fit inside --bh. */
 /* eight half-tracks, each die spanning two: four across, and a short last row can
    sit on a half-step so it centres instead of hanging off the left edge */
 .board{flex:0 0 auto;position:relative;grid-template-columns:repeat(8,minmax(0,1fr));gap:var(--gap);padding:var(--pad);align-content:center;
  margin-inline:auto;width:100%;
  /* The tray claims the height its rows actually need at a legible die size — six dice ask for two
     rows, not for every spare pixel on the screen. --bh is the ceiling: on a short phone, or at
     twelve dice, the band runs out first and the dice shrink to fit it instead. */
  --pad:12px;--gap:10px;
  --dw:min(calc((min(100vw,var(--app-w)) - 24px - 2*var(--pad) - (var(--cols,4) - 1)*var(--gap))/var(--cols,4)),104px);
  /* the size a die can be if the BAND is what binds (a short phone, or four rows of dice), and
     the size it actually gets: the smaller of the two. The face scales with it, or the numbers
     hold the tiles open and sixteen dice spill out of the tray. */
  --dband:calc((var(--bh) - 2*var(--pad) - 2px - (var(--r,2) - 1)*var(--gap))/var(--r,2));
  --dsz:min(var(--dw),var(--dband));
  --need:calc(var(--r,2)*var(--dw) + (var(--r,2) - 1)*var(--gap) + 2*var(--pad));
  --bhfit:calc(100dvh - var(--chrome,116px) - var(--abar,76px) - var(--shelfh,0px) - 219px);
  --bh:max(132px,var(--bhfit));
  height:min(var(--need),var(--bh));
  /* the 2px is slack: without it a four-row board lands a pixel proud of the tray */
  max-width:min(calc(var(--cols,4)*var(--dw) + (var(--cols,4) - 1)*var(--gap) + 2*var(--pad)),
   calc(2*var(--pad) + (var(--cols,4) - 1)*var(--gap) + var(--cols,4)*(var(--bh) - 2*var(--pad) - 2px - (var(--r,2) - 1)*var(--gap))/var(--r,2)))}
 /* no mark behind the felt: the dice and the track are all the board needs to carry */
 .die{grid-column:span 2;aspect-ratio:1;width:auto;height:auto;min-height:0;min-width:0;
  font-size:clamp(13px,calc(var(--dsz)*0.42),40px);border-radius:16px;border-width:3px}
 /* a short last row centres itself: render() gives every die its own column */
 .die small{font-size:clamp(8px,calc(var(--dsz)*0.14),12px);right:9px;top:7px}
 .die.held::after{bottom:6px}

 /* the hand readout takes the height the board no longer wastes */
 .hand{flex:1 1 auto;max-height:34vh;min-height:112px;justify-content:center;gap:10px;padding:12px 14px;border-radius:18px;
  background:linear-gradient(175deg,#2c2c25 0%,#232320 100%);border:1px solid #383830;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.05),0 8px 20px -14px #000}
 .hand.empty{background:linear-gradient(175deg,#242420 0%,#1f1f1b 100%);border-color:#2c2c26;
  box-shadow:inset 0 2px 8px -4px #000}
 .hand .name{font-size:clamp(24px,8.4vw,38px);line-height:1.08}
 .hand .calc{font-size:15px;display:flex;flex-wrap:wrap;gap:6px;align-items:center;justify-content:center}
 .hand .calc b{padding:5px 13px;border-radius:11px;font-size:20px}

 /* ---------- collections: chrome off, content in the first screen ---------- */
 body.collMode .runrail,body.collMode .tabs{display:none}
 body.collMode header{grid-template-columns:44px minmax(0,1fr) 44px;grid-template-areas:"burger title char"}
 body.collMode h1{display:block;grid-area:title;font-size:13px;font-weight:800;letter-spacing:.07em;text-align:center;color:#c8c8ba}
 /* a short collection stretches its rows instead of leaving a footer void —
    the fresh 0/29 Hands page was 40% empty black */
 .coll{padding:10px 12px 4px;display:flex;flex-direction:column;min-height:calc(100dvh - var(--chrome,116px) - 14px)}
 .hgrid,.pgrid{flex:1 1 auto;align-content:stretch}
 .hgrid{grid-auto-rows:minmax(52px,1fr)}
 .pgrid{grid-auto-rows:minmax(96px,auto)}
 .collhead{font-size:12px;margin:0 0 8px;letter-spacing:.09em;font-weight:800;color:#b9b9aa}
 .pgrid{grid-template-columns:repeat(3,minmax(0,1fr));gap:7px;align-items:start;grid-auto-flow:row dense}
 .pcard{padding:8px 6px;gap:5px;border-radius:12px;cursor:pointer}
  .pcard .ic img{width:40px!important;height:auto!important}
 .pcard .ic.q{width:30px;height:34px;font-size:22px}
 .pcard .ic{position:relative}
 .pcard .tx b{font-size:11px;line-height:1.2;text-align:center}
 .pcard .tx .r{font-size:9px;letter-spacing:.08em;margin-top:3px;text-align:center}
 .pcard .tx>span.d{display:none;font-size:12px;line-height:1.3;margin-top:5px;text-align:center}
 .pcard.open{grid-column:1/-1}
 .pcard.open .tx>span.d{display:block}
  .pcard.open .ic img{width:58px!important;height:auto!important}
 .pcard.locked{padding:6px 5px}
 .pcard.locked .tx .a{font-size:9px;line-height:1.25;text-align:center;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
 .pcard.locked.open .tx .a{-webkit-line-clamp:none;font-size:12px}
 /* a 4-up grid of cheap dashed slots for the undiscovered hands; a found hand
    takes a double slot and keeps its numbers, so the wall reads as cheaper */
 .hgrid{grid-template-columns:repeat(4,minmax(0,1fr));gap:7px;align-items:stretch;grid-auto-flow:row dense}
 .hcard.found{grid-column:span 2}
 .hcard:not(.found){min-height:42px;padding:5px;border-style:dashed;border-color:#33332c;opacity:.42;align-items:center;justify-content:center}
 .hcard:not(.found) b{font-size:15px}

 /* ---------- tree hand-levels sheet: rows fill the sheet instead of
        stopping a third of the way down ---------- */
 #handPanel{display:flex;flex-direction:column}
 #handPanel .hpbody{flex:1 1 auto;display:flex;flex-direction:column;min-height:0}
 #handPanel .tree{flex:1 1 auto;display:flex;flex-direction:column}
 #handPanel .branch{flex:1 1 auto;display:flex;flex-direction:column;gap:6px}
 #handPanel .branch h3{flex:0 0 auto}
 #handPanel .node.hrow{flex:1 1 auto;min-height:66px;padding:11px 12px;align-content:center;margin:0}
}

/* narrow phones: the die grid gets tighter gutters so the faces stay large */
@media(max-width:379px){
 .board{--gap:8px;--pad:9px}
 .tabs button{font-size:10px;letter-spacing:.02em;gap:4px}
}

/* short phones (SE / 360x740 class): trim the readout chrome so the dice keep their size */
@media(max-width:99999px) and (max-height:780px){
 #play{gap:7px}
 .hud{padding:3px 12px 25px}
 #scored{--sfz:46px}
 .hsub b{font-size:18px}
 .hand{min-height:88px;padding:9px 12px;gap:6px}
 .hand .name{font-size:clamp(19px,6vw,25px)}
 .hand .calc{font-size:14px}
 .hand .calc b{font-size:16px;padding:3px 9px}
 .board{--bhfit:calc(100dvh - var(--chrome,116px) - var(--abar,76px) - var(--shelfh,0px) - 181px)}
}


/* ---- scoring pop tags on the board ---- */
.die .stag{border-color:var(--gold);color:var(--gold)}
.die .stag{position:absolute;left:50%;bottom:-18px;transform:translateX(-50%);background:#222;border:1px solid var(--gold);color:var(--gold);
 font-size:11px;font-weight:800;padding:1px 6px;border-radius:8px;animation:flup 1.15s ease-out forwards;white-space:nowrap;z-index:7;letter-spacing:.04em}

/* ---- scoring count-up: only the companions that fire light up ---- */
.fig{transition:opacity .16s,filter .16s,border-color .16s,box-shadow .16s}
.fig.idle{opacity:.3;filter:grayscale(1)}
.fig.fired{opacity:1;filter:none;border-color:var(--acc);box-shadow:0 0 0 1px rgba(214,255,46,.45),0 0 22px -6px rgba(214,255,46,.8)}
@media(prefers-reduced-motion:reduce){.fig.pulse{animation:none}}

/* ================= PARTY (multiplayer) ================= */
/* Every rule here is scoped to party chrome or to .inparty, so solo renders byte-identical. */
.navmenu .pcodechip{font-style:normal;font-size:12px;font-weight:800;letter-spacing:.14em;color:#1e1e19;background:var(--acc);border-radius:6px;padding:2px 6px;margin-left:8px;vertical-align:1px}

/* --- bottom sheet --- */
#partySheet{position:fixed;inset:0;z-index:60;display:flex;align-items:flex-end;justify-content:center}
#partySheet.hidden{display:none}
#partySheet .pscrim{position:absolute;inset:0;background:rgba(8,8,6,.66);opacity:0;transition:opacity .2s}
#partySheet.in .pscrim{opacity:1}
.psheet{position:relative;width:100%;max-width:520px;max-height:92dvh;display:flex;flex-direction:column;
 background:linear-gradient(180deg,#31312a 0%,var(--panel) 22%);border:1px solid #4a4a3f;border-bottom:0;
 border-radius:20px 20px 0 0;box-shadow:0 -18px 50px rgba(0,0,0,.6);
 transform:translateY(14px);opacity:0;transition:transform .22s cubic-bezier(.2,.9,.3,1),opacity .22s}
#partySheet.in .psheet{transform:none;opacity:1}
.pshead{display:flex;align-items:center;gap:10px;padding:12px 16px 10px;border-bottom:1px solid #3d3d34;flex:0 0 auto}
.pshead b{font-size:15px;font-weight:900;letter-spacing:.14em;flex:1 1 auto}
.pshead .pclose{background:#3a3a32;color:var(--ink);border:0;border-radius:11px;width:44px;height:44px;font-size:17px;flex:0 0 auto}
.psbody{padding:14px 16px calc(16px + env(safe-area-inset-bottom));overflow-y:auto;display:flex;flex-direction:column;gap:12px;-webkit-overflow-scrolling:touch}

/* --- your identity --- */
.pme{display:flex;align-items:center;gap:12px;background:#25251f;border:1px solid #3d3d34;border-radius:14px;padding:10px 12px}
.pav{display:flex;align-items:center;justify-content:center;background:#1a1a15;border-radius:10px;padding:3px 5px;line-height:0;flex:0 0 auto}
.pnamef{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;gap:3px}
.pnamef span{font-size:11px;letter-spacing:.1em;color:var(--dim);font-weight:700}
.pname,.pcodein,.pchatin{background:#161612;border:1px solid #47473c;color:var(--ink);border-radius:10px;
 font:inherit;font-weight:700;padding:0 12px;min-height:44px;width:100%;-webkit-appearance:none}
.pname:focus,.pcodein:focus,.pchatin:focus{outline:0;border-color:var(--acc);box-shadow:0 0 0 2px rgba(214,255,46,.2)}
.pme .pcls{display:none}
@media (min-width:420px){.pme .pcls{display:block;font-style:normal;font-size:12px;font-weight:800;letter-spacing:.06em;color:var(--dim);flex:0 0 auto}}

/* --- create / join --- */
.pbig{background:var(--acc);color:#1b1b12;border:0;border-radius:13px;font:inherit;font-size:15px;font-weight:900;letter-spacing:.09em;min-height:52px;padding:0 18px;width:100%}
.pbig:active{transform:translateY(1px)}
.por{display:flex;align-items:center;gap:12px;color:var(--dim);font-size:11px;font-weight:800;letter-spacing:.16em}
.por i{flex:1 1 auto;height:1px;background:#3d3d34}
.pjoin{display:flex;gap:10px}
.pcodein{flex:1 1 auto;text-align:center;font-size:24px;font-weight:900;letter-spacing:.4em;text-indent:.4em;text-transform:uppercase}
.pjoin .pbig{width:auto;flex:0 0 auto}
.perr{color:var(--hot);font-size:13px;font-weight:700;min-height:1px}

/* --- the code --- */
.pcode{display:flex;align-items:center;gap:12px;background:#20201a;border:1px dashed #5c5c4c;border-radius:14px;padding:10px 12px}
.pcode span{font-size:11px;letter-spacing:.1em;color:var(--dim);font-weight:800}
.pcode b{flex:1 1 auto;font-size:38px;font-weight:900;letter-spacing:.22em;line-height:1;color:var(--acc);text-shadow:0 0 24px rgba(214,255,46,.35)}
.pcopy{background:#3a3a32;color:var(--ink);border:1px solid #525245;border-radius:11px;font:inherit;font-size:12px;font-weight:800;letter-spacing:.1em;min-height:44px;padding:0 14px;flex:0 0 auto}

/* --- members --- */
.pmembers{display:flex;flex-direction:column;gap:6px}
.pm{display:flex;align-items:center;gap:11px;background:#25251f;border:1px solid #3d3d34;border-left:4px solid var(--pc,#3d3d34);border-radius:12px;padding:7px 12px;min-height:56px}
.pm.me{background:#2c2c23}
.pmt{flex:1 1 auto;min-width:0}
.pmt b{display:block;font-size:15px;font-weight:800;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.pmt b em{font-style:normal;font-size:11px;font-weight:800;letter-spacing:.08em;color:var(--pc);margin-left:4px}
.pmt span{display:block;font-size:12px;color:var(--dim);font-weight:600}
.pdot{width:10px;height:10px;border-radius:50%;background:#4a4a40;flex:0 0 auto}
.pdot.on{background:#7ade7a;box-shadow:0 0 10px rgba(122,222,122,.8)}
.pwait{text-align:center;color:var(--dim);font-size:13px;font-weight:700;letter-spacing:.06em;padding:8px 0}
.prun{display:flex;align-items:baseline;justify-content:center;gap:10px;color:var(--dim);font-size:12px;font-weight:800;letter-spacing:.1em}
.prun b{color:var(--ink);font-size:14px}

/* --- chat --- */
.pchat{display:flex;flex-direction:column;gap:8px;border-top:1px solid #3d3d34;padding-top:12px}
.pchatlog{display:flex;flex-direction:column;gap:5px;height:min(34dvh,240px);overflow-y:auto;-webkit-overflow-scrolling:touch;padding-right:2px}
.pcl{font-size:14px;line-height:1.3;background:#22221c;border-radius:10px;padding:6px 10px;border-left:3px solid var(--pc,#4a4a40)}
.pcl.me{background:#2b2b21}
.pcl b{color:var(--pc,#eee);font-weight:800;font-size:12px;letter-spacing:.04em;margin-right:7px}
.pcl span{color:#ddd;word-break:break-word}
.pchatbar{display:flex;gap:8px}
.psend{background:var(--acc);color:#1b1b12;border:0;border-radius:11px;min-width:52px;min-height:44px;font-size:17px;flex:0 0 auto}
.pleave{background:transparent;color:var(--hot);border:1px solid #5a3641;border-radius:12px;font:inherit;font-size:13px;font-weight:800;letter-spacing:.1em;min-height:48px}

/* --- seat pips: still used on the tree, to show who lit a node --- */
.ppip{display:flex;align-items:center;justify-content:center;width:19px;height:19px;border-radius:50%;
 background:var(--pc,#888);color:#14140f;font-size:9px;font-weight:900;letter-spacing:0;font-style:normal;line-height:1;
 box-shadow:0 1px 4px rgba(0,0,0,.5),inset 0 -1px 0 rgba(0,0,0,.2)}
.ppip.me{box-shadow:0 0 0 2px #14140f,0 0 0 3.5px var(--pc),0 1px 4px rgba(0,0,0,.5)}
.inparty .die{position:relative;overflow:visible}
.inparty .actions button{position:relative;overflow:visible}

/* --- whose turn: the line above the buttons --- */
#pturn{display:flex;align-items:center;gap:10px;width:100%;max-width:560px;margin:0 auto;padding:8px 12px;
 border-radius:14px;border:1px solid #45453a;background:#22221c;min-height:52px}
#pturn .pav{padding:2px 4px}
#pturn .pav img{image-rendering:pixelated;width:22px;height:auto;display:block}
#pturn b{flex:1 1 auto;font-size:17px;font-weight:900;letter-spacing:.1em;line-height:1.1}
#pturn.mine{border-color:var(--acc);background:linear-gradient(180deg,#3a3f19,#26261c);
 box-shadow:0 0 0 1px rgba(214,255,46,.35),0 0 26px -8px rgba(214,255,46,.75)}
#pturn.mine b{color:var(--acc)}
#pturn.theirs b{color:#ffd18a}
#pturn .pwaits{font-size:11px;font-weight:800;letter-spacing:.14em;color:var(--dim);text-transform:uppercase}
#pturn .ppass{background:#3a3a32;color:var(--acc);border:1px solid #5f6a2c;border-radius:11px;font:inherit;
 font-size:12px;font-weight:900;letter-spacing:.12em;min-height:40px;padding:0 16px;flex:0 0 auto}
#pturn .ppass:active{transform:translateY(1px)}
#pturn.flip{animation:pturnflip .5s cubic-bezier(.2,1.2,.4,1)}
@keyframes pturnflip{0%{transform:scale(.94);filter:brightness(2.2)}60%{transform:scale(1.02)}100%{transform:none;filter:none}}
@media(prefers-reduced-motion:reduce){#pturn.flip{animation:none}}

/* --- not your turn: the board reads locked, and a tap still answers you --- */
body.notmyturn #board .die{opacity:.42;filter:saturate(.35);cursor:not-allowed}
body.notmyturn #board .die.held{opacity:.6}
body.notmyturn .actions button,body.notmyturn .actions button:disabled{opacity:.34;filter:grayscale(.7);cursor:not-allowed}
body.notmyturn .actions button::after{content:'🔒';position:absolute;top:50%;right:12px;transform:translateY(-50%);
 font-size:14px;filter:none;opacity:.9}
body.notmyturn .shelf{opacity:.7}

/* --- xp split on the run-end screen --- */
.dsplit{display:flex;flex-direction:column;gap:6px;background:rgba(0,0,0,.26);border:1px solid #3d3d34;border-radius:14px;padding:12px}
.dsplit>b{font-size:11px;letter-spacing:.14em;color:var(--dim);font-weight:800}
.dsr{display:flex;align-items:center;gap:10px;min-height:40px}
.dsr span{flex:1 1 auto;text-align:left;font-weight:700;font-size:14px}
.dsr b{color:var(--acc);font-weight:900;font-variant-numeric:tabular-nums}
/* the send bar stays reachable while the phone keyboard eats the sheet */
.pchatbar{position:sticky;bottom:calc(-16px - env(safe-area-inset-bottom));background:var(--panel);padding:8px 0 calc(8px + env(safe-area-inset-bottom));margin-bottom:-8px;z-index:2}

/* --- who lit what: seat pips on the skill tree --- */
.tnode .tpip,.hrow .tpip{position:absolute;top:-6px;right:-6px;width:17px;height:17px;font-size:8px;z-index:4}
.hrow{position:relative}
.tnode.plit{box-shadow:0 0 0 2px var(--pc,#888),0 0 18px -4px var(--pc,#888)}

/* --- wallets: gold is per seat, so the rail says who can afford what --- */
#pwallets{display:flex;gap:6px;justify-content:center;flex-wrap:wrap;padding:4px 10px 2px;grid-column:1/-1}
.pw{display:inline-flex;align-items:center;gap:5px;font-style:normal;background:#22221c;border:1px solid #3d3d34;
 border-left:3px solid var(--pc,#4a4a40);border-radius:999px;padding:2px 9px 2px 5px;min-height:26px}
.pw.me{background:#2e2e24;border-color:var(--pc,#4a4a40)}
.pw b{display:flex;align-items:center;justify-content:center;width:17px;height:17px;border-radius:50%;background:var(--pc,#888);color:#14140f;font-size:9px;font-weight:900}
.pw span{font-size:12px;font-weight:800;color:var(--gold);font-variant-numeric:tabular-nums}
.pmg{font-style:normal;font-size:13px;font-weight:900;color:var(--gold);font-variant-numeric:tabular-nums;flex:0 0 auto}
.pmn{font-style:normal;color:var(--dim);font-weight:700;margin-left:8px}

/* --- the shop: the turn holder runs it, everyone else watches --- */
.pshophead{color:var(--dim);font-size:12px;font-weight:700;letter-spacing:.06em;margin:12px 0 6px}
.pshop .card{position:relative;overflow:visible}
.pshop .card.poor{opacity:.55}
.pshop .fig{overflow:visible}
.pshop .skip{position:relative;overflow:visible;background:#3a3a32;color:var(--acc);text-decoration:none;
 border-radius:12px;padding:0 22px;min-height:48px;font-weight:900;letter-spacing:.1em}
.pshopturn{display:block;text-align:center;font-size:13px;font-weight:900;letter-spacing:.1em;color:#ffd18a;
 background:#2a241c;border:1px solid #5a4a30;border-radius:12px;padding:8px 10px;margin:0 0 10px}
.pshopturn.mine{color:var(--acc);background:#2f331a;border-color:#6a7a30}
.pshop.locked .draftbody,.pshop.locked .skip{opacity:.45;filter:grayscale(.6)}
/* the phone layout of the offers and the shelf is the solo one — the shop is the same sheet */

/* party strip: the smallest honest picture of who you are playing with, and whose turn it is */
/* the phone header is a grid; the strip has to span it or it lands in the 44px burger column */
#partyStrip{display:flex;gap:6px;justify-content:center;flex-wrap:wrap;padding:4px 8px;grid-column:1/-1}
#partyStrip .pm{display:inline-flex;align-items:center;gap:5px;background:#2a2a24;border:1px solid #45453a;
  border-radius:999px;padding:2px 9px 2px 3px;font-size:11px;color:#c9c9b8}
#partyStrip .pm.me{border-color:#6e6e5a;color:#eee}
#partyStrip .pm.off{opacity:.45}
#partyStrip .pm img{image-rendering:pixelated;width:18px;height:auto;display:block}
#partyStrip .pm b{font-weight:700}
#partyStrip .pm i{font-style:normal;color:var(--gold)}
/* the seat holding the turn is lit and labelled; the rest are plainly stood down */
#partyStrip.turns .pm.idle{opacity:.5;filter:grayscale(.8)}
#partyStrip.turns .pm.idle.me{opacity:.66;border-color:#7d7d66}
#partyStrip.turns .pm.up{background:linear-gradient(180deg,#4a5320,#2f3319);border-color:var(--acc);color:#fff;
 box-shadow:0 0 0 1px rgba(214,255,46,.5),0 0 18px -4px rgba(214,255,46,.8);opacity:1;filter:none}
#partyStrip.turns .pm.up b{font-weight:900}
#partyStrip .pturnflag{font-style:normal;font-size:9px;font-weight:900;letter-spacing:.1em;color:#1e1e19;
 background:var(--acc);border-radius:5px;padding:1px 5px}

/* --- the party sheet says it too --- */
.psturn{display:flex;flex-direction:column;gap:8px;text-align:center;background:#22221c;border:1px solid #45453a;
 border-radius:14px;padding:12px}
.psturn b{font-size:19px;font-weight:900;letter-spacing:.12em;color:#ffd18a}
.psturn span{font-size:12px;color:var(--dim);font-weight:700}
.psturn.mine{border-color:var(--acc);background:linear-gradient(180deg,#3a3f19,#26261c)}
.psturn.mine b{color:var(--acc)}
.pm.up{box-shadow:0 0 0 1px var(--acc) inset}
.pmt .pturnflag{font-style:normal;font-size:10px;font-weight:900;letter-spacing:.1em;color:#1e1e19;
 background:var(--acc);border-radius:5px;padding:1px 5px;margin-left:4px}
.pw.up{border-color:var(--acc);box-shadow:0 0 0 1px rgba(214,255,46,.5)}

/* Companions on the shelf are a glanceable row of faces: the sprite carries the identity,
   and the detail only appears when you point at one (or hold it on a phone). */
.shelf .fig{padding:4px;gap:0;border-radius:10px;position:relative}
.shelf .fig > div:not(.ic):not(.life){position:absolute;left:50%;top:calc(100% + 8px);transform:translateX(-50%) translateY(-4px);
  width:max-content;max-width:220px;background:#26261f;border:1px solid #55554a;border-left:3px solid var(--gold);
  border-radius:10px;padding:8px 10px;text-align:left;opacity:0;pointer-events:none;transition:opacity .12s,transform .12s;
  z-index:50;box-shadow:0 10px 26px rgba(0,0,0,.5)}
.shelf .fig:hover > div:not(.ic):not(.life),.shelf .fig.peek > div:not(.ic):not(.life){opacity:1;transform:translateX(-50%) translateY(0)}
.shelf{position:relative;z-index:20}
.shelf .fig b{display:block;font-size:12px;color:#eee}
.shelf .fig span{display:block;font-size:12px;color:var(--dim);white-space:normal}
/* sets left rides the corner of the tile, where it reads at a glance */
.shelf .fig .life{position:absolute;right:-4px;bottom:-5px;margin:0;font-size:10px;font-weight:800;padding:0 4px;
 min-width:15px;text-align:center;background:#1b1b16;border:1px solid #55554a;color:#cfcfc2;border-radius:7px;line-height:15px}
.shelf .fig.cracking .life{border-color:var(--hot)}
@media(max-width:99999px){
  .shelf{gap:6px;padding:0 6px}
  .shelf .fig{padding:3px}
  .shelf .fig .ic img{width:36px!important;height:auto!important}
  .shelf .fig > div:not(.ic):not(.life){max-width:min(74vw,260px)}
}

/* ================= CLASS BRANCHES IN THE TREE ================= */
/* Six lanes threaded between the five trunks. Your class's lane is lit; the other five read as
   somebody else's road — dim, padlocked, and named. */
#treeEdges path.cwedge{opacity:.05}
#treeEdges path.cwedge.mine{opacity:.13}
#treeEdges text.clsword{font-size:30px;font-weight:900;letter-spacing:.28em;opacity:.16;text-anchor:middle;dominant-baseline:middle;font-family:inherit}
#treeEdges text.clsword.mine{opacity:.5}
#treeView.lowzoom #treeEdges text.clsword{opacity:.3}
#treeView.lowzoom #treeEdges text.clsword.mine{opacity:.75}
.mouthcls{filter:grayscale(1)}
.mouthcls.me{filter:none;box-shadow:0 0 0 2px var(--tc,#fff),0 0 18px -3px var(--tc,#fff);border-radius:8px}
.tnode.cls{border-style:dashed}
.tnode.cls.owned,.tnode.cls.lit{border-style:solid}
.tnode.ccap{width:76px;height:76px}.tnode.ccap .lbl{top:78px}
.tnode.clslock{opacity:.34;border-style:dotted;cursor:default}
.tnode.clslock .price{font-size:9px;letter-spacing:.06em;color:var(--tc);border-color:color-mix(in srgb,var(--tc) 45%,#55554a)}

/* ================= PARTY MEMBERS ================= */
/* One card, two homes: a column beside the board on desktop, a compact chip row inline with the
   companion shelf on a phone. A class name is never cut and never hyphenated — it is the one word
   that tells you who someone is. */
#partySide{display:none}
#partyPillsM{display:none}
.rphead{display:flex;align-items:baseline;justify-content:space-between;gap:8px;padding:0 2px 4px;
 font-size:11px;font-weight:900;letter-spacing:.16em;color:var(--dim)}
.rphead em{font-style:normal;font-weight:900;letter-spacing:.18em;color:#1e1e19;background:var(--acc);border-radius:6px;padding:2px 7px;font-size:11px}
.rpill{display:grid;grid-template-columns:auto minmax(0,1fr) auto;grid-template-areas:'av name gold' 'av cls cls' 'turn turn turn';
 align-items:center;column-gap:9px;row-gap:1px;background:var(--panel);border:1px solid #3d3d34;
 border-left:4px solid var(--pc,#3d3d34);border-radius:12px;padding:8px 11px}
.rpav{grid-area:av;display:flex;align-items:center;justify-content:center;background:#1e1e19;border-radius:9px;padding:3px 5px;line-height:0}
.rpav img{image-rendering:pixelated;width:26px!important;height:auto!important;display:block}
.rpname{grid-area:name;font-size:14px;font-weight:800;line-height:1.2;color:var(--ink);overflow-wrap:break-word;min-width:0}
.rpgold{grid-area:gold;font-style:normal;font-size:15px;font-weight:800;color:var(--gold);font-variant-numeric:tabular-nums;line-height:1}
.rpgold u{text-decoration:none;font-size:10px;color:#a98c39;margin-left:1px}
.rpcls{grid-area:cls;font-size:10px;font-weight:800;letter-spacing:.09em;text-transform:uppercase;
 color:var(--pc,#8d8d82);white-space:nowrap;line-height:1.3}
.rpturn{grid-area:turn;justify-self:stretch;margin-top:6px;font-style:normal;font-size:10px;font-weight:900;letter-spacing:.12em;
 text-align:center;color:#1e1e19;background:var(--acc);border-radius:6px;padding:3px 6px}
.rpill.me{background:#31312a}
.rpill.up{border-color:var(--acc);background:linear-gradient(180deg,#3b4020,#2b2b22);box-shadow:0 0 0 1px rgba(214,255,46,.3)}
.rpill.idle{opacity:.6}
.rpill.off{opacity:.38}
/* the shelf line: companions, with the party inline beside them on a phone */
.shelfline{display:flex;align-items:center;justify-content:center;gap:8px;width:100%;flex-wrap:wrap}
.shelfline:empty{display:none}
@media(min-width:99999px){
 #partySide{display:flex;flex-direction:column;gap:8px;position:sticky;top:12px}
 #partySide:empty{display:none}
 main.treeMode #partySide{display:none}
}
@media(max-width:99999px){
 /* inline with the companion shelf: a chip, not a card — the board owns the screen */
 #partyPillsM{display:flex;gap:6px;flex-wrap:wrap;justify-content:center}
 #partyPillsM:empty{display:none}
 #partyPillsM .rpill{grid-template-areas:'av name gold' 'av cls turn';column-gap:7px;padding:5px 9px;
  border-radius:10px;border-left-width:3px;box-shadow:none}
 #partyPillsM .rpav img{width:18px!important}
 #partyPillsM .rpav{padding:2px 3px;border-radius:7px}
 #partyPillsM .rpname{font-size:12px}
 #partyPillsM .rpgold{font-size:12px}
 #partyPillsM .rpcls{font-size:9px}
 #partyPillsM .rpturn{margin:0 0 0 6px;justify-self:end;font-size:8px;padding:1px 5px;letter-spacing:.08em}
}

/* ================= NAME YOUR CHARACTER ================= */
#draft.charpick{z-index:80}
#draft.charpick .namefield{display:flex;flex-direction:column;gap:6px;width:100%;max-width:420px;margin:0 auto 16px}
#draft.charpick .namefield span{font-size:11px;font-weight:900;letter-spacing:.16em;color:var(--dim)}
#draft.charpick .namefield input{background:#1e1e19;border:2px solid #4c4c40;border-radius:12px;color:var(--ink);
 font:inherit;font-size:19px;font-weight:800;padding:12px 14px;min-height:52px;width:100%}
#draft.charpick .namefield input:focus{outline:none;border-color:var(--acc);box-shadow:0 0 0 3px rgba(214,255,46,.18)}
#draft.charpick .card.charcard.sel{border-color:var(--acc);box-shadow:0 0 0 2px rgba(214,255,46,.5),0 0 26px -8px rgba(214,255,46,.8)}
#draft.charpick .go{display:block;width:100%;max-width:420px;margin:18px auto 0;background:var(--acc);color:#1a1e05;
 border:none;border-radius:14px;font:inherit;font-size:17px;font-weight:900;letter-spacing:.1em;
 min-height:56px;text-decoration:none;box-shadow:0 6px 20px -8px rgba(214,255,46,.8)}
#draft.charpick .go:active{transform:translateY(1px)}
#draft.charpick .go[disabled]{background:#3a3a32;color:var(--dim);box-shadow:none;opacity:1}
/* the class is locked for the length of a run */
.charchip.locked{opacity:.55;cursor:default}

.charchip{position:relative}
/* between runs: the one place the class is free to move */
#died .dsec{width:100%;min-height:48px;margin-top:10px;background:transparent;border:1px solid #55554a;border-radius:12px;
 color:var(--dim);font:inherit;font-size:13px;font-weight:800;letter-spacing:.1em}
#died .dsec:hover{border-color:#7a7a68;color:var(--ink)}

/* One layout, phone-shaped. On a wide screen the app is a centred phone-width column
   rather than a stretched desktop page. */
:root{--app-w:430px}
body{background:#141410}
header,main,#partyStrip,#sayBar{max-width:var(--app-w);margin-inline:auto}
main{width:100%}
body>header{width:100%}
#died,.draftbox,#partySheet .in{max-width:var(--app-w);margin-inline:auto}
#feed{max-width:var(--app-w);margin-inline:auto}

/* the pinned action bar belongs to the app column, not the whole window */
.actions{left:50%!important;right:auto!important;transform:translateX(-50%);width:100%;max-width:var(--app-w)}

/* the sheet always offers a way out to the board */
.psfoot{position:sticky;bottom:0;padding:10px 14px calc(10px + env(safe-area-inset-bottom));background:linear-gradient(rgba(30,30,25,0),#22221c 40%)}
.pgo{width:100%;min-height:52px;border-radius:14px;background:var(--acc);color:#111;font-weight:900;font-size:16px;letter-spacing:.06em}

/* PASS rides in the party row now the banner is gone */
.rppass{margin-left:auto;background:#3a3a30;color:var(--acc);border:1px solid #55554a;border-radius:9px;
  padding:5px 10px;font-size:11px;font-weight:800;letter-spacing:.06em;min-height:32px}

/* the hand readout said little and ate a third of the screen: one line, no panel */
.hand{min-height:0!important;max-height:none!important;flex:0 0 auto!important;padding:4px 8px!important;
  background:none!important;border:0!important;box-shadow:none!important;gap:2px!important}
.hand .name{font-size:16px!important;line-height:1.15!important}
.hand .calc{font-size:12px!important;gap:4px!important}
.hand .calc b{font-size:13px!important;padding:1px 6px!important;border-radius:7px!important}
.hand.empty{display:none!important}

/* bosses get a fixed row under the dice so nothing above them shifts when one appears */
#bossRow{min-height:0;margin:6px auto 0;max-width:var(--app-w);width:100%}
#bossRow:empty{display:none}

/* the class chip reads as locked by being inert, not by wearing a padlock */
.charchip.locked::after,.charchip.locked .lockic{content:none!important;display:none!important}
.charchip.locked{opacity:.72;filter:saturate(.7)}

/* The trunk colours are one continuous wheel behind the map: hue says which branch, and the
   ring fades out at the hub and at the rim so nothing has an edge. */
#treeField{position:absolute;left:0;top:0;border-radius:50%;pointer-events:none;z-index:0;
 opacity:.34;filter:blur(26px) saturate(1.15);
 -webkit-mask-image:radial-gradient(closest-side,transparent 0%,#000 26%,#000 62%,transparent 96%);
 mask-image:radial-gradient(closest-side,transparent 0%,#000 26%,#000 62%,transparent 96%)}

/* the stale-tab chip: quiet, out of the way of both thumbs, and impossible to miss */
#newbuild{position:fixed;left:50%;transform:translateX(-50%);bottom:calc(var(--abar,76px) + 12px);z-index:120;
 background:var(--acc);color:#1e1e19;font-size:12px;font-weight:900;letter-spacing:.08em;
 padding:9px 16px;border-radius:999px;box-shadow:0 8px 22px -8px rgba(0,0,0,.8);animation:nbin .3s ease-out}
@keyframes nbin{from{opacity:0;transform:translateX(-50%) translateY(8px)}to{opacity:1;transform:translateX(-50%) translateY(0)}}

/* Portrait only. A phone on its side leaves about 250px of usable height: the tray, the readout
   and the buttons cannot all be on screen, and the chip that says so ends up over the dice. */
#rotate{display:none}
@media (orientation:landscape) and (max-height:560px){
  #rotate{display:flex;position:fixed;inset:0;z-index:9999;flex-direction:column;gap:8px;
   align-items:center;justify-content:center;text-align:center;padding:24px;background:#14140f}
  #rotate b{font-size:20px;font-weight:900;letter-spacing:.04em;color:var(--acc)}
  #rotate span{font-size:14px;color:var(--dim)}
  #rotate::before{content:'';width:34px;height:54px;border:3px solid #55554a;border-radius:8px;
   transform:rotate(90deg);margin-bottom:14px}
  body>*:not(#rotate){pointer-events:none}
}

/* ---------- the roll-on decision, drawn ----------
   The track above the target carries the marks a bigger hand pays for; the coins under the roll
   count are what banking now would pay from the rolls still in hand. Rolling burns a coin and
   moves you along the track, so the two prices sit on screen at once. */
.hud .bar{overflow:visible}
.bar .mark{position:absolute;top:50%;transform:translate(-50%,-50%);width:9px;height:9px;border-radius:50%;
 background:#2a2a22;border:2px solid #55554a;pointer-events:none;z-index:2;transition:background .18s,border-color .18s,box-shadow .18s}
.bar .mark.target{width:4px;height:14px;border-radius:2px;background:#fff;border:0;opacity:.9}
.bar .mark i{position:absolute;left:50%;bottom:calc(100% + 6px);transform:translateX(-50%);
 width:auto;height:auto;   /* .bar i is the FILL rule: it would collapse this label to nothing */
 font-style:normal;font-family:inherit;font-size:11px;font-weight:800;letter-spacing:.02em;line-height:1;
 padding:2px 5px;border-radius:7px;background:#1a1a15;white-space:nowrap;
 color:#6f6f60;font-variant-numeric:tabular-nums;transition:color .18s,transform .18s}
.bar .mark i::before{content:'○';margin-right:1px;font-size:9px;vertical-align:1px}
.bar .mark.lit{background:var(--gold);border-color:var(--gold);box-shadow:0 0 10px -2px var(--gold)}
.bar .mark.lit i{color:var(--gold)}
.bar .mark.last i{transform:translateX(-82%)}
.bar .mark.first i{transform:translateX(-30%)}
.bar .mark.next{border-color:var(--gold);box-shadow:0 0 0 3px rgba(255,201,77,.16)}
.bar .mark.next i{color:var(--gold)}
/* the frame a mark is reached: it strikes, then settles */
.bar .mark.ping{animation:markping .42s cubic-bezier(.2,1.6,.4,1)}
.bar .mark.ping i{animation:markpingn .42s cubic-bezier(.2,1.6,.4,1)}
@keyframes markping{
 0%{transform:translate(-50%,-50%) scale(1);box-shadow:0 0 0 0 rgba(255,201,77,.9)}
 45%{transform:translate(-50%,-50%) scale(2.1);box-shadow:0 0 18px 5px rgba(255,201,77,.75)}
 100%{transform:translate(-50%,-50%) scale(1);box-shadow:0 0 10px -2px var(--gold)}}
@keyframes markpingn{0%{filter:brightness(1)}40%{filter:brightness(2.2)}100%{filter:brightness(1)}}
@media (prefers-reduced-motion:reduce){.bar .mark.ping,.bar .mark.ping i{animation:none}}
.bar .mark.next{width:11px;height:11px}

/* The rolls, as pips, and the whole trade in one row: a GOLD pip is a roll that still pays you
   if you bank now, a plain pip is a roll that pays nothing, a hollow one is spent. Roll again and
   a gold pip goes out — the price, shown by the thing that changes. */
.hud .hr{position:relative}
.coins{display:flex;gap:var(--pipgap,5px);justify-content:flex-end;margin-top:6px;align-items:center;
 flex-wrap:nowrap;max-width:min(52vw,220px);overflow:hidden}
.coins i{display:block;flex:0 0 auto;width:var(--pip,11px);height:var(--pip,11px);border-radius:50%;
 transition:background .2s,box-shadow .2s,width .15s,height .15s}
.coins i.coin{background:var(--gold);box-shadow:0 0 0 1px rgba(255,201,77,.35),0 0 9px -1px rgba(255,201,77,.9)}
.coins i.roll{background:#5c5c4e;box-shadow:inset 0 0 0 1px #6d6d5c}
.coins i.gone{background:transparent;box-shadow:inset 0 0 0 1.5px #3d3d33}
@media(prefers-reduced-motion:reduce){.coins i{transition:none}}
@media(prefers-reduced-motion:reduce){.bar .mark,.bar .mark i{transition:none}}

/* ---------- the chapter's boss, announced before battle 1 ----------
   Same voice as the death sheet: one card, one thing to read, one button. The compact version
   lives in the boss row and never covers the dice. */
#bossCard{position:fixed;inset:0;z-index:75;display:flex;align-items:center;justify-content:center;padding:22px;
 background:radial-gradient(120% 70% at 50% 10%,#3a2028 0%,#191914 55%,#0f0f0c 100%);animation:bcin .22s ease-out}
@keyframes bcin{from{opacity:0}to{opacity:1}}
.bcbox{display:flex;flex-direction:column;align-items:center;gap:10px;text-align:center;max-width:340px;width:100%}
.bceyebrow{font-size:11px;font-weight:800;letter-spacing:.16em;color:var(--dim)}
.bcart{line-height:0;filter:drop-shadow(0 10px 22px rgba(255,95,138,.35))}
.bcart img{image-rendering:pixelated}
.bcname{font-size:clamp(22px,7vw,34px);font-weight:900;letter-spacing:.02em;color:var(--hot);text-shadow:0 0 26px rgba(255,95,138,.45)}
.bcrule{font-size:15px;line-height:1.4;color:var(--ink);max-width:30ch}
.bcwhen{font-size:13px;color:var(--dim);letter-spacing:.04em}
.bcwhen b{color:var(--gold)}
.bcgo{margin-top:8px;min-width:190px;min-height:52px;font-size:15px;font-weight:900;letter-spacing:.12em;
 border-radius:12px;background:var(--acc);color:#1e1e19;box-shadow:0 6px 0 #7f9a1c}
.bcgo:active{transform:translateY(3px);box-shadow:0 3px 0 #7f9a1c}
/* the quiet forecast card in the boss row: same shape, none of the alarm */
.fig.boss.ahead{border-color:#6b5a3a;background:#2b2620}
.fig.boss.ahead b{color:var(--gold)}
@media(prefers-reduced-motion:reduce){#bossCard{animation:none}}

/* The Silencer takes one companion for the battle: it is on the shelf, and plainly out of it. */
.shelf .fig.gagged,.shelfrow .fig.gagged{opacity:.42;filter:grayscale(1)}
.shelf .fig.gagged::after{content:'';position:absolute;left:14%;right:14%;top:50%;height:2px;background:var(--hot);transform:rotate(-18deg);border-radius:2px}

/* the run-end sheet says what happened and where, and gets out of the way */
#died .dwhere{font-size:clamp(15px,4.6vw,19px);font-weight:800;letter-spacing:.03em;color:var(--ink);margin-top:2px}
#died.won .dwhere{color:var(--acc)}
/* the XP tile is the party's XP-split anchor; on its own it reads as a line, not a grid */
/* the sheet is three short lines and two buttons now: let it be a box, not a full-height column */
#died .diedbox{min-height:0;justify-content:center}
#died .dstats.w{display:flex;justify-content:center;margin:6px 0 2px;flex:0 0 auto;max-height:none}
#died .dstats.w .dstat{background:none;border:0;padding:0;min-width:0;text-align:center}
#died .dstats.w .dstat span{letter-spacing:.14em}

/* The screen after the recap: what the run unlocked, one card each, arriving one after another. */
#died.found{background:radial-gradient(120% 70% at 50% 6%,#33291a 0%,#191914 55%,#101010 100%)}
#died.found .diedbox{justify-content:flex-start}
#died b.ft{font-size:min(12vw,58px);font-weight:900;letter-spacing:.1em;line-height:1;color:var(--gold);
 text-shadow:0 0 30px rgba(232,190,72,.55);animation:diedpop .5s cubic-bezier(.2,1.4,.4,1)}
#died .fsub{color:var(--dim);font-size:13px;font-weight:800;letter-spacing:.12em;text-transform:uppercase;margin-top:-6px}
#died .ugrid{display:flex;flex-direction:column;gap:10px;text-align:left}
#died .ucard{display:flex;align-items:center;gap:12px;padding:10px 12px;border-radius:14px;border:1px solid #5a4a28;
 background:linear-gradient(170deg,#2d281c,#1f1d16);box-shadow:0 0 22px -10px rgba(232,190,72,.7);
 opacity:0;animation:ucardin .45s cubic-bezier(.2,1.3,.4,1) forwards}
#died .ucard.uncommon{border-color:#3f8a72}#died .ucard.rare{border-color:#4f7fd6}#died .ucard.legendary{border-color:#c9962c}
#died .ucard .ic{flex:0 0 auto;width:52px;display:flex;justify-content:center}
#died .ucard .ic img{width:48px !important}
#died .ucard .hic{height:52px;align-items:center;border-radius:10px;background:#2a2433;color:#ff8fb0;font-weight:900;font-size:15px}
#died .ucard .tx{display:flex;flex-direction:column;gap:2px;min-width:0}
#died .ucard em{font-style:normal;font-size:10px;font-weight:900;letter-spacing:.14em;color:var(--gold)}
#died .ucard b{font-size:16px;color:var(--ink)}
#died .ucard span{font-size:13px;color:var(--ink);opacity:.85}
#died .ucard i{font-style:normal;font-size:11px;color:var(--dim)}
@keyframes ucardin{0%{opacity:0;transform:translateY(14px) scale(.92)}100%{opacity:1;transform:none}}
#diedNext{width:100%;min-height:56px;font-size:19px;font-weight:900;letter-spacing:.08em;border-radius:14px;
 background:var(--gold);color:#221a05;box-shadow:0 5px 0 #8a6a14;animation:diedpop .5s .2s both cubic-bezier(.2,1.4,.4,1)}
@media(prefers-reduced-motion:reduce){#died .ucard{animation:none;opacity:1}}
