/* ManaCore client styles — extracted from online.html (formerly one inlined <style> block).
   Loaded via <link rel="stylesheet" href="online.css"> from online.html's <head>.
   online.css lives in the same directory as online.html, so relative url() (e.g. logo.png)
   resolve identically; url(#id) refs point at the in-document SVG defs. */
  /* ---- THEMES (modular: palette lives entirely in CSS vars) -------------------------------
     Classic green-felt table is the default :root palette — kept intact for instant revert.
     ManaCore (arcane void) is layered under body.theme-core and only overrides variables +
     a few prominent accents. Switch with the 🎨 button; remove the body class to revert. */
  :root{--bg:#0c0e0b;--felt:#16261a;--feltglow:#27492f88;--line:#33402e;--text:#ece5d6;--gold:#c8a35a;--gold2:#e7c884;}
  body.theme-core{--bg:#070912;--felt:#0d1124;--feltglow:#3a2d7a55;--line:#27305a;--text:#e9ecf8;--gold:#7c6cff;--gold2:#b9a8ff;}
  body.theme-core .bar{background:linear-gradient(180deg,#0e1024,#08091a)}
  body.theme-core .btn{background:#1b1f3c;border-color:#3a4480;color:#dfe2f5}
  body.theme-core .btn:hover{background:#262c54;border-color:var(--gold)}
  body.theme-core .btn.gold{background:#332b6e;border-color:var(--gold);color:#fff}
  body.theme-core .ava.me{border-color:#3a4480}
  body.theme-core .ava.opp{border-color:#5a3566}
  body.theme-core .ava.me .life{color:#9fb4ff}
  body.theme-core .chip{background:#161a33}
  body.theme-core .ph{background:#161a33;color:#8a90b5}
  body.theme-core .ph.on{color:#0a0b18}
  body.theme-core .ph.on.mine{background:#7c9bff}
  body.theme-core .ph.on.opp{background:#c77bd6}
  /* deck-color accents — set from the same color the playmat uses, so the page tints to match the mat.
     Layered AFTER theme-core so these win; only the accent vars change (the dark base stays). */
  /* --felt = base table color (shows when no playmat image / through the image veil); --bg = page backdrop.
     Kept dark + saturated toward the deck color so cards stay readable but the whole table reads as the deck. */
  body.mat-white{--gold:#c8a35a;--gold2:#f0dcab;--line:#4a4530;--feltglow:#5a4e2a55;--felt:#191610;--bg:#100e08}
  body.mat-blue{--gold:#3f8fd6;--gold2:#8fcaff;--line:#274a6a;--feltglow:#173a6655;--felt:#0b1426;--bg:#070b16}
  body.mat-black{--gold:#9a78ff;--gold2:#cbb6ff;--line:#3a3358;--feltglow:#2a1f4a55;--felt:#130f20;--bg:#0c0915}
  body.mat-red{--gold:#d9573c;--gold2:#ff9f82;--line:#5a3026;--feltglow:#4a1c1755;--felt:#1c0e0b;--bg:#120807}
  body.mat-green{--gold:#46a85f;--gold2:#88d79e;--line:#2f5236;--feltglow:#1b401f55;--felt:#0c1a10;--bg:#07120a}
  body.mat-colorless{--gold:#9aa2b4;--gold2:#cdd3df;--line:#3a3f4a;--feltglow:#2a303c55;--felt:#13151b;--bg:#0b0c10}
  *{box-sizing:border-box}
  body{margin:0;height:100vh;display:flex;flex-direction:column;overflow:hidden;background:var(--bg);
    color:var(--text);font-family:"Iowan Old Style","Palatino Linotype",Palatino,Georgia,serif;font-size:14px}
  .bar{display:flex;align-items:center;gap:11px;padding:9px 18px;background:linear-gradient(180deg,#1b1812,#13110c);
    border-bottom:1px solid var(--line);box-shadow:0 1px 0 #ffffff0d inset,0 6px 18px #0007;z-index:10}
  /* Fullscreen button floats to the far-right of the top bar (order + auto margin push it there without a DOM move). */
  #fsBtn{order:99;margin-left:auto}
  /* Performance mode: drop the ambient/animated decorative layers entirely (the JS effects are already off via FX()). */
  body.lite #embers, body.lite #mmEmbers, body.lite #fxbeams, body.lite #fxlayer{ display:none !important; }
  /* brand wordmark: a monogram badge + tracked name + ONLINE tag — reads as a designed logo, not a heading */
  .bar h1{font-size:16px;margin:0;font-weight:600;display:flex;align-items:center;gap:9px;letter-spacing:0}
  .bar .bmark{display:grid;place-items:center;width:1.7em;height:1.7em;border-radius:8px;font-size:.95em;font-weight:800;
    color:#0a0a16;background:linear-gradient(145deg,var(--gold2),var(--gold));box-shadow:0 2px 10px var(--feltglow),inset 0 1px 0 #ffffff66}
  .bar .bname{font-size:1.1em;font-weight:700;letter-spacing:1.4px;color:var(--text)}
  .bar .bcore{color:var(--gold2)}
  .bar .btag{font-size:.58em;font-weight:700;letter-spacing:2.5px;color:var(--gold2);opacity:.85;
    border:1px solid var(--gold);border-radius:5px;padding:3px 5px 2px;align-self:center;
    display:inline-flex;align-items:center;justify-content:center;line-height:1;
    text-indent:2.5px;text-align:center}   /* inline-flex + line-height:1 keeps ONLINE centered both ways */
  .bardiv{width:1px;align-self:stretch;margin:4px 1px;background:linear-gradient(180deg,transparent,var(--line) 30%,var(--line) 70%,transparent)}
  /* searchable dropdown (draft set picker): an input + an openable, filterable, scrollable list */
  .combo{position:relative;display:inline-block}
  .combo>input{font-size:14px;padding:.35em 1.6em .35em .5em;width:230px;max-width:46vw;
    background:#15120e;color:var(--text);border:1px solid var(--line);border-radius:7px}
  .combo>input:focus{outline:none;border-color:var(--gold)}
  .combo::after{content:"▾";position:absolute;right:.55em;top:50%;transform:translateY(-50%);color:var(--gold2);pointer-events:none;font-size:11px}
  .combolist{position:absolute;top:calc(100% + 4px);left:0;min-width:100%;max-height:240px;overflow-y:auto;z-index:95;display:none;
    background:linear-gradient(160deg,#211d16,#15120e);border:1px solid var(--gold);border-radius:8px;box-shadow:0 16px 44px #000d}
  .combo.open .combolist{display:block}
  .comboitem{padding:7px 11px;font-size:13px;cursor:pointer;color:var(--text);display:flex;justify-content:space-between;gap:12px;align-items:center}
  .comboitem:hover,.comboitem.active{background:#ffffff18}
  .comboitem .cd{color:var(--gold2);font-size:11px;font-weight:700;letter-spacing:.5px}
  .comboitem.none{color:#9a93b5;font-style:italic;cursor:default;justify-content:center}
  /* custom dropdown trigger (mode picker) — looks like .combo>input but holds the matte sword icon */
  .combo-trigger{font-size:14px;padding:.35em 1.6em .35em .55em;min-width:150px;max-width:46vw;cursor:pointer;
    display:inline-flex;align-items:center;background:#15120e;color:var(--text);border:1px solid var(--line);border-radius:7px;white-space:nowrap}
  .combo-trigger:focus{outline:none;border-color:var(--gold)}
  .combo.open .combo-trigger{border-color:var(--gold)}
  .modecombo .comboitem{justify-content:flex-start}
  .modecombo .comboitem.sel{background:#ffffff10}
  .bar a{text-decoration:none}
  .spacer{flex:1}
  .chip{background:#241f17;border:1px solid var(--line);border-radius:7px;padding:5px 10px;font-size:13px}
  .btn{background:#2a3a2c;border:1px solid #46603f;color:#dfe9d6;border-radius:8px;padding:7px 13px;
    cursor:pointer;font-family:inherit;font-size:13px;transition:background .14s ease,border-color .14s ease,transform .05s ease,box-shadow .14s ease}
  .btn:hover{background:#365239;border-color:var(--gold)}.btn:active{transform:translateY(1px)}
  .btn.gold{background:#5a4a22;border-color:var(--gold);color:#fff7e0;font-weight:600}
  main{flex:1;display:flex;min-height:0;overflow:hidden}   /* clip the board when it's zoomed in (scroll-to-zoom) */
  /* Arena-style player pods: big life number in the table corners (no left rail) */
  .ava{position:absolute;left:12px;z-index:9;display:flex;flex-direction:row;align-items:center;gap:9px;
    padding:6px 13px 6px 9px;border-radius:13px;background:#191510e0;border:1px solid var(--line);
    box-shadow:0 6px 20px #0009;backdrop-filter:blur(2px);cursor:pointer}
  .ava.opp{top:12px;border-color:#5a3530}
  .ava.me{top:8px;bottom:auto;border-color:#3a5a38}   /* top-left of the player's half (anchored inside .half.me), mirroring the opponent */
  /* multi-opponent portrait strip (top-center): one clickable pod per opponent, focused one ringed */
  .oppstrip{position:absolute;top:12px;left:50%;transform:translateX(-50%);z-index:10;display:flex;gap:8px}
  .oppstrip .pod{display:flex;align-items:center;gap:7px;padding:5px 11px 5px 8px;border-radius:11px;
    background:#191510e0;border:1px solid var(--line);box-shadow:0 5px 16px #0009;cursor:pointer;
    backdrop-filter:blur(2px);transition:border-color .12s,box-shadow .12s,transform .12s}
  .oppstrip .pod:hover{transform:translateY(1px)}
  .oppstrip .pod.focus{border-color:var(--gold2);box-shadow:0 0 0 2px var(--gold2),0 5px 16px #0009}
  .oppstrip .pod.active{border-color:#ffcf5a}
  .oppstrip .pod.legal{border-color:#ff6a6a;box-shadow:0 0 0 3px #ff6a6a,0 0 14px 3px #ff5d5daa;animation:tgtpulse 1s ease-in-out infinite}
  /* hastarget = this (not-shown) opponent's board holds a legal target → click the pod to view + target it.
     Amber + dashed to read as "look here", distinct from the solid red .legal (the player themself is a target);
     a pod can carry both, and .legal's stronger red box-shadow wins when it does. */
  .oppstrip .pod.hastarget{border-color:#ffcf5a;outline:2px dashed #ffcf5a99;outline-offset:2px}
  .oppstrip .pod.dead{opacity:.4;filter:grayscale(1)}
  .oppstrip .pod .pl{font-size:24px;font-weight:800;line-height:.9;color:#ff8f7e;min-width:26px;text-align:center}
  .oppstrip .pod .pn{font-size:11px;color:var(--gold2);font-weight:600;white-space:nowrap;max-width:90px;overflow:hidden;text-overflow:ellipsis}
  .oppstrip .pod .pmini{display:flex;gap:7px;font-size:10px;color:#b6ad98}
  .oppstrip .pod .pcd{font-size:10px;color:#ff8f7e;font-weight:700}
  .ava .apic{width:38px;height:38px;border-radius:50%;overflow:hidden;flex:0 0 auto;display:none;
    background:#0006;border:1px solid var(--line);align-items:center;justify-content:center;
    font-size:18px;font-weight:800;color:var(--gold2)}
  .ava .apic.has{display:flex}
  .ava .apic img{width:100%;height:100%;object-fit:cover;display:block}
  .oppstrip .pod .apic{width:30px;height:30px;border-radius:50%;overflow:hidden;flex:0 0 auto}
  .oppstrip .pod .apic img{width:100%;height:100%;object-fit:cover;display:block}
  .ava .ainfo{display:flex;flex-direction:column;gap:3px}
  .aname{font-size:12px;color:var(--gold2);font-weight:600;white-space:nowrap}
  .life{font-size:46px;font-weight:800;line-height:.9;min-width:44px;text-align:center}
  .ava.opp .life{color:#ff8f7e}.ava.me .life{color:#9be08a}
  .mini{display:flex;gap:10px;font-size:12px;color:#b6ad98}.mini b{color:#fff}
  .mini span{display:inline-flex;align-items:center;gap:3px}
  .ico{width:13px;height:13px;flex:0 0 auto;opacity:.92;color:var(--gold2)}
  /* matte line-art button/header icons (mtg_icons_matte) — tint with theme accent via currentColor */
  .bico{width:1.05em;height:1.05em;flex:0 0 auto;vertical-align:-0.15em;margin-right:.5em;color:var(--gold2);stroke:currentColor}
  .mms-h .bico{vertical-align:-0.18em;margin-right:.4em}
  /* compact icons inside small board chips / mini-counters / icon-only buttons */
  .st .bico,.pmini .bico,.pcd .bico{width:1em;height:1em;margin-right:.16em;vertical-align:-0.12em}
  .chalbtn .bico{margin-right:0;color:inherit}   /* dark icon on the gold button (not gold-on-gold) */
  /* rank tier emblem (rank_emblems) — sits to the LEFT of a player name everywhere a name is shown */
  .rankbadge{width:1.7em;height:1.7em;flex:0 0 auto;vertical-align:-0.44em;margin-left:.36em;object-fit:contain;
    image-rendering:auto;filter:drop-shadow(0 1px 2px #0008);user-select:none;-webkit-user-drag:none}
  .nm-wrap{display:inline-flex;align-items:center;min-width:0}
  .nm-wrap>.rankbadge{vertical-align:middle}
  .nm-wrap>.nm,.nm-wrap>span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  /* ranked-medal achievement (🥈/🥇/🏆) shown just LEFT of the rank emblem; best one only */
  .rankmedal{font-size:1.02em;margin-left:.34em;vertical-align:-0.12em;cursor:default;user-select:none;line-height:1;flex:0 0 auto}
  .nm-wrap>.rankmedal{vertical-align:middle}
  /* floating mana — a centered pill hovering just above your lands (Arena-like; no persistent widget) */
  .manafloat{position:absolute;left:50%;transform:translateX(-50%);z-index:9;display:none;align-items:center;gap:6px;
    bottom:calc(clamp(138px,22vh,250px) + clamp(72px,12vh,116px));padding:5px 12px;border-radius:22px;
    background:#0d0b07ee;box-shadow:inset 0 0 0 1px var(--gold),0 0 18px #e7c88466}
  .manafloat.has{display:flex}
  .manafloat .plabel{font-size:10px;color:var(--gold2);font-weight:700;letter-spacing:.5px}
  .mana{width:24px;height:24px;border-radius:50%;font-size:13px;display:grid;place-items:center;color:#000;font-weight:800;box-shadow:inset 0 0 0 1px #0006,0 1px 3px #0008}
  .mana.W{background:#f5f0d8}.mana.U{background:#2a7fc0;color:#fff}.mana.B{background:#39332c;color:#e6dccb}.mana.R{background:#d3322a;color:#fff}.mana.G{background:#1f8a4c;color:#fff}.mana.C{background:#c2bbac}
  /* restricted (conditional) mana — e.g. Plaza of Heroes "legendary only": dashed amber ring + smaller text so the lock badge fits */
  .mana.restricted{box-shadow:inset 0 0 0 1px #0006,0 0 0 2px #e0a32b,0 1px 3px #0008;font-size:10px;cursor:help}
  .table{flex:1;min-width:0;display:flex;flex-direction:column;
    background:radial-gradient(ellipse at 50% 50%,var(--feltglow),transparent 72%),var(--felt)}
  /* drag-to-play: highlight the mat while a card is over it */
  .table.dropok{box-shadow:inset 0 0 0 3px var(--gold),inset 0 0 40px var(--feltglow)}
  .card[draggable="true"]{cursor:grab}.card[draggable="true"]:active{cursor:grabbing}
  .half{flex:1;display:flex;flex-direction:column;min-height:0;padding:6px 14px;gap:5px}
  .half.opp{padding-top:38px}   /* keep the opponent's top row (cards center & overflow upward) clear of the title bar */
  .half.opp,.half.me{position:relative}   /* containing block for the player avatar + the opponent's command zone */
  .row{flex:1;display:flex;gap:8px;flex-wrap:wrap;align-content:center;justify-content:center;min-height:0;position:relative}
  .row.lands{flex:.7;background:rgba(0,0,0,.22);border-radius:8px;   /* neutral darken so it reads on any deck-tinted felt */
    padding-right:calc(2*var(--deckw) + 34px)}                       /* keep lands clear of the deck+graveyard piles */
  /* When a land row wraps (many lands, late game), grow it toward the center line instead of letting the
     centered overflow spill off the screen edge: opponent lands fill downward, your lands fill upward. */
  .half.opp .row.lands{align-content:flex-start}
  .half.me  .row.lands{align-content:flex-end}
  .table.hasexile .row.lands{padding-right:calc(3*var(--deckw) + 46px)}   /* exile pile shown → reserve one more column */
  /* creatures paint in FRONT of lands so a tall creature card isn't clipped behind the land row */
  .half.me #myCre{z-index:3}.half.me #myLand{z-index:1}
  .half.opp #oppCre{z-index:3}.half.opp #oppLand{z-index:1}
  .center{min-height:7px;background:#0a0d08;border-top:1px solid var(--line);border-bottom:1px solid var(--line)}
  body.theme-core .center{background:var(--bg)}   /* divider follows the deck-tinted backdrop */
  /* turn/phase indicator: now a full-width bar pinned to the very bottom of the page */
  .turnbar{flex:0 0 auto;display:flex;align-items:center;justify-content:center;padding:7px 16px;
    background:linear-gradient(0deg,#0a0d08,#13110c);border-top:1px solid var(--line);z-index:10}
  body.theme-core .turnbar{background:linear-gradient(0deg,var(--bg),var(--felt))}   /* blends up into the deck-tinted felt */
  .turnbar .prompt{flex:0 1 auto;text-align:center;color:var(--gold2);font-style:italic}
  /* "skip to my turn" lives on the turn bar; pulses amber while armed */
  .yieldbtn{font-size:12px;padding:5px 9px;flex:0 0 auto}   /* in the right rail, under the decision panel */
  .yieldbtn.on{background:#332b6e;border-color:var(--gold);color:#fff;box-shadow:0 0 10px var(--gold);animation:decglow 1.2s ease-in-out infinite}
  #phase{font-size:17px;font-style:normal}
  #phase .who{font-weight:800;letter-spacing:.6px}
  #phase.mine .who{color:#9be08a}#phase.opp .who{color:#ff9b8a}
  body.theme-core #phase.mine .who{color:#8fffa8}body.theme-core #phase.opp .who{color:#ff9b8a}
  /* newly drawn cards slide up from the deck with a glow; new permanents pulse as they hit the mat */
  @keyframes drawIn{0%{opacity:0;transform:translateY(48px) scale(.84)}55%{opacity:1}100%{opacity:1;transform:none}}
  .hand .card.justdrawn{animation:drawIn .55s cubic-bezier(.2,.8,.2,1);box-shadow:0 0 0 3px var(--gold2),0 0 22px var(--gold2)}
  @keyframes enterPulse{0%{opacity:.15;transform:translateY(-16px) scale(.82);box-shadow:0 0 0 4px var(--gold2),0 0 26px var(--gold2)}55%{opacity:1}100%{opacity:1;transform:none;box-shadow:0 0 0 0 #0000}}
  .card.justentered{animation:enterPulse .55s cubic-bezier(.2,.8,.2,1)}
  /* hover-to-read card preview */
  #preview{position:fixed;left:136px;top:50%;transform:translateY(-50%);width:300px;z-index:80;max-height:94vh;overflow:auto;
    background:#14110c;border:1px solid var(--gold);border-radius:12px;padding:10px;box-shadow:0 14px 44px #000e;
    opacity:0;pointer-events:none;transition:opacity .1s;display:flex;flex-direction:column;gap:6px}
  #preview.show{opacity:1}
  #preview img{max-height:50vh;width:auto;max-width:100%;margin:0 auto;border-radius:8px;display:block}
  #preview .pn{font-size:13px;color:#dcd4c2;font-weight:600}
  #preview .ptl{font-size:11px;color:#b6ad98;font-style:italic;border-bottom:1px solid #ffffff14;padding-bottom:5px}
  #preview .tx{font-size:12px;color:#d8d2c2;line-height:1.38}
  /* split / Room cards: each half's text under its own title */
  .cardhalf + .cardhalf{margin-top:6px;padding-top:6px;border-top:1px solid #ffffff1f}
  .chname{font-weight:800;color:var(--gold2);margin-bottom:1px}
  #preview .st{display:flex;flex-wrap:wrap;gap:4px;margin-top:2px}
  #preview .st .b{font-size:11px;font-weight:700;padding:1px 6px;border-radius:5px;background:#2a2f4a;border:1px solid #ffffff2a;color:#eef0fb}
  #preview .st .b.plus{background:#1f8a4c}#preview .st .b.minus{background:#b02525}
  /* right-click: full-screen card zoom */
  #zoom{position:fixed;inset:0;background:#000d;backdrop-filter:blur(3px);z-index:90;display:none;
    align-items:center;justify-content:center;cursor:zoom-out}
  #zoom.show{display:flex;gap:16px;flex-wrap:wrap;padding:14px}
  #zoom img{max-height:90dvh;max-width:54vw;border-radius:20px;box-shadow:0 22px 70px #000}
  /* card-text panel beside the zoomed art — a fallback to READ the card when the graphic is missing */
  #zoom .zinfo{flex:0 1 auto;max-width:min(46vw,380px);max-height:88dvh;overflow:auto;text-align:left;
    background:linear-gradient(160deg,#211d16,#15120e);border:1px solid var(--gold);border-radius:14px;padding:16px;box-shadow:0 18px 60px #000;cursor:auto}
  #zoom .zname{font-size:19px;color:var(--gold2);font-weight:700;line-height:1.25}
  #zoom .ztype{color:#c9c2e6;font-style:italic;border-bottom:1px solid var(--line);padding-bottom:7px;margin:6px 0 9px;font-size:14px}
  #zoom .ztext{white-space:pre-wrap;line-height:1.5;font-size:15px;color:var(--text)}
  #zoomFlip{position:fixed;bottom:22px;left:50%;transform:translateX(-50%);z-index:91;cursor:pointer;font-size:15px;padding:10px 18px}
  /* prev/next arrows on the full-screen card reader (paper collection); keyboard ←/→ too */
  .zoomnav{position:fixed;top:50%;transform:translateY(-50%);z-index:92;width:54px;height:54px;border-radius:50%;
    background:#0a0c18cc;border:1px solid var(--line);color:var(--gold2);font-size:32px;line-height:1;cursor:pointer;
    display:flex;align-items:center;justify-content:center}
  .zoomnav:hover{background:var(--btn);border-color:var(--gold)}
  .zoomnav.prev{left:24px}.zoomnav.next{right:24px}
  .zoomnav[disabled]{opacity:.2;cursor:default;pointer-events:none}
  @media(max-width:640px){ .zoomnav{width:42px;height:42px;font-size:24px}.zoomnav.prev{left:6px}.zoomnav.next{right:6px} }
  /* click-a-card ability menu: floats next to the clicked permanent */
  #abilmenu{position:fixed;z-index:88;display:none;min-width:190px;max-width:300px;background:linear-gradient(160deg,#211d16,#15120e);
    border:1px solid var(--gold);border-radius:10px;padding:6px;box-shadow:0 16px 48px #000e;flex-direction:column;gap:4px}
  #abilmenu.show{display:flex}
  #abilmenu .amh{font-size:12px;font-weight:700;color:var(--gold2);padding:3px 6px 5px;border-bottom:1px solid #ffffff1a}
  #abilmenu .amb{text-align:left;background:#2a3a2c;border:1px solid #46603f;color:#dfe9d6;border-radius:7px;padding:6px 9px;
    cursor:pointer;font-family:inherit;font-size:12px;line-height:1.3}
  #abilmenu .amb:hover{background:#365239;border-color:var(--gold)}
  #abilmenu .amb.off{opacity:.5;cursor:not-allowed;background:#1e1b15;border-style:dashed;border-color:#5a5040;color:#9a9286}
  #abilmenu .amb.off .sym{filter:grayscale(.6)}
  /* stack zone — cast spells/abilities, centered on the board */
  .stackzone{position:absolute;left:50%;top:41%;transform:translate(-50%,-50%);display:flex;gap:14px;z-index:8;pointer-events:none}
  /* smaller + slightly transparent. Hover-to-read works normally; only while you're PICKING TARGETS does
     it go click-through (.noclick) so it can't block selecting the creature drawn underneath it. */
  .scard{position:relative;height:clamp(94px,14.5vh,164px);width:calc(clamp(94px,14.5vh,164px)*.717);border-radius:8px;box-shadow:0 0 0 2px var(--gold2),0 10px 28px #000d;pointer-events:auto;cursor:zoom-in;opacity:.9;transition:margin-left .14s ease,transform .14s ease}
  /* crowded stack (5+): fan the cards into an overlapping row so they don't eat the board. Each peeks a
     ~46px sliver; hovering lifts that card clear (raised above the count-driven z-index) to read it. */
  .stackzone.crowded{gap:0}
  .stackzone.crowded .scard + .scard{margin-left:calc(-1 * (clamp(94px,14.5vh,164px)*.717) + 46px)}
  .stackzone.crowded .scard:hover{transform:translateY(-12px) scale(1.05);z-index:60 !important;box-shadow:0 0 0 2px var(--gold),0 14px 30px #000e;opacity:1}
  .stackzone.noclick .scard{pointer-events:none}
  .scard img{width:100%;height:100%;object-fit:cover;border-radius:8px;display:block}
  /* art-less stack card (tokens & their abilities have no Scryfall image): a legible parchment-ish token
     face instead of a near-black void */
  .scard .snm{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;
    text-align:center;gap:4px;color:#f0e7cf;font-size:12px;font-weight:600;line-height:1.25;padding:7px;border-radius:8px;
    background:linear-gradient(160deg,#2d2a1f 0%,#1b1810 60%,#14110b 100%);box-shadow:inset 0 0 0 1px #ffffff24,inset 0 0 22px #0009}
  .scard .snm::before{content:"✦";font-size:15px;color:var(--gold2);opacity:.7}
  .scard .tgt{position:absolute;bottom:-17px;left:0;right:0;text-align:center;font-size:11px;color:#e7c884;text-shadow:0 1px 3px #000;white-space:nowrap}
  /* deck card-back image */
  .deck .back{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;border-radius:7px}
  .deck .dn{position:relative;z-index:1}
  /* centered overlays: game over + deck import */
  .overlay2{position:fixed;inset:0;background:#000c;backdrop-filter:blur(3px);z-index:66;display:none;align-items:center;justify-content:center;padding:24px}
  .overlay2.show{display:flex}
  /* Dungeon map (Venture into the Dungeon) */
  .dgpanel{max-width:560px;max-height:88dvh;overflow:auto;align-items:stretch;gap:6px}
  .dgdungeon{margin-bottom:12px}
  .dgname{font-weight:800;color:var(--gold2);font-size:15px}
  .dgwho{font-size:12px;opacity:.65;margin-bottom:8px}
  .dgroom{position:relative;border:1px solid #55452a;border-radius:10px;padding:8px 10px 8px 28px;margin:6px 0;background:#1a1610}
  .dgroom.cur{border-color:var(--gold);background:linear-gradient(160deg,#2c2413,#1c1710);box-shadow:inset 0 0 0 1px var(--gold),0 2px 10px #0009}
  .dgmark{position:absolute;left:8px;top:9px;font-size:12px;color:var(--gold2)}
  .dgrname{font-weight:700;color:#f4ecd8;font-size:13px}
  .dgroom.cur .dgrname{color:var(--gold2)}
  .dgrtext{font-size:12px;opacity:.85;margin-top:3px;line-height:1.35}
  .dgnext{font-size:11px;opacity:.55;margin-top:4px;font-style:italic}
  .dgnext.done{color:#8fdf8f;opacity:.8;font-style:normal}
  /* basic-tutorial coaching card: non-modal, top-centre, never blocks the hand/action bar (FEATURES.tutorial) */
  #tutbox{position:fixed;top:60px;left:50%;transform:translateX(-50%);z-index:62;display:none;
    width:min(94vw,420px);padding:14px 17px 15px;border-radius:12px;
    background:linear-gradient(180deg,#1c2436f2,#141a28f2);border:1px solid var(--gold2);
    box-shadow:0 10px 34px #000a,0 0 0 1px #0006 inset;color:#ede6d6;font-size:16px;line-height:1.5}
  #tutbox.show{display:block;animation:tutIn .35s cubic-bezier(.2,.8,.2,1)}
  @keyframes tutIn{from{opacity:0;transform:translate(-50%,-8px)}to{opacity:1;transform:translate(-50%,0)}}
  #tutbox .tut-h{display:flex;align-items:center;justify-content:space-between;margin-bottom:7px}
  #tutbox .tut-dots{display:flex;gap:5px}
  #tutbox .tdot{width:7px;height:7px;border-radius:50%;background:#ffffff26}
  #tutbox .tdot.on{background:var(--gold2)} #tutbox .tdot.cur{background:var(--gold2);box-shadow:0 0 0 3px #e7c88433}
  #tutbox .tut-x{background:none;border:0;color:#9c9a8c;font-size:15px;cursor:pointer;padding:0 2px;line-height:1}
  #tutbox .tut-x:hover{color:#eee}
  #tutbox .tut-t{font-weight:700;color:var(--gold2);margin-bottom:5px;font-size:18px}
  #tutbox .tut-b{color:#d8d2c4} #tutbox .tut-b b{color:#fff}
  #tutbox .tut-acts{margin-top:10px;text-align:right}
  @media (max-width:760px){ #tutbox{top:auto;bottom:8px;font-size:14px;width:min(96vw,440px)} #tutbox .tut-t{font-size:16px} }
  /* floating "Results" button to reopen the game-over screen after viewing the final board */
  #resultsBtn{position:fixed;bottom:56px;left:50%;transform:translateX(-50%);z-index:72}   /* above the turn bar, clear of other buttons */
  /* "Peek board": hide the chooser panel + clear the dim so you can read the battlefield, leaving only
     the peek button to toggle back. Card hover/zoom still works through the now-transparent overlay. */
  #chPeek{position:fixed;top:12px;right:14px;z-index:71;display:none;font-size:14px;padding:9px 15px;
    box-shadow:0 4px 16px #000b}
  #chooser.show #chPeek{display:inline-flex;align-items:center;gap:6px}
  #chooser.peeking #chPeek{top:auto;bottom:16px;left:50%;right:auto;transform:translateX(-50%)}  /* while peeking, center it at the bottom so it's an obvious "go back" */
  #chooser.peeking{background:transparent;backdrop-filter:none;pointer-events:none}
  #chooser.peeking .panel2{display:none}
  #chooser.peeking #chPeek{pointer-events:auto}
  /* draft pack-opening animation overlay (over everything while it plays) */
  #packopen{background:#000d;z-index:90}
  .packwrap{display:flex;flex-direction:column;align-items:center;gap:14px}
  #packvid{max-width:min(82vw,440px);max-height:62vh;border-radius:12px;filter:drop-shadow(0 18px 50px #000)}
  .packspin{display:flex;flex-direction:column;align-items:center;gap:14px}
  .packspin .pse{font-size:64px;animation:packbob 1.6s ease-in-out infinite}
  .packspin span{color:var(--gold2);font-size:16px;font-weight:600;letter-spacing:.5px}
  @keyframes packbob{0%,100%{transform:translateY(0) rotate(-4deg)}50%{transform:translateY(-10px) rotate(4deg)}}
  /* draft room: the backdrop behind the pick picker */
  #draftroom{position:fixed;inset:0;display:none;z-index:40;padding:18px;flex-direction:column;align-items:center;
    background:radial-gradient(120% 90% at 50% 0%, var(--feltglow), transparent 60%), linear-gradient(180deg,#0b0b16,#070710)}
  #draftroom.show{display:flex}
  .droom{margin-top:2vh;display:flex;flex-direction:column;align-items:center;gap:14px;width:100%;max-width:min(98vw,1200px);flex:1 1 auto;min-height:0}
  .dhead{font-size:clamp(16px,2.4vw,24px);color:var(--gold2);font-weight:700;letter-spacing:.6px;text-align:center;
    text-shadow:0 2px 14px var(--feltglow)}
  .dseats{display:flex;flex-wrap:wrap;gap:9px;justify-content:center;max-width:680px}
  .dseat{background:#0008;border:1px solid var(--line);border-radius:9px;padding:7px 12px;font-size:13px;color:var(--text);
    display:flex;align-items:center;gap:7px;transition:border-color .2s,box-shadow .2s}
  .dseat.me{border-color:var(--gold);background:#ffffff0d}
  .dseat.picking{box-shadow:0 0 0 1px var(--gold),0 0 12px var(--feltglow);border-color:var(--gold)}
  .dseat .pk{color:var(--gold2);font-weight:800;min-width:1.3em;text-align:center}
  .dseat .pkl{font-size:10px;color:#9a93b5;text-transform:uppercase;letter-spacing:.5px}
  .drow{display:flex;gap:14px;align-items:center;flex-wrap:wrap;justify-content:center}
  .dwait{color:var(--gold2);font-style:italic;font-size:13px}
  .dpoolhdr{color:var(--gold2);font-weight:700;font-size:13px;letter-spacing:.5px}
  /* your-picks tabletop: grouped into type sections; duplicates stack into offset piles.
     --poolh lives on .dpool so BOTH the draft-room pool (#dPool) and the build pool (#bPool) get a
     size (scroll-wheel zoom adjusts it per element). Default is small; mouse-over previews each card. */
  .dpool{--poolh:130px;display:flex;flex-direction:column;align-items:stretch;gap:6px;width:100%;
    flex:1 1 auto;min-height:0;overflow-y:auto;overflow-x:hidden;padding:14px 16px;border-radius:14px;
    background:radial-gradient(120% 100% at 50% 0%, var(--feltglow), #0000 72%), #0000002e;border:1px solid var(--line)}
  .dempty{color:#9a93b5;font-style:italic;padding:18px;font-size:13px;text-align:center}
  .dsection{display:flex;flex-direction:column;gap:2px}
  .dsechdr{color:var(--gold2);font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.7px;opacity:.92;border-bottom:1px solid var(--line);padding:0 2px 3px}
  .dsecrow{display:flex;flex-wrap:wrap;gap:14px 16px;align-items:flex-start;padding:8px 2px 12px}
  .poolc{height:var(--poolh);width:calc(var(--poolh)*.717);border-radius:7px;overflow:hidden;background:#1a1712;position:relative;cursor:zoom-in;box-shadow:0 3px 10px #0009;flex:0 0 auto}
  .poolc img{width:100%;height:100%;object-fit:cover;display:block}
  .poolc .nm{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;text-align:center;font-size:9px;padding:3px;color:#d8cdb6}
  /* pile = fixed offset stack (each card peeks 26px). Hover lifts ONLY that card — no whole-pile reflow. */
  .poolpile{position:relative;width:calc(var(--poolh)*.717);flex:0 0 auto}
  .poolpile .poolc{position:absolute;left:0;top:calc(var(--i,0)*26px);transition:transform .14s ease, box-shadow .14s ease}
  .poolpile .poolc:hover{transform:translateY(-9px) scale(1.05);z-index:50;box-shadow:0 12px 28px #000d}
  .poolpile .cnt{position:absolute;top:-7px;right:-7px;z-index:60;background:var(--gold);color:#150f06;font-weight:800;font-size:11px;
    border-radius:11px;min-width:20px;height:20px;display:grid;place-items:center;padding:0 5px;box-shadow:0 2px 6px #0008}
  /* deck-build screen (after the draft) */
  #deckbuild{position:fixed;inset:0;display:none;z-index:42;padding:18px;flex-direction:column;align-items:center;
    background:radial-gradient(120% 90% at 50% 0%, var(--feltglow), transparent 60%), linear-gradient(180deg,#0b0b16,#070710)}
  #deckbuild.show{display:flex}
  .bbar{display:flex;flex-wrap:wrap;gap:10px 14px;align-items:center;justify-content:center}
  .bsteps{display:flex;flex-wrap:wrap;gap:8px}
  .bstep{display:flex;align-items:center;gap:4px;background:#0008;border:1px solid var(--line);border-radius:8px;padding:3px 5px}
  .bstep .btn{padding:2px 9px;font-size:15px;line-height:1}
  .bsl{font-size:12px;color:#cfc8e6;min-width:54px;text-align:center}
  .bsl b{color:var(--gold2);font-size:14px}
  .bcount{font-size:14px;color:var(--text)}
  .bcount b{font-size:17px}.bcount b.ok{color:#9be08a}.bcount b.low{color:#e6b96a}
  .bhint{font-size:12px;font-style:italic;color:#e6b96a}.bhint.ok{color:#9be08a}
  .poolc.cut{opacity:.32;filter:grayscale(.7)}
  .poolc.cut::after{content:"✕";position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-size:26px;color:#ff8f7e;text-shadow:0 1px 4px #000}
  /* fullscreen toggle for the draft room & deck-build screens (reuses toggleFullscreen) */
  .dfsbtn{position:absolute;top:14px;right:16px;z-index:5;font-size:18px;line-height:1;padding:6px 11px}
  /* deck-build stats strip (mana curve · spells by colour · pip distribution · ramp) */
  .dstats{display:flex;flex-wrap:wrap;gap:10px 18px;align-items:flex-end;justify-content:center;width:100%;
    padding:8px 14px;border-radius:12px;background:#0000002e;border:1px solid var(--line)}
  .dstat{display:flex;flex-direction:column;gap:4px;align-items:center}
  .dstat .dslab{font-size:10px;color:#9a93b5;text-transform:uppercase;letter-spacing:.6px}
  .curve{display:flex;gap:3px;align-items:flex-end;height:38px}
  .curve .cb{position:relative;width:15px;display:flex;flex-direction:column;justify-content:flex-end;align-items:center}
  .curve .cb i{display:block;width:100%;background:linear-gradient(180deg,var(--gold),var(--gold2));border-radius:2px 2px 0 0;min-height:2px}
  .curve .cb b{font-size:9px;color:#cfc8e6;font-weight:700;margin-bottom:1px}
  .curve .cb u{font-size:9px;color:#9a93b5;font-style:normal;margin-top:2px}
  .cpips{display:flex;gap:7px;align-items:center}
  .cpip{display:flex;align-items:center;gap:3px;font-size:12px;color:var(--text);font-weight:700}
  .cpip .dot{width:13px;height:13px;border-radius:50%;box-shadow:inset 0 0 0 1px #0006}
  .cpip.off{opacity:.3}
  .cW .dot{background:#f7f3d8}.cU .dot{background:#8fc7e8}.cB .dot{background:#9a8fa8}.cR .dot{background:#e89b7e}.cG .dot{background:#8fca94}.cC .dot{background:#c9c2b4}
  .cbar{display:flex;height:12px;width:150px;border-radius:6px;overflow:hidden;box-shadow:inset 0 0 0 1px #0006}
  .cbar i{display:block;height:100%}
  .cbar .sW{background:#f7f3d8}.cbar .sU{background:#8fc7e8}.cbar .sB{background:#9a8fa8}.cbar .sR{background:#e89b7e}.cbar .sG{background:#8fca94}
  .dramp{font-size:19px;font-weight:800;color:var(--gold2)}
  /* draft pick timer (dynamic: more time early, less late; reserve bank shown) */
  .picktimer{margin:0 auto 10px;display:flex;flex-direction:column;gap:5px;align-items:center;width:min(360px,82%)}
  .picktimer .ptbar{width:100%;height:8px;border-radius:5px;background:#0006;overflow:hidden;box-shadow:inset 0 0 0 1px #0006}
  .picktimer .ptfill{height:100%;width:100%;background:linear-gradient(90deg,#8fca94,var(--gold));transition:width .25s linear}
  .picktimer.warn .ptfill{background:linear-gradient(90deg,#e6b96a,#ff8f7e)}
  .picktimer .pttxt{font-size:12px;color:#cfc8e6;letter-spacing:.3px;font-weight:600}
  .picktimer.warn .pttxt{color:#ffb59e}
  .picktimer .ptbank{color:#9a93b5;font-weight:400}
  .panel2{background:linear-gradient(160deg,#211d16,#15120e);border:1px solid var(--gold);border-radius:16px;padding:24px;box-shadow:0 22px 60px #000;display:flex;flex-direction:column;gap:14px;align-items:center}
  .panel2 .res{font-size:46px;font-weight:800;letter-spacing:1px}.panel2 .res.win{color:#9be08a}.panel2 .res.lose{color:#ff8f7e}
  #deckmodal .panel2{align-items:stretch;min-width:460px;max-width:560px}
  #deckmodal h3{margin:0;color:var(--gold2)}#deckmodal .hint{color:#9c9a8c;font-size:12px;font-style:italic}
  /* "currently loaded" deck readout — prominent, not a muted hint */
  #deckmodal #deckCur{color:var(--gold2);font-style:normal;font-size:13px;background:#0d0b07;border:1px solid var(--gold);border-radius:8px;padding:7px 11px}
  #deckmodal #deckCur b{color:#fff}
  #deckmodal textarea{width:100%;height:280px;background:#15120e;color:var(--text);border:1px solid var(--line);border-radius:8px;padding:10px;font-family:ui-monospace,monospace;font-size:13px;resize:vertical}
  #deckmodal .row2{display:flex;gap:8px;justify-content:flex-end}
  /* the Library picker: let the <select> shrink so a long deck name truncates instead of overflowing off-screen */
  #deckmodal .row2 label{flex:1 1 auto;min-width:0;max-width:100%}
  #deckPick{flex:1 1 auto;min-width:0;max-width:100%;text-overflow:ellipsis}
  .mini .gy{cursor:pointer}.mini .gy:hover{color:var(--gold2)}
  /* card-list viewer (graveyard) */
  .cardgrid{display:flex;flex-wrap:wrap;gap:10px;max-width:660px;max-height:64vh;overflow:auto;justify-content:center}
  .cardgrid .gc{height:168px;width:calc(168px*.717);border-radius:7px;overflow:hidden;background:#1a1712;position:relative;cursor:zoom-in}
  .cardgrid .gc img{width:100%;height:100%;object-fit:cover;display:block}
  .cardgrid .gc .nm{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;text-align:center;font-size:10px;padding:4px;color:#d8cdb6}
  .cardgrid .gc.pick{box-shadow:0 0 0 3px #ffe066,0 0 14px #ffe066}
  /* Fact-or-Fiction pile chooser: two stacked dashed boxes inside the card grid */
  .pilegroup{width:100%;display:flex;flex-direction:column;gap:6px}
  .pilehdr{font-weight:700;color:var(--gold2);font-size:13px}
  .pilerow{display:flex;flex-wrap:wrap;gap:10px;justify-content:center;min-height:64px;border:1px dashed var(--line);border-radius:8px;padding:8px}
  .cardgrid .gc.nopick{opacity:.42;filter:grayscale(.55);cursor:default}   /* revealed but not a legal choice */
  .cardgrid .gc.pick::after{content:"✓";position:absolute;top:3px;left:4px;background:#ffe066;color:#1a140a;border-radius:50%;width:18px;height:18px;display:grid;place-items:center;font-size:12px;font-weight:800}
  .cardgrid .empty{color:#9c9a8c;font-style:italic;padding:30px}
  /* revealed-cards strip (opponent's revealed hand etc.) */
  .revealzone{position:fixed;top:56px;left:50%;transform:translateX(-50%);z-index:78;display:flex;flex-direction:column;gap:6px;align-items:center;pointer-events:none}
  .revealrow{background:#16130d;border:1px solid var(--gold);border-radius:10px;padding:7px 12px;display:flex;gap:8px;align-items:center;box-shadow:0 10px 30px #000e,0 0 0 4px #0008;pointer-events:auto}
  .revealrow .rlbl{color:var(--gold2);font-size:12px;font-weight:700;margin-right:2px;white-space:nowrap}
  .revealrow .rc{height:98px;width:calc(98px*.717);border-radius:5px;overflow:hidden;background:#0e0c08;position:relative;cursor:zoom-in}
  .revealrow .rc img{width:100%;height:100%;object-fit:cover;display:block}
  .revealrow .rc .nm{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;text-align:center;font-size:9px;padding:2px;color:#d8cdb6}
  /* transient center-screen popup for a momentary public reveal (so a fast-forwarding opponent can't miss it) */
  #revealPop{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);z-index:96;display:flex;flex-direction:column;gap:10px;align-items:center;pointer-events:none}
  .rvpop{background:#16130d;border:1px solid var(--gold);border-radius:14px;padding:12px 16px;display:flex;flex-direction:column;gap:9px;align-items:center;box-shadow:0 18px 50px #000f,0 0 0 5px #0009,0 0 26px var(--gold);opacity:0;transform:translateY(14px) scale(.92);transition:opacity .28s ease,transform .28s cubic-bezier(.2,.9,.3,1.2)}
  .rvpop.show{opacity:1;transform:none}
  .rvpop-lbl{color:var(--gold2);font-size:14px;font-weight:800;letter-spacing:.02em;white-space:nowrap}
  .rvpop-cards{display:flex;gap:10px}
  .rvpop .rc{height:190px;width:calc(190px*.717);border-radius:8px;overflow:hidden;background:#0e0c08;position:relative}
  .rvpop .rc img{width:100%;height:100%;object-fit:cover;display:block}
  .rvpop .rc .nm{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;text-align:center;font-size:11px;padding:4px;color:#d8cdb6}
  /* game-over banner in the decision panel */
  .gover{font-size:22px;font-weight:800;text-align:center;padding:6px}
  .gover.win{color:#9be08a}.gover.lose{color:#ff8f7e}
  .stackbox{font-size:12px;color:#e7c884;background:#241c2caa;border:1px solid #6a4f7f;border-radius:6px;padding:3px 9px;max-width:40%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .hand{display:flex;gap:6px;justify-content:center;align-items:flex-end;padding:6px 10px 10px;min-height:150px;
    background:linear-gradient(0deg,#0a0c07,transparent);max-width:100%;overflow:hidden;position:relative;z-index:5}
  /* drop a held card back here to keep it in hand (regret) */
  .hand.regret{box-shadow:inset 0 0 0 3px #c2554d,inset 0 0 32px #7a2a2a55}
  .hand.regret::after{content:"↩ release to keep in hand";position:absolute;top:6px;left:50%;transform:translateX(-50%);
    font-size:12px;font-weight:700;color:#ffd2cc;background:#5a201ccc;border:1px solid #c2554d;border-radius:7px;padding:2px 9px;pointer-events:none}
  /* dragging a card off the deck onto the hand draws it */
  .hand.drawhover{box-shadow:inset 0 0 0 3px var(--gold),inset 0 0 32px #e7c88455}
  .hand.drawhover::after{content:"🃏 release to draw";position:absolute;top:6px;left:50%;transform:translateX(-50%);
    font-size:12px;font-weight:700;color:#fff3d6;background:#4a3a14cc;border:1px solid var(--gold);border-radius:7px;padding:2px 9px;pointer-events:none}
  .card{height:clamp(112px,17vh,192px);width:calc(clamp(112px,17vh,192px)*.717);border-radius:7px;overflow:hidden;
    background:#1a1712;position:relative;box-shadow:0 2px 7px #000a;flex:0 0 auto;cursor:default}
  /* hand cards shrink to fit the felt width (aspect-ratio keeps them uniform) instead of overflowing */
  .hand .card{flex:0 1 calc(clamp(138px,22vh,250px)*.717);width:auto;height:auto;aspect-ratio:.717;
    min-width:48px;max-width:calc(clamp(138px,22vh,250px)*.717)}
  .card img{width:100%;height:100%;object-fit:cover;display:block;border-radius:inherit}   /* self-round so the art stays rounded even when the card allows overflow (tapped) */
  .card .nm{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;text-align:center;
    font-size:10px;padding:4px;color:#d8cdb6}
  .card.tapped{transform:rotate(90deg) scale(.71);overflow:visible}  /* <=.717 so the rotated hitbox stays inside
                                                       the card's column and doesn't steal clicks from the next
                                                       card. overflow:visible so corner badges (e.g. the damage
                                                       counter) aren't clipped by the rounded corner when rotated. */
  /* legal target: a bold, pulsing red halo so selectable targets are impossible to miss on a busy board */
  .card.legal{box-shadow:0 0 0 4px #ff6a6a,0 0 18px 4px #ff5d5dcc;cursor:crosshair;animation:tgtpulse 1s ease-in-out infinite}
  @keyframes tgtpulse{0%,100%{box-shadow:0 0 0 3px #ff6a6a,0 0 12px 2px #ff5d5d99;filter:brightness(1)}50%{box-shadow:0 0 0 6px #ff5d5d,0 0 26px 8px #ff5d5d;filter:brightness(1.15)}}
  .card.playable{box-shadow:0 0 0 3px #6cd06c,0 0 12px #6cd06c99;cursor:pointer}
  /* selected MUST come last so it overrides legal/playable when a card is both */
  .card.sel{box-shadow:0 0 0 4px #ffe066,0 0 22px #ffe066,inset 0 0 0 9999px #ffe06622;outline:2px solid #fff9;z-index:5}
  .card.sel::after{content:"✓";position:absolute;top:3px;left:4px;background:#ffe066;color:#1a140a;border-radius:50%;width:18px;height:18px;display:grid;place-items:center;font-size:12px;font-weight:800}
  .card.attacking{box-shadow:0 0 0 4px #ff9e3d,0 0 18px #ff9e3d}   /* bolder, aggressive orange */
  .card.blkatk{box-shadow:0 0 0 4px #ff3b30,0 0 24px #ff5a3d,0 0 40px #ff5a3d99!important;z-index:6}  /* being attacked: unmistakable red */
  .atkbadge{position:absolute;top:2px;left:2px;background:#c81e12;color:#fff;border:1px solid #ff9e8f;
    border-radius:5px;font-size:10px;font-weight:800;letter-spacing:.3px;padding:0 5px;white-space:nowrap;z-index:9;pointer-events:none;box-shadow:0 1px 4px #000b}
  /* a creature assigned as a blocker during declare-blockers: bold green ring so it clearly reads as committed */
  .card.selblk{box-shadow:0 0 0 4px #5fe08a,0 0 22px #5fe08a,inset 0 0 0 9999px #5fe08a1f;outline:2px solid #dfffe6cc;z-index:5}
  .card.selblk::after{content:"\1F6E1";position:absolute;top:3px;right:4px;font-size:13px;filter:drop-shadow(0 1px 2px #000)}
  /* declare-attackers: an opponent planeswalker you can aim attackers at (purple = "defender you may strike") */
  .card.deftarget{box-shadow:0 0 0 3px #c08bff,0 0 14px #c08bffcc;cursor:crosshair}
  /* gentle pulse so selected attackers / blockers / declared attackers catch the eye (no transform: safe when tapped) */
  .card.sel,.card.selblk,.card.attacking,.card.blkatk,.card.deftarget{animation:combatglow 1.25s ease-in-out infinite}
  @keyframes combatglow{0%,100%{filter:brightness(1)}50%{filter:brightness(1.13)}}
  .card.act{cursor:pointer}.card.act:hover{box-shadow:0 0 0 2px var(--gold)}
  .pt{position:absolute;bottom:2px;right:2px;background:#000c;border:1px solid #fff5;border-radius:4px;font-size:11px;padding:0 3px;color:#fff;font-weight:700}
  .dfcb{position:absolute;top:5px;left:5px;width:18px;height:18px;border-radius:50%;background:#1a1430dd;border:1px solid var(--gold);color:var(--gold2);font-size:12px;line-height:1;display:grid;place-items:center;z-index:4;pointer-events:none}
  /* A tapped card is rotated 90°, leaving its (often buffed) power/toughness sideways. The P/T sits at the
     local bottom-right, which the rotation maps to the card's VISUAL bottom-left — counter-rotate it upright
     there, and make it big/bold/opaque so it clearly dominates the card's own (now-sideways) printed P/T. */
  .card.tapped .pt{transform:rotate(-90deg) scale(1.5);transform-origin:center;bottom:16px;right:12px;
    background:#000e;border:1.5px solid #ffd76b;color:#fff;font-weight:800;z-index:6;box-shadow:0 1px 5px #000b}
  /* damage: persistent badge + floating pop on each hit */
  .dmg{position:absolute;top:2px;right:2px;background:#7a0d0d;border:1px solid #ff8a8a;border-radius:4px;font-size:11px;padding:0 3px;color:#ffe2e2;font-weight:800;z-index:6}
  .dmgpop{position:absolute;top:48%;left:50%;font-size:32px;font-weight:900;color:#ff5252;text-shadow:0 2px 6px #000,0 0 14px #ff0000;pointer-events:none;z-index:20;animation:dmgfloat 1.1s ease-out forwards}
  @keyframes dmgfloat{0%{opacity:0;transform:translate(-50%,-10%) scale(.6)}18%{opacity:1;transform:translate(-50%,-70%) scale(1.3)}100%{opacity:0;transform:translate(-50%,-170%) scale(1)}}
  .hitflash{position:absolute;inset:0;background:radial-gradient(circle,#ff000066,#ff000000 70%);border-radius:7px;pointer-events:none;z-index:19;animation:hitfade .6s ease-out forwards}
  @keyframes hitfade{0%{opacity:1}100%{opacity:0}}
  .blbl{position:absolute;top:2px;right:2px;background:#2a7fc0;color:#fff;border-radius:3px;font-size:9px;padding:0 3px}
  /* counters (+1/+1, -1/-1, stun, …) stacked on the left edge — big enough to read at a glance */
  .ctrs{position:absolute;left:3px;top:50%;transform:translateY(-50%);display:flex;flex-direction:column;gap:3px;z-index:7;pointer-events:none}
  .ctr{font-size:11px;font-weight:800;padding:1px 5px;border-radius:5px;background:#43434f;color:#fff;border:1px solid #ffffff80;white-space:nowrap;text-shadow:0 1px 2px #000;box-shadow:0 1px 4px #000a}
  .ctr.plus{background:#1f8a4c}.ctr.minus{background:#b02525}
  .ctr.stun{background:#1f6f9e;border-color:#9fe2ff}        /* stun = won't untap; cyan, distinct from damage/+1 */
  /* stunned creatures get a faint cyan wash so it's obvious at a glance (they stay tapped) */
  .card.stunned{box-shadow:inset 0 0 0 2px #5fc7ff,0 0 10px #2a9fd688}
  /* "doesn't untap" lock (Tidebinder Mage, Frost Titan, Sleep…): frost ring + ❄ badge so a creature
     that's stuck tapped reads as intentionally held down, not just normally tapped. */
  .card.nountap{box-shadow:inset 0 0 0 2px #7fd6ff,0 0 12px #3aa9e0aa}
  .nountap{position:absolute;top:2px;left:2px;z-index:8;background:#0a2b40e6;border:1px solid #7fd6ff;border-radius:6px;
    font-size:11px;line-height:1;padding:2px 4px;color:#dff3ff;box-shadow:0 1px 4px #000a,0 0 8px #3aa9e088;cursor:help}
  /* Ring-bearer: clearly mark the designated creature with a gold ring + a 💍 corner badge */
  .card.ringbearer{box-shadow:inset 0 0 0 2px #ffcf6b,0 0 13px #ffcf6baa}
  .card.ringbearer::after{content:"💍";position:absolute;bottom:3px;right:3px;font-size:14px;z-index:8;filter:drop-shadow(0 1px 2px #000)}
  /* The Ring indicator near each avatar (level + hover shows the stacked abilities) */
  .ringchip{margin-top:4px;font-size:11px;font-weight:800;color:#1a140a;background:linear-gradient(180deg,#ffe08a,#e8b24a);border:1px solid #fff3c4;border-radius:6px;padding:1px 6px;white-space:nowrap;cursor:help;box-shadow:0 1px 4px #000a}
  /* Persistent player designations (monarch/initiative/city's blessing) + resource counters (poison/energy/…) */
  .statuschip{margin-top:4px;display:flex;flex-wrap:wrap;gap:3px;justify-content:center;max-width:150px}
  .stbadge{font-size:11px;font-weight:800;line-height:1.4;color:#f4ecd8;background:#2b2416;border:1px solid #55452a;border-radius:6px;padding:0 5px;white-space:nowrap;cursor:help;box-shadow:0 1px 3px #0009}
  .stbadge.crown{color:#1a140a;background:linear-gradient(180deg,#ffe08a,#e8b24a);border-color:#fff3c4}
  .stbadge.init{color:#f4ecd8;background:linear-gradient(180deg,#8a2f2f,#5e1e1e);border-color:#c96}
  .stbadge.bless{color:#f4ecd8;background:linear-gradient(180deg,#3f6f8a,#274a5e);border-color:#9cd}
  .stbadge.emblem{color:#1a140a;background:linear-gradient(180deg,#d9b8ff,#a678e0);border-color:#e7d3ff}
  .stbadge.res.warn{color:#fff;background:linear-gradient(180deg,#7a1f1f,#4e1010);border-color:#e66;animation:poisonpulse 1.4s ease-in-out infinite}
  @keyframes poisonpulse{0%,100%{box-shadow:0 1px 3px #0009}50%{box-shadow:0 0 7px #f55}}
  @media(prefers-reduced-motion:reduce){.stbadge.res.warn{animation:none}}
  /* Class enchantment level: how many tiers/abilities are unlocked */
  .clvl{position:absolute;top:2px;left:2px;background:#5a3ea6;color:#fff;border:1px solid #cbb6ff;border-radius:5px;font-size:11px;font-weight:800;padding:0 4px;z-index:7;text-shadow:0 1px 2px #000;box-shadow:0 1px 4px #000a}
  /* Saga chapter tracker (📜 II/III) — labels the lore counter so it reads as a chapter, not a raw counter */
  .saga{position:absolute;top:2px;left:2px;background:linear-gradient(180deg,#b8863b,#7a5320);color:#fff2d6;border:1px solid #e9c98a;border-radius:5px;font-size:11px;font-weight:800;padding:0 4px;z-index:7;text-shadow:0 1px 2px #000;box-shadow:0 1px 4px #000a}
  /* Battle (Siege) protector badge — who you must attack through */
  .battle{position:absolute;top:2px;left:2px;background:linear-gradient(180deg,#8a2f2f,#5e1e1e);color:#ffe;border:1px solid #e6a; border-radius:5px;font-size:11px;font-weight:800;padding:0 4px;z-index:7;text-shadow:0 1px 2px #000;box-shadow:0 1px 4px #000a}
  .card.underatk{box-shadow:0 0 0 4px #ff5a3d,0 0 18px #ff5a3d}   /* a battle/planeswalker currently being attacked */
  /* Utility-token icon badge (💰 Treasure, 🍗 Food, …) — quick ID for stacks of identical tokens */
  .tokbadge{position:absolute;top:2px;right:2px;width:20px;height:20px;border-radius:50%;background:#1a1430dd;border:1px solid var(--gold);font-size:13px;line-height:1;display:grid;place-items:center;z-index:7;pointer-events:none;box-shadow:0 1px 4px #000a}
  /* aura/equipment indicator on an enchanted permanent (bottom-left; red ⛓ when it can't attack/block) */
  .enchb{position:absolute;left:3px;bottom:3px;min-width:18px;height:18px;padding:0 3px;border-radius:9px;background:#1a1430dd;border:1px solid var(--gold);color:var(--gold2);font-size:12px;line-height:1;display:grid;place-items:center;z-index:7;pointer-events:none;box-shadow:0 1px 4px #000a}
  .enchb.bad{border-color:#ff8f7e;color:#ff8f7e}
  /* aura/equipment grouped with their host: attachments tuck up behind the host's lower edge (offset so
     each peeks out + is hoverable); hovering the unit drops them out to read. Keeps the board compact. */
  .unit{display:flex;flex-direction:column;align-items:center;gap:0;position:relative}
  .unit > .card{position:relative;z-index:3}
  .unit .atts{display:flex;gap:0;justify-content:center;position:relative;z-index:2;
    margin-top:calc(-0.58 * clamp(64px,10vh,108px));transition:margin-top .15s}
  .unit:hover .atts{margin-top:4px}                       /* fan the attachments out on hover */
  .unit .atts .card.att + .card.att{margin-left:-12px}    /* overlap multiple attachments into a small fan */
  .card.att{height:clamp(64px,10vh,108px);width:calc(clamp(64px,10vh,108px)*.717);box-shadow:0 0 0 1px #ffcf6b88,0 2px 6px #000a}
  /* cards on the mat lift off the felt with a soft drop shadow. Overlapping cards in a pile/unit share ONE
     shadow — only the rearmost/base card casts — so stacked cards don't draw dark seams against each other. */
  .table .row .card{box-shadow:0 8px 17px -5px #000c}
  .tokwrap:not(:first-child) .card{box-shadow:none}                                 /* token pile: only the bottom card casts */
  .tokstack:hover .tokwrap .card,.table.picking .tokwrap .card{box-shadow:0 8px 17px -5px #000c}  /* fanned out to tap → each casts again */
  .unit .atts .card.att{box-shadow:0 0 0 1px #ffcf6b88}                             /* attachments tuck under the host → keep only their gold outline (the host casts the unit's shadow) */
  /* evergreen keyword badges (flying, deathtouch, …) — same pill language as the 💤 badge, parchment-toned */
  .kw{position:absolute;top:2px;left:50%;transform:translateX(-50%);display:flex;flex-wrap:wrap;gap:2px;justify-content:center;max-width:94%;z-index:8;pointer-events:none}
  .kwb{font-size:8.5px;font-weight:800;letter-spacing:.3px;color:#1a140a;background:linear-gradient(180deg,#f0dca8,#d6b367);
    border:1px solid #fff3c4;border-radius:5px;padding:1px 3px;line-height:1;box-shadow:0 1px 3px #000a}
  /* A tapped card is rotated 90°, which turns every text badge sideways. Counter-rotate them -90° so
     FLY / LL / counters / damage / class-level all read upright (same trick the .pt P/T badge uses).
     Each keeps its own positioning transform and just composes the counter-rotation on top. */
  /* counter-rotated, the kw row runs along the card's LONG edge — so drop the narrow-width wrap budget
     (it caused 3+ badges to wrap + clip) and shrink the pills a touch so several fit in one line. */
  .card.tapped .kw{top:50%;left:50%;right:auto;transform:translate(-50%,-50%) rotate(-90deg);flex-wrap:nowrap;max-width:none;gap:1px}
  .card.tapped .kwb{font-size:7px;padding:0 2px;letter-spacing:0}
  .card.tapped .ctrs{transform:translateY(-50%) rotate(-90deg)}
  .card.tapped .dmg,.card.tapped .clvl,.card.tapped .nountap,.card.tapped .blbl,.card.tapped .dfcb,.card.tapped .saga,.card.tapped .battle,.card.tapped .tokbadge,.card.tapped .atkbadge{transform:rotate(-90deg)}
  /* keyword reminder text in the card preview / zoom panels — a short glossary of the abilities on the card */
  .kwgloss{margin-top:6px;padding-top:5px;border-top:1px solid #ffffff22;font-size:11px;color:#cdbf9b;line-height:1.34}
  .kwgloss div{margin:2px 0}.kwgloss b{color:var(--gold2);font-weight:800}
  /* surrender (white flag): a quiet red-tinted button, hidden until a game is actually live */
  .dangerbtn{display:none;border-color:#7a3b3b;color:#ffd9d4}
  .dangerbtn.show{display:inline-flex}
  .dangerbtn:hover{background:#5a1f1f;border-color:#c25a52}
  /* ===== eye candy (FEATURES.effects; all DOM is JS-created only when enabled + motion allowed) ===== */
  /* ambient embers drifting up over the felt */
  #embers{position:absolute;inset:0;overflow:hidden;pointer-events:none;z-index:0}
  .ember{position:absolute;bottom:-14px;width:var(--s,6px);height:var(--s,6px);border-radius:50%;opacity:0;
    background:radial-gradient(circle,#ffe6a8cc,#e7c88400 70%);animation:emberrise var(--d,9s) linear var(--delay,0s) infinite}
  @keyframes emberrise{0%{transform:translateY(0) translateX(0) scale(.5);opacity:0}
    12%{opacity:.7}55%{transform:translateY(-44vh) translateX(var(--x,10px)) scale(1)}
    88%{opacity:.45}100%{transform:translateY(-88vh) translateX(calc(var(--x,10px)*-1)) scale(.5);opacity:0}}
  /* targeting beam: a glowing arc from the spell on the stack to each chosen target */
  #fxbeams{position:fixed;inset:0;width:100vw;height:100vh;pointer-events:none;z-index:60}   /* SVG is a replaced element: inset:0 alone leaves it at its 300x150 intrinsic size (clipping beams) — force full-viewport */
  #fxbeams .beam{fill:none;stroke:url(#beamgrad);stroke-width:3;stroke-linecap:round;filter:url(#beamglow);
    stroke-dasharray:10 8;animation:beamflow .6s linear infinite}
  #fxbeams .beamdot{fill:#fff3c4;filter:url(#beamglow);animation:beampulse 1s ease-in-out infinite}
  #fxbeams .beam.ghost{stroke-width:2.6;opacity:.72}    /* preview beam to the hovered legal target — kept clearly visible */
  #fxbeams .beamdot.ghost{opacity:.8}
  #fxbeams .beam.blockbeam{stroke-width:4.5;opacity:1}   /* declare-blockers: attacker → its chosen blocker */
  #fxbeams .beamdot.blockbeam{opacity:1}
  #fxbeams .beam.blockbeam.dash{stroke-width:3.4;opacity:.9;stroke-dasharray:8 6;animation:blockdash .6s linear infinite}
  @keyframes blockdash{to{stroke-dashoffset:-13}}
  @keyframes beamflow{to{stroke-dashoffset:-18}}
  @keyframes beampulse{0%,100%{r:5;opacity:.7}50%{r:8;opacity:1}}
  /* life total change: flash + scale/shake, plus a floating delta */
  .life.lifeup{animation:lifeup .6s ease-out}
  .life.lifedn{animation:lifedn .55s ease-out}
  @keyframes lifeup{0%{color:#7CFC8A;text-shadow:0 0 14px #4cd964;transform:scale(1)}45%{transform:scale(1.2)}100%{transform:scale(1)}}
  @keyframes lifedn{0%{color:#ff6b6b;text-shadow:0 0 14px #ff2d2d;transform:translateX(0)}25%{transform:translateX(-3px) scale(1.06)}55%{transform:translateX(3px)}100%{transform:translateX(0) scale(1)}}
  .lifedelta{position:fixed;z-index:61;pointer-events:none;font-weight:900;font-size:26px;text-shadow:0 2px 8px #000;
    transform:translateX(-50%);animation:lifefloat 1.55s ease-out forwards}
  .lifedelta.up{color:#8effa0}.lifedelta.dn{color:#ff7a7a}
  @keyframes lifefloat{0%{opacity:0;transform:translateX(-50%) translateY(0) scale(.7)}
    18%{opacity:1;transform:translateX(-50%) translateY(-16px) scale(1.2)}
    68%{opacity:1;transform:translateX(-50%) translateY(-34px) scale(1.02)}
    100%{opacity:0;transform:translateX(-50%) translateY(-60px) scale(1)}}
  /* low-life vignette — pulsing red edge when YOUR life is <=5 */
  #lowlifeFx{position:fixed;inset:0;pointer-events:none;z-index:7;opacity:0;transition:opacity .5s;
    background:radial-gradient(ellipse at 50% 118%,#ff000033,transparent 55%),radial-gradient(ellipse at 50% -18%,#ff000022,transparent 45%);
    box-shadow:inset 0 0 120px 24px #8b000055}
  #lowlifeFx.show{opacity:1;animation:heartbeat 1.5s ease-in-out infinite}
  @keyframes heartbeat{0%,100%{opacity:.35}50%{opacity:.85}}
  /* decision "what is this for" context: the source spell/ability + its rules text under the prompt */
  .dctx{font-size:12px;color:#cdbf9b;line-height:1.32;margin:1px 2px 6px;max-height:30vh;overflow:auto}
  .dctx b{color:var(--gold2);font-weight:800}
  /* creature death / leave-play dissolve (a ghost of the card fading + sinking to ash) */
  .dissolvefx{position:fixed;z-index:58;pointer-events:none;border-radius:7px;overflow:hidden;animation:dissolve .74s ease-in forwards}
  .dissolvefx img{width:100%;height:100%;object-fit:cover;border-radius:7px;display:block}
  .dissolvefx .nm{width:100%;height:100%;display:flex}
  @keyframes dissolve{0%{opacity:1;filter:none;transform:translateY(0) scale(1) rotate(0)}
    100%{opacity:0;filter:grayscale(1) brightness(.35) blur(3px);transform:translateY(14px) scale(.86) rotate(2deg)}}
  /* turn-change banner */
  #turnbanner{position:fixed;left:0;right:0;top:36%;z-index:62;pointer-events:none;text-align:center;opacity:0}
  #turnbanner.show{animation:turnsweep 1.5s ease-out}
  #turnbanner .tb{display:inline-block;padding:8px 30px;border-radius:40px;font-size:26px;font-weight:900;letter-spacing:1px;color:#fff;
    background:linear-gradient(100deg,#0d0b07f0,#241c10f0);box-shadow:inset 0 0 0 1px var(--gold),0 8px 30px #000c,0 0 30px #e7c88455}
  #turnbanner.mine .tb{box-shadow:inset 0 0 0 1px #6fe08a,0 8px 30px #000c,0 0 30px #4cd96466;color:#dffbe6}
  @keyframes turnsweep{0%{opacity:0;transform:translateY(-12px) scale(.92)}14%{opacity:1;transform:translateY(0) scale(1)}80%{opacity:1}100%{opacity:0;transform:scale(1.02)}}
  /* spell-cast ripple at the stack */
  .castfx{position:fixed;z-index:59;pointer-events:none;border-radius:50%;width:30px;height:30px;transform:translate(-50%,-50%);
    background:radial-gradient(circle,var(--cc,#ffd76b99),transparent 70%);animation:castripple .7s ease-out forwards}
  @keyframes castripple{0%{opacity:0;transform:translate(-50%,-50%) scale(.3)}25%{opacity:.9}100%{opacity:0;transform:translate(-50%,-50%) scale(7)}}
  .cardelemfx{position:fixed;z-index:59;pointer-events:none;object-fit:fill}   /* one-shot element burst over a card taking elemental damage */
  /* ETB golden sweep across an entering permanent */
  .card.justentered::after{content:"";position:absolute;inset:0;border-radius:7px;pointer-events:none;z-index:9;
    background:linear-gradient(115deg,transparent 32%,#fff3c4aa 50%,transparent 68%);background-size:300% 100%;animation:etbsweep .65s ease-out}
  @keyframes etbsweep{0%{background-position:140% 0;opacity:0}30%{opacity:1}100%{background-position:-40% 0;opacity:0}}
  /* combat: attackers lunge toward the enemy (animate top so it composes with the tapped rotation) */
  .card.charge-up{animation:chargeup .5s ease-out}
  .card.charge-dn{animation:chargedn .5s ease-out}
  @keyframes chargeup{0%{top:0}45%{top:-15px}100%{top:0}}
  @keyframes chargedn{0%{top:0}45%{top:15px}100%{top:0}}
  /* clash spark at a block's meeting point */
  .sparkfx{position:fixed;z-index:60;pointer-events:none;width:26px;height:26px;border-radius:50%;transform:translate(-50%,-50%);
    background:radial-gradient(circle,#fff,#ffb24daa 40%,transparent 70%);animation:spark .5s ease-out forwards}
  @keyframes spark{0%{opacity:0;transform:translate(-50%,-50%) scale(.2)}30%{opacity:1;transform:translate(-50%,-50%) scale(1.3)}100%{opacity:0;transform:translate(-50%,-50%) scale(2)}}
  /* damage feedback: floating -N + red flash on the hit creature/face, plus a scaled screen shake */
  .dmgfloat{position:fixed;z-index:61;pointer-events:none;font-weight:900;font-size:30px;color:#ff5252;text-shadow:0 2px 6px #000,0 0 14px #ff0000;
    transform:translate(-50%,-50%);animation:dmgfloatup 1.4s ease-out forwards}
  @keyframes dmgfloatup{0%{opacity:0;transform:translate(-50%,-50%) scale(.6)}16%{opacity:1;transform:translate(-50%,-90%) scale(1.3)}70%{opacity:1;transform:translate(-50%,-118%) scale(1.05)}100%{opacity:0;transform:translate(-50%,-165%) scale(1)}}
  .hitflashfx{position:fixed;z-index:60;pointer-events:none;border-radius:8px;background:radial-gradient(circle,#ff000077,transparent 70%);animation:hitfadefx .5s ease-out forwards}
  @keyframes hitfadefx{0%{opacity:1}100%{opacity:0}}
  main.shake{animation:scrShake .32s ease-in-out}
  @keyframes scrShake{0%,100%{transform:translate(0,0)}20%{transform:translate(calc(var(--shk,3px)*-1),1px)}40%{transform:translate(var(--shk,3px),-1px)}60%{transform:translate(calc(var(--shk,3px)*-1),0)}80%{transform:translate(var(--shk,2px),1px)}}
  /* lethal hit: a bigger, white-hot number (shown at the dying creature's last spot) + a 💀 */
  .dmgfloat.lethal{color:#fff;text-shadow:0 2px 8px #000,0 0 18px #ff2a2a,0 0 32px #ff0000;animation-duration:1.75s}
  .hitflashfx.lethal{background:radial-gradient(circle,#ffffffcc,#ff0000aa 45%,transparent 72%)}
  /* slash streak across a struck creature */
  .slashfx{position:fixed;z-index:62;pointer-events:none;width:var(--sl,72px);height:5px;border-radius:3px;transform:translate(-50%,-50%) rotate(-32deg);
    background:linear-gradient(90deg,transparent,#fff,#ffd0d0,#fff,transparent);box-shadow:0 0 12px #fff,0 0 20px #ff5252;animation:slashfx .34s ease-out forwards}
  .slashfx.lethal{height:7px;box-shadow:0 0 16px #fff,0 0 28px #ff0000}
  @keyframes slashfx{0%{opacity:0;transform:translate(-50%,-50%) rotate(-32deg) scaleX(.2)}30%{opacity:1}100%{opacity:0;transform:translate(-50%,-50%) rotate(-32deg) scaleX(1.15)}}
  /* red edge vignette when a player takes a big hit (pairs with the existing life-total flash) */
  #bloodfx{position:fixed;inset:0;z-index:59;pointer-events:none;opacity:0;
    background:radial-gradient(ellipse at 50% 50%,transparent 52%,#c1000077 100%)}
  #bloodfx.on{animation:bloodfx .6s ease-out}
  @keyframes bloodfx{0%{opacity:0}25%{opacity:1}100%{opacity:0}}
  /* win/lose finale (sits inside #gameover, behind the result panel) */
  #finaleFx{position:absolute;inset:0;pointer-events:none;overflow:hidden;z-index:0;border-radius:inherit}
  #finaleFx .rays{position:absolute;left:50%;top:44%;width:220vmax;height:220vmax;transform:translate(-50%,-50%);opacity:0;transition:opacity 1.2s;
    background:repeating-conic-gradient(from 0deg,#ffd76b18 0 5deg,transparent 5deg 16deg);animation:rayspin 16s linear infinite}
  #finaleFx.win .rays{opacity:1}
  #finaleFx.win{background:radial-gradient(ellipse at 50% 44%,#e7c88422,transparent 60%)}
  #finaleFx.lose{background:radial-gradient(ellipse at 50% 50%,transparent 28%,#2a0000bb 92%)}
  #gameover .panel2{position:relative;z-index:1}   /* keep the result panel above the finale rays */
  @keyframes rayspin{to{transform:translate(-50%,-50%) rotate(360deg)}}
  /* results-screen rank: current emblem + name + rating delta, with a promotion banner + emblem pop on rank-up */
  #goRank{display:none;flex-direction:column;align-items:center;gap:5px;margin:12px 0 2px}
  #goRank.on{display:flex}
  #goRank .go-emblem img.rankbadge{width:84px;height:84px;filter:drop-shadow(0 6px 18px #000b)}
  #goRank.promo .go-emblem{animation:goEmblemIn .6s cubic-bezier(.2,1.5,.4,1) both}
  @keyframes goEmblemIn{0%{transform:scale(.3) rotate(-14deg);opacity:0}60%{opacity:1}100%{transform:scale(1) rotate(0);opacity:1}}
  #goRank .go-rankname{font-weight:700;color:var(--gold2);letter-spacing:.6px;font-size:15px}
  #goRank .go-unranked{opacity:.85;font-weight:600;color:var(--text)}
  #goRank .go-rating{font-size:13px;opacity:.92}
  #goRank .go-rating .dup{color:#7ad27a;font-weight:800}#goRank .go-rating .ddn{color:#e08a8a;font-weight:800}
  #goRank .go-promo{margin-top:5px;font-weight:800;color:#0a0b18;background:linear-gradient(180deg,var(--gold2),var(--gold));
    padding:6px 15px;border-radius:20px;box-shadow:0 6px 22px var(--feltglow);animation:goPromoIn .5s ease both .15s}
  @keyframes goPromoIn{0%{transform:translateY(8px) scale(.92);opacity:0}100%{transform:none;opacity:1}}
  /* newly-earned achievements on the results screen */
  #goAch{display:none;flex-direction:column;gap:6px;margin:10px auto 2px;max-width:340px}
  #goAch.on{display:flex}
  #goAch .go-achhdr{text-align:center;font-size:11px;letter-spacing:2px;text-transform:uppercase;color:var(--gold2);opacity:.85}
  #goAch .go-achrow{display:flex;align-items:center;gap:10px;text-align:left;padding:7px 11px;border:1px solid var(--gold);border-radius:10px;
    background:linear-gradient(180deg,#ffffff14,#ffffff06);animation:goPromoIn .45s ease both .1s}
  #goAch .go-achrow .bi{font-size:20px;flex:0 0 auto}
  #goAch .go-acht{display:flex;flex-direction:column;min-width:0}
  #goAch .go-acht b{color:var(--gold2);font-size:14px}
  #goAch .go-achd{font-size:11.5px;opacity:.8}
  /* permanents band (artifacts/enchantments/planeswalkers) — a slim neutral shelf between creatures + lands */
  .row.perms{flex:.6;background:rgba(0,0,0,.16);border-radius:8px}
  .half.opp #oppPerm{z-index:2}.half.me #myPerm{z-index:2}
  /* identical tokens fan into one offset pile so a wide board doesn't fill the screen. Each member is
     still its own (cached) .card — fully clickable/highlightable — we only shift the wrapper. Collapsed
     by default; fanned apart on hover (desktop) or while picking attackers/blockers/targets (touch). */
  .tokstack{position:relative;display:inline-flex;align-items:flex-end;flex:0 0 auto}
  .tokwrap{flex:0 0 auto;position:relative;transition:margin-left .14s,transform .14s}
  .tokwrap{transform:translateY(calc(var(--i,0) * -5px));z-index:var(--i,0)}
  .tokwrap + .tokwrap{margin-left:calc(-1 * (clamp(112px,17vh,192px)*.717) + 27px)}   /* leave a ~27px sliver */
  .tokstack:hover .tokwrap,.table.picking .tokwrap{transform:none;z-index:auto}
  .tokstack:hover .tokwrap + .tokwrap,.table.picking .tokwrap + .tokwrap{margin-left:6px}   /* fan out to tap each */
  .tokn{position:absolute;top:-3px;right:-4px;z-index:40;background:var(--gold);color:#1a140a;font-weight:800;
    font-size:12px;line-height:1;border-radius:9px;padding:2px 7px;box-shadow:0 1px 4px #000a,inset 0 0 0 1px #fff6;pointer-events:none}
  .tokstack:hover .tokn,.table.picking .tokn{display:none}   /* fanned → the pile count is just noise */
  /* summoning sickness: dim the card + a sleepy badge so it's obvious it can't attack yet */
  .card.summonsick{filter:brightness(.66) saturate(.8)}
  .card.summonsick::before{content:"💤 sick";position:absolute;bottom:3px;left:3px;font-size:10px;font-weight:800;letter-spacing:.3px;
    color:#e3eeff;background:#0a1840ea;border:1px solid #76b0ff;border-radius:6px;padding:1px 5px;z-index:8;
    box-shadow:0 1px 4px #000,0 0 10px #3a7cff88}
  .rightrail{width:280px;flex:0 0 280px;display:flex;flex-direction:column;gap:8px;padding:10px;background:#0d0f0c;border-left:1px solid var(--line);position:relative;z-index:20}   /* z-index: stay above the zoomed board */
  .table{transform-origin:0 0}   /* scroll-to-zoom anchors here; JS sets the transform */
  .decision{background:#15120e;border:1px solid var(--gold);border-radius:10px;padding:12px;min-height:60px}
  .decision .dp{color:var(--gold2);font-size:13px;margin-bottom:8px}
  /* pulse the decision box whenever it's YOUR turn to act, so the game doesn't stall unnoticed */
  .decision.awaiting{border-color:var(--gold2);animation:decglow 1.2s ease-in-out infinite}
  @keyframes decglow{0%,100%{box-shadow:0 0 4px 0 #c8a35a44}50%{box-shadow:0 0 20px 4px var(--gold)}}
  .opts{display:flex;flex-direction:column;gap:6px;max-height:38vh;overflow:auto}
  .opts .o{text-align:left;white-space:normal;line-height:1.3;font-size:12.5px}
  .acts{display:flex;gap:6px;flex-wrap:wrap;margin-top:8px}
  .log{flex:1;min-height:0;overflow:auto;background:#0a0c08;border:1px solid var(--line);border-radius:8px;padding:8px;font-size:12px}
  #logExpand{display:none}   /* shown only on landscape phones (opens the full-screen log + chat) */
  .log .e{padding:1px 0;border-bottom:1px solid #ffffff0a;color:#c7c0b0}
  .log .e.lg-dmg{color:#ff8f7e}.log .e.lg-life{color:#9be08a}.log .e.lg-draw{color:#86c5ff}
  .log .e.lg-cast{color:#e7c884}.log .e.lg-death{color:#cf9bdb}.log .e.lg-exile{color:#caa9e0}
  .log .e.lg-turn{color:#fff;font-weight:700;border-top:1px solid #ffffff22;margin-top:3px;padding-top:3px}
  /* player chat stands out from the engine log: bold, tinted, color-coded per player */
  .log .e.lg-chat{font-weight:800;background:#ffffff10;border-left:3px solid currentColor;border-radius:4px;padding:2px 6px;margin:2px 0}
  .log .e.lg-chat0{color:#6fb7ff}   /* seat 0 = blue */
  .log .e.lg-chat1{color:#ff9e5e}   /* seat 1 = orange */
  /* player names inside combat-log lines use the same per-seat color as their chat */
  .log .e .lname0{color:#6fb7ff;font-weight:800}
  .log .e .lname1{color:#ff9e5e;font-weight:800}
  /* card names in the log: distinct color + hover shows the card */
  .log .e .cardname{color:#e8c98a;font-weight:700;text-decoration:underline dotted #e8c98a66;cursor:help}
  /* Chat message boxes are <textarea> (class .chatinp), NOT <input> — a textarea can never be a username/
     password field, so phones/managers never offer login autofill on them. Style them to read as one line. */
  textarea.chatinp{resize:none;overflow:hidden;white-space:nowrap;line-height:1.3;font-family:inherit;
    box-sizing:border-box;height:auto;align-self:center;background:#0a0c08;border:1px solid var(--line);border-radius:8px;color:var(--text)}
  .chatbox{display:none;gap:6px}
  .chatbox.show{display:flex}
  .chatbox input,.chatbox textarea{flex:1;min-width:0;background:#0a0c08;border:1px solid var(--line);border-radius:8px;color:var(--text);padding:6px 8px;font-size:12px}
  /* lobby chat (pre-game / between matches) */
  .lc-log{max-height:150px;overflow-y:auto;display:flex;flex-direction:column;gap:3px;background:#0a0c08;border:1px solid var(--line);border-radius:8px;padding:7px 9px;font-size:13px}
  .lc-msg{line-height:1.3;word-break:break-word;color:var(--text)}
  .lc-msg b{font-weight:800}
  .lc-seat0 b{color:#6fb7ff}.lc-seat1 b{color:#ff9e5e}
  .lc-empty{color:#8a8a78;font-style:italic}
  .nameinp{width:8.5em;background:#0a0c08;border:1px solid var(--line);border-radius:6px;color:var(--text);padding:5px 7px;font-size:12px}
  .ava.sel{box-shadow:0 0 0 3px #ff5d5d}
  .ava.legal{box-shadow:0 0 0 3px #ff6a6a,0 0 16px 3px #ff5d5dbb;animation:tgtpulse 1s ease-in-out infinite}   /* you can aim a spell at a player: pulse the avatar too */
  /* phase tracker (lives at the BOTTOM of the right rail, near the hand) */
  .phaserail{display:flex;gap:3px;flex-wrap:wrap}
  .ph{flex:1;text-align:center;font-size:10.5px;padding:4px 2px;border-radius:5px;background:#1b2417;color:#7c8b76;white-space:nowrap}
  .ph.on{background:var(--gold);color:#1a140a;font-weight:700}
  .ph.on.mine{background:#7ad27a}.ph.on.opp{background:#e69b8a}
  /* deck stacks (manual draw) */
  .table{position:relative;--deckw:calc(clamp(112px,17vh,192px)*.66)}
  .deck{position:absolute;right:14px;z-index:6;width:var(--deckw);height:calc(var(--deckw)/.717);
    border-radius:7px;border:1px solid #4a3c20;display:grid;place-items:center;
    background:repeating-linear-gradient(45deg,#241c10,#241c10 6px,#2e2415 6px,#2e2415 12px);
    box-shadow:2px 2px 0 -1px #2a2113,4px 4px 0 -2px #1c1509,0 4px 12px #000a}
  #oppDeck{top:14px}#myDeck{bottom:calc(clamp(138px,22vh,250px) + 16px)}
  /* graveyard pile — paired just left of each deck (Arena-style) */
  .grave{right:calc(14px + var(--deckw) + 12px);cursor:pointer;overflow:hidden}
  #oppGrave{top:14px}#myGrave{bottom:calc(clamp(138px,22vh,250px) + 16px)}
  .grave .top{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;border-radius:7px}
  .grave .ghost{position:absolute;inset:0;display:grid;place-items:center;font-size:30px;opacity:.45}
  .grave:not(.empty) .ghost{display:none}
  .grave.empty .top{display:none}
  .grave:hover{box-shadow:0 0 0 2px var(--gold),0 4px 14px #000c}
  .deck .dn{background:#000b;color:#fff;border:1px solid #ffffff55;border-radius:6px;padding:1px 7px;font-size:13px;font-weight:700}
  .deck.live{cursor:pointer;animation:deckpulse 1.1s ease-in-out infinite}
  .deck.live .dn::after{content:" ⟲";color:#e7c884}
  @keyframes deckpulse{0%,100%{box-shadow:2px 2px 0 -1px #2a2113,0 0 0 0 #e7c88400}50%{box-shadow:2px 2px 0 -1px #2a2113,0 0 18px 5px #e7c884cc}}
  /* exile pile — paired just left of each graveyard (one more deck-width over) */
  /* command zone (commander format) — left edge, mid-height, clear of the corner avatars + right piles */
  .cmdzone{position:absolute;left:12px;z-index:6;display:flex;flex-direction:column;align-items:center;gap:4px;pointer-events:auto}
  #oppCommand{top:auto;bottom:6px}   /* bottom-left of the opponent's half (anchored in .half.opp) — clear of the name pods */
  #myCommand{bottom:30%}
  .cmdzone .card{height:clamp(84px,13vh,150px);width:calc(clamp(84px,13vh,150px)*.717);box-shadow:0 0 0 2px #c8a35a,0 0 12px #c8a35a88}
  /* multiple commanders (partner / a Background enchantment) fan as an offset stack: front card on top,
     extras tucked behind and slightly up-left so each is visible + hoverable instead of hidden. */
  .cmdstack{position:relative;display:inline-block}
  .cmdstack .card{position:relative;z-index:3}
  .cmdstack .card.behind{position:absolute;left:calc(var(--i,1) * -13px);top:calc(var(--i,1) * -15px);
    z-index:calc(2 - var(--i,1));transform:scale(.92);filter:brightness(.78)}
  .cmdstack .card.behind:hover{filter:brightness(1);z-index:5}
  .cmddmg{font-size:12px;font-weight:800;color:#ffd0a0;background:#5a1d12cc;border:1px solid #ff8a6a;border-radius:6px;padding:1px 6px;text-shadow:0 1px 2px #000;cursor:help}
  .cmddmg.lethal{background:#7a0d0d;color:#fff;animation:decglow 1.2s ease-in-out infinite}
  .exilepile{right:calc(14px + 2*(var(--deckw) + 12px))}
  #oppExile{top:14px}#myExile{bottom:calc(clamp(138px,22vh,250px) + 16px)}
  /* tell the piles apart at a glance: graveyard = amber label, exile = violet frame + tint + label */
  .grave::after{content:"GRAVE";position:absolute;left:0;right:0;bottom:0;text-align:center;font-size:8px;font-weight:800;
    letter-spacing:.6px;color:#e9d9a8;background:linear-gradient(0deg,#000d,transparent);padding:6px 0 1px;z-index:3;pointer-events:none}
  .exilepile{box-shadow:0 0 0 1.5px #8a63b8,0 0 12px #6a4f7f88,2px 2px 0 -1px #2a2113,0 4px 12px #000a}
  .exilepile::before{content:"";position:absolute;inset:0;background:#6a3fa033;z-index:2;border-radius:7px;pointer-events:none}
  .exilepile::after{content:"EXILE";color:#e1c2f7}
  /* inline mana / tap symbols inside rules & cost text — same palette as the mana pool pips */
  .sym{display:inline-grid;place-items:center;min-width:15px;height:15px;border-radius:50%;font-size:10px;
    font-weight:700;color:#000;vertical-align:-2px;margin:0 1px;line-height:1;box-shadow:inset 0 0 0 1px #0004}
  .sym.W{background:#f5f0d8}.sym.U{background:#2a7fc0;color:#fff}.sym.B{background:#39332c;color:#e6dccb}
  .sym.R{background:#d3322a;color:#fff}.sym.G{background:#1f8a4c;color:#fff}.sym.C{background:#c2bbac}
  .sym.gen{background:#cabfa0}.sym.tap{background:#d8cdae;font-size:11px}
  .sym.energy{background:#123; color:#7fe3ff; font-size:11px}
  /* XMage hint-icon glyphs surfaced from rules text (restriction/requirement/good/bad/dungeon) */
  .ric{font-style:normal;font-weight:700;font-size:.92em;vertical-align:baseline;margin-right:2px}
  .ric.bad{color:#ff8f7e}.ric.warn{color:#e6b96a}.ric.good{color:#8fca94}
  .sym.multi{border-radius:8px;padding:0 4px;background:#cabfa0;font-size:9px;letter-spacing:-.5px}
  /* ---- MOBILE -----------------------------------------------------------------------------
     Everything phone-specific lives below in ONE media query so the desktop layout above is
     untouched. The two mobile-only buttons are hidden by default and only shown inside it. */
  #moreBtn,#logBtn{display:none}
  @media (max-width:760px){
    body{height:100dvh}                                   /* dvh: survive the mobile browser's shrinking chrome */
    /* toolbar: wrap, shrink, and tuck secondary controls behind the ⋯ menu */
    .bar{flex-wrap:wrap;gap:7px;padding:6px 9px}
    .bar h1{font-size:14px}
    .btn{padding:6px 10px;font-size:12px}
    #moreBtn{display:inline-flex;align-items:center}
    .bar .barsec{display:none}
    body.menuopen .bar .barsec{display:inline-flex;align-items:center}
    /* board takes the full width; the right rail drops below it as a short bottom band */
    main{flex-direction:column}
    .table{--deckw:calc(clamp(112px,17vh,192px)*.52);min-height:40vh}     /* slimmer piles; keep the board from collapsing */
    /* flex:0 1 auto (was 0 0) + min-height:0 → the rail SHRINKS to fit and scrolls internally instead of
       overflowing main (overflow:hidden), which used to clip the log/chat buttons under the turn bar */
    .rightrail{width:auto;flex:0 1 auto;min-height:0;max-height:46vh;overflow-y:auto;
      border-left:none;border-top:1px solid var(--line);padding:7px 9px;gap:6px}
    .decision{order:-2}.yieldbtn{order:-1}.phaserail{order:0}#logBtn{order:1;display:inline-flex}
    .chatbox{order:2}.log{order:3}
    .rightrail .log{display:none}                          /* hidden by default; 📜 expands it */
    body.logopen .rightrail .log{display:block;min-height:120px}
    .opts{max-height:30vh}
    /* modals fit a narrow screen */
    .overlay2{padding:12px}
    .panel2{padding:16px;max-width:100%}
    #deckmodal .panel2{min-width:0;width:100%}
    /* no iOS long-press text-selection / callout on cards — long-press is our "zoom to read" gesture */
    .card{-webkit-touch-callout:none;-webkit-user-select:none;user-select:none}
  }
  /* Lobby on phones (portrait OR a short landscape viewport): the panel can be taller than the visible
     screen, and a centered overlay would clip its top/bottom behind the browser chrome (ready button + chat
     lost behind the address bar). Anchor to the top of the *visible* viewport (dvh) and scroll, with a
     safe-area bottom gap so the last button clears the toolbar. */
  @media (max-width:900px), (max-height:600px){
    #lobby{inset:0 0 auto 0;height:100dvh;align-items:flex-start;justify-content:center;
      overflow-y:auto;-webkit-overflow-scrolling:touch;
      padding:max(10px,env(safe-area-inset-top)) max(12px,env(safe-area-inset-right)) calc(env(safe-area-inset-bottom) + 22px) max(12px,env(safe-area-inset-left))}
  }
  /* Touch devices synthesize a mouseenter on tap, which would pop the hover-read panel and eat the
     screen. Suppress it where there's no real hover — long-press → zoom (and pinch-zoom) read cards. */
  @media (hover:none){ #preview{display:none!important}
    /* long-press is OUR zoom gesture — suppress the browser's image save/copy menu. -webkit-touch-callout
       is iOS-only, so ALSO make the card art non-interactive: the long-press then lands on the card <div>
       (not an <img>), so the browser has no image to offer, and our long-press-to-zoom still fires. */
    .card,.card img,.deck img,.cmdzone img,.scard img,#zoom img,#mImg,.revealrow .rc img{-webkit-touch-callout:none;-webkit-user-select:none;user-select:none}
    .card img,.deck img,.cmdzone img,#zoom img,#mImg,.revealrow .rc img{pointer-events:none} }
  /* ---- force landscape on phones ONLY where it's needed: a full-screen "rotate" overlay covers the
     app in portrait, but only while body.needland is set (in a battle / draft room). The main menu,
     profile and the menu's fullscreen panels stay usable in portrait. updateLandscapeLock() drives it. */
  #rotate{display:none}
  @media (orientation:portrait) and (max-width:820px){
    body.needland #rotate{display:flex;position:fixed;inset:0;z-index:200;background:var(--bg);color:var(--text);
      flex-direction:column;align-items:center;justify-content:center;gap:14px;text-align:center;padding:30px}
    #rotate .ro-i{font-size:64px;animation:rotatehint 2.4s ease-in-out infinite;transform-origin:center}
    #rotate .ro-t{font-size:22px;font-weight:800;color:var(--gold2)}
    #rotate .ro-s{font-size:14px;color:var(--muted);max-width:320px;line-height:1.5}
    /* escape hatch: portrait users who don't want to rotate can still get back to the (portrait-OK) menu */
    #rotate .ro-back{margin-top:8px;font:inherit;font-size:14px;font-weight:600;color:var(--text);cursor:pointer;
      border:1px solid var(--line);background:#ffffff10;border-radius:10px;padding:10px 18px}
    #rotate .ro-back:hover,#rotate .ro-back:active{border-color:var(--gold);background:#ffffff1f}
  }
  @keyframes rotatehint{0%,55%{transform:rotate(0)}80%,100%{transform:rotate(90deg)}}
  /* ---- landscape phones: small cards (read by long-press / pinch zoom) → more room for the board ---- */
  @media (orientation:landscape) and (max-height:600px){
    body{height:100dvh}                       /* dvh excludes the browser address bar so the hand isn't hidden behind it */
    /* declutter the toolbar to ONE short row (desktop launch + toggles tuck behind ⋯ / the 📱 menu) so
       the battlefield gets the vertical space — same chrome the narrow-portrait phone uses */
    .bar{flex-wrap:wrap;gap:5px;padding:3px 8px}
    .bar h1{font-size:12px} .btn{padding:4px 8px;font-size:11px}
    #moreBtn,#mobileBtn{display:inline-flex;align-items:center}
    .bar .barsec{display:none} body.menuopen .bar .barsec{display:inline-flex;align-items:center}
    .deskonly{display:none!important}
    body.has-chat #chatBtn{display:inline-flex;align-items:center} .chatbox{display:none!important}
    /* keep the rail on the RIGHT (landscape has width to spare) but NARROW; board takes the rest */
    .rightrail{width:176px;flex:0 0 176px;padding:6px;gap:8px;font-size:12px;overflow-y:auto}
    /* turn/decision up top, battle log fills the middle, Skip + Log/Chat docked at the BOTTOM */
    .phaserail{order:0}.decision{order:1}.log{order:2}.yieldbtn{order:3}#logExpand{order:4}.chatbox{order:5}
    #logBtn{display:none} #logExpand{display:block;font-size:11px;padding:5px 7px;flex:0 0 auto}
    .yieldbtn{flex:0 0 auto}
    .rightrail .log{display:block;flex:1 1 auto;min-height:40px}
    .opts{max-height:34vh}
    /* the decision (prompt + Hint/Pass) must keep its full height — only the log flexes/shrinks */
    .phaserail{flex:0 0 auto} .decision{padding:8px;min-height:0;flex:0 0 auto}
    /* the reveal/preview card was a fixed 98px (oversized + clipped here) — shrink it and clear the bar */
    .revealzone{top:42px;z-index:95}
    .revealrow{padding:4px 7px;gap:6px} .revealrow .rc{height:64px;width:calc(64px*.717)}
    .rvpop{padding:9px 11px;gap:7px} .rvpop-lbl{font-size:12px} .rvpop .rc{height:128px;width:calc(128px*.717)}
    .revealrow .rlbl{font-size:11px}
    /* small cards — read them by double-tap / pinch / long-press zoom (board only).
       NB: set width too, not just height, or the box keeps the desktop width → wrong aspect → cropped art. */
    .card{height:clamp(38px,16vh,130px);width:calc(clamp(38px,16vh,130px)*.717)}
    .hand{min-height:0;padding:2px 8px 4px;gap:3px}
    .hand .card{flex:0 1 calc(clamp(38px,17vh,130px)*.717);max-width:calc(clamp(38px,17vh,130px)*.717);min-width:22px}
    .table{--deckw:calc(clamp(38px,12vh,130px)*.58)}
    .half{padding:2px 10px;gap:2px}.half.opp{padding-top:15px}
    .row{gap:4px}.life{font-size:22px;min-width:22px}
    .ava{gap:5px}.ava .aname{font-size:11px}
    .turnbar{padding:2px 12px}#phase{font-size:13px}
  }
  /* ---- full-screen chat ---- */
  #chatBtn{display:none}                                  /* only when a human opponent is present (applyModeUI) */
  .cbadge{display:none;background:#e0533a;color:#fff;border-radius:10px;font-size:11px;font-weight:800;padding:0 6px;margin-left:5px}
  #chatfull .chatpanel{width:100%;max-width:520px;height:80vh;max-height:92vh;align-items:stretch;gap:10px;padding:14px}
  .chathead{display:flex;align-items:center;justify-content:space-between}
  .chatlog{flex:1;overflow:auto;display:flex;flex-direction:column;gap:7px;padding:6px;background:#0a0c08;border:1px solid var(--line);border-radius:10px}
  .chatlog .bubble{max-width:82%;padding:7px 11px;border-radius:13px;font-size:14px;line-height:1.35;word-break:break-word}
  .chatlog .bubble .bn{display:block;font-size:11px;opacity:.7;font-weight:700;margin-bottom:1px}
  .chatlog .bubble.me{align-self:flex-end;background:#2f6db0;color:#fff;border-bottom-right-radius:4px}
  .chatlog .bubble.them{align-self:flex-start;background:#3a3320;color:#ffd9a8;border-bottom-left-radius:4px}
  .chatlog .logline{font-size:13px;color:#c7c0b0;line-height:1.4;padding:1px 2px}
  .chatlog .chatempty{margin:auto;color:var(--muted);font-style:italic}
  .chatrow{display:flex;gap:7px}
  .chatrow input,.chatrow textarea{flex:1;min-width:0;background:#0a0c08;border:1px solid var(--line);border-radius:9px;color:var(--text);padding:11px;font-size:15px}
  #chatToast{position:fixed;top:10px;left:50%;transform:translateX(-50%) translateY(-160%);z-index:90;
    max-width:min(90vw,420px);background:linear-gradient(160deg,#243a59,#16243a);border:1px solid #3a6ea5;
    border-radius:12px;box-shadow:0 10px 28px #000b;color:#eaf2ff;padding:10px 14px;font-size:13px;cursor:pointer;
    display:flex;gap:10px;align-items:center;transition:transform .3s cubic-bezier(.2,.8,.2,1),opacity .3s;opacity:0;pointer-events:none}
  #chatToast.show{transform:translateX(-50%) translateY(0);opacity:1;pointer-events:auto}
  #chatToast .ct-i{font-size:19px;line-height:1}
  #chatToast .ct-body{min-width:0;display:flex;flex-direction:column;gap:1px}
  #chatToast .ct-from{font-weight:800;color:#9fc2ff;font-size:12px}
  #chatToast .ct-text{opacity:.94;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:62vw}
  /* generic silent notice toast (top-center) — e.g. "X declined your challenge". No sound, auto-dismisses. */
  #notice{position:fixed;top:max(10px,env(safe-area-inset-top));left:50%;transform:translateX(-50%) translateY(-160%);z-index:97;
    max-width:min(90vw,420px);background:linear-gradient(160deg,#3a2f18,#241c10);border:1px solid var(--gold);
    border-radius:12px;box-shadow:0 10px 28px #000b;color:#f3e6c8;padding:10px 14px;font-size:13px;text-align:center;
    transition:transform .3s cubic-bezier(.2,.8,.2,1),opacity .3s;opacity:0;pointer-events:none}
  #notice.show{transform:translateX(-50%) translateY(0);opacity:1}
  #notice b{color:var(--gold2)}
  @media (max-width:760px){
    /* roomier touch targets + a less cramped board */
    .life{font-size:34px;min-width:34px}
    .hand{min-height:104px;padding:4px 6px 7px;gap:5px}
    .ava .aname{font-size:12px}
    #mobileBtn{display:inline-flex;align-items:center}
    /* the 📱 Menu (vs AI / 1v1) + ⋯ toggles replace these desktop launch controls on a phone */
    .deskonly{display:none!important}
    /* chat on a phone = a full-screen overlay opened by the bar button (not the cramped inline row) */
    body.has-chat #chatBtn{display:inline-flex;align-items:center}
    .chatbox{display:none!important}
    /* chat truly fills the screen on a phone (no centered card, no border radius) */
    #chatfull{padding:0;align-items:stretch;justify-content:stretch}
    #chatfull .chatpanel{height:100%;width:100%;max-width:none;max-height:none;border:none;border-radius:0;
      padding:10px max(10px,env(safe-area-inset-left)) max(10px,env(safe-area-inset-bottom))}
  }
  /* ===== main menu (entry screen: random playmat backdrop + deck-color palette + drifting embers) ===== */
  #mainmenu{position:fixed;inset:0;z-index:80;display:none;flex-direction:column;align-items:center;justify-content:center;
    background:#05060c;overflow:hidden}
  #mainmenu.show{display:flex}
  /* the mat lives on its own layer so we can parallax it (JS, pointer) AND ken-burns it (CSS) independently */
  #mmBg{position:absolute;inset:-28px;z-index:0;overflow:hidden;transition:transform .35s ease-out}   /* overscan > parallax travel so edges never show */
  #mmBgImg{position:absolute;inset:-9%;background-size:cover;background-position:center;will-change:transform}
  #mmBgImg.kb{animation:mmKen 34s ease-in-out infinite alternate}
  @keyframes mmKen{0%{transform:scale(1.05) translate(0,0)}100%{transform:scale(1.16) translate(-2.2%,-2.2%)}}
  #mainmenu::before{content:"";position:absolute;inset:0;z-index:1;pointer-events:none;   /* vignette so buttons read over any mat */
    background:radial-gradient(ellipse at 50% 42%,#0a0b1866 0%,#05060cd6 84%)}
  #mmEmbers{position:absolute;inset:0;z-index:1;overflow:hidden;pointer-events:none}
  /* faint arcane sigil ring drifting behind the title */
  .mm-rune{position:absolute;top:50%;left:50%;width:min(118vmin,840px);height:min(118vmin,840px);
    transform:translate(-50%,-50%);transform-origin:center;z-index:1;pointer-events:none;opacity:.07;
    color:var(--gold2);animation:mmSpin 120s linear infinite}
  @keyframes mmSpin{to{transform:translate(-50%,-50%) rotate(360deg)}}
  .mm-panel{position:relative;z-index:2;display:flex;flex-direction:column;align-items:center;gap:22px;text-align:center;
    padding:26px;max-width:min(92vw,520px);animation:mmIn .5s ease both;
    /* when the button stack is taller than the viewport (short landscape phones, or admin+resume adding rows) the
       menu used to clip top & bottom — cap to the viewport and scroll internally so every button stays reachable.
       Hide the scrollbar: the panel is centered & narrower than the window, so an internal scrollbar would float
       mid-screen (looks broken); scrolling still works via wheel/touch/keyboard. */
    max-height:100dvh;overflow-y:auto;overscroll-behavior:contain;scrollbar-width:none}
  .mm-panel::-webkit-scrollbar{width:0;height:0}
  @keyframes mmIn{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}
  .mm-title{margin:0;font-size:clamp(40px,9vw,78px);line-height:1;letter-spacing:.05em;font-weight:800;
    color:var(--text);text-shadow:0 0 34px var(--feltglow),0 2px 12px #000b;
    background:linear-gradient(100deg,var(--text) 32%,var(--gold2) 50%,var(--text) 68%);background-size:220% auto;
    -webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;animation:mmShimmer 6.5s linear infinite}
  @keyframes mmShimmer{to{background-position:220% center}}
  .mm-title .mc{-webkit-text-fill-color:var(--gold2);color:var(--gold2)}   /* "Core" stays solid gold while "Mana" shimmers */
  /* Brand LOGO (crystal + wordmark). Its shape lives in the ALPHA channel, so we use it as a CSS mask and fill it
     with the SAME themed shimmer gradient the title used. Because it fills with var(--gold2)/var(--text), it
     recolours itself for every theme AND every playmat (mat-white/blue/black/red each remap those vars) — so it
     "fits" the green felt, the blue mat, etc. automatically. Drop-shadow keeps it legible on any mat.
     ASSET NOTE: this used to point at logo.png (1024², 196 KB). A mask reads ONLY alpha, so that file's ~3000
     distinct RGB values were downloaded and thrown away every visit, at 4× the resolution this ever renders
     (max 244 CSS px → 768 covers DPR 3). logo-mask.* are the same alpha, flattened and resized: 46 KB PNG /
     24 KB WebP, byte-for-byte identical mask output. logo.png is kept in the repo as the design master but is
     no longer fetched by anything. */
  .mm-logo{width:clamp(146px,32vw,244px);aspect-ratio:1;max-height:23vh;margin:0 0 -14px;flex:0 0 auto;
    -webkit-mask:url("logo-mask.png") center/contain no-repeat;mask:url("logo-mask.png") center/contain no-repeat;
    /* Prefer WebP where image-set() is understood. Declared AFTER the plain url() above, never instead of it:
       if image-set is unsupported these two lines are dropped and the PNG still applies. An invalid mask would
       render NO logo at all, so the universally-safe form has to come first. */
    -webkit-mask-image:image-set(url("logo-mask.webp") type("image/webp"), url("logo-mask.png") type("image/png"));
    mask-image:image-set(url("logo-mask.webp") type("image/webp"), url("logo-mask.png") type("image/png"));
    background:linear-gradient(100deg,var(--text) 30%,var(--gold2) 50%,var(--text) 70%);background-size:200% 100%;
    background-position:0 50%;animation:mmLogoShine 6.5s linear infinite;
    filter:drop-shadow(0 2px 14px #000b) drop-shadow(0 0 26px var(--feltglow))}
  /* Seamless sweep: with background-size 200%, a background-position of 200% shifts the pattern by EXACTLY one tile, so
     the loop is invisible. (The old 220%/220% moved 1.2 tiles — a non-integer — which is why it jumped every cycle.)
     Y is pinned at 50% so it doesn't drift; the gradient ends are both var(--text) so adjacent tiles meet cleanly. */
  @keyframes mmLogoShine{to{background-position:200% 50%}}
  .mm-sub{margin:-12px 0 4px;color:var(--gold2);font-size:12px;letter-spacing:.26em;text-transform:uppercase;opacity:.82}
  .mm-btns{display:flex;flex-direction:column;gap:13px;width:min(86vw,330px);flex:0 0 auto}
  .mm-btn{position:relative;font:inherit;font-size:18px;font-weight:600;color:var(--text);cursor:pointer;flex:0 0 auto;
    padding:15px 20px;border-radius:13px;border:1px solid var(--line);
    background:linear-gradient(180deg,#ffffff14,#ffffff06);backdrop-filter:blur(2px);
    transition:transform .12s ease,border-color .15s ease,background .15s ease,box-shadow .15s ease}
  .mm-btn:not(.soon){overflow:hidden}    /* clip the shine sweep (but not the "coming soon" chip that sticks out) */
  .mm-btn:not(.soon)::after{content:"";position:absolute;top:0;left:-130%;width:55%;height:100%;pointer-events:none;
    background:linear-gradient(105deg,transparent,#ffffff5e,transparent);transform:skewX(-18deg)}
  .mm-btn:not(.soon):hover::after{animation:mmShine .7s ease}
  @keyframes mmShine{to{left:150%}}
  .mm-btn:hover{transform:translateY(-2px);border-color:var(--gold);background:linear-gradient(180deg,#ffffff22,#ffffff0c);
    box-shadow:0 8px 26px #0007,0 0 0 1px var(--gold) inset}
  .mm-btn.gold{border-color:var(--gold);background:linear-gradient(180deg,color-mix(in srgb,var(--gold) 55%,transparent),#ffffff10);
    box-shadow:0 6px 24px var(--feltglow)}
  .mm-btn.soon{opacity:.6;cursor:default}
  .mm-btn.soon:hover{transform:none;box-shadow:none;border-color:var(--line);background:linear-gradient(180deg,#ffffff10,#ffffff04)}
  /* landscape phones (short viewport): shrink the logo/gaps/buttons so the whole menu fits without scrolling.
     The .mm-panel scroll cap above still catches the rare overflow (e.g. admin + resume rows). */
  @media (orientation:landscape) and (max-height:600px){
    .mm-panel{gap:9px;padding:12px 26px}
    .mm-logo{max-height:15vh;margin-bottom:-6px}
    .mm-sub{display:none}
    .mm-btns{gap:8px}
    .mm-btn{padding:10px 18px;font-size:15px;border-radius:11px}
  }
  /* admin alert dot (XMage-needs-update) — inside the button's top-right so overflow:hidden doesn't clip it */
  .mm-alertdot{position:absolute;top:9px;right:11px;width:10px;height:10px;border-radius:50%;background:#ff5a5a;
    box-shadow:0 0 0 2px #0007,0 0 9px #ff5a5a;pointer-events:none;animation:mmAlertPulse 1.6s ease-in-out infinite}
  @keyframes mmAlertPulse{0%,100%{opacity:1}50%{opacity:.45}}
  @media(prefers-reduced-motion:reduce){ .mm-alertdot{animation:none} }
  /* admin user list: name/meta on top, a tidy left-aligned action bar below (rare actions behind ⋯) */
  .adm-row{padding:10px 4px;border-bottom:1px solid rgba(255,255,255,.06)}
  .adm-row .adm-id b{font-size:14px}
  .adm-tag{font-size:10px;font-weight:600;margin-left:3px;white-space:nowrap}
  .adm-tag.sup{color:#ffd24a}.adm-tag.adm{color:#caa84a}.adm-tag.on{color:#7bd88f}.adm-tag.ban{color:#e06a6a}
  .adm-tag.mute{color:#e0a24a}
  .adm-mutesel{font-size:12px;padding:4px 6px;width:auto;min-width:0;box-sizing:border-box}
  .adm-sub{font-size:11px;color:#8a8a78;margin-top:3px;line-height:1.55}
  .adm-acts{display:flex;flex-wrap:wrap;gap:6px;align-items:center;margin-top:9px}
  .adm-acts .adm-more{display:none;flex-wrap:wrap;gap:6px}
  .adm-acts .adm-more.show{display:inline-flex}
  .adm-btn{font-size:11px;padding:4px 10px;line-height:1.1}
  .adm-morebtn{font-weight:700;letter-spacing:1px;min-width:34px}
  .adm-morebtn.on{border-color:var(--gold);color:var(--gold2)}
  .adm-you{font-size:11px;color:#8a8a78;margin-right:2px;align-self:center}
  .mm-soon{position:absolute;top:-9px;right:12px;font-size:10px;letter-spacing:.06em;text-transform:uppercase;
    background:var(--gold);color:#0a0b18;font-weight:700;padding:2px 7px;border-radius:99px;box-shadow:0 2px 8px #0008}
  .mm-fs{position:absolute;top:max(12px,env(safe-area-inset-top));right:max(12px,env(safe-area-inset-right));z-index:3;
    width:44px;height:44px;border-radius:11px;font-size:19px;cursor:pointer;color:var(--text);
    border:1px solid var(--line);background:#ffffff12;backdrop-filter:blur(2px)}
  .mm-fs:hover{border-color:var(--gold);background:#ffffff1f}
  /* account chip (top-left of the menu): subtle by design — guests see a plain "Log in" link */
  .mm-acct{position:absolute;top:max(12px,env(safe-area-inset-top));left:max(12px,env(safe-area-inset-left));z-index:3;
    display:flex;align-items:center;gap:8px;min-height:40px;max-width:42vw;padding:6px 13px;border-radius:11px;font:inherit;
    font-size:13px;font-weight:600;color:var(--text);cursor:pointer;border:1px solid var(--line);background:#ffffff10;
    backdrop-filter:blur(2px);opacity:.8;transition:opacity .15s ease,border-color .15s ease,background .15s ease}
  .mm-acct:hover{border-color:var(--gold);background:#ffffff1f;opacity:1}
  .mm-logout{position:absolute;top:max(60px,calc(env(safe-area-inset-top) + 48px));left:max(12px,env(safe-area-inset-left));z-index:3;
    font:inherit;font-size:12px;font-weight:600;color:var(--text);cursor:pointer;border:1px solid var(--line);
    background:#ffffff0c;backdrop-filter:blur(2px);border-radius:9px;padding:5px 11px;opacity:.7}
  .mm-logout:hover{border-color:var(--gold);background:#ffffff1a;opacity:1}
  /* right rail: live online players + leaderboard, embedded in the menu (desktop only) */
  #mmSide{display:none;position:absolute;z-index:2;top:88px;right:0;bottom:0;width:320px;
    flex-direction:column;gap:16px;padding:16px 14px 20px;overflow-y:auto;
    background:linear-gradient(180deg,#0a0b14cc,#070810ee);border-left:1px solid var(--line);
    box-shadow:-8px 0 26px #0006;animation:mmIn .5s ease both}
  .mms-sec{display:flex;flex-direction:column;gap:7px}
  .mms-board{flex:1 1 auto;min-height:90px}
  .mms-h{font-size:12px;letter-spacing:.16em;text-transform:uppercase;color:var(--gold2);font-weight:700;
    padding:0 2px 5px;border-bottom:1px solid var(--line)}
  #mmChatSec .mms-h{display:flex;align-items:center}
  .mms-hsub{margin-left:auto;font-size:10px;letter-spacing:.03em;text-transform:none;color:var(--muted);font-weight:500}
  .mms-list{display:flex;flex-direction:column;gap:5px}
  .mms-row{display:flex;align-items:center;gap:8px;font-size:13px;padding:5px 8px;border-radius:8px;background:#ffffff08}
  .mms-row .av{width:20px;height:20px;font-size:11px}
  .mms-row .nm{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--text)}
  .mms-row .nm.online{color:#5fb0ff;font-weight:600}   /* online players on the leaderboard show blue */
  .mms-row .rk{min-width:22px;text-align:right;color:var(--gold2);font-weight:700;font-variant-numeric:tabular-nums}   /* right-align so the rank hugs the name, not the far left */
  .mms-row .rt{color:var(--gold2);font-weight:700;font-variant-numeric:tabular-nums;min-width:38px;text-align:right}
  .mms-row.me{background:#ffffff16;box-shadow:0 0 0 1px var(--gold) inset}
  .mms-row .chalbtn{padding:3px 9px;font-size:12px}
  .mms-row .inmatch{font-size:11px}
  .mms-empty{color:#8a8a78;font-size:12px;padding:6px 4px}
  .mms-muted{color:#e0a24a;font-size:12px;line-height:1.4;padding:6px 8px;margin:4px 0 0;border-radius:8px;
    background:#e0a24a1a;border:1px solid #e0a24a44}
  /* global lobby chat in the right rail (logged-in only); flex-none so it keeps a stable height below the board */
  .mms-chat{flex:0 0 auto}
  .mms-chatlog{display:flex;flex-direction:column;gap:5px;height:150px;overflow-y:auto;padding:6px;
    background:#0a0c08;border:1px solid var(--line);border-radius:9px}
  .mms-chatlog .cm{font-size:12.5px;line-height:1.32;word-break:break-word}
  .mms-chatlog .cm .cn{font-weight:700;color:#5fb0ff;margin-right:5px}      /* sender name (blue, like online players) */
  .mms-chatlog .cm .cn.cnlink{cursor:pointer}                               /* clickable → opens the sender's public profile */
  .mms-chatlog .cm .cn.cnlink:hover{text-decoration:underline}
  .mms-chatlog .cm.me .cn{color:var(--gold2)}                               /* your own messages: gold name */
  .mms-chatlog .cm .ct{color:var(--text)}
  .mms-chatlog .chatempty{margin:auto;color:#8a8a78;font-size:12px;font-style:italic;text-align:center}
  .mms-chatrow{display:flex;gap:6px;margin-top:6px}
  .mms-chatrow input,.mms-chatrow textarea{flex:1;min-width:0;background:#0a0c08;border:1px solid var(--line);border-radius:8px;
    color:var(--text);padding:7px 9px;font-size:13px}
  .mms-chatrow .btn{padding:5px 11px;font-size:12px}
  /* left rail: changelog / "what's new". Mirrors the right rail. */
  #mmNews{display:none;position:absolute;z-index:2;top:88px;left:0;bottom:0;width:300px;
    flex-direction:column;gap:14px;padding:16px 14px 20px;overflow-y:auto;
    background:linear-gradient(180deg,#0a0b14cc,#070810ee);border-right:1px solid var(--line);
    box-shadow:8px 0 26px #0006;animation:mmIn .5s ease both}
  .news-item{padding:7px 9px;border-radius:8px;background:#ffffff08}
  .news-date{font-size:11px;color:var(--gold2);font-weight:700;letter-spacing:.04em;margin-bottom:4px}
  .news-item ul{margin:0;padding-left:15px;display:flex;flex-direction:column;gap:4px}
  .news-item li{font-size:12.5px;color:var(--text);line-height:1.35}
  /* announcements: like a news item but accented (gold left bar) and the body is free text */
  .ann-item{background:#caa84a14;box-shadow:inset 2px 0 0 var(--gold2)}
  .ann-title{font-size:13px;font-weight:700;color:var(--gold2);margin-bottom:3px}
  .ann-body{font-size:12.5px;color:var(--text);line-height:1.4;white-space:pre-line}
  .ann-when{font-size:10px;color:#8a8a78;margin-top:5px;letter-spacing:.03em}
  /* The rails are pure overlays (no layout push) so the menu panel stays centered. Only show them where
     they clear a 520px-wide centered panel: right rail ≥1180px, both rails ≥1200px. */
  @media(min-width:1180px){ #mmSide{display:flex} }
  @media(min-width:1200px){ #mmNews{display:flex} }
  /* On the menu, park the floating Audio widget (injected by music.js, bottom-left by default) just to the
     right of the "What's new" rail so it no longer overlaps it. Only where that rail shows (≥1200px). */
  @media(min-width:1200px){ body.atmenu #audioWidget{left:312px} }
  /* ---- mobile menu: the rails don't fit, so surface them as fullscreen panels via a button row ---- */
  .mm-mob{display:none}
  @media (max-width:1179px){
    .mm-mob{position:relative;z-index:2;display:grid;grid-template-columns:1fr 1fr;gap:10px;
      width:min(86vw,330px);margin-top:20px;animation:mmIn .5s ease both}
  }
  .mm-mobbtn{font:inherit;font-size:14px;font-weight:600;color:var(--text);cursor:pointer;
    padding:12px 10px;border-radius:11px;border:1px solid var(--line);
    background:linear-gradient(180deg,#ffffff12,#ffffff06);backdrop-filter:blur(2px);
    transition:border-color .15s ease,background .15s ease}
  .mm-mobbtn:hover,.mm-mobbtn:active{border-color:var(--gold);background:#ffffff18}
  /* fullscreen host for one rail section at a time (z-index > the menu's 80 and the menu-launched modals' 90) */
  #mmFs{display:none;position:fixed;inset:0;z-index:95;background:#070810;
    flex-direction:column;padding:max(10px,env(safe-area-inset-top)) max(14px,env(safe-area-inset-right)) 14px max(14px,env(safe-area-inset-left))}
  #mmFs.show{display:flex}
  .mmfs-head{display:flex;align-items:center;gap:12px;padding:4px 2px 12px;border-bottom:1px solid var(--line)}
  .mmfs-back{display:inline-flex;align-items:center;gap:6px;font:inherit;font-size:15px;font-weight:600;
    color:var(--text);cursor:pointer;border:1px solid var(--line);background:#ffffff10;border-radius:10px;padding:8px 13px}
  .mmfs-back:hover,.mmfs-back:active{border-color:var(--gold);background:#ffffff1c}
  .mmfs-back .bico{width:18px;height:18px}
  .mmfs-title{font-size:17px;font-weight:700;color:var(--gold2);letter-spacing:.02em}
  .mmfs-body{flex:1;min-height:0;display:flex;flex-direction:column;overflow:hidden;padding-top:12px}
  /* the moved rail section fills the panel; its inner list/chat scrolls, and its own header is redundant */
  #mmFs .mms-sec{flex:1;min-height:0;gap:9px}
  #mmFs .mms-h{display:none}
  #mmFs .mms-h.ann-h{display:block}   /* keep the Announcements label in the fullscreen What's-new panel */
  #mmFs .mms-list{flex:1;min-height:0;overflow-y:auto}
  #mmFs .mms-row{font-size:15px;padding:9px 11px}
  #mmFs .mms-chatlog{flex:1;height:auto;min-height:0}
  #mmFs .mms-chatlog .cm{font-size:15px}
  #mmFs .mms-chatrow{margin-top:10px}
  #mmFs .mms-chatrow input,#mmFs .mms-chatrow textarea{font-size:15px;padding:10px 11px}
  #mmFs .news-item li{font-size:14px}
  /* deck-builder overlay (iframe) — sits above the menu (80) but below the music widget (86) so the
     music control stays reachable; no navigation = fullscreen + music persist */
  #builderOverlay,#collectionOverlay,#companionOverlay{position:fixed;inset:0;z-index:84;display:none;background:#05060c}
  #builderOverlay.show,#collectionOverlay.show,#companionOverlay.show{display:block}
  /* Admin opens as a full-screen, page-like overlay (roomy) rather than a cramped modal. It lives in the
     main page, so music keeps playing and presence/online status stay live — same as the builder/binder. */
  #adminmodal{padding:0;align-items:stretch;background:var(--bg);background-size:cover;background-position:center}   /* wallpaper set in openAdmin() */
  #adminmodal>.panel2{width:100%;max-width:none;height:100%;border:none;border-radius:0;padding:0;gap:0;
    background:transparent;box-shadow:none;align-items:stretch;overflow:auto}
  #adminmodal .admin-page{width:100%;max-width:1040px;margin:0 auto;box-sizing:border-box;
    padding:16px clamp(14px,4vw,40px) 48px;display:flex;flex-direction:column;gap:12px}
  #adminmodal .prof-topbar{position:sticky;top:0;z-index:2;
    background:rgba(6,8,14,.5);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);
    padding:11px 0;border-bottom:1px solid var(--line)}
  #adminmodal .prof-scroll{max-height:none;overflow:visible}   /* the whole page scrolls, not an inner box */
  /* now that admin is a full-width page, let its text fields use the room (the default .nameinp is 8.5em) */
  #adminmodal #adminAnnTitle,#adminmodal #adminAnnBody{width:100%;box-sizing:border-box}
  #adminmodal #adminAnnBody{min-height:120px}
  #builderFrame,#collectionFrame,#companionFrame{width:100%;height:100%;border:0;display:block}
  /* opponent-disconnected banner (top-center, during a match) */
  #dcBanner{position:fixed;top:max(10px,env(safe-area-inset-top));left:50%;transform:translateX(-50%);z-index:86;display:none;
    background:linear-gradient(160deg,#3a2418,#1c1410);border:1px solid #c98b4a;border-radius:11px;padding:9px 16px;
    color:#f3d8b8;font-size:13px;font-weight:600;box-shadow:0 8px 26px #000a;max-width:92vw;text-align:center}
  #dcBanner.show{display:block}
  #dcBanner b{color:#ffce8a}
  /* away-forfeit banner: shown when you leave a live AI match sitting in the menu/binder. z-index above the
     builder/collection iframes (84) and the music widget (86) so it's visible everywhere you browse. */
  #awayBanner{position:fixed;top:max(10px,env(safe-area-inset-top));left:50%;transform:translateX(-50%);z-index:200;display:none;
    align-items:center;gap:12px;background:linear-gradient(160deg,#2c2a16,#161410);border:1px solid #c9b04a;border-radius:11px;
    padding:8px 10px 8px 16px;color:#efe6c2;font-size:13px;font-weight:600;box-shadow:0 8px 26px #000a;max-width:94vw}
  #awayBanner.show{display:flex}
  #awayBanner b.awt{color:#ffe58a;font-variant-numeric:tabular-nums;font-size:14px}
  #awayBanner.urgent{border-color:#e06a6a;background:linear-gradient(160deg,#33191a,#1a1210)}
  #awayBanner.urgent b.awt{color:#ff9e9e}
  #awayBanner .btn{padding:5px 10px;font-size:12px}
  /* Scheduled-maintenance notice (nightly card-DB update). In a game it toasts (fades after 5s, returns
     every 15 min, hideable via ✕); on the main menu it sits quietly (.persist) for the whole window.
     Anchored bottom-center so it never collides with the top bars / menu chrome that vary per page. */
  #maintNote{position:fixed;bottom:max(16px,calc(env(safe-area-inset-bottom) + 14px));left:50%;transform:translateX(-50%);
    z-index:201;display:none;align-items:center;gap:10px;max-width:min(92vw,560px);
    padding:9px 12px 9px 13px;border-radius:11px;font-size:13px;line-height:1.35;
    background:linear-gradient(160deg,#1d2340,#141a2e);border:1px solid #6f7fd6aa;color:#e2e6ff;
    box-shadow:0 10px 30px #0009;opacity:0;transition:opacity .5s ease}
  #maintNote.show{display:flex;opacity:1}
  #maintNote.fading{opacity:0}
  #maintNote.scanning{background:linear-gradient(160deg,#1f3020,#132010);border-color:#7fc06aaa;color:#e7ffdb}
  #maintNote .mn-ico{font-size:16px;flex:0 0 auto}
  #maintNote .mn-msg b.mn-t{color:#ffe58a;font-variant-numeric:tabular-nums;font-weight:700}
  #maintNote.scanning .mn-msg b.mn-t{color:#c1f0a2}
  #maintNote .mn-x{flex:0 0 auto;background:#0004;border:1px solid #ffffff33;color:#cfd4ff;border-radius:7px;
    padding:3px 8px;cursor:pointer;font-size:12px;line-height:1;font-family:inherit}
  #maintNote .mn-x:hover{border-color:#ffffff66}
  #maintNote.persist .mn-x{display:none}   /* menu mode: no hide button — it just stays out of the way */
  @media(prefers-reduced-motion:reduce){ #maintNote{transition:none} }
  .mm-acct>span:last-child{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .av{flex:0 0 auto;width:24px;height:24px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;
    font-size:12px;font-weight:800;color:#0a0b18;background:var(--gold2);overflow:hidden}
  .av img{width:100%;height:100%;object-fit:cover}
  #leaderboardmodal,#onlinemodal{z-index:90}   /* opened FROM the main menu (z-index 80) */
  .profpanel{gap:14px;min-width:min(92vw,420px);max-width:min(94vw,460px)}
  .prof-scroll{display:flex;flex-direction:column;gap:14px;width:100%;max-height:min(52vh,420px);overflow:auto;padding-right:4px}
  /* PROFILE AS A FULL PAGE (not a popup) — fills the viewport and scrolls as a whole, so everything fits. */
  #profilemodal{z-index:90;align-items:flex-start;justify-content:center;padding:0;overflow-y:auto;
    background:radial-gradient(120% 90% at 50% -10%,#241f16 0%,#15120e 55%,#0d0b08 100%)}
  #profilemodal .profpanel{background:none;border:none;border-radius:0;box-shadow:none;padding:0;
    width:100%;min-width:0;max-width:860px;min-height:100%;gap:18px;align-items:stretch;
    padding:max(18px,env(safe-area-inset-top)) max(18px,env(safe-area-inset-right)) 28px max(18px,env(safe-area-inset-left))}
  #profilemodal .prof-topbar{display:flex;align-items:center;justify-content:space-between;gap:12px}
  #profilemodal .prof-topbar h2{margin:0;font-size:20px;color:var(--text);letter-spacing:.02em}
  #profilemodal .prof-head{align-self:center;width:100%;max-width:560px}
  #profilemodal .prof-rank{justify-content:flex-start}
  #profilemodal .prof-scroll{max-height:none;overflow:visible;gap:18px}   /* let the PAGE scroll, not an inner box */
  #profilemodal .row2{flex-wrap:wrap}
  @media (min-width:720px){
    #profilemodal .badges{gap:10px}
    #profilemodal .prof-sec{background:#ffffff06;border:1px solid var(--line);border-radius:14px;padding:14px 16px}
  }
  .prof-rank{display:flex;flex-wrap:wrap;gap:8px;justify-content:center;font-size:13px;color:var(--text)}
  .prof-rank .chip{background:#ffffff12;border:1px solid var(--line);border-radius:99px;padding:3px 11px}
  .prof-rank .chip b{color:var(--gold2)}
  /* the leading rank chip: emblem left of the tier name, vertically centred */
  .prof-rank .rankchip{display:inline-flex;align-items:center;gap:5px}
  .prof-rank .rankchip .rankbadge{width:1.5em;height:1.5em;margin:0;vertical-align:middle}
  .prof-sec{display:flex;flex-direction:column;gap:7px;width:100%}
  /* vs-Players W/L/D/rate summary: a compact centred 4-tile band (same tile size as the detailed grid
     below, rather than stretching across the full ~860px panel) so it reads as a tidy KPI row. */
  #profWlSec .dgrid{max-width:520px;margin:0 auto;width:100%}
  #profWlSec .dstat{align-items:center;text-align:center}
  /* detailed vs-Players stats */
  .dgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(104px,1fr));gap:8px}
  .dstat{background:#ffffff08;border:1px solid var(--line);border-radius:11px;padding:9px 11px;display:flex;flex-direction:column;gap:2px}
  .dstat b{font-size:19px;color:var(--gold2);font-weight:700;line-height:1.05}
  .dstat b small{font-size:11px;color:var(--muted);font-weight:600}
  .dstat span{font-size:11px;color:var(--muted);line-height:1.2}
  .dstat span i{opacity:.65;font-style:normal}
  .dstyle{background:#ffffff08;border:1px solid var(--line);border-radius:11px;padding:8px 12px;font-size:13px;margin-top:8px}
  .dsub{margin-top:10px;font-size:12px;color:var(--gold2);opacity:.9}
  .eloseg{display:inline-flex;border:1px solid var(--line);border-radius:7px;overflow:hidden;text-transform:none;letter-spacing:0}
  .eloseg button{background:transparent;border:0;color:var(--muted);font:600 10px/1 inherit;padding:4px 9px;cursor:pointer}
  .eloseg button:not(:last-child){border-right:1px solid var(--line)}
  .eloseg button.on{background:#ffffff14;color:var(--gold2)}
  .cbar{display:flex;height:16px;border-radius:8px;overflow:hidden;border:1px solid var(--line)}
  .cbar span{display:block;min-width:3px}
  .badges{display:flex;flex-wrap:wrap;gap:8px}
  .badge{display:flex;align-items:center;gap:7px;background:#ffffff10;border:1px solid var(--line);border-radius:10px;padding:5px 9px;font-size:12px}
  .badge .bi{font-size:17px;line-height:1}
  .badge.locked{opacity:.38;filter:grayscale(1)}
  .badge b{color:var(--gold2);font-weight:600}
  .badge{cursor:help}
  /* achievement hover/tap box */
  #achTip{position:fixed;z-index:9999;display:none;pointer-events:none;max-width:240px;   /* topmost: shows over the profile + public-profile modals */
    background:linear-gradient(160deg,#221d16,#14110d);border:1px solid var(--gold);border-radius:10px;
    padding:9px 12px;box-shadow:0 10px 30px #000b;font-size:12px;color:var(--text)}
  #achTip.show{display:block}
  #achTip b{color:var(--gold2);font-size:13px}
  #achTip .how{margin-top:4px;color:#cfc7b5}
  #achTip .won{margin-top:5px;color:#9fe0a0;font-weight:600}
  #achTip .lk{margin-top:5px;color:#8a8a78}
  .declist{display:flex;flex-direction:column;gap:6px;width:100%}
  .drow{display:flex;align-items:center;gap:10px;background:#ffffff0a;border:1px solid var(--line);border-radius:9px;padding:7px 11px;font-size:13px}
  .drow .dn{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:flex;align-items:center;gap:8px}
  .drow .rec{color:#9a9286;font-variant-numeric:tabular-nums}
  .drow .wr{color:var(--gold2);font-weight:700;min-width:42px;text-align:right}
  .drow .rk{color:var(--gold2);font-weight:700;min-width:22px;text-align:right}
  .drow .av{width:22px;height:22px}
  .drow.me{border-color:var(--gold);background:#ffffff14}
  .prof-empty{color:#8a8a78;font-size:12px;font-style:italic}
  /* playmat / table-look picker (profile): an "Auto" chip + one swatch per mat color */
  .matpick{display:flex;flex-wrap:wrap;gap:8px;align-items:center;justify-content:center}
  .matsw{width:34px;height:34px;border-radius:9px;border:2px solid var(--line);cursor:pointer;padding:0;
    transition:transform .12s,border-color .12s,box-shadow .12s}
  .matsw:hover{transform:translateY(-1px)}
  .matsw.auto{width:auto;height:34px;padding:0 13px;font-size:12px;font-weight:700;letter-spacing:.04em;color:#12121a;
    background:conic-gradient(from 210deg,#f0dcab,#3f8fd6,#9a78ff,#d9573c,#46a85f,#f0dcab)}
  .matsw.active{border-color:var(--gold2);box-shadow:0 0 0 2px var(--gold2)}
  /* spectate: hide every player-action control (they'd POST as the watched seat) + the in-game banner */
  body.spectating #surrenderBtn, body.spectating #yieldBtn, body.spectating #dmgToggle,
  body.spectating #stepToggle, body.spectating #passAllToggle, body.spectating #menuToggle,
  body.spectating #chatbox, body.spectating #logExpand, body.spectating #bugBtn,
  body.spectating #chatBtn, body.spectating #chatToast{display:none!important}
  #specBanner{position:fixed;top:8px;left:50%;transform:translateX(-50%);z-index:60;display:none;align-items:center;gap:12px;
    padding:7px 8px 7px 14px;border-radius:12px;background:rgba(8,10,18,.82);border:1px solid var(--line);
    backdrop-filter:blur(6px);color:var(--text);font-size:13px;box-shadow:0 6px 22px #0009;max-width:94vw}
  #specBanner.show{display:flex}
  #specBanner .spec-eye{color:var(--gold2);font-weight:700;white-space:nowrap}
  #specBanner #specWho{font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  #specBanner .btn{padding:5px 12px}
  .spec-list{display:flex;flex-direction:column;gap:8px;max-height:60vh;overflow:auto}
  .spec-row{display:flex;align-items:center;gap:12px;padding:10px 12px;border:1px solid var(--line);border-radius:10px;background:#ffffff06}
  .spec-vs{flex:1;min-width:0}
  .spec-names{font-weight:700;color:var(--gold2);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .spec-meta{font-size:12px;color:#9c9a8c}
  .spec-empty{color:#8a8a78;font-size:13px;font-style:italic;padding:14px 4px}
  .spec-toggle{display:flex;align-items:center;gap:8px;font-size:13px;cursor:pointer}
  .chalbtn{font:inherit;font-size:12px;font-weight:600;color:#0a0b18;background:var(--gold2);border:none;border-radius:7px;padding:5px 11px;cursor:pointer}
  /* clickable leaderboard / online rows → open a player's public profile */
  .clickrow{cursor:pointer;transition:background .12s ease,border-color .12s ease}
  .mms-row.clickrow:hover{background:#ffffff16}
  .drow.clickrow:hover{border-color:var(--gold);background:#ffffff12}
  /* public profile modal (base prof-topbar so it isn't only styled inside #profilemodal) */
  .prof-topbar{display:flex;align-items:center;justify-content:space-between;gap:12px}
  .prof-topbar h2{margin:0;font-size:20px;color:var(--text);letter-spacing:.02em}
  .pp-name{font-size:20px;font-weight:700;color:var(--text)}
  #ppStats{display:flex;flex-direction:column;gap:7px;align-items:center;text-align:center}
  .pp-wl{display:flex;flex-direction:column;align-items:center;gap:1px}
  .pp-big{font-size:34px;font-weight:800;color:var(--gold2);line-height:1}
  .pp-sub{font-size:11px;letter-spacing:.12em;text-transform:uppercase;color:var(--muted)}
  .pp-line{font-size:14px;color:var(--text)} .pp-line b{color:var(--gold2)}
  .pp-muted{color:var(--muted);font-size:12px}
  /* public "Paper collection" button on someone's profile + the read-only binder it opens */
  .pp-collbtn{align-self:center;display:inline-flex;align-items:center;gap:8px}
  .pp-collbtn .pc-n{color:var(--muted);font-weight:400;font-size:12px}
  /* public collection: full-bleed iframe of collection.html in read-only (?user=) mode */
  #pubcoll{padding:0;align-items:stretch;justify-content:stretch;backdrop-filter:none}
  #pubcollFrame{width:100%;height:100%;border:0;display:block;background:var(--bg)}
  #pubcollBack{position:absolute;top:10px;right:12px;z-index:2}
  #pcGrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(112px,1fr));gap:12px;overflow-y:auto;padding:4px 2px}
  .pc-tile{position:relative;border-radius:9px;overflow:hidden;background:#0a0c18;aspect-ratio:63/88;box-shadow:0 3px 10px #0007;cursor:zoom-in}
  .pc-tile img{width:100%;height:100%;object-fit:cover;display:block}
  .pc-tile .nm{display:none;position:absolute;inset:0;align-items:center;justify-content:center;text-align:center;
    padding:6px;font-size:11px;color:var(--text);background:#12131f}
  .pc-tile .qty{position:absolute;right:5px;bottom:5px;background:#0a0c18d8;color:var(--gold2);font-weight:800;
    font-size:12px;border-radius:6px;padding:2px 6px;line-height:1}
  .pc-tile .foiltag{position:absolute;left:5px;top:5px;font-size:13px;text-shadow:0 0 4px #000}
  .pc-tile .rar{position:absolute;top:6px;right:6px;width:11px;height:11px;border-radius:50%;border:1px solid #000;box-shadow:0 0 5px #000}
  .pc-tile .rar.COMMON{background:#2b2b2b}.pc-tile .rar.UNCOMMON{background:#9fb6c4}
  .pc-tile .rar.RARE{background:#d9bb62}.pc-tile .rar.MYTHIC{background:#df6a23}
  .pc-empty{color:var(--muted);text-align:center;padding:26px 8px;font-size:14px}
  /* while the public collection modal (z-98) is open, lift the shared hover/zoom card reader above it */
  body.pcopen #preview{z-index:9994} body.pcopen #zoom{z-index:9996} body.pcopen #zoomFlip{z-index:9997}
  .chalbtn:hover{filter:brightness(1.1)}
  .chalbtn.sent{background:#ffffff20;color:var(--text);cursor:default}
  .drow .inmatch{font-size:12px;font-weight:600;color:#d9b35a;white-space:nowrap;opacity:.9}
  /* incoming-challenge toast (bottom-center of the menu) */
  #chalToast{position:fixed;left:50%;bottom:max(18px,env(safe-area-inset-bottom));transform:translateX(-50%);z-index:95;
    display:none;align-items:center;gap:12px;background:linear-gradient(160deg,#241f16,#15120e);border:1px solid var(--gold);
    border-radius:13px;padding:11px 15px;box-shadow:0 10px 34px #000a;max-width:92vw}
  #chalToast.show{display:flex}
  #chalToast .ct-t{font-size:14px;color:var(--text)}
  #chalToast .ct-t b{color:var(--gold2)}
  .prof-head{display:flex;align-items:center;gap:14px}
  .prof-ava{flex:0 0 auto;width:56px;height:56px;border-radius:50%;display:flex;align-items:center;justify-content:center;
    font-size:24px;font-weight:800;color:#0a0b18;background:var(--gold2);overflow:hidden}
  .prof-ava img{width:100%;height:100%;object-fit:cover}
  .prof-head .nameinp{flex:1}
  .ps-h{font-size:11px;letter-spacing:.16em;text-transform:uppercase;color:var(--gold2);margin-bottom:6px;text-align:center}
  @media (prefers-reduced-motion: reduce){   /* respect the OS "reduce motion" setting */
    #mmBgImg.kb,.mm-rune,.mm-title,.mm-logo,.mm-btn:not(.soon):hover::after,.mm-panel{animation:none}
    .mm-title{-webkit-text-fill-color:var(--text)}.mm-title .mc{-webkit-text-fill-color:var(--gold2)}
    #mmBg{transition:none}
  }
