:root {
  --pants: #372e64;        /* leg color (the legs are drawn, not images) */
  --pants-cuff: #3c3369;   /* rolled cuff color */
  --skin-arm: #ffcfa6;     /* arm color */
  --bg: #111111;
  --ink: #f3ece0;
  --muted: #b9ae9c;
  --coral: #D85A30;
  --line: #3a352e;
  --outline: #151515;
  --iris: #2e5aa8;
  --lid-l: #f2b088;   /* matches the lit left side of the face */
  --lid-r: #e0a27b;   /* matches the shaded right side */
}
* { box-sizing: border-box; }
html, body { height: 100%; }
body { margin: 0; background: var(--bg); color: var(--ink); font-family: "Archivo", system-ui, sans-serif; overflow: hidden; }
h1 { position: fixed; top: 1rem; left: 1.25rem; margin: 0; font-size: 1.1rem; font-weight: 800; z-index: 4; pointer-events: none; }
h1 span { color: var(--coral); }

/* ===== STAGE: a 16:9 world that fits the window; place everything in % ===== */
.viewport {
  position: fixed; inset: 0; display: grid; place-items: center;
  container-type: size; transition: right 0.35s cubic-bezier(.3,1,.4,1);
}
.scene {
  position: relative; width: min(100cqw, calc(100cqh * 16 / 9)); aspect-ratio: 16 / 9;
  background: var(--scene-bg, #1d1d21); overflow: hidden;
}
.scene.show-bounds { outline: 2px dashed var(--coral); outline-offset: -2px; }

/* ===== RESPONSIVE: 16:9 on wide screens, 9:16 on tall ones (phones, narrow windows).
   Sizes inside the stage use cqmin (1% of the stage's SHORT side), so on a wide stage they
   are the same as before and on a tall stage everything scales to the width.
   --fit shrinks Sammie's box on the tall stage so he is the same size compared with its width.
   Positions stay in % of the stage, so left/right placement and walks just work. ===== */
.scene { --fit: 1; --ground: 100%; }
@container (aspect-ratio < 1) {
  /* --ground: where the bottom of the world sits on the tall stage (lower it to give Sammie more sky) */
  /* --wu: world unit. 1.2 makes Sammie and his bubble 20% bigger on phones. */
  .scene { width: min(100cqw, calc(100cqh * 9 / 16)); aspect-ratio: 9 / 16; --fit: 0.5625; --ground: 84%; --wu: 1.2cqmin; }
}
.world { position: absolute; left: 0; right: 0; bottom: calc(100% - var(--ground)); height: calc(100 * var(--wu, 1cqmin)); }

/* ===== ACTOR: a 1:1 box anchored at his feet.
   --x = % across the stage, --y = % down the stage (where his feet touch),
   --size = box height as % of the stage height ===== */
.actor {
  position: absolute; left: var(--x, 50%); top: var(--y, 92%); height: calc(var(--size, 80%) * var(--fit, 1));
  aspect-ratio: 1 / 1; transform: translate(-50%, -100%) scaleX(var(--facing, 1));
  transition-property: left, top, height; transition-duration: var(--move-ms, 0ms);
  transition-timing-function: var(--move-ease, ease-in-out);
}
.actor svg { width: 100%; height: 100%; display: block; overflow: visible; }
.scene.show-bounds .actor { outline: 1px dashed rgb(243 236 224 / 0.5); }

/* slide-in control panel */
.panel-toggle { position: fixed; top: 1rem; right: 1rem; z-index: 6; padding: 0.55rem 1rem; }
.panel {
  position: fixed; top: 0; right: 0; bottom: 0; width: min(20rem, 100%); z-index: 5;
  display: grid; gap: 1rem; align-content: start; overflow-y: auto;
  padding: 4.5rem 1.25rem 2rem; background: rgb(17 17 17 / 0.97); border-left: 2px solid var(--line);
  transform: translateX(100%); visibility: hidden;
  transition: transform 0.35s cubic-bezier(.3,1,.4,1), visibility 0s linear 0.35s;
}
.panel.open { transform: none; visibility: visible; transition: transform 0.35s cubic-bezier(.3,1,.4,1), visibility 0s; }
@media (min-width: 900px) { body.panel-open .viewport { right: 20rem; } }   /* wide screens: keep the scene in view */
@media (prefers-reduced-motion: reduce) { .panel, .panel.open, .viewport, .actor { transition: none; } }

.panel h2 { margin: 0 0 0.4rem; font-size: 0.75rem; letter-spacing: 0.18em; text-transform: uppercase; color: var(--muted); }
.range { display: grid; grid-template-columns: 3.5rem 1fr 2.5rem; align-items: center; gap: 0.5rem; font-size: 0.85rem; margin-bottom: 0.35rem; }
.range input { width: 100%; accent-color: var(--coral); }
.range output { color: var(--muted); text-align: right; }
.btns { display: grid; grid-template-columns: 1fr 1fr; gap: 0.4rem; }
button, .file {
  font: 600 0.9rem "Archivo", sans-serif; padding: 0.6rem 0.5rem;
  background: var(--bg); color: var(--ink); border: 2px solid var(--ink); cursor: pointer; text-align: center;
}
button:hover, .file:hover { background: var(--ink); color: var(--bg); }
button[aria-pressed="true"] { background: var(--coral); border-color: var(--coral); color: #fff; }
button:focus-visible, .file:focus-within { outline: 3px solid var(--coral); outline-offset: 2px; }
.file { display: block; grid-column: 1 / -1; }
.file input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.hint { margin: 0; font-size: 0.8rem; color: var(--muted); line-height: 1.4; }
.meter { height: 8px; background: var(--line); }
.meter i { display: block; height: 100%; width: 0; background: var(--coral); }

/* ===== RIG (viewBox units = image pixels, 559 x 1229) ===== */

#pupils { transform: translate(var(--lx, 0px), var(--ly, 0px)); transition: transform 0.25s ease; }
.lid { transform: scaleY(var(--lid, 1)); transition: transform 0.09s linear; }
#lidL { transform-origin: 247px 206px; }
#lidR { transform-origin: 347px 206px; }
.brow { transform: translateY(var(--by, 0px)) rotate(var(--br, 0deg)); transition: transform 0.2s ease; }
#browL { transform-origin: 245px 192px; }
#browR { transform-origin: 348px 192px; }

.mouth { display: none; }
#rig[data-mouth="rest"] #m-rest,
#rig[data-mouth="press"] #m-press,
#rig[data-mouth="side"] #m-side,
#rig[data-mouth="frown"] #m-frown,
#rig[data-mouth="small"] #m-small,
#rig[data-mouth="wide"] #m-wide,
#rig[data-mouth="oo"] #m-oo,
#rig[data-mouth="ee"] #m-ee,
#rig[data-mouth="grin"] #m-grin,
#rig[data-mouth="sleepy"] #m-sleepy,
#rig[data-mouth="laugh"] #m-laugh,
#rig[data-mouth="teeth"] #m-teeth,
#rig[data-mouth="wobble"] #m-wobble,
#rig[data-mouth="bleh"] #m-bleh,
#rig[data-mouth="pucker"] #m-pucker { display: inline; }

#eyesHappy { display: none; }
#rig[data-eyes="happy"] #eyesHappy { display: inline; }
#rig[data-eyes="happy"] #eyesOpen { display: none; }
.iris { transform-box: fill-box; transform-origin: center; transform: scale(var(--ps, 1)); transition: transform 0.15s ease; }

/* mouth drifts side to side between phrases; no transition = cutout snap */
#mouths { transform: translateX(var(--mx, 0px)); }


/* face shifts toward where he looks, so it reads as a head turn */
#face, #faceFront { transform: translate(var(--fx, 0px), var(--fy, 0px)); transition: transform 0.28s cubic-bezier(.3,1.3,.5,1); }

/* ===== HEAD ===== */
#head, #headFront { transform-origin: 294px 446px; transform: rotate(var(--tilt, 0deg)) translateY(var(--nod, 0px));
        transition: transform 0.3s cubic-bezier(.3,1.4,.5,1); }

/* ===== ARMS ===== */
#handL > .h, #handR > .h { transform: scale(var(--hs, 0.86)); transform-origin: 0 0; }
#handL > .h-rest, #handR > .h-rest { transform: scale(0.62, 0.84); }
/* ===== BODY (drawn): shirt, collar, pants seat ===== */
#rig { --shirt: #e03432; }
.shirt-body { fill: var(--shirt); }
.seat { fill: var(--pants); }
.collar { fill: none; stroke: var(--shirt); stroke-width: 11; stroke-linecap: round; filter: brightness(0.82); }
.sleeve .hem { fill: none; stroke: rgb(0 0 0 / 0.18); stroke-width: 3; stroke-linecap: round; }
.legtube { fill: none; stroke: var(--pants); stroke-width: 72; stroke-linecap: butt; stroke-linejoin: round; }
.pantcuff { fill: none; stroke: var(--pants-cuff); stroke-width: 78; stroke-linecap: butt; }
.pantcuff-line { fill: none; stroke: rgb(0 0 0 / 0.35); stroke-width: 3; stroke-linecap: butt; }
.tube { fill: none; stroke: var(--skin-arm); stroke-width: 46; stroke-linecap: round; stroke-linejoin: round; }
.h { display: none; }
#rig[data-hl="rest"] #handL .h-rest, #rig[data-hr="rest"] #handR .h-rest,
#rig[data-hl="open"] #handL .h-open, #rig[data-hr="open"] #handR .h-open,
#rig[data-hl="point"] #handL .h-point, #rig[data-hr="point"] #handR .h-point,
#rig[data-hl="thumbs"] #handL .h-thumbs, #rig[data-hr="thumbs"] #handR .h-thumbs,
#rig[data-hl="fist"] #handL .h-fist, #rig[data-hr="fist"] #handR .h-fist,
#rig[data-hl="point2"] #handL .h-point2, #rig[data-hr="point2"] #handR .h-point2,
#rig[data-hl="thumbs2"] #handL .h-thumbs2, #rig[data-hr="thumbs2"] #handR .h-thumbs2 { display: inline; }

@media (prefers-reduced-motion: reduce) {
  #body { animation: none; }
  #pupils, .lid, .brow { transition: none; }
}


/* =====================================================================
   BUBBLE: pink soap bubble, a pure circle via clip-path.
   --d = diameter as % of the stage height; left/top place its center.
   bubble.js drives all of these each frame.
   ===================================================================== */
.scene { container-type: size; }
.bubble {
  --d: 60;
  position: absolute; left: 50%; top: 50%;
  width: calc(var(--d) * var(--wu, 1cqmin)); aspect-ratio: 1 / 1;
  transform: translate(-50%, -50%);
  clip-path: circle(50% at 50% 50%);
  will-change: transform, left, top, width;
}
/* Sammie inside: centered so his feet clear the curve of the bubble */
.bubble .actor { --x: 50%; --y: 91%; --size: 80%; --fit: 1; transform: translate(-50%, -100%) rotate(var(--sway, 0deg)) scaleX(var(--facing, 1)); transform-origin: 50% 100%; }
.bubble .ground-shadow { display: none; }

/* tint behind him */
.bubble-back {
  position: absolute; inset: 0; border-radius: 50%;
  background: radial-gradient(circle at 50% 55%,
    rgb(255 175 215 / 0.10) 0%, rgb(255 150 205 / 0.16) 58%,
    rgb(255 120 190 / 0.34) 88%, rgb(255 205 235 / 0.55) 100%);
}
/* glass in front of him: rim, highlights */
.bubble-front {
  position: absolute; inset: 0; border-radius: 50%; pointer-events: none;
  background:
    radial-gradient(ellipse 20% 12% at 31% 20%, rgb(255 255 255 / 0.85), transparent 72%),
    radial-gradient(ellipse 6% 4% at 22% 33%, rgb(255 255 255 / 0.6), transparent 70%),
    radial-gradient(ellipse 12% 6% at 70% 84%, rgb(255 255 255 / 0.35), transparent 72%),
    radial-gradient(circle at 50% 50%, transparent 64%, rgb(255 140 200 / 0.20) 82%, rgb(255 225 242 / 0.55) 97%);
  box-shadow:
    inset 0 0 0 2px rgb(255 225 242 / 0.5),
    inset -14px -18px 46px rgb(255 95 175 / 0.28),
    inset 10px 12px 34px rgb(185 150 255 / 0.22);
}
/* iridescent swirl around the rim */
.bubble-sheen {
  position: absolute; inset: 0; border-radius: 50%;
  background: conic-gradient(from 0deg,
    rgb(255 120 200 / 0.30), rgb(160 205 255 / 0.24), rgb(255 232 150 / 0.20),
    rgb(205 145 255 / 0.26), rgb(255 120 200 / 0.30));
  -webkit-mask: radial-gradient(circle, transparent 62%, #000 90%);
          mask: radial-gradient(circle, transparent 62%, #000 90%);
  mix-blend-mode: screen;
  animation: sheen 9s linear infinite;
}
@keyframes sheen { to { transform: rotate(360deg); } }

/* soft floor shadow that fades in as the bubble arrives */
.bubble-shadow {
  position: absolute; left: 50%; top: 97%; width: 30%; height: 4%;
  transform: translate(-50%, -50%); border-radius: 50%;
  background: radial-gradient(closest-side, rgb(0 0 0 / 0.45), transparent);
  opacity: 0;
}
@media (prefers-reduced-motion: reduce) { .bubble-sheen { animation: none; } }

/* start button over the stage (sound needs a click) */
/* ===== LOBBY: the "Release the bubble" marquee button ===== */
.release-btn {
  position: absolute; left: 76%; top: 52%; transform: translate(-50%, -50%) rotate(-3deg); z-index: 3;
  padding: 2.2cqmin 3.2cqmin; border: 0.7cqmin solid #e7b53a; border-radius: 1.6cqmin; cursor: pointer;
  background: radial-gradient(circle at 50% 30%, #c8202a, #7a0d12); color: #fff6d8;
  font: 800 3.6cqmin/1.05 "Archivo", sans-serif; letter-spacing: 0.06em; text-transform: uppercase; text-align: center;
  box-shadow: 0 1.2cqmin 0 #4a070b, 0 0 4cqmin rgb(231 181 58 / 0.35);
  transition: transform 0.25s cubic-bezier(.3,1.6,.5,1), opacity 0.4s, box-shadow 0.2s;
  animation: marqueeBob 2.2s ease-in-out infinite;
}
.release-btn span { position: relative; z-index: 1; display: block; max-width: 9em; text-shadow: 0 0.3cqmin 0 #4a070b; }
.release-btn::before {                          /* chase lights around the edge */
  content: ""; position: absolute; inset: 0.6cqmin; border-radius: 1cqmin; pointer-events: none;
  background:
    radial-gradient(circle, #fff6c8 0 0.5cqmin, transparent 0.65cqmin) 0 0 / 3cqmin 3cqmin repeat-x,
    radial-gradient(circle, #fff6c8 0 0.5cqmin, transparent 0.65cqmin) 0 100% / 3cqmin 3cqmin repeat-x,
    radial-gradient(circle, #fff6c8 0 0.5cqmin, transparent 0.65cqmin) 0 0 / 3cqmin 3cqmin repeat-y,
    radial-gradient(circle, #fff6c8 0 0.5cqmin, transparent 0.65cqmin) 100% 0 / 3cqmin 3cqmin repeat-y;
  animation: chase 0.6s steps(2) infinite;
}
@keyframes chase { to { background-position: 3cqmin 0, -3cqmin 100%, 0 -3cqmin, 100% 3cqmin; } }
@keyframes marqueeBob { 0%, 100% { translate: 0 0; } 50% { translate: 0 -1cqmin; } }
.release-btn:hover, .release-btn:focus-visible { transform: translate(-50%, -50%) rotate(0deg) scale(1.08); background: radial-gradient(circle at 50% 30%, #e0333c, #8e1418); color: #fff; }
.release-btn:focus-visible { outline: 0.5cqmin solid #fff; outline-offset: 0.8cqmin; }
.release-btn:active { transform: translate(-50%, -50%) scale(0.96); box-shadow: 0 0.4cqmin 0 #4a070b; }
.release-btn.gone { opacity: 0; transform: translate(60%, -160%) rotate(25deg) scale(0.6); pointer-events: none; }
body:not(.lobby) .release-btn:not(.gone) { display: none; }
.actor.leap { translate: 0 -140cqmin; transition: translate 0.55s cubic-bezier(.5,-0.4,.8,.6); }
@media (prefers-reduced-motion: reduce) { .release-btn, .release-btn::before { animation: none; } }
.tapout {
  width: 100%; margin-top: 0.5rem; background: #1d1d21; color: var(--ink);
  border: 2px solid var(--line); font: 0.75rem ui-monospace, monospace; padding: 0.4rem; resize: vertical;
}

/* ===== BUBBLE SKIN: show.js drives these each frame so scrubbing is exact =====
   --skin 0..1 = how much bubble there is, --skin-scale = burst / re-form size,
   --clip = clip radius (50% = bubble, 100% = no clipping once popped) */
.bubble { clip-path: circle(var(--clip, 50%) at 50% 50%); }
.bubble-back, .bubble-front { opacity: var(--skin, 1); transform: scale(var(--skin-scale, 1)); }
.bubble.popped .ground-shadow { display: inline; }
.scrub { grid-template-columns: 3rem 1fr; }
.droplet {
  position: absolute; left: 50%; top: 50%; width: var(--sz); aspect-ratio: 1; border-radius: 50%;
  background: rgb(255 210 235 / 0.9); box-shadow: 0 0 6px rgb(255 160 210 / 0.8);
  transform: translate(-50%, -50%) rotate(var(--a)) translateX(var(--r));
  animation: fly 0.8s cubic-bezier(.2,.7,.4,1) forwards;
}
@keyframes fly {
  to { transform: translate(-50%, -50%) rotate(var(--a)) translateX(calc(var(--r) + var(--dist))); opacity: 0; }
}

/* ===== special eyes and blush ===== */
#eyesHeart, #eyesDizzy { display: none; }
#rig[data-eyes="heart"] #eyesHeart, #rig[data-eyes="dizzy"] #eyesDizzy { display: inline; }
#rig[data-eyes="heart"] #pupils, #rig[data-eyes="dizzy"] #pupils { display: none; }
#eyesHeart path { transform-box: fill-box; transform-origin: center; animation: thump 0.6s ease-in-out infinite; }
@keyframes thump { 50% { transform: scale(1.18); } }
.spiral { transform-box: fill-box; transform-origin: center; animation: spiralspin 0.9s linear infinite; }
@keyframes spiralspin { to { transform: rotate(360deg); } }
#blush { opacity: calc(var(--blush, 0) * 0.55); transition: opacity 0.3s ease; }
@media (prefers-reduced-motion: reduce) { #eyesHeart path, .spiral { animation: none; } }

/* ===== more effects: star eyes, sparkle, tears, sweat, steam, red face, Zzz, shake ===== */
#eyesStar, #sparkle, #tears, #sweat, #steam, #zzz { display: none; }
#rig[data-eyes="star"] #eyesStar { display: inline; }
#rig[data-eyes="star"] #pupils { display: none; }
#eyesStar polygon { transform-box: fill-box; transform-origin: center; animation: twinkle 0.8s ease-in-out infinite; }
@keyframes twinkle { 50% { transform: scale(1.15) rotate(12deg); } }
#rig[data-fx~="sparkle"] #sparkle,
#rig[data-fx~="tears"] #tears,
#rig[data-fx~="sweat"] #sweat,
#rig[data-fx~="steam"] #steam,
#rig[data-fx~="zzz"] #zzz { display: inline; }
.tear { animation: tear 1s ease-in infinite; }
.tear.t2 { animation-delay: 0.5s; }
@keyframes tear { 0% { transform: translateY(0); opacity: 0; } 15% { opacity: 1; } 100% { transform: translateY(120px); opacity: 0; } }
#sweat { animation: sweat 1.8s ease-in-out infinite; }
@keyframes sweat { 0% { transform: translateY(-6px); opacity: 0; } 20% { opacity: 1; } 80% { opacity: 1; } 100% { transform: translateY(34px); opacity: 0; } }
.puff { transform-box: fill-box; transform-origin: center; animation: puff 0.9s ease-out infinite; }
.puff.p2 { animation-delay: 0.45s; }
@keyframes puff { 0% { transform: translateY(0) scale(0.4); opacity: 0.9; } 100% { transform: translateY(-80px) scale(1.6); opacity: 0; } }
#redface { opacity: 0; mix-blend-mode: multiply; transition: opacity 0.4s ease; }
#rig[data-fx~="red"] #redface { opacity: 0.45; }
.z { opacity: 0; animation: zzz 2.4s ease-out infinite; }
.z.z2 { animation-delay: 0.8s; } .z.z3 { animation-delay: 1.6s; }
@keyframes zzz { 0% { transform: translate(0, 0); opacity: 0; } 20% { opacity: 1; } 100% { transform: translate(50px, -110px); opacity: 0; } }
#rig[data-fx~="shake"] #head, #rig[data-fx~="shake"] #headFront { animation: headshake 0.12s linear infinite; }
@keyframes headshake { 0%, 100% { translate: 0 0; } 25% { translate: -4px 1px; } 75% { translate: 4px -1px; } }
#rig[data-fx~="bigmouth"] #m-wide { transform-box: fill-box; transform-origin: center; scale: 1.45; }
@media (prefers-reduced-motion: reduce) {
  #eyesStar polygon, .tear, #sweat, .puff, .z, #rig[data-fx~="shake"] #head { animation: none; }
  .z { opacity: 1; }
}


/* ===== layer switches set per pose ===== */
#sleeveOverL, #sleeveOverR, #handBackL, #handBackR { display: none; }
#rig[data-sleeveover~="L"] #sleeveOverL, #rig[data-sleeveover~="R"] #sleeveOverR { display: inline; }
#rig[data-handsback*="L"] #handBackL, #rig[data-handsback*="R"] #handBackR { display: inline; }
#rig[data-handsback*="L"] #handTopL, #rig[data-handsback*="R"] #handTopR { display: none; }

/* ===================== COSTUMES ===================== */
/* drawn shoes (ruby slippers): hide the shoe images while a drawn pair is on */
.drawn-shoe { display: none; }
#rig[data-drawnshoe] .drawn-shoe { display: inline; }
#rig[data-drawnshoe] #shoeL, #rig[data-drawnshoe] #shoeR { display: none; }
#rig[data-drawnshoe] .pantcuff { stroke-width: 74; }
.glint { transform-box: fill-box; transform-origin: center; animation: glint 1.6s ease-in-out infinite; opacity: 0; }
@keyframes glint { 0%, 70%, 100% { opacity: 0; transform: scale(0.2) rotate(0deg); } 82% { opacity: 1; transform: scale(1) rotate(45deg); } }

/* holding a prop: that hand closes into a fist around it */
#rig[data-propl] #handL .h { display: none; }
#rig[data-propl] #handL .h-fist { display: inline; }
#rig[data-propr] #handR .h { display: none; }
#rig[data-propr] #handR .h-fist { display: inline; }

/* hat moves (pivot at the brim) */
#hatMove { transform-origin: 330px 95px; }
#rig[data-hat="tip"] #hatMove { animation: hattip 1.1s cubic-bezier(.3,1.3,.5,1); }
#rig[data-hat="tipL"] #hatMove { animation: hattipL 1.1s cubic-bezier(.3,1.3,.5,1); }
#rig[data-hat="pop"] #hatMove { animation: hatpop 1.15s ease-in-out; }
@keyframes hattip {
  0% { transform: none; } 30% { transform: translate(18px, -46px) rotate(16deg); }
  70% { transform: translate(18px, -46px) rotate(16deg); } 100% { transform: none; }
}
@keyframes hattipL {
  0% { transform: none; } 30% { transform: translate(-30px, -50px) rotate(-14deg); }
  70% { transform: translate(-30px, -50px) rotate(-14deg); } 100% { transform: none; }
}
@keyframes hatpop {
  0% { transform: none; } 12% { transform: translateY(8px) scale(1.04, 0.94); }
  50% { transform: translateY(-230px) rotate(180deg); } 84% { transform: translateY(0) rotate(360deg); }
  90% { transform: translateY(6px) rotate(360deg) scale(1.06, 0.92); } 100% { transform: rotate(360deg); }
}
/* "click your heels" sparkle burst */
#heelBurst .spark { transform-box: fill-box; transform-origin: center; opacity: 0; }
#heelBurst.go .spark { animation: spark 0.75s ease-out forwards; }
@keyframes spark { 0% { opacity: 1; transform: translate(0, 0) scale(0.3); } 100% { opacity: 0; transform: translate(var(--dx), var(--dy)) scale(1.2) rotate(90deg); } }
@media (prefers-reduced-motion: reduce) { .glint, #hatMove, #heelBurst .spark { animation: none !important; } .glint { opacity: 0.8; } }

/* tuxedo shirt cuffs at the wrists (shown by outfits with long sleeves) */
.shirtcuff { display: none; }
#rig[data-cuffs] .shirtcuff { display: inline; }

/* ===================== VOTE PEN ===================== */
/* sparkler: flickering glow and sparks */
.spk { transform-box: fill-box; transform-origin: 0 0; animation: spk 0.32s ease-out infinite; }
@keyframes spk { 0% { opacity: 1; transform: scale(0.2); } 70% { opacity: 1; } 100% { opacity: 0; transform: scale(1.25); } }
.spglow { transform-box: fill-box; transform-origin: center; animation: spglow 0.12s steps(2) infinite alternate; }
@keyframes spglow { from { opacity: 0.75; transform: scale(0.92); } to { opacity: 1; transform: scale(1.08); } }
/* I Voted sticker slaps on */
.sticker { transform-box: fill-box; transform-origin: center; animation: slap 0.5s cubic-bezier(.2,1.5,.4,1); }
@keyframes slap { from { transform: scale(2.6) rotate(-30deg); opacity: 0; } 40% { opacity: 1; } to { transform: rotate(-8deg); } }
/* "I want YOU": lean in toward the viewer */
#body { transform-origin: 290px 1200px; transition: transform 0.35s cubic-bezier(.3,1.4,.5,1); }
#rig[data-lunge] #body { transform: scale(1.12) translateY(-10px); }
#rig[data-lunge] #handR > .h-point { transform: scale(1.5); transition: transform 0.3s; }
/* speech bubble */
.speech { position: absolute; z-index: 8; max-width: 34cqw; padding: 1.2cqmin 2cqmin; border-radius: 3cqmin;
          background: #f4f1ea; color: #1f3a94; font: 800 4.6cqmin/1.1 "Archivo", sans-serif; letter-spacing: 0.02em;
          box-shadow: 0 0.6cqmin 0 #c8202a; opacity: 0; transform: scale(0.4); transform-origin: 0 100%; pointer-events: none;
          transition: opacity 0.2s, transform 0.3s cubic-bezier(.3,1.6,.5,1); }
.speech::after { content: ""; position: absolute; left: 1.5cqmin; bottom: -2.2cqmin; border: 1.4cqmin solid transparent;
                 border-top: 2cqmin solid #f4f1ea; border-left-width: 0.6cqmin; }
.speech.on { opacity: 1; transform: none; }
.plume { transform-box: fill-box; transform-origin: 50% 100%; animation: plume 1.8s ease-in-out infinite; }
@keyframes plume { 0%, 100% { transform: rotate(-4deg); } 50% { transform: rotate(4deg); } }
/* fireworks and bunting live on the stage */
.fireworks { position: absolute; inset: 0; pointer-events: none; z-index: 7; overflow: hidden; }
.fw-p { position: absolute; width: 0.7cqw; height: 0.7cqw; min-width: 4px; min-height: 4px; border-radius: 50%;
        background: var(--c); box-shadow: 0 0 6px 2px var(--c); animation: fw 1.3s cubic-bezier(.15,.7,.3,1) forwards; }
@keyframes fw { 0% { transform: translate(0, 0) scale(1.4); opacity: 1; }
                80% { opacity: 1; } 100% { transform: translate(var(--dx), calc(var(--dy) + 6cqmin)) scale(0.4); opacity: 0; } }
.fw-flash { position: absolute; width: 6cqw; height: 6cqw; margin: -3cqw 0 0 -3cqw; border-radius: 50%;
            background: radial-gradient(circle, #fff 0, rgb(255 255 255 / 0) 70%); animation: fwflash 0.35s ease-out forwards; }
@keyframes fwflash { from { opacity: 1; transform: scale(0.3); } to { opacity: 0; transform: scale(1.4); } }
.bunting { position: absolute; left: 0; right: 0; top: 0; width: 100%; height: auto; z-index: 1; pointer-events: none;
           transform: translateY(-110%); transition: transform 0.6s cubic-bezier(.3,1.3,.5,1); }
.bunting.on { transform: none; }
@media (prefers-reduced-motion: reduce) { .spk, .spglow, .sticker, .fw-p, .fw-flash { animation: none !important; } .fw-p { display: none; } }

/* white gloves (second line marshal, etc.) */
#rig[data-gloves] #handL .h, #rig[data-gloves] #handR .h { filter: grayscale(1) brightness(1.7) contrast(0.85); }

/* ===================== COSTUME LIBRARY ===================== */
.fxlayer { position: absolute; inset: 0; pointer-events: none; z-index: 7; overflow: hidden; }
.ptcl { position: absolute; margin: -1.5cqmin 0 0 -1.5cqmin; animation-timing-function: linear; animation-fill-mode: both; }
.ptcl svg { display: block; overflow: visible; }
.ptcl.fall  { animation-name: ptFall; }
.ptcl.float { animation-name: ptFloat; animation-timing-function: ease-out; }
.ptcl.throw { animation-name: ptThrow; animation-timing-function: cubic-bezier(.2,.6,.4,1); }
@keyframes ptFall  { from { transform: translate(0, 0) rotate(0deg); } to { transform: translate(var(--dx), 115cqmin) rotate(var(--rot)); } }
@keyframes ptFloat { 0% { opacity: 0; transform: translate(0, 0) scale(0.4); } 15% { opacity: 1; }
                     100% { opacity: 0; transform: translate(var(--dx), -45cqmin) scale(1.1) rotate(calc(var(--rot) / 8)); } }
@keyframes ptThrow { 0% { transform: translate(0, 0) rotate(0deg); }
                     40% { transform: translate(calc(var(--dx) * 0.5), -30cqmin) rotate(calc(var(--rot) / 2)); }
                     100% { transform: translate(var(--dx), 70cqmin) rotate(var(--rot)); opacity: 0.9; } }
.camflash { position: absolute; inset: 0; background: #fff; animation: camflash 0.6s ease-out forwards; }
@keyframes camflash { 0% { opacity: 0.95; } 100% { opacity: 0; } }
#rig[data-flash] .bulb { fill: #fff; filter: drop-shadow(0 0 30px #fff); }
.bopper { transform-box: fill-box; transform-origin: 50% 100%; animation: bop 0.9s ease-in-out infinite; }
@keyframes bop { 0%, 100% { transform: rotate(-12deg) translateY(0); } 50% { transform: rotate(12deg) translateY(-8px); } }
.scarf { transform-box: fill-box; transform-origin: 0 50%; animation: scarf 0.7s ease-in-out infinite alternate; }
@keyframes scarf { from { transform: skewY(-6deg) scaleX(0.94); } to { transform: skewY(6deg) scaleX(1.04); } }
.ballswirl { transform-box: fill-box; transform-origin: center; animation: swirl 3s linear infinite; }
@keyframes swirl { to { transform: rotate(360deg); } }
.ballhalo { transform-box: fill-box; transform-origin: center; animation: halo 1.6s ease-in-out infinite; }
@keyframes halo { 0%, 100% { opacity: 0.6; transform: scale(0.92); } 50% { opacity: 1; transform: scale(1.06); } }
#rig[data-reading] .ballhalo { animation-duration: 0.35s; }
#rig[data-reading] .ballswirl { animation-duration: 0.6s; }
.canopy { transform-box: fill-box; transform-origin: 50% 60%; animation: canopy 1.1s ease-in-out infinite; }
@keyframes canopy { 0%, 100% { transform: scaleX(1) rotate(-3deg); } 50% { transform: scaleX(0.9) rotate(3deg); } }
.hankywave { transform-box: fill-box; transform-origin: 100% 40%; animation: hanky 0.5s ease-in-out infinite alternate; }
@keyframes hanky { from { transform: skewY(-10deg) scaleX(0.9); } to { transform: skewY(10deg) scaleX(1.05); } }
.blowout { transform-box: fill-box; transform-origin: 0 50%; transform: scaleX(0.12); transition: transform 0.25s cubic-bezier(.3,1.5,.5,1); }
#rig[data-blow] .blowout { transform: scaleX(1); }
@media (prefers-reduced-motion: reduce) {
  .ptcl, .camflash, .bopper, .scarf, .ballswirl, .ballhalo, .canopy, .hankywave, .plume { animation: none !important; }
  .ptcl { display: none; }
}
.feather { transform-box: fill-box; transform-origin: 50% 100%; animation: feather 2.2s ease-in-out infinite; }
@keyframes feather { 0%, 100% { rotate: -3deg; } 50% { rotate: 3deg; } }

/* Bubble Club ears: wobble, shimmer, bounce on roll call, pop and grow back */
.bubear { transform-box: fill-box; transform-origin: center; animation: bubwob 2.6s ease-in-out infinite; }
@keyframes bubwob { 0%, 100% { transform: scale(1, 1); } 30% { transform: scale(1.05, 0.95); } 60% { transform: scale(0.96, 1.04); } }
.bubrim { animation: iris 4s linear infinite; }
@keyframes iris { to { filter: hue-rotate(360deg); } }
#rig[data-bubbly] .bubear { animation: bubbounce 0.35s ease-in-out infinite alternate; }
@keyframes bubbounce { from { transform: translateY(0) scale(1); } to { transform: translateY(-14px) scale(1.06, 0.94); } }
#rig[data-popears] .bubear { animation: bubpop 1.4s ease-out; }
@keyframes bubpop { 0% { transform: scale(1); } 12% { transform: scale(1.25); opacity: 1; } 18% { transform: scale(1.4); opacity: 0; }
                    55% { transform: scale(0); opacity: 0; } 85% { transform: scale(1.1); opacity: 1; } 100% { transform: scale(1); } }
@media (prefers-reduced-motion: reduce) { .bubear, .bubrim { animation: none !important; } }

/* ===================== BODY STYLE: FLAT + OUTLINE ===================== */
:root { --outline-w: 7; --ink-line: #262022; --shirt: #d63a2f; --flat-pants: #22184a; --sleeve-depth: 0.4; }
#flatBody, #flatSleeves, .legline, .cuffline { display: none; }
#rig[data-body="flat"] #torsoImg { display: none; }
#rig[data-body="flat"] #flatBody, #rig[data-body="flat"] #flatSleeves { display: inline; }
#rig[data-body="flat"] .legline, #rig[data-body="flat"] .cuffline { display: inline; }
#rig[data-body="flat"] { --pants: var(--flat-pants); --pants-cuff: #2c2160; }
.flat-shirt { fill: var(--shirt); }
.flat-shirt-shade { fill: url(#flatRound); }                 /* round chest, lit from the upper left; no bevel at the hem */
.flat-collar-shadow { fill: #000; opacity: 0.16; filter: blur(6px); }
.flat-line { fill: none; stroke: var(--ink-line); stroke-width: var(--outline-w); stroke-linejoin: round; }
.flat-collar { fill: none; stroke: var(--ink-line); stroke-width: calc(var(--outline-w) * 0.8); stroke-linecap: round; }
.flat-seat { fill: var(--pants); stroke: var(--ink-line); stroke-width: var(--outline-w); stroke-linejoin: round; }
.flat-seat-shade { fill: url(#flatRound); }
.legline { fill: none; stroke: var(--ink-line); stroke-width: calc(72px + var(--outline-w) * 2px); stroke-linecap: butt; stroke-linejoin: round; }
.cuffline { fill: none; stroke: var(--ink-line); stroke-width: calc(78px + var(--outline-w) * 2px); stroke-linecap: butt; }
/* sleeves: outlined, with only a light roll of shading */
#rig[data-body="flat"] .sleeve > path:first-child { stroke: var(--ink-line); stroke-width: var(--outline-w); stroke-linejoin: round; }
#rig[data-body="flat"] .sleeve .hem { stroke: var(--ink-line); stroke-width: calc(var(--outline-w) * 0.8); }

/* T-shirt color swatches */
.swatches { grid-template-columns: repeat(5, 1fr); }
.swatches button { font-size: 0.7rem; padding: 0.5rem 0.2rem; text-transform: capitalize; border-left: 0.9rem solid var(--sw); }

/* ===================== PANEL: tabs and groups ===================== */
.panel.tabbed { display: flex; flex-direction: column; gap: 0; overflow: hidden; padding: 4.2rem 0 0; }
.tabbar { flex: none; display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.3rem; padding: 0 1rem 0.8rem; border-bottom: 2px solid var(--line); }
.tab { font-size: 0.8rem; padding: 0.55rem 0.3rem; border-color: var(--line); color: var(--muted); }
.tab[aria-selected="true"] { background: var(--coral); border-color: var(--coral); color: #fff; }
.panes { flex: 1; overflow-y: auto; padding: 0.4rem 1.25rem 1.2rem; }
.pane { display: grid; gap: 0.2rem; }
.pane[hidden] { display: none; }
.group { border-bottom: 1px solid var(--line); padding: 0.2rem 0 0.7rem; }
.group[hidden] { display: none; }
.group > summary { list-style: none; cursor: pointer; padding: 0.6rem 0 0.5rem; font-size: 0.75rem; font-weight: 800; letter-spacing: 0.18em;
                   text-transform: uppercase; color: var(--ink); display: flex; justify-content: space-between; align-items: center; }
.group > summary::-webkit-details-marker { display: none; }
.group > summary::after { content: "+"; font-size: 1rem; color: var(--muted); letter-spacing: 0; }
.group[open] > summary::after { content: "\2212"; }
.group > summary:focus-visible { outline: 3px solid var(--coral); outline-offset: 2px; }
.group > * + * { margin-top: 0.45rem; }
.sublabel { margin: 0.6rem 0 0.3rem; font-size: 0.7rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--muted); }
.panel-foot { flex: none; padding: 0.8rem 1.25rem; border-top: 2px solid var(--line); }
.panel-foot button { width: 100%; }
.saybox .sayrow { display: grid; grid-template-columns: 1fr auto; gap: 0.4rem; }
.saybox input { font: inherit; padding: 0.55rem; background: #1d1d21; color: var(--ink); border: 2px solid var(--line); min-width: 0; }
.saybox input:focus-visible { outline: 3px solid var(--coral); outline-offset: 2px; }
.panes .btns { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.panes .btns > * { min-width: 0; overflow-wrap: anywhere; }
.panes .swatches { grid-template-columns: repeat(5, minmax(0, 1fr)); }
.panes .swatches button { border-left-width: 0.6rem; padding: 0.5rem 0.1rem; font-size: 0.65rem; }
.panes .swatches button { height: 2.2rem; padding: 0; border: 2px solid var(--line); background: var(--sw); }
.panes .swatches button:hover { border-color: var(--ink); background: var(--sw); }
.panes .swatches button[aria-pressed="true"] { border: 3px solid var(--ink); outline: 3px solid var(--coral); outline-offset: 1px; background: var(--sw); }

/* =====================================================================
   THE SAMMIE SHOW: scenes, curtain, spotlight, Kristin, the marquee sign
   Stacking, back to front: scenes 0, bunting 1, Sammie, curtain 3,
   spotlight 4, Sammie in front of the curtain 5, Kristin + sign 6,
   effects 7, speech 8.
   ===================================================================== */
.scenes { position: absolute; inset: 0; z-index: 0; }
.scenebg { position: absolute; inset: 0; opacity: 0; transition: opacity 0.7s ease; background: var(--bg, #1d1d21); overflow: hidden; }
.scenebg.on { opacity: 1; }
/* scene images: wide art on the 16:9 stage, tall art on the 9:16 stage; anchored to the floor line */
.scenebg.has-img { background: var(--img-wide) center bottom / cover no-repeat, var(--bg, #1d1d21); }
@container (aspect-ratio < 1) { .scenebg.has-img { background-image: var(--img-tall); } }
.scenebg.has-img > .art, .scenebg.has-img > .floor, .scenebg.has-img > .title, .scenebg.has-img > .tag { display: none; }
.scenebg video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.scenebg .floor { position: absolute; left: 0; right: 0; bottom: 0; height: calc(100% - var(--ground) + 13cqmin); background: var(--floor, #141418); }
.scenebg .title { position: absolute; top: 17%; left: 0; right: 0; text-align: center; font: 7.5cqmin/1 "Rye", serif; color: var(--ink2, #f4f1ea); opacity: 0.3; letter-spacing: 0.04em; }
.scenebg .tag { position: absolute; left: 1.5%; bottom: 1.5%; font: 1.7cqmin ui-monospace, monospace; color: #fff; opacity: 0.45; }
.scenebg .art { position: absolute; inset: 0; }

.curtain { position: absolute; inset: 0; z-index: 3; pointer-events: none; }
.curtain-panel {
  position: absolute; top: 0; bottom: 0; width: 51%;
  background: repeating-linear-gradient(90deg, #4f0910 0, #86121d 2.6%, #b81f2c 4.6%, #86121d 6.6%, #4f0910 9%);
  box-shadow: inset 0 -6cqmin 6cqmin rgb(0 0 0 / 0.35), inset 0 4cqmin 5cqmin rgb(0 0 0 / 0.3);
  /* closing: waits for the valance to drop in first */
  transition: transform 1.3s cubic-bezier(.65,0,.3,1) 0.45s, filter 1.6s ease 0s;
  filter: brightness(var(--curtain-lit, 1));
}
.curtain-panel::after {                       /* gold fringe along the hem */
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 2.6%;
  background: repeating-linear-gradient(90deg, #e7b53a 0 0.4cqw, #9a6a12 0.4cqw 0.7cqw);
}
.curtain-l { left: 0; transform-origin: 0 50%; }
.curtain-r { right: 0; transform-origin: 100% 50%; }
/* OPEN: panels slide all the way off stage, then the valance flies up and out.
   CLOSE: the reverse, valance drops in, then the panels sweep closed. */
.curtain.open .curtain-panel { transition-delay: 0s; }
.curtain.open .curtain-l { transform: translateX(-102%); }
.curtain.open .curtain-r { transform: translateX(102%); }
.curtain.fast .curtain-panel { transition-duration: 0.45s; transition-delay: 0.15s; }
.curtain.fast.open .curtain-panel { transition-delay: 0s; }
.curtain-valance {
  position: absolute; left: 0; right: 0; top: 0; height: 12%;
  background: repeating-linear-gradient(90deg, #5e0b12 0, #9a1622 2%, #c0222f 3.5%, #9a1622 5%, #5e0b12 7%);
  -webkit-mask: radial-gradient(circle at 50% 0, #000 70%, transparent 71%) 0 100% / 7% 140% repeat-x, linear-gradient(#000, #000) 0 0 / 100% 72% no-repeat;
          mask: radial-gradient(circle at 50% 0, #000 70%, transparent 71%) 0 100% / 7% 140% repeat-x, linear-gradient(#000, #000) 0 0 / 100% 72% no-repeat;
}
.curtain-valance::after { content: ""; position: absolute; left: 0; right: 0; top: 66%; height: 6%; background: #e7b53a; }
.curtain-valance { transition: transform 0.6s cubic-bezier(.5,0,.3,1), filter 1.6s ease 0s; filter: brightness(var(--curtain-lit, 1)); }
/* opening: house lights down, the velvet sits in shadow until the curtain opens */
.curtain.dim { --curtain-lit: 0.3; }
.curtain.open .curtain-valance { transform: translateY(-115%); transition-delay: 0.9s; }
.curtain.fast .curtain-valance { transition-duration: 0.25s; }
.curtain.fast.open .curtain-valance { transition-delay: 0.3s; }

.spotlight { position: absolute; inset: 0; z-index: 4; pointer-events: none; opacity: 0; transition: opacity 0.35s;
  background: radial-gradient(ellipse var(--sw, 22cqmin) var(--sh, 40cqmin) at var(--sx, 50%) var(--sy, calc(var(--ground) - 38cqmin)), transparent 70%, rgb(0 0 0 / 0.9) 100%); }
.spotlight.on { opacity: 1; }
body.lobby .bubble, body.inone .bubble { z-index: 5; }

.kbubble { position: absolute; z-index: 6; width: calc(var(--d, 30) * var(--wu, 1cqmin)); aspect-ratio: 1; left: 20%; top: -40%;
           transform: translate(-50%, -50%); opacity: 0; pointer-events: none; }
.kbubble > div { position: absolute; inset: 0; }

/* transformations */
.actor.spin { animation: spinY 0.34s linear infinite; }
@keyframes spinY { 0% { scale: 1 1; } 25% { scale: 0.06 1; } 50% { scale: -1 1; } 75% { scale: -0.06 1; } 100% { scale: 1 1; } }
.actor.flash svg { animation: flashme 0.6s ease-out; }
@keyframes flashme { 0% { filter: brightness(1.9) saturate(0.7); } 100% { filter: none; } }
.actor.slip { opacity: 0; scale: 0.86; transition: opacity 0.35s, scale 0.35s; }

/* ===== the 1950s marquee sign ===== */
.marquee-btn {
  position: absolute; left: 75%; top: 46%; width: 36cqw; aspect-ratio: 520 / 320; z-index: 6;
  padding: 0; border: 0; background: none; cursor: pointer;
  transform: translate(-50%, -50%) rotate(-3deg);
  transition: transform 0.3s cubic-bezier(.3,1.6,.5,1), opacity 0.45s;
  animation: marqueeBob 2.6s ease-in-out infinite;
}
@container (aspect-ratio < 1) {
  .marquee-btn { left: 50%; top: 24%; width: 84cqw; }
  .marquee-btn.gone { transform: translate(-50%, -50%) translate(10cqw, -40cqh) rotate(20deg) scale(0.6); }
  .speech { max-width: 70cqw; }
}
.marquee-btn:hover, .marquee-btn:focus-visible { background: none; transform: translate(-50%, -50%) rotate(0deg) scale(1.06); }
.marquee-btn:focus-visible { outline: 0.5cqmin solid #fff; outline-offset: 0.6cqmin; }
.marquee-btn:active { transform: translate(-50%, -50%) scale(0.97); }
.marquee-btn svg { display: block; width: 100%; height: 100%; overflow: visible; }
.marquee-btn .bulb { fill: #6e5320; animation: bulbChase 0.9s steps(1) infinite; animation-delay: calc(var(--i) * -0.3s); }
@keyframes bulbChase { 0% { fill: #fff2b8; } 33.33% { fill: #6e5320; } }
.marquee-btn .glow { opacity: 0; animation: glowChase 0.9s steps(1) infinite; animation-delay: calc(var(--i) * -0.3s); }
@keyframes glowChase { 0% { opacity: 0.85; } 33.33% { opacity: 0; } }
/* HOVER LIGHTS: the pattern changes every 2.2s (data-lights is set in sammieshow.js).
   Each bulb has --n (its number around the sign), --r and --q (random 0 to 1), data-odd. */
.marquee-btn[data-lights] .bulb { animation: bulbOn var(--dur) var(--ease, steps(1)) infinite; animation-delay: var(--del); }
.marquee-btn[data-lights] .glow { animation: glowOn var(--dur) var(--ease, steps(1)) infinite; animation-delay: var(--del); }
@keyframes bulbOn { 0%, 49.9% { fill: #fff6cf; } 50%, 100% { fill: #6e5320; } }
@keyframes glowOn { 0%, 49.9% { opacity: 0.95; } 50%, 100% { opacity: 0; } }
/* fast chase running around the sign */
.marquee-btn[data-lights="chase"] .bulbset { --dur: 0.36s; --del: calc(var(--i) * -0.12s); }
/* random twinkle, every bulb on its own clock, soft fades */
.marquee-btn[data-lights="twinkle"] .bulbset { --dur: calc(0.5s + var(--r) * 0.9s); --del: calc(var(--q) * -1.4s); --ease: ease-in-out; }
/* every other bulb, flip-flopping */
.marquee-btn[data-lights="alternate"] .bulbset { --dur: 0.5s; --del: 0s; }
.marquee-btn[data-lights="alternate"] .bulbset[data-odd="1"] { --del: -0.25s; }
/* a long wave sweeping around the whole border */
.marquee-btn[data-lights="wave"] .bulbset { --dur: 1.1s; --del: calc(var(--n) / var(--bulbs) * -1.1s); --ease: ease-in-out; }
/* all on, with quick random sparkles dropping out */
.marquee-btn[data-lights="sparkle"] .bulbset { --dur: calc(0.18s + var(--r) * 0.5s); --del: calc(var(--q) * -0.7s); }
.marquee-btn[data-lights="sparkle"] .bulb { animation-name: bulbSpark; }
.marquee-btn[data-lights="sparkle"] .glow { animation-name: glowSpark; }
@keyframes bulbSpark { 0%, 79.9% { fill: #fff6cf; } 80%, 100% { fill: #6e5320; } }
@keyframes glowSpark { 0%, 79.9% { opacity: 0.95; } 80%, 100% { opacity: 0.1; } }
.marquee-btn .burst { transform-box: fill-box; transform-origin: center; animation: burstTw 1.6s ease-in-out infinite; }
@keyframes burstTw { 0%, 100% { scale: 1; rotate: 0deg; } 50% { scale: 1.15; rotate: 12deg; } }
.marquee-btn:hover .burst { animation-duration: 0.5s; }
.marquee-btn.blast .bulb { animation: bulbChase 0.18s steps(1) infinite; }
.marquee-btn.gone { opacity: 0; pointer-events: none; transform: translate(-50%, -50%) translate(26cqw, -14cqmin) rotate(28deg) scale(0.6); }
body:not(.lobby) .marquee-btn:not(.gone) { display: none; }
@media (prefers-reduced-motion: reduce) {
  .marquee-btn, .marquee-btn .bulb, .marquee-btn .glow, .marquee-btn .burst, .actor.spin { animation: none !important; }
  .marquee-btn .bulb { fill: #fff2b8; } .curtain-panel, .curtain-valance { transition-duration: 0.01s; transition-delay: 0s !important; }
}


/* ===== FINALE SIGN: 1950s Vegas marquee (sammieshow.js builds it, .on lights it up) ===== */
.curtain { transition: transform 1.6s cubic-bezier(.6,0,.3,1); }
.curtain.fly { transform: translateY(-105%); }
.finale-sign { position: absolute; inset: 0; z-index: 4; pointer-events: none; opacity: 0; transition: opacity 0.8s;
  background: radial-gradient(ellipse at 50% 45%, rgb(0 0 0 / 0.15), rgb(0 0 0 / 0.65)); }
.finale-sign.on { opacity: 1; }
.finale-sign svg { position: absolute; left: 50%; top: 44%; width: 66%; transform: translate(-50%, -50%) scale(0.92); overflow: visible; }
.finale-sign .fs-tall { display: none; }
@container (aspect-ratio < 1) {
  .finale-sign .fs-wide { display: none; }
  .finale-sign .fs-tall { display: block; width: 92%; top: 42%; }
}
.finale-sign.on svg { animation: fsIn 1s cubic-bezier(.3,1.5,.5,1) forwards; }
@keyframes fsIn { from { transform: translate(-50%, -50%) scale(0.92); } to { transform: translate(-50%, -50%) scale(1); } }
/* bulbs: dark, then chase once the sign is on */
.finale-sign .fdot { fill: #6e5320; }
.finale-sign .fglow { fill: #ffd36b; opacity: 0; }
.finale-sign.on .fbulb .fdot, .finale-sign.on .fbulb2 .fdot { animation: fChaseDot 0.9s steps(1) infinite; animation-delay: calc(0.4s + var(--n) * -0.3s); }
.finale-sign.on .fbulb .fglow, .finale-sign.on .fbulb2 .fglow { animation: fChaseGlow 0.9s steps(1) infinite; animation-delay: calc(0.4s + var(--n) * -0.3s); }
@keyframes fChaseDot { 0% { fill: #fff6cf; } 33.33% { fill: #6e5320; } }
@keyframes fChaseGlow { 0% { opacity: 0.8; } 33.33% { opacity: 0; } }
/* letters: dark until they flicker on, one after another */
.finale-sign .fl { fill-opacity: 0.12; stroke-opacity: 0.25; }
.finale-sign.on .fl { animation: fFlicker 0.6s linear forwards; animation-delay: calc(1s + var(--k) * 0.13s); }
@keyframes fFlicker { 0% { fill-opacity: 0.12; } 15% { fill-opacity: 1; } 28% { fill-opacity: 0.2; } 45% { fill-opacity: 1; stroke-opacity: 1; }
                      58% { fill-opacity: 0.35; } 100% { fill-opacity: 1; stroke-opacity: 1; } }
/* starburst pops, then twinkles */
.finale-sign .fburst { transform-box: fill-box; transform-origin: center; transform: scale(0); }
.finale-sign.on .fburst { animation: fPop 0.5s cubic-bezier(.3,1.8,.5,1) 2.6s forwards, fTwinkle 1.4s ease-in-out 3.1s infinite; }
@keyframes fPop { to { transform: scale(1); } }
@keyframes fTwinkle { 0%, 100% { transform: scale(1) rotate(0deg); } 50% { transform: scale(1.18) rotate(15deg); } }
/* neon arrow flashes on, then STAY TUNED! blinks */
.finale-sign .farrow { opacity: 0; }
.finale-sign.on .farrow { animation: fNeon 1.2s steps(1) 3.1s infinite; }
@keyframes fNeon { 0% { opacity: 1; } 70% { opacity: 1; } 71% { opacity: 0.15; } 100% { opacity: 0.15; } }
.finale-sign .ftuned, .finale-sign .ftuned-box { opacity: 0.25; }
.finale-sign.on .ftuned, .finale-sign.on .ftuned-box { animation: fBlink 0.8s steps(1) 3.6s infinite; }
@keyframes fBlink { 0% { opacity: 1; } 60% { opacity: 1; } 61% { opacity: 0.45; } 100% { opacity: 0.45; } }
@media (prefers-reduced-motion: reduce) {
  .finale-sign.on * { animation: none !important; }
  .finale-sign.on .fl, .finale-sign.on .ftuned, .finale-sign.on .ftuned-box, .finale-sign.on .farrow { fill-opacity: 1; opacity: 1; }
  .finale-sign.on .fburst { transform: none; }
}

/* ===== THE BRIDGE effects ===== */
/* scenes switch with no fade during the roulette */
.scenes.snap .scenebg { transition: none; }
/* glitch: jitter with an RGB split; .pix on the rig pixelates him */
.actor.glitch > svg { animation: glitchJit 0.32s steps(1) infinite; }
@keyframes glitchJit {
  0%   { transform: translate(0, 0); filter: drop-shadow(5px 0 0 rgb(255 0 120 / 0.8)) drop-shadow(-5px 0 0 rgb(0 230 255 / 0.8)); }
  20%  { transform: translate(-3%, 0) skewX(10deg); clip-path: inset(10% 0 55% 0); }
  40%  { transform: translate(2%, 0); filter: drop-shadow(-6px 0 0 rgb(255 0 120 / 0.8)) drop-shadow(6px 0 0 rgb(0 230 255 / 0.8)); clip-path: none; }
  60%  { transform: translate(0, 1%) skewX(-6deg); clip-path: inset(48% 0 12% 0); }
  80%  { transform: translate(1%, 0); clip-path: none; filter: hue-rotate(90deg) saturate(2); }
}
#rig.pix { filter: url(#pixelate) !important; }
#rig.sketch { filter: saturate(1.25) contrast(1.1); }
/* the lineup: copies pop in behind him, smaller, then wink out */
.lineup { position: absolute; pointer-events: none; transform-origin: 50% 100%; animation: lineupIn 0.45s cubic-bezier(.3,1.6,.5,1) both; }
.lineup > .actor { opacity: 0.95; }
.lineup.out { animation: lineupOut 0.35s ease-in forwards; }
@keyframes lineupIn { from { transform: scale(0); opacity: 0; } to { transform: scale(var(--ls, 0.86)); opacity: 1; } }
@keyframes lineupOut { from { transform: scale(var(--ls, 0.86)); opacity: 1; } to { transform: scale(0) translateY(-20%); opacity: 0; } }
@container (aspect-ratio < 1) { .lineup { --ls: 0.62; } }
@media (prefers-reduced-motion: reduce) { .actor.glitch > svg, .lineup, .lineup.out { animation: none; } }

/* ===== LOBBY: house lights down, the usher's flashlight is the light ===== */
.flashbeam { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 7; pointer-events: none; mix-blend-mode: screen;
  opacity: 0; transition: opacity 0.12s; }
.flashbeam.on { opacity: 1; }
body:not(.lobby) .flashbeam { display: none; }
/* the sign sits in the dark until the beam finds it */
body.lobby .marquee-btn { filter: brightness(0.42) saturate(0.7); transition: transform 0.3s cubic-bezier(.3,1.6,.5,1), opacity 0.45s, filter 0.35s; }
body.lobby .marquee-btn.lit { filter: brightness(1.08) drop-shadow(0 0 2.4cqmin rgb(255 225 150 / 0.55)); }
@media (prefers-reduced-motion: reduce) { .flashbeam { transition: none; } }



/* ===== SET PIECES (set.js): the panorama look ===== */
.set { position: absolute; inset: 0; pointer-events: none; }
.piece { position: absolute; z-index: 0; left: var(--xw); top: var(--yw); width: var(--ww); height: var(--hw, auto);
  --fx: var(--ox); --fy: var(--oy); --fs: 0.001; --fr: var(--rw, 0deg); --fold: 0deg;
  transform: translate(var(--ax, -50%), var(--ay, -100%)) translate(var(--fx), var(--fy)) rotate(var(--fr)) perspective(70cqmin) rotateX(var(--fold)) scale(var(--fs));
  opacity: 0; visibility: hidden;
  transition: transform var(--dur) cubic-bezier(.3, 1.25, .45, 1) var(--dl), opacity 0.3s linear var(--dl), visibility 0s linear calc(var(--dur) + var(--dl)); }
.piece:not(.pops) { --fs: 1; }
.piece.in { --fx: 0px; --fy: 0px; --fs: 1; opacity: 1; visibility: visible; transition: transform var(--dur) cubic-bezier(.3, 1.25, .45, 1) var(--dl), opacity 0.3s linear var(--dl), visibility 0s; }
.piece.box { --ax: 0%; --ay: 0%; transform-origin: 50% 50%; }
/* POP-UP BOOK: the piece lies flat and folds up (or down) on a hinge, overshoots, and settles */
.piece.fold { --fs: 1; opacity: 1; }
.piece.fold-up { transform-origin: var(--org, 50% 100%); --fold: 90deg; }
.piece.fold-down { transform-origin: var(--org, 50% 0%); --fold: -90deg; }
.piece.fold.in { --fold: 0deg; transition: transform var(--dur) cubic-bezier(.25, 1.6, .45, 1) var(--dl), opacity 0.2s linear var(--dl), visibility 0s; }
.piece.fold:not(.in) { opacity: 0; transition: transform calc(var(--dur) * 0.7) cubic-bezier(.6, 0, .9, .4) var(--dl), opacity 0.15s linear calc(var(--dl) + var(--dur) * 0.6), visibility 0s linear calc(var(--dur) + var(--dl)); }
.piece.fold::after { content: ""; position: absolute; left: 6%; right: 6%; bottom: -1.2cqmin; height: 2.4cqmin; border-radius: 50%;
  background: radial-gradient(closest-side, rgb(0 0 0 / 0.45), transparent); transition: opacity var(--dur); opacity: 0; pointer-events: none; }
.piece.fold-up.in::after { opacity: 1; }
.piece.tall-only { display: none; }
.piece.front { z-index: 5; }                         /* in front of the curtain and the spotlight, for the "in one" moments */
.piece > svg, .piece > div { display: block; width: 100%; height: auto; overflow: visible; }
.piece.box > div { height: 100%; }
.piece.flip > svg { transform: scaleX(-1); }
.set.instant .piece, .set.instant .piece * { transition: none !important; }
@container (aspect-ratio < 1) {
  .piece { left: var(--xt); top: var(--yt); width: var(--wt); height: var(--ht, auto); --fr: var(--rt, 0deg); }
  .piece.wide-only { display: none; }
  .piece.tall-only { display: block; }
}
/* hanging signs swing a little when they land; the scandal sign shakes */
.piece.swing.in > svg { transform-origin: 50% 0; animation: pieceSwing 1.8s ease-out var(--dl) 1; }
@keyframes pieceSwing { 0% { rotate: 7deg; } 30% { rotate: -5deg; } 55% { rotate: 3deg; } 80% { rotate: -1deg; } 100% { rotate: 0deg; } }
.piece.shake.lit > svg { animation: pieceShake 0.5s ease-in-out 2; }
@keyframes pieceShake { 0%, 100% { translate: 0 0; } 25% { translate: -1.2% 0; rotate: -2deg; } 75% { translate: 1.2% 0; rotate: 2deg; } }
.piece.tilt0 > svg { rotate: -7deg; } .piece.tilt1 > svg { rotate: 5deg; } .piece.tilt2 > svg { rotate: -3deg; }

/* marquee bulbs chase and letters flicker on once a piece is lit */
.piece .mb .d { fill: #6e5320; } .piece .mb .g { fill: #ffd36b; opacity: 0; }
.piece.lit .mb .d { animation: fChaseDot 0.9s steps(1) infinite; animation-delay: calc(var(--n) * -0.3s); }
.piece.lit .mb .g { animation: fChaseGlow 0.9s steps(1) infinite; animation-delay: calc(var(--n) * -0.3s); }
.piece .ml { fill-opacity: 0.15; stroke-opacity: 0.3; }
.piece.lit .ml { animation: fFlicker 0.5s linear forwards; animation-delay: calc(var(--k) * 0.045s); }

/* lights on: ring light, neon, ON AIR, studio lamps, camera REC, mirror */
.piece .halo { opacity: 0; transition: opacity 0.3s; }
.piece.lit .halo { opacity: 1; animation: ringOn 0.5s steps(1) 1; }
.piece.lit .ring { stroke: #fff6e6; }
@keyframes ringOn { 0% { opacity: 1; } 20% { opacity: 0.1; } 40% { opacity: 1; } 55% { opacity: 0.2; } 70% { opacity: 1; } }
.piece .neonT { stroke: #5a2a44; filter: none; }
.piece.lit .neonT { stroke: #ff5ab4; filter: url(#neonF); animation: ringOn 0.6s steps(1) 1; }
.piece.lit .onairBox { fill: #c8202a; } .piece.lit .onairT { fill: #fff; filter: drop-shadow(0 0 6px #fff); }
.piece .lamp { fill: #4a3a3a; } .piece.lit .lamp { fill: #fff6d0; filter: drop-shadow(0 0 10px #fff6d0); }
.piece .rec { opacity: 0.25; } .piece.lit .rec { animation: recBlink 1s steps(1) infinite; }
@keyframes recBlink { 0% { opacity: 1; } 50% { opacity: 0.2; } }
.piece .playhead { transform: translateX(100px); }
.piece.lit .playhead { animation: playhead 3.2s linear infinite; }
@keyframes playhead { from { transform: translateX(40px); } to { transform: translateX(960px); } }
.piece .clickring { transform-origin: 40px 40px; opacity: 0; }
.piece.lit .clickring { animation: clickRing 0.7s ease-out 1; }
.piece.lit > svg { animation: cursorClick 0.25s ease-in-out 1; }
@keyframes clickRing { 0% { opacity: 1; transform: scale(0.2); } 100% { opacity: 0; transform: scale(2.4); } }
@keyframes cursorClick { 50% { scale: 0.88; } }
.piece.glide.in > svg { animation: boatGlide 9s linear forwards; }
@keyframes boatGlide { from { translate: -120% 0; } to { translate: 120% 0; } }
.piece.glide .wheel { transform-box: fill-box; transform-origin: center; animation: spinWheel 2s linear infinite; }
@keyframes spinWheel { to { rotate: 360deg; } }

/* the console TV: static test card for the public demo */
.tvset { position: relative; }
.tvset .tvcab { display: block; width: 100%; height: auto; overflow: visible; }
.tvscreen { position: absolute; left: 8.1%; top: 18.1%; width: 68.8%; height: 60.6%; border-radius: 13% / 16%; overflow: hidden; background: #0a0a0c; }
.tvscreen svg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: 0; transition: opacity 0.6s; }
.piece.lit .tvscreen svg { opacity: 1; }
.tvscreen .scan { position: absolute; inset: 0; background: repeating-linear-gradient(0deg, rgb(0 0 0 / 0.18) 0 2px, transparent 2px 4px),
  radial-gradient(ellipse at 50% 40%, rgb(255 255 255 / 0.12), transparent 60%, rgb(0 0 0 / 0.5)); pointer-events: none; }
.piece.lit .tvscreen { animation: tvOn 0.5s ease-out 1; }
@keyframes tvOn { 0% { clip-path: inset(49% 0 49% 0); filter: brightness(3); } 60% { clip-path: inset(0 0 0 0); filter: brightness(1.6); } 100% { filter: none; } }

/* the Kristin wall frames */
.kframe { position: absolute; inset: 0; background: var(--fc); padding: 7%; box-shadow: 0.4cqmin 0.6cqmin 0 rgb(0 0 0 / 0.35); }
.kmat { position: relative; width: 100%; height: 100%; background: #fbf6ea; padding: 7%; container-type: size; }
.kmat span { position: absolute; inset: 7%; display: grid; place-items: center; background: #e9e2d2; color: #c9bfa8; font: 52cqmin/1 "Rye", serif; }
.kmat img { position: absolute; inset: 7%; width: 86%; height: 86%; object-fit: cover; opacity: 0; transition: opacity 0.4s; }
.kmat img.in { opacity: 1; }
.kheart { position: absolute; right: -5%; top: -7%; width: 18%; height: auto; }
@media (prefers-reduced-motion: reduce) { .piece, .piece * { animation: none !important; transition-duration: 0.01s !important; } }
/* "Except followers": everything goes dark except a pool of light on the FOLLOWERS 0 sign (and Sammie, who stands in front) */
.piece.fade.pops { --fs: 1; }
.piece.fade { transition: opacity 0.25s linear, visibility 0s linear 0.25s; }
.piece.fade.in { transition: opacity 0.12s linear, visibility 0s; }
.blackout { position: absolute; inset: 0; background: radial-gradient(ellipse 13% 17% at 66% 25%, transparent 60%, rgb(0 0 0 / 0.86) 100%); }
@container (aspect-ratio < 1) { .blackout { background: radial-gradient(ellipse 22% 9% at 72% 18%, transparent 60%, rgb(0 0 0 / 0.86) 100%); } }
.piece .dogeyes { animation: dogBlink 3.2s steps(1) infinite; transform-box: fill-box; transform-origin: center; }
@keyframes dogBlink { 0%, 92% { transform: scaleY(1); } 93%, 97% { transform: scaleY(0.1); } }
/* the Emerald City: soft glow, then it blazes when he clicks his heels */
.piece .cityglow { opacity: 0.35; transition: opacity 0.5s; }
.piece .win { fill: #8acfa0; }
.piece.lit .cityglow { opacity: 1; animation: cityPulse 2.4s ease-in-out 0.6s infinite; }
.piece.lit .win { fill: #f4fff6; filter: drop-shadow(0 0 4px #b0ffd0); }
.piece.lit .cstar { filter: drop-shadow(0 0 8px #fff6b0); animation: ringOn 0.5s steps(1) 1; }
.piece.lit > svg { animation: cityFlash 0.7s ease-out 1; }
@keyframes cityFlash { 0% { filter: brightness(2.6); } 100% { filter: none; } }
@keyframes cityPulse { 50% { opacity: 0.6; } }
/* Main Street: windows and lamps glow once a shop is lit; the castle twinkles */
.piece .shopwin { filter: brightness(0.5); } .piece.lit .shopwin { filter: drop-shadow(0 0 6px #ffcf7a); }
.piece .lampglow { opacity: 0; } .piece.lit .lampglow { opacity: 0.4; }
.piece .cwin { fill: #6a5a3a; } .piece.lit .cwin { fill: #fff2b8; }
.piece.lit .cstar { animation: starTw 1.6s ease-in-out infinite; transform-box: fill-box; transform-origin: center; }
@keyframes starTw { 50% { transform: scale(1.3) rotate(15deg); filter: drop-shadow(0 0 6px #fff6b0); } }
/* clouds: each one floats and bobs on its own slow rhythm (the svg moves, the piece handles enter and exit) */
.piece.drift > svg { animation: cloudDrift 9s ease-in-out infinite alternate; }
.piece.drift.d1 > svg { animation-duration: 11s; animation-delay: -3s; }
.piece.drift.d2 > svg { animation-duration: 8s; animation-delay: -5s; }
.piece.drift.d3 > svg { animation-duration: 12s; animation-delay: -2s; }
.piece.drift.d4 > svg { animation-duration: 10s; animation-delay: -7s; }
.piece.drift.d5 > svg { animation-duration: 13s; animation-delay: -4s; }
.piece.drift.flip > svg { animation-name: cloudDriftFlip; }
@keyframes cloudDrift { 0% { translate: -4% 0; } 50% { translate: 2% -6%; } 100% { translate: 5% 2%; } }
@keyframes cloudDriftFlip { 0% { transform: scaleX(-1); translate: 4% 0; } 50% { transform: scaleX(-1); translate: -2% -6%; } 100% { transform: scaleX(-1); translate: -5% 2%; } }
.piece.drift { --dur-out: 1.6s; }
.piece.drift:not(.in) { transition: transform 1.6s cubic-bezier(.5, 0, .8, .5), opacity 0.4s linear 1.2s, visibility 0s linear 1.6s; }
/* lobby sign lettering: dim in the dark, flickers on letter by letter when the flashlight finds it, then an
   occasional buzz like an old neon tube. Outside the lobby it stays fully lit. */
body.lobby .marquee-btn .sl { fill-opacity: 0.3; transition: fill-opacity 0.4s; }
body.lobby .marquee-btn.lit .sl { animation: fFlicker 0.5s linear forwards, signBuzz 7s steps(1) infinite; animation-delay: calc(var(--k) * 0.06s), calc(2s + var(--k) * 0.53s); }
@keyframes signBuzz { 0%, 96% { fill-opacity: 1; } 97% { fill-opacity: 0.25; } 98% { fill-opacity: 1; } 99% { fill-opacity: 0.4; } }
@media (prefers-reduced-motion: reduce) { body.lobby .marquee-btn .sl { fill-opacity: 1; animation: none !important; } }
/* the spinning newspaper: in from far away, twirling, and slaps to a stop; leaves crumpling small */
.piece.spinin:not(.in) { --fr: 900deg; }
.piece.spinin.in { transition: transform 0.9s cubic-bezier(.2, .9, .3, 1.15), opacity 0.2s, visibility 0s; }
.piece.spinin:not(.in) { transition: transform 0.45s cubic-bezier(.6, 0, .9, .4), opacity 0.2s linear 0.25s, visibility 0s linear 0.45s; }
.flashes { position: absolute; inset: 0; }
.flashes i { position: absolute; width: 22cqmin; height: 22cqmin; margin: -11cqmin; border-radius: 50%; opacity: 0;
  background: radial-gradient(circle, #fff 0 12%, rgb(255 255 255 / 0.7) 22%, transparent 62%); }
.piece.lit .flashes i { animation: popFlash 1.4s steps(1) infinite; animation-delay: calc(var(--i) * 0.21s); }
@keyframes popFlash { 0% { opacity: 1; } 8% { opacity: 0.4; } 14% { opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .piece.lit .flashes i { animation: none; } }
.piece.front.top { z-index: 6; }
/* wall pieces (the Kristin frames) are placed first in the set layer, so the furniture stacks in front of them */
/* CARRY ACROSS A CUT: the piece glides to a new spot (e.g. the newspaper onto the apology wall) */
.piece.carry.in { transition: transform 0.9s cubic-bezier(.2, .9, .3, 1.15), left 1s cubic-bezier(.5, 0, .3, 1), top 1s cubic-bezier(.5, 0, .3, 1), width 1s cubic-bezier(.5, 0, .3, 1), opacity 0.2s, visibility 0s; }
.piece.carry.pinned { left: var(--pxw); top: var(--pyw); width: var(--pww); --fr: -3deg; z-index: 0; }
@container (aspect-ratio < 1) { .piece.carry.pinned { left: var(--pxt); top: var(--pyt); width: var(--pwt); } }
.piece .tape, .piece .sticky { opacity: 0; }
.piece.pinned .tape { opacity: 1; transition: opacity 0.2s 0.9s; }
.piece.pinned .sticky { opacity: 1; transform-box: fill-box; transform-origin: center; animation: stickySlap 0.35s cubic-bezier(.3, 1.8, .5, 1) 1.5s both; }
@keyframes stickySlap { from { opacity: 0; scale: 2.2; } to { opacity: 1; scale: 1; } }
/* the mic tilts toward him on held notes and swings out on the chorus (pivot at the base) */
.piece .micsvg { transform-origin: 50% 97%; transition: rotate 0.5s cubic-bezier(.3, 1.4, .5, 1); }
.piece.lean .micsvg { rotate: -9deg; }
.piece.swingmic .micsvg { animation: micSwing 2.9s ease-in-out 1; }
@keyframes micSwing { 0% { rotate: 0deg; } 20% { rotate: 22deg; } 45% { rotate: -16deg; } 70% { rotate: 10deg; } 100% { rotate: 0deg; } }
.piece.front.mic { z-index: 6; }
/* TAP ME!: a gentle pulse so the eye finds the button */
.marquee-btn .tapme { transform-box: fill-box; transform-origin: center; animation: tapPulse 2.4s ease-in-out infinite; }
@keyframes tapPulse { 0%, 70%, 100% { scale: 1; filter: none; } 80% { scale: 1.1; filter: drop-shadow(0 0 6px #7ff0e6); } 90% { scale: 0.98; } }
@media (prefers-reduced-motion: reduce) { .marquee-btn .tapme { animation: none; } }
/* sparkler writing: the letters draw on as glowing light, then fizzle */
.piece .sparkname text { stroke-dasharray: 1; stroke-dashoffset: 1; }
.piece.lit .sparkname text { animation: sparkDraw 1.9s ease-in-out forwards, sparkFlicker 0.12s steps(2) infinite; }
@keyframes sparkDraw { to { stroke-dashoffset: 0; } }
@keyframes sparkFlicker { 50% { stroke: #ffd36b; } }
.piece.fade:not(.in) .sparkname { filter: blur(3px); }
/* the moon is stolen: the sky gets a shade darker */
.skydim { position: absolute; inset: 0; background: rgb(0 4 24 / 0.35); }
/* merch: the bobblehead nods */
.piece.lit .bobble { transform-box: fill-box; transform-origin: 50% 100%; animation: bobble 0.9s ease-in-out infinite; }
@keyframes bobble { 0%, 100% { rotate: -8deg; } 50% { rotate: 8deg; } }
.piece.moonpin.pinned { z-index: 5; }   /* the stolen moon sits in front of him, under his arm */
/* =====================================================================
   TAPPABLE: hotspots on set pieces, and the card they open (tappable.js)
   ===================================================================== */
.world { pointer-events: none; }
.world .release-btn:not(.gone), .world button { pointer-events: auto; }
.piece.tappable.in { pointer-events: auto; cursor: pointer; }
.piece.tappable:focus-visible { outline: 0.5cqmin solid #ffd36b; outline-offset: 0.6cqmin; }
.piece.tappable.in:hover > svg { filter: drop-shadow(0 0 1.2cqmin rgb(255 211 107 / 0.85)); }
.taphint { position: absolute; right: -1cqmin; top: -1cqmin; z-index: 2; font: 800 normal 1.6cqmin/1 Archivo, sans-serif; letter-spacing: 0.08em;
  color: #1a1a1f; background: #ffd36b; padding: 0.5cqmin 0.9cqmin; border-radius: 99px; box-shadow: 0 0.3cqmin 0 #8a6a1a;
  opacity: 0; transform: scale(0.4); transition: opacity 0.3s, transform 0.3s cubic-bezier(.3,1.6,.5,1); pointer-events: none; }
.piece.tappable.in .taphint { opacity: 1; transform: scale(1); animation: tapPulse 1.6s ease-in-out 1s infinite; }
@keyframes tapPulse { 50% { transform: scale(1.15); } }
@media (prefers-reduced-motion: reduce) { .piece.tappable.in .taphint { animation: none; } }

.tapcard { position: absolute; inset: 0; z-index: 20; display: grid; place-items: center; --ox: 50%; --oy: 50%; }
.tapcard[hidden] { display: none; }
.tap-backdrop { position: absolute; inset: 0; background: rgb(12 8 18 / 0.72); opacity: 0; transition: opacity 0.25s; backdrop-filter: blur(2px); }
.tapcard.on .tap-backdrop { opacity: 1; }
.tap-box { position: relative; width: min(84cqw, 120cqh); max-height: 88cqh; display: flex; flex-direction: column; align-items: center; gap: 1.6cqmin;
  transform-origin: var(--ox) var(--oy); transform: scale(0.2); opacity: 0; transition: transform 0.35s cubic-bezier(.3,1.3,.5,1), opacity 0.2s; }
.tapcard.on .tap-box { transform: none; opacity: 1; }
.tap-body { width: 100%; min-height: 0; overflow: auto; display: grid; place-items: center; }
.tap-zoom { width: 100%; display: grid; place-items: center; }
.tap-zoom svg { display: block; width: min(100%, 76cqh * 1.4); height: auto; max-height: 76cqh; }
.tap-close { font: 800 2.2cqmin/1 Archivo, sans-serif; color: #1a1a1f; background: #ffd36b; border: 0; border-radius: 99px; padding: 1.4cqmin 3cqmin;
  box-shadow: 0 0.5cqmin 0 #8a6a1a; cursor: pointer; flex: none; }
.tap-close:focus-visible { outline: 0.4cqmin solid #fff; outline-offset: 0.4cqmin; }
/* article cards */
.tap-box[data-type="article"] { width: min(86cqw, 110cqh); }
.tap-article { width: 100%; box-sizing: border-box; background: #fff8ea; color: #1a1a1f; border-radius: 1.4cqmin; padding: 3cqmin 3.4cqmin;
  display: grid; grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr); column-gap: 3cqmin; align-items: start; font: 500 2.2cqmin/1.45 Archivo, sans-serif; }
.tap-art { grid-row: 1 / span 4; } .tap-art svg { width: 100%; height: auto; max-height: 64cqh; display: block; }
.tap-kicker { margin: 0; font-weight: 800; font-size: 1.7cqmin; letter-spacing: 0.14em; color: #c8202a; }
.tap-article h2 { margin: 0.4cqmin 0 1.2cqmin; font: 400 4cqmin/1.1 Rye, serif; color: #1a1a1f; }
.tap-text p { margin: 0 0 1cqmin; } .tap-list { margin: 0 0 1.2cqmin; padding-left: 2.4cqmin; } .tap-list li { margin-bottom: 0.5cqmin; }
.tap-fine { font-size: 1.7cqmin; color: #6a5a4a; font-style: italic; }
@container (aspect-ratio < 1) {
  .tap-box { width: 92cqw; }
  .tap-article { grid-template-columns: 1fr; font-size: 3.4cqmin; padding: 4cqmin; }
  .tap-art { grid-row: auto; max-width: 60%; justify-self: center; margin-bottom: 2cqmin; } .tap-art svg { max-height: 34cqh; }
  .tap-kicker { font-size: 2.6cqmin; } .tap-article h2 { font-size: 6cqmin; } .tap-fine { font-size: 2.8cqmin; }
  .tap-close { font-size: 3.6cqmin; padding: 2.2cqmin 5cqmin; } .taphint { font-size: 2.6cqmin; }
}
/* postcards turn over */
.tap-box[data-type="flip"] { width: min(70cqw, 96cqh); perspective: 200cqmin; }
.tap-flip { position: relative; width: 100%; aspect-ratio: 300 / 220; transform-style: preserve-3d; transition: transform 0.8s cubic-bezier(.4,1.4,.5,1); }
.tapcard.flipped .tap-flip { transform: rotateY(180deg); }
.tap-flip { cursor: pointer; }
.tap-fliphint { margin: 2cqmin 0 0; text-align: center; font: 700 normal 1.9cqmin/1.2 Archivo, sans-serif; letter-spacing: .06em; color: #fff6e0; opacity: .85; }
@container (aspect-ratio < 1) { .tap-fliphint { font-size: 3cqmin; } }
.tap-face { position: absolute; inset: 0; backface-visibility: hidden; }
.tap-face svg { width: 100%; height: 100%; display: block; }
.tap-back { transform: rotateY(180deg); }
.tap-body:has(.tap-flip) { overflow: visible; }
.pcback { position: absolute; inset: 0 3.3% 5.4% 0; background: #fff8ea; display: grid; grid-template-columns: 1.3fr 1fr; padding: 5% 5%; box-sizing: border-box; gap: 4%;
  box-shadow: 1cqmin 1cqmin 0 rgb(0 0 0 / 0.25); font: italic 400 3.4cqmin/1.3 "Brush Script MT", "Segoe Script", "Comic Sans MS", cursive; color: #2a3a8a; }
.pcmsg { border-right: 0.3cqmin solid #c9b8a0; padding-right: 5%; } .pcmsg p { margin: 0 0 0.8em; } .pcmsg .pcps { margin-top: 1.2em; color: #c8202a; }
.pcaddr { position: relative; padding-top: 34%; } .pcaddr p { margin: 0; border-bottom: 0.25cqmin solid #c9b8a0; line-height: 1.9; }
.pcstamp { position: absolute; right: 0; top: 0; width: 34%; aspect-ratio: 0.85; background: #ff9ad5; border: 0.5cqmin dashed #fff8ea; outline: 0.3cqmin solid #c94f8a;
  display: grid; place-items: center; font: 800 normal 2.6cqmin Archivo, sans-serif; color: #fff; }
@container (aspect-ratio < 1) { .tap-box[data-type="flip"] { width: 94cqw; } .pcback { font-size: 3.2cqmin; } }

/* Pre-show: reuse the finale's real merchandise stand, in front of the curtain. */
body.sammie-preshow .piece[data-id="merch"] { pointer-events: none; }
body.sammie-preshow-merch .piece[data-id="merch"] { z-index: 8; }

/* Kristin's souvenir trophies: tiny city medals instead of hearts. */
.ktrophy {position:absolute;left:1%;right:1%;bottom:1%;display:flex;align-items:center;justify-content:center;gap:2%;padding:2% 1%;background:linear-gradient(120deg,#7b5616,#e9c66e,#94661c);color:#231509;box-shadow:0 1px 3px #0008;font-family:Arial,sans-serif;font-weight:800;line-height:1.05;white-space:nowrap;overflow:hidden}
.kmedal {font-size:clamp(7px,1.1cqmin,17px)} .kcity {font-size:clamp(5px,.75cqmin,11px);letter-spacing:.04em}.kcaption {font-size:clamp(4px,.57cqmin,9px);font-style:italic;font-weight:600;overflow:hidden;text-overflow:ellipsis}
.oz-monkey-flight {width:100%;height:100%;animation:ozMonkeyCross 4.5s linear both;transform-origin:center}
.oz-monkey-flight svg {width:100%;height:100%;overflow:visible;filter:drop-shadow(3px 5px 3px #0005)}
.oz-monkey-wing {transform-box:fill-box;transform-origin:center 75%;animation:ozFlap .24s ease-in-out infinite alternate}
.oz-monkey-wing-r {animation-direction:alternate-reverse}
@keyframes ozFlap {from{transform:rotate(-22deg)}to{transform:rotate(24deg)}}
@keyframes ozMonkeyCross {0%{transform:translate(-70vw,4vh) scale(.65) rotate(-8deg)}50%{transform:translate(30vw,-8vh) scale(1.1) rotate(7deg)}100%{transform:translate(115vw,1vh) scale(.8) rotate(-4deg)}}
@media(prefers-reduced-motion:reduce){.oz-monkey-flight,.oz-monkey-wing{animation:none}}

/* Kristin's worldwide near-miss trophy labels */
.ktrophy{position:absolute;left:3%;right:3%;bottom:2%;background:linear-gradient(120deg,#80591c,#eac774,#926419);padding:2% 1%;display:flex;align-items:center;justify-content:center;gap:3%;color:#26190d;white-space:nowrap;overflow:hidden;font:700 clamp(5px,.72cqmin,12px)/1.05 Arial,sans-serif;box-shadow:0 1px 3px #0007}
.ktrophy .kmedal{font-size:1.4em}.ktrophy .kcaption{font-size:.75em;font-style:italic;overflow:hidden;text-overflow:ellipsis}
/* Broadway phone and Kristin shrine */
.phone-shrine{width:100%;height:100%;display:flex;justify-content:center;align-items:center;gap:2%;transform:rotate(-2deg)}
.shrine-frame{width:18%;height:70%;padding:2%;background:#ae803e;border:2px solid #f7d58d;box-shadow:2px 3px 0 #0007;transform:rotate(var(--tilt,3deg))}
.shrine-frame:nth-child(even){--tilt:-7deg}.shrine-frame img{width:100%;height:100%;object-fit:cover}
.ringing-phone .phone-handset{transform-box:fill-box;transform-origin:center bottom;animation:phoneShake .13s steps(2,end) infinite alternate}
@keyframes phoneShake{from{transform:rotate(-5deg) translateY(-3px)}to{transform:rotate(5deg) translateY(2px)}}
@media(prefers-reduced-motion:reduce){.ringing-phone .phone-handset{animation:none}}

/* New welcome: visible only while the pre-show runs. */

/* Welcome props: match the established cutout scenery, hanging rigging, and bulb marquees. */
#sammieIntroProps{position:absolute;inset:0;z-index:24;pointer-events:none;overflow:hidden;display:none;font-family:Georgia,serif;color:#ffe5a3}
body.sammie-preshow #sammieIntroProps{display:block}
#sammieIntroProps .iprop{position:absolute;display:none;box-sizing:border-box;text-align:center;filter:drop-shadow(5px 7px 0 #160e17a8)}
#sammieIntroProps .ip-rig{position:absolute;bottom:100%;height:45vh;left:20%;width:60%;border-left:2px solid #b0a9a2;border-right:2px solid #b0a9a2;pointer-events:none}
#sammieIntroProps .ip-bulbs{position:absolute;inset:3%;border:3px solid #e6ba65;pointer-events:none;display:flex;flex-wrap:wrap;align-content:space-between;justify-content:space-around;gap:3px;padding:3px}
#sammieIntroProps .ip-bulbs i{width:clamp(3px,.7cqmin,9px);height:clamp(3px,.7cqmin,9px);border-radius:50%;background:#ffedaf;box-shadow:0 0 6px #ffe29b;animation:ipChase .9s steps(2,end) infinite;animation-delay:calc(var(--b)*-65ms)}
@keyframes ipChase{50%{background:#a86936;box-shadow:none}}
#sammieIntroProps.ip-merch-on .ip-merch{display:grid;bottom:13%;right:6%;width:35%;padding:2cqmin;background:#69293c;border:6px ridge #d6a55b;gap:1.2cqmin;animation:ipSlide .7s steps(6,end) both}
.ip-merch strong{font:900 2.3cqmin Georgia,serif}.ip-merch-items{display:flex;gap:.5cqmin;justify-content:space-around}.ip-merch-items>span{display:grid;background:#f3d49a;color:#5e2b3a;border:2px solid #c88b4b;width:30%;font-size:3cqmin}.ip-merch-items small{font:700 1cqmin system-ui}
@keyframes ipLower{from{transform:translateY(-130%)}to{transform:translateY(0)}}
@keyframes ipSlide{from{transform:translateX(150%)}to{transform:translateX(0)}}
@keyframes ipSway{from{transform:rotate(-8deg)}to{transform:rotate(8deg)}}
/* The *real* skip button gets the joke: chasing bulbs and a restrained wobble. */
@keyframes ipSkipWiggle{0%,100%{rotate:0deg}25%{rotate:-5deg}75%{rotate:5deg}}
@keyframes ipSkipGlow{50%{box-shadow:0 0 16px #f5d783,0 0 4px #fff inset}}
@keyframes ipArrowDrop{from{translate:0 -25px;opacity:0}to{translate:0 0;opacity:1}}

/* Short announcement: original merchandise artwork only; black stage, lingering existing flashlight. */
#sammieIntroProps { display:none !important; }
#sammieIntroBlackout { display:none; position:absolute; inset:0; background:#000; z-index:90; pointer-events:none; }
body.sammie-intro-blackout #sammieIntroBlackout { display:block; }
body.sammie-intro-blackout .flashbeam { z-index:91; mix-blend-mode:normal; }
body.sammie-intro-blackout .marquee-btn { opacity:0 !important; }

/* Intro: modest theatrical paper-cutout hearts, not a screen overlay. */
.sammie-intro-hearts{position:absolute;inset:0;pointer-events:none;z-index:85;overflow:hidden;visibility:hidden}
.sammie-intro-hearts.playing{visibility:visible}
.sammie-intro-hearts span{position:absolute;left:calc(40% + (var(--i) * 1.8%));bottom:24%;font-size:clamp(12px,2.1vw,27px);color:#e96a95;-webkit-text-stroke:1px #8b2954;text-shadow:2px 3px 0 #5c2544;opacity:0;transform:translateY(0) rotate(-12deg);}
.sammie-intro-hearts.playing span{animation:sammie-heart-rise 2.8s ease-out both;animation-delay:calc(var(--i) * 0.095s)}
@keyframes sammie-heart-rise{0%{opacity:0;transform:translateY(0) rotate(-12deg) scale(.6)}18%{opacity:.9}80%{opacity:.85}100%{opacity:0;transform:translateY(-32vh) translateX(calc((var(--i) - 7) * 5px)) rotate(18deg) scale(1.2)}}
@media(prefers-reduced-motion:reduce){.sammie-intro-hearts.playing span{animation:none;opacity:0}}

/* Broadway shrine: one signed poster and four intentionally uneven cutout frames.
   The set-piece positioning stays anchored above the red phone. */
.phone-shrine{position:relative;display:block;transform:none;overflow:visible}
.phone-shrine .shrine-poster{position:absolute;left:32%;top:2%;width:37%;height:94%;padding:1.5%;background:#aa7535;border:3px solid #f5d394;box-shadow:3px 5px 0 #0008;transform:rotate(-1deg);z-index:2}
.phone-shrine .shrine-poster img{display:block;width:100%;height:100%;object-fit:contain;background:#19151d}
.phone-shrine .shrine-frame{position:absolute;width:22%;height:39%;padding:1.4%;background:#ae803e;border:2px solid #f7d58d;box-shadow:2px 3px 0 #0008;z-index:1}
.phone-shrine .shrine-photo-1{left:5%;top:8%;transform:rotate(-9deg)}
.phone-shrine .shrine-photo-2{left:4%;top:56%;transform:rotate(7deg)}
.phone-shrine .shrine-photo-3{right:3%;top:7%;transform:rotate(8deg)}
.phone-shrine .shrine-photo-4{right:4%;top:56%;transform:rotate(-7deg)}
.phone-magic-wrap{position:relative;width:100%;height:100%;overflow:visible}
.phone-magic-wrap>svg{display:block;width:100%;height:100%}
.phone-magic-notes{position:absolute;inset:0;overflow:visible;pointer-events:none}
.phone-magic-notes span{position:absolute;left:55%;top:22%;font-family:Georgia,serif;font-size:clamp(15px,2.5vw,42px);font-weight:bold;color:#ffdc7b;-webkit-text-stroke:.6px #aa612b;text-shadow:0 0 5px #fff3ae,0 0 12px #f8a3d4,2px 3px 0 #52284b;opacity:0;animation:phone-note-magic 1.45s ease-out infinite;animation-delay:calc(var(--n) * .25s)}
.phone-magic-notes span:nth-child(1){--n:0;--dx:-35px}
.phone-magic-notes span:nth-child(2){--n:1;--dx:20px}
.phone-magic-notes span:nth-child(3){--n:2;--dx:-10px}
.phone-magic-notes span:nth-child(4){--n:3;--dx:44px}
.phone-magic-notes span:nth-child(5){--n:4;--dx:-48px}
@keyframes phone-note-magic{0%{opacity:0;transform:translate(0,0) rotate(-12deg) scale(.3)}18%{opacity:1;transform:translate(0,-8px) rotate(5deg) scale(1)}65%{opacity:.9}100%{opacity:0;transform:translate(var(--dx),-75px) rotate(20deg) scale(.65)}}
/* Magical stage-light hearts, like the show's sparkling musical effects. */
.sammie-intro-hearts span{color:#ff9dc8;-webkit-text-stroke:1px #9d386d;text-shadow:0 0 5px #fff3c4,0 0 13px #f870bd,2px 3px 0 #742e58}
.sammie-intro-hearts.playing span{animation-name:sammie-heart-magic;animation-duration:2.6s}
.sammie-intro-hearts span::after{content:'✦';position:absolute;top:-.4em;right:-.3em;font-size:.55em;color:#ffe6a0;text-shadow:0 0 6px #fff;animation:heart-glint .48s steps(2,end) infinite alternate}
@keyframes sammie-heart-magic{0%{opacity:0;transform:translateY(0) scale(.15) rotate(-25deg)}15%{opacity:1;transform:translateY(-10px) scale(1.25) rotate(8deg)}35%{transform:translateY(-50px) scale(.85) rotate(-8deg)}80%{opacity:.9}100%{opacity:0;transform:translateY(-31vh) translateX(calc((var(--i) - 7) * 6px)) rotate(24deg) scale(.4)}}
@keyframes heart-glint{from{opacity:.2;transform:scale(.6)}to{opacity:1;transform:scale(1.35)}}
@media(prefers-reduced-motion:reduce){.phone-magic-notes span,.sammie-intro-hearts span::after{animation:none;opacity:0}}

/* Phone shrine uses the proven Kristin wall frame and lazy image loader. */
.phone-shrine .kframe{box-sizing:border-box;display:block}
.phone-shrine .kmat{box-sizing:border-box;width:100%;height:100%;padding:7%;position:relative}
.phone-shrine .kmat img{display:block;position:absolute;inset:7%;width:86%;height:86%;object-fit:cover;opacity:0;transition:opacity .4s}
.phone-shrine .kmat img.in{opacity:1}
.phone-shrine .shrine-poster .kmat img{object-fit:contain;background:#17151c}

/* Performance: stop decorative CSS timelines outside the viewport. */
html.sammie-offscreen *, html.sammie-offscreen *::before, html.sammie-offscreen *::after { animation-play-state: paused !important; }

/* Public demo panel: keep original controls and listeners intact. */
.panel.sammie-public-demo .demo-preview-pane > .group { display: none !important; }
.panel.sammie-public-demo .demo-preview-pane { align-content: start; }
.panel.sammie-public-demo .demo-teaser { margin: 1.25rem 0.15rem; padding: 1.5rem 1.1rem; border: 2px solid #a77d30; background: #19191d; box-shadow: 5px 6px 0 rgba(0,0,0,.28); text-align: center; }
.panel.sammie-public-demo .demo-teaser h3 { margin: 0 0 1rem; color: #f6d990; font-size: 1.05rem; letter-spacing: .11em; line-height: 1.35; }
.panel.sammie-public-demo .demo-teaser p { color: #e8dfcb; font-size: .88rem; line-height: 1.55; margin: .8rem 0; }
.panel.sammie-public-demo .demo-teaser .demo-teaser-lead { font-size: 1rem; color: #fff; font-weight: 700; }
.panel.sammie-public-demo .demo-teaser .demo-teaser-aside { border-top: 1px solid #6a552c; margin-top: 1.35rem; padding-top: 1rem; color: #c8b58c; font-style: italic; font-size: .8rem; }
.panel.sammie-public-demo #rtnJumps button.demo-scene-active { border-color: #f2c65a; background: #3c3020; color: #ffe7a1; box-shadow: inset 0 0 0 1px #f2c65a, 0 0 10px rgba(242,198,90,.18); font-weight: 800; }
.panel.sammie-public-demo #rtnJumps button.demo-scene-active:focus-visible { outline: 3px solid #fff; outline-offset: 2px; }

/* Public demo: hide tap timing visually, preserve its DOM and listeners. */
.panel.sammie-public-demo #pane-show > .demo-hidden-tap-tools { display: none !important; }
.panel.sammie-public-demo .demo-show-about { margin: 1.35rem 0 1rem; padding: 1.1rem 0.2rem; border-top: 1px solid #514b42; }
.panel.sammie-public-demo .demo-show-about h3 { margin: .15rem 0 .9rem; font-size: .95rem; font-weight: 800; letter-spacing: .15em; color: #f0e8da; }
.panel.sammie-public-demo .demo-show-about p { margin: .8rem 0; color: #d6d0c6; font-size: .9rem; line-height: 1.55; }
.panel.sammie-public-demo .demo-show-about .demo-show-about-punchline { color: #f5d38a; font-weight: 700; }
.panel.sammie-public-demo .demo-show-about .demo-show-about-signoff { color: #f4efe6; font-weight: 700; }

/* ===== PAPER CUTOUT SIGNPOSTS (signpost() in set.js) ===== */
.signpost .sb, .signpost .sbw { transform-box: view-box; }
.signpost .sb { transition: transform .5s cubic-bezier(.3, 1.7, .5, 1), opacity .15s linear; }
/* staggered: each board waits, swung up on its brad, until its state class arrives */
.piece.stagger .sb { opacity: 0; transform: rotate(var(--sw)) scale(.5); }
.piece.stagger.s1 .sb1, .piece.stagger.s2 .sb2, .piece.stagger.s3 .sb3, .piece.stagger.s4 .sb4, .piece.stagger.s5 .sb5 { opacity: 1; transform: none; }
/* the boards he points at wiggle on their brads */
.piece.wl .sbL .sbw, .piece.wr .sbR .sbw { animation: sbWiggle .36s ease-in-out var(--wd) 2; }
@keyframes sbWiggle { 0%, 100% { transform: rotate(0); } 30% { transform: rotate(-9deg); } 70% { transform: rotate(7deg); } }
/* "Sometimes even the right ones": every board whirls like a weathervane and settles */
.piece.whirl .sbw { animation: sbWhirl 1.3s cubic-bezier(.25, .6, .35, 1.25) calc(var(--wd) * 2) 1 both; }
.piece.whirl .sbR .sbw { animation-name: sbWhirlR; }
@keyframes sbWhirl { 0% { transform: rotate(0); } 100% { transform: rotate(-360deg); } }
@keyframes sbWhirlR { 0% { transform: rotate(0); } 100% { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .signpost .sb { transition: none; } }

/* ===== SKYWRITING WITCH (skywriting() in set.js) ===== */
/* the whole sky leans back, so the letters lie on the sky and recede */
.piece.skyw > svg { transform: perspective(110cqmin) rotateX(17deg); transform-origin: 50% 55%; overflow: visible; }
.skywrite .sw-puff { --puff: 1; }
.skywrite .sw-soft, .skywrite .sw-core { fill: none; stroke-linecap: round; stroke-linejoin: round; }
.skywrite .sw-soft { stroke: #fbf7ff; stroke-opacity: .5; stroke-width: calc(17px * var(--puff)); }
.skywrite .sw-core { stroke: #ffffff; stroke-opacity: .9; stroke-width: calc(6px * var(--puff)); }
.skywrite .sw-cut { animation: swWobble .4s steps(2, end) infinite alternate; transform-box: fill-box; transform-origin: center; }
.skywrite .sw-cape { animation: swCape .22s steps(2, end) infinite alternate; transform-box: fill-box; transform-origin: 100% 0; }
@keyframes swWobble { from { transform: rotate(-4deg); } to { transform: rotate(4deg); } }
@keyframes swCape { from { transform: rotate(-10deg); } to { transform: rotate(8deg); } }

/* ===== THE SAMMIE SHOW marquee (showMarquee() in set.js): cutout stars pop in once the bulbs light ===== */
.piece .mstar { transform: scale(0) rotate(-40deg); transform-box: fill-box; transform-origin: center; transition: transform .45s cubic-bezier(.3, 1.8, .5, 1); }
.piece.lit .mstar { transform: none; transition-delay: calc(.5s + var(--s) * .18s); animation: mstarTwinkle 2.4s ease-in-out calc(1.4s + var(--s) * .6s) infinite; }
@keyframes mstarTwinkle { 0%, 100% { transform: none; } 50% { transform: scale(.82) rotate(12deg); } }
/* the arrow wags at him */
.piece.lit .himarrow { transform-origin: 50% 0; animation: himWag .5s ease-in-out infinite alternate; }
@keyframes himWag { from { transform: rotate(-4deg); } to { transform: rotate(4deg); } }
@media (prefers-reduced-motion: reduce) { .piece .mstar { transform: none; } }

/* ===== the flying autograph quill (quillTick in set.js) ===== */
.quillfly { position: absolute; inset: 0; overflow: visible; }
.quillfly .qpen { position: absolute; left: 0; top: 0; overflow: visible; filter: drop-shadow(2px 3px 0 #0005); }
.quillfly .qsplat { position: absolute; left: 0; top: 0; transform-origin: 50% 50%; }
.quillfly .qsplat svg { display: block; width: 100%; height: auto; }
