/* Brainrotteria, concept D: concept B's pixel-scene site, with a home page that cycles through several
   animated locations (the scene modules in d-src/scenes/*). Colours are the game's (PixelIcons.swift Pal)
   plus Luna Park's indigo sky. Type, footer and inner pages are concept B's, to the letter. */

@font-face {
  font-family: "Brainrot Pixel";
  src: url("fonts/brainrot-pixel-bold.woff2") format("woff2");
  font-weight: 700;
  font-display: block;
}

:root {
  color-scheme: dark;
  --ink: #24140f;
  --night: #120f45;        /* the sky at the top of the picture */
  --night-2: #1c1a6a;
  --nebula: #4b2a9e;
  --cream: #fff3d6;
  --cream-dark: #f0d9a8;
  --cream-light: #fffaf0;
  --gold: #ffc83d;
  --gold-dark: #d08a12;
  --magenta: #ff3cac;
  --cyan: #2bd2ff;
  --coffee: #6b3a2a;
  --body: "Nunito", ui-rounded, "SF Pro Rounded", system-ui, -apple-system, "Segoe UI", sans-serif;
  --pixel: "Brainrot Pixel", ui-monospace, monospace;
  --px: 0.125em;           /* one pixel of the pixel font (8 pixels per em) */
  --u: 4px;                /* one pixel of the pixel UI borders */
  --slice: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' shape-rendering='crispEdges'%3E%3Crect x='3' y='3' width='6' height='6' fill='%23fff3d6'/%3E%3Cpath fill='%2324140f' d='M2 0h8v1h1v1h1v8h-1v1h-1v1H2v-1H1v-1H0V2h1V1h1z'/%3E%3Cpath fill='%23fff3d6' d='M2 1h8v1h1v8h-1v1H2v-1H1V2h1z'/%3E%3Cpath fill='%23fffaf0' d='M2 2h8v1H3v7H2z'/%3E%3Cpath fill='%23f0d9a8' d='M9 3h1v7H2v1h8v-1h1V3z' /%3E%3C/svg%3E");
}

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; background: var(--night); }
body {
  margin: 0; color: var(--cream); background: var(--night);
  font: 500 1.0625rem/1.65 var(--body);
}
img { max-width: 100%; height: auto; display: block; }
a { color: var(--cyan); font-weight: 700; }
:focus-visible { outline: 3px solid var(--gold); outline-offset: 3px; }

.pixel { font-family: var(--pixel); font-weight: 700; line-height: 1.25; text-transform: uppercase; letter-spacing: 0; }
/* A one-pixel ink outline plus a two-pixel hard drop, as the game draws its titles. */
.outlined {
  text-shadow:
    var(--px) 0 var(--ink), calc(-1 * var(--px)) 0 var(--ink), 0 var(--px) var(--ink), 0 calc(-1 * var(--px)) var(--ink),
    var(--px) var(--px) var(--ink), calc(-1 * var(--px)) var(--px) var(--ink), var(--px) calc(-1 * var(--px)) var(--ink),
    calc(-1 * var(--px)) calc(-1 * var(--px)) var(--ink),
    0 calc(2 * var(--px)) var(--ink), var(--px) calc(2 * var(--px)) var(--ink), calc(-1 * var(--px)) calc(2 * var(--px)) var(--ink);
}
/* Outlined pixel letters need two more pixels between them, or the outlines merge into a slab. */
.outlined { letter-spacing: calc(2 * var(--px)); margin-right: calc(-2 * var(--px)); }

/* ---------- Footer: just the links, on whatever is behind it ---------- */

.foot { padding: 40px 16px 32px; text-align: center; }
.foot nav { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px 24px; }
.foot a { font-family: var(--pixel); font-weight: 700; text-transform: uppercase; font-size: 16px; line-height: 1.25; color: var(--cream); text-decoration: none; }
.foot a:hover { color: var(--gold); }
.foot p { margin: 14px 0 0; font-size: 0.9rem; font-weight: 700; color: rgba(255, 243, 214, 0.85); }
.home .foot { position: absolute; z-index: 1; left: 0; right: 0; bottom: 0; padding-bottom: max(22px, env(safe-area-inset-bottom)); }
/* Phones: the links wrap as ABOUT FAQ SUPPORT over PRIVACY POLICY instead of leaving one word alone. */
@media (max-width: 440px) { .foot { padding-inline: 12px; } .foot nav { gap: 8px 20px; } .foot nav a:nth-child(3) { order: 1; } }
.home .foot a, .home .foot p { color: var(--cream); text-shadow: 0 1px 0 var(--ink), 0 2px 0 var(--ink), 0 0 3px var(--ink), 0 3px 8px rgba(18, 15, 69, 0.9); }
.home .foot a:hover { color: var(--gold); }
.home .foot p { color: var(--cream); }

/* ---------- Inner pages: a marquee strip of the funfair, then pixel panels ---------- */

.inner { background: var(--night); }
.inner::before { /* a sky of dim pixel stars behind the panels */
  content: ""; position: fixed; inset: 0; z-index: -1; pointer-events: none;
  background:
    radial-gradient(1.5px 1.5px at 20% 30%, rgba(255, 255, 255, 0.35) 50%, transparent 51%),
    radial-gradient(1.5px 1.5px at 70% 60%, rgba(255, 255, 255, 0.3) 50%, transparent 51%),
    radial-gradient(1.5px 1.5px at 45% 85%, rgba(255, 255, 255, 0.25) 50%, transparent 51%),
    radial-gradient(1.5px 1.5px at 85% 15%, rgba(255, 255, 255, 0.35) 50%, transparent 51%),
    radial-gradient(1.5px 1.5px at 10% 70%, rgba(255, 255, 255, 0.25) 50%, transparent 51%),
    radial-gradient(1.5px 1.5px at 60% 10%, rgba(255, 255, 255, 0.3) 50%, transparent 51%),
    radial-gradient(1.5px 1.5px at 92% 78%, rgba(255, 255, 255, 0.25) 50%, transparent 51%),
    radial-gradient(1.5px 1.5px at 33% 55%, rgba(255, 255, 255, 0.2) 50%, transparent 51%),
    radial-gradient(ellipse 80% 60% at 50% -10%, var(--nebula), transparent 70%);
  background-size: 480px 480px, 560px 560px, 520px 520px, 600px 600px, 440px 440px, 500px 500px, 640px 640px, 580px 580px, 100% 100%;
  background-repeat: repeat, repeat, repeat, repeat, repeat, repeat, repeat, repeat, no-repeat;
}

