/* Agragal — gothic necromancy. Palette and motion per GDD §15. */
:root{
  --floor:#16131d; --floor-2:#1d1926; --ink:#0d0b13;
  --panel:#171325; --panel-2:#1f1a30; --line:#2e2743;
  --bone:#e9e3d1; --bone-dim:#b3a98e;
  --necro:#57f2a1; --necro-deep:#1f8f5c;
  --xp:#4fd8ff; --xp-deep:#1b7fa8;
  --soul:#b087ff; --soul-deep:#5f38c4;
  --blood:#e0455a; --amber:#ffb454;
  --team:#ff5ce1; --team-deep:#a11a86;  /* witchfire: the lich and his staff */
  --danger:#ff3b57;
  --text:#d9d2ea; --muted:#8a80a8;
  --tile:40px;
}
*{box-sizing:border-box}
/* A game you tap fast: kill the 300ms double-tap zoom and the long-press text
   selection, and let the pad take a hold without highlighting. Pinch zoom is
   deliberately left alone. */
button,.dpad-btn,.rack-cell,.draft-card{touch-action:manipulation;-webkit-tap-highlight-color:transparent}
#deck,#foot,#brand,.dpad-btn,#status{-webkit-user-select:none;user-select:none}
html,body{margin:0;padding:0}
html{height:100%}
body{
  background:
    radial-gradient(1200px 700px at 50% -10%, #241c3a 0%, transparent 60%),
    var(--ink);
  color:var(--text);
  font:14px/1.5 ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
  /* NOT 100dvh: on a phone dvh is the toolbar-less height, which measures
     several px taller than innerHeight and left the page permanently
     scrollable by that difference. 100% of html is the real viewport. */
  min-height:100%;
  /* and a block formatting context, so the console's top margin cannot
     collapse out through body and push the document that many px taller */
  display:flow-root;
}
kbd{
  font:600 11px/1 ui-monospace,SFMono-Regular,Menlo,monospace;
  background:#241d3a;border:1px solid var(--line);border-bottom-width:2px;
  border-radius:4px;padding:2px 5px;color:var(--bone);
}
button{font:inherit;cursor:pointer}

/* --------------------------------------------------- the virtual console
   The whole game lives in a handheld: a brand strip, a recessed screen with
   thin status/info rails above and below it, and a control deck. No sidebar —
   everything that used to sit beside the board is now a rail, so the layout
   collapses to one column and scales down to a phone without reflowing. */
#console{
  --pad:clamp(9px,2.2vw,16px);
  --screen:clamp(216px, min(94vw, calc(100vh - 440px)), 552px);
  --screen:clamp(216px, min(94vw, calc(100dvh - 440px)), 552px);
  --case:#241d33; --case-hi:#332a49; --case-lo:#171126;
  --bezel:#0d0a16; --silk:#7a6fa3;
  width:min(100%,620px);margin:8px auto 10px;padding:var(--pad);
  background:linear-gradient(180deg,var(--case-hi),var(--case) 18%,var(--case-lo));
  border:1px solid #3b3157;border-radius:20px 20px 34px 34px;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.10),
    inset 0 -3px 0 rgba(0,0,0,.45),
    0 18px 48px rgba(0,0,0,.6);
}

#brand{display:flex;align-items:center;gap:9px;padding:2px 4px 9px}
#logo{width:26px;height:26px;filter:drop-shadow(0 0 7px rgba(87,242,161,.35))}
#brand h1{
  margin:0;font-size:16px;letter-spacing:.17em;text-transform:uppercase;
  color:var(--bone);font-weight:800;text-shadow:0 0 12px rgba(176,135,255,.45);
}
#date-label{font-size:10.5px;color:var(--silk);letter-spacing:.05em;min-width:0;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
#share-btn{
  margin-left:auto;flex:none;background:#2c2347;color:var(--text);
  border:1px solid #43376b;border-bottom-width:2px;border-radius:7px;
  padding:5px 12px;min-height:40px;font-size:12px;
}
#share-btn:hover{background:#382c5c}
#sfx-btn{
  margin-left:auto;flex:none;display:grid;place-items:center;
  background:#2c2347;color:var(--silk);border:1px solid #43376b;border-bottom-width:2px;
  border-radius:7px;width:40px;height:40px;padding:0;
}
#sfx-btn+#share-btn{margin-left:6px}   /* the pair travels together, right-aligned */
#sfx-btn svg{width:19px;height:19px;display:block}
#sfx-btn:hover{background:#382c5c;color:var(--text)}
#sfx-btn.off{color:#6a5f8c;background:#231c39}

/* ------------------------------------------------------------ the screen */
#screen{
  background:var(--bezel);border-radius:12px;padding:6px;
  border:1px solid #05040a;
  box-shadow:inset 0 2px 7px rgba(0,0,0,.9), 0 1px 0 rgba(255,255,255,.06);
}
#status{display:flex;align-items:center;gap:6px;padding:1px 2px 5px}
.st-bar{
  position:relative;flex:1 1 0;min-width:54px;height:15px;border-radius:8px;
  background:#0a0812;border:1px solid #2a2340;overflow:hidden;
}
.st-bar i{display:block;height:100%;width:0;transition:width .18s ease-out}
.st-bar.hp i{background:linear-gradient(90deg,#8d2130,var(--blood))}
.st-bar.xp i{background:linear-gradient(90deg,var(--xp-deep),var(--xp))}
.st-bar b{
  position:absolute;inset:0;display:grid;place-items:center;
  font:700 9.5px/1 ui-monospace,SFMono-Regular,Menlo,monospace;
  color:#fff;text-shadow:0 1px 2px rgba(0,0,0,.95);
}
.st-chip{
  display:inline-flex;align-items:center;gap:3px;flex:none;
  font:600 9px/1 ui-monospace,SFMono-Regular,Menlo,monospace;
  color:var(--silk);letter-spacing:.06em;
  background:#100c1c;border:1px solid #251e3a;border-radius:6px;padding:4px 6px;
}
.st-chip b{color:var(--bone);font-size:11px}

#phyl{
  position:relative;height:13px;margin-bottom:6px;border-radius:7px;overflow:hidden;
  background:#0a0812;border:1px solid #2a2340;
}
#dawn-fill{display:block;height:100%;width:0;
  background:linear-gradient(90deg,var(--soul-deep),var(--soul));transition:width .2s}
#dawn-fill.lit{background:linear-gradient(90deg,#c9821f,var(--amber))}
#phyl span{
  position:absolute;inset:0;display:grid;place-items:center;
  font:700 8.5px/1 ui-monospace,SFMono-Regular,Menlo,monospace;
  color:#fff;letter-spacing:.08em;text-shadow:0 1px 2px rgba(0,0,0,.95);
}
#phyl span.urgent{color:#fff2cf;animation:telepulse .8s ease-in-out infinite}

#board-wrap{position:relative;width:var(--screen);height:var(--screen);margin:0 auto}
#game{
  display:block;width:100%;height:100%;
  background:var(--floor);border-radius:5px;
  box-shadow:inset 0 0 60px rgba(0,0,0,.8);
}
.sprite-sheet{position:absolute;width:0;height:0;overflow:hidden;pointer-events:none}
#sheet-host{position:absolute;width:0;height:0;overflow:hidden}

/* the rails under the display: rack + streak, then the log */
#rackline{display:flex;align-items:center;gap:8px;padding:6px 2px 0}
/* One fixed row of ten: a wrapped second row pushed the page past a phone's
   screen late in the night. On a narrow screen the cells shrink instead. */
#rack-grid{display:grid;grid-template-columns:repeat(10,minmax(0,29px));gap:4px;flex:1;min-width:0}
.rl-meta{display:flex;align-items:center;gap:6px;flex:none}
#streak-box{
  display:inline-flex;align-items:center;gap:3px;
  font:600 10px/1 ui-monospace,monospace;color:var(--silk);
  background:#100c1c;border:1px solid #251e3a;border-radius:6px;padding:4px 7px;
}
#streak-box b{color:var(--amber);font-size:12px}
/* Only where the rail has room: on a phone it crushed ten rack cells to slivers. */
#day-record{display:none;font-size:9.5px;color:var(--silk);white-space:nowrap}
@media (min-width:700px) and (min-height:561px){
  #day-record{display:inline}
}
.hidden{display:none !important}
.rack-cell{
  display:flex;flex-direction:column;align-items:center;gap:2px;
  background:#100c1c;border:1px solid #251e3a;border-radius:6px;padding:3px 1px 2px;min-width:0;
}
.rack-cell.p{border-color:#33285a}
.rack-cell.maxed{border-color:var(--amber);box-shadow:0 0 6px rgba(255,180,84,.3)}
.rack-cell svg{width:min(17px,100%);height:auto;aspect-ratio:1}
.pips{display:flex;gap:1.5px}
.pips i{width:2.5px;height:2.5px;border-radius:50%;background:var(--necro)}
.rack-cell.p .pips i{background:var(--soul)}
.pips i.off{background:#332c4d}
#log{
  padding:4px 3px 2px;font-size:10.5px;line-height:1.4;color:var(--muted);
  height:35px;overflow:hidden;
}
#log div{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;opacity:.55}
#log div:last-child{color:var(--text);opacity:1}

/* ------------------------------------------------------------- the deck */
#deck{
  display:flex;align-items:center;justify-content:center;
  padding:calc(var(--pad) + 2px) 4px 2px;
}
.pad-col{display:flex;flex-direction:column;align-items:center;gap:9px}
.silk{
  font:600 8px/1.3 ui-monospace,SFMono-Regular,Menlo,monospace;
  letter-spacing:.14em;text-transform:uppercase;color:var(--silk);text-align:center;
}
.silk kbd{font-size:8px;padding:1px 4px;background:#191233;border-color:#3b3157}

#dpad{
  --cell:clamp(50px,15vw,66px);
  display:grid;grid-template-columns:repeat(3,var(--cell));
  grid-template-rows:repeat(3,var(--cell));gap:9px;
  padding:9px;background:#15101f;border-radius:18px;
  box-shadow:inset 0 2px 5px rgba(0,0,0,.7),0 1px 0 rgba(255,255,255,.05);
}
.dpad-btn{
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:1px;
  background:linear-gradient(180deg,#3b3157,#2a2240);
  border:1px solid #4a3d6e;border-radius:8px;
  color:var(--bone);box-shadow:0 2px 0 #191233;padding:0;
}
.dpad-btn i{font:normal 17px/1 ui-sans-serif,system-ui;font-style:normal}
.dpad-btn b{font:700 9px/1 ui-monospace,SFMono-Regular,Menlo,monospace;
  letter-spacing:.05em;color:var(--silk)}
.dpad-btn.dg{background:linear-gradient(180deg,#332a49,#241d36)}
.dpad-btn.dg i{color:var(--silk)}
.dpad-btn.wait{background:#1d1730;box-shadow:inset 0 2px 4px rgba(0,0,0,.6)}
.dpad-btn.wait i{color:var(--silk);font-size:15px}
.dpad-btn.wait b{font-size:7px}
.dpad-btn:active{transform:translateY(2px);box-shadow:none;background:var(--soul-deep)}

/* a round in flight dims the deck, but a press still lands — it rushes the
   round rather than being dropped, so the controls stay live */
#console.busy #dpad{opacity:.6}

/* ...and when it is rushed, the motion shortens to match */
#game.rush #l-ents .ent{transition-duration:55ms}
#game.rush #l-hero .hero{transition-duration:45ms}
#game.rush .fx{animation-duration:.15s}
#game.rush .dnum{animation-duration:.28s}
#game.rush .fx-orb{animation-duration:.12s}

#foot{display:flex;justify-content:center;gap:10px;padding:calc(var(--pad) + 4px) 0 2px}
#foot button{
  background:#1d1730;color:var(--silk);border:1px solid #322853;
  border-bottom-width:2px;border-radius:16px;padding:5px 15px;
  min-height:40px;                     /* a thumb, not a mouse pointer */
  font:600 9px/1 ui-monospace,monospace;letter-spacing:.16em;text-transform:uppercase;
}
#foot button:hover{background:#282047;color:var(--text)}

/* ------------------------------------------------------------ the board */
/* the follow camera: one transform on the world group, glided by CSS */
#world{transition:transform 130ms ease-out}
#game.rush #world{transition-duration:50ms}
#l-props use.prop{filter:drop-shadow(0 2px 3px rgba(0,0,0,.6))}
#l-props use.bones{filter:none}

/* One colour language for the floor: gold is worth having, red will hurt you,
   teal is a soul. Traps are meant to be seen — armed ones breathe. */
#l-mire use.harm{opacity:.92;filter:drop-shadow(0 0 4px rgba(224,69,90,.3))}
#l-traps use{animation:trapPulse 1.6s ease-in-out infinite;transition:opacity .25s}
@keyframes trapPulse{0%,100%{filter:drop-shadow(0 0 4px rgba(224,69,90,.6))}
  50%{filter:drop-shadow(0 0 11px rgba(255,59,87,1))}}
#l-traps use.spent{opacity:.3;filter:grayscale(1) brightness(.6);animation:none}

/* the three beats of a turn: the lich (0.1s), then the undead (0.2s) */
#l-hero .hero{transition:transform 100ms ease-out}
#l-ents .ent{transition:transform 200ms cubic-bezier(.25,.8,.35,1)}
#l-ents .ent.dying{animation:entDie .26s ease-out forwards}
@keyframes entDie{to{opacity:0;filter:brightness(2.6) saturate(.2)}}
/* the bigger the silhouette, the redder the air around it */
#l-ents .ent.t1 .body{filter:drop-shadow(0 0 4px rgba(224,69,90,.35))}
#l-ents .ent.t2 .body{filter:drop-shadow(0 0 7px rgba(224,69,90,.6))}
#l-ents .ent.t3 .body{filter:drop-shadow(0 0 11px rgba(255,45,70,.9)) drop-shadow(0 0 22px rgba(224,69,90,.55))}
#l-ents .ent.big{z-index:2}
#l-ents .ent.phasing{opacity:.72}
#l-ents .ent.flash .body{filter:brightness(2.4) saturate(.3)}
/* Grasping Hands (and mire, and traps): held fast — pale, bone-bound, still */
#l-ents .ent.held .body{filter:saturate(.35) brightness(1.15) drop-shadow(0 0 5px rgba(233,227,209,.9))}
/* Plague: rotting, sick yellow-green, and it bubbles */
#l-ents .ent.plagued .body{filter:sepia(.5) hue-rotate(40deg) saturate(1.6) drop-shadow(0 0 6px rgba(169,207,69,.95))}
/* Death Mark: the sentence hangs over its head until it falls */
#l-ents .mark-glyph{filter:drop-shadow(0 0 6px rgba(176,135,255,.95));animation:telepulse .8s ease-in-out infinite}
/* a skeleton's heap on the floor — red the turn before it stands up */
#l-heaps .heap{opacity:.85;filter:drop-shadow(0 1px 2px rgba(0,0,0,.6))}
#l-heaps .heap.rising{filter:drop-shadow(0 0 7px rgba(224,69,90,.95));animation:telepulse .7s ease-in-out infinite}
#l-ents .ent.feared .body{transform-box:fill-box;transform-origin:center;
  filter:saturate(.4) brightness(1.25) drop-shadow(0 0 7px rgba(233,227,209,.9));
  animation:shiver .34s linear infinite}
@keyframes shiver{25%{transform:translateX(-1.2px)}75%{transform:translateX(1.2px)}}
/* witchfire marks your side and nothing else in the sanctum */
#l-hero .hero .body{filter:drop-shadow(0 0 8px rgba(255,92,225,.6))}
#l-hero .hero.slowed .body{filter:drop-shadow(0 0 8px rgba(255,92,225,.6)) sepia(.6) hue-rotate(250deg)}
#l-hero .hero .ward-ring{display:none;fill:none;stroke:#e9e3d1;stroke-width:3;stroke-dasharray:7 3;
  filter:drop-shadow(0 0 5px rgba(233,227,209,.8));transform-box:fill-box;transform-origin:center;
  animation:wardspin 6s linear infinite}
#l-hero .hero.warded .ward-ring{display:block}
@keyframes wardspin{to{transform:rotate(360deg)}}
#l-hero .hero.rites .body{filter:drop-shadow(0 0 10px rgba(224,69,90,.95)) drop-shadow(0 0 3px rgba(255,180,84,.8))}
#l-ents .ent.mine .body{filter:drop-shadow(0 0 6px rgba(255,92,225,.75))}
#l-ents .ent.mine .hp-f{fill:var(--team)}

/* your reach: a breath of witchlight on the floor, no border. It has to be
   readable without competing with a telegraph two tiles away. */
.magnet{
  fill:url(#g-reach);stroke:none;pointer-events:none;
  animation:magnetPulse 3.4s ease-in-out infinite;
}
@keyframes magnetPulse{50%{opacity:.62}}
#l-hero .hero.dawn .body{
  filter:drop-shadow(0 0 16px rgba(255,180,84,.95)) drop-shadow(0 0 34px rgba(255,220,140,.6));
  animation:dawnpulse 1.2s ease-in-out infinite;
}
@keyframes dawnpulse{50%{filter:drop-shadow(0 0 24px rgba(255,214,148,1)) drop-shadow(0 0 48px rgba(255,180,84,.75))}}

/* the one worth killing: an undead with a spell already armed */
#l-ents .ent.casting .body{
  filter:drop-shadow(0 0 8px #ff3b57) drop-shadow(0 0 16px rgba(255,59,87,.7)) saturate(1.7) brightness(1.15);
  animation:castpulse .7s ease-in-out infinite;
}
@keyframes castpulse{50%{filter:drop-shadow(0 0 14px #ff5c72) drop-shadow(0 0 26px rgba(255,59,87,.95)) saturate(2.2) brightness(1.35)}}

/* HP over the head — dark track, colour by remaining fraction. Full-health
   trash keeps its bar dim so sixty of them do not drown out the telegraphs;
   anything wounded, elite, or you, shows at full strength. */
.hp-t{fill:#0a0810;opacity:.55}
.hp-f{transition:width .18s ease-out;opacity:.5}
#l-ents .ent.hurt-bar .hp-t,#l-ents .ent.big .hp-t{opacity:.9}
#l-ents .ent.hurt-bar .hp-f,#l-ents .ent.big .hp-f{opacity:1}
#l-hero .hero .hp-t{opacity:.9}
#l-hero .hero .hp-f{opacity:1}

/* Bone Orbit: one full revolution per turn, and only when the sweep lands.
   A continuous spin showed shards crossing an undead on turns the weapon had
   not fired, which is exactly the lie we are trying not to tell. */

/* soul orbs: the wrapper <g> holds the tile position, the <use> inside is
   free to bob and flicker. Each orb's delay is seeded from its id so the
   floor shimmers instead of pulsing in unison. */
#l-orbs .orb{animation:orbIn .28s ease-out}
@keyframes orbIn{from{opacity:0}}
#l-orbs .orb-core{
  transform-origin:20px 20px;
  animation:orbBob 1.9s ease-in-out infinite, orbFlicker .9s ease-in-out infinite;
}
@keyframes orbBob{50%{transform:translateY(-2px) scale(1.05)}}
@keyframes orbFlicker{
  0%,100%{opacity:.9;filter:drop-shadow(0 0 4px rgba(79,216,255,.7))}
  34%{opacity:1;filter:drop-shadow(0 0 10px rgba(79,216,255,1))}
  62%{opacity:.82;filter:drop-shadow(0 0 3px rgba(79,216,255,.55))}
}

/* telegraphs sit UNDER the entities: you must always see the horde */
rect.tele{
  fill:rgba(255,59,87,.18);stroke:rgba(255,59,87,.62);stroke-width:1.5;
  animation:telepulse .9s ease-in-out infinite;
}
rect.tele-hot{fill:rgba(255,59,87,.3);stroke:rgba(255,120,140,.95);stroke-width:2}
@keyframes telepulse{50%{fill:rgba(255,59,87,.32)}}

/* floating damage: green off the undead, red off the lich, gold on a crit */
.dnum{
  font:800 14px/1 ui-monospace,SFMono-Regular,Menlo,monospace;
  fill:#8dffc4;paint-order:stroke;stroke:#07050b;stroke-width:3.5px;stroke-linejoin:round;
  pointer-events:none;
  /* without fill-box the scale below happens about the centre of the whole
     1640px arena and the number is flung halfway across the map */
  transform-box:fill-box;transform-origin:center;
  animation:dfloat .75s ease-out forwards;
}
@keyframes dfloat{
  0%{opacity:0;transform:translate(0,2px) scale(.8)}
  20%{opacity:1;transform:translate(0,-1px) scale(1.06)}
  70%{opacity:1;transform:translate(var(--drift,0),-6px) scale(1)}
  100%{opacity:0;transform:translate(var(--drift,0),-11px) scale(1)}
}
.dnum.crit{fill:#ffd694;font-size:20px}
.dnum.taken{fill:#ff8a9c}
.dnum.miss{fill:#b0a6cc;font-size:12px;font-weight:600}

.fx{pointer-events:none;animation:fxout .4s ease-out forwards}
@keyframes fxout{to{opacity:0}}
/* Soulbolt is a beam, not a dart: three stacked strokes (flare, body, white
   core) read as a laser, and both ends flash where it leaves and lands. */
.fx-beam{filter:drop-shadow(0 0 7px var(--soul)) drop-shadow(0 0 16px rgba(176,135,255,.75))}
.fx-beam line{stroke-linecap:round;animation:beamFade .34s ease-out forwards}
.fx-beam .beam-glow{stroke:rgba(176,135,255,.34);stroke-width:13}
.fx-beam .beam-body{stroke:var(--soul);stroke-width:6}
.fx-beam .beam-core{stroke:#f4ecff;stroke-width:2.2}
.fx-beam circle{transform-box:fill-box;transform-origin:center}
.fx-beam .beam-muzzle{fill:rgba(244,236,255,.85);animation:beamPop .3s ease-out forwards}
.fx-beam .beam-hit{fill:rgba(176,135,255,.5);stroke:#f4ecff;stroke-width:2;
  animation:fxgrow .34s ease-out forwards}
@keyframes beamFade{0%{opacity:1}62%{opacity:.9}100%{opacity:0}}
@keyframes beamPop{0%{opacity:1;transform:scale(.4)}100%{opacity:0;transform:scale(1.5)}}
.fx-blink{fill:none;stroke:var(--necro);stroke-width:3;stroke-linecap:round;
  filter:drop-shadow(0 0 5px var(--necro))}
/* Death Arc: the chain is drawn on from the lich outward, so the eye follows
   it body to body instead of a whole polyline appearing at once */
/* Death Arc is lightning: a fat blue discharge with a white-hot core inside
   it, thrown off the straight line and forking as it goes. */
.fx-arc{filter:drop-shadow(0 0 5px #4fd8ff) drop-shadow(0 0 14px rgba(79,216,255,.8))
         drop-shadow(0 0 26px rgba(43,140,255,.45))}
.fx-arc polyline{fill:none;stroke-linejoin:round;stroke-linecap:round}
.fx-arc .arc-glow{stroke:#3fbaff;stroke-width:7;opacity:.55}
.fx-arc .arc-core{stroke:#f2fbff;stroke-width:2.4}
.fx-arcfork{stroke:#cdeeff;stroke-width:2.2;stroke-linecap:round;opacity:.9;
  filter:drop-shadow(0 0 6px #4fd8ff) drop-shadow(0 0 12px rgba(79,216,255,.7));
  animation:forkFlick .3s steps(3) forwards}
@keyframes forkFlick{0%{opacity:.95}60%{opacity:.45}100%{opacity:0}}
.fx-arc.draw polyline{
  stroke-dasharray:var(--len);stroke-dashoffset:var(--len);
  animation:arcDraw .2s linear forwards, fxout .36s .2s ease-out forwards;
}
@keyframes arcDraw{to{stroke-dashoffset:0}}
.fx-arcnode{
  fill:none;stroke:#dff4ff;stroke-width:2.4;opacity:0;
  transform-box:fill-box;transform-origin:center;
  filter:drop-shadow(0 0 6px #4fd8ff);
  animation:arcHit .34s ease-out forwards;
}
@keyframes arcHit{
  0%{opacity:0;transform:scale(.3)}
  25%{opacity:1;transform:scale(.75)}
  100%{opacity:0;transform:scale(1.35)}
}
#game.rush .fx-arc.draw polyline{animation-duration:.1s,.16s}
#game.rush .fx-arcnode{animation-duration:.16s}
#game.rush .fx-beam line,#game.rush .fx-beam circle{animation-duration:.14s}
#game.rush .fx-siphon *{animation-duration:.16s}
#game.rush .fx-swing{animation-duration:.12s}
#game.rush .fx-spikeup{--d:0ms;animation-duration:.13s}
#game.rush .fx-handup{--d:0ms;animation-duration:.13s}
#game.rush .fx-plague *,#game.rush .fx-doom *,#game.rush .fx-tear rect{animation-duration:.14s}
.fx-blink{stroke:var(--soul);stroke-width:4;stroke-linecap:round;opacity:.8}
.fx-die,.fx-burn,.fx-hurt,.fx-trap{transform-box:fill-box;transform-origin:center}
@keyframes fxgrow{from{transform:scale(.55)}to{transform:scale(1);opacity:0}}
.fx-scythe{
  fill:none;stroke:#eafff4;stroke-width:6;stroke-linecap:round;
  filter:drop-shadow(0 0 6px var(--necro)) drop-shadow(0 0 12px rgba(87,242,161,.7));
  animation:fxslash .38s ease-out forwards;
}
@keyframes fxslash{from{opacity:.95;stroke-width:8}to{opacity:0;stroke-width:3}}
.fx-swing{transform-origin:0 0;transform:rotate(var(--a0));
  animation:fxswing .34s cubic-bezier(.25,.6,.3,1) forwards}
.fx-swing .blade{filter:drop-shadow(0 0 5px rgba(87,242,161,.8))}
@keyframes fxswing{0%{transform:rotate(var(--a0));opacity:1}72%{opacity:1}
  100%{transform:rotate(var(--a1));opacity:0}}
.fx-spikeup{transform-box:fill-box;transform-origin:50% 100%;
  animation:fxrise .38s cubic-bezier(.2,.85,.3,1) var(--d,0ms) both;
  filter:drop-shadow(0 0 4px rgba(233,227,209,.6))}
@keyframes fxrise{0%{transform:translateY(26%) scaleY(.12);opacity:0}30%{opacity:1}
  75%{transform:translateY(0) scaleY(1);opacity:1}100%{transform:translateY(0) scaleY(1);opacity:0}}
.fx-knell{fill:rgba(233,227,209,.1);stroke:#eafff4;stroke-width:3;animation:fxgrow .45s ease-out forwards}
/* Soul Siphon: a funnel with its mouth on the undead, pinched at the lich,
   and the drink visibly running down it the wrong way — inward. */
.fx-siphon{filter:drop-shadow(0 0 6px rgba(141,255,196,.7))}
.fx-siphon .siphon-cone{fill:rgba(141,255,196,.20);stroke:rgba(141,255,196,.75);stroke-width:1.3;
  animation:siphonPull .5s ease-out forwards}
.fx-siphon .siphon-flow{stroke:#dfffee;stroke-width:3;stroke-linecap:round;
  stroke-dasharray:3 9;animation:siphonFlow .5s linear forwards}
.fx-siphon .siphon-mouth{fill:#dfffee;transform-box:fill-box;transform-origin:center;
  animation:siphonDrink .5s ease-out forwards}
@keyframes siphonPull{0%{opacity:.25}35%{opacity:1}100%{opacity:0}}
@keyframes siphonFlow{from{stroke-dashoffset:48}to{stroke-dashoffset:0}}
@keyframes siphonDrink{0%{transform:scale(.3);opacity:.4}55%{transform:scale(1.2);opacity:1}100%{transform:scale(.6);opacity:0}}
.fx-boltdot{fill:rgba(87,242,161,.45);stroke:var(--necro);stroke-width:2;
  transform-box:fill-box;transform-origin:center;animation:fxgrow .32s ease-out forwards}
.fx-corpse{fill:rgba(87,242,161,.26);stroke:var(--necro);stroke-width:3;animation:fxgrow .38s ease-out forwards;filter:drop-shadow(0 0 6px rgba(87,242,161,.8))}
.fx-revive{fill:rgba(255,92,225,.2);stroke:var(--team);stroke-width:4;animation:fxgrow .6s ease-out forwards}
.fx-witchfire{fill:rgba(255,92,225,.3);stroke:var(--amber);stroke-width:3;animation:fxgrow .45s ease-out forwards;
  filter:drop-shadow(0 0 8px rgba(255,92,225,.9)) drop-shadow(0 0 16px rgba(255,180,84,.5))}
.fx-knell,.fx-corpse,.fx-revive,.fx-witchfire{transform-box:fill-box;transform-origin:center}
.dnum.heal{fill:#8dffc4}
.dnum.rot{fill:#c6e86a}
.fx-spikes rect{fill:rgba(233,227,209,.24);stroke:var(--bone-dim)}
.fx-blast rect{fill:rgba(255,59,87,.55);stroke:#ff8a9c}
/* a death is a burst of loose soul, not a green coin on the floor */
.fx-die{fill:none;stroke:rgba(87,242,161,.9);stroke-width:3.5;animation:fxburst .42s ease-out forwards}
.fx-burn{fill:none;stroke:rgba(255,214,148,.95);stroke-width:3.5;animation:fxburst .42s ease-out forwards}
.fx-trap{fill:none;stroke:rgba(255,59,87,.95);stroke-width:3.5;animation:fxburst .42s ease-out forwards}
.fx-raise,.fx-effigy,.fx-crush,.fx-reform{transform-box:fill-box;transform-origin:center;fill:none;stroke-width:3;animation:fxburst .42s ease-out forwards}
.fx-raise,.fx-effigy{stroke:var(--team);filter:drop-shadow(0 0 6px rgba(255,92,225,.8))}
.fx-crush{stroke:rgba(233,227,209,.85);stroke-dasharray:4 3}
.fx-reform{stroke:rgba(224,69,90,.9)}
/* Grasping Hands: a hand clawing up out of every tile */
.fx-hands rect{fill:rgba(233,227,209,.16);stroke:rgba(179,169,142,.6)}
.fx-handup{transform-box:fill-box;transform-origin:50% 100%;
  animation:fxrise .42s cubic-bezier(.2,.85,.3,1) var(--d,0ms) both;
  filter:drop-shadow(0 0 5px rgba(87,242,161,.7))}
/* Plague: a gob of sickness, and the hop body to body */
.fx-plague line{stroke:#a9cf45;stroke-width:3;stroke-linecap:round;stroke-dasharray:2 6;animation:beamFade .4s ease-out forwards}
.fx-plague circle{fill:rgba(169,207,69,.45);stroke:#d7ff6a;stroke-width:1.5;transform-box:fill-box;transform-origin:center;
  animation:fxgrow .4s ease-out forwards}
.fx-plague{filter:drop-shadow(0 0 6px rgba(169,207,69,.9))}
.fx-plague.hop line{stroke-width:2}
/* Death Mark: the name flares as it is written; the sentence falls from above */
.fx-markin{transform-box:fill-box;transform-origin:center;filter:drop-shadow(0 0 8px rgba(176,135,255,.95));
  animation:markin .45s ease-out forwards}
@keyframes markin{0%{transform:scale(1.8);opacity:0}40%{opacity:1}100%{transform:scale(1);opacity:0}}
.fx-doom{filter:drop-shadow(0 0 8px rgba(176,135,255,.95)) drop-shadow(0 0 18px rgba(95,56,196,.7))}
.fx-doom .doom-blade{stroke:#f4ecff;stroke-width:5;stroke-linecap:round;stroke-dasharray:120;stroke-dashoffset:120;
  animation:doomfall .22s cubic-bezier(.6,0,1,1) forwards, fxout .3s .22s ease-out forwards}
.fx-doom .doom-hit{fill:rgba(176,135,255,.45);stroke:#f4ecff;stroke-width:2.5;transform-box:fill-box;transform-origin:center;
  opacity:0;animation:fxgrow .36s .2s ease-out forwards}
@keyframes doomfall{to{stroke-dashoffset:0}}
/* the Bone Ward shatters taking the hit */
.fx-shield{fill:none;stroke:#e9e3d1;stroke-width:4;stroke-dasharray:6 4;transform-box:fill-box;transform-origin:center;
  filter:drop-shadow(0 0 7px rgba(233,227,209,.9));animation:fxburst .42s ease-out forwards}
/* an Unbound Folio tears: paper scraps */
.fx-tear rect{fill:#e8dcc0;transform-box:fill-box;transform-origin:center;animation:tear .5s ease-out forwards}
@keyframes tear{to{transform:translate(var(--dx),var(--dy)) rotate(200deg);opacity:0}}
/* a Grave Hound's pounce */
.fx-leap{stroke:rgba(224,69,90,.8);stroke-width:5;stroke-linecap:round;animation:beamFade .3s ease-out forwards}
@keyframes fxburst{from{transform:scale(.3);opacity:1}to{transform:scale(1.3);opacity:0}}
.fx-hurt{fill:rgba(224,69,90,.5);stroke:#ff8a9c;stroke-width:2;animation:fxgrow .4s ease-out forwards}
/* a collected soul streaks into the lich and is swallowed */
.fx-orb{
  transform-origin:20px 20px;
  filter:drop-shadow(0 0 7px rgba(79,216,255,.95));
  animation:orbFly .34s cubic-bezier(.45,0,.9,.55) forwards;
}
@keyframes orbFly{
  0%{transform:translate(0,0) scale(1);opacity:1}
  100%{transform:translate(var(--dx),var(--dy)) scale(.2);opacity:0}
}

/* off-screen signposts — fairness with a follow camera (GDD 12), and, since
   the minimap is gone, the only way to find the door */
#edge-warn .edge{
  position:absolute;width:0;height:0;margin:-6px 0 0 -6px;
  border-left:6px solid transparent;border-right:6px solid transparent;
  border-bottom:10px solid var(--danger);
  transform:rotate(var(--a,0));
  filter:drop-shadow(0 0 5px var(--danger));
  animation:telepulse .9s ease-in-out infinite;
}
#edge-warn .edge.door{
  border-bottom-color:var(--amber);filter:drop-shadow(0 0 5px rgba(255,180,84,.7));
  opacity:.55;animation:none;
}
#edge-warn .edge.door.open{
  opacity:1;margin:-8px 0 0 -8px;
  border-left-width:8px;border-right-width:8px;border-bottom-width:13px;
  filter:drop-shadow(0 0 11px var(--amber));animation:telepulse .9s ease-in-out infinite;
}
#dawn-flash{opacity:0;border-radius:5px;
  background:radial-gradient(circle at 50% 50%,rgba(255,238,200,.95),rgba(255,180,84,.35) 45%,transparent 72%)}
#dawn-flash.go{animation:dawnflash 1.5s ease-out}
@keyframes dawnflash{0%{opacity:0}12%{opacity:1}100%{opacity:0}}
/* taking a hit: the glass flushes red from the edges and the lich flinches */
#hurt-flash{position:absolute;inset:0;pointer-events:none;opacity:0;border-radius:5px;
  background:radial-gradient(circle at 50% 50%,transparent 42%,rgba(224,69,90,.30) 74%,rgba(255,45,70,.62) 100%)}
#hurt-flash.go{animation:hurtflash .42s ease-out}
@keyframes hurtflash{0%{opacity:0}14%{opacity:1}100%{opacity:0}}
#l-hero .hero.struck .body{animation:struck .32s steps(2,jump-none)}
@keyframes struck{0%{filter:brightness(1.7) saturate(4) hue-rotate(-40deg)}100%{filter:none}}
#game.rush #hurt-flash.go{animation-duration:.16s}

/* ------------------------------------------------------------- modals */
.modal{
  position:fixed;inset:0;z-index:40;display:grid;place-items:center;padding:16px;
  overflow-y:auto;overscroll-behavior:contain;
  background:rgba(8,6,14,.82);backdrop-filter:blur(3px);
}
.modal-card{
  position:relative;background:var(--panel-2);border:1px solid var(--line);
  border-radius:14px;padding:22px;max-width:620px;width:100%;
  max-height:84vh;overflow:auto;box-shadow:0 24px 70px rgba(0,0,0,.7);
}
.modal-card h2{margin:0 0 14px;font-size:19px;color:var(--bone);letter-spacing:.04em}
.modal-close{
  position:absolute;top:4px;right:6px;background:none;border:0;
  color:var(--muted);font-size:24px;line-height:1;
  width:44px;height:44px;display:grid;place-items:center;  /* a real tap target */
}
.modal-close:hover{color:var(--bone)}

.draft-card-wrap{max-width:880px;width:100%;text-align:center}
.draft-title{margin:0;font-size:21px;color:var(--bone);letter-spacing:.03em;
  text-shadow:0 0 22px rgba(87,242,161,.35)}
.draft-sub{margin:5px 0 18px;color:var(--muted);font-size:13px}
.draft-sub b{color:var(--necro)}
#draft-list{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px}
.draft-card{
  position:relative;display:flex;flex-direction:column;align-items:center;gap:7px;
  background:linear-gradient(180deg,#241d3d,#1a1530);
  border:1px solid var(--line);border-radius:13px;padding:20px 14px 16px;
  color:var(--text);text-align:center;transition:transform .12s,border-color .12s,box-shadow .12s;
}
.draft-card:hover{transform:translateY(-4px);border-color:var(--necro-deep);
  box-shadow:0 12px 34px rgba(0,0,0,.55),0 0 0 1px rgba(87,242,161,.3)}
.draft-card.passive:hover{border-color:var(--soul-deep);box-shadow:0 12px 34px rgba(0,0,0,.55),0 0 0 1px rgba(176,135,255,.35)}
.dc-key{position:absolute;top:8px;left:10px;font:600 11px/1 ui-monospace,monospace;
  color:var(--muted);border:1px solid var(--line);border-radius:4px;padding:2px 5px}
.dc-icon{width:52px;height:52px;filter:drop-shadow(0 0 12px rgba(87,242,161,.3))}
.draft-card.passive .dc-icon{filter:drop-shadow(0 0 12px rgba(176,135,255,.35))}
.dc-name{font-size:15px;font-weight:600;color:var(--bone)}
.dc-tag{font-size:10px;text-transform:uppercase;letter-spacing:.1em;color:var(--necro)}
.draft-card.passive .dc-tag{color:var(--soul)}
.dc-cad{
  font:600 11px/1 ui-monospace,SFMono-Regular,Menlo,monospace;
  color:var(--bone-dim);border:1px solid var(--line);border-radius:20px;padding:4px 10px;
  white-space:nowrap;
}
.dc-desc{font-size:12px;color:var(--muted);line-height:1.45}

/* On a phone three columns cannot hold a spell card: the cadence pill alone
   sets a ~155px floor, which pushed the third card off the screen entirely and
   made it unpickable. One column of wide rows instead — same information, and
   each option becomes a target you cannot miss. */
@media (max-width:560px){
  .draft-title{font-size:18px}
  .draft-sub{margin:4px 0 12px;font-size:12px}
  #draft-list{grid-template-columns:1fr;gap:9px}
  .draft-card{
    display:grid;align-items:center;text-align:left;
    grid-template-columns:auto minmax(0,1fr) auto;
    grid-template-areas:
      "icon name name"
      "icon tag  cad"
      "icon desc desc";
    gap:3px 12px;padding:12px 14px;
  }
  .draft-card:hover{transform:none}
  .dc-key{display:none}                       /* there is no number row to press */
  .dc-icon{grid-area:icon;width:44px;height:44px;align-self:center}
  .dc-name{grid-area:name;font-size:15px}
  .dc-tag{grid-area:tag;align-self:center}
  .dc-cad{grid-area:cad;align-self:center;padding:3px 8px;font-size:10px}
  .dc-desc{grid-area:desc;font-size:11.5px;line-height:1.4}
}

.rooms-sub{margin:0 0 12px;font-size:12px;color:var(--muted)}
.room-opt{
  display:flex;align-items:center;gap:12px;width:100%;text-align:left;
  background:#1d1730;border:1px solid var(--line);border-radius:11px;
  padding:11px 13px;margin-bottom:9px;color:var(--text);
  transition:border-color .12s, background .12s;
}
.room-opt:hover{background:#271f42;border-color:var(--soul-deep)}
.room-icon{width:38px;height:38px;flex:0 0 38px}
.room-text{display:flex;flex-direction:column;gap:2px;min-width:0}
.room-name{font-weight:700;color:var(--bone);display:flex;align-items:center;gap:6px;flex-wrap:wrap}
.room-blurb{font-size:11.5px;color:var(--muted)}
.room-sig{font:600 10px/1 ui-monospace,SFMono-Regular,Menlo,monospace;color:var(--necro);letter-spacing:.04em}
.tag.tonight{color:var(--amber);border-color:#5a4420}
.tag.here{color:var(--xp);border-color:#1f4e63}
.tag.sig{color:var(--necro);border-color:#1f4e37}
.bes-tonight{
  font:600 10px/1 ui-monospace,SFMono-Regular,Menlo,monospace;letter-spacing:.12em;
  text-transform:uppercase;color:var(--silk);padding:0 0 8px;border-bottom:1px solid var(--line);
}

.bes-row{display:flex;gap:12px;padding:10px 0;border-bottom:1px solid var(--line)}
.bes-row:last-child{border-bottom:0}
.bes-icon{width:44px;height:44px;flex:0 0 44px}
.bes-name{font-weight:600;color:var(--bone);font-size:14px;display:flex;align-items:center;gap:6px;flex-wrap:wrap}
.bes-stats{font:400 11px/1 ui-monospace,monospace;color:var(--muted)}
.bes-desc{font-size:12px;color:var(--muted);margin-top:2px}
.tag{font-size:9px;text-transform:uppercase;letter-spacing:.09em;padding:2px 6px;border-radius:20px;
  border:1px solid var(--line);color:var(--muted)}
.tag.elite{color:var(--amber);border-color:#5a4420}
.tag.boss{color:var(--blood);border-color:#5a2230}
.tag.tele{color:var(--soul);border-color:#3a2d58}

.help-body h3{margin:16px 0 4px;font-size:13px;color:var(--necro);letter-spacing:.06em;text-transform:uppercase}
.help-body p{margin:0;color:var(--muted);font-size:13px}
.help-body b{color:var(--text)}
.help-foot{margin-top:16px !important;padding-top:12px;border-top:1px solid var(--line)}

/* ---------------------------------------------------------- end screen */
#overlay{
  position:fixed;inset:0;z-index:50;display:grid;place-items:center;padding:16px;
  background:rgba(8,6,14,.88);backdrop-filter:blur(4px);
}
#overlay-card{
  background:var(--panel-2);border:1px solid var(--line);border-radius:16px;
  padding:26px;max-width:520px;width:100%;text-align:center;
  max-height:88vh;overflow:auto;box-shadow:0 26px 80px rgba(0,0,0,.75);
}
#overlay-title{margin:0 0 12px;font-size:25px;color:var(--bone);letter-spacing:.05em}
#overlay-body .big{margin:0 0 6px;font-size:17px;color:var(--text)}
#overlay-body .big b{color:var(--necro);font-size:26px}
#overlay-body .note{margin:0 0 14px;color:var(--muted);font-size:12.5px}
.end-stats{display:grid;grid-template-columns:repeat(4,1fr);gap:8px;margin:14px 0}
.end-stats div{background:#120f1e;border:1px solid #261f3c;border-radius:9px;padding:9px 4px}
.end-stats b{display:block;font-size:20px;color:var(--bone)}
.end-stats span{font-size:9.5px;color:var(--muted);text-transform:uppercase;letter-spacing:.08em}
#share-snippet{
  text-align:left;background:#100d1b;border:1px solid var(--line);border-radius:9px;
  padding:11px;font:12px/1.6 ui-monospace,SFMono-Regular,Menlo,monospace;
  color:var(--text);white-space:pre-wrap;word-break:break-word;margin:0 0 14px;
}
.end-actions{display:flex;gap:10px;justify-content:center;flex-wrap:wrap}
.main-btn{
  background:linear-gradient(180deg,var(--necro-deep),#137047);color:#eafff4;
  border:1px solid #2fbb7b;border-radius:9px;padding:10px 24px;font-weight:600;
  box-shadow:0 6px 20px rgba(31,143,92,.35);
}
.main-btn:hover{filter:brightness(1.15)}
.ghost-btn{
  background:#241d3d;color:var(--text);border:1px solid var(--line);
  border-radius:9px;padding:10px 18px;
}
.ghost-btn:hover{background:#2f2650;border-color:var(--soul-deep)}
#overlay-body .hint{margin:14px 0 0;color:var(--muted);font-size:11.5px}

/* ----------------------------------------------------------- responsive
   One column at every size, so the only thing that changes is scale. */
@media (max-width:520px){
  #console{border-radius:16px 16px 26px 26px}
  #brand h1{font-size:14px}
  .st-chip{padding:4px 5px}
  #log{height:32px;font-size:10px}
}
@media (max-width:380px){
  .st-chip[title="Armor"]{display:none}
  .pips{gap:1px}                              /* ten cells of 19px on a 320px phone */
  .pips i{width:2px;height:2px}
}
/* short viewports: shrink the deck so the display keeps as much height as it
   can — a 15-tile window at 14px a tile is not readable. */
@media (max-height:720px){
  #console{--screen:clamp(200px, min(94vw, calc(100vh - 342px)), 552px);
    --screen:clamp(200px, min(94vw, calc(100dvh - 342px)), 552px);margin:2px auto 6px}
  #brand{padding:0 2px 5px}
  #logo{width:20px;height:20px}
  #brand h1{font-size:13px}
  #share-btn{padding:3px 9px;font-size:11px;min-height:34px}
  .st-bar{height:13px}
  #phyl{height:11px;margin-bottom:4px}
  #rackline{padding-top:4px}
  .rack-cell svg{width:min(15px,100%)}
  #log{height:16px;padding:3px 3px 0}          /* one line is enough down here */
  #dpad{--cell:clamp(44px,13vw,54px);gap:6px;padding:6px}
  #deck{padding-top:6px}
  #foot{padding-top:6px}
  #foot button{padding:3px 11px;font-size:8px;min-height:36px}
  .silk{font-size:7.5px}
}
/* Landscape phones cannot stack a display on top of a deck — 330px of height
   does not go that far. Turn the handheld sideways instead: pad on the left,
   buttons on the right, display in the middle. `display:contents` on the deck
   lets its two halves become columns of the console grid. */
/* Very short phones (a 568pt iPhone SE, a 640px budget Android): the board is
   being squeezed below readable. The prose log and the pad caption are the two
   things the rails already say for you, so they go and the display keeps the
   height instead. */
@media (max-height:680px) and (orientation:portrait){
  #log{display:none}
  .pad-col .silk{display:none}
  #foot button{min-height:34px}
  #foot{padding-top:4px}
  #deck{padding-top:4px}
}
@media (orientation:landscape) and (max-height:560px){
  #console{
    --screen:clamp(140px, calc(100vh - 140px), 430px);
    --screen:clamp(140px, calc(100dvh - 140px), 430px);
    display:grid;align-items:center;gap:0 10px;width:min(100%,940px);
    grid-template-columns:auto minmax(0,1fr) auto;
    grid-template-areas:
      "brand brand brand"
      "pad   screen foot";
    margin:2px auto;
  }
  #brand{grid-area:brand;padding-bottom:5px}
  #screen{grid-area:screen;justify-self:center;
    width:min(100%, max(calc(var(--screen) + 16px), 390px))}
  #deck{display:contents}
  .pad-col{grid-area:pad}
  #foot{grid-area:foot;flex-direction:column;gap:5px;padding:6px 0 0}
  #foot button{width:100%}
  #log{display:none}              /* the rails keep the numbers; prose can wait */
  #rackline{padding-top:3px;padding-bottom:0}
  .rack-cell{padding:2px 1px 1px}
  .rack-cell svg{width:min(14px,100%)}
  #brand{padding-bottom:3px}
  #brand h1{font-size:12px}
  #logo{width:18px;height:18px}
  .st-bar{height:12px}
  #phyl{height:10px;margin-bottom:3px}
  #screen{padding:4px}
}

@media (prefers-reduced-motion:reduce){
  *{animation:none !important;transition:none !important}
}
