/* Sparkle Duel — "Starlit Arena".
   The lab grammar (ink #3b2a2a outlines, hard 4px offset shadows, sticker buttons, Chewy +
   Sniglet, big drop-shadowed emoji) applied to a world that is this game's alone: a floodlit
   golden duelling ring standing in a sapphire→teal twilight, under an aurora and a low moon,
   ringed by floating lanterns.

   Explicitly NOT: the old lab purple #0f0a1e (Nick: "remove all boring purple"), the lollipop
   stand's day-blue-and-sand, the sewing shop's cream. Sapphire + teal + hot gold is a
   combination no other game in the lab uses, so a screenshot of this can only be this. */

:root{
  --ink:#3b2a2a;
  --sh:4px 4px 0 var(--ink);
  --sh-sm:3px 3px 0 var(--ink);
  --paper:#fff7e6;

  /* the twilight */
  --sky1:#0e2a63;   /* deep sapphire, top */
  --sky2:#12569a;
  --sky3:#0f8a96;   /* teal at the horizon */
  --glow:#2fd9d0;

  /* the ring */
  --floor1:#ffdf9b;
  --floor2:#f0932b;
  --floor3:#a8452f;

  /* jewels */
  --magenta:#ff3d8a;
  --gold:#ffd23f;
  --mint:#5dffb0;
  --cyan:#35c9f5;
  --coral:#ff8a3c;
  --violet:#a45cff;

  --railW:clamp(190px,25vw,290px);
}

*{box-sizing:border-box;-webkit-tap-highlight-color:transparent}
html,body{height:100%;margin:0;overscroll-behavior:none}
body{
  font-family:'Nunito','Trebuchet MS',sans-serif;font-weight:800;color:var(--ink);
  background:var(--sky1);touch-action:none;user-select:none;-webkit-user-select:none;
  -webkit-touch-callout:none;overflow:hidden;
}
.d,#foeName,.sticker,.chip,.card b,#bannerT,.pow,#comboN{font-family:'Chewy','Arial Black',sans-serif;font-weight:400}
.hide{display:none!important}

/* ============================ the world ============================ */
#stage{position:fixed;inset:0;overflow:hidden;
  background:
    radial-gradient(120% 70% at 50% 108%, rgba(255,223,155,.55) 0%, rgba(255,223,155,0) 62%),
    linear-gradient(180deg,#081a44 0%, var(--sky1) 22%, var(--sky2) 58%, var(--sky3) 100%);
}
/* aurora: two soft ribbons that drift */
.aur{position:absolute;left:-20%;right:-20%;height:34vh;filter:blur(28px);opacity:.5;pointer-events:none}
#aur1{top:2%;background:linear-gradient(90deg,transparent,var(--mint) 25%,var(--cyan) 55%,transparent);
  transform:skewY(-6deg);animation:drift 18s ease-in-out infinite alternate}
#aur2{top:14%;background:linear-gradient(90deg,transparent,var(--violet) 30%,var(--magenta) 62%,transparent);
  transform:skewY(5deg);opacity:.35;animation:drift 25s ease-in-out infinite alternate-reverse}
@keyframes drift{to{transform:translateX(9%) skewY(3deg)}}

#moon{position:absolute;left:7%;top:6%;width:clamp(64px,9vw,118px);aspect-ratio:1;border-radius:50%;
  background:radial-gradient(circle at 36% 34%,#fffdf2,#ffe9a8 60%,#ffcf5e);
  box-shadow:0 0 0 12px rgba(255,231,168,.16),0 0 0 30px rgba(255,231,168,.08),0 0 70px rgba(255,220,140,.6);
  pointer-events:none}

#stars{position:absolute;inset:0;pointer-events:none}
#stars i{position:absolute;width:3px;height:3px;border-radius:50%;background:#fff;
  box-shadow:0 0 7px 2px rgba(255,255,255,.85);animation:tw 2.6s ease-in-out infinite alternate}
@keyframes tw{from{opacity:.25;transform:scale(.6)}to{opacity:1;transform:scale(1.25)}}

/* floating lanterns — the crowd of the arena */
#lanterns{position:absolute;inset:0;pointer-events:none}
.lan{position:absolute;font-size:26px;filter:drop-shadow(0 0 16px rgba(255,210,63,.85));
  animation:bobLan 6s ease-in-out infinite alternate}
@keyframes bobLan{to{transform:translateY(-26px) rotate(6deg)}}

/* the ring itself: a golden lit stone disc, ink-outlined like everything else */
#ring{position:absolute;left:50%;bottom:-19vh;width:112%;height:46vh;transform:translateX(-50%);
  border-radius:50%;border:6px solid var(--ink);
  background:
    radial-gradient(ellipse at 50% 6%, #fff6dc 0%, var(--floor1) 18%, var(--floor2) 48%, var(--floor3) 88%, #7d2f36 100%);
  box-shadow:0 -10px 50px rgba(255,190,90,.5), 0 0 0 10px rgba(255,61,138,.18),
             inset 0 12px 0 rgba(255,255,255,.4);
  pointer-events:none}
#ring:after{content:'';position:absolute;left:16%;right:16%;top:18%;height:50%;border-radius:50%;
  border:5px dashed rgba(59,42,42,.4)}
/* runes around the rim — this is a duelling circle, not a beach */
#ring:before{content:'✦   ✧   ✦   ✧   ✦   ✧   ✦   ✧   ✦';position:absolute;left:0;right:0;top:5%;
  text-align:center;font-size:clamp(13px,1.8vw,20px);color:rgba(59,42,42,.45);letter-spacing:2px}
/* two crystal lamp-posts marking the edge of the duelling circle */
.pil{position:absolute;bottom:11vh;width:clamp(24px,3vw,40px);height:26vh;
  background:linear-gradient(90deg,#14415f,#4fb6cf 40%,#9ff0ff 52%,#4fb6cf 62%,#14415f);
  border:4px solid var(--ink);border-radius:10px 10px 3px 3px;box-shadow:var(--sh);pointer-events:none}
.pil:before{content:'';position:absolute;left:-11px;right:-11px;top:-15px;height:17px;background:var(--gold);
  border:4px solid var(--ink);border-radius:7px}
.pil:after{content:'';position:absolute;left:-13px;right:-13px;bottom:-13px;height:15px;background:var(--gold);
  border:4px solid var(--ink);border-radius:5px}
.pil.l{left:2.5%}.pil.r{right:calc(var(--railW) + 10px)}
.pil i{position:absolute;left:50%;top:-58px;transform:translateX(-50%);font-size:34px;
  filter:drop-shadow(0 0 18px rgba(93,255,176,.95));font-style:normal;animation:tw 2s ease-in-out infinite alternate}

/* ============================ layout ============================ */
#wrap{position:absolute;inset:0;display:flex;flex-direction:row;gap:0}
#arena{position:relative;flex:1 1 auto;min-width:0;min-height:0}
/* padding-top clears the shared ⛶ (top-right, 48px at 12,12): a card under it made
   fullscreen.js relocate itself DOWN onto the spellbook, which is the doubled-control bug. */
#rail{position:relative;flex:0 0 var(--railW);display:flex;flex-direction:column;gap:8px;
  padding:74px 12px 14px 6px}

@media (orientation:portrait), (max-aspect-ratio:11/10){
  #wrap{flex-direction:column}
  #rail{flex:0 0 auto;flex-direction:column;padding:4px 12px 12px 70px}
  #ring{bottom:-20vh;height:38vh;width:150%}
  .pil.r{right:2.5%}
  .pil{height:19vh;bottom:16vh}
}

/* ============================ HUD ============================ */
#hud{position:absolute;left:66px;right:10px;top:10px;display:flex;align-items:center;gap:8px;z-index:6;
  pointer-events:none;flex-wrap:wrap}
#hud>*{pointer-events:auto}
.chip{display:flex;align-items:center;gap:6px;background:var(--paper);border:4px solid var(--ink);
  border-radius:999px;padding:4px 12px;box-shadow:var(--sh-sm);font-size:clamp(13px,1.6vw,17px);
  min-height:38px;line-height:1}
.chip.tapme{cursor:pointer}
.chip.tapme:active{transform:translate(2px,2px);box-shadow:1px 1px 0 var(--ink)}
#gems{gap:3px;padding:4px 10px}
#gems i{font-style:normal;font-size:clamp(15px,2vw,21px);filter:grayscale(1) opacity(.35)}
#gems i.on{filter:none;text-shadow:0 0 10px rgba(255,210,63,.9)}

/* ============================ fighters ============================ */
.fighter{position:absolute;z-index:4;text-align:center;pointer-events:auto;cursor:pointer}
.fighter .em{display:block;line-height:1;filter:drop-shadow(4px 5px 0 rgba(59,42,42,.35))}
#foe{right:8%;top:16%}
#foe .em{font-size:clamp(64px,12vw,132px);animation:foeBob 2.4s ease-in-out infinite alternate}
@keyframes foeBob{to{transform:translateY(-16px) rotate(3deg)}}
#foe.wind .em{animation:wind .85s ease-in;filter:drop-shadow(0 0 26px var(--magenta)) drop-shadow(4px 5px 0 rgba(59,42,42,.35))}
@keyframes wind{0%{transform:scale(1)}60%{transform:scale(1.22) rotate(-6deg)}100%{transform:scale(1)}}
#foe.hurt .em{animation:shake .4s}
@keyframes shake{0%,100%{transform:translateX(0)}25%{transform:translateX(-12px) rotate(-8deg)}75%{transform:translateX(12px) rotate(8deg)}}
#foe.froze .em{filter:drop-shadow(0 0 22px var(--cyan)) saturate(.4) brightness(1.3);animation:none}
#foe.gone{transition:transform .7s cubic-bezier(.4,0,.9,.3),opacity .7s;transform:translate(60vw,-30vh) scale(.4);opacity:0}
#foe.arrive{animation:arrive .8s cubic-bezier(.2,1.5,.4,1)}
@keyframes arrive{from{transform:translate(70vw,-26vh) scale(.3);opacity:0}to{transform:none;opacity:1}}

/* Maya is no longer parked in the corner: duel.js drives left/top every frame and she is
   translated from her own centre, so she can stand anywhere on the ring floor. z-index 11 puts
   her ABOVE the cast layer, which is what lets her be dragged mid-cast. */
#hero{left:9%;top:74%;transform:translate(-50%,-50%);z-index:11;touch-action:none}
#hero.dashing{filter:drop-shadow(0 0 26px var(--cyan)) drop-shadow(0 0 60px #fff)}
#hero.safe .em{opacity:.6}
#hero .em{font-size:clamp(58px,10vw,116px);animation:heroBob 2.9s ease-in-out infinite alternate}
@keyframes heroBob{to{transform:translateY(-9px)}}
#hero .hat{position:absolute;left:50%;top:-4%;transform:translateX(-50%);font-size:clamp(28px,5vw,58px);
  filter:drop-shadow(3px 4px 0 rgba(59,42,42,.3));pointer-events:none}
#hero.cast .em{animation:heroCast .45s}
@keyframes heroCast{0%{transform:scale(1)}35%{transform:scale(1.18) rotate(-7deg)}100%{transform:scale(1)}}
#hero.hurt .em{animation:shake .4s}
#hero.surge{filter:drop-shadow(0 0 30px var(--gold)) drop-shadow(0 0 60px var(--magenta))}

/* health bars, sitting under each fighter */
.hp{margin:8px auto 0;width:clamp(110px,17vw,210px);height:22px;background:rgba(59,42,42,.5);
  border:4px solid var(--ink);border-radius:999px;box-shadow:var(--sh-sm);overflow:hidden;position:relative}
.hp i{display:block;height:100%;width:100%;border-radius:999px;transition:width .3s cubic-bezier(.2,1,.4,1)}
#foeHp i{background:linear-gradient(180deg,#ff8fbb,var(--magenta))}
#heroHp i{background:linear-gradient(180deg,#a5ffd8,var(--mint))}
.hp b{position:absolute;inset:0;display:grid;place-items:center;font-size:13px;color:#fff;
  text-shadow:0 2px 0 rgba(59,42,42,.9);font-family:'Nunito',system-ui,sans-serif;font-weight:800;font-weight:400;letter-spacing:.5px}
#foeName{margin-top:6px;font-size:clamp(15px,2.2vw,24px);color:#fff;text-shadow:3px 3px 0 var(--ink)}
#foeName small{display:block;font-size:.62em;opacity:.85}
#heroName{margin-top:6px;font-size:clamp(13px,1.8vw,19px);color:#fff;text-shadow:3px 3px 0 var(--ink);
  font-family:'Fredoka','Nunito',sans-serif;font-weight:400}

/* speech bubble */
#bubble{position:absolute;right:calc(8% + clamp(50px,9vw,100px));top:6%;max-width:min(46%,300px);
  background:var(--paper);border:4px solid var(--ink);border-radius:16px;padding:8px 13px;
  box-shadow:var(--sh);font-size:clamp(13px,1.7vw,18px);line-height:1.25;z-index:7;
  transform-origin:100% 100%;animation:pops .3s cubic-bezier(.2,1.6,.4,1)}
#bubble:after{content:'';position:absolute;right:16px;bottom:-15px;border:8px solid transparent;
  border-top:14px solid var(--ink)}
@keyframes pops{from{transform:scale(.3);opacity:0}to{transform:scale(1);opacity:1}}

/* ============================ incoming orbs ============================ */
/* ============================ living arena props ============================ */
#props{position:absolute;inset:0;z-index:10;pointer-events:none}
.prop{position:absolute;transform:translate(-50%,-50%);pointer-events:auto;cursor:pointer;
  display:grid;place-items:center;line-height:1}
.prop .pe{font-size:clamp(40px,6vw,68px);filter:drop-shadow(4px 5px 0 rgba(59,42,42,.35))}
.prop.gone{animation:propGone .35s forwards;pointer-events:none}
@keyframes propGone{to{transform:translate(-50%,-50%) scale(1.9);opacity:0}}

/* the crystal: cover that eats an orb or two, then shatters */
.prop.rock .pe{font-size:clamp(46px,7vw,84px)}
.prop.rock.cracked .pe{filter:drop-shadow(0 0 16px var(--magenta)) drop-shadow(4px 5px 0 rgba(59,42,42,.35));
  transform:rotate(-6deg)}
.prop.rock.bonk{animation:bonk .28s}
@keyframes bonk{0%,100%{transform:translate(-50%,-50%)}40%{transform:translate(calc(-50% + 9px),-50%) scale(.93)}}

/* the bounce cloud: step on it and it flings her across the ring */
.prop.cloud .pe{animation:cloudBob 2.2s ease-in-out infinite alternate}
@keyframes cloudBob{to{transform:translateY(-14px) scale(1.06)}}
.prop.cloud.spent{opacity:.35;filter:grayscale(1)}
.prop.cloud.bounce{animation:cloudSquish .35s}
@keyframes cloudSquish{40%{transform:translate(-50%,-50%) scale(1.35,.7)}}

/* a dropped power-up, sitting in a glowing ring so it reads as "come and get me" */
.prop.pick{width:74px;height:74px;border-radius:50%;border:4px solid var(--ink);
  box-shadow:var(--sh-sm),0 0 26px currentColor;animation:pickBob 1.1s ease-in-out infinite alternate}
.prop.pick .pe{font-size:clamp(30px,4vw,44px)}
@keyframes pickBob{to{transform:translate(-50%,calc(-50% - 12px))}}
.prop.pick.fading{opacity:.45}