.marquee {
  position: relative; isolation: isolate; height: clamp(200px, 30vw, 300px); overflow: hidden;
  display: grid; place-items: center; text-align: center; padding: 0 16px;
}
.marquee__art {
  position: absolute; inset: 0 0 var(--u) 0; z-index: 0;
  background: url("img/lunapark-1672.webp") center 14% / cover; image-rendering: pixelated;
}
.marquee__art::after { /* the picture ends in a pixel dither, not a line */
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: calc(var(--u) * 3);
  background:
    conic-gradient(from 90deg at 50% 50%, var(--night) 25%, transparent 0 50%, var(--night) 0 75%, transparent 0) 0 0 / calc(var(--u) * 2) calc(var(--u) * 2),
    linear-gradient(to top, var(--night) var(--u), transparent 0);
}
.marquee::before { /* a dark top edge so the home link and nav read over the picture */
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 96px; z-index: 0; pointer-events: none;
  background: linear-gradient(to bottom, rgba(18, 15, 69, 0.85), rgba(18, 15, 69, 0.45) 50%, transparent);
}
.marquee .home-link, .marquee nav, .marquee h1 { position: relative; z-index: 1; }
.marquee .home-link { position: absolute; top: 16px; left: 16px; display: flex; align-items: center; gap: 12px; font-size: 16px; color: var(--gold); text-decoration: none; }
.marquee .home-link img { width: 40px; height: 40px; image-rendering: auto; border: 2px solid var(--ink); border-radius: 10px; box-shadow: 0 2px 0 var(--ink); }
.marquee nav { position: absolute; top: 26px; right: 20px; display: flex; gap: 20px; }
.marquee nav a { font-size: 16px; color: #fff; text-decoration: none; }
.marquee nav a[aria-current] { color: var(--gold); }
.marquee nav a:hover, .marquee .home-link:hover { color: var(--cream); }
/* The page's name on a pixel sign, like a place's name card in the game. */
.marquee h1 {
  margin: 0; color: var(--ink); line-height: 1; padding: 14px 20px 18px;
  font-size: clamp(32px, 4vw, 48px); font-size: round(down, clamp(32px, 4vw, 48px), 8px);
  border: calc(var(--u) * 3) solid transparent; border-image: var(--slice) 4 fill / calc(var(--u) * 3) stretch;
  filter: drop-shadow(0 calc(var(--u) * 2) 0 rgba(18, 15, 69, 0.9));
}
@media (max-width: 480px) {
  .marquee { height: 200px; padding-top: 24px; }
  .marquee .home-link span { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  .marquee nav { top: 26px; right: 16px; gap: 16px; }
  .marquee h1 { font-size: 32px; padding: 12px 16px 14px; }
}

.page { width: min(100% - 32px, 720px); margin: 40px auto 8px; display: grid; gap: 32px; }
@media (min-width: 720px) { .page { margin-top: 56px; gap: 40px; } }

/* The pixel panel: a 9-slice drawn in SVG (notched corners, ink outline, cream bevel) and the hard
   ink drop every panel in the game has. */
.panel {
  --b: calc(var(--u) * 4);
  color: var(--ink);
  border: var(--b) solid transparent;
  border-image: var(--slice) 4 fill / var(--b) stretch;
  filter: drop-shadow(0 calc(var(--u) * 2) 0 rgba(18, 15, 69, 0.9));
}
.panel__in { padding: calc(28px - var(--u) * 3) calc(24px - var(--u) * 2) calc(30px - var(--u) * 3); }
@media (min-width: 720px) { .panel__in { padding: calc(40px - var(--u) * 3) calc(44px - var(--u) * 2) calc(44px - var(--u) * 3); } }

.panel h2 { margin: 0 0 12px; font-size: 24px; color: var(--coffee); }
.panel h2 + .lede { margin-top: 4px; }
.panel p, .panel ul { margin: 0 0 14px; }
.panel p:last-child, .panel ul:last-child { margin-bottom: 0; }
.panel ul { padding-left: 1.3em; }
.panel li { margin-bottom: 6px; }
.panel a { color: #1f4fb8; overflow-wrap: anywhere; }
.panel .lede { font-size: 1.25rem; font-weight: 700; line-height: 1.5; }
.panel .updated { font-style: italic; color: var(--coffee); }
.prose h2 { margin-top: 36px; font-size: 16px; }
.prose h2:first-child { margin-top: 0; }

/* FAQ: one panel, each question a section parted by a dotted pixel rule. */
.qa + .qa { margin-top: 26px; padding-top: 26px;
  background: linear-gradient(90deg, var(--coffee) 50%, transparent 0) 0 0 / calc(var(--u) * 2) var(--u) repeat-x; }
.qa h2 { font-size: 16px; }
.qa p:last-child { margin-bottom: 0; }

/* About, at a glance: like a game stats list. Label, dotted leader, value. */
.glance { margin: 16px 0 0; padding: 0; }
.glance div { display: flex; align-items: baseline; gap: 12px; padding: 10px 0; }
.glance dt { font-size: 16px; color: var(--coffee); white-space: nowrap; }
.glance div::after { content: ""; order: 1; flex: 1; min-width: 20px; height: var(--u); translate: 0 -4px;
  background: linear-gradient(90deg, rgba(36, 20, 15, 0.3) 50%, transparent 0) 0 0 / calc(var(--u) * 2) var(--u) repeat-x; }
.glance dd { order: 2; margin: 0; font-weight: 800; text-align: right; }
@media (max-width: 440px) {
  .glance div { flex-wrap: wrap; gap: 4px 12px; }
  .glance div::after { display: none; }
  .glance dd { flex-basis: 100%; text-align: left; }
}

/* ---------- Home: the whole viewport is a picture, and the picture changes ---------- */

.home { overflow: hidden; }
.hero { position: relative; height: 100vh; height: 100svh; overflow: hidden; background: var(--night); }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; margin: -1px; }

/* Every scene is a stage: the picture's own 1672 x 941 box, scaled to cover the viewport, so every light
   and sprite sits on the pixel it belongs to. Portrait phones look at the part the scene names (--focus). */
.scene { position: absolute; inset: 0; overflow: hidden; }
.stage {
  --w: max(100vw, calc(100vh * 1672 / 941));
  --w: max(100vw, calc(100svh * 1672 / 941));
  --focus: 50%;
  --fx: 50%;
  position: absolute; left: 50%; top: 50%;
  width: var(--w); height: calc(var(--w) * 941 / 1672);
  translate: calc(-1 * var(--fx)) -50%;
  background: var(--night);
}
@media (max-aspect-ratio: 4/5) { .stage { --fx: var(--focus); } }
@media (min-aspect-ratio: 4/5) and (max-aspect-ratio: 1/1) { .stage { --fx: calc((50% + var(--focus)) / 2); } }
.stage > img, .stage > canvas, .stage img.plate { position: absolute; inset: 0; width: 100%; height: 100%; }
.stage img { image-rendering: -webkit-optimize-contrast; image-rendering: pixelated; }
.stage canvas { image-rendering: pixelated; }
.stage .fx { position: absolute; display: block; pointer-events: none; mix-blend-mode: screen; }

/* Only the scene on show is in the page. The one leaving stays for the transition; the rest are held
   back (and their pictures are not even fetched until the carousel preloads them). */
.stage:not(.is-active):not(.is-leaving) { display: none; }
.stage:not(.is-active) * { animation-play-state: paused !important; }
.stage.is-leaving { z-index: 0; }
.stage.is-active { z-index: 1; }

/* The change of scene: the new picture arrives through a growing grid of pixel dots over the old one, in
   steps like a game's screen wipe. With Reduce Motion it is a plain cross-fade. */
@property --dot { syntax: "<length>"; inherits: false; initial-value: 20px; }
.stage.is-entering {
  --dot: 20px;
  -webkit-mask-image: radial-gradient(circle, #000 var(--dot), transparent calc(var(--dot) + 0.5px));
  mask-image: radial-gradient(circle, #000 var(--dot), transparent calc(var(--dot) + 0.5px));
  -webkit-mask-size: 28px 28px; mask-size: 28px 28px;
  -webkit-mask-position: center; mask-position: center;
}
@media (prefers-reduced-motion: no-preference) {
  .stage.is-entering { animation: dots 0.7s steps(10) both; }
}
@media (prefers-reduced-motion: reduce) {
  .stage.is-entering { -webkit-mask-image: none; mask-image: none; animation: appear 0.6s ease both; }
}
@keyframes dots { from { --dot: 0px; } to { --dot: 20px; } }

/* Title screen: the name stands at the bottom, where concept B put it; a scene that reads better with the
   name up top says so (data-title="top") and the carousel lifts it there (--lift, measured in px). */
.title { position: absolute; z-index: 2; left: 0; right: 0; bottom: clamp(120px, 19vh, 190px); text-align: center; padding: 0 16px;
  translate: 0 calc(-1 * var(--lift, 0px)); }
.hero[data-title="top"] .title { --lift: var(--lift-measured, 0px); }
.title h1 { margin: 0; color: var(--gold); white-space: nowrap;
  font-size: clamp(24px, 6.4vw, 104px); font-size: round(down, clamp(24px, 6.4vw, 104px), 8px); }
.title p { margin: 1.1em 0 0; color: var(--cream);
  font-size: clamp(16px, 1.8vw, 24px); font-size: round(down, clamp(16px, 1.8vw, 24px), 8px); }
.title p span { white-space: nowrap; }
@media (max-width: 440px) {
  .title { bottom: 196px; }
  .title h1 { font-size: 24px; }
  .title p { font-size: 16px; line-height: 1.5; }
}

/* The arrows: two small pixel buttons in the bottom right corner, drawn like the game's own arrow keys,
   quiet until the pointer finds them. Hidden until the script arrives (there is nothing to turn without it). */
.arrows { position: absolute; z-index: 3; right: max(14px, env(safe-area-inset-right)); bottom: max(16px, env(safe-area-inset-bottom)); display: flex; gap: 8px; }
.arrows[hidden] { display: none; }
.arrow {
  --b: #fff3d6;
  width: 40px; height: 40px; padding: 0; margin: 0; cursor: pointer; display: grid; place-items: center;
  color: var(--ink); background: var(--b); border: 0; border-radius: 0;
  box-shadow: 0 0 0 var(--u) var(--ink), 0 calc(var(--u) * 2) 0 0 var(--ink), 0 calc(var(--u) * 2) 0 var(--u) var(--ink);
  opacity: 0.72; transition: opacity 0.2s, translate 0.1s steps(2), box-shadow 0.1s steps(2);
}
.arrow:hover, .arrow:focus-visible { opacity: 1; --b: var(--gold); }
.arrow:active { translate: 0 calc(var(--u) * 2); box-shadow: 0 0 0 var(--u) var(--ink); }
.arrow:focus-visible { outline: 3px solid var(--gold); outline-offset: calc(var(--u) + 3px); }
.arrow span { width: 20px; height: 20px; image-rendering: pixelated;
  background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10' shape-rendering='crispEdges'%3E%3Cpath d='M4 1h2v2H4zM2 3h2v2H2zM0 5h2v2H0zM2 7h2v2H2zM4 9h2v1H4zM6 4h4v2H6z' fill='%23000'/%3E%3C/svg%3E") center / 100% 100% no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10' shape-rendering='crispEdges'%3E%3Cpath d='M4 1h2v2H4zM2 3h2v2H2zM0 5h2v2H0zM2 7h2v2H2zM4 9h2v1H4zM6 4h4v2H6z' fill='%23000'/%3E%3C/svg%3E") center / 100% 100% no-repeat; }
.arrow.next span { scale: -1 1; }
.arrow[disabled] { opacity: 0.35; cursor: default; }
@media (hover: none) { .arrow { opacity: 0.7; } }
/* On narrow screens the footer takes the whole bottom, so the arrows sit above it, under the name; in a
   short landscape window (a phone on its side) the bottom is all text, so they go to the top right corner. */
/* On phones the bottom is one centred stack: name, coming soon, the arrows, then the footer. */
@media (max-width: 640px) and (orientation: portrait) { .arrows { bottom: 128px; right: auto; left: 50%; translate: -50% 0; gap: 14px; } }
@media (max-width: 440px) and (orientation: portrait) { .arrows { bottom: 128px; } .arrow { width: 36px; height: 36px; } .arrow span { width: 18px; height: 18px; } }
@media (max-width: 900px) and (orientation: landscape) and (max-height: 520px) { .arrows { bottom: auto; top: max(14px, env(safe-area-inset-top)); right: max(14px, env(safe-area-inset-right)); } }
/* ---------- Motion: the title drops in and the coming-soon line blinks like press start; with Reduce
   Motion everything holds still (each scene's own animations live in its scene.css, also behind this query) ---------- */

@media (prefers-reduced-motion: no-preference) {
  .title h1 { animation: drop 0.7s steps(7) both; }
  .title p { animation: appear 0.01s 0.9s both, blink 1.4s 1.2s steps(1) infinite; }
  .home .foot, .home .arrows { animation: appear 0.01s 1.1s both; }
  .title { transition: translate 0.5s steps(8); }

  /* Page changes like a game menu: the old screen blinks off, the new one steps in. */
  @view-transition { navigation: auto; }
  ::view-transition-old(root) { animation: 0.12s steps(2) both blinkout; }
  ::view-transition-new(root) { animation: 0.22s steps(4) both stepin; }
}
@keyframes spin { to { rotate: 360deg; } }
@keyframes breathe { 50% { opacity: 0.35; } }
@keyframes drop { from { translate: 0 -2em; opacity: 0; } 70% { translate: 0 0.12em; opacity: 1; } to { translate: 0 0; opacity: 1; } }
@keyframes appear { from { opacity: 0; } to { opacity: 1; } }
@keyframes blink { 50% { opacity: 0; } }
@keyframes blinkout { to { opacity: 0; } }
@keyframes stepin { from { opacity: 0; scale: 0.96; } to { opacity: 1; scale: 1; } }


/* ---------- Scenes ---------- */

/* funfair */
/* Luna Park, the funfair on the Moon (concept B's scene), with the Ferris wheel turning: the plate has no
   rim, spokes or cabins; the rim and spokes are one sprite that rotates, the sixteen cabins orbit on the same
   clock and stay upright, and the hub (Mr. Brainrot) sits still on top. Every measure is a % of the 1672 x 941
   picture; the wheel's centre is at (1091, 298) and its rim's outer edge 262 px out. */
.stage[data-scene="funfair"] .earth {
  left: 17.9%; top: 15.9%; width: 24%; aspect-ratio: 1; translate: -50% -50%; border-radius: 50%;
  background: radial-gradient(circle, rgba(170, 220, 255, 0.55) 40%, rgba(120, 180, 255, 0.25) 56%, transparent 68%);
  opacity: 0.7;
}
.stage[data-scene="funfair"] .wheel {
  position: absolute; left: 65.25%; top: 31.67%; width: 32.5%; aspect-ratio: 1; translate: -50% -50%;
}
.stage[data-scene="funfair"] .rim { position: absolute; inset: 0; width: 100%; height: 100%; }
/* Chasing bulbs: a bright sector sweeping around a ring of lights the picture has. */
.stage[data-scene="funfair"] .chase { aspect-ratio: 1; translate: -50% -50%; border-radius: 50%;
  background: conic-gradient(from 0deg, transparent 0 240deg, rgba(255, 255, 255, 0.45) 300deg, #fff 354deg, transparent 360deg); }
.stage[data-scene="funfair"] .ring { left: 50%; top: 50%; width: 96.7%;
  -webkit-mask: radial-gradient(circle, transparent 86%, #000 86.5%, #000 100%); mask: radial-gradient(circle, transparent 86%, #000 86.5%, #000 100%); }
.stage[data-scene="funfair"] .hubring { left: 65.25%; top: 31.67%; width: 13.6%;
  -webkit-mask: radial-gradient(circle, transparent 82%, #000 83%, #000 100%); mask: radial-gradient(circle, transparent 82%, #000 83%, #000 100%); }
.stage[data-scene="funfair"] .tower { left: 94.6%; top: 11.7%; width: 7.6%;
  -webkit-mask: radial-gradient(circle, transparent 72%, #000 73%, #000 100%); mask: radial-gradient(circle, transparent 72%, #000 73%, #000 100%); }
/* The cabins hang from the rim: each on a spoke of its own (a point at the hub, turned to its place),
   turned back the other way about its hanger so it stays upright. */
.stage[data-scene="funfair"] .cars { position: absolute; left: 65.25%; top: 31.67%; width: 0; height: 0; }
.stage[data-scene="funfair"] .car { position: absolute; left: 0; top: 0; width: 0; height: 0; rotate: calc(var(--i) * 22.5deg); }
.stage[data-scene="funfair"] .cab {
  position: absolute; left: 0; top: calc(var(--w) * -0.1685); width: calc(var(--w) * 0.0372); height: auto;
  max-width: none; translate: -50% 0; transform-origin: 50% 7%; rotate: calc(var(--i) * -22.5deg);
}
.stage[data-scene="funfair"] .hub { position: absolute; left: 65.25%; top: 31.67%; width: 15.3%; height: auto; translate: -50% -50%; }
/* The drop tower's shaft: light running up its bulb strips. */
.stage[data-scene="funfair"] .shaft { left: 93%; top: 15.9%; width: 3.4%; height: 28.7%; opacity: 0.9;
  background: repeating-linear-gradient(to top, transparent 0 0, transparent 70%, rgba(255, 255, 255, 0.85) 78%, transparent 84%, transparent 100%);
  background-size: 100% 48%; background-position: 0 0; }
/* The neon roller coaster: a slow magenta breath. */
.stage[data-scene="funfair"] .neon { left: 31%; top: 16.5%; width: 17%; height: 15%; border-radius: 50%; opacity: 0.35;
  background: radial-gradient(ellipse, rgba(255, 60, 172, 0.7), transparent 70%); }

@media (prefers-reduced-motion: no-preference) {
  .stage[data-scene="funfair"] .earth { animation: breathe 6s ease-in-out infinite; }
  .stage[data-scene="funfair"] .wheel { animation: spin 48s steps(192) infinite; }
  .stage[data-scene="funfair"] .car { animation: funfair-orbit 48s steps(192) infinite; }
  .stage[data-scene="funfair"] .cab { animation: funfair-upright 48s steps(192) infinite; }
  .stage[data-scene="funfair"] .ring { animation: spin 4s steps(48) infinite; }
  .stage[data-scene="funfair"] .hubring { animation: spin 2.4s steps(24) infinite reverse; }
  .stage[data-scene="funfair"] .tower { animation: spin 1.6s steps(16) infinite; }
  .stage[data-scene="funfair"] .shaft { animation: funfair-climb 1.4s steps(7) infinite; }
  .stage[data-scene="funfair"] .neon { animation: breathe 3.2s ease-in-out infinite; }
}
@keyframes funfair-orbit { from { rotate: calc(var(--i) * 22.5deg); } to { rotate: calc(var(--i) * 22.5deg + 360deg); } }
@keyframes funfair-upright { from { rotate: calc(var(--i) * -22.5deg); } to { rotate: calc(var(--i) * -22.5deg - 360deg); } }
@keyframes funfair-climb { to { background-position: 0 -48%; } }

/* villa */
/* Villa degli Influencer, the content house in Positano. The plate has no mascot, boats or drone: Mr. Brainrot
   bobs in the pool (his lower part under the waterline, a ripple around him), three boats drift on the sea
   behind the cliffs, the drone hovers, two all-white clouds and a gull cross the sky, and the sun glints on
   the water as small pixel crosses. Measures are % of the 1672 x 941 picture. */
.stage[data-scene="villa"] .cloud { position: absolute; height: auto; opacity: 0.97; }
.stage[data-scene="villa"] .cloud-1 { left: 29%; top: 4.5%; width: 18%; }
.stage[data-scene="villa"] .cloud-2 { left: 44%; top: 22.5%; width: 10%; opacity: 0.9; }

/* The sea sits between the terrace wall and the cliffs; the boats sail behind both. */
.stage[data-scene="villa"] .sea { position: absolute; inset: 0;
  clip-path: polygon(36% 39.6%, 70.5% 39.6%, 74.5% 44%, 77.5% 48.5%, 79% 53%, 79% 58%, 40.2% 58%, 40.2% 47.6%, 36.6% 46.2%); }
.stage[data-scene="villa"] .boat { position: absolute; left: 30%; top: var(--y); width: var(--bw); height: auto; }

.stage[data-scene="villa"] .gull { position: absolute; left: 32%; top: 16%; width: 4.2%; height: auto; opacity: 0; }
.stage[data-scene="villa"] .drone { position: absolute; left: 63%; top: 31%; width: 8.4%; height: auto; }

/* The ring lights breathe. */
.stage[data-scene="villa"] .ring { width: 6.4%; aspect-ratio: 1; border-radius: 50%; translate: -50% -50%;
  background: radial-gradient(circle, rgba(255, 255, 255, 0.62) 0, rgba(255, 255, 255, 0.25) 32%, rgba(255, 255, 255, 0) 68%); }
.stage[data-scene="villa"] .r1 { left: 33.8%; top: 47.4%; }
.stage[data-scene="villa"] .r2 { left: 85.6%; top: 49%; }

/* Sun on the water: a sparse scatter of four-pointed pixel glints, each a plus of three picture pixels. */
.stage[data-scene="villa"] .glints { position: absolute; inset: 0; pointer-events: none; }
.stage[data-scene="villa"] .glints i {
  --p: calc(var(--w) / 1672 * 3);
  position: absolute; left: var(--x); top: var(--y); width: var(--p); height: var(--p); translate: -50% -50%;
  background: #fff; opacity: 0;
  box-shadow: calc(-1 * var(--p)) 0 #fff, var(--p) 0 #fff, 0 calc(-1 * var(--p)) #fff, 0 var(--p) #fff,
              calc(-2 * var(--p)) 0 #fffbe8, calc(2 * var(--p)) 0 #fffbe8, 0 calc(-2 * var(--p)) #fffbe8, 0 calc(2 * var(--p)) #fffbe8;
}
/* As a still frame, every third glint is lit. */
.stage[data-scene="villa"] .glints i:nth-child(3n + 1) { opacity: 0.95; }

/* Mr. Brainrot: the sprite ends at the waterline, and the box he bobs in is cut there too, so he only ever
   sinks a little into the water and comes back. */
.stage[data-scene="villa"] .float { position: absolute; left: 51.2%; top: 41.45%; width: 15.73%; height: 25.1%; overflow: hidden; }
.stage[data-scene="villa"] .mascot { position: absolute; left: 0; top: 0; width: 100%; height: auto; max-width: none; }
/* The ripple: a thin pixel ring on the water about him. */
.stage[data-scene="villa"] .ripple {
  --p: calc(var(--w) / 1672 * 3);
  position: absolute; left: 59%; top: 66.6%; width: 18%; height: 3.6%; translate: -50% -50%;
  border: var(--p) solid rgba(255, 255, 255, 0.75); border-radius: 50%; opacity: 0; pointer-events: none;
}
.stage[data-scene="villa"] .ripple-1 { opacity: 0.6; scale: 0.9; }

@media (prefers-reduced-motion: no-preference) {
  .stage[data-scene="villa"] .cloud-1 { animation: villa-drift 240s ease-in-out infinite alternate; animation-delay: -90s; }
  .stage[data-scene="villa"] .cloud-2 { animation: villa-drift-back 180s ease-in-out infinite alternate; animation-delay: -40s; }
  .stage[data-scene="villa"] .boat { animation: villa-sail var(--d) linear infinite, villa-bob 3.2s ease-in-out infinite; animation-delay: var(--delay), 0s; }
  .stage[data-scene="villa"] .gull { animation: villa-fly 34s linear infinite 3s; }
  .stage[data-scene="villa"] .drone { animation: villa-hover 9s ease-in-out infinite; }
  .stage[data-scene="villa"] .ring { animation: villa-breathe 4.6s ease-in-out infinite alternate; }
  .stage[data-scene="villa"] .r2 { animation-delay: -2.1s; }
  .stage[data-scene="villa"] .glints i { opacity: 0; animation: villa-glint 3.2s steps(1, end) infinite; animation-delay: var(--d); }
  .stage[data-scene="villa"] .mascot { animation: villa-float 3.4s ease-in-out infinite; }
  .stage[data-scene="villa"] .ripple-1 { opacity: 0; scale: 1; animation: villa-ripple 3.4s steps(6) infinite; }
  .stage[data-scene="villa"] .ripple-2 { animation: villa-ripple 3.4s steps(6) infinite 1.7s; }
}
@keyframes villa-drift { from { translate: 0 0; } to { translate: calc(var(--w) * 0.2) 0; } }
@keyframes villa-drift-back { from { translate: 0 0; } to { translate: calc(var(--w) * -0.14) 0; } }
@keyframes villa-sail { from { translate: 0 0; } to { translate: calc(var(--w) * 0.52) 0; } }
@keyframes villa-bob { 50% { transform: translateY(3%) rotate(1.2deg); } }
@keyframes villa-fly {
  0% { opacity: 0; transform: translate(0, 0); } 4% { opacity: 1; }
  25% { transform: translate(calc(var(--w) * 0.11), calc(var(--w) * -0.012)); }
  50% { transform: translate(calc(var(--w) * 0.22), calc(var(--w) * 0.004)); }
  60% { opacity: 1; transform: translate(calc(var(--w) * 0.27), calc(var(--w) * -0.006)); }
  64%, 100% { opacity: 0; transform: translate(calc(var(--w) * 0.29), calc(var(--w) * -0.008)); } }
@keyframes villa-hover {
  0% { translate: 0 0; } 25% { translate: calc(var(--w) * 0.008) calc(var(--w) * -0.0045); }
  50% { translate: calc(var(--w) * 0.015) calc(var(--w) * 0.0025); } 75% { translate: calc(var(--w) * 0.005) calc(var(--w) * 0.0055); } 100% { translate: 0 0; } }
@keyframes villa-breathe { from { opacity: 0.45; scale: 0.92; } to { opacity: 1; scale: 1.06; } }
@keyframes villa-glint { 0%, 66% { opacity: 0; scale: 0.34; } 70% { opacity: 1; scale: 0.34; } 78% { opacity: 1; scale: 1; } 90% { opacity: 1; scale: 0.34; } 94%, 100% { opacity: 0; } }
@keyframes villa-float { 0%, 100% { translate: 0 0; } 50% { translate: 0 calc(var(--w) * 0.005); } }
@keyframes villa-ripple { 0% { opacity: 0.8; scale: 0.82 0.7; } 100% { opacity: 0; scale: 1.12 1.3; } }

/* kitchen */
/* Cucina della Nonna, concept A's diorama: the coast seen through a real hole in the window (boats, two
   clouds, a gull flying the way it faces, sun glinting on the sea), the kitchen itself with its string
   lights, ring light and lamp breathing and a sunbeam crossing now and then, the lemon bough swaying in the
   arch, and a slow golden hour that comes and goes. The camera drifts a little (scene.js sets --mx/--my).
   Measures are % of the 1672 x 941 picture. */
.stage[data-scene="kitchen"] { --mx: 0; --my: 0; }
.stage[data-scene="kitchen"] .cam { position: absolute; inset: 0; transform-origin: 50% 50%; }
.stage[data-scene="kitchen"] .layer { position: absolute; inset: 0; }
.stage[data-scene="kitchen"] .layer img, .stage[data-scene="kitchen"] .layer .fx, .stage[data-scene="kitchen"] .layer span { position: absolute; }
.stage[data-scene="kitchen"] img.plate { position: absolute; inset: 0; width: 100%; height: 100%; }

/* Far: the coast. The view is wider than the window so it can slide behind the frame. */
.stage[data-scene="kitchen"] .far { transform: translate(calc(var(--mx) * -0.35%), calc(var(--my) * -0.25%)); }
.stage[data-scene="kitchen"] .window { position: absolute; left: 25%; top: 4.5%; width: 48%; aspect-ratio: 1672 / 1241; }
.stage[data-scene="kitchen"] .view { inset: 0; width: 100%; height: 100%; }
.stage[data-scene="kitchen"] .glare { left: 0; right: 0; top: 55%; bottom: 20%; mix-blend-mode: screen; opacity: 0.5;
  background: radial-gradient(ellipse 30% 40% at 52% 35%, rgba(255, 250, 220, 0.5), transparent 70%); }
.stage[data-scene="kitchen"] .cloud { width: 9%; left: 30%; top: 15%; opacity: 0.95; height: auto; }
.stage[data-scene="kitchen"] .cloud-2 { width: 5%; left: 55%; top: 24%; }
.stage[data-scene="kitchen"] .boat { width: 3.1%; left: 38%; top: 46.5%; height: auto; transform-origin: 50% 90%; }
.stage[data-scene="kitchen"] .boat-2 { width: 2.2%; left: 58%; top: 44.2%; }
.stage[data-scene="kitchen"] .gull { width: 2%; left: 36%; top: 22%; height: auto; opacity: 0; }
/* Sun on the sea: a few pixel glints, like the villa's. */
.stage[data-scene="kitchen"] .glints { position: absolute; inset: 0; pointer-events: none; }
.stage[data-scene="kitchen"] .glints i {
  --p: calc(var(--w) / 1672 * 2);
  position: absolute; left: var(--x); top: var(--y); width: var(--p); height: var(--p); translate: -50% -50%;
  background: #fff; opacity: 0;
  box-shadow: calc(-1 * var(--p)) 0 #fff, var(--p) 0 #fff, 0 calc(-1 * var(--p)) #fff, 0 var(--p) #fff;
}
.stage[data-scene="kitchen"] .glints i:nth-child(2n + 1) { opacity: 0.9; }

/* Room: the kitchen with a real hole where the window glass would be, a touch larger so its edges never show. */
.stage[data-scene="kitchen"] .room { transform: translate(calc(var(--mx) * -0.8%), calc(var(--my) * -0.55%)) scale(1.025); }
.stage[data-scene="kitchen"] .bulb { width: 3.4%; aspect-ratio: 1; translate: -50% -50%; border-radius: 50%;
  background: radial-gradient(circle, rgba(255, 238, 170, 0.95) 0 14%, rgba(255, 200, 80, 0.45) 30%, transparent 68%); }
.stage[data-scene="kitchen"] .ring { left: 55.7%; top: 50%; width: 9.5%; aspect-ratio: 1; translate: -50% -50%; border-radius: 50%;
  background: radial-gradient(circle, transparent 48%, rgba(255, 238, 190, 0.85) 56%, rgba(255, 214, 120, 0.35) 64%, transparent 74%); }
.stage[data-scene="kitchen"] .lamp { left: 73.8%; top: 46%; width: 7%; aspect-ratio: 1; translate: -50% -50%; border-radius: 50%;
  background: radial-gradient(circle, rgba(255, 226, 150, 0.7), transparent 65%); }
.stage[data-scene="kitchen"] .sunbeam { inset: -20% auto -20% -30%; width: 34%; opacity: 0;
  background: linear-gradient(90deg, transparent, rgba(255, 246, 214, 0.35), transparent); transform: skewX(-18deg); mix-blend-mode: soft-light; }

/* The lemon bough hangs into the window, clipped to the arch so it never crosses the frame. */
.stage[data-scene="kitchen"] .bough { clip-path: url(#kitchen-arch); }
.stage[data-scene="kitchen"] .mover { position: absolute; inset: 0; transform: translate(calc(var(--mx) * -1.2%), calc(var(--my) * -0.8%)); }
.stage[data-scene="kitchen"] .branch { left: 48.6%; top: 8.3%; width: 19.6%; height: auto; transform-origin: 96% 2%; }

/* Light: a slow day that turns golden and back. */
.stage[data-scene="kitchen"] .golden { position: absolute; inset: 0; opacity: 0; pointer-events: none; mix-blend-mode: multiply;
  background: linear-gradient(180deg, rgba(255, 150, 70, 0.9), rgba(255, 190, 110, 0.7) 45%, rgba(255, 140, 90, 0.75)); }
.stage[data-scene="kitchen"] .glow { position: absolute; inset: 0; opacity: 0; pointer-events: none; mix-blend-mode: screen;
  background: radial-gradient(ellipse 36% 50% at 51% 36%, rgba(255, 210, 120, 0.55), transparent 70%); }

@media (prefers-reduced-motion: no-preference) {
  .stage[data-scene="kitchen"] .cam { animation: kitchen-breathe 40s ease-in-out infinite alternate; }
  .stage[data-scene="kitchen"] .bulb { animation: kitchen-twinkle 2.8s ease-in-out infinite; animation-delay: var(--d, 0s); }
  .stage[data-scene="kitchen"] .ring { animation: kitchen-pulse 3.6s ease-in-out infinite; }
  .stage[data-scene="kitchen"] .lamp { animation: kitchen-pulse 5s ease-in-out infinite; }
  .stage[data-scene="kitchen"] .glare { animation: kitchen-pulse 9s ease-in-out infinite; }
  .stage[data-scene="kitchen"] .glints i { opacity: 0; animation: kitchen-glint 3s steps(1, end) infinite; animation-delay: var(--d); }
  .stage[data-scene="kitchen"] .sunbeam { animation: kitchen-sweep 24s ease-in-out infinite; }
  .stage[data-scene="kitchen"] .cloud-1 { animation: kitchen-cloud 170s linear infinite; }
  .stage[data-scene="kitchen"] .cloud-2 { animation: kitchen-cloud 230s linear infinite -90s; }
  .stage[data-scene="kitchen"] .boat-1 { animation: kitchen-sail 150s linear infinite, kitchen-bob 3.2s ease-in-out infinite; }
  .stage[data-scene="kitchen"] .boat-2 { animation: kitchen-sail-back 190s linear infinite -60s, kitchen-bob 2.7s ease-in-out infinite -1s; }
  .stage[data-scene="kitchen"] .gull { animation: kitchen-fly 46s ease-in-out infinite 8s; }
  .stage[data-scene="kitchen"] .branch { animation: kitchen-sway 5.5s ease-in-out infinite alternate; }
  .stage[data-scene="kitchen"] .golden { animation: kitchen-golden 64s ease-in-out infinite; }
  .stage[data-scene="kitchen"] .glow { animation: kitchen-glow 64s ease-in-out infinite; }
  .stage[data-scene="kitchen"] .far, .stage[data-scene="kitchen"] .room, .stage[data-scene="kitchen"] .mover { transition: transform 0.3s linear; }
}
@keyframes kitchen-breathe { from { transform: scale(1); } to { transform: translate(-0.6%, -0.3%) scale(1.035); } }
@keyframes kitchen-twinkle { 50% { opacity: 0.4; } }
@keyframes kitchen-pulse { 50% { opacity: 0.5; } }
@keyframes kitchen-glint { 0%, 62% { opacity: 0; } 66%, 90% { opacity: 1; } 94%, 100% { opacity: 0; } }
@keyframes kitchen-sweep { 0%, 40% { left: -30%; opacity: 0; } 50% { opacity: 1; } 78% { opacity: 1; } 88%, 100% { left: 110%; opacity: 0; } }
@keyframes kitchen-cloud { from { translate: calc(var(--w) * -0.14) 0; } to { translate: calc(var(--w) * 0.14) 0; } }
@keyframes kitchen-sail { from { translate: calc(var(--w) * -0.05) 0; } to { translate: calc(var(--w) * 0.14) 0; } }
@keyframes kitchen-sail-back { from { translate: calc(var(--w) * 0.06) 0; } to { translate: calc(var(--w) * -0.12) 0; } }
@keyframes kitchen-bob { 50% { transform: translateY(2%) rotate(1.4deg); } }
@keyframes kitchen-fly {
  0%, 60% { opacity: 0; translate: 0 0; }
  62% { opacity: 1; }
  80% { translate: calc(var(--w) * 0.1) calc(var(--w) * -0.03); }
  98% { opacity: 1; translate: calc(var(--w) * 0.22) calc(var(--w) * -0.01); }
  100% { opacity: 0; translate: calc(var(--w) * 0.22) calc(var(--w) * -0.01); } }
@keyframes kitchen-sway { from { transform: rotate(-1.3deg); } to { transform: rotate(1.2deg); } }
@keyframes kitchen-golden { 0%, 38% { opacity: 0; } 58%, 72% { opacity: 0.42; } 92%, 100% { opacity: 0; } }
@keyframes kitchen-glow { 0%, 38% { opacity: 0; } 58%, 72% { opacity: 0.9; } 92%, 100% { opacity: 0; } }

/* sanremo */
/* Il Palco di Sanremo: the song-festival stage at night. The plate (a Codex edit of the backdrop) has no
   spotlight beams and no sailboats. On top of it: the picture's own lamps, brightened (truss lenses, the
   arch lamps, the front row of bulbs in three chasing groups), six flat two-tone spotlight beams swinging from
   the truss as the original drew them, the sparkles on the LED screens twinkling, the two sailboats
   drifting on the sea seen through the arches, the flower mascot blinking, and petals drifting down
   (canvas). Every measure is a % of the 1672 x 941 picture. */
.stage[data-scene="sanremo"] .lit, .stage[data-scene="sanremo"] .dim, .stage[data-scene="sanremo"] .blink,
.stage[data-scene="sanremo"] .sea, .stage[data-scene="sanremo"] .beam {
  position: absolute; display: block; pointer-events: none; height: auto; max-width: none;
}
/* Brightened copies of the lamps: fading them in over the plate lights exactly those pixels. */
.stage[data-scene="sanremo"] .archlamps { left: 0.12%; top: 4.888%; width: 99.88%; opacity: 0.55; }
.stage[data-scene="sanremo"] .truss-0 { left: 20.873%; top: 0.213%; width: 64.833%; opacity: 0.9; }
.stage[data-scene="sanremo"] .truss-1 { left: 22.608%; top: 0%; width: 62.5%; opacity: 0.3; }
.stage[data-scene="sanremo"] .bulbs-0 { left: 3.11%; top: 83.953%; width: 85.167%; opacity: 1; }
.stage[data-scene="sanremo"] .bulbs-1 { left: 8.732%; top: 83.953%; width: 83.792%; opacity: 0.35; }
.stage[data-scene="sanremo"] .bulbs-2 { left: 13.696%; top: 83.953%; width: 83.553%; opacity: 0; }
/* The sparkles on the screens, covered by the screen colour around them: in they go dark, out they shine. */
.stage[data-scene="sanremo"] .sparkle-0 { left: 47.488%; top: 9.033%; width: 36.543%; opacity: 0; }
.stage[data-scene="sanremo"] .sparkle-1 { left: 48.445%; top: 15.09%; width: 31.699%; opacity: 0; }
/* The mascot's open eye, closed (from the Codex "both eyes closed" edit): shown for one blink. */
.stage[data-scene="sanremo"] .blink { left: 60.287%; top: 30.606%; width: 4.426%; opacity: 0; }

/* The sea through each arch: a window the boats sail across. Left: from behind the palm trunk to behind
   the piano (the notch at the lower right is the piano's lid, the slope along the bottom the flowers in
   front of the balustrade). Right: from the pillar to the flowers. Picture pixels: left window 82-224 x
   478-564, right window 1552-1634 x 478-552. */
.stage[data-scene="sanremo"] .sea { overflow: hidden; }
.stage[data-scene="sanremo"] .sea-l { left: 4.904%; top: 50.797%; width: 8.493%; height: 9.139%;
  clip-path: polygon(0 0, 100% 0, 100% 81.4%, 79.6% 81.4%, 79.6% 100%, 48% 95%, 20% 78%, 9% 66%, 0 58%); }
.stage[data-scene="sanremo"] .sea-r { left: 92.823%; top: 50.797%; width: 4.904%; height: 7.864%; }
.stage[data-scene="sanremo"] .boat { position: absolute; height: auto; max-width: none; --k: calc(var(--w) / 1672); }
.stage[data-scene="sanremo"] .sea-l .boat { left: 40.1%; top: 22.1%; width: 26.1%; }
.stage[data-scene="sanremo"] .sea-r .boat { left: 30.5%; top: 31.1%; width: 41.5%; }

/* Spotlight beams: a flat two-tone cone, as the backdrop painted them, hanging from a truss lens and
   swinging a few degrees. The top of each beam is its pivot. */
.stage[data-scene="sanremo"] .beam {
  width: 7.2%; aspect-ratio: 120 / 760; translate: -50% 0; transform-origin: 50% 0;
  mix-blend-mode: screen; rotate: var(--a, 0deg);
  clip-path: polygon(45% 0, 55% 0, 100% 100%, 0 100%);
}
.stage[data-scene="sanremo"] .beam::before {
  content: ""; position: absolute; inset: 0;
  clip-path: polygon(48% 0, 52% 0, 72% 100%, 28% 100%);
}
.stage[data-scene="sanremo"] .pink { background: rgba(255, 96, 196, 0.3); }
.stage[data-scene="sanremo"] .pink::before { background: rgba(255, 150, 220, 0.28); }
.stage[data-scene="sanremo"] .gold { background: rgba(255, 196, 90, 0.3); }
.stage[data-scene="sanremo"] .gold::before { background: rgba(255, 228, 150, 0.26); }
.stage[data-scene="sanremo"] .b1 { left: 24.5%; top: 3.7%; --a: -14deg; aspect-ratio: 120 / 700; }
.stage[data-scene="sanremo"] .b2 { left: 31.4%; top: 2.2%; --a: 5deg; aspect-ratio: 120 / 560; }
.stage[data-scene="sanremo"] .b3 { left: 39.5%; top: 2.2%; --a: -9deg; aspect-ratio: 120 / 600; }
.stage[data-scene="sanremo"] .b4 { left: 66.4%; top: 5%; --a: -22deg; aspect-ratio: 120 / 480; }
.stage[data-scene="sanremo"] .b5 { left: 73.9%; top: 2%; --a: 3deg; aspect-ratio: 120 / 560; }
.stage[data-scene="sanremo"] .b6 { left: 77.9%; top: 3.2%; --a: -18deg; aspect-ratio: 120 / 660; }
.stage[data-scene="sanremo"] .petals { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }

@media (prefers-reduced-motion: no-preference) {
  .stage[data-scene="sanremo"] .bulbs-0 { animation: sanremo-chase 0.9s steps(1) infinite; }
  .stage[data-scene="sanremo"] .bulbs-1 { animation: sanremo-chase 0.9s steps(1) infinite -0.3s; }
  .stage[data-scene="sanremo"] .bulbs-2 { animation: sanremo-chase 0.9s steps(1) infinite -0.6s; }
  .stage[data-scene="sanremo"] .truss-0 { animation: sanremo-lens 3.6s steps(4) infinite; }
  .stage[data-scene="sanremo"] .truss-1 { animation: sanremo-lens 3.6s steps(4) infinite -1.8s; }
  .stage[data-scene="sanremo"] .archlamps { animation: sanremo-glow 5s ease-in-out infinite; }
  .stage[data-scene="sanremo"] .sparkle-0 { animation: sanremo-twinkle 2.8s steps(1) infinite; }
  .stage[data-scene="sanremo"] .sparkle-1 { animation: sanremo-twinkle 2.8s steps(1) infinite -1.4s; }
  .stage[data-scene="sanremo"] .blink { animation: sanremo-blink 6.5s steps(1) infinite 2s; }
  .stage[data-scene="sanremo"] .sea-l .boat { animation: sanremo-sail-l 75s linear infinite, sanremo-bob 2.6s steps(2) infinite; }
  .stage[data-scene="sanremo"] .sea-r .boat { animation: sanremo-sail-r 48s linear infinite, sanremo-bob 3.1s steps(2) infinite -1s; }
  .stage[data-scene="sanremo"] .b1 { animation: sanremo-swing 7s ease-in-out infinite alternate; --s: -14deg; --e: 4deg; }
  .stage[data-scene="sanremo"] .b2 { animation: sanremo-swing 6.2s ease-in-out infinite alternate -3s; --s: 5deg; --e: -11deg; }
  .stage[data-scene="sanremo"] .b3 { animation: sanremo-swing 8.5s ease-in-out infinite alternate -1.5s; --s: -9deg; --e: 7deg; }
  .stage[data-scene="sanremo"] .b4 { animation: sanremo-swing 7.6s ease-in-out infinite alternate -5s; --s: -22deg; --e: -6deg; }
  .stage[data-scene="sanremo"] .b5 { animation: sanremo-swing 6.8s ease-in-out infinite alternate -2s; --s: 3deg; --e: 14deg; }
  .stage[data-scene="sanremo"] .b6 { animation: sanremo-swing 9s ease-in-out infinite alternate -4s; --s: -18deg; --e: -2deg; }
}
@keyframes sanremo-chase { 0% { opacity: 1; } 33.3% { opacity: 0.35; } 66.6% { opacity: 0; } }
@keyframes sanremo-lens { 0% { opacity: 0.9; } 25% { opacity: 0.55; } 50% { opacity: 0.3; } 75% { opacity: 0.6; } }
@keyframes sanremo-glow { 50% { opacity: 0.25; } }
@keyframes sanremo-twinkle { 0%, 60% { opacity: 0; } 60.1%, 72% { opacity: 1; } 72.1%, 100% { opacity: 0; } }
@keyframes sanremo-blink { 0%, 96% { opacity: 0; } 96.1%, 98.2% { opacity: 1; } 98.3%, 100% { opacity: 0; } }
/* The boats sail to the right, at one speed: out behind the piano (left) or the flowers (right), then in
   again from behind the palm trunk or the pillar. In picture pixels (--k scales them with the stage). */
@keyframes sanremo-sail-l { 0% { translate: 0 0; } 47.5% { translate: calc(85 * var(--k)) 0; } 47.51% { translate: calc(-94 * var(--k)) 0; } 100% { translate: 0 0; } }
@keyframes sanremo-sail-r { 0% { translate: 0 0; } 49% { translate: calc(57 * var(--k)) 0; } 49.01% { translate: calc(-59 * var(--k)) 0; } 100% { translate: 0 0; } }
@keyframes sanremo-bob { 50% { margin-top: calc(2 * var(--k)); } }
@keyframes sanremo-swing { from { rotate: var(--s); } to { rotate: var(--e); } }

/* colosseo */
/* Colosseo Live: the Colosseum at sunset, lit for the show. The plate (a Codex edit of the backdrop) has no
   firework bursts, no sky beams and no banners. On top of it: fireworks, twinkling stars, swallows and the
   gold sparks falling from the firework mascot (canvas); five pale beams fanning up from the rim as the
   original drew them, swinging; the rim lamps, tower lamps and stage bulbs (three chasing groups), lit copies
   of the picture's own pixels; the five LED panels pulsing in turn, the big heart beating; and the two
   banners, cut out of the original, swaying on their rods. Every measure is a % of the 1672 x 941 picture. */
.stage[data-scene="colosseo"] .lit, .stage[data-scene="colosseo"] .banner, .stage[data-scene="colosseo"] .beam {
  position: absolute; display: block; pointer-events: none; height: auto; max-width: none;
}
.stage[data-scene="colosseo"] .rim-0 { left: 33.553%; top: 31.987%; width: 51.017%; opacity: 0.7; }
.stage[data-scene="colosseo"] .rim-1 { left: 34.211%; top: 32.625%; width: 50.12%; opacity: 0.3; }
.stage[data-scene="colosseo"] .towerlamps { left: 1.316%; top: 36.557%; width: 97.368%; opacity: 0.7; }
.stage[data-scene="colosseo"] .panel-0 { left: 40.251%; top: 51.328%; width: 4.665%; opacity: 0; }
.stage[data-scene="colosseo"] .panel-1 { left: 47.907%; top: 42.827%; width: 4.665%; opacity: 0; }
.stage[data-scene="colosseo"] .panel-2 { left: 55.383%; top: 41.02%; width: 11.842%; opacity: 0; }
.stage[data-scene="colosseo"] .panel-3 { left: 70.156%; top: 41.339%; width: 5.263%; opacity: 0; }
.stage[data-scene="colosseo"] .panel-4 { left: 80.024%; top: 48.459%; width: 5.443%; opacity: 0; }
.stage[data-scene="colosseo"] .heart { left: 57.117%; top: 44.102%; width: 8.373%; opacity: 0; }
.stage[data-scene="colosseo"] .bulbs-0 { left: 1.017%; top: 92.561%; width: 97.488%; opacity: 1; }
.stage[data-scene="colosseo"] .bulbs-1 { left: 8.612%; top: 92.561%; width: 76.615%; opacity: 0.35; }
.stage[data-scene="colosseo"] .bulbs-2 { left: 15.132%; top: 92.561%; width: 76.376%; opacity: 0; }
/* The banners hang from their rods: the pivot is the rod, at the top. */
.stage[data-scene="colosseo"] .banner { transform-origin: 50% 3%; }
.stage[data-scene="colosseo"] .banner-l { left: 1.077%; top: 50.053%; width: 5.921%; }
.stage[data-scene="colosseo"] .banner-r { left: 93.242%; top: 50.053%; width: 5.861%; }
/* The sky beams: flat pale bands from the rim lamps up into the sunset, their foot on the rim. */
.stage[data-scene="colosseo"] .beam {
  width: 6.6%; aspect-ratio: 110 / 520; translate: -50% -100%; transform-origin: 50% 100%;
  background: rgba(255, 140, 205, 0.24); mix-blend-mode: screen; rotate: var(--a, 0deg);
  clip-path: polygon(0 0, 100% 0, 66% 100%, 34% 100%);
}
/* The beam pivots at its foot, so a negative angle leans it up-left: the left beams fan up-left, the right
   ones up-right, as the original fanned them. */
.stage[data-scene="colosseo"] .b1 { left: 36.2%; top: 31.5%; --a: -44deg; aspect-ratio: 110 / 640; }
.stage[data-scene="colosseo"] .b2 { left: 42.8%; top: 30.5%; --a: -28deg; aspect-ratio: 110 / 580; }
.stage[data-scene="colosseo"] .b3 { left: 46.5%; top: 29.5%; --a: -12deg; aspect-ratio: 110 / 520; }
.stage[data-scene="colosseo"] .b4 { left: 69.2%; top: 30.5%; --a: 24deg; aspect-ratio: 110 / 560; }
.stage[data-scene="colosseo"] .b5 { left: 75%; top: 31%; --a: 40deg; aspect-ratio: 110 / 620; }
.stage[data-scene="colosseo"] .sky { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }

@media (prefers-reduced-motion: no-preference) {
  .stage[data-scene="colosseo"] .bulbs-0 { animation: colosseo-chase 1.05s steps(1) infinite; }
  .stage[data-scene="colosseo"] .bulbs-1 { animation: colosseo-chase 1.05s steps(1) infinite -0.35s; }
  .stage[data-scene="colosseo"] .bulbs-2 { animation: colosseo-chase 1.05s steps(1) infinite -0.7s; }
  .stage[data-scene="colosseo"] .rim-0 { animation: colosseo-twinkle 2.2s steps(3) infinite; }
  .stage[data-scene="colosseo"] .rim-1 { animation: colosseo-twinkle 2.2s steps(3) infinite -1.1s; }
  .stage[data-scene="colosseo"] .towerlamps { animation: colosseo-glow 3s ease-in-out infinite; }
  .stage[data-scene="colosseo"] .panel-0 { animation: colosseo-panel 4s steps(1) infinite 0s; }
  .stage[data-scene="colosseo"] .panel-1 { animation: colosseo-panel 4s steps(1) infinite -0.8s; }
  .stage[data-scene="colosseo"] .panel-2 { animation: colosseo-panel 4s steps(1) infinite -1.6s; }
  .stage[data-scene="colosseo"] .panel-3 { animation: colosseo-panel 4s steps(1) infinite -2.4s; }
  .stage[data-scene="colosseo"] .panel-4 { animation: colosseo-panel 4s steps(1) infinite -3.2s; }
  .stage[data-scene="colosseo"] .heart { animation: colosseo-heartbeat 2s steps(1) infinite; }
  .stage[data-scene="colosseo"] .banner-l { animation: colosseo-sway 3.4s ease-in-out infinite alternate; }
  .stage[data-scene="colosseo"] .banner-r { animation: colosseo-sway 3.9s ease-in-out infinite alternate -1.7s; }
  .stage[data-scene="colosseo"] .b1 { animation: colosseo-swing 9s ease-in-out infinite alternate; --s: -44deg; --e: -34deg; }
  .stage[data-scene="colosseo"] .b2 { animation: colosseo-swing 7.5s ease-in-out infinite alternate -3s; --s: -28deg; --e: -16deg; }
  .stage[data-scene="colosseo"] .b3 { animation: colosseo-swing 8.2s ease-in-out infinite alternate -5s; --s: -12deg; --e: 0deg; }
  .stage[data-scene="colosseo"] .b4 { animation: colosseo-swing 8.8s ease-in-out infinite alternate -2s; --s: 24deg; --e: 12deg; }
  .stage[data-scene="colosseo"] .b5 { animation: colosseo-swing 10s ease-in-out infinite alternate -6s; --s: 40deg; --e: 30deg; }
}
@keyframes colosseo-chase { 0% { opacity: 1; } 33.3% { opacity: 0.35; } 66.6% { opacity: 0; } }
@keyframes colosseo-twinkle { 0% { opacity: 0.7; } 33% { opacity: 0.3; } 66% { opacity: 0.5; } }
@keyframes colosseo-glow { 50% { opacity: 0.3; } }
@keyframes colosseo-panel { 0%, 10% { opacity: 1; } 10.1%, 100% { opacity: 0; } }
@keyframes colosseo-heartbeat { 0%, 7% { opacity: 1; } 7.1%, 18% { opacity: 0; } 18.1%, 25% { opacity: 1; } 25.1%, 100% { opacity: 0; } }
@keyframes colosseo-sway { from { rotate: -2.5deg; scale: 1 1; } to { rotate: 2.5deg; scale: 0.96 1; } }
@keyframes colosseo-swing { from { rotate: var(--s); } to { rotate: var(--e); } }

/* vesuvio */
/* Il Covo nel Vesuvio: the lair inside the volcano at dusk. The plate (a Codex edit of the backdrop) has an
   empty monorail track. On top of it: the lava falls and the lava pool, lit copies of the picture's own lava
   pixels pulsing at different rhythms (and the mascot carved in the rock, lit by them); the LED wall's slow
   breath and flicker; the racks' and screens' cyan LEDs, three groups that go dark in turn (the "off" layer
   is their dark glass); the town lights on the bay twinkling; the red light on the dish blinking; steam,
   lava bubbles and twinkling stars (canvas); and the monorail train, cut out of the original, running the
   whole track from the right edge down to the mascot and up again to the left edge, stopping at its
   station by the screens. Every measure is a % of the 1672 x 941 picture. */
.stage[data-scene="vesuvio"] .lit, .stage[data-scene="vesuvio"] .off, .stage[data-scene="vesuvio"] .dishtip,
.stage[data-scene="vesuvio"] .train {
  position: absolute; display: block; pointer-events: none; height: auto; max-width: none;
}
.stage[data-scene="vesuvio"] .lava-falls { left: 0; top: 0; width: 100%; opacity: 0.35; }
.stage[data-scene="vesuvio"] .lava-pool { left: 22.727%; top: 68.013%; width: 55.622%; opacity: 0.35; }
.stage[data-scene="vesuvio"] .mascot-glow { left: 35.885%; top: 13.603%; width: 12.859%; opacity: 0.3; }
.stage[data-scene="vesuvio"] .screens { left: 59.868%; top: 25.399%; width: 40.132%; opacity: 0.2; }
.stage[data-scene="vesuvio"] .leds-0 { left: 57.596%; top: 24.761%; width: 42.344%; opacity: 0; }
.stage[data-scene="vesuvio"] .leds-1 { left: 57.895%; top: 26.78%; width: 41.986%; opacity: 0; }
.stage[data-scene="vesuvio"] .leds-2 { left: 59.33%; top: 23.486%; width: 40.67%; opacity: 0; }
.stage[data-scene="vesuvio"] .town-0 { left: 28.11%; top: 58.13%; width: 16.029%; opacity: 0; }
.stage[data-scene="vesuvio"] .town-1 { left: 28.17%; top: 58.023%; width: 16.447%; opacity: 0; }
.stage[data-scene="vesuvio"] .dishtip { left: 77.99%; top: 2.019%; width: 1.675%; opacity: 0; }
.stage[data-scene="vesuvio"] .air { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
/* The train at its station (where the original drew it); its path is in picture pixels, scaled with the
   stage (--w is the stage's width, 1672 picture pixels). */
.stage[data-scene="vesuvio"] .train { left: 51.555%; top: 29.118%; width: 15.909%; --k: calc(var(--w) / 1672);
  transform-origin: 50% 50%; }

@media (prefers-reduced-motion: no-preference) {
  .stage[data-scene="vesuvio"] .lava-falls { animation: vesuvio-lava 4.2s ease-in-out infinite; }
  .stage[data-scene="vesuvio"] .lava-pool { animation: vesuvio-lava 3.1s ease-in-out infinite -1.2s; }
  .stage[data-scene="vesuvio"] .mascot-glow { animation: vesuvio-warm 4.2s ease-in-out infinite; }
  .stage[data-scene="vesuvio"] .screens { animation: vesuvio-screen 7s steps(1) infinite; }
  .stage[data-scene="vesuvio"] .leds-0 { animation: vesuvio-led 2.7s steps(1) infinite; }
  .stage[data-scene="vesuvio"] .leds-1 { animation: vesuvio-led 3.3s steps(1) infinite -1.1s; }
  .stage[data-scene="vesuvio"] .leds-2 { animation: vesuvio-led 2.1s steps(1) infinite -0.7s; }
  .stage[data-scene="vesuvio"] .town-0 { animation: vesuvio-town 3.6s steps(1) infinite; }
  .stage[data-scene="vesuvio"] .town-1 { animation: vesuvio-town 4.4s steps(1) infinite -2s; }
  .stage[data-scene="vesuvio"] .dishtip { animation: vesuvio-beacon 1.6s steps(1) infinite; }
  .stage[data-scene="vesuvio"] .train { animation: vesuvio-train 44s linear infinite; }
}
@keyframes vesuvio-lava { 0%, 100% { opacity: 0.1; } 40% { opacity: 0.5; } 55% { opacity: 0.35; } 70% { opacity: 0.55; } }
@keyframes vesuvio-warm { 0%, 100% { opacity: 0.1; } 40% { opacity: 0.4; } 70% { opacity: 0.45; } }
@keyframes vesuvio-screen { 0%, 100% { opacity: 0.2; } 30% { opacity: 0.05; } 31% { opacity: 0.35; } 32.5% { opacity: 0.1; } 34% { opacity: 0.3; } 36% { opacity: 0.2; } 68% { opacity: 0.3; } 69% { opacity: 0.05; } 70% { opacity: 0.2; } }
@keyframes vesuvio-led { 0%, 20% { opacity: 1; } 20.1%, 55% { opacity: 0; } 55.1%, 62% { opacity: 1; } 62.1%, 100% { opacity: 0; } }
@keyframes vesuvio-town { 0%, 12% { opacity: 1; } 12.1%, 48% { opacity: 0; } 48.1%, 56% { opacity: 1; } 56.1%, 100% { opacity: 0; } }
@keyframes vesuvio-beacon { 0%, 15% { opacity: 1; } 15.1%, 100% { opacity: 0; } }
/* The train's run, right to left, in picture pixels from its station (sprite centre x 995): waits at the
   station, pulls away down the slope, crosses in front of the mascot through the dip (the track curves, so
   it turns with it), climbs the left slope and leaves at the left edge; after a while it comes in again at
   the right edge, glides down the straight slope and brakes into the station. The poses come from the
   deck's top edge measured on the plate (x→y: 0→213, 100→240, 200→283, 300→312, 400→332, 500→348,
   600→358, 700→360, 800→345, 900→322, 1000→300, 1150→272, 1300→244, 1500→204, 1672→172): the train is
   a chord of its own length on that curve, so its tilt is the chord's. One speed everywhere but the stops. */
@keyframes vesuvio-train {
  0%, 16%  { translate: calc(0 * var(--k)) calc(0 * var(--k)); rotate: 0.0deg; animation-timing-function: ease-in; }
  19.00%   { translate: calc(-95 * var(--k)) calc(21 * var(--k)); rotate: -1.4deg; animation-timing-function: linear; }
  21.57%   { translate: calc(-195 * var(--k)) calc(35 * var(--k)); rotate: 1.3deg; }
  24.14%   { translate: calc(-295 * var(--k)) calc(43 * var(--k)); rotate: 6.8deg; }
  26.71%   { translate: calc(-395 * var(--k)) calc(48 * var(--k)); rotate: 14.1deg; }
  29.29%   { translate: calc(-495 * var(--k)) calc(40 * var(--k)); rotate: 18.4deg; }
  31.86%   { translate: calc(-595 * var(--k)) calc(26 * var(--k)); rotate: 21.2deg; }
  34.43%   { translate: calc(-695 * var(--k)) calc(1 * var(--k)); rotate: 25.3deg; }
  37.00%   { translate: calc(-795 * var(--k)) calc(-28 * var(--k)); rotate: 29.1deg; }
  39.57%   { translate: calc(-895 * var(--k)) calc(-53 * var(--k)); rotate: 29.7deg; }
  42.14%   { translate: calc(-995 * var(--k)) calc(-87 * var(--k)); rotate: 27.3deg; }
  46.00%   { translate: calc(-1145 * var(--k)) calc(-131 * var(--k)); rotate: 26.4deg; }
  46.01%, 70% { translate: calc(805 * var(--k)) calc(-152 * var(--k)); rotate: 0deg; animation-timing-function: linear; }
  75.14%   { translate: calc(605 * var(--k)) calc(-116 * var(--k)); rotate: 0.5deg; }
  80.29%   { translate: calc(405 * var(--k)) calc(-78 * var(--k)); rotate: -0.1deg; }
  86.71%   { translate: calc(155 * var(--k)) calc(-30 * var(--k)); rotate: 0.4deg; animation-timing-function: ease-out; }
  100%     { translate: calc(0 * var(--k)) calc(0 * var(--k)); rotate: 0.0deg; }
}
}