/* ============ PREMIUM PASS ============ */
/* bigger, poppier cards (MTG Arena-ish); scale down only on small phones */
:root{--card-w:132px;--card-h:184px}
@media(max-width:900px){:root{--card-w:112px;--card-h:156px}}
@media(max-width:600px){:root{--card-w:96px;--card-h:134px}}

/* real card scans fill the whole frame */
.card.realart{background:#0a121c}
.card.realart .fullart{position:absolute;inset:0}
.card.realart .fullart img{width:100%;height:100%;object-fit:cover;border-radius:8px}
.card.realart .power.live{position:absolute;bottom:3px;left:5px;font-family:var(--font-display);font-size:21px;color:#fff;
  text-shadow:0 0 6px #000,0 0 12px var(--frame),0 2px 2px #000;z-index:3;
  background:rgba(6,12,20,.55);padding:0 6px;border-radius:6px}
.card .power.live .buff{color:var(--don)}

/* leader cards slightly bigger on the board */
#myLeaderWrap .card,#oppLeaderWrap .card{width:calc(var(--card-w)*.92);height:calc(var(--card-h)*.92)}

/* ============ HOVER PREVIEW (MTG-Arena-style enlarge on mouseover) ============
   A single large clone renders in a fixed layer, position clamped to the
   viewport so it never clips at screen edges — the in-place hover lift
   above stays subtle instead of scaling (which was the clipping culprit). */
#hoverPreview{position:fixed;z-index:97;pointer-events:none;opacity:0;transform:scale(.82);
  transition:opacity .1s ease,transform .12s ease;transform-origin:top left;
  display:flex;align-items:flex-start;gap:14px}
#hoverPreview.on{opacity:1;transform:scale(1)}
#hoverPreview.flip{flex-direction:row-reverse}
#hoverPreview .card{width:252px;height:352px;pointer-events:none;flex-shrink:0;
  box-shadow:0 0 0 3px var(--gold),0 34px 70px rgba(0,0,0,.75),0 0 46px rgba(233,180,76,.4)}
#hoverPreview .card .name{font-size:14px}
#hoverPreview .card .power{font-size:30px}
#hoverPreview .card .power.live{font-size:30px}
#hoverPreview .card .cost{width:38px;height:38px;font-size:20px}
#hoverPreview .card .tag{font-size:11px;padding:3px 7px}
#hoverPreview .card .counter{font-size:12px;padding:2px 10px}
#hoverPreview .card .rar{font-size:10px}
.hp-rules{width:230px;background:linear-gradient(180deg,rgba(18,42,61,.97),rgba(11,28,43,.97));
  border:1px solid var(--gold-deep);border-radius:12px;padding:14px 16px;margin-top:6px;
  box-shadow:0 20px 50px rgba(0,0,0,.6)}
.hp-rules b{font-family:var(--font-display);font-size:19px;color:var(--heading);display:block;line-height:1.15}
.hp-rules .hp-meta{display:block;font-size:11px;color:var(--parchment-dim);margin:3px 0 8px}
.hp-rules .hp-kw{display:flex;flex-wrap:wrap;gap:5px;margin-bottom:8px;font-size:11.5px}
.hp-rules p{font-size:11.5px;line-height:1.45;color:var(--parchment)}
.hp-rules p .kw{color:var(--heading);font-weight:800}
/* Touch devices get this panel too now — it's what long-press opens, so it
   may only be hidden while inactive (it used to be display:none outright,
   which is why long-press had to fall back to the old full-screen modal).
   Its desktop layout is card + rules side by side at ~496px, which simply
   does not fit a phone; on touch it becomes a centred, viewport-fitted
   column instead of overflowing off the right edge. */
@media(hover:none),(pointer:coarse){
  #hoverPreview{display:none}
  #hoverPreview.on{display:flex}
}
/* The compact layout keys off WIDTH, not pointer type: a narrow desktop
   window overflows exactly the same way a phone does, and emulated/resized
   browsers still report pointer:fine, so a coarse-pointer-only rule silently
   fails to apply where it's needed most. */
@media(max-width:560px){
  #hoverPreview.on{flex-direction:column;align-items:center;gap:8px;
    left:50%!important;top:50%!important;transform:translate(-50%,-50%) scale(1);
    width:max-content;max-width:94vw;max-height:92vh;overflow:auto}
  #hoverPreview.on .card{width:min(58vw,252px);height:auto;aspect-ratio:5/7}
  #hoverPreview.on .hp-rules{width:min(86vw,300px)}
  /* Dim the page behind so the preview reads as a focused inspect view. */
  #hoverPreview.on::before{content:"";position:fixed;inset:0;z-index:-1;background:rgba(0,0,0,.55)}
}

/* Rare-and-up info boxes get a metal-tier gradient BORDER, escalating
   silver → platinum → gold → diamond; the rarest tiers also get a glow.

   The panel fill MUST stay var(--surface): the two-layer background-clip
   trick paints layer 1 over the padding box and layer 2 (the metal gradient)
   only in the border. Layer 1 was previously a hardcoded dark navy, which
   beat the light themes' `.hp-rules{background:var(--surface)}` on
   specificity — so on the white Manga/Wave skins a rare card's box rendered
   near-black while the theme kept its text dark, which read as a broken /
   half-loaded panel. Never hardcode a fill colour here. */
.hp-rules{position:relative;overflow:hidden}
/* Three background layers: a faint diagonal weave TEXTURE, the theme fill,
   and the metal gradient. The first two are clipped to the padding box, the
   third to the border box — that's what paints the gradient border. The
   texture is tinted with the tier colour (never a flat white), so it reads as
   material on both the light and dark skins. */
.hp-rules[class*="rar-"]{border:2px solid transparent;background-origin:border-box;
  background-clip:padding-box,padding-box,border-box;
  background-image:
    repeating-linear-gradient(135deg,var(--rar-tex) 0 1px,transparent 1px 6px),
    linear-gradient(var(--surface),var(--surface)),
    var(--rar-grad)}
/* Two independent particle layers drifting at different speeds and
   directions — the parallax is what sells "floating motes" rather than a
   flat blinking dot pattern. Both ride the tier colour. */
.hp-rules[class*="rar-"]::before,.hp-rules[class*="rar-"]::after{
  content:"";position:absolute;inset:-12% -4%;border-radius:inherit;pointer-events:none;z-index:0}
.hp-rules[class*="rar-"]::before{
  background-image:
    radial-gradient(circle at 14% 26%,var(--rar-spark) 0 1.6px,transparent 2.6px),
    radial-gradient(circle at 63% 12%,var(--rar-spark) 0 1.2px,transparent 2.2px),
    radial-gradient(circle at 86% 58%,var(--rar-spark) 0 1.5px,transparent 2.5px),
    radial-gradient(circle at 34% 78%,var(--rar-spark) 0 1.1px,transparent 2.1px);
  animation:rarfloatA 7s ease-in-out infinite}
.hp-rules[class*="rar-"]::after{
  background-image:
    radial-gradient(circle at 44% 40%,var(--rar-spark) 0 1px,transparent 2px),
    radial-gradient(circle at 74% 84%,var(--rar-spark) 0 1.3px,transparent 2.3px),
    radial-gradient(circle at 22% 56%,var(--rar-spark) 0 .9px,transparent 1.9px);
  animation:rarfloatB 5.2s ease-in-out infinite}
/* Lift content above the particle layers — but NOT the stamp, which is
   absolutely positioned in the corner. This rule previously matched it too
   and forced position:relative, collapsing it from 24px to a 4px border box
   (it vanished visually). Exclude it explicitly. */
.hp-rules[class*="rar-"] > *:not(.rarstamp){position:relative;z-index:1}
@keyframes rarfloatA{
  0%{transform:translate3d(0,6px,0);opacity:.25}
  50%{transform:translate3d(3px,-5px,0);opacity:.85}
  100%{transform:translate3d(-2px,-14px,0);opacity:.2}}
@keyframes rarfloatB{
  0%{transform:translate3d(0,-4px,0);opacity:.5}
  50%{transform:translate3d(-4px,5px,0);opacity:.15}
  100%{transform:translate3d(3px,12px,0);opacity:.45}}