/* ============================ rival phase two ============================ */
#foe.rage .em{font-size:clamp(84px,15vw,168px);
  animation:ragePulse 1.1s ease-in-out infinite alternate}
@keyframes ragePulse{from{transform:scale(1) rotate(-3deg)}to{transform:scale(1.12) rotate(3deg)}}
#foe.rage{filter:drop-shadow(0 0 30px var(--rage,#ff3d8a)) drop-shadow(0 0 70px var(--rage,#ff3d8a)) saturate(1.4)}
/* the NAME stays white — a magenta name on the magenta rage sky was unreadable. The bar carries
   the new colour instead, which is where she is already looking. */
#foe.rage #foeHp i{background:linear-gradient(180deg,#fff,var(--rage,#ff3d8a))}
#foe.rage #foeName small{color:var(--gold)}
.rageRing{position:absolute;left:50%;top:38%;width:clamp(120px,20vw,230px);aspect-ratio:1;
  transform:translate(-50%,-50%);border-radius:50%;border:5px dashed var(--rage,#ff3d8a);
  opacity:.55;animation:spin 5s linear infinite;pointer-events:none}
@keyframes spin{to{transform:translate(-50%,-50%) rotate(360deg)}}
/* the whole arena leans into the fight: the aurora goes hot and the ring rim burns */
#stage.rage #aur1{background:linear-gradient(90deg,transparent,var(--magenta) 25%,var(--coral) 55%,transparent);opacity:.62}
#stage.rage #aur2{background:linear-gradient(90deg,transparent,#ff2d55 30%,var(--gold) 62%,transparent);opacity:.45}
#stage.rage{background:
    radial-gradient(120% 70% at 50% 108%, rgba(255,150,90,.6) 0%, rgba(255,150,90,0) 62%),
    linear-gradient(180deg,#1a0a34 0%, #3d1355 22%, #7a2a63 58%, #b8503f 100%)}
#stage.rage #ring{box-shadow:0 -10px 60px rgba(255,90,90,.6), 0 0 0 12px rgba(255,45,85,.3),
  inset 0 12px 0 rgba(255,255,255,.4)}
#flash{position:absolute;inset:0;z-index:19;pointer-events:none;background:#fff;
  animation:flashOut .55s forwards}
@keyframes flashOut{from{opacity:.85}to{opacity:0}}

#orbs{position:absolute;inset:0;z-index:17;pointer-events:none}
.orb{position:absolute;width:60px;height:60px;margin:-30px 0 0 -30px;border-radius:50%;
  will-change:left,top;
  display:grid;place-items:center;font-size:30px;cursor:pointer;pointer-events:auto;
  border:4px solid var(--ink);box-shadow:var(--sh-sm),0 0 24px currentColor;
  animation:orbSpin 1.1s linear infinite}
@keyframes orbSpin{to{transform:rotate(360deg)}}
.orb.pop{animation:orbPop .28s forwards;pointer-events:none}
@keyframes orbPop{to{transform:scale(2.1);opacity:0}}

/* ============================ cast layer ============================ */
#castLayer{position:absolute;inset:0;z-index:9;pointer-events:none}
#castLayer.live{pointer-events:auto}

/* trace: a constellation of star nodes joined by a faint line */
.node{position:absolute;width:66px;height:66px;margin:-33px 0 0 -33px;border-radius:50%;
  display:grid;place-items:center;font-size:31px;color:#fff;
  background:radial-gradient(circle,rgba(255,255,255,.32),rgba(255,255,255,.06));
  border:4px dashed rgba(255,255,255,.85);box-shadow:0 0 22px rgba(255,255,255,.55);
  animation:nodePulse 1s ease-in-out infinite alternate}
@keyframes nodePulse{to{transform:scale(1.13)}}
.node.next{border-style:solid;border-color:var(--gold);box-shadow:0 0 34px var(--gold),var(--sh-sm)}
.node.done{border-color:var(--mint);background:var(--mint);color:var(--ink);animation:nodeDone .35s forwards}
@keyframes nodeDone{to{transform:scale(1.5);opacity:0}}
.node b{font-family:'Fredoka','Nunito',sans-serif;font-weight:400;font-size:22px;pointer-events:none}

/* charge: a ring that fills, with a golden "let go NOW" band */
/* The charge ring and the rhythm rings are FEEDBACK ONLY. #pad underneath owns every pointer
   event, so a tap in the middle of the ring still reaches the cast handler — when the ring ate
   the pointerup, a hold got stuck "charging" until its timeout. */
#charge{position:absolute;left:50%;top:46%;transform:translate(-50%,-50%);width:clamp(160px,26vw,240px);
  aspect-ratio:1;border-radius:50%;display:grid;place-items:center;pointer-events:none}
#charge svg{position:absolute;inset:0;width:100%;height:100%;transform:rotate(-90deg)}
#chargeTxt{position:relative;font-family:'Fredoka','Nunito',sans-serif;font-weight:400;color:#fff;
  font-size:clamp(15px,2.4vw,24px);text-shadow:3px 3px 0 var(--ink);text-align:center;line-height:1.1}
#charge.ready #chargeTxt{color:var(--gold);animation:pulseBig .35s ease-in-out infinite alternate}
@keyframes pulseBig{to{transform:scale(1.16)}}

/* rhythm: rings closing on a target */
#rhythm{position:absolute;left:50%;top:46%;transform:translate(-50%,-50%);width:clamp(150px,24vw,220px);
  aspect-ratio:1;display:grid;place-items:center;pointer-events:none}
#rhythm .target{position:absolute;inset:22%;border-radius:50%;border:5px solid var(--gold);
  box-shadow:0 0 26px var(--gold),inset 0 0 22px rgba(255,210,63,.5)}
#rhythm .ring{position:absolute;inset:0;border-radius:50%;border:5px solid #fff;opacity:.9}
#rhythm .lbl{position:absolute;bottom:-38px;left:50%;transform:translateX(-50%);white-space:nowrap;
  font-family:'Fredoka','Nunito',sans-serif;font-weight:400;color:#fff;text-shadow:3px 3px 0 var(--ink);font-size:clamp(14px,2vw,20px)}

/* a big tappable pad so any tap in the arena counts during a cast */
#pad{position:absolute;inset:0}

/* floating "PERFECT!" style pops */
.pow{position:absolute;transform:translate(-50%,-50%);white-space:nowrap;pointer-events:none;
  color:#fff;text-shadow:4px 4px 0 var(--ink);animation:powUp 1s forwards;z-index:12}
@keyframes powUp{0%{transform:translate(-50%,-50%) scale(.4);opacity:0}
  25%{transform:translate(-50%,-70%) scale(1.2);opacity:1}
  100%{transform:translate(-50%,-160%) scale(1);opacity:0}}
.pow.p1{font-size:clamp(20px,3vw,32px)}
.pow.p2{font-size:clamp(24px,3.6vw,38px);color:var(--mint)}
.pow.p3{font-size:clamp(30px,4.6vw,50px);color:var(--gold)}
.pow.p4{font-size:clamp(34px,5.6vw,62px);color:var(--magenta)}
.pow.dmg{font-size:clamp(22px,3.2vw,36px);color:var(--gold)}
.pow.ouch{color:var(--magenta);font-size:clamp(20px,3vw,32px)}

/* combo badge */
#combo{position:absolute;left:50%;top:8%;transform:translateX(-50%);z-index:11;
  background:var(--magenta);border:4px solid var(--ink);border-radius:14px;padding:4px 14px;
  box-shadow:var(--sh);color:#fff;text-shadow:2px 2px 0 rgba(59,42,42,.7);
  font-size:clamp(15px,2.2vw,22px);white-space:nowrap;animation:pops .3s}
#combo.bump{animation:bumpC .35s}
@keyframes bumpC{40%{transform:translateX(-50%) scale(1.28) rotate(-3deg)}}

/* SPARKLE SURGE overlay */
#surge{position:absolute;inset:0;z-index:10;pointer-events:none;
  background:radial-gradient(circle at 50% 70%,rgba(255,210,63,.28),transparent 60%);
  animation:surgeP 1.1s ease-in-out infinite alternate}
@keyframes surgeP{to{background:radial-gradient(circle at 50% 70%,rgba(255,61,138,.3),transparent 62%)}}

/* ============================ rail: the spellbook ============================ */
#rail .railHead{font-family:'Fredoka','Nunito',sans-serif;font-weight:400;color:#fff;text-shadow:3px 3px 0 var(--ink);
  font-size:clamp(14px,1.9vw,20px);letter-spacing:1px;text-align:center;margin-bottom:2px}
#spells{flex:1 1 auto;display:flex;flex-direction:column;gap:8px;min-height:0}
.card{flex:1 1 0;min-height:60px;display:flex;align-items:center;gap:10px;padding:6px 10px;
  background:var(--paper);border:4px solid var(--ink);border-radius:16px;box-shadow:var(--sh);
  transform:rotate(-1.2deg);cursor:pointer;position:relative;overflow:hidden;text-align:left}
.card:nth-child(even){transform:rotate(1.4deg)}
.card:active{transform:translate(3px,3px);box-shadow:1px 1px 0 var(--ink)}
.card.armed{background:var(--gold);transform:translate(3px,3px) scale(1.02);box-shadow:1px 1px 0 var(--ink)}
.card .ce{font-size:clamp(26px,3.6vw,40px);line-height:1;filter:drop-shadow(2px 3px 0 rgba(59,42,42,.28));flex:0 0 auto}
.card .ct{min-width:0;flex:1 1 auto}
.card b{display:block;font-size:clamp(13px,1.7vw,19px);line-height:1.05;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.card s{display:block;text-decoration:none;font-size:clamp(10px,1.25vw,13px);opacity:.72;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.card .how{position:absolute;right:6px;top:5px;font-size:13px;font-family:'Nunito',system-ui,sans-serif;font-weight:800;
  font-weight:400;background:var(--ink);color:var(--paper);border-radius:8px;padding:1px 7px;letter-spacing:.4px}
.card .bar{position:absolute;left:0;bottom:0;height:5px;width:100%}

.sticker{font-size:clamp(14px,1.9vw,20px);padding:9px 16px;min-height:46px;border:4px solid var(--ink);
  border-radius:14px;background:var(--mint);box-shadow:var(--sh);cursor:pointer;transform:rotate(-1.6deg);
  color:var(--ink);letter-spacing:.5px}
.sticker:active{transform:translate(3px,3px);box-shadow:1px 1px 0 var(--ink)}
.sticker.pink{background:var(--magenta);color:#fff}
.sticker.gold{background:var(--gold)}
.sticker.big{font-size:clamp(17px,2.6vw,26px);padding:12px 26px;min-height:54px}

@media (orientation:portrait), (max-aspect-ratio:11/10){
  #spells{flex-direction:row;gap:6px}
  .card{flex-direction:column;justify-content:center;gap:2px;padding:6px 4px;min-height:74px;text-align:center}
  .card .ct{width:100%}
  .card b{font-size:clamp(10px,2.7vw,15px);white-space:normal;line-height:1.02;
    display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
  .card s{display:none}
  .card .how{position:static;margin-top:2px;padding:0 6px}
  #rail .railHead{display:none}
  #bookRow{display:flex;gap:8px;justify-content:center;margin-top:6px}
}

/* ============================ banner (never a modal) ============================ */
/* Sits BELOW the HUD row (gems + difficulty chip) and clear of the shared 🏠 at 12,12 — a
   banner pinned to top:0 covered both. */
#banner{position:absolute;left:50%;top:60px;transform:translate(-50%,calc(-100% - 70px));z-index:14;
  background:var(--paper);border:5px solid var(--ink);border-radius:22px;box-shadow:var(--sh);
  padding:14px 26px 16px;text-align:center;max-width:min(92%,620px);transition:transform .45s cubic-bezier(.2,1.5,.4,1)}
#banner.show{transform:translate(-50%,0)}
#bannerT{font-size:clamp(22px,4vw,42px);line-height:1.05}
#bannerS{font-size:clamp(13px,1.8vw,18px);margin-top:4px}
#bannerU{display:flex;gap:8px;justify-content:center;flex-wrap:wrap;margin-top:8px}
#bannerU span{background:var(--gold);border:3px solid var(--ink);border-radius:999px;padding:3px 12px;
  font-family:'Fredoka','Nunito',sans-serif;font-weight:400;font-size:clamp(12px,1.6vw,16px);box-shadow:var(--sh-sm)}
#bannerB{margin-top:10px}

/* toast — the only "instructions", and it never blocks anything */
#toast{position:absolute;left:50%;bottom:14px;transform:translate(-50%,160%);z-index:13;
  background:var(--ink);color:var(--paper);border-radius:16px;padding:8px 18px;
  font-size:clamp(12px,1.7vw,18px);max-width:min(92%,540px);text-align:center;transition:transform .35s;
  pointer-events:none;box-shadow:0 6px 0 rgba(0,0,0,.25);line-height:1.25}
#toast.show{transform:translate(-50%,0)}

/* ============================ spellbook sheet ============================ */
#sheet{position:absolute;left:0;right:0;bottom:0;z-index:20;background:var(--paper);
  border-top:5px solid var(--ink);border-radius:24px 24px 0 0;padding:14px 16px 18px;
  transform:translateY(102%);transition:transform .4s cubic-bezier(.2,1.2,.4,1);max-height:86%;
  display:flex;flex-direction:column}
