/* ============================================================
   INKVILLE — wjam.css
   Wednesday Jams — the secret guitar-hero jam

   Part of the game.css split. Loaded as <link> tags from index.html in
   THIS ORDER — the cascade depends on it. Do not reorder the links.
   ============================================================ */
/* ===== WEDNESDAY JAMS — the secret guitar-hero jam (v3.03) ===== */
#wjamStage{position:absolute; inset:0; z-index:45; overflow:hidden; font-family:var(--fontD);
  background:radial-gradient(120% 80% at 50% 0%,#241748 0%,#140f26 55%,#0a0a14 100%);}
#wjamStage .wj-star{position:absolute; width:2px; height:2px; background:#fff; border-radius:50%; opacity:.8; animation:wjTwinkle 2.4s steps(2) infinite;}
@keyframes wjTwinkle{50%{opacity:.25}}
#wjamStage .wj-moon{position:absolute; top:14px; right:22px; width:34px; height:34px; border-radius:50%;
  background:radial-gradient(circle at 38% 38%,#fdf6e3,#d9cfa8); box-shadow:0 0 22px #fdf6e355;}
.wj-hud{position:absolute; top:6px; z-index:6; text-align:center; color:#f2ead6;}
.wj-hud .lab{font-size:7px; letter-spacing:1px; opacity:.65;}
.wj-hud .val{font-size:16px; color:#f4c542;}
#wjScore{left:8px;} #wjHi{right:8px;}
#wjTitle{position:absolute; top:4px; left:50%; transform:translateX(-50%); z-index:6; display:flex; align-items:center; gap:8px; white-space:nowrap;}   /* v3.59 — the MARQUEE header: big name, JP sub, checkered flags both sides */
#wjTitle .wj-tt{font-family:var(--fontD); font-size:clamp(15px,4.6vw,22px); color:#e86a9a; letter-spacing:2px; text-shadow:0 0 12px #e86a9a99, 2px 2px 0 #1b1018; text-align:center; line-height:1.2;}
#wjTitle .wj-tt i{display:block; font-style:normal; font-size:9px; color:#cbb8d8; letter-spacing:3px; text-shadow:none;}
#wjTitle .wj-flag{width:26px; height:26px; display:block; animation:nimFlagWave .7s ease-in-out infinite alternate;}
#wjTitle .wj-flag.fr{transform:scaleX(-1);}
#wjTitle .wj-flag svg{width:100%; height:100%;}
/* ⭐ v3.59 — THE GODDESS: crowned, shaded, rainbow-cycling, wrapped in a living aura, headbanging forever */
.wj-goddess{width:70px; z-index:5; animation:wjHeadbang .46s ease-in-out infinite alternate;}
.wj-goddess .wj-godink{position:relative; display:block; z-index:2; filter:drop-shadow(0 0 8px #ff5cf0) drop-shadow(0 0 16px #7fd4ff88);}
.wj-goddess .wj-aura{position:absolute; left:50%; top:42%; width:120px; height:120px; transform:translate(-50%,-50%); z-index:0; pointer-events:none; border-radius:50%;
  background:conic-gradient(#ff5cf055,#f4c54255,#7fd4ff55,#6bbf5955,#ff5cf055); filter:blur(6px);
  animation:wjAuraSpin 2.4s linear infinite, wjAuraPulse 1.1s ease-in-out infinite alternate;}
@keyframes wjHeadbang{from{transform:rotate(-7deg);}to{transform:rotate(6deg);}}
@keyframes wjAuraSpin{to{rotate:360deg;}}
@keyframes wjAuraPulse{from{opacity:.55; scale:.92;}to{opacity:.95; scale:1.12;}}
/* the COMBO RUSH — both inklings blaze while time stands still */
.wj-guitarist.wj-shine{animation:wjShine 1.1s ease-out;}
@keyframes wjShine{0%{filter:brightness(3) saturate(2) drop-shadow(0 0 22px #fff);}100%{filter:none;}}
#wjamStage.wj-freeze{animation:wjFreezeFlick .16s steps(2) infinite;}
#wjamStage.wj-freeze #wjHwy{filter:saturate(1.6) brightness(1.18);}
@keyframes wjFreezeFlick{0%{filter:hue-rotate(0) contrast(1.15);}100%{filter:hue-rotate(28deg) contrast(1.3);}}
#wjStarRow{position:absolute; top:26px; left:50%; transform:translateX(-50%); z-index:6; font-size:12px; letter-spacing:3px; color:#3a3348;}
#wjStarRow .on{color:#f4c542; text-shadow:0 0 8px #f4c542;}
#wjCombo{position:absolute; top:52px; left:50%; transform:translateX(-50%); z-index:6; font-size:14px; color:#49c6c0; letter-spacing:2px; min-height:16px; text-shadow:0 0 10px #49c6c0; transition:transform .08s;}
#wjCombo.pop{transform:translateX(-50%) scale(1.35);}
#wjCombo.hot{color:#f4c542; text-shadow:0 0 12px #f4c542, 0 0 4px #fff;}
#wjHwy{position:absolute; left:50%; transform:translateX(-50%); top:80px; bottom:158px; width:min(94%,340px); display:flex; gap:5px; z-index:3;
  border-bottom:4px solid #fff9; box-shadow:0 4px 16px #fff6; background:linear-gradient(#ffffff05,#ffffff12);}
.wj-lane{flex:1; position:relative; overflow:hidden; border-left:1px solid #ffffff10; border-right:1px solid #ffffff10;}
.wj-lane::after{content:''; position:absolute; left:0; right:0; bottom:0; height:40%; background:linear-gradient(transparent,var(--lc,#fff2)); opacity:.16; pointer-events:none;}
.wj-note{position:absolute; left:8%; right:8%; height:20px; border-radius:6px; border:2px solid #00000077; background:var(--lc); box-shadow:0 0 10px var(--lc);}
#wjFrets{position:absolute; left:50%; transform:translateX(-50%); bottom:92px; width:min(94%,340px); display:flex; gap:5px; z-index:6; align-items:flex-end;}
/* the FRETS — a tall gem: three square sides, a domed round top (like a guitar-hero note) */
.wj-fret{flex:1; height:54px; border-radius:30px 30px 7px 7px; border:3px solid #00000088; background:var(--lc);
  box-shadow:0 5px 0 #00000066, inset 0 4px 8px #ffffff66, inset 0 -4px 8px #00000044; cursor:pointer; transition:transform .05s, filter .05s;}
.wj-fret.press{transform:translateY(6px) scale(.96); filter:brightness(1.75); box-shadow:0 0 16px var(--lc);}
.wj-guitarist{position:absolute; bottom:16px; width:60px; z-index:5; animation:wjBob 1.4s ease-in-out infinite;}
.wj-guitarist.v{right:0; animation-delay:.3s;}
.wj-guitarist.p{left:0;}
.wj-guitarist svg{width:100%; height:auto; display:block;}
.wj-guitarist .wj-gtr{position:absolute; bottom:2px; width:56px; z-index:6;}
.wj-guitarist.p .wj-gtr{right:-14px; transform:rotate(12deg);}
.wj-guitarist.v .wj-gtr{left:-14px; transform:scaleX(-1) rotate(12deg);}
.wj-guitarist.v > svg:not(.wj-gtr), .wj-vspeak.v svg{filter:hue-rotate(292deg) saturate(1.45) brightness(1.06);}   /* V goes hot magenta — the rock&roll inkling */
@keyframes wjBob{50%{transform:translateY(-6px)}}
.wj-guitarist.leave.p{animation:wjLeaveL .8s ease-in forwards;}
.wj-guitarist.leave.v{animation:wjLeaveR .8s ease-in forwards;}
@keyframes wjLeaveL{to{transform:translate(-140px,0) rotate(-20deg); opacity:0}}
@keyframes wjLeaveR{to{transform:translate(140px,0) rotate(20deg); opacity:0}}
.wj-burst{position:absolute; z-index:7; font-size:12px; pointer-events:none; animation:wjBurst .4s ease-out forwards; color:#f4c542; text-shadow:0 0 6px #f4c542;}
@keyframes wjBurst{0%{opacity:1; transform:translateY(0) scale(1)}100%{opacity:0; transform:translateY(-24px) scale(1.5)}}
#wjMeter{position:absolute; bottom:74px; left:50%; transform:translateX(-50%); width:min(94%,340px); height:6px; background:#00000066; z-index:6; border:1px solid #ffffff22;}
#wjMeter i{display:block; height:100%; width:50%; background:linear-gradient(90deg,#c93a22,#f4c542,#6bbf59); transition:width .2s;}
/* short handheld portrait — keep everything on-screen, nothing cut by the bottom */
@media (max-height:680px){
  #wjHwy{top:76px; bottom:146px;} #wjFrets{bottom:84px;} .wj-fret{height:46px;} #wjMeter{bottom:70px;} .wj-guitarist{width:54px;}
}
.wj-topjam{display:flex; justify-content:space-between; font-family:var(--fontD); font-size:11px; padding:4px 6px; letter-spacing:1px; border-bottom:1px dashed #ffffff22;}
.wj-topjam b{color:#f4c542;}
.wj-topjam.me{background:#f4c5421a; color:#fff;}
#wjNameIn{font-family:var(--fontD); font-size:22px; letter-spacing:8px; text-align:center; text-transform:uppercase; width:120px; padding:6px; background:#0a0a14; color:#f4c542; border:2px solid #f4c542; margin:8px auto; display:block;}
/* BUTTON CANON — CONFIRM/OK/YES = GREEN, BACK/CANCEL in a confirm = RED */
.btn.ok{background:#1f7a3f; color:var(--cream);}
/* ⭐ v0.400 — ONLINE IS NAVY, NOT PURPLE (user-declared 2026-07-31). Every game's doorstep now reads
   SOLO in green / ONLINE in navy / BACK in black, and the navy is a deep, refined one rather than a
   bright blue — #1f3566 carries the cream at 9.7:1, comfortably over the 4.5:1 floor crReadable
   holds every screen in this game to. `.purple` is kept as an alias so nothing that still names it
   loses its colour. */
.btn.navy,.btn.purple{background:#1f3566; color:var(--cream);}   /* v0.355 — a deeper green: cream on the old #2e9e4f measured 3.2:1, under the 4.5:1 line. Same button, readable text (5.0:1). */
/* EQUIPPED — the numbers board: level base in cream, gear bonus in GREEN */
.eqgrid{display:grid; grid-template-columns:auto repeat(4,1fr); gap:4px 6px; align-items:center; background:var(--ink); border-radius:6px; padding:6px 8px; margin-bottom:6px;}
.eq-t{font-family:var(--fontD); font-size:8px; color:#cfc7b0; letter-spacing:1px; display:flex; flex-direction:column; gap:2px;}
.eq-t i{font-style:normal; opacity:.5; font-size:7px;}
.eq-c{display:flex; flex-direction:column; align-items:center; gap:1px; font-family:var(--fontD);}
.eq-n{font-size:7px; color:#cfc7b0; letter-spacing:1px;}
.eq-c b{font-size:10px; color:var(--cream);}
.eq-c i{font-style:normal; font-size:9px; color:#5fe08a;}   /* what the WEAR adds — always green */
.btn.vipwear{width:100%; background:var(--teal); color:var(--ink); margin-top:8px;}
.btn.optbig{width:88%; min-height:54px; box-sizing:border-box; display:inline-flex; align-items:center; justify-content:center;}   /* every OPTIONS button the exact same size */
.curchip[data-cur="cup"] svg{width:14px; height:14px;}   /* the cup stands as tall as its number */
/* CURRENCY CANON — the ink LOGO speaks, not the word; it rides a cream disc so it READS on any button, even black */
.inkw{width:16px; height:16px; display:inline-flex; align-items:center; justify-content:center; vertical-align:-3px; margin-right:3px;
  background:var(--cream); border-radius:50%; box-shadow:0 0 0 1px #1b151055; padding:1px; box-sizing:border-box;}
.inkw svg{width:100%; height:100%;}
.btn.opt span{white-space:normal; line-height:1.35;}   /* long amounts WRAP to a second line — never spill the box */
/* the UN-REEL + the exact-count pop */
.unreelIn{animation:unreelA .35s var(--pop);}
@keyframes unreelA{from{transform:translateX(34px) scaleX(.2); opacity:0}to{transform:none; opacity:1}}
.exactPop{position:fixed; transform:translateX(-50%); z-index:215; font-family:var(--fontD); font-size:12px;
  background:var(--ink); color:var(--cream); border:2px solid #0a0810; border-radius:3px; padding:10px 10px;
  display:flex; align-items:center; gap:3px; box-shadow:2px 2px 0 #000a; pointer-events:none; animation:exactA 3s ease forwards;}   /* a SECOND strip of the reel unrolls beneath the bar */
.exactPop::before,.exactPop::after{content:''; position:absolute; left:3px; right:3px; height:4px;
  background:repeating-linear-gradient(90deg, var(--gold) 0 5px, transparent 5px 11px);}
.exactPop::before{top:2px;} .exactPop::after{bottom:2px;}
.exactPop .inkw{background:var(--cream);}
@keyframes exactA{0%{opacity:0; transform:translateX(-50%) translateY(-3px)}8%,88%{opacity:1; transform:translateX(-50%) translateY(0)}100%{opacity:0}}
/* the RINK's glitching bonus clock — every 8th floor, +10s if you slide through it */
@keyframes rgClkGl{0%,68%{filter:none; transform:none}76%{filter:hue-rotate(120deg) saturate(1.8); transform:translate(1px,-1px) skewX(6deg)}86%{filter:invert(.2); transform:translate(-1px,1px)}94%,100%{filter:none; transform:none}}
.rkGl10{position:fixed; transform:translateX(-50%); z-index:215; font-family:var(--fontD); font-size:16px; color:#2e9e4f;
  text-shadow:2px 2px 0 #1b1510; pointer-events:none; animation:rkG10A 1.2s ease-out forwards, rgClkGl .22s steps(2) 5;}
@keyframes rkG10A{0%{opacity:0}12%{opacity:1}80%{opacity:1; transform:translateX(-50%) translateY(-14px)}100%{opacity:0; transform:translateX(-50%) translateY(-20px)}}
/* — the NEW frames: all motion, no words — */
.fr-breathe{animation:frBreathe 2.6s ease-in-out infinite;}
@keyframes frBreathe{50%{opacity:.5}}
.fr-rip{position:absolute; left:50%; top:50%; width:86%; height:86%; transform:translate(-50%,-50%); border:3px solid #2b2650aa; border-radius:50%; pointer-events:none; animation:frRip 2.4s ease-out infinite;}
.fr-rip.r2{animation-delay:1.2s;}
@keyframes frRip{0%{transform:translate(-50%,-50%) scale(.72); opacity:.9}100%{transform:translate(-50%,-50%) scale(1.18); opacity:0}}
.fr-satPath{position:absolute; left:50%; top:50%; width:104%; height:104%; transform:translate(-50%,-50%); border:2px dashed #1b151033; border-radius:50%; pointer-events:none; animation:frSpin 5s linear infinite;}
.fr-satDot{position:absolute; left:50%; top:-4px; width:8px; height:8px; margin-left:-4px; background:var(--gold); border:2px solid var(--ink); border-radius:0;}
/* CART MASTER frame — the whole set orbits the inklet */
.fr-cmRing{position:absolute; left:50%; top:50%; transform:translate(-50%,-50%); border-radius:50%; pointer-events:none; animation:frSpin 6s linear infinite;}
.fr-cmRing.r1{width:114%; height:114%;}
.fr-cmRing.r2{width:132%; height:132%; animation-duration:8.5s; animation-direction:reverse;}
.fr-cmRing.r3{width:98%; height:98%; animation-duration:5s;}
.fr-cmCard{position:absolute; left:50%; top:-5px; width:8px; height:11px; margin-left:-4px; background:var(--gold); border:1.5px solid var(--ink); border-radius:1px; box-shadow:0 0 4px #f4c542;}
.fr-cmCard.b{top:auto; bottom:-5px;}
.fr-cmRing.r2 .fr-cmCard{background:var(--red);}
.fr-cmRing.r3 .fr-cmCard{background:#4a6fa5;}
@keyframes frSpin{to{transform:translate(-50%,-50%) rotate(360deg)}}
/* ⭐⭐ v0.483 — LINK-UP: two PS1-style pads orbiting the inkling, the secret frame that arrives with
   the CONTROLLER DETECTED badge. Built on the same ring mechanism as CART MASTER (frSpin), with the
   two rings at different sizes and speeds so the pair never lines up into one shape.
   ⚠ The pad is COUNTER-ROTATED by its own animation, so it stays the right way up all the way round
   instead of tumbling — a controller upside-down at the top of its orbit reads as a glitch.
   The two counter-spins must stay the exact mirror of their ring's, direction included, or it
   wobbles: r2's ring is reversed, so its counter-spin is not. */
.fr-padRing{position:absolute; left:50%; top:50%; transform:translate(-50%,-50%); border-radius:50%;
  pointer-events:none; z-index:5; animation:frSpin 7s linear infinite;}
.fr-padRing.r1{width:122%; height:122%;}
.fr-padRing.r2{width:150%; height:150%; animation-duration:10.5s; animation-direction:reverse;}
.fr-padCtl{position:absolute; left:50%; top:-9px; width:22px; height:15px; margin-left:-11px;
  display:block; filter:drop-shadow(0 1px 0 #1b151055) drop-shadow(0 0 4px #ffffff55);
  animation:frPadUp 7s linear infinite;}
.fr-padRing.r2 .fr-padCtl{animation-duration:10.5s; animation-direction:reverse;}
.fr-padCtl svg{display:block; width:100%; height:100%;}
@keyframes frPadUp{to{transform:rotate(-360deg)}}
/* the shop/profile preview is a small circle — the orbit has to come in or the pads sit outside it */
.fr-prev .fr-padRing.r1{width:108%; height:108%;}
.fr-prev .fr-padRing.r2{width:130%; height:130%;}
.fr-prev .fr-padCtl{width:17px; height:12px; margin-left:-8.5px; top:-7px;}
.fr-reelRing{position:absolute; left:50%; top:50%; width:102%; height:102%; transform:translate(-50%,-50%); border:5px dashed #1b1510; border-radius:50%; pointer-events:none; animation:frSpin 9s linear infinite; box-sizing:border-box;}
/* ⭐ v0.656 — THE 24-BIT FRAME rides the SAME simple circle as every other frame (Odaroo, 2026-08-05).
   ⚠⚠ It used to be 112% wide and rotate in `steps(24)`, so it both sat OUTSIDE the ring every other
   frame keeps to (102–104%) and jumped a block at a time instead of turning. It is now 104% and on
   the shared `frSpin` linear turn — one plain circle, like the rest. Do not put the steps back. */
.fr-24ring{position:absolute; left:50%; top:50%; width:104%; height:104%; transform:translate(-50%,-50%);
  z-index:4; pointer-events:none; overflow:visible; animation:frSpin 6.5s linear infinite;
  filter:drop-shadow(0 0 3px #f4c54277);}
/* — the FRAME SHOP: just the circles, price under, tap for the playbill — */
.frshop{background:none; border:none; padding:4px 2px; cursor:pointer; display:flex; flex-direction:column; align-items:center; gap:4px;}
.frshop .fr-prev{width:64px; height:64px; position:relative;}
.fr-prev.noink{background:radial-gradient(circle at 40% 34%, #fdfdfd, #efe9d8 72%); border-radius:50%;}
.frshop-pr{font-family:var(--fontD); font-size:9px; color:var(--ink); display:flex; align-items:center; gap:2px;}
.frshop.wornfr .fr-prev{box-shadow:0 0 0 3px var(--gold), 0 0 14px var(--gold); border-radius:50%;}
.frgrid2{display:grid; grid-template-columns:repeat(3,1fr); gap:10px 4px; justify-items:center;}
input::placeholder{color:#1b151055; letter-spacing:2px; font-family:var(--fontD); text-transform:uppercase;}
.ledg-tabs{display:flex; gap:6px; justify-content:center; margin:8px 0;}
.ledg-body{max-height:44vh; overflow-y:auto; text-align:left; border:2px solid var(--ink); background:var(--cream);
  border-radius:6px; padding:8px 10px; margin:4px 0 6px; -webkit-overflow-scrolling:touch;}
.ledg-era{font-family:var(--fontD); font-size:8px; letter-spacing:1px; color:#5a3a75; background:#5a3a7518;
  border-left:4px solid #5a3a75; padding:5px 8px; margin:10px 0 4px; border-radius:0 4px 4px 0;}
.ledg-era:first-child{margin-top:0;}
.ledg-row{display:grid; grid-template-columns:56px 1fr; gap:8px; font-size:11px; line-height:1.5;
  padding:4px 2px; border-bottom:1px dashed #1b151022;}
.ledg-row b{color:#c9552e; font-family:var(--fontD); font-size:8px; padding-top:2px;}
.ledg-body.ledg-story{font-size:11.5px; line-height:1.65;}
.ledg-body.ledg-story p{margin:0 0 10px;}
.ledg-body.ledg-story b{color:#c9552e;}
#battleHP{position:relative; align-items:flex-start;}   /* everything hangs from the BAR line */
/* ⭐⭐⭐ v0.712 — `.bhp-clock` IS DELETED, AND THE HEALTH BARS TAKE THE ROOM IT WAS HOLDING.
   (Odaroo, 2026-08-06: "we're going to save a lot of real estate of the time row where the HP is —
   make the HP bar almost as long as the middle of the screen so that we see the HP bar going
   down.") The countdown moved to the header reel; the element that used to sit between the two bars
   is gone from brawl.js's markup, so this rule has nothing left to dress.
   ⚠ It is left written down as a headstone rather than silently deleted because #bClock STILL
   EXISTS — it is the header plate now (vsClkOwner, js/online.js). Anyone grepping for the id after
   seeing a clock on this screen needs to land here and be told where it went, not find nothing.
   ⚠⚠ THE WIDENING IS SUBTRACTION, NOT A NEW WIDTH. `.bhp-side` is already `flex:1` and `.bhp-bar`
   already `width:100%`, so each bar reaches from its own avatar to the middle of the screen the
   moment the thing that was parked there stops taking its ~55px. The two numbers below are what is
   left of the fixed cost on this row: 8px of side padding and a 5px gap were sized around a
   three-object row, and on a folded phone they are worth another ~14px of visible drain. */
#battleHP{padding-left:4px; padding-right:4px; gap:2px;}
#battleHP .bhp-av{align-self:flex-start; margin-top:-4px;}   /* avatars hug the bar line too */
.bhp-lv{flex:none; font-family:var(--fontD); font-size:8px; color:#ffe58a; background:#00000066; border-radius:4px; padding:2px 3px; text-shadow:1px 1px 0 #000;}   /* fighter LEVEL, right by the bar */
/* ⚠⚠ v0.668 — `position:relative` IS LOAD-BEARING. The frame parts frameDeco() puts inside this box
   are absolutely positioned, so with no positioning context here they resolved against #battleHP —
   the full-width HP bar — and every OCTA-THON portrait's ring was painted as a huge ellipse across
   the whole bar instead of a circle around the face. The box is already 34×34, so once it positions
   its own children the ring is a true circle and needs no .fr-stage. */
.bhp-av{position:relative; width:34px; height:34px; flex:none; image-rendering:pixelated; filter:drop-shadow(1px 1px 0 #0008); background:#ffffff14; border-radius:50%;}
.bhp-av svg{width:100%; height:100%;}
.bhp-bar{display:flex; gap:3px; width:100%; height:20px; flex:none; max-width:none;}   /* taller, stretches all the way to the middle (no flex-basis collapse in the column) */
.bhp-bar.foe{flex-direction:row-reverse;}   /* foe drains from the centre outward toward its avatar */
.bhp-seg{flex:1; background:#00000055; border:1.5px solid #0a0810; border-radius:2px; overflow:hidden;}
/* ⚠⚠ v0.834 — THE FILL SCALES; IT NO LONGER RESIZES. `width` is a layout property and this bar is
   tweened one HP at a time, so it re-solved the page on every frame of every hit. The gradient runs
   TOP-TO-BOTTOM, which is the whole reason `scale` is safe here — a 90deg gradient would be
   squashed by it and would need `clip-path` instead (see `#efill`).
   ⚠⚠ THE ORIGIN IS THE EDGE THE BAR HUGS. Yours empties toward the left, theirs toward the right;
   with a default centre origin both would shrink toward their middles and the damage would appear
   to break off BOTH ends. */
.bhp-seg > i{display:block; height:100%; width:100%; transform-origin:left center; background:linear-gradient(#8ee87a,#3aa84a); transition:scale .35s ease;}
.bhp-bar.foe .bhp-seg > i{background:linear-gradient(#ef7a72,#c93a22); margin-left:auto; transform-origin:right center;}   /* fill hugs the RIGHT — damage breaks off the LEFT edge, like the classics */
.bhp-bar.low .bhp-seg > i{animation:pulse .55s infinite;}   /* low HP PULSES but never changes colour — yours stays GREEN, theirs stays RED */
.hpnum{flex:none; font-family:var(--fontD); font-size:11px; color:var(--cream); align-self:center; padding:0 4px; text-shadow:1px 1px 0 #000; letter-spacing:.5px;}   /* 256 per bar — the ACTIVE bar's count, timer font, riding the bar line */
#stage.targeting{cursor:crosshair;}
/* (the DROP YOUR PIECE banner is retired — the drag hint toast covers it) */
.vsname{font-family:var(--fontD); letter-spacing:1px;}
/* event race bar */
#raceWrap{position:absolute; top:6px; left:8px; right:8px; z-index:25; display:none;}
#raceWrap.on{display:block;}
.racebar{height:13px; background:var(--cream); border:2px solid var(--ink); position:relative; margin-bottom:3px;}
.racefill{height:100%; transition:width .3s;}
.racelabel{font-size:12px; letter-spacing:1px; text-transform:uppercase;}
/* ---------------- pack opening ---------------- */
#packStage{
  flex:1; display:flex; flex-direction:column; align-items:center; justify-content:flex-start;
  position:relative; gap:12px; z-index:5; padding:12px 14px 28px; overflow-y:auto; min-height:0;
}
#packStage::-webkit-scrollbar{width:5px} #packStage::-webkit-scrollbar-thumb{background:var(--ink)}
.packbox{
  width:150px; height:200px; background:var(--red); border:4px solid var(--ink);
  box-shadow:7px 7px 0 var(--ink); cursor:pointer; position:relative;
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  transition:transform .2s var(--pop); color:var(--cream); text-align:center;
}
.packbox:hover{transform:scale(1.06) rotate(-2deg);}
.packbox.gold{background:var(--gold); color:var(--ink);}
.packbox .pname{font-family:var(--fontD); font-size:19px; line-height:1.1; padding:0 8px;}
.packbox .pprice{margin-top:10px; font-size:17px; background:var(--ink); color:var(--cream); padding:3px 12px; transform:skewX(-8deg);}
.packbox.shaking{animation:packShake .55s ease-in-out infinite;}
@keyframes packShake{0%,100%{transform:rotate(0)}20%{transform:rotate(-5deg) scale(1.04)}60%{transform:rotate(5deg) scale(1.06)}}
.burst{
  position:absolute; inset:-30%; pointer-events:none; z-index:1; opacity:0;
  background:repeating-conic-gradient(from 0deg, #d9a23255 0 12deg, transparent 12deg 24deg);
  animation:burstSpin 1.2s linear infinite;
}
.burst.on{opacity:1;}
@keyframes burstSpin{to{transform:rotate(30deg)}}
/* ---- pack-tile glitch art (#28/#29) ---- */
.pkglitch{position:absolute; inset:0; pointer-events:none; z-index:1; opacity:.45; mix-blend-mode:overlay;
  background:repeating-linear-gradient(0deg,#0000 0 3px,#00000022 3px 6px); animation:pkgScan 3s linear infinite;}
@keyframes pkgScan{to{background-position:0 60px;}}
.pkglitch::after{content:''; position:absolute; left:0; right:0; height:9px; top:30%; mix-blend-mode:screen;
  background:linear-gradient(90deg,#ff0040aa,transparent 45%,transparent 55%,#00e6ffaa); animation:pkgSlice 2.6s steps(1,end) infinite;}
@keyframes pkgSlice{0%,72%{opacity:0; top:18%}74%{opacity:.85; top:42%}77%{opacity:0}80%{opacity:.8; top:66%}83%,100%{opacity:0; top:80%}}
/* ---- shop miniature-card racks (#29) ---- */
.shoprack{display:flex; gap:6px; justify-content:center; flex-wrap:wrap; margin-top:5px;}
.shopcard{width:78px; display:flex; flex-direction:column; align-items:center; gap:3px; cursor:pointer;}
.shopcard .card{width:78px;}
.buycard .card{width:112px; margin:0 auto;}   /* the expanded pick inside the info box */
.shopcard .card .nm{font-size:10px; min-height:15px; padding:2px 1px 1px; line-height:1;}
.shopcard .card .stats{font-size:10px; padding:0 3px 4px;}
.shopcard .card .cost{font-size:10px; padding:2px 4px;}
.shopcard .card .rar{font-size:7px; letter-spacing:.5px;}
.shopcard .card .lvl,.shopcard .card .cnt,.shopcard .card .upchip{font-size:8px;}
.shopcard .card .dbar{height:10px;}
.shopcard .card .dbar>b{font-size:8px;}
.shopcard .ptag{font-family:var(--fontD); font-size:11px; background:var(--ink); color:var(--cream); padding:1px 7px; transform:skewX(-7deg); white-space:nowrap; line-height:1.5;}   /* compact: icon ×N, nothing more */
.shopcard.leg .ptag{background:var(--gold2); color:var(--ink);}
.shopcard .sold{width:90px; aspect-ratio:5/7; border:2px dashed var(--ink); opacity:.4; display:flex; align-items:center; justify-content:center; font-size:11px;}
.wardbtn{display:flex; align-items:center; gap:9px; background:var(--gold); color:var(--ink); border:3px solid var(--ink);
  box-shadow:4px 4px 0 var(--ink); padding:7px 16px; margin:10px auto; cursor:pointer; font-family:var(--fontD); font-size:15px; transition:transform .16s var(--pop);}
.wardbtn:hover{transform:scale(1.05) rotate(-1deg);}
.wardbtn svg{flex:none;}
.wardbtn.big{font-size:19px; padding:13px 26px; box-shadow:6px 6px 0 var(--ink); border-width:4px;}   /* the boutique gets a MARQUEE-sized door */
.wardbtn.big svg{transform:scale(1.5);}
.ptag .ptzap{position:absolute; right:-13px; top:-14px; width:30px; height:30px; pointer-events:none;}
.ptag .ptzap .ptz-txt{position:absolute; inset:0; display:flex; align-items:center; justify-content:center; font-family:var(--fontD); font-size:5.5px; color:var(--ink); transform:rotate(-12deg);}
.reveal-row{display:flex; gap:10px; flex-wrap:wrap; justify-content:center; perspective:700px;}
.reveal-row .card{width:88px; animation:flipIn .55s var(--pop) backwards;}
.pname,.pprice{font-family:var(--fontD);}
.card.r4{position:relative; overflow:hidden;}
/* ⭐ FRAME LAW v3 — REMOVED: a whole-card gold shine (.card.r4::after) and an epic inner glow (.card.r3::after).
   `::after` on .card is NOT free — it draws the horizontal edge of the top-right GB notch. These two rules
   overwrote it, so epic cards had their corner edge shoved to (0,0) and legendary cards lost it entirely
   (the overlay is transparent) — which is exactly why gold and silver borders read as THINNER than a common
   card's black one at the top-right. Rarity is frame COLOUR only now, per canon; legendaries still shine via
   the .art::after / .rar::after sweep above, which sits on its own elements and touches no border. */
.pity{font-size:14px; letter-spacing:1px; background:var(--cream); border:2px solid var(--ink); padding:4px 12px; transform:skewX(-6deg);}
.pitymini{display:flex; justify-content:center; gap:10px; margin-bottom:8px; font-family:var(--fontD); font-size:10px; color:var(--ink);}
.pitymini span{display:inline-flex; align-items:center; gap:3px; background:var(--cream); border:2px solid var(--ink); padding:2px 8px; box-shadow:1px 1px 0 #0006;}
.pm-ico{width:12px; height:12px;} .pm-ico svg{width:100%; height:100%;}
.pm-dia{width:8px; height:8px; background:var(--gold2); border:1px solid var(--ink); transform:rotate(45deg); display:inline-block;}
/* singles price tag — grocery-store style with a ZAP starburst bubble */
.ptag{position:relative;}
.ptag .ptzap{position:absolute; right:-9px; top:-9px; width:22px; height:22px; pointer-events:none;}
.ptag .pt-ink{display:inline-block; width:12px; height:12px; vertical-align:-2px; margin-right:2px;} .ptag .pt-ink svg{width:100%; height:100%; display:block;}   /* inline-block — the icon obeys its 12px now (no more giant stars) */
@keyframes flipIn{from{transform:rotateY(95deg) scale(.7)} to{transform:none}}
/* ---------------- missions ---------------- */
.mission{
  display:flex; align-items:center; gap:12px; background:var(--cream);
  border:3px solid var(--ink); box-shadow:4px 4px 0 #1b151077; padding:11px 13px;
  transition:transform .15s var(--pop);
}
.mission:nth-child(odd){transform:rotate(-.6deg);}
.mission:nth-child(even){transform:rotate(.6deg);}
.mission .mdone{color:var(--teal); font-family:var(--fontD);}
/* ⚠ v0.404 — A GIG'S WORDS MUST NOT RUN OUT OF ITS BOX. "THE ODD fin…" and "another ro…" in
   Odaroo's screenshot were both this: a flex child with no min-width cannot shrink below its
   content, so the description pushed itself past the card's edge instead of wrapping inside it. */
/* ⭐ v0.404 — a gig section heading is a TITLE with its explanation on a second line, not one long
   run of display type that walks off the right of a 375px screen */
.gig-sec{font-family:var(--fontD); font-size:calc(12px * var(--gs,1)); line-height:1.25;
  padding:calc(4px * var(--gs,1)) calc(2px * var(--gs,1)) calc(3px * var(--gs,1));
  overflow-wrap:anywhere;}
.gig-sec span{display:block; font-size:calc(8px * var(--gs,1)); opacity:.65; letter-spacing:0; margin-top:calc(2px * var(--gs,1));}
.mission>div{min-width:0;}
.mission>div>div{overflow-wrap:anywhere; word-break:break-word;}
.mbar{height:9px; background:var(--paper3); border:2px solid var(--ink); margin-top:5px;}
.mfill{height:100%; background:var(--teal); transition:width .4s var(--pop);}
.mission .btn{flex:none;}
/* streak */
.streak-row{display:flex; gap:5px; justify-content:center; margin:10px 0;}
#scr-gigs{background:repeating-linear-gradient(45deg,#f6ead0 0 26px,#efe2c5 26px 52px);}
.gigParade{display:flex; gap:9px; justify-content:center; padding:5px 0 2px; position:relative; z-index:5;}
#gigsList .mission{border-left:6px solid #3f7d4e;}   /* uniform — no red/blue alternation */
.sday{
  width:52px; height:76px; border:2px solid var(--ink); background:var(--cream);
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  font-size:12px; gap:2px; overflow:hidden;
}
.sday-row{display:flex; align-items:center; gap:2px;}
.sday-star{display:flex; align-items:center; gap:1px; font-size:11px; font-weight:bold; color:var(--gold2);}
.sday b{font-family:var(--fontD); font-size:14px; line-height:1;}
.sday-ico{width:13px; height:13px; display:block;}
.sday-ico svg{width:100%; height:100%;}
.sday-amt{font-size:8px; font-weight:bold; letter-spacing:-.3px; white-space:nowrap; line-height:1;}
.sday-r{font-size:7px; opacity:.75; line-height:1;}
.sday.got{background:var(--teal); color:var(--cream);}
.sday.today{background:var(--gold); border-width:3px; transform:scale(1.14); box-shadow:3px 3px 0 var(--ink);}   /* gold & big — but it only BREATHES while the claim is live (.claimme) */
.sday.got{position:relative;}
.sday.got b{font-size:18px; width:21px; height:21px; border:2px solid currentColor; display:flex; align-items:center; justify-content:center; margin:0 auto 1px; background:#ffffff22; line-height:1;}   /* claimed = a real CHECKBOX with a BIG check, and it sits STILL */
/* ---------------- title screen ---------------- */
#scr-title{grid-template-rows:1fr auto 1fr; justify-items:center; padding-bottom:0; gap:0;}   /* the WORDMARK owns the true centre — equal halves above and below, both folds */
#scr-title.on{display:grid;}   /* grid ONLY while showing — the !important that beat .screen{display:none} leaked the title backdrop everywhere */
#scr-title .t-top{align-self:end; display:flex; flex-direction:column; align-items:center; gap:4px; z-index:5; padding-bottom:8px; min-height:0;}
#scr-title .t-bot{align-self:start; display:flex; flex-direction:column; align-items:center; z-index:5; padding-top:8px; min-height:0;}
@media (max-height:700px){ #titleStartBtn{font-size:16px!important; padding:8px 30px!important;} #titleAce{width:120px!important; height:125px!important;} }   /* short screens: everything still clears the pad */
#logoWrap{z-index:5; position:relative; padding:10px 0; overflow:visible; width:100%; text-align:center;}   /* visible so the wordmark is never clipped on wide (Fold) screens */
.logo-stack{position:relative; display:block; width:fit-content; max-width:100%; margin:0 auto;}   /* fit-content, or the version tag right-aligns to the SCREEN instead of to the wordmark */
#scr-title .logo-stack .subtitle{width:auto!important; padding:0!important;}   /* beats #scr-title .subtitle{width:100%} — a 100% child would stretch the fit-content stack */
/* ⭐ v0.726 — the title block is ONE CENTRED column: INKVILLE, the tagline tucked up under it, then
   the version tag centred under both (it hung on the RIGHT from v0.719 until Odaroo asked for all
   three lines centred, 2026-08-06). The version is in the FLOW (it used to be absolutely positioned
   off the h1) so the tagline can sit between the two without the tag landing on top of it. */
.logo-ver{display:block; text-align:center; margin-top:1px; padding-right:0; font-family:var(--fontD); font-size:9px; color:var(--ink); opacity:.7; letter-spacing:1px; text-shadow:1px 1px 0 var(--paper3);}
#scr-title .logo-stack .subtitle{margin-top:4px;}   /* the tagline rides CLOSE to the wordmark — but never closer than the wordmark's own 4px drop-shadow */
.glogo{position:relative; display:block; font-family:var(--fontD); font-size:40px; color:var(--ink);
  letter-spacing:2px; text-shadow:4px 4px 0 var(--paper3); animation:glMain 4.2s steps(1) infinite;}
.glogo::before,.glogo::after{content:attr(data-t); position:absolute; left:0; top:0; text-shadow:none;}
/* ⚠⚠ v0.726 — NOTHING IS PAINTED BEHIND INKVILLE (Odaroo, 2026-08-06). The RGB split painted a red
   copy of the wordmark one layer down (killed in v0.725) and a teal one (killed here); on the phone
   they read as a coloured glow behind the letters. BOTH split layers are gone for good — the
   wordmark is the letters and nothing else. Do not restore either one. */
.glogo::before,.glogo::after{display:none!important;}
@keyframes glA{0%,88%{transform:translate(0,0)} 89%,93%{transform:translate(3px,-2px)} 94%,100%{transform:translate(-2px,1px)}}
@keyframes glB{0%,82%{transform:translate(0,0)} 83%,88%{transform:translate(-3px,2px)} 89%,100%{transform:translate(2px,-1px)}}
@keyframes glMain{0%,91%{transform:none} 92%,93%{transform:translateX(2px) skewX(2deg)} 94%,95%{transform:translateX(-2px)} 96%,100%{transform:none}}
/* on wider screens (Fold unfolded etc.) the RGB-split glitch layers fragment the wordmark — show a clean solid INKVILLE instead */
@media (min-width:520px){
  .glogo::before,.glogo::after{display:none!important;}
  .glogo{animation:none!important;}
}
/* ⚠⚠ v0.832 — THE SCAN LINE IS PAINTED, NOT MOVED. It used to animate `top` from 6% to 96%, and
   `top` is a LAYOUT property: the title screen was re-solving the whole page 60 times a second for
   this one 3px line, permanently. (Same fault, same build, as `#scratch` and the mascot's breath —
   see the long note beside `.inkpng` in css/base.css.)
   ⚠ It is a background-position animation rather than a transform because the travel is a
   percentage of the PARENT's height, and a transform percentage resolves against the element's own
   3px box. Moving the paint instead is exactly what `hudFilmRoll` already does in this game, and it
   costs paint only — no layout. The band is now the gradient; the box is the whole logo. */
#logoWrap::after{content:''; position:absolute; left:10%; right:10%; top:6%; bottom:4%;
  background:linear-gradient(#fdf6e3,#fdf6e3) no-repeat; background-size:100% 3px;
  opacity:.35; animation:logoscan 3.2s linear infinite; pointer-events:none;}
@keyframes logoscan{from{background-position:0 0%}to{background-position:0 100%}}
#scr-title .title-xl{z-index:5; animation:popIn .7s var(--pop);}
.rmarchrow{display:flex; justify-content:center; gap:7px; overflow:hidden; min-height:40px;}
.rmarch{animation:marchBob .55s steps(2) infinite;}
@keyframes marchBob{50%{transform:translateY(-4px)}}
#scr-title{justify-content:center; text-align:center;}
#scr-title .tiny,#scr-title .subtitle{width:100%; padding:0 12px; text-align:center;}
/* ⭐ v0.725 — the wordmark is 110% of what it was (26/9vw/58 → 28.6/9.9vw/63.8): INKVILLE is the
   flagship and must be the biggest thing on the sign. ⚠ 9.9vw is close to the ceiling on a 375px
   phone — "INKVILLE" is 8 glyphs of a ~1.11em-wide face plus 2px of tracking, i.e. ~344px of a
   351px usable line. Do not raise it further without re-measuring that. */
h1.glogo{font-size:clamp(28.6px,9.9vw,63.8px)!important; line-height:1.15; word-break:keep-all;}
.bar-title{max-width:70%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;}
.topbar{position:relative; z-index:40;}
#titleAce{width:152px; height:158px; margin:0 auto 4px; z-index:4; position:relative;   /* NO top margin — centering gives the crown its headroom, nothing ever crops */
  animation:aceFloat 3.4s ease-in-out infinite;}   /* sits a touch LOWER now — the bulbs land underneath */
/* the BULB FRAME — the EXACT five-dot row under the inklet, copy-pasted back-to-back around the whole screen.
   Dots are REAL elements laid by buildTitleFrame() to fit the edges exactly — never cut off, Fold 6 or desktop. DEFAULT look. */
#titleFrame{position:absolute; inset:4px; z-index:6; pointer-events:none;}
#titleFrame .tfb{position:absolute; width:10px; height:10px; background:var(--gold); animation:pulse .9s infinite;}
#titleFrame .tfb.r{background:var(--red); animation-delay:.45s;}
/* ⭐ v3.67 — THE FRAME NOW HUGS THE SCREEN, exactly like the title screen's. It used to run from y:66 down
   to the D-pad, so it wrapped the GAME TILES rather than the screen — and its top bulb row landed straight
   on the welcome line, punching holes through the text. inset:4px puts it on the true screen perimeter
   (clear of the reel), and z-index 63 lets the bottom row read along the very bottom edge instead of
   vanishing under the translucent D-pad. Stays pointer-events:none, so it can never intercept a tap. */
#homeFrame{position:fixed; inset:4px; z-index:7; pointer-events:none;}   /* BELOW the D-pad (62) — the pad draws over the bottom run, exactly as on the title screen, so no bulb ever sits on a button */
#homeFrame .hfb{position:absolute; width:10px; height:10px; background:var(--gold); animation:pulse .9s infinite;}
#homeFrame .hfb.r{background:var(--red); animation-delay:.45s;}
/* a warmer marquee glow behind the menu.
   ⭐⭐⭐ v0.859 — THE WARMTH IS BAKED INTO THE TWO COLOURS, NOT APPLIED AS A `filter`.
   `.sunburst` is `inset:-65%` — measured at 3,777,302px, by a wide margin the largest surface in
   the game. ⚠⚠ IT NO LONGER SPINS: v0.887 deleted `spinSlow` from it, because a ~34M device-pixel
   texture animating for ever is the largest compositor bill on the phone and a 90s rotation is
   imperceptible. The filter rule below still stands and still matters. A `filter`
   on an element whose transform is animating is a COMPOSITING BLOCKER: Blink cannot hand the
   rotation to the GPU and must re-rasterise that whole surface on the main thread, every frame,
   for the life of the screen. The filter here was `saturate(1.05) brightness(1.02)` — a 5% and a
   2% whisper — so it is expressible exactly as two hex values, run through the filter spec's own
   saturation matrix. The pixels are identical; the raster is not.
   ⚠⚠ DO NOT PUT A `filter` BACK ON THIS ELEMENT. If the tone needs changing, change these two
   colours. Any filter at all re-imposes the whole cost, however gentle it looks written down. */
#scr-home .sunburst{--paper:#f7eacc; --paper2:#eedcb4;}
#scr-home::after{content:''; position:absolute; inset:0; z-index:0; pointer-events:none; background:radial-gradient(120% 80% at 50% 8%, #f4c5421a, transparent 55%), linear-gradient(#00000000 60%, #2a17110d);}
#titleAce svg{width:100%; height:100%; image-rendering:pixelated; filter:drop-shadow(0 0 10px #7ab6ff99) drop-shadow(3px 3px 0 #1b1510);}
#titleAce.tgl{animation:titleGl .16s steps(2) 1;}
@keyframes aceFloat{0%,100%{transform:translateY(0)}50%{transform:translateY(-8px)}}
@keyframes titleGl{0%{transform:translateX(-4px) skewX(5deg); filter:hue-rotate(120deg) saturate(2.4)}50%{transform:translateX(4px) skewX(-4deg); filter:hue-rotate(-70deg) saturate(1.8)}100%{transform:none}}
#glitchMoon{position:absolute; width:52px; height:52px; z-index:4; cursor:pointer;
  left:calc(50% - 118px); top:26%; opacity:.7; animation:moonTwitch 5s steps(1) infinite;}
@keyframes moonTwitch{0%,92%{transform:translate(0,0)}93%{transform:translate(-3px,1px)}96%{transform:translate(2px,-1px)}98%{transform:translate(0,0)}}
#marquee{
  position:absolute; top:0; left:0; right:0; background:var(--ink); color:var(--gold);
  font-family:var(--fontD); font-size:17px; letter-spacing:2px; padding:7px 0;
  white-space:nowrap; overflow:hidden; z-index:6;
}
#marquee span{display:inline-block; animation:mq 36s linear infinite; padding-left:100%;}
#scr-title .bulbs{margin-top:6px;}

/* ⭐ v0.875 — THE DISCORD HINT (top-right of the title screen, and only there).
   ⚠⚠ It is anchored off `--sat`, the SAFE-AREA TOP inset, exactly as #app's padding is — on
      Android that inset IS the status bar, and a fixed 8px would put the badge under it in
      Chrome's fullscreen. (`--sat` here is the inset; css/games.css's `--sat` on #superSky is a
      saturation filter — different variable, different scope, do not tidy the two into one name.)
   ⚠ It is `position:absolute` inside the title's grid, so it takes no row and cannot push the
      wordmark off the true centre the grid rows exist to protect.
   ⭐ v0.895 — ONE INSET ON EVERY FOLD, CLEAR OF THE FRAME (Odaroo, 2026-09-22). The dotted
      frame is `#titleFrame{inset:4px}` with 10px squares, so the band runs 4..14px from the
      edge; the badge used to sit at 14px (10px on a screen under 700px tall — i.e. INSIDE the
      band on the folded Fold 8). `--tdgap` is the same 24px on both folds: 10px of clear paper
      between the ring and the frame, and the badge is the same size everywhere.
   ⭐ v0.895 — THE RING FLIPS AROUND THE LOGO, the way the boot cartridge (`.ick-spin`,
      css/base.css) turns around its still ink drop: the ring is the `::before` box spinning on
      rotateY under a perspective, and the logo is a flat sibling over the axis that never moves.
      ⚠⚠ The ring is an HTML box, NOT the <svg> and nothing inside it (v0.832), it carries NO
      filter (v0.859 — the shadow is a box-shadow, which is paint, not a filter), and it has a
      reduced-motion block so SMOOTH MODE reaches it (v0.887). The v0.859 line that used to
      forbid any never-ending animation here is superseded by this one, measured: the ring is a
      56px box, not a 3.7-million-pixel surface. */
#titleDisc{--tdgap:24px; --tdsz:56px; position:absolute; z-index:6;
  top:calc(var(--tdgap) + var(--sat,0px)); right:var(--tdgap);
  width:var(--tdsz); height:var(--tdsz); display:flex; align-items:center; justify-content:center;
  perspective:220px; opacity:.78; cursor:pointer;
  -webkit-tap-highlight-color:transparent; transition:opacity .18s, translate .12s;}
#titleDisc::before{content:''; position:absolute; inset:0; border-radius:50%;
  border:2px solid var(--ink); background:var(--paper2); box-shadow:2px 2px 0 var(--ink);
  animation:tdFlip 3.6s linear infinite;}
@keyframes tdFlip{from{transform:rotateY(0deg)}to{transform:rotateY(360deg)}}
#titleDisc svg{position:relative; z-index:1; width:32px; height:32px; display:block; fill:var(--ink);}
#titleDisc:hover,#titleDisc:focus-visible{opacity:1;}
#titleDisc:active{opacity:1; translate:1px 1px;}
@media (prefers-reduced-motion:reduce){ #titleDisc::before{animation:none;} }
@keyframes mq{to{transform:translateX(-200%)}}
.bulbs{display:flex; gap:9px; z-index:5;}
.bulb{width:10px;height:10px;border-radius:50%;background:var(--gold);animation:pulse 0.9s infinite;}
.bulb:nth-child(2n){animation-delay:.45s; background:var(--red);}
/* misc */
.row{display:flex; align-items:center; gap:8px;}
.spacer{flex:1;}
.center{text-align:center;}
.tiny{font-size:13px; letter-spacing:1px; opacity:.75;}
.divider{border-top:3px dashed var(--ink); opacity:.35; margin:12px 0;}
/* ============================================================
   ⭐ v0.454 — THE OPTIONS CARD KEEPS ITS BUTTONS INSIDE IT.
   Odaroo photographed the red BACK button stepping out of the bottom of the dialog frame on the
   unfolded screen. The card is a scroll area with a fixed max height; the buttons are 54px each
   plus gaps, and the sliders above them grow with the screen — so on a taller layout the stack
   simply ran past the frame instead of the frame giving way.
   ⚠ width:88% ON A BUTTON IS NOT THE SAME AS FITTING. It was already 88% WIDE; what escaped was the
   bottom edge. Height is the axis that was never bounded.
   ============================================================ */
#modalBox .btn.optbig{width:88%; max-width:100%; flex:0 0 auto;}
#modalBox .btn.optbig:last-of-type{margin-bottom:4px;}
/* the dialog's own contents may scroll, but the last button must never be cut off by the frame */
#modalBox .center{padding-bottom:2px;}

/* ============================================================
   ⭐⭐ v0.518 — THE GIGS SHEET FILLS THE UNFOLDED SCREEN
   Same story as the badge wall (see the block at the end of css/hub.css): --gs is a device-pixel
   correction and reads 1 on both folds, so a screen you only LOOK at has to key its type on the
   viewport width or the unfolded Fold shows the folded phone's layout with empty margins.
   ============================================================ */
.m-desc{font-size:calc(12px * var(--gs,1)); font-weight:bold; line-height:1.3;}

@media (min-width:640px){
  /* the sheet is centred and given a readable measure instead of one thin column of paper */
  #gigsList{max-width:min(1080px, 94%); margin:0 auto; width:100%;}
  .gig-sec{font-size:calc(20px * var(--gs,1)); padding:calc(7px * var(--gs,1)) calc(4px * var(--gs,1)) calc(5px * var(--gs,1));}
  .gig-sec span{font-size:calc(12px * var(--gs,1));}
  .mission{gap:calc(18px * var(--gs,1)); padding:calc(16px * var(--gs,1)) calc(19px * var(--gs,1));
    border-width:calc(4px * var(--gs,1));}
  .m-desc{font-size:calc(17px * var(--gs,1));}
  .mission .tiny{font-size:calc(12px * var(--gs,1));}
  .mission .mdone{font-size:calc(15px * var(--gs,1));}
  .mbar{height:calc(13px * var(--gs,1)); margin-top:calc(7px * var(--gs,1));}
  .gigParade{gap:calc(14px * var(--gs,1)); padding:calc(8px * var(--gs,1)) 0 calc(4px * var(--gs,1));}
  .sday{width:calc(74px * var(--gs,1)); height:calc(108px * var(--gs,1)); font-size:calc(16px * var(--gs,1));}
}