.hp-rules.rar-silver{--rar-grad:linear-gradient(135deg,#eef1f4,#9aa3ad 45%,#eef1f4 70%,#7d868f);
  --rar-spark:rgba(154,163,173,.95);--rar-tex:rgba(154,163,173,.10);
  box-shadow:0 20px 50px rgba(0,0,0,.35),0 0 16px rgba(160,170,180,.45)}
.hp-rules.rar-platinum{--rar-grad:linear-gradient(135deg,#f4f8ff,#b9c6d6 40%,#e9f0fb 65%,#8fa0b3);
  --rar-spark:rgba(150,175,210,.95);--rar-tex:rgba(150,175,210,.11);
  box-shadow:0 20px 50px rgba(0,0,0,.35),0 0 26px rgba(150,175,210,.7)}
.hp-rules.rar-gold{--rar-grad:linear-gradient(135deg,#fff3c4,#e9b44c 40%,#fff6d8 65%,#a8790f);
  --rar-spark:rgba(233,180,76,.98);--rar-tex:rgba(233,180,76,.13);
  box-shadow:0 20px 50px rgba(0,0,0,.35),0 0 34px rgba(233,180,76,.8)}
.hp-rules.rar-diamond{--rar-grad:linear-gradient(135deg,#8fe6ff,#7adfff 25%,#ff9df5 50%,#c9a0ff 75%,#8fe6ff);
  --rar-spark:rgba(122,223,255,.98);--rar-tex:rgba(140,210,255,.13);
  background-size:auto,100% 100%,250% 250%;animation:diamondshift 3s ease-in-out infinite;
  box-shadow:0 20px 50px rgba(0,0,0,.35),0 0 48px rgba(140,210,255,.95)}
.hp-rules.rar-diamond::before{animation-duration:4.6s}
.hp-rules.rar-diamond::after{animation-duration:3.4s}
@keyframes diamondshift{0%,100%{background-position:0 0,0 0,0% 50%}50%{background-position:0 0,0 0,100% 50%}}
/* Manga/special art — the top tier, above diamond. Deliberately the only tier
   that is NOT a metal/gem gradient: ink-black and paper-white with a single
   red accent, quoting the manga page the art itself comes from. Reads instantly
   as "different kind of thing" rather than "one more shade of shiny", which is
   the point when it's a 1.5% pull. Faster shimmer + heaviest glow so it also
   wins on pure loudness next to a diamond panel. */
.hp-rules.rar-manga{--rar-grad:linear-gradient(135deg,#fff 0%,#f2f2f2 18%,#111 19%,#111 26%,#fff 27%,#fff 52%,#d1232a 53%,#d1232a 60%,#fff 61%,#fafafa 78%,#111 79%,#111 86%,#fff 87%);
  --rar-spark:rgba(209,35,42,.98);--rar-tex:rgba(17,17,17,.14);
  background-size:auto,100% 100%,300% 300%;animation:mangashift 2.4s ease-in-out infinite;
  box-shadow:0 20px 50px rgba(0,0,0,.45),0 0 54px rgba(209,35,42,.85),0 0 18px rgba(0,0,0,.9)}
.hp-rules.rar-manga::before{animation-duration:3.2s}
.hp-rules.rar-manga::after{animation-duration:2.2s}
@keyframes mangashift{0%,100%{background-position:0 0,0 0,0% 50%}50%{background-position:0 0,0 0,100% 50%}}

/* Rarity stamp: the real jolly-roger PNG used as a MASK, so the panel behind
   shows through the skull shape (a stencil / "Schablone" cutout) instead of
   a flat glyph sitting on top. The ring around it carries the tier colour. */
.rarstamp{position:absolute;right:8px;bottom:6px;width:24px;height:24px;border-radius:50%;
  border:2px solid var(--rar-stamp,#9aa3ad);background:var(--rar-stamp,#9aa3ad);opacity:.55;
  -webkit-mask:url('/assets/ui/jollyroger.png') center/62% no-repeat,linear-gradient(#000,#000);
  -webkit-mask-composite:xor;mask:url('/assets/ui/jollyroger.png') center/62% no-repeat,linear-gradient(#000,#000);
  mask-composite:exclude;font-size:0}
.rarstamp-silver{--rar-stamp:#9aa3ad}
.rarstamp-platinum{--rar-stamp:#8fa0b3}
.rarstamp-gold{--rar-stamp:#e9b44c;opacity:.75}
.rarstamp-diamond{--rar-stamp:#7adfff;opacity:.9;filter:drop-shadow(0 0 6px rgba(122,223,255,.9))}

/* ============ DON!! as mini cards ============
   Ready = shining gold face; rested = same face, dimmed + rotated (paid);
   locked = card-back silhouette for DON!! still in the deck (undrawn). */
.doncard{width:30px;height:42px;border-radius:5px;position:relative;flex-shrink:0;
  background:radial-gradient(circle at 35% 25%,#fff6d8,var(--don) 48%,var(--gold-deep));
  box-shadow:0 2px 6px rgba(0,0,0,.55),inset 0 0 0 1px rgba(255,255,255,.45);
  display:flex;align-items:center;justify-content:center;overflow:hidden;
  transition:transform .15s,filter .2s,box-shadow .15s}
.doncard .dsym{font-family:var(--font-display);font-size:9.5px;color:var(--ink);text-align:center;
  line-height:1;text-shadow:0 1px 0 rgba(255,255,255,.5);letter-spacing:-.02em}
.doncard.rested{transform:rotate(90deg) scale(.82);filter:brightness(.55) saturate(.6)}
.doncard.clickable{cursor:pointer;box-shadow:0 0 0 2px var(--emerald),0 0 10px rgba(63,169,124,.75),inset 0 0 0 1px rgba(255,255,255,.45)}
.doncard.clickable:hover{transform:scale(1.22);z-index:3}
.doncard.selected{box-shadow:0 0 0 3px #fff,0 0 16px #fff;transform:scale(1.22)}
.doncard.locked{background:linear-gradient(160deg,#16222f,#0a1420);
  box-shadow:0 2px 5px rgba(0,0,0,.5),inset 0 0 0 1px rgba(255,255,255,.08)}
.doncard.locked .backimg{width:100%;height:100%;object-fit:cover;opacity:.5;filter:grayscale(.4) brightness(.6)}
.doncard.locked .dsym{opacity:.3;color:#9fc6e0}
.dondeck-stack{position:relative;width:44px;height:42px;flex-shrink:0;margin-left:2px}
.dondeck-stack .doncard{position:absolute;top:0}
.dondeck-stack .doncard:nth-child(1){left:0;z-index:1}
.dondeck-stack .doncard:nth-child(2){left:5px;z-index:2}
.dondeck-stack .doncard:nth-child(3){left:10px;z-index:3}
.dondeck-count{position:absolute;bottom:-15px;left:0;right:0;text-align:center;font-size:10.5px;color:var(--parchment-dim);font-weight:700;white-space:nowrap}

/* ============ deck stacks (real card-back art) ============ */
.deckstack{position:relative;width:44px;height:60px;margin:0 auto}
.deckstack .card{position:absolute;top:0;left:0;width:36px!important;height:50px!important;pointer-events:none}
.deckstack .card:nth-child(1){top:6px;left:6px;z-index:1;opacity:.7}
.deckstack .card:nth-child(2){top:3px;left:3px;z-index:2;opacity:.88}
.deckstack .card:nth-child(3){top:0;left:0;z-index:3}
.deckstack-count{position:absolute;bottom:-16px;left:0;right:0;text-align:center;font-size:11px;font-weight:800;color:var(--parchment)}
.deckstack.empty{opacity:.3}

/* ============ midbar: floating, non-obscuring ============
   Individually-styled pills with the arena art visible between them,
   instead of one solid bar across the board's midline. */
#duel .midbar{background:transparent;border:none;box-shadow:none;backdrop-filter:none;padding:4px 6px;gap:10px}
.phase{background:linear-gradient(180deg,rgba(24,46,66,.62),rgba(9,18,28,.5));
  padding:6px 20px;border-radius:22px;box-shadow:0 4px 16px rgba(0,0,0,.4),inset 0 0 0 1px rgba(233,180,76,.3);
  backdrop-filter:blur(5px)}
#log{background:rgba(6,14,22,.42);border-radius:14px;padding:5px 16px;backdrop-filter:blur(5px);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.06)}
#duel .endturn{border-radius:26px;box-shadow:0 4px 0 #5c1620,0 6px 18px rgba(0,0,0,.4)}

/* activate button — bigger and self-labeling so it reads as "click me for
   an ability" at a glance, not just a mystery glowing dot */
/* The button box itself must NEVER be animated: it used to run an infinite
   scale(1.18) pulse, which made the hit target physically grow and shrink —
   clicks aimed near its edge landed outside it depending on the animation
   phase, so activating an ability took several tries. The pulse now lives on
   a ::before halo that is pointer-events:none, leaving a rock-steady target.
   z-index is also lifted above neighbouring cards, which could overlap it. */
.fxbtn{position:absolute;top:-10px;right:-10px;z-index:20;width:34px;height:34px;border-radius:50%;
  background:radial-gradient(circle at 35% 30%,#fff3c9,var(--don) 45%,var(--gold-deep));
  font-size:16px;box-shadow:0 0 12px rgba(242,193,78,.9),0 2px 4px rgba(0,0,0,.6);
  cursor:pointer;display:flex;align-items:center;justify-content:center;border:2px solid var(--ink)}
/* Generous invisible hit area — the visual stays 34px, the target is ~50px. */
.fxbtn::after{content:"";position:absolute;inset:-8px;border-radius:50%}
.fxbtn::before{content:"";position:absolute;inset:-3px;border-radius:50%;pointer-events:none;z-index:-1;
  box-shadow:0 0 12px rgba(242,193,78,.9);animation:fxpulse 1.1s ease-in-out infinite alternate}
.fxbtn:active{transform:scale(.94)}
@keyframes fxpulse{to{transform:scale(1.18);box-shadow:0 0 22px rgba(242,193,78,1)}}

/* duel board background (user-supplied arena art) */
#duel{position:relative;overflow:hidden}
#duelBg{position:absolute;inset:-3%;background-size:cover;background-position:center;z-index:-1;
  filter:saturate(.92) brightness(.8);animation:bgdrift 60s ease-in-out infinite alternate}
#duelBg::after{content:"";position:absolute;inset:0;background:radial-gradient(ellipse at 50% 50%,transparent 30%,rgba(6,16,26,.78) 100%)}
@keyframes bgdrift{from{transform:scale(1)}to{transform:scale(1.07) translateY(-1.5%)}}
#duel .hud,#duel .midbar{background:rgba(4,12,20,.66);backdrop-filter:blur(5px);border-radius:12px;border:1px solid rgba(35,65,90,.8)}
.boardshake{animation:boardshake .5s ease}
@keyframes boardshake{20%{transform:translate(-6px,3px)}40%{transform:translate(5px,-3px)}60%{transform:translate(-3px,2px)}80%{transform:translate(2px,-1px)}}

/* End Turn pulse when nothing else to do */
.endturn.pulse{animation:etpulse 1.6s ease-in-out infinite}
@keyframes etpulse{50%{box-shadow:0 3px 0 #5c1620,0 0 24px rgba(209,73,91,.9)}}

/* effect banner */
#fxBanner{position:absolute;top:38%;left:50%;transform:translate(-50%,-50%) scale(.7);z-index:45;
  display:flex;align-items:center;gap:14px;background:linear-gradient(90deg,rgba(6,14,24,0),rgba(6,14,24,.94) 18%,rgba(6,14,24,.94) 82%,rgba(6,14,24,0));
  padding:14px 46px;opacity:0;pointer-events:none;transition:opacity .25s,transform .25s}
/* Now stays up until dismissed (see showFxBanner) rather than auto-fading
   after 2.4s -- re-enable pointer events while visible so the close button
   and the card-hover zoom actually work. */
#fxBanner.on{opacity:1;transform:translate(-50%,-50%) scale(1);pointer-events:auto}
#fxBanner .fxb-card{--card-w:96px;--card-h:134px;width:96px;height:134px;flex-shrink:0;cursor:pointer}
#fxBanner .fxb-text{max-width:420px}
#fxBanner .fxb-text b{display:block;font-family:var(--font-display);font-size:22px;color:var(--heading)}
#fxBanner .fxb-text span{font-size:13px;color:var(--parchment)}
#fxBanner .fxb-close{position:absolute;top:6px;right:10px;background:none;border:none;color:var(--parchment-dim);
  font-size:16px;cursor:pointer;padding:4px;line-height:1;opacity:.7}
#fxBanner .fxb-close:hover{opacity:1;color:var(--crimson)}

/* choice modal */
.choicegrid{max-height:46vh;overflow-y:auto}
.choice-card{position:relative;cursor:pointer;border-radius:12px;padding:5px;transition:transform .12s}
.choice-card:hover{transform:translateY(-4px)}
.choice-card .card{pointer-events:none}
.choice-card.sel{outline:3px solid var(--emerald);box-shadow:0 0 22px rgba(63,169,124,.8);border-radius:12px}
.choice-card.ineligible{opacity:.35;filter:grayscale(.8)}
.choice-label{text-align:center;font-size:11px;color:var(--parchment-dim);margin-top:4px;max-width:var(--card-w)}

/* ============ VS INTRO (Hearthstone-style) ============ */
#vsIntro{position:fixed;inset:0;z-index:80;display:none;align-items:center;justify-content:center;gap:4vw;
  background:radial-gradient(ellipse at 50% 45%,#132c42 0%,#050d16 75%);overflow:hidden}
#vsIntro.open{display:flex}
#vsIntro::before{content:"";position:absolute;inset:-20%;pointer-events:none;
  background:repeating-conic-gradient(from 0deg,transparent 0 26deg,rgba(233,180,76,.06) 26deg 30deg);
  animation:raysspin 24s linear infinite}
@keyframes raysspin{to{transform:rotate(360deg)}}
/* Fixed equal width for both sides — without this, a longer leader name on
   one side makes that .vs-side render wider than the other, which pushes
   the "VS" glyph in the middle off the true visual center between the two
   portraits (it was only ever centered in the combined-content block, not
   symmetric to the cards). */
#vsIntro .vs-side{display:flex;flex-direction:column;align-items:center;gap:14px;z-index:2;flex:0 0 min(240px,34vw)}
#vsIntro .vs-side.left{animation:vsL .9s cubic-bezier(.2,1.4,.4,1) both}
#vsIntro .vs-side.right{animation:vsR .9s cubic-bezier(.2,1.4,.4,1) both;animation-delay:2.3s}
@keyframes vsL{from{transform:translateX(-120vw) rotate(-10deg)}60%{transform:translateX(3vw) rotate(2deg)}to{transform:none}}
@keyframes vsR{from{transform:translateX(120vw) rotate(10deg)}60%{transform:translateX(-3vw) rotate(-2deg)}to{transform:none}}
#vsIntro .vs-card{--card-w:min(240px,34vw);--card-h:calc(min(240px,34vw)*1.4);width:var(--card-w);height:var(--card-h);
  pointer-events:none;box-shadow:0 0 60px rgba(233,180,76,.35),0 30px 60px rgba(0,0,0,.7);animation:vsfloat 3s ease-in-out infinite alternate}
@keyframes vsfloat{from{transform:translateY(0) rotate(-1deg)}to{transform:translateY(-12px) rotate(1.5deg)}}
#vsIntro .vs-name{text-align:center}
#vsIntro .vs-its{display:block;font-family:var(--font-display);font-size:18px;letter-spacing:.4em;color:var(--parchment-dim)}
#vsIntro .vs-name b{display:block;font-family:var(--font-display);font-size:clamp(20px,3.4vw,38px);color:var(--heading);text-shadow:0 0 26px rgba(233,180,76,.6);max-width:36vw}
#vsIntro .vs-player{display:block;font-size:13px;color:var(--parchment-dim);margin-top:4px}
#vsIntro .vs-burst{font-family:var(--font-display);font-size:clamp(60px,10vw,130px);color:var(--crimson);z-index:3;
  text-shadow:0 0 40px rgba(209,73,91,.9),0 4px 0 #5c1620;animation:vsburst .6s cubic-bezier(.2,2,.4,1) both;animation-delay:2.9s}
@keyframes vsburst{from{transform:scale(4);opacity:0}to{transform:scale(1);opacity:1}}
#vsIntro.closing{animation:introfade .6s ease both}
@keyframes introfade{to{opacity:0;transform:scale(1.06)}}

/* ============ PACK OPENING v2 — real 3D object + tear-and-eruption ============
   The sealed pack is a genuine hinged CSS box (front/back/4 spines) instead
   of a flat card image — each spine face uses transform-origin at the shared
   edge plus a single rotate, so the geometry can't drift out of alignment.
   Tearing splits the "front" (two identical art copies, each clipped to a
   jagged half) apart along their shared seam; the card deal afterward erupts
   from that same point instead of just dropping in from above. */
#packstage{perspective:1200px;position:relative;min-height:320px}
.packwrap{position:relative;width:230px;height:330px;margin:10px auto;cursor:pointer}
.packwrap .tearhint{position:absolute;bottom:-34px;left:0;right:0;text-align:center;font-size:13px;color:var(--parchment-dim);animation:etpulse 2s infinite;z-index:5}
.pack3d{position:relative;width:100%;height:100%;transform-style:preserve-3d;
  --tiltx:0deg;--tilty:0deg;
  transform:rotateX(calc(4deg + var(--tiltx))) rotateY(calc(-8deg + var(--tilty)));
  animation:packfloat 4.2s ease-in-out infinite alternate;transition:transform .18s ease-out}
@keyframes packfloat{from{transform:rotateX(calc(2deg + var(--tiltx))) rotateY(calc(-10deg + var(--tilty))) translateY(0)}
  to{transform:rotateX(calc(6deg + var(--tiltx))) rotateY(calc(-4deg + var(--tilty))) translateY(-6px)}}
.packwrap:hover .pack3d{animation-play-state:paused}
.pack-face{position:absolute;border-radius:14px;box-shadow:0 18px 50px rgba(0,0,0,.6)}
.pack-face.back{inset:0;background:repeating-linear-gradient(135deg,var(--surface2) 0 10px,var(--surface) 10px 20px);
  border:3px solid var(--gold-deep);transform:translateZ(-13px) rotateY(180deg);display:flex;align-items:center;justify-content:center;overflow:hidden}
.pack-face.back .backpattern{position:absolute;inset:0;opacity:.12;
  background:radial-gradient(circle at 30% 30%,transparent 0 18px,var(--ink) 19px 20px,transparent 21px) 0 0/44px 44px}
.pack-face.back .backwordmark{font-family:var(--font-display);font-size:15px;letter-spacing:3px;color:var(--gold);opacity:.55;transform:rotate(-90deg)}
.pack-face.spine-l,.pack-face.spine-r{top:0;width:26px;height:100%;background:linear-gradient(90deg,var(--gold-deep),var(--surface2));border-radius:0}
.pack-face.spine-l{left:0;transform-origin:0 50%;transform:rotateY(-90deg)}
.pack-face.spine-r{right:0;transform-origin:100% 50%;transform:rotateY(90deg)}
.pack-face.top,.pack-face.bottom{left:0;width:100%;height:26px;background:linear-gradient(180deg,var(--gold-deep),var(--surface2));border-radius:0}
.pack-face.top{top:0;transform-origin:50% 0;transform:rotateX(90deg)}
.pack-face.bottom{bottom:0;transform-origin:50% 100%;transform:rotateX(-90deg)}
.tearhalf{position:absolute;inset:0;border-radius:14px;overflow:hidden;transform:translateZ(13px);
  background:linear-gradient(155deg,var(--surface2),var(--surface) 60%,var(--surface2));
  border:3px solid var(--gold-deep);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px}
.tearhalf::before{content:"";position:absolute;inset:0;background:linear-gradient(115deg,transparent 30%,rgba(255,255,255,.14) 48%,transparent 60%);
  background-size:250% 250%;animation:foilsweep 3.5s ease-in-out infinite;pointer-events:none}
.tearhalf .setname{font-family:var(--font-display);font-size:44px;color:var(--heading);text-shadow:0 0 20px rgba(233,180,76,.5)}
.tearhalf.top{clip-path:polygon(0 0,100% 0,100% 47%,86% 45%,74% 53%,61% 44%,48% 52%,35% 45%,22% 51%,0 46%)}
.tearhalf.bottom{clip-path:polygon(0 46%,22% 51%,35% 45%,48% 52%,61% 44%,74% 53%,86% 45%,100% 47%,100% 100%,0 100%)}
.tearhalf .packimg{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:1}
.tearhalf .packmeta{position:absolute;left:0;right:0;bottom:0;z-index:2;text-align:center;padding:10px}
.tearflash{position:absolute;left:0;right:0;top:44%;height:10%;transform:translateZ(14px);z-index:6;opacity:0;pointer-events:none;
  background:linear-gradient(180deg,transparent,rgba(255,246,216,.95),transparent);filter:blur(2px)}

/* Beat 1 — anticipation: a growing tremor plus a slow pre-glow at the seam,
   as if tension is building before the paper actually gives way. */
.pack3d.anticipating{animation:packanticipate .65s cubic-bezier(.4,0,.6,1) both}
@keyframes packanticipate{
  0%,100%{transform:rotate(0deg) scale(1)}
  12%{transform:rotate(-1deg) scale(1.004)}24%{transform:rotate(1deg) scale(1.004)}
  38%{transform:rotate(-1.6deg) scale(1.01)}52%{transform:rotate(1.6deg) scale(1.01)}
  67%{transform:rotate(-2.6deg) scale(1.018)}80%{transform:rotate(2.6deg) scale(1.018)}
  93%{transform:rotate(-3.2deg) scale(1.026)}}
.pack3d.anticipating .tearflash{animation:tearpreglow .65s ease-in both}
@keyframes tearpreglow{0%{opacity:0}55%{opacity:.3}100%{opacity:.55}}

/* Beat 2 — the seam gives way just a little and HOLDS there (no further
   motion for ~380ms): the anticipation peak, right before it fully rips. */
.pack3d.snapping .tearhalf.top{transition:transform .18s cubic-bezier(.3,0,.7,1);transform:translateZ(22px) translateY(-7%) rotate(-2.2deg)}
.pack3d.snapping .tearhalf.bottom{transition:transform .18s cubic-bezier(.3,0,.7,1);transform:translateZ(22px) translateY(7%) rotate(1.6deg)}
.pack3d.snapping .tearflash{opacity:.85;filter:blur(1.5px)}

/* Beat 3 — the full, slower rip (was .55s, now .85s — takes its time). */
.pack3d.ripping .tearflash{animation:tearflashpulse .85s ease-out both}
.pack3d.ripping{animation:ripshake .5s ease-out both}
@keyframes ripshake{0%{transform:rotateX(var(--tiltx,0deg)) rotateY(var(--tilty,0deg)) scale(1)}
  20%{transform:rotate(-2deg) scale(1.05)}45%{transform:rotate(2deg) scale(1.03)}to{transform:scale(1.02)}}
@keyframes tearflashpulse{0%{opacity:.55}30%{opacity:1}100%{opacity:0}}
.pack3d.ripping .tearhalf.top{transition:transform .85s cubic-bezier(.16,.7,.3,1),opacity .85s ease .2s;
  transform:translateZ(70px) translateY(-135%) rotateX(35deg) rotate(-16deg);opacity:0}
.pack3d.ripping .tearhalf.bottom{transition:transform .85s cubic-bezier(.16,.7,.3,1),opacity .85s ease .2s;
  transform:translateZ(70px) translateY(135%) rotateX(-35deg) rotate(11deg);opacity:0}

/* Beat 4 — settle before the cards appear. */
.packwrap.tearing{animation:packgone .4s ease-out .2s both}
@keyframes packgone{to{transform:scale(.7);opacity:0}}
.packrow{display:flex;flex-wrap:wrap;gap:14px;justify-content:center;padding:16px 0}
/* Card shell: NO transform/rotation lives on .pcard itself — the flip is
   handled entirely by the .pflip wrapper below. (An older single-element
   flip implementation used to rotate .pcard directly; it was superseded by
   the two-faced .pflip wrapper but never removed, so BOTH rotated the card
   at once — 180°(.pcard) + 180°(.pflip) + 180°(back's own) = 540° ≡ 180°,
   an uncancelled net rotation that showed the card back mirrored, or on some
   renders left the front face visibly bleeding through. Removed for good.) */
.pcard{position:relative}
.pcard.dealing{animation:dealout .62s cubic-bezier(.2,1,.35,1) both}
/* Erupt from the torn pack's position (--fx/--fr, tight spread — same point
   for every card) with a camera-ward overshoot at the midpoint, then settle
   into the flex row at --dx/--dr's gentler scatter. */
@keyframes dealout{
  0%{transform:translateY(90px) translateX(var(--fx,0)) rotate(var(--fr,0deg)) scale(.15);opacity:0;filter:brightness(2.2) blur(1px)}
  55%{transform:translateY(-46px) translateX(calc(var(--dx,0) * .5)) rotate(calc(var(--dr,0deg) * 1.6)) scale(1.18);opacity:1;filter:brightness(1.25)}
  100%{transform:translateY(0) translateX(0) rotate(0) scale(1);opacity:1;filter:none}}
.pcard.facedown{cursor:pointer}
.pcard.r-SR .facedown-back{border-color:#c9a0ff;box-shadow:0 0 24px rgba(155,91,209,.75);color:#c9a0ff}
.pcard.r-SEC .facedown-back,.pcard.r-SP .facedown-back{border-color:#ffd54a;box-shadow:0 0 34px rgba(255,213,74,.9);color:#ffd54a;animation:rareglow 1.2s ease-in-out infinite alternate}
.pcard.r-L .facedown-back{border-color:#7adfff;box-shadow:0 0 24px rgba(122,223,255,.75);color:#7adfff}
.pcard.r-R .facedown-back{border-color:#7ad7a8;box-shadow:0 0 18px rgba(63,169,124,.6);color:#7ad7a8}
@keyframes rareglow{to{box-shadow:0 0 60px rgba(255,213,74,1)}}
.pburst{position:absolute;left:50%;top:50%;width:8px;height:8px;border-radius:50%;pointer-events:none;z-index:9;
  animation:pburst .7s ease-out forwards}
@keyframes pburst{from{transform:translate(-50%,-50%) scale(1);opacity:1}to{transform:translate(calc(-50% + var(--bx)),calc(-50% + var(--by))) scale(.2);opacity:0}}

/* topbar / panels polish */
#topbar{background:linear-gradient(180deg,rgba(9,22,36,.97),rgba(6,16,26,.92));box-shadow:0 4px 24px rgba(0,0,0,.45)}
#topbar .brand{text-shadow:0 0 18px rgba(233,180,76,.45)}
.panel{box-shadow:0 10px 30px rgba(0,0,0,.35);border-radius:16px;background:linear-gradient(180deg,rgba(12,28,44,.55),rgba(4,12,20,.5))}
body{background-attachment:fixed}
/* menu background art if the user drops menu*.png into assets/backgrounds */
#menuBg{position:fixed;inset:0;z-index:-2;background-size:cover;background-position:center;opacity:.35;
  filter:saturate(.9);animation:bgdrift 90s ease-in-out infinite alternate}

/* tutorial coach */
#coach{position:fixed;z-index:90;max-width:min(400px,92vw);background:linear-gradient(180deg,var(--surface2),var(--surface));
  border:2px solid var(--gold);border-radius:14px;padding:16px 18px;box-shadow:0 16px 50px rgba(0,0,0,.7),0 0 30px rgba(233,180,76,.25);
  display:none;animation:enter .3s ease}
#coach.on{display:block}
#coach h4{font-family:var(--font-display);font-size:21px;color:var(--heading);margin-bottom:6px}
#coach p{font-size:13.5px;line-height:1.5}
#coach .coachbtns{display:flex;gap:8px;margin-top:12px;justify-content:flex-end}
.coach-target{outline:3px solid var(--gold)!important;outline-offset:3px;border-radius:10px;animation:coachpulse 1s ease-in-out infinite alternate;z-index:60;position:relative}
@keyframes coachpulse{to{outline-color:rgba(233,180,76,.35)}}

/* ============================================================
   MANGA THEME — structural pass (default skin)
   Thicker black outlines, sharper/edged corners, flatter "ink and
   halftone" shadows instead of soft glows — pirate-flag + shonen-manga
   graphic identity. Card-color frames (red/green/blue/purple/yellow/
   black) are untouched; this only restyles UI chrome.
   ============================================================ */
.btn{border:3px solid var(--ink);border-radius:6px;background:linear-gradient(180deg,var(--gold),var(--gold-deep));
  box-shadow:4px 4px 0 var(--ink),8px 8px 18px rgba(0,0,0,.4);color:#fff;text-shadow:0 1px 2px rgba(0,0,0,.4)}
.btn:hover{transform:translate(-2px,-2px);box-shadow:6px 6px 0 var(--ink),8px 8px 18px rgba(0,0,0,.4)}
.btn:active{transform:translate(1px,1px);box-shadow:2px 2px 0 var(--ink)}
.btn.ghost{background:transparent;color:var(--parchment);box-shadow:none;border:3px solid var(--parchment)}
.btn.ghost:hover{box-shadow:4px 4px 0 rgba(255,255,255,.25)}
.btn.danger{border-color:var(--ink);background:linear-gradient(180deg,var(--crimson),var(--crimson-deep));box-shadow:4px 4px 0 var(--ink),8px 8px 18px rgba(0,0,0,.4)}
.smallbtn{border:2px solid var(--ink);border-radius:5px;background:rgba(255,255,255,.08)}
.smallbtn:hover{background:rgba(255,255,255,.18)}
.panel{border:3px solid var(--ink)!important;border-radius:8px!important;background:var(--surface)!important;
  box-shadow:5px 5px 0 rgba(0,0,0,.35)!important}
#topbar{border-bottom:3px solid var(--ink);background:linear-gradient(180deg,var(--surface),var(--surface2))}
.modalbox{border:3px solid var(--ink);border-radius:10px;background:var(--surface);
  box-shadow:8px 8px 0 rgba(0,0,0,.35),0 20px 60px rgba(0,0,0,.45)}
input,select,textarea{border:2px solid var(--ink);border-radius:5px}
.toast{border:2px solid var(--ink);border-radius:6px;box-shadow:4px 4px 0 rgba(0,0,0,.5)}
.starteropt{border:3px solid var(--ink);border-radius:8px}
.starteropt:hover,.starteropt.sel{border-color:var(--heading);box-shadow:4px 4px 0 var(--ink)}
.deckcardrow{border:2px solid var(--ink);border-radius:6px}
.packwrap .packart{border:3px solid var(--ink);border-radius:10px;box-shadow:6px 6px 0 rgba(0,0,0,.55)}
.packbox{border:3px solid var(--ink);border-radius:8px}
.rankbadge{border:4px solid var(--ink);box-shadow:6px 6px 0 rgba(0,0,0,.5)}
.doncoin,.doncard{box-shadow:0 0 0 2px var(--ink),0 2px 5px rgba(0,0,0,.55)}
#vsIntro .vs-card,#hoverPreview .card{box-shadow:0 0 0 4px var(--ink),0 34px 70px rgba(0,0,0,.75)}
.hp-rules{border:3px solid var(--ink);border-radius:6px}
#coach{border:3px solid var(--ink);border-radius:8px;box-shadow:6px 6px 0 rgba(0,0,0,.5)}

/* ============================================================
   CLASSIC THEME — restore the original soft/rounded/gold look
   (kept byte-for-byte close to the pre-manga values; higher-specificity

/* Manga: a thin black inking ring around every card, echoing comic-panel
   borders, without touching the color-coded frame border itself. */
.card{box-shadow:0 0 0 1px rgba(0,0,0,.65),0 4px 12px rgba(0,0,0,.5)}

/* ============================================================
   BATCH 3 — hand fan, drag arrow, activation, DON buff, pack flip,
   new-card star, idle GIFs, booster art, foil v2, theme scoping,
   wave decorations, splash slideshow
   ============================================================ */

/* ---- dark islands: overlays that stay dark in light themes keep light text ---- */
#vsIntro,#gameover,.authbox{--parchment:#f2f0ea;--parchment-dim:#a9b3bd;--heading:#f2c14e;color:var(--parchment)}
.authbox{background:rgba(7,20,32,.82)!important;backdrop-filter:blur(6px)}
.card .name{color:#f2efe8}

/* ---- hand fan (MTG/HS): centered, overlapped, tucked into the bottom ---- */
#handrow{justify-content:center;overflow:visible;min-height:0;height:calc(var(--card-h)*.72);padding:0 40px;position:relative;z-index:20}
#handrow .handcard{margin:0 calc(var(--card-w)*-.18);transform:translateY(34%) rotate(calc(var(--fan)*2.4deg));transform-origin:50% 130%;transition:transform .16s ease,box-shadow .16s}
#handrow .handcard:hover{transform:translateY(-16%) rotate(0deg) scale(1.1);z-index:60!important}
@media(max-width:900px){#handrow{height:calc(var(--card-h)*.8)}#handrow .handcard{margin:0 calc(var(--card-w)*-.24)}}

/* ---- Hearthstone-style drag-to-attack arrow ---- */
#dragArrow{position:fixed;inset:0;width:100vw;height:100vh;z-index:96;pointer-events:none;display:none}
#dragArrow.on{display:block}
#dragArrow path{fill:none;stroke:var(--don);stroke-width:9;stroke-linecap:round;stroke-dasharray:18 14;filter:drop-shadow(0 0 8px rgba(242,193,78,.8));animation:arrowdash .5s linear infinite}
#dragArrow polygon{fill:var(--don);filter:drop-shadow(0 0 8px rgba(242,193,78,.8))}
#dragArrow.locked path{stroke:#ff4b55;filter:drop-shadow(0 0 12px rgba(255,75,85,.9))}
#dragArrow.locked polygon{fill:#ff4b55;filter:drop-shadow(0 0 12px rgba(255,75,85,.9))}
@keyframes arrowdash{to{stroke-dashoffset:-32}}

/* ---- ability activation: clearer affordance + firing flash ---- */
.fxbtn{width:36px;height:36px;font-size:18px;top:auto;bottom:-12px;right:-12px}
.card.activating{animation:activatecard .55s ease}
@keyframes activatecard{25%{transform:scale(1.14);box-shadow:0 0 0 6px rgba(242,193,78,.95),0 0 60px rgba(242,193,78,.9)}}
.card.activating::after{content:"";position:absolute;inset:-6px;border:3px solid var(--don);border-radius:14px;animation:activering .55s ease forwards;pointer-events:none;z-index:9}
@keyframes activering{from{opacity:1;transform:scale(.9)}to{opacity:0;transform:scale(1.5)}}

/* ---- DON!! buff: glowing edges + rotated tag on the right edge ---- */
.card.donboosted{box-shadow:0 0 0 2px var(--don),0 0 18px rgba(242,193,78,.75),0 4px 12px rgba(0,0,0,.5)}
.card .donbuff{position:absolute;top:50%;right:-13px;transform:translateY(-50%) rotate(90deg);transform-origin:center;
  background:linear-gradient(180deg,#ffe9a8,var(--don));color:#3a2c05;font-weight:900;font-size:12px;letter-spacing:.03em;
  padding:2px 10px;border-radius:5px;border:2px solid rgba(58,44,5,.85);box-shadow:0 0 10px rgba(242,193,78,.9);z-index:7;white-space:nowrap}
.card .donpips{top:4px;right:4px}

/* ---- pack flip v2: explicit faces, no mirrored bleed-through ---- */
.pcard{perspective:900px;transform:none}
.pcard .pflip{position:relative;width:var(--card-w);height:var(--card-h);transform-style:preserve-3d;transition:transform .55s cubic-bezier(.3,1.3,.5,1)}
.pcard.facedown .pflip{transform:rotateY(180deg)}
.pcard.facedown:hover .pflip{transform:rotateY(180deg) translateY(-8px) scale(1.04)}
.pcard.flipped .pflip{transform:rotateY(0)}
.pcard .pfront{backface-visibility:hidden;-webkit-backface-visibility:hidden;transform:rotateY(0) translateZ(1px)}
.pcard .facedown-back{position:absolute;inset:0;border-radius:10px;transform:rotateY(180deg) translateZ(1px);backface-visibility:hidden;-webkit-backface-visibility:hidden;overflow:hidden;
  background:#0a1420;border:2px solid var(--gold-deep);display:flex;align-items:center;justify-content:center}
.pcard .facedown-back .backimg{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.pcard .facedown-back .backq{position:relative;z-index:2;font-family:var(--font-display);font-size:50px;color:rgba(255,255,255,.85);text-shadow:0 0 14px rgba(0,0,0,.8)}
.pcard.r-SR .facedown-back{border-color:#c9a0ff;box-shadow:0 0 24px rgba(155,91,209,.75)}
.pcard.r-SEC .facedown-back,.pcard.r-SP .facedown-back{border-color:#ffd54a;box-shadow:0 0 34px rgba(255,213,74,.9);animation:rareglow 1.2s ease-in-out infinite alternate}
.pcard.r-L .facedown-back{border-color:#7adfff;box-shadow:0 0 24px rgba(122,223,255,.75)}
.pcard.r-R .facedown-back{border-color:#7ad7a8;box-shadow:0 0 18px rgba(63,169,124,.6)}

/* ---- new-card star (until first hover/tap) ---- */
.newstar{position:absolute;top:-14px;left:-10px;width:34px;height:34px;z-index:7;pointer-events:none;animation:starfloat 2s ease-in-out infinite alternate}
.newstar svg{width:100%;height:100%;fill:#ffd21c;stroke:#151310;stroke-width:1.6px;filter:drop-shadow(0 2px 3px rgba(0,0,0,.45))}
.newstar.seen{animation:starpop .45s ease forwards}
/* A new pull that actually completes a deck you were short on gets a
   colorful ring instead of the plain gold star — a bigger deal than
   "just new". */
.newstar.fillsdeck svg{fill:#7adfff}
.newstar.fillsdeck::before{content:"";position:absolute;inset:-6px;border-radius:50%;pointer-events:none;
  background:conic-gradient(from 0deg,#7adfff,#c9a0ff,#ffd54a,#7adfff);
  filter:blur(3px);opacity:.8;animation:fillsdeckspin 1.8s linear infinite,starfloat 2s ease-in-out infinite alternate;z-index:-1}
@keyframes fillsdeckspin{to{transform:rotate(360deg)}}
@keyframes starfloat{from{transform:translateY(0) rotate(-8deg)}to{transform:translateY(-6px) rotate(8deg)}}
@keyframes starpop{to{transform:scale(2);opacity:0}}

/* ---- idle corner GIFs ---- */
/* Sunk 1px below the viewport edge so the GIF's own bottom edge never draws
   a visible hard line against the page — it just fades into the frame. */
.idlegif{position:fixed;bottom:-1px;max-width:min(220px,28vw);max-height:240px;z-index:38;pointer-events:none;
  animation:idlein .5s cubic-bezier(.2,1.4,.4,1)}
.idlegif.left{left:10px}
.idlegif.right{right:10px}
.idlegif.bye{animation:idleout .55s ease forwards}
@keyframes idlein{from{transform:translateY(110%)}}
@keyframes idleout{to{transform:translateY(115%)}}

/* ---- real booster art in shop + sealed pack ---- */
.packbox{padding:0}
.packbox .packimg{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.packbox .packmeta{position:absolute;left:0;right:0;bottom:0;padding:8px 10px;z-index:2;text-align:center;
  background:linear-gradient(0deg,rgba(8,14,22,.88),rgba(8,14,22,0));--parchment:#f2f0ea;--parchment-dim:#c8cdd4;color:#fff}
.packbox .packmeta .setname{font-size:20px;color:#ffd75e;text-shadow:0 1px 3px #000}
.packbox.noart .packmeta{background:none}
.packbox.noart .packmeta .setname{font-size:26px}
.packwrap .packart{padding:0}
.packwrap .packart .packimg{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:1}
.packwrap .packart .packmeta{position:absolute;left:0;right:0;bottom:0;z-index:2;text-align:center;padding:10px;
  background:linear-gradient(0deg,rgba(8,14,22,.85),rgba(8,14,22,0));--parchment:#f2f0ea;color:#fff}
.packwrap .packart .packmeta .setname{font-size:34px;color:#ffd75e;text-shadow:0 2px 6px #000}

/* ---- foil v2: metallic rainbow + texture ---- */
.card.v-foil::before{content:"";position:absolute;inset:0;z-index:4;pointer-events:none;mix-blend-mode:color-dodge;opacity:.85;
  background:
    linear-gradient(115deg,transparent 18%,rgba(64,214,255,.5) 32%,rgba(255,88,229,.55) 44%,rgba(255,224,80,.5) 55%,rgba(96,255,150,.45) 66%,transparent 82%),
    repeating-linear-gradient(115deg,rgba(255,255,255,.14) 0 2px,transparent 2px 6px);
  background-size:280% 280%,14px 14px;animation:foilsweep 3.2s ease-in-out infinite}
.card.v-foil::before{border-radius:inherit}
.card.v-foil::after{content:"";position:absolute;inset:0;z-index:4;pointer-events:none;mix-blend-mode:overlay;opacity:.5;
  border-radius:inherit;
  background:repeating-conic-gradient(from 20deg,rgba(255,255,255,.28) 0 4deg,transparent 4deg 12deg);
  /* feather the rotating godrays so no square gradient corners ever show */
  -webkit-mask-image:radial-gradient(ellipse 62% 62% at 50% 50%,#000 46%,transparent 74%);
  mask-image:radial-gradient(ellipse 62% 62% at 50% 50%,#000 46%,transparent 74%);
  animation:foilspin 9s linear infinite}
@keyframes foilspin{to{transform:rotate(360deg) scale(1.6)}}
.card.v-foil .fullart img{filter:saturate(1.25) contrast(1.08)}

/* ---- wave theme: layered animated ocean (real art, not CSS scallops) ----
   Three hand-drawn wave bands drift at golden-ratio speeds and heights
   (Fibonacci 34/55/89s — adjacent ratios ≈ φ) with a sprinkle of foam
   particles. Kept low (~150px tall) so it's a shoreline, not a flood. */
#waveOcean{display:none}
[data-theme="wave"] #waveOcean{display:block;position:fixed;left:0;right:0;bottom:0;height:210px;z-index:-1;pointer-events:none}
/* Each layer is exactly as tall as its own scaled artwork (art aspect ratios:
   back 1996x381, mid 2100x431, front 2100x381) so crests are NEVER cropped —
   the PNGs' transparent sky does the blending. A soft top mask feathers the
   remaining edge, and a deep-sea fill sits underneath so horizontal tile
   seams never expose the page background. */
#waveOcean .wl{position:absolute;left:0;right:0;background-repeat:repeat-x;background-position:0 bottom;
  -webkit-mask-image:linear-gradient(180deg,transparent 0,#000 26%);mask-image:linear-gradient(180deg,transparent 0,#000 26%)}
#waveOcean .wl.back{bottom:44px;height:150px;opacity:.42;filter:brightness(.5) saturate(.65) hue-rotate(-6deg);
  background-image:url('/assets/backgrounds/wave/ocean-back2.png');background-size:auto 100%;
  animation:oceandrift 89s linear infinite}
#waveOcean .wl.mid{display:none}
#waveOcean .wl.front{bottom:-6px;height:110px;opacity:.72;filter:brightness(.66) saturate(.8) hue-rotate(-6deg);
  background-image:url('/assets/backgrounds/wave/ocean-front2.png');background-size:auto 100%;
  animation:oceandrift 34s linear infinite reverse}
/* deep water under the art: kills tile gaps and grounds the band */
#waveOcean::after{content:'';position:absolute;left:0;right:0;bottom:0;height:80px;z-index:-1;
  background:linear-gradient(180deg,rgba(0,26,74,0),rgba(0,26,74,.75) 55%,rgba(0,20,58,.95))}
@keyframes oceandrift{to{background-position-x:-1000px}}
/* foam: tiny white flecks bobbing up off the crests */
#waveOcean .foam{position:absolute;left:0;right:0;bottom:0;height:112px;opacity:.3;
  background:
    radial-gradient(circle 2px at 12% 62%,#fff 60%,transparent 61%),
    radial-gradient(circle 1.5px at 28% 46%,#fff 60%,transparent 61%),
    radial-gradient(circle 2.5px at 41% 70%,#fff 60%,transparent 61%),
    radial-gradient(circle 1.5px at 57% 52%,#fff 60%,transparent 61%),
    radial-gradient(circle 2px at 69% 66%,#fff 60%,transparent 61%),
    radial-gradient(circle 1.5px at 82% 44%,#fff 60%,transparent 61%),
    radial-gradient(circle 2px at 93% 60%,#fff 60%,transparent 61%);
  background-size:620px 112px;background-repeat:repeat-x;
  animation:foamdrift 21s linear infinite}
@keyframes foamdrift{
  0%{background-position:0 0;opacity:.24}
  50%{opacity:.4}
  100%{background-position:-620px -14px;opacity:.24}}
[data-theme="wave"] #menuBg{opacity:.14;filter:saturate(.55) sepia(.25)}

/* ---- splash slideshow (login) ---- */
#auth{position:relative;overflow:hidden}
#splashLayer{position:absolute;inset:0;z-index:0}
#auth>div:not(#splashLayer){position:relative;z-index:2}
.splash-img{position:absolute;inset:-6%;background-size:cover;background-position:center;opacity:0;transition:opacity 1.6s ease}
.splash-img.show{opacity:1}
.splash-img.panning{animation:splashpan 11s ease-in-out forwards}
@keyframes splashpan{from{transform:scale(1.12) translate(2.5%,1.5%)}to{transform:scale(1.02) translate(-2%,-1%)}}
.splash-vignette{position:absolute;inset:0;background:radial-gradient(ellipse at 50% 45%,transparent 35%,rgba(4,10,16,.72) 100%)}

/* ---- seaking-inspired board structure ---- */
.fieldslot{width:var(--card-w);height:var(--card-h);border:2px dashed rgba(255,255,255,.28);border-radius:10px;flex-shrink:0;
  background:rgba(8,16,26,.16);box-shadow:inset 0 0 18px rgba(0,0,0,.18)}
.kwbadges{position:absolute;top:3px;left:3px;display:flex;flex-direction:column;gap:3px;z-index:6;pointer-events:none}
.kwbadges .kwb{width:22px;height:22px;border-radius:50%;background:rgba(8,14,22,.85);border:2px solid rgba(236,220,174,.85);
  display:flex;align-items:center;justify-content:center;font-size:11px;line-height:1;box-shadow:0 2px 5px rgba(0,0,0,.5)}
.kwbadges .kwb.granted{border-color:var(--don);box-shadow:0 0 10px rgba(242,193,78,.85)}

/* ============ theme-consistent battle chrome ============
   Light skins (Manga/Wave) get white-glass duel surfaces with theme fonts;
   Classic restores the deep-blue glass below. */
#duel .hud,#duel .midbar{background:rgba(255,255,255,.88);border:2px solid var(--ink);color:var(--parchment)}
.phase{background:rgba(255,255,255,.92);box-shadow:0 4px 14px rgba(0,0,0,.25),inset 0 0 0 2px var(--ink)}
#log{background:rgba(255,255,255,.6);color:var(--parchment-dim);box-shadow:inset 0 0 0 1px rgba(0,0,0,.15)}
#log .imp{color:var(--parchment)}
#duel .hint{color:var(--parchment);background:rgba(255,255,255,.65);border-radius:12px;padding:2px 14px;width:max-content;max-width:92vw;margin:0 auto}
.hp-rules{background:var(--surface);border:2px solid var(--ink)}
.hp-rules b{color:var(--heading)}
.hp-rules p,.hp-rules p .kw{color:var(--parchment)}
.hp-rules p .kw{color:var(--gold)}
#coach{background:var(--surface);border-color:var(--gold);color:var(--parchment)}
.fieldslot{border-color:rgba(255,255,255,.55)}

/* ============ grinder stats charts ============ */
.kpi .kpisub{display:block;font-size:10px;color:var(--parchment-dim);margin-top:2px}
.dualcol{flex:1;position:relative;min-width:18px;height:100%;background:rgba(127,127,127,.12);border-radius:4px 4px 0 0}
.dualcol .ghost{position:absolute;bottom:0;left:0;right:0;background:rgba(127,127,127,.25);border-radius:4px 4px 0 0}
.dualcol .fill{position:absolute;bottom:0;left:0;right:0;background:linear-gradient(180deg,#ffd75e,#c98d12);border-radius:4px 4px 0 0;z-index:2}
.dualcol i{position:absolute;top:-18px;left:0;right:0;text-align:center;font-size:10.5px;font-weight:800;font-style:normal}
.dualcol span{position:absolute;bottom:-20px;left:0;right:0;text-align:center;font-size:10px;color:var(--parchment-dim)}
.racepair{flex:1;position:relative;display:flex;align-items:flex-end;gap:3px;height:100%;min-width:20px}
.racepair .rb{flex:1;border-radius:3px 3px 0 0;min-height:2px}
.racepair .rb.dealt{background:linear-gradient(180deg,#ffd75e,#c98d12)}
.racepair .rb.taken{background:linear-gradient(180deg,#e4606b,#8f2434)}
.racepair span{position:absolute;bottom:-20px;left:0;right:0;text-align:center;font-size:10px;color:var(--parchment-dim)}
.racekey.dealt{color:#d8a52c}
.racekey.taken{color:#c74e59}
.statbar{margin-bottom:14px}

/* hand floats over the screen bottom (HS-style), out of the flex flow so it
   can never squeeze or overlap the leader HUD */
#handrow{position:fixed;left:0;right:0;bottom:0;height:calc(var(--card-h)*.60);z-index:30;pointer-events:none;overflow:visible;padding:0}
#handrow .handcard{pointer-events:auto;transform:translateY(42%) rotate(calc(var(--fan)*2.4deg))}
#handrow .handcard:hover{transform:translateY(-8%) rotate(0deg) scale(1.1)}
#duel{padding-bottom:calc(var(--card-h)*.34)}
@media(max-width:900px){#duel{padding-bottom:calc(var(--card-h)*.4)}}

/* short-viewport fit: scale the board down instead of overflowing */
@media(max-height:860px){:root{--card-w:96px;--card-h:134px}.zone{min-height:0}#duel{gap:2px;padding-bottom:calc(var(--card-h)*.52)}#handrow .handcard{transform:translateY(50%) rotate(calc(var(--fan)*2.4deg))}}
@media(max-height:640px){:root{--card-w:84px;--card-h:117px}#duel .hud{padding:4px 8px;gap:8px}.lifecard{width:12px;height:18px}}
@media(max-height:500px){:root{--card-w:66px;--card-h:92px}.phase{font-size:15px;padding:3px 12px}#log{max-height:34px;font-size:11px}.doncard{width:22px;height:31px}.doncard .dsym{font-size:7px}}

@media(max-height:500px){#myLeaderWrap .card,#oppLeaderWrap .card{width:calc(var(--card-w)*.85);height:calc(var(--card-h)*.85)}#duel{padding:2px 8px calc(var(--card-h)*.18);gap:0}#duel .hud{padding:2px 6px}.hint{font-size:10px;min-height:12px}.midbar{padding:2px}}

/* summoning sickness visual */
.card.sicknote{filter:saturate(.55) brightness(.92)}
.card.sicknote .fullart img{filter:saturate(.7)}
.sickbadge{position:absolute;bottom:-9px;left:50%;transform:translateX(-50%);z-index:7;font-size:15px;
  background:rgba(10,16,24,.85);border:2px solid rgba(236,220,174,.7);border-radius:12px;padding:0 7px;line-height:1.35;
  box-shadow:0 2px 6px rgba(0,0,0,.5);pointer-events:none;animation:sickbob 2.2s ease-in-out infinite alternate}
@keyframes sickbob{to{transform:translateX(-50%) translateY(-3px)}}

/* ============ HS-STYLE DUEL LAYOUT ============
   Cards own the center; life sits on the left edge, deck+DON!! on the
   right, End Turn is the classic right-mid round button. */
#duel{padding:40px 118px 0}
#duel.active{display:flex;flex-direction:column;justify-content:center}
.topstrip{position:fixed;top:0;left:50%;transform:translateX(-50%);z-index:31;display:flex;gap:14px;align-items:center;
  background:rgba(255,255,255,.9);border:2px solid var(--ink);border-top:none;border-radius:0 0 14px 14px;padding:4px 18px;white-space:nowrap}
.topstrip .oppname{font-weight:800;max-width:34vw;overflow:hidden;text-overflow:ellipsis}
.tsitem{font-size:12px;color:var(--parchment-dim)}
.tsitem b{color:var(--parchment)}
.edgebox{position:fixed;z-index:31;display:flex;flex-direction:column;align-items:center;gap:7px;
  background:rgba(255,255,255,.85);border:2px solid var(--ink);border-radius:12px;padding:8px 9px;backdrop-filter:blur(4px)}
.edgebox.left{left:8px}
.edgebox.right{right:8px}
.edgebox.top{top:48px}
.edgebox.bottom{bottom:calc(var(--card-h)*.62 + 6px)}
.lifestack.vert{flex-direction:column;gap:3px}
.lifestack.vert .lifecard{width:30px;height:16px}
.edgebox .donbar{max-width:76px;flex-wrap:wrap;justify-content:center;gap:4px}
.donbar.mini .doncard{width:26px;height:36px}
.donbar.mini .doncard .dsym{font-size:8px}
.edgebox .deckstack{margin:2px auto 14px}
.boardarea{display:flex;flex-direction:column;gap:8px}
.fieldrow{display:flex;align-items:center;gap:10px;justify-content:center;min-height:0}
.leaderslot{flex-shrink:0;margin-right:14px;position:relative}
.leaderslot::after{content:"LEADER";position:absolute;left:50%;transform:translateX(-50%);bottom:-15px;font-size:8px;font-weight:800;letter-spacing:.18em;color:var(--parchment-dim)}
.leaderslot .card{box-shadow:0 0 0 3px var(--don),0 6px 16px rgba(0,0,0,.4)}
.fieldcards{display:flex;gap:10px;flex-wrap:nowrap;justify-content:center}
#duel .midbar{max-width:min(680px,58vw);margin:0 auto;width:100%}
.endturn.sidebtn{position:fixed;right:16px;top:50%;transform:translateY(-50%);z-index:32;width:78px;height:78px;border-radius:50%;
  font-size:13.5px;line-height:1.15;padding:0;text-transform:uppercase;
  box-shadow:0 0 0 3px var(--ink),0 6px 18px rgba(0,0,0,.45)}
.endturn.sidebtn:hover{transform:translateY(-50%) scale(1.07)}
.endturn.sidebtn:disabled{transform:translateY(-50%)}
.endturn.sidebtn.pulse{animation:etpulse2 1.6s ease-in-out infinite}
@keyframes etpulse2{50%{box-shadow:0 0 0 3px var(--ink),0 0 26px rgba(216,28,36,.85)}}
/* hint now lives in the left rail (below the log) instead of floating over
   the hand — no more text colliding with cards underneath. */
.leftrail .hint{position:static;transform:none;width:auto;max-width:none;
  font-size:11.5px;padding:5px 11px;border-radius:10px;margin:0;text-align:center}
.hint:empty{display:none}
#oppThinking{font-size:11.5px}
/* classic: dark chrome for the new elements */
@media(max-height:860px){.edgebox.bottom{bottom:calc(var(--card-h)*.58)}}
@media(max-width:1050px){#duel{padding:40px 90px 0}.edgebox{padding:6px}.lifestack.vert .lifecard{width:24px;height:13px}}

/* board rows: keep leader+field as one centered group */
.boardarea .fieldrow{justify-content:center}
.leaderslot{margin-right:22px}
/* hand: readable resting height, still tucked */
#handrow{height:calc(var(--card-h)*.78)}
#handrow .handcard{transform:translateY(26%) rotate(calc(var(--fan)*2.4deg))}
#handrow .handcard:hover{transform:translateY(-14%) rotate(0deg) scale(1.12)}
#duel{padding-bottom:calc(var(--card-h)*.60)}
.edgebox.bottom{bottom:calc(var(--card-h)*.80 + 6px)}
@media(max-height:860px){#duel{padding-bottom:calc(var(--card-h)*.62)}#handrow .handcard{transform:translateY(30%) rotate(calc(var(--fan)*2.4deg))}}

/* ============ LEFT RAIL: turn pill + battle log between the life stacks ============ */
/* Sits directly under the opponent's Life stack — keeps the turn/log block
   next to the info it relates to instead of floating in the dead space at
   screen-center, and frees the rest of the rail for the board to breathe. */
.leftrail{position:fixed;left:8px;top:200px;z-index:31;width:212px;
  display:flex;flex-direction:column;gap:6px;align-items:stretch}
.leftrail .phase{text-align:center;padding:5px 10px;font-size:clamp(13px,4.2vw,17px);border-radius:12px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%;box-sizing:border-box}
.leftrail #log{max-height:132px;min-height:52px;overflow-y:auto;font-size:11.5px;line-height:1.4;
  border-radius:12px;padding:14px 11px 9px;text-align:left;cursor:pointer}
.leftrail #log:hover{box-shadow:inset 0 0 0 1px rgba(255,255,255,.25)}
.leftrail::after{content:'⤢ tap to expand';font-size:9.5px;text-align:center;color:var(--parchment-dim);
  opacity:.7;margin-top:-2px}
#duel .midbar{display:none}
.midline{height:2px;margin:2px auto;width:min(62%,520px);
  background:repeating-linear-gradient(90deg,rgba(255,255,255,.5) 0 14px,transparent 14px 26px)}
/* board shifts right to clear the rail */
#duel.active{padding-left:236px;padding-right:120px}
@media(max-width:1180px){.leftrail{width:170px}#duel.active{padding-left:190px;padding-right:104px}}
/* Short windows: the centered rail must never touch the life stacks that are
   pinned to the screen corners — pin it below the top stack and let the log
   flex-shrink into whatever space remains. */
@media(max-height:760px){
  .leftrail{top:228px;bottom:auto;transform:none;max-height:calc(100vh - 228px - 320px);overflow:hidden}
  .leftrail #log{max-height:none;flex:1 1 auto;min-height:36px}
}
@media(max-height:600px){.leftrail{display:none}} /* tiny landscape phones: board first */

/* ============ life cards = real face-down OPTCG cards (tabletop feel) ============ */
.lifecard{background-image:url('/assets/cards/_cardback.webp');background-size:cover;background-position:center;
  border:1.5px solid rgba(0,0,0,.55);border-radius:4px;box-shadow:0 2px 5px rgba(0,0,0,.5)}
.lifestack.vert .lifecard{width:44px;height:31px}
.lifecard.gone{transform:translateX(16px) rotate(9deg);opacity:0}

/* ============ End Turn: gold face, black text, anchored above my resources ============ */
.endturn.sidebtn{position:fixed;right:22px;top:auto;bottom:calc(var(--card-h)*.80 + 132px);transform:none;
  width:92px;height:92px;border-radius:50%;font-size:14px;line-height:1.12;padding:0;letter-spacing:.04em;
  background:radial-gradient(circle at 38% 30%,#ffe89a,#f2c14e 45%,#c9931a);color:#171207;font-weight:900;
  text-shadow:0 1px 0 rgba(255,255,255,.45);box-shadow:0 0 0 4px var(--ink),0 8px 20px rgba(0,0,0,.5)}
.endturn.sidebtn:hover:not(:disabled){transform:scale(1.06);box-shadow:0 0 0 4px var(--ink),0 10px 26px rgba(0,0,0,.55)}
.endturn.sidebtn:disabled{opacity:.42;transform:none}
.endturn.sidebtn.pulse{animation:etpulse3 1.5s ease-in-out infinite}
@keyframes etpulse3{50%{box-shadow:0 0 0 4px var(--ink),0 0 30px rgba(242,193,78,.95)}}

/* ============ badges may hang outside the card frame ============
   The card clipped its own DON!! orb/tag and ⚡ button; clip only the art. */
.card{overflow:visible}
.card::before,.card::after{border-radius:inherit}
.card .fullart{overflow:hidden;border-radius:8px}
.card .donpips{top:-8px;right:-8px;flex-direction:row;gap:3px}
.card .donpip{width:15px;height:15px;box-shadow:0 0 8px rgba(242,193,78,.95),0 0 0 2px rgba(24,18,4,.55)}
.pcard .pflip .card,.deckstack .card,.collslot .card{overflow:hidden}

/* DON!! drag targeting */
.card.dontarget{box-shadow:0 0 0 3px var(--don),0 0 22px rgba(242,193,78,.85);cursor:copy}
body.donDragging #dragArrow path{stroke:var(--don)}
body.donDragging .card:not(.dontarget){filter:brightness(.82)}

/* starter deck product tiles */
.deckbox{width:172px;height:238px;border-radius:8px;border:3px solid var(--ink);position:relative;overflow:hidden;cursor:pointer;
  background:linear-gradient(160deg,var(--surface2),var(--surface));box-shadow:4px 4px 0 rgba(0,0,0,.35);transition:transform .15s,box-shadow .15s}
.deckbox:hover{transform:translate(-2px,-3px);box-shadow:6px 7px 0 rgba(0,0,0,.4)}
.deckbox .packimg{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:top center}
.deckbox .packmeta{position:absolute;left:0;right:0;bottom:0;z-index:2;padding:8px 9px;text-align:center;color:#fff;
  background:linear-gradient(0deg,rgba(8,14,22,.94),rgba(8,14,22,.75) 62%,rgba(8,14,22,0))}
.deckbox .setname{font-family:var(--font-display);font-size:17px;color:#ffd75e;line-height:1.1}
.deckbox .deckname{font-size:12px;font-weight:800;line-height:1.2;margin:2px 0 3px}
.deckbox .label{color:#c8cdd4}

/* ============ DON!! cosmetic skins ============ */
.doncard.skinned{background:#0d1420;padding:0}
.doncard.skinned .donart{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;border-radius:4px}
.doncard.skinned .dsym{display:none}
.doncard.shiny::after{content:'';position:absolute;inset:0;border-radius:4px;pointer-events:none;mix-blend-mode:color-dodge;
  background:linear-gradient(115deg,transparent 20%,rgba(120,220,255,.55) 36%,rgba(255,120,240,.6) 48%,rgba(255,235,120,.55) 60%,transparent 78%);
  background-size:280% 280%;animation:foilsweep 2.6s ease-in-out infinite}
/* deck-editor picker */
.donpick{display:flex;flex-wrap:wrap;gap:9px;margin-top:8px}
.donopt{position:relative;cursor:pointer;border-radius:7px;padding:3px;transition:transform .12s}
.donopt:hover{transform:translateY(-3px)}
.donopt.sel{outline:3px solid var(--emerald);box-shadow:0 0 16px rgba(63,169,124,.7)}
.donopt.locked{filter:grayscale(1) brightness(.42);cursor:not-allowed}
.donopt .doncard.big{width:52px;height:73px;border-radius:6px}
.donopt .lockbadge{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);font-size:10.5px;font-weight:800;
  background:rgba(0,0,0,.78);color:#fff;padding:2px 6px;border-radius:9px;white-space:nowrap}
/* storage / duplicate choice */
.sparebox{margin-top:12px;padding:12px 16px;border:2px dashed var(--gold-deep);border-radius:10px;
  background:rgba(127,127,127,.10);font-size:13.5px;font-weight:400;max-width:640px;margin-left:auto;margin-right:auto}
.collslot .sparecount{position:absolute;bottom:-7px;right:-6px;z-index:6;background:#4a5261;color:#fff;font-weight:800;
  font-size:10.5px;border-radius:9px;padding:1px 6px;box-shadow:0 2px 4px rgba(0,0,0,.5)}

/* ============ manga panel edges (menus) ============
   Fills the empty side gutters with inked panel art, faded into the page so
   it frames the content instead of competing with it. */
#mangaEdge{position:fixed;inset:0;z-index:-1;pointer-events:none;display:none}
#mangaEdge span{position:absolute;top:0;bottom:0;width:clamp(120px,15vw,300px);
  background-color:#fff;background-image:url('/assets/backgrounds/manga/panels-action.avif');
  background-size:cover;background-blend-mode:luminosity;opacity:.9}
#mangaEdge .me-l{left:0;background-position:left center;
  -webkit-mask-image:linear-gradient(90deg,#000 0,#000 42%,transparent 100%);mask-image:linear-gradient(90deg,#000 0,#000 42%,transparent 100%)}
#mangaEdge .me-r{right:0;background-position:right center;
  /* Was scaleX(-1) for a mirrored-symmetry look, but the source art has
     baked-in onomatopoeia lettering ("HA HA HA") that reads backwards when
     flipped — background-position already differs from .me-l so this still
     isn't a literal duplicate, just no longer mirrored. */
  -webkit-mask-image:linear-gradient(270deg,#000 0,#000 42%,transparent 100%);mask-image:linear-gradient(270deg,#000 0,#000 42%,transparent 100%)}
@media(min-width:1100px){#mangaEdge{display:block}}
[data-theme="wave"] #mangaEdge span{opacity:.13}
/* subtle manga texture inside light-theme panels/modals instead of dead white */
.panel,.modalbox{position:relative;isolation:isolate}
.panel::before,.modalbox::before{content:'';position:absolute;inset:0;z-index:-1;border-radius:inherit;pointer-events:none;
  background-image:url('/assets/backgrounds/manga/panels-collage.jpg');background-size:cover;background-position:center;
  opacity:.05;mix-blend-mode:multiply}
/* deck format badges */
.fmtbadge{font-size:10px;font-weight:900;letter-spacing:.08em;padding:3px 8px;border-radius:5px;border:2px solid var(--ink);text-shadow:none}
.fmtbadge.standard{background:var(--emerald);color:#06231a}
.fmtbadge.casual{background:var(--amber);color:#2b1f02}
.fmtbadge.premium{background:linear-gradient(135deg,#ffe9a8,var(--gold) 45%,#a8790f);color:#2b1f02}
/* END TURN must never sit on top of the right rail */
.endturn.sidebtn{right:14px;bottom:auto;top:calc(50% - 44px);width:84px;height:84px}
@media(max-height:860px){.endturn.sidebtn{width:70px;height:70px;font-size:12.5px;top:calc(50% - 36px)}}
.edgebox.right{right:106px}
@media(max-width:1180px){.edgebox.right{right:92px}}

/* ============ Wave = official-site navy ============ */
[data-theme="wave"] body{background:linear-gradient(180deg,#001d5e,#001745 60%,#001236)}
[data-theme="wave"] h1,[data-theme="wave"] h2,[data-theme="wave"] h3{letter-spacing:.06em}
[data-theme="wave"] .panel{background:rgba(255,255,255,.05);border:1px solid var(--line-dim);box-shadow:0 8px 28px rgba(0,0,20,.45)}
[data-theme="wave"] .panel::before{opacity:.05;mix-blend-mode:screen}
[data-theme="wave"] .modalbox::before{opacity:.05;mix-blend-mode:screen}
[data-theme="wave"] .btn{box-shadow:0 4px 0 #8a6f16,0 10px 24px rgba(0,0,30,.5)}
[data-theme="wave"] .smallbtn{background:rgba(255,255,255,.10)}
[data-theme="wave"] .smallbtn:hover{background:rgba(255,255,255,.22)}
[data-theme="wave"] input,[data-theme="wave"] select,[data-theme="wave"] textarea{background:rgba(255,255,255,.08);border-color:var(--line-dim);color:#fff}
[data-theme="wave"] #topbar{background:rgba(0,18,54,.92);border-bottom:2px solid var(--gold-deep)}
[data-theme="wave"] #mangaEdge span{opacity:.06;filter:invert(1)}


/* deck rows lead with leader art */
.deckcardrow .deckleaderart{width:46px;height:64px;object-fit:cover;object-position:top center;border-radius:5px;
  border:2px solid var(--line);box-shadow:0 3px 8px rgba(0,0,0,.35);flex-shrink:0}
.deckcardrow{align-items:center}

/* brand: straw-hat jolly roger in a white chip (works on navy + paper) */
.brand{display:inline-flex;align-items:center;gap:9px}
.brandlogo{width:32px;height:32px;object-fit:contain;filter:drop-shadow(0 1px 2px rgba(0,0,0,.35))}
/* turn pill + log: clamp long deck names, keep the log scrolling in-box */
.leftrail .phase{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%}
.leftrail #log{overflow-x:hidden;word-break:break-word;overflow-wrap:anywhere}
.leftrail #log div{max-width:100%}

/* attached DON!! tucked under the buffed card, peeking out at the bottom */
.card{isolation:isolate}
.dontuck{position:absolute;left:50%;bottom:-13px;transform:translateX(-50%);z-index:-1;
  display:flex;gap:0;pointer-events:none}
.dontuck .doncard.mini{width:26px;height:36px;margin:0 -5px;border-radius:4px;
  transform:rotate(calc((var(--ti) - 1) * 7deg)) translateY(calc(var(--ti) * 1px));
  box-shadow:0 3px 7px rgba(0,0,0,.5),inset 0 0 0 1px rgba(255,255,255,.4)}
.dontuck .doncard.mini .dsym{font-size:7.5px}
.card.rested .dontuck{display:none} /* rotated card: skip the flourish */

/* vary the manga texture per panel so neighbours never match */
.panel:nth-of-type(3n+2)::before{background-image:url('/assets/backgrounds/manga/panels-action.avif');background-position:20% 30%}
.panel:nth-of-type(3n)::before{background-image:url('/assets/backgrounds/manga/panels-crew.jpg');background-position:center 20%}
/* hub: ranked ladder gets the action spread, profile gets the crew lineup */
.grid2 .panel:nth-child(1)::before{background-image:url('/assets/backgrounds/manga/panels-action.avif');background-position:center 35%}
.grid2 .panel:nth-child(2)::before{background-image:url('/assets/backgrounds/manga/panels-crew.jpg');background-position:center 65%}

/* drag-to-play ghost + drop zone */
.dragghost{position:fixed;z-index:96;pointer-events:none;transform:translate(-50%,-58%) scale(1.04) rotate(2deg);
  opacity:.92;box-shadow:0 24px 60px rgba(0,0,0,.6);transition:none}
.dragghost.candrop{box-shadow:0 0 0 3px var(--emerald),0 0 34px rgba(63,169,124,.8),0 24px 60px rgba(0,0,0,.6)}
.draghidden{opacity:.25;filter:grayscale(.6)}
.boardarea.dropready{outline:3px dashed rgba(63,169,124,.55);outline-offset:-8px;border-radius:18px}

/* ============ deck grid: 2:3 leader-art tiles ============ */
.deckgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(190px,1fr));gap:18px;margin-top:16px}
@media(min-width:1400px){.deckgrid{grid-template-columns:repeat(5,1fr)}}
.decktile{position:relative;aspect-ratio:2/3;border-radius:12px;overflow:hidden;cursor:pointer;
  border:var(--outline-w) solid var(--outline);background:#0d1420;
  box-shadow:0 6px 18px rgba(0,0,0,.35);transition:transform .15s,box-shadow .15s}
.decktile:hover{transform:translateY(-5px);box-shadow:0 14px 34px rgba(0,0,0,.5)}
.decktile .dt-art{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:top center}
.decktile .dt-noart{display:flex;align-items:center;justify-content:center;font-size:52px;background:linear-gradient(160deg,#20344a,#111d2b)}
.decktile .dt-shade{position:absolute;inset:0;background:linear-gradient(180deg,transparent 48%,rgba(0,0,0,.86) 88%)}
.decktile .dt-top{position:absolute;top:8px;left:8px}
.decktile .dt-info{position:absolute;left:10px;right:10px;bottom:8px;color:#fff;display:flex;flex-direction:column;gap:2px}
.decktile .dt-name{font-family:var(--font-display);font-size:17px;line-height:1.1;text-shadow:0 2px 4px #000}
.decktile .dt-leader{font-size:11px;opacity:.85;text-shadow:0 1px 3px #000}
.decktile .dt-del{position:absolute;top:8px;right:8px;width:30px;height:30px;border-radius:8px;
  background:rgba(0,0,0,.55);font-size:14px;opacity:0;transition:opacity .15s}
.decktile:hover .dt-del{opacity:1}
.decktile .dt-fav{position:absolute;top:8px;left:8px;width:30px;height:30px;border-radius:8px;
  background:rgba(0,0,0,.55);font-size:16px;color:#fff;opacity:0;transition:opacity .15s,transform .15s}
.decktile:hover .dt-fav,.decktile .dt-fav.on{opacity:1}
.decktile .dt-fav.on{color:var(--don);background:rgba(0,0,0,.7)}
.decktile .dt-fav:hover{transform:scale(1.15)}
.fmtbadge.broken{background:var(--crimson);color:#fff}
/* DON gallery modal */
.donpick.gallery{max-height:52vh;overflow-y:auto;padding:4px}
.donpick.gallery .donopt .doncard.big{width:64px;height:90px}
.donopt .donname{font-size:9.5px;font-weight:700;text-align:center;max-width:70px;margin-top:3px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* ============ battle info upgrades ============ */
/* concede: small, yellow, labelled — no mystery flag */
.concedebtn{background:linear-gradient(180deg,var(--don),#c9921a);color:#241a02;font-weight:900;font-size:10.5px;
  text-transform:uppercase;letter-spacing:.07em;padding:5px 10px;border-radius:7px;border:2px solid var(--ink);
  box-shadow:0 2px 0 #8a6a10;cursor:pointer}
.concedebtn:hover{filter:brightness(1.1)}
/* opponent hand: face-down fan pinned to the top edge */
#oppHandFan{position:fixed;top:24px;z-index:29;left:50%;transform:translateX(-50%);z-index:30;display:flex;pointer-events:none}
#oppHandFan .opphandcard{width:46px;height:64px;margin:0 -9px;
  transform:rotate(calc(var(--fan) * -4deg)) translateY(calc(var(--fan) * var(--fan) * 1.6px));
  transform-origin:top center;box-shadow:0 3px 8px rgba(0,0,0,.45)}
/* Nav bar is hidden during battle now (HS-style immersion) — the old 34px
   reserve for it left oppName sitting lower than the corner life/deck rails.
   Align it to the same top offset as the edgeboxes instead. */
#duel .topstrip{margin-top:0;top:0}
/* deck stacks: bigger card backs, count only on hover as an on-card overlay */
.deckstack{width:58px;height:76px}
.deckstack .card{width:50px!important;height:70px!important}
.deckstack-count{display:none}
.deckstack-peek{position:absolute;inset:0;z-index:5;display:flex;align-items:center;justify-content:center;
  font-family:var(--font-display);font-size:24px;color:#fff;background:rgba(4,10,20,.68);border-radius:8px;
  opacity:0;transition:opacity .12s;pointer-events:none;text-shadow:0 2px 4px #000}
.deckstack:hover .deckstack-peek{opacity:1}
/* DON!! cards: bigger, and the standard face is a proper black DON!! card
   (official look) instead of a golden box */
.doncard{width:38px;height:53px;border-radius:6px;
  background:radial-gradient(circle at 50% 28%,#3a3a3a,#101010 70%);
  box-shadow:0 2px 6px rgba(0,0,0,.55),inset 0 0 0 1.5px #c9a227}
.doncard .dsym{font-size:12px;color:#fff;text-shadow:0 0 6px rgba(240,195,60,.9),0 1px 1px #000;
  transform:rotate(-14deg);font-weight:400}
.doncard .dsym::after{content:'!!';color:var(--don)}
.dondeck-stack{width:56px;height:53px}
.dondeck-stack .doncard:nth-child(2){left:6px}
.dondeck-stack .doncard:nth-child(3){left:12px}
.dontuck .doncard.mini{width:30px;height:42px}
.dontuck{bottom:-16px}
.dontuck .doncard.mini .dsym{font-size:9px}

/* ============ battle rail pass v3 ============ */
/* rails flush to the screen edges */
.edgebox.right{right:6px}
.edgebox.left{left:6px}
/* End Turn lives on the same edge column, in the gap between the two right
   bars; inboard fallback on short windows where that gap vanishes */
.endturn.sidebtn{right:10px;top:calc(50% - 40px)}
@media(max-height:720px){.endturn.sidebtn{right:110px;top:calc(50% - 35px)}}
/* deck + DON: bigger, tabletop-prominent */
.deckstack{width:66px;height:88px}
.deckstack .card{width:60px!important;height:84px!important}
.doncard{width:42px;height:59px}
.doncard .dsym{font-size:13px}
.dondeck-stack{width:62px;height:59px}
.dondeck-stack .doncard:nth-child(2){left:7px}
.dondeck-stack .doncard:nth-child(3){left:14px}
.donbar.mini .doncard{width:28px;height:39px}
/* no text escapes an edge rail */
.edgebox{overflow:hidden;max-width:96px}
.edgebox .label,.edgebox .tsitem,.edgebox span{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* life cards: the card-back is portrait art — rotate it inside the
   horizontal life-card slot so the stack reads as real sideways cards */
.lifestack.vert .lifecard{position:relative;overflow:hidden;background:none;border-radius:3px}
.lifestack.vert .lifecard::before{content:'';position:absolute;left:50%;top:50%;width:31px;height:44px;
  transform:translate(-50%,-50%) rotate(90deg);
  background:url('/assets/cards/_cardback.webp') center/cover;border-radius:2px}
/* drop impact ripple (card thrown onto the table) */
.dropimpact{position:fixed;z-index:95;width:26px;height:26px;border-radius:50%;pointer-events:none;
  transform:translate(-50%,-50%);border:3px solid rgba(255,255,255,.85);
  animation:dropimp .45s ease-out forwards}
@keyframes dropimp{from{opacity:.9;scale:.4}to{opacity:0;scale:2.6}}
/* wave theme: official map + crew footer art on the menus */
[data-theme="wave"] #menuBg{background-image:url('/assets/backgrounds/splash/one-piece-signed-map-update-0-v0-1p0jrt1k3xog1.jpg')!important;
  background-size:cover;background-position:center;filter:saturate(.9) brightness(.75)}
[data-theme="wave"] #menuBg::before{content:'';position:absolute;left:0;right:0;bottom:0;height:38%;
  background:url('/assets/backgrounds/splash/footer_illust_chara.webp') center bottom/contain no-repeat;opacity:.9}

/* ============ immersive battle: no app chrome ============
   Hearthstone-style — the nav bar disappears during a match; Concede and the
   in-board UI are the only chrome. Nav returns on the result screen. */
body:has(#duel.active) #topbar{display:none}
body:has(#duel.active) #mangaEdge{display:none}
/* with the topbar gone everything anchors to the true screen edge */
#oppHandFan{top:6px}
.edgebox.left.top,.edgebox.right.top{top:10px}
/* End Turn: fixed lane just inboard of the right rail — one rule to end the
   cascade fights, valid at every height */
.endturn.sidebtn{right:120px!important;left:auto!important;top:calc(50% - 42px)!important;bottom:auto!important}
@media(max-width:900px){.endturn.sidebtn{right:106px!important}}
/* DON deck count label needs reserved space, not overflow */
.dondeck-stack{margin-bottom:17px}
.dondeck-count{bottom:-16px}

@media(max-width:1180px){.leftrail .phase{font-size:15px;padding:4px 8px;line-height:1.2}}

/* imported-deck rows for cards you don't own: greyed + craft-on-the-spot */
.dl-row.missing{opacity:.55;background:repeating-linear-gradient(45deg,transparent 0 8px,rgba(127,127,127,.08) 8px 16px)}
.dl-row .craftbtn{font-size:10.5px;font-weight:800;padding:3px 8px;border-radius:6px;
  background:linear-gradient(180deg,var(--don),#c9921a);color:#241a02;border:1.5px solid var(--ink);white-space:nowrap}
.dl-row .craftbtn:hover{filter:brightness(1.12)}

/* deck editor: the deck as unique cards with quantity dots (MTG Arena) */
.pool.deckview{background:rgba(127,127,127,.06);border-radius:12px;padding:10px;min-height:120px}
.qtydots{display:flex;gap:4px;justify-content:center;margin-top:5px}
.qdot{width:9px;height:9px;border-radius:50%;background:transparent;border:2px solid var(--ink);box-shadow:0 1px 2px rgba(0,0,0,.3)}
.qdot.owned{background:#f0b429;border-color:var(--ink)}

/* product-box shots (transparent bg) display whole, not cropped */
.deckbox .packimg.productimg{object-fit:contain;background:transparent;padding:4px}

/* ============ trash piles + zone labels (sim-informed, prettier) ============ */
.trashpile{display:flex;flex-direction:column;align-items:center;gap:3px;margin:2px 0}
.trashpile .trashtop{position:relative;width:44px;height:62px;border-radius:5px}
.trashpile .trashtop.empty{border:2px dashed rgba(127,127,127,.4)}
.trashpile .trashtop .card{width:44px!important;height:62px!important;filter:grayscale(.35) brightness(.8);box-shadow:0 2px 6px rgba(0,0,0,.45)}
.trashpile .trashcount{position:absolute;right:-6px;bottom:-6px;z-index:6;min-width:20px;height:20px;border-radius:10px;
  background:var(--crimson);color:#fff;font-size:11px;display:flex;align-items:center;justify-content:center;
  padding:0 5px;border:2px solid var(--ink);box-shadow:0 2px 4px rgba(0,0,0,.5)}
.trashpile.clickable{cursor:pointer}
.trashpile.clickable:hover .trashtop .card{filter:none;transform:translateY(-2px)}
/* faint zone lettering on the play rows, like the sim's playmats — visible
   only while a row is empty so it never fights with the cards */
.fieldcards{position:relative}
.fieldcards::before{content:'CHARACTER AREA';position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
  font-family:var(--font-display);font-size:clamp(16px,2.6vw,30px);letter-spacing:.35em;color:currentColor;opacity:0;pointer-events:none;transition:opacity .3s}
.fieldcards:not(:has(.card))::before{opacity:.10}

/* armed blocker awaiting confirm */
.blockopt.armed{outline:3px solid var(--emerald);box-shadow:0 0 12px rgba(63,169,124,.7)}
.blockconfirm{margin-top:6px}

/* pre-match deck picker */
/* Pre-match deck picker: a horizontal GALLERY, not a wrapping grid. The grid
   clipped tiles at the container edge and stacked them badly on narrow
   screens; a single scrolling row always shows whole tiles, scroll-snaps to
   them, and works identically with a mouse wheel, a trackpad swipe or a
   finger. Padding + visible overflow on the cross axis keeps the hover lift
   and the focus ring from being sheared off. */
.deckgrid.picker{display:flex;grid-template-columns:none;gap:14px;
  overflow-x:auto;overflow-y:visible;max-height:none;
  padding:10px 4px 16px;margin-top:0;
  scroll-snap-type:x mandatory;scrollbar-width:thin;overscroll-behavior-x:contain}
.deckgrid.picker .decktile{flex:0 0 clamp(132px,38vw,168px);scroll-snap-align:center}
.deckgrid.picker::-webkit-scrollbar{height:8px}
.deckgrid.picker::-webkit-scrollbar-thumb{background:var(--gold-deep);border-radius:4px}
/* Long deck names must ellipsis rather than clip mid-glyph. */
.decktile .dt-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block}
.dt-favstar{color:#ffd21c;text-shadow:0 1px 3px rgba(0,0,0,.7);font-size:15px;line-height:1}
.decktile.locked{filter:grayscale(.8) brightness(.6);cursor:not-allowed}
.decktile.lastused{outline:3px solid var(--gold);box-shadow:0 0 16px rgba(224,178,60,.5)}

/* ============ right rail v4: guaranteed fit ============ */
/* DON!! stacks: 3 overlapped cards + count badge, fixed height */
.donstack{position:relative;width:64px;height:62px;flex-shrink:0;cursor:default}
.donstack .doncard{position:absolute;top:calc(var(--si) * 2px);left:calc(var(--si) * 9px);z-index:calc(3 - var(--si))}
.donstack .doncount{position:absolute;right:-4px;bottom:-6px;z-index:6;min-width:20px;height:20px;border-radius:10px;
  background:var(--ink);color:var(--don);font-size:11.5px;display:flex;align-items:center;justify-content:center;
  padding:0 5px;border:2px solid var(--don);box-shadow:0 2px 5px rgba(0,0,0,.5)}
.donstack .doncard.restedstack{filter:brightness(.5) saturate(.5)}
.donstack.readystack.clickable{cursor:pointer}
.donstack.readystack.clickable:hover .doncard:first-child{transform:translateY(-3px)}
.donstack.readystack.clickable .doncard{box-shadow:0 0 0 2px var(--emerald),0 0 10px rgba(63,169,124,.6)}
.donstack.readystack.selected .doncard{box-shadow:0 0 0 3px #fff,0 0 14px #fff}
.donbar{display:flex;flex-direction:column;align-items:center;gap:8px}
.donbar.mini .donstack{width:52px;height:44px}
.donbar.mini .donstack .doncard{left:calc(var(--si) * 7px)}
/* the rails themselves: pinned to their screen half, never taller than it */
.edgebox.right.top{top:8px;bottom:auto;max-height:calc(50vh - 58px);overflow:visible}
.edgebox.right.bottom{bottom:8px;top:auto;max-height:calc(50vh - 58px);overflow:visible;justify-content:flex-end}
.edgebox{gap:6px;padding:5px}
/* compact rail furniture so the budget always holds */
.edgebox .deckstack{width:56px;height:76px}
.edgebox .deckstack .card{width:52px!important;height:73px!important}
.trashpile{margin:0}
.trashpile .label{font-size:8.5px;letter-spacing:.12em;margin:0}
.trashpile .trashtop{width:38px;height:53px}
.trashpile .trashtop .card{width:38px!important;height:53px!important}
.edgebox .tsitem{font-size:10px}
@media(max-height:820px){
  .edgebox .deckstack{width:46px;height:64px}
  .edgebox .deckstack .card{width:44px!important;height:61px!important}
  .donstack{height:52px}.donstack .doncard{width:34px;height:48px}
  .trashpile .trashtop{width:32px;height:45px}
  .trashpile .trashtop .card{width:32px!important;height:45px!important}
}

/* ============ deck editor: use the whole screen ============ */
#edit .hubwrap{max-width:min(1900px,97vw);padding:18px 22px}
#edit .builder-body{display:flex;gap:24px;align-items:flex-start;flex-wrap:nowrap}
#edit .builder-body > div:first-child{flex:1 1 auto;min-width:0}
#edit .decklist{flex:0 0 330px;max-height:calc(100vh - 150px)}
#edit .pool{grid-template-columns:repeat(auto-fill,minmax(var(--card-w),1fr));gap:16px}
#edit .pool.deckview{grid-template-columns:repeat(auto-fill,minmax(var(--card-w),1fr))}
@media(max-width:1000px){#edit .builder-body{flex-wrap:wrap}#edit .decklist{flex:1 1 100%;max-height:none}}
/* cards needing crafting read as unfinished, not broken */
.pool .slot.needcraft .card{filter:grayscale(.45) brightness(.85)}
.pool .slot.needcraft:hover .card{filter:none}

/* DON!! attached but not boosting right now (opponent's turn) — dim, no glow */
.dontuck.dormant .doncard.mini{filter:brightness(.5) saturate(.55);box-shadow:none}

/* blocker picker: real card thumbnails instead of text buttons */
.blockrow{justify-content:center}
.blockcard{cursor:pointer;transition:transform .15s}
.blockcard:hover{transform:translateY(-4px)}
.blockcard .card{box-shadow:0 0 0 2px var(--emerald),0 0 10px rgba(63,169,124,.5)}
/* Armed = selected but NOT yet committed (both blockers and counters). Green
   reads as "this is your pick, now confirm it"; the slow breathe makes the
   selection obvious without being noisy while you compare options. */
.blockcard.armed .card,.cwrap.armed .card{box-shadow:0 0 0 3px var(--emerald),0 0 18px rgba(63,169,124,.8);
  animation:armedbreathe 1.4s ease-in-out infinite alternate}
.cwrap.armed,.blockcard.armed{transform:translateY(-4px);transition:transform .18s ease}
@keyframes armedbreathe{to{box-shadow:0 0 0 4px var(--emerald),0 0 26px rgba(63,169,124,1)}}
.blockconfirm-zoom{display:flex;gap:16px;align-items:center;justify-content:center;margin-top:14px;
  background:rgba(0,0,0,.25);border-radius:14px;padding:14px;max-width:520px;margin-left:auto;margin-right:auto}

/* starter deck preview modal (box art + blurb + full decklist) */
.sdpreview{display:flex;gap:20px;align-items:flex-start;flex-wrap:wrap;justify-content:center}
.sdpreview-art{width:210px;border-radius:10px;box-shadow:0 12px 34px rgba(0,0,0,.5)}
.sdpreview-art.fallback{width:150px}
.sdpreview-info{min-width:240px;max-width:340px}
.sdpreview-list{max-height:38vh;overflow-y:auto;display:grid;grid-template-columns:1fr 1fr;gap:2px 14px;margin-top:6px}
@media(max-width:700px){.sdpreview-list{grid-template-columns:1fr}}

/* ============ kill native browser drag-and-drop on card art ============
   Real card scans are <img> tags; browsers natively make images draggable,
   which HIJACKS our custom pointer-based drag (attack/DON-attach/play-from-
   hand) — the OS takes over the gesture, our pointermove/pointerup never
   fire, and letting go does nothing. This was the actual root cause behind
   drag-and-drop "not working" — kill native image/element dragging
   everywhere on the board and in the hand. */
.card img,.doncard img,.dontuck img,.card,.doncard,.handcard,.donstack{
  -webkit-user-drag:none;user-drag:none;-khtml-user-drag:none;-moz-user-drag:none;
  -webkit-touch-callout:none;user-select:none;-webkit-user-select:none}

/* pack owned-count badge on shop/mypacks tiles */
.packbox{position:relative}
.packowned{position:absolute;top:8px;right:8px;z-index:5;background:var(--crimson);color:#fff;font-weight:900;
  font-size:13px;min-width:26px;height:26px;border-radius:13px;display:flex;align-items:center;justify-content:center;
  padding:0 7px;border:2px solid var(--ink);box-shadow:0 3px 6px rgba(0,0,0,.5)}

.dl-row.hoverable{cursor:pointer}
.dl-row.hoverable:hover{background:rgba(255,255,255,.08)}

/* league leaderboard */
.leaderboard{display:flex;flex-direction:column;gap:4px}
.lbrow{display:grid;grid-template-columns:32px 34px 1fr 80px 130px;align-items:center;gap:10px;
  padding:8px 12px;border-radius:8px;background:rgba(127,127,127,.06)}
.lbrow.me{background:rgba(224,178,60,.18);outline:1px solid var(--gold-deep)}
.lbrank{font-family:var(--font-display);font-size:18px;color:var(--parchment-dim);text-align:center}
.lbrow:nth-child(1) .lbrank{color:#e6b800}
.lbrow:nth-child(2) .lbrank{color:#b9c2cc}
.lbrow:nth-child(3) .lbrank{color:#c47b3e}
.lbname{font-weight:800}
.lbwins{font-family:var(--font-display);font-size:16px;color:var(--heading);text-align:right}
.lbwins i{font-style:normal;font-size:10px;color:var(--parchment-dim);margin-left:3px;font-weight:400}
@media(max-width:640px){.lbrow{grid-template-columns:26px 1fr 60px}.lbrow .label:nth-of-type(2){display:none}}

/* DON!! drag ghost: full playing-card size so the artwork is actually visible */
.dondragghost{position:fixed;z-index:96;width:120px;height:168px;border-radius:9px;pointer-events:none;
  transform:translate(-50%,-58%) rotate(3deg);overflow:hidden;
  box-shadow:0 0 0 3px var(--emerald),0 24px 60px rgba(0,0,0,.6),0 0 30px rgba(63,169,124,.5)}
.dondragghost .donart{width:100%;height:100%;object-fit:cover}
.dondragghost .dsym{font-size:26px;display:flex;align-items:center;justify-content:center;height:100%}

/* daily deal: glowy shining outline + tag */
.packbox.dailydeal{outline:3px solid var(--don);outline-offset:2px;
  animation:dealglow 2.2s ease-in-out infinite}
@keyframes dealglow{0%,100%{box-shadow:0 0 12px rgba(240,195,60,.45)}50%{box-shadow:0 0 30px rgba(240,195,60,.9)}}
.dealtag{position:absolute;top:-10px;left:50%;transform:translateX(-50%);z-index:6;
  background:linear-gradient(180deg,var(--don),#c9921a);color:#241a02;font-weight:900;font-size:10.5px;
  letter-spacing:.08em;padding:3px 10px;border-radius:8px;border:2px solid var(--ink);white-space:nowrap;
  box-shadow:0 3px 8px rgba(0,0,0,.4)}
/* open-all button on My Packs tiles */
.openallbtn{margin-top:6px;font-size:10.5px}

.lbbadge{font-size:20px;text-align:center;filter:drop-shadow(0 2px 3px rgba(0,0,0,.4))}
.lbbadgename{display:block;font-style:normal;font-size:10px;color:var(--parchment-dim);font-weight:400}

/* sortable stat headers */
th.sortable{cursor:pointer;user-select:none}
th.sortable:hover{color:var(--heading)}
th.sortable.on{color:var(--heading);text-decoration:underline}
/* daily deal v2: sticker needs air above the flex row, godrays on hover */
#seasonRow{padding-top:16px}
.packbox.dailydeal{position:relative;overflow:visible}
.packbox.dailydeal::before{content:'';position:absolute;inset:-30px;z-index:-1;pointer-events:none;
  background:repeating-conic-gradient(from 0deg,rgba(240,195,60,.22) 0 9deg,transparent 9deg 22deg);
  border-radius:50%;opacity:0;transform:scale(.6);transition:opacity .35s,transform .5s cubic-bezier(.2,1.3,.4,1);
  animation:raysspin 18s linear infinite;
  -webkit-mask-image:radial-gradient(circle,#000 30%,transparent 70%);mask-image:radial-gradient(circle,#000 30%,transparent 70%)}
.packbox.dailydeal:hover::before{opacity:1;transform:scale(1.25)}
.packbox.dailydeal{outline:none;border:3px solid transparent;border-radius:12px;
  background-image:linear-gradient(var(--surface2,#12233a),var(--surface2,#12233a)),
    linear-gradient(120deg,#f0c33c,#fff6d8 25%,#c9921a 50%,#fff6d8 75%,#f0c33c);
  background-origin:border-box;background-clip:padding-box,border-box;
  animation:dealshimmer 3s linear infinite}
@keyframes dealshimmer{to{background-position:0 0,300% 0}}
.packbox.dailydeal{background-size:auto,300% 100%}

/* PWA bits: locked nav while offline, persistent update toast */
#topbar nav button.locked{opacity:.35;cursor:not-allowed;text-decoration:line-through}
body.offline #connState::before{content:'⚓ offline — local mode'}
.updatetoast{position:fixed;bottom:18px;left:50%;transform:translateX(-50%);z-index:99;
  background:var(--ink);color:#fff;padding:12px 22px;border-radius:12px;border:2px solid var(--don);
  box-shadow:0 8px 30px rgba(0,0,0,.5);font-size:14px;cursor:pointer}

/* expanded match log */
.logviewer{max-height:60vh;overflow-y:auto;background:rgba(0,0,0,.25);border-radius:10px;padding:12px 14px;
  font-size:13.5px;line-height:1.6;text-align:left}
.logviewer div{padding:2px 0;border-bottom:1px solid rgba(255,255,255,.06)}
.logviewer div.imp{font-weight:700;color:var(--heading)}

/* top-10 meta decks panel */
.topdeckrow{display:grid;grid-template-columns:34px 1fr 60px 70px;align-items:center;gap:10px;
  padding:6px 10px;border-radius:8px;background:rgba(127,127,127,.06);margin-bottom:3px}
.tdrank{font-family:var(--font-display);font-size:15px;color:var(--parchment-dim);text-align:center}
.topdeckrow:nth-child(1) .tdrank{color:#e6b800}
.tdname{font-weight:700}
.tdshare{font-size:12px;color:var(--parchment-dim);text-align:right}

/* ============ Decks page: decks central, meta sidebar, hover fan ============ */
.decksLayout{display:grid;grid-template-columns:1fr 230px;gap:22px;align-items:start}
@media(max-width:980px){.decksLayout{grid-template-columns:1fr}.metaSidebar{order:2}}
.metaSidebar{position:sticky;top:64px;background:rgba(127,127,127,.06);border-radius:12px;padding:12px}
.metaSidebar .topdeckrow{grid-template-columns:24px 1fr auto;gap:6px;padding:4px 6px;font-size:11.5px}
.metaSidebar .topdeckrow .smallbtn{display:none}
.metaSidebar .tdrank{font-size:12px}
.metaSidebar .tdshare{font-size:10.5px}
/* tile wrapper so the fan can escape the tile's own overflow clip */
/* The hover fan-out is a mouse affordance: it needs room to the RIGHT of the
   tile, which a phone-width grid simply doesn't have — it pushed the flex
   frame out and broke the layout. There's also no hover on touch, so the
   animation was never reachable there anyway. Drop it entirely below the
   breakpoint rather than shrinking it into something cramped. */
@media(max-width:560px){
  .deckfan{display:none}
  .decktile-wrap:hover .decktile{transform:none}
}
.decktile-wrap{position:relative}
.decktile-wrap:hover{z-index:10}
.decktile-wrap .decktile{position:relative;z-index:2}
.deckfan{position:absolute;inset:0;z-index:1;pointer-events:none}
.deckfan .df{position:absolute;top:8%;left:12%;width:74%;aspect-ratio:5/7;object-fit:cover;
  border-radius:8px;border:2px solid var(--ink);box-shadow:0 8px 22px rgba(0,0,0,.5);
  opacity:0;transform:translateX(0) rotate(0deg);transform-origin:bottom left;
  transition:transform .38s cubic-bezier(.2,1.25,.4,1) calc(var(--fi)*45ms),opacity .25s calc(var(--fi)*45ms)}
.decktile-wrap:hover .deckfan .df{opacity:1;
  transform:translateX(calc(66% + var(--fi)*16%)) rotate(calc(6deg + var(--fi)*7deg))}
.decktile-wrap:hover .decktile{transform:translateY(-5px)}

/* blocker verdict chips */
.cchip.ok{background:var(--emerald);color:#06231a}
.cchip.bad{background:var(--crimson);color:#fff}

/* login screen: readable fields + corner mute */
.authbox{position:relative}
.authbox form{display:flex;flex-direction:column;gap:10px}
.authbox input{color:#111;background:#fff;caret-color:#111}
.authbox input::placeholder{color:#777}
.authbox .authmute{position:absolute;top:10px;right:10px}

/* inline stage ability button in the rail */
.fxbtn.stagefx{position:static;width:22px;height:22px;font-size:12px;margin-left:6px;display:inline-flex;vertical-align:middle}

/* A blocked [Activate: Main] ability keeps its ⚡ but greys out and explains
   the requirement on hover/tap, rather than disappearing — an absent button
   is indistinguishable from a broken card. */
.fxbtn.locked{opacity:.4;filter:grayscale(1);cursor:help;box-shadow:none}
.fxbtn.locked:hover{opacity:.7}

/* Stage-card arena transform: a second background layer fades in over the
   current one, then is promoted to the base layer. Two layers (rather than
   swapping one background-image) avoid any flash of empty board mid-swap. */
#duelBgNext{position:absolute;inset:-3%;background-size:cover;background-position:center;z-index:-1;
  opacity:0;transition:opacity 1.2s ease, transform 1.2s ease;transform:scale(1.06);pointer-events:none}
#duelBgNext.show{opacity:1;transform:scale(1)}
#duelBgNext::after{content:"";position:absolute;inset:0;
  background:radial-gradient(ellipse at 50% 50%,transparent 30%,rgba(6,16,26,.78) 100%)}

/* Collection card detail: owned printings shown as real cards side by side.
   The grid deliberately keeps ONE tile per card; this is where base/foil/alt/
   anime are broken out, since a foil is something you judge by eye. Each
   printing stays independently selectable — they have different dust and
   auction values and must never be merged into one pile. */
.collvars{display:flex;flex-wrap:wrap;gap:12px;justify-content:center;margin:10px 0 4px}
.collvar{cursor:pointer;border-radius:10px;padding:6px;border:2px solid transparent;
  transition:transform .15s ease,border-color .15s ease,box-shadow .15s ease}
.collvar:hover{transform:translateY(-3px)}
.collvar.sel{border-color:var(--emerald);box-shadow:0 0 16px rgba(63,169,124,.6)}
.collvar-card .card{--card-w:104px;--card-h:146px;width:104px;height:146px;pointer-events:none}
.collvar-meta{display:flex;flex-direction:column;align-items:center;gap:1px;margin-top:5px;font-size:11.5px}
.collvar-meta b{color:var(--heading)}
.collvar-meta .qty{position:static;background:none;color:var(--parchment-dim);font-weight:700;padding:0}

/* ============================================================
   MOBILE BATTLE LAYOUT  (≤560px, desktop untouched)
   The duel chrome was laid out desktop-first: fixed-position edge rails and
   fixed-width modals that a phone simply cannot fit, so life cards collided
   with the board, the DON!!/deck rail overlapped the play area, and the
   defense popup ran off-screen. Everything below is width-gated.
   ============================================================ */
@media(max-width:560px){
  /* --- Life / DON!! / deck rails: shrink and pull tight to the edges --- */
  .edgebox{gap:3px}
  .edgebox.left{left:2px}
  .edgebox.right{right:2px}
  .edgebox.top{top:40px}
  .lifecard{width:30px!important;height:21px!important}
  .edgebox .donbar{max-width:52px;gap:2px}
  .edgebox .doncard,.edgebox .doncard.mini{width:20px!important;height:28px!important}
  .edgebox .deckstack{width:32px;height:44px;margin:2px auto 12px}
  .edgebox .deckstack .card{width:26px!important;height:36px!important}
  .deckstack-count{font-size:9px;bottom:-13px}
  /* The OPPONENT's rail is reference information, not something you act on —
     shrink it further so the board keeps the space. */
  .edgebox.top .doncard,.edgebox.top .doncard.mini{width:16px!important;height:22px!important}
  .edgebox.top .deckstack{width:26px;height:36px}
  .edgebox.top .deckstack .card{width:22px!important;height:30px!important}
  /* Board must clear both rails so nothing overlaps the play area. */
  .boardarea{padding-left:38px;padding-right:38px}
  .leftrail{width:auto;max-width:44vw;left:2px;font-size:10.5px}

  /* --- Every modal fits the viewport, and scrolls instead of clipping --- */
  .modalbox{width:96vw;max-width:96vw;max-height:88vh;overflow-y:auto;padding:12px}
  .modalbox h3{font-size:20px}
  /* Defense window: attacker/defender pair + blocker & counter rows all need
     to be reachable on a phone, so cards shrink and rows wrap+scroll. */
  .counteropts{flex-wrap:wrap;justify-content:center;gap:6px;max-height:40vh;overflow-y:auto}
  .counteropts .card,.blockrow .card{--card-w:64px;--card-h:90px;width:64px!important;height:90px!important}
  .vsrow .card{--card-w:70px;--card-h:98px;width:70px!important;height:98px!important}
  .blockconfirm-zoom{flex-direction:column;align-items:center;gap:8px}
  .blockconfirm-zoom .card{width:96px!important;height:134px!important}
  .cchip{font-size:9.5px;padding:1px 5px}
  .modal-actions{flex-wrap:wrap;gap:6px}
  .modal-actions .btn,.modal-actions .smallbtn{flex:1 1 auto;min-width:120px}

  /* --- VS intro: cards were cut off at the top --- */
  #vsIntro{gap:2vw;padding:8px;align-content:center}
  #vsIntro .vs-side{flex:0 0 min(150px,40vw)}
  #vsIntro .vs-card{--card-w:min(150px,40vw);--card-h:calc(min(150px,40vw)*1.4)}
  #vsIntro .vs-name b{font-size:clamp(14px,4vw,20px);max-width:42vw}
  #vsIntro .vs-its{font-size:11px;letter-spacing:.2em}
  #vsIntro .vs-burst{font-size:clamp(34px,11vw,60px)}
}

@media(max-width:560px){
  /* The left rail (turn pill + match log) is a desktop sidebar; at phone width
     it sat on top of the board. Collapse it to a slim, translucent strip
     pinned under the top bar — still readable, no longer covering play area.
     Tapping it still opens the full-size log viewer. */
  .leftrail{max-width:40vw;top:34px;bottom:auto;transform:none;
    background:rgba(0,0,0,.42);border-radius:8px;padding:3px 5px;backdrop-filter:blur(3px)}
  .leftrail #log{max-height:74px;font-size:9.5px;line-height:1.25;overflow-y:auto}
  .phase{font-size:10px;padding:1px 6px}
  /* Hint pill: keep it out of the board and let it wrap instead of stretching. */
  #duel .hint{font-size:10.5px;max-width:92vw;padding:2px 8px;line-height:1.3}
  /* End Turn is the primary action — keep it thumb-reachable and clear of
     the hand, which is fixed to the bottom edge. */
  .endturn.sidebtn{width:74px;height:74px;font-size:12px;
    bottom:calc(var(--card-h)*.62 + 74px);right:6px}
}

/* ============================================================
   LEFT RAIL / HINT / LIFE — collision fix (all widths)
   .leftrail and .edgebox.left both sat at left:8px, so the turn pill + log
   shared x-space with the life column and overlapped it whenever the life
   stack was tall (5 cards + empty slots). The rail is now vertically CENTRED
   in the gap between the two life stacks and narrower, which is where it
   visually belongs anyway.
   ============================================================ */
.leftrail{top:50%;transform:translateY(-50%);width:178px;left:6px;
  max-height:46vh;justify-content:center}
.leftrail #log{max-height:112px}
/* Life cards read as the health bar — make them a touch larger on desktop so
   they're legible at a glance (mobile keeps the compact size, below). */
.lifestack.vert .lifecard{width:52px;height:36px}
/* The "You can:" hint was full-bleed and intrusive. Constrain it and centre
   it over the board rather than letting it span the whole window. */
#duel .hint{max-width:min(430px,54vw);white-space:normal;line-height:1.35;
  font-size:12px;padding:3px 12px;text-align:center}

/* Tablet / narrow-desktop (561–900px) was the range that stayed broken: the
   ≤560px mobile rules didn't apply and the desktop rail was too wide for it. */
@media(max-width:900px){
  .leftrail{width:150px;font-size:11px}
  .leftrail #log{max-height:88px;font-size:10.5px}
  .leftrail .phase{font-size:15px;padding:3px 8px}
  #duel .hint{max-width:min(360px,62vw);font-size:11px}
  .lifestack.vert .lifecard{width:44px;height:31px}
}

/* The arena background must never move with a swipe/scroll — it was
   position:absolute, so any overscroll dragged the battlefield around.
   Fixed pins it to the viewport, and overscroll-behavior kills the rubber-band. */
#duelBg,#duelBgNext{position:fixed}
#duel{overscroll-behavior:none;touch-action:pan-y}

@media(max-width:560px){
  /* On a phone the life bar belongs pinned along the BOTTOM edge as a
     horizontal health bar, not a vertical column fighting the board. */
  .edgebox.left.bottom{position:fixed;left:0;right:0;bottom:0;top:auto;
    flex-direction:row;justify-content:center;align-items:flex-end;gap:3px;
    max-width:100vw;padding:2px 4px;background:linear-gradient(0deg,rgba(0,0,0,.55),transparent);
    z-index:34}
  .edgebox.left.bottom .lifestack.vert{flex-direction:row;gap:3px}
  .edgebox.left.bottom .lifecard{width:26px!important;height:18px!important}
  .edgebox.left.bottom .lifecard.gone{transform:translateY(10px) rotate(9deg)}
  /* Hand sits just above the life bar so they never collide. */
  .handrow{bottom:24px}
}

/* ============================================================
   RARITY STAMP — a TRUE cutout through the info box
   Previously the mask was applied to the stamp disc, so the skull revealed
   the panel sitting behind it — you saw the info box's own background, not
   the page. To be genuinely see-through the hole has to be punched in the
   PANEL itself, so the card art / battlefield behind shows through.
   The panel is masked with a full-coverage layer minus the skull, and the
   stamp element is reduced to a thin ring outlining that hole.
   ============================================================ */

/* Ring only — no fill, so nothing blocks the hole. Thinner per feedback. */
.rarstamp{position:absolute;right:6px;bottom:4px;width:26px;height:26px;border-radius:50%;
  border:1px solid var(--rar-stamp,#9aa3ad);background:none;opacity:.85;
  -webkit-mask:none;mask:none;font-size:0;pointer-events:none}
.rarstamp-gold{opacity:.95}
.rarstamp-diamond{opacity:1;filter:drop-shadow(0 0 5px rgba(122,223,255,.9))}

/* ============ IDENTITY CHIP + PROFILE ============ */
#userMenu{position:relative}
#userBtn{display:flex;align-items:center;gap:7px;background:rgba(255,255,255,.10);
  border:2px solid var(--ink);border-radius:6px;padding:3px 9px;cursor:pointer;
  font-weight:800;color:inherit;font-family:inherit;font-size:13px;max-width:210px}
#userBtn:hover{background:rgba(255,255,255,.20)}
#userBtn #userName{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
#userBtn .caret{opacity:.6;font-size:10px}
.ubadge{display:flex;align-items:center;justify-content:center;flex-shrink:0}
.rankbadge-img{object-fit:contain;filter:drop-shadow(0 1px 2px rgba(0,0,0,.5))}
#userDrop{display:none;position:absolute;right:0;top:calc(100% + 6px);z-index:60;
  min-width:180px;background:var(--surface);border:2px solid var(--ink);border-radius:8px;
  box-shadow:6px 6px 0 rgba(0,0,0,.35),0 12px 30px rgba(0,0,0,.4);overflow:hidden}
#userMenu.open #userDrop{display:block}
#userDrop button{display:block;width:100%;text-align:left;padding:9px 12px;background:none;
  border:0;cursor:pointer;font-family:inherit;font-size:13px;color:var(--parchment)}
#userDrop button:hover{background:rgba(255,255,255,.12)}
.profhead{display:flex;align-items:center;gap:18px;flex-wrap:wrap}
.profbadge{width:96px;height:96px;display:flex;align-items:center;justify-content:center;flex-shrink:0}
.profbadge .rankbadge-emoji{font-size:64px}
@media(max-width:560px){
  #userBtn{max-width:130px;font-size:11px;padding:2px 6px}
  .profhead{gap:10px}
  .profbadge{width:64px;height:64px}
  .profbadge .rankbadge-img{width:64px!important;height:64px!important}
}

/* Music transport in the top bar. Title truncates rather than pushing the
   wallet around; on narrow bars it drops out entirely and only the three
   icon buttons remain. */
#musBar{display:flex;align-items:center;gap:3px}
#musBar .smallbtn{padding:2px 6px;font-size:11px;line-height:1.1}
#musTitle{max-width:150px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  font-size:10.5px;opacity:.75;margin-left:4px}
@media(max-width:900px){#musTitle{display:none}}
@media(max-width:560px){#musBar .smallbtn{padding:1px 4px;font-size:10px}}

/* ============================================================
   EFFECT BANNER (#fxBanner) — "what just happened" popup
   This element existed in the markup and was populated by showFxBanner(),
   but had NO CSS at all: unpositioned, no background, no text colour. It
   rendered as an unstyled block, which read as a blacked-out popup with no
   text. This is the styling it always needed.
   ============================================================ */
#fxBanner{position:fixed;left:50%;top:22%;transform:translate(-50%,-14px) scale(.94);
  z-index:70;display:none;align-items:center;gap:14px;pointer-events:none;
  max-width:min(560px,92vw);padding:12px 18px;border-radius:14px;
  background:linear-gradient(180deg,rgba(10,22,34,.96),rgba(6,14,22,.96));
  border:2px solid var(--gold);box-shadow:0 18px 50px rgba(0,0,0,.65),0 0 32px rgba(233,180,76,.35);
  opacity:0;transition:opacity .22s ease,transform .22s cubic-bezier(.2,1.3,.4,1)}
#fxBanner.on{display:flex;opacity:1;transform:translate(-50%,0) scale(1)}
#fxBanner .fxb-card{--card-w:74px;--card-h:104px;width:74px;height:104px;flex-shrink:0;
  border-radius:8px;overflow:hidden;box-shadow:0 6px 18px rgba(0,0,0,.6)}
#fxBanner .fxb-text{display:flex;flex-direction:column;gap:4px;min-width:0}
/* Explicit light colours: the banner sits on its own dark panel regardless of
   the active theme, so it must not inherit the light skins' dark text. */
#fxBanner .fxb-text b{font-family:var(--font-display);font-size:19px;color:#f2c14e;line-height:1.15}
#fxBanner .fxb-text span{font-size:13px;line-height:1.4;color:#f2f0ea}
@media(max-width:560px){
  #fxBanner{top:16%;gap:10px;padding:9px 12px;max-width:94vw}
  #fxBanner .fxb-card{--card-w:54px;--card-h:76px;width:54px;height:76px}
  #fxBanner .fxb-text b{font-size:15px}
  #fxBanner .fxb-text span{font-size:11.5px}
}

/* Turn pill + log + hint: one consistent column width.
   The rail was narrow while the hint ran nearly full-bleed, so they read as
   two unrelated widths. Both now use the SAME clamp — the rail gets wider,
   the hint narrower, meeting in the middle — and the rail fills the vertical
   gap between the two life stacks instead of floating in it. */
:root{--railw:clamp(190px,22vw,268px)}
.leftrail{width:var(--railw);max-height:52vh;justify-content:center;gap:8px}
.leftrail .phase{width:100%}
.leftrail #log{max-height:none;flex:1 1 auto;min-height:96px}
#duel .hint{max-width:var(--railw)}
@media(max-width:900px){
  :root{--railw:clamp(170px,34vw,230px)}
  .leftrail{max-height:46vh}
  .leftrail #log{min-height:74px;font-size:10.5px}
}
@media(max-width:560px){
  :root{--railw:clamp(150px,44vw,210px)}
  .leftrail{max-height:34vh}
  .leftrail #log{min-height:56px}
}

/* Keep the rail strictly INSIDE the gap between the two life stacks. It was
   centred on the viewport with a 52vh cap, which on tall screens ran past the
   bottom life stack. The life boxes sit at fixed offsets, so a tighter cap
   keeps the rail in the gap at every height without hard-coding positions. */
.leftrail{max-height:min(38vh,250px)}
.leftrail #log{min-height:60px}
@media(max-width:900px){.leftrail{max-height:min(34vh,210px)}}
@media(max-width:560px){.leftrail{max-height:min(30vh,170px)}.leftrail #log{min-height:48px}}

/* ============================================================
   RARITY STAMP v3 — solid medallion, no see-through
   The cut-through-the-panel version clipped the box edge and fought the
   rounded corners, so the effect broke more than it impressed. This is a
   self-contained medallion instead: the jolly roger is masked out of a
   metal gradient (so the SKULL itself is the metal), sitting on a recessed
   dark disc with a rim highlight. Reads as a struck coin — high value, and
   nothing about it can break the panel it sits on.
   ============================================================ */
.hp-rules[class*="rar-"]{-webkit-mask:none;mask:none}
.rarstamp{position:absolute;right:7px;bottom:5px;width:30px;height:30px;border-radius:50%;
  background:radial-gradient(circle at 34% 30%,rgba(0,0,0,.30),rgba(0,0,0,.62));
  border:1px solid var(--rar-stamp,#9aa3ad);
  box-shadow:inset 0 1px 2px rgba(255,255,255,.30),inset 0 -2px 4px rgba(0,0,0,.55),0 1px 3px rgba(0,0,0,.5);
  -webkit-mask:none;mask:none;font-size:0;pointer-events:none;opacity:1;overflow:hidden}
/* The skull is a masked metal gradient — struck INTO the medallion. */
.rarstamp::after{content:"";position:absolute;inset:4px;
  background:linear-gradient(150deg,#fff,var(--rar-stamp,#9aa3ad) 45%,#fff 62%,var(--rar-stamp,#9aa3ad));
  -webkit-mask:url('/assets/ui/jollyroger.png') center/contain no-repeat;
  mask:url('/assets/ui/jollyroger.png') center/contain no-repeat;
  filter:drop-shadow(0 1px 1px rgba(0,0,0,.65))}
.rarstamp-silver{--rar-stamp:#c8d0d8}
.rarstamp-platinum{--rar-stamp:#dce6f5}
.rarstamp-gold{--rar-stamp:#f0c33c;box-shadow:inset 0 1px 2px rgba(255,255,255,.35),inset 0 -2px 4px rgba(0,0,0,.55),0 0 8px rgba(240,195,60,.55)}
.rarstamp-diamond{--rar-stamp:#9fe4ff;box-shadow:inset 0 1px 2px rgba(255,255,255,.4),inset 0 -2px 4px rgba(0,0,0,.5),0 0 12px rgba(159,228,255,.85)}

/* ============================================================
   "WANTED" — a pulled card that completes a deck you were short on.
   This is the best moment in a pack open, so it gets a gold corner banner,
   a starburst and a pulsing aura rather than a quiet outline. Deliberately
   loud: the player should spot it across the room.
   ============================================================ */
.pcard.wantedhit{position:relative;z-index:3}
.pcard.wantedhit .pfront{box-shadow:0 0 0 3px #ffd21c,0 0 26px rgba(255,210,28,.95)!important;
  animation:wantedpulse 1.1s ease-in-out infinite alternate}
@keyframes wantedpulse{to{box-shadow:0 0 0 4px #fff3c4,0 0 40px rgba(255,210,28,1)!important}}
.wantedflag{position:absolute;top:-11px;left:50%;transform:translateX(-50%);z-index:9;
  display:flex;align-items:center;gap:4px;padding:3px 10px;border-radius:999px;
  background:linear-gradient(180deg,#fff3c4,#f0c33c 55%,#a8790f);
  border:2px solid var(--ink);box-shadow:0 3px 10px rgba(0,0,0,.55);
  font-family:var(--font-display);font-size:11px;letter-spacing:.06em;color:#2b1f02;
  white-space:nowrap;animation:wantedpop .5s cubic-bezier(.2,1.8,.4,1) both}
@keyframes wantedpop{from{transform:translateX(-50%) scale(.4);opacity:0}}
.wantedflag .wf-star{font-size:12px;animation:wantedspin 2.4s linear infinite}
@keyframes wantedspin{to{transform:rotate(360deg)}}
/* Radiating glow behind the card so it reads even in a crowded pack row. */
.pcard.wantedhit::before{content:"";position:absolute;inset:-14px;border-radius:16px;z-index:-1;
  background:radial-gradient(circle,rgba(255,210,28,.5),transparent 68%);
  animation:wantedpulse 1.1s ease-in-out infinite alternate;pointer-events:none}
@media(max-width:560px){.wantedflag{font-size:9px;padding:2px 7px}}

/* ============================================================
   Cost-discount badge — a one-shot "next play costs N less" effect (e.g.
   Rosinante's Trafalgar Law discount) used to apply completely silently:
   the DON!! total just came out lower with no on-screen explanation, so a
   correctly-working discount looked identical to a bug. Old cost strikes
   through, the discounted cost pops in green next to it, top-left corner
   so it reads immediately without covering art.
   ============================================================ */
.costdiscount{position:absolute;top:4px;left:4px;z-index:6;display:flex;align-items:center;gap:3px;
  padding:2px 6px;border-radius:8px;background:rgba(10,14,10,.85);border:1px solid #3ddc6f;
  box-shadow:0 0 8px rgba(61,220,111,.65);font-family:var(--font-display);font-size:12px;
  animation:discountpop .4s cubic-bezier(.2,1.8,.4,1) both}
@keyframes discountpop{from{transform:scale(.5);opacity:0}}
.costdiscount .cd-old{color:#8a9088;text-decoration:line-through;font-size:10px}
.costdiscount .cd-new{color:#3ddc6f;font-weight:800}

/* ============================================================
   Top bar cleanup — theme/mute/music transport shrunk so the bar stops
   overflowing/wrapping; music title text removed entirely (still readable
   via a tooltip on the pause button). Skip/prev are desktop-only: no room
   for them on mobile and little reason to hunt for a specific track there.
   ============================================================ */
.smallbtn.micro{padding:4px 7px;font-size:13px;min-width:0}
@media(max-width:560px){
  .musSkipBtn{display:none}
}

/* ============================================================
   Stage indicators — were plain inline text (illegible at a glance,
   "too tiny"), now a proper pill that reads as an actual board element
   and hints it's hoverable for a full card preview.
   ============================================================ */
#myStage, #oppStage{display:inline-flex;align-items:center;font-size:13.5px;font-weight:700}
#myStage.has-stage, #oppStage.has-stage{padding:3px 10px;border-radius:999px;
  background:rgba(233,180,76,.14);border:1px solid rgba(233,180,76,.55);cursor:pointer;
  color:var(--heading)}
#myStage.has-stage:hover, #oppStage.has-stage:hover{background:rgba(233,180,76,.26);box-shadow:0 0 8px rgba(233,180,76,.4)}

/* ============================================================
   DON!! skin hover zoom — the gallery/deck-editor thumbnails are small
   (~52px), too small to actually judge an art skin before unlocking or
   equipping it.
   ============================================================ */
.donzoom{position:fixed;z-index:9999;pointer-events:none;opacity:0;transform:scale(.85);
  transition:opacity .12s,transform .12s;background:rgba(8,14,22,.92);border:2px solid var(--gold-deep);
  border-radius:12px;padding:10px;box-shadow:0 10px 30px rgba(0,0,0,.6);text-align:center;width:200px}
.donzoom.on{opacity:1;transform:scale(1)}
.donzoom img{width:100%;border-radius:8px;display:block}
.donzoom-name{margin-top:6px;font-family:var(--font-display);font-size:13px;color:var(--heading)}

/* ============ one-time recovery code hand-off ============
   Blocking overlay, not a toast: the code is shown exactly once and only a
   bcrypt hash of it is kept, so there is no second chance to surface it. The
   Continue button stays disabled until the player explicitly acknowledges
   saving it. */
.reccode-ov{position:fixed;inset:0;z-index:10000;display:flex;align-items:center;justify-content:center;
  background:rgba(0,0,0,.82);backdrop-filter:blur(3px);padding:20px}
.reccode-box{max-width:520px;width:100%;background:var(--surface,#0d1520);color:var(--parchment,#f2f0ea);
  border:3px solid var(--gold-deep,#a8790f);border-radius:14px;padding:24px;
  box-shadow:0 24px 70px rgba(0,0,0,.7);text-align:center}
.reccode-box h2{font-family:var(--font-display);font-size:28px;color:var(--heading,#ffd75e);margin:0 0 10px}
.reccode-box p{font-size:13.5px;line-height:1.55;color:var(--parchment-dim,#c8cdd4);margin:0 0 16px}
/* Monospace + generous letter-spacing because this gets read off a screen and
   retyped by hand, sometimes from a photo. */
.reccode{font-family:ui-monospace,'Cascadia Code',Consolas,monospace;font-size:22px;font-weight:700;
  letter-spacing:2px;color:#fff;background:rgba(0,0,0,.45);border:2px dashed var(--gold-deep,#a8790f);
  border-radius:10px;padding:14px 10px;margin:0 0 12px;user-select:all;word-break:break-all}
.reccode-ack{display:flex;align-items:center;justify-content:center;gap:8px;margin:16px 0 14px;
  font-size:13px;cursor:pointer}
.reccode-ack input{width:17px;height:17px;cursor:pointer}
.reccode-box .bigbtn{width:100%;padding:12px;font-family:var(--font-display);font-size:18px;cursor:pointer;
  border-radius:10px;border:2px solid var(--ink,#111);background:var(--crimson,#d1232a);color:#fff}
.reccode-box .bigbtn:disabled{opacity:.45;cursor:not-allowed}
.minilink{font-size:12px;color:var(--parchment-dim,#c8cdd4);text-decoration:underline}