#sheet.show{transform:none}
#sheetH{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:8px}
#sheetH .d{font-size:clamp(18px,2.8vw,28px)}
#sheetG{flex:1 1 auto;overflow:auto;-webkit-overflow-scrolling:touch;display:grid;
  grid-template-columns:repeat(auto-fill,minmax(148px,1fr));gap:9px;padding:2px}
.sc{display:flex;align-items:center;gap:8px;padding:7px 9px;background:#fff;border:4px solid var(--ink);
  border-radius:14px;box-shadow:var(--sh-sm);cursor:pointer;min-height:56px;text-align:left}
.sc:active{transform:translate(2px,2px);box-shadow:1px 1px 0 var(--ink)}
.sc.on{background:var(--gold)}
.sc.lock{opacity:.55;cursor:default}
.sc .ce{font-size:30px;filter:drop-shadow(2px 3px 0 rgba(59,42,42,.25))}
.sc b{display:block;font-family:'Nunito',system-ui,sans-serif;font-weight:800;font-weight:400;font-size:15px;line-height:1.05}
.sc s{display:block;text-decoration:none;font-size:13px;opacity:.72}
#hatRow{display:flex;gap:8px;flex-wrap:wrap;margin-top:10px}
.hc{width:52px;height:52px;display:grid;place-items:center;font-size:26px;background:#fff;
  border:4px solid var(--ink);border-radius:14px;box-shadow:var(--sh-sm);cursor:pointer}
.hc.on{background:var(--gold)}
.hc.lock{opacity:.4;cursor:default}

/* A canvas is a REPLACED element: with inset:0 and no explicit width/height it takes its
   INTRINSIC size (the width/height attributes) instead of stretching, so `cvs.width=clientWidth*DPR`
   fed itself and the canvas doubled on every resize until it was 16 777 216px square and painted
   the whole game white. width/height 100% is what actually pins it. */
#fx{position:absolute;inset:0;width:100%;height:100%;z-index:15;pointer-events:none}
