/* Night Ryder 1983: landing page.
   An entry screen (the waiting room), then one scrolling page over a sunset and a moving grid. Pixel type, neon, CRT glass. */
:root {
  --sky: #01021e;
  --floor: #020434;
  --panel: #080a36;
  --panel-2: #0d1048;
  --pink: #ff3cc8;
  --pink-dark: #a0107e;
  --cyan: #6ee7ff;
  --blue: #5ec8ff;
  --yellow: #ffd24a;
  --text: #e9ecff;
  --dim: #a4abe0;
  --gut: clamp(1.1rem, 4vw, 2.5rem);
  --pixel: "Press Start 2P", ui-monospace, "Courier New", monospace;
  --body: system-ui, -apple-system, "Segoe UI", sans-serif;
  --film-display: "Bebas Neue", Impact, "Arial Narrow", "Helvetica Neue", sans-serif;
  /* how much darker the video is once a visitor has entered (0 = as bright as the banner, 1 = black) */
  --scene-dark: 0.6;
  /* where the entry screen's "Loading" line sits (centered in the glowing floor of the banner, as approved on the waiting room) */
  --tagY: calc(max(100vh, 56.25vw) * 0.13 + 72.5vh);
  --tagY: calc(max(100dvh, 56.25vw) * 0.13 + 72.5dvh);
  /* CRT / analog look (same as the waiting room; the scanlines are a little lighter so text stays crisp). */
  --grain: 0.08;
  --scanlines: 0.13;
  --vignette: 0.5;
  --roll: 0.05;
  --noise: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='256' height='256'%3E%3Cfilter id='l' color-interpolation-filters='sRGB'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='2' seed='7' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 1 0 0 0 0'/%3E%3CfeComponentTransfer%3E%3CfeFuncA type='linear' slope='4' intercept='-2'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Cfilter id='d' color-interpolation-filters='sRGB'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='2' seed='7' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0'/%3E%3CfeComponentTransfer%3E%3CfeFuncA type='linear' slope='-4' intercept='2'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='256' height='256' filter='url(%23l)'/%3E%3Crect width='256' height='256' filter='url(%23d)'/%3E%3C/svg%3E");
}
@media (max-aspect-ratio: 3/2) {
  :root { --tagY: calc(75vh + 14.0625vw); --tagY: calc(75dvh + 14.0625vw); }
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; background: var(--sky); }
html.locked, html.locked body { overflow: hidden; height: 100%; }
/* the page itself is not shown until a visitor has entered: the welcome screen is only the banner, the Loading line and the Enter button */
html.locked main { visibility: hidden; }
/* ...and the script places the films (inline visibility and opacity) while the page is still locked, which would otherwise show them through the welcome screen
   and then fade them out; !important beats those inline values */
html.locked .films, html.locked .film { visibility: hidden !important; }
html.locked .films { opacity: 0 !important; transition: none !important; animation: none !important; }
body {
  margin: 0; min-height: 100vh; background: transparent; color: var(--text);
  font-family: var(--body); font-size: clamp(1.3rem, 1.1rem + 0.6vw, 1.6rem); line-height: 1.25;
  -webkit-font-smoothing: none; text-rendering: optimizeSpeed;
}
img, video { display: block; max-width: 100%; }
/* The page's two videos are backgrounds and never have controls. An iPhone in Low Power Mode refuses to autoplay a video and draws its own round play button over it (2026-11-04, seen by the user on the welcome screen): hide every part of the browser's own controls. */
video::-webkit-media-controls, video::-webkit-media-controls-enclosure, video::-webkit-media-controls-panel, video::-webkit-media-controls-overlay-enclosure, video::-webkit-media-controls-overlay-play-button,
video::-webkit-media-controls-start-playback-button, video::-webkit-media-controls-play-button { display: none !important; opacity: 0 !important; visibility: hidden !important; pointer-events: none !important; -webkit-appearance: none; }
a { color: inherit; }
h1, h2, h3, p, ul, ol, dl, dd { margin: 0; }
ul, ol { padding: 0; list-style: none; }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
:focus-visible { outline: 3px solid var(--cyan); outline-offset: 3px; }
.wrap { width: min(1120px, 100% - 2 * var(--gut)); margin-inline: auto; position: relative; z-index: 1; }
.amp { color: var(--pink); }

/* ---------- the entry screen: the waiting room (no button: it opens by itself, or on any click, tap or key) ---------- */
.entry { position: fixed; inset: 0; z-index: 40; overflow: hidden; cursor: pointer; }
/* "Loading..." and "Please wait..." take turns in the same spot; the dots fill in one by one. All steps are hard jumps so it ticks like an 8-bit screen. */
/* the Loading line sits in the glowing floor of the banner, a little above where it used to (about 50 px on a 900 px tall screen), so it looks centred between the lettering and the bottom edge */
.entry-ui { position: absolute; left: 0; right: 0; display: grid; justify-items: center;
  top: calc(var(--tagY) - 0.55rem - 5.5vh); top: calc(var(--tagY) - 0.55rem - 5.5dvh); }
.entry-tag {
  margin: 0; display: grid; justify-items: center;
  font-family: var(--pixel); font-size: clamp(0.6rem, 1.5vw, 0.95rem); letter-spacing: 0.14em; text-transform: uppercase; color: #fff;
  text-shadow: -1.5px 0 rgba(255, 40, 90, 0.7), 1.5px 0 rgba(40, 200, 255, 0.7), 0 0 6px var(--pink), 0 0 18px var(--pink), 0 0 36px rgba(255, 60, 200, 0.55);
}
.entry-tag .msg { grid-area: 1 / 1; white-space: nowrap; }
.entry-tag .msg-a { animation: msg-a 6.4s steps(1, end) infinite; }
.entry-tag .msg-b { animation: msg-b 6.4s steps(1, end) infinite; }
.entry-tag .dot { animation: dot-1 1.6s steps(1, end) infinite; }
.entry-tag .dot:nth-child(2) { animation-name: dot-2; }
.entry-tag .dot:nth-child(3) { animation-name: dot-3; }
@keyframes msg-a { 0% { opacity: 1; } 50% { opacity: 0; } 100% { opacity: 0; } }
@keyframes msg-b { 0% { opacity: 0; } 50% { opacity: 1; } 100% { opacity: 1; } }
@keyframes dot-1 { 0% { opacity: 0; } 25% { opacity: 1; } 100% { opacity: 0; } }
@keyframes dot-2 { 0% { opacity: 0; } 50% { opacity: 1; } 100% { opacity: 0; } }
@keyframes dot-3 { 0% { opacity: 0; } 75% { opacity: 1; } 100% { opacity: 0; } }
/* once the page has loaded the line becomes a blinking invitation (there is no button): "Click to enter", or "Tap to enter" on touch screens */
.entry-tag .msg-c { opacity: 0; }
.entry-tag .c-touch { display: none; }
@media (hover: none) and (pointer: coarse) { .entry-tag .c-mouse { display: none; } .entry-tag .c-touch { display: inline; } }
.entry.ready .msg-a, .entry.ready .msg-b { animation: none; opacity: 0; }
.entry.ready .msg-c { opacity: 1; animation: blink 1.2s steps(1, end) infinite; }
@keyframes blink { 50% { opacity: 0; } }
/* Opening the site: the Loading line flickers out in hard steps, like an 8-bit screen, while the video darkens. */
.entry.leaving { pointer-events: none; }
.entry.leaving .entry-ui { animation: uioff 0.5s steps(5, end) forwards; }
@keyframes uioff { 0% { opacity: 1; } 20% { opacity: 0; } 40% { opacity: 1; filter: brightness(2.2); } 60% { opacity: 0; } 80% { opacity: 1; filter: brightness(2.2); } 100% { opacity: 0; } }

/* ---------- the background for the whole site: a looping video ---------- */
/* the colours above and below the banner fill the bars on tall screens, so the page blends into the video's edges */
.bg { position: fixed; inset: 0; z-index: -1; overflow: hidden; background: linear-gradient(var(--sky) 50%, var(--floor) 50%); }
.bg-layer { position: absolute; inset: 0; }
.bg-layer img, .bg-layer video, .bg-layer canvas { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: 50% 45%; }
@media (max-aspect-ratio: 3/2) { .bg-layer img, .bg-layer video { object-fit: contain; object-position: 50% 50%; } }
/* after Enter the version without the lettering fades in (in steps, like an 8-bit screen) over the first one */
.bg-home { opacity: 0; transition: opacity 0.9s steps(9, end); }
/* on a phone the home scene is as tall as the viewport gets at its largest (toolbar hidden) and hangs from the top edge: when the browser's toolbar slides away or back
   the sun and the grid do not change, the part under the toolbar is just cut off (app.js builds the grid for the same height: HS in layout()) */
.compact .bg-home { bottom: auto; height: 100vh; height: 100lvh; min-height: 100%; will-change: transform; }
.compact .bg-home canvas { -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 90px), transparent); mask-image: linear-gradient(to bottom, #000 calc(100% - 90px), transparent); }
/* ---------- phones: the welcome screen shows the tall version of the banner (night-ryder-loop-tall.mp4, 1080 x 2520: the banner untouched in the middle, the sky continued above and the grid below),
   as wide as the screen and centred, so the banner has exactly the size it has when it is letterboxed, with the sky and the grid filling the rest ---------- */
.compact .bg-intro img, .compact .bg-intro video { object-fit: cover; object-position: 50% 50%; }
.lvh-probe { position: fixed; top: 0; left: 0; width: 0; height: 100vh; height: 100lvh; visibility: hidden; pointer-events: none; }
.svh-probe { position: fixed; top: 0; left: 0; width: 0; height: 100vh; height: 100svh; visibility: hidden; pointer-events: none; }
.entered .bg-home { opacity: 1; }
.bg-home img, .bg-home video, .bg-home canvas { object-fit: cover; object-position: 50% 45%; }
/* the grid canvas (see app.js) covers the floor part of the picture and the video once it has its first picture */
.bg-home canvas { inset: auto; width: auto; height: auto; object-fit: fill; opacity: 0; }   /* placed and sized by app.js */
.bg-home canvas.on { opacity: 1; }
/* the sunset (see "The sunset" in app.js): a canvas laid over the scene with the scene's own "cover" placement (the .bg-layer rules above), hidden until the last film is passed */
.bg-set { visibility: hidden; pointer-events: none; }
.compact .bg-set { will-change: transform; }   /* a phone: the sunset's layer slides with the scene (app.js) */
/* the arcade (see "The arcade" in app.js): lies over everything in .bg, including the darkening layer below (z-index 1), so that its neon is at full brightness against the dim night;
   hidden until it appears on the horizon. The pictures are placed by app.js (transforms from the top left corner, sizes in render pixels) */
/* the city behind the arcade (app.js, "The city"): same layer as the arcade and painted before it, so under it. Light is stored in the pictures' alpha channel (plain compositing, no blend modes). */
.bg-city { position: absolute; inset: 0; z-index: 1; visibility: hidden; overflow: hidden; pointer-events: none; }
.bg-city img { position: absolute; left: 0; top: 0; max-width: none; transform-origin: 0 0; opacity: 0; will-change: transform, opacity; }
#cityClip, #citySkyBox { position: absolute; left: 0; top: 0; width: 100%; height: 100%; overflow: hidden; }   /* the sky glow, the skyline and its mist: app.js cuts this box off at the horizon while the city is still rising out of it (clip-path) */
#cityRefl { position: absolute; left: 0; top: 0; transform-origin: 0 0; opacity: 0; will-change: transform, opacity; }   /* the city's reflection in the floor, drawn by app.js on a small canvas (no 3000 px layer, no per-frame mask) */
#citySky, #cityMist { position: absolute; left: 0; top: 0; transform-origin: 0 0; opacity: 0; will-change: transform, opacity; }
#citySky { width: 1000px; height: 1000px; background: radial-gradient(ellipse closest-side, rgba(30, 64, 200, 0.42) 0%, rgba(30, 64, 200, 0.37) 20%, rgba(30, 64, 200, 0.26) 40%, rgba(30, 64, 200, 0.13) 60%, rgba(30, 64, 200, 0.05) 80%, rgba(30, 64, 200, 0) 100%); }   /* the light of the city on the sky: a soft blue ellipse (app.js sizes it and cuts it off at the city's base) */
#cityMist { width: 100%; height: 100px; background: radial-gradient(ellipse 55% 140% at 50% 100%, rgba(235, 50, 175, 0.17) 0%, rgba(235, 50, 175, 0.06) 55%, rgba(235, 50, 175, 0) 100%), linear-gradient(rgba(90, 40, 200, 0.30), rgba(90, 40, 200, 0.30));
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, rgba(0, 0, 0, 0.2) 40%, rgba(0, 0, 0, 0.62) 70%, #000 91%, transparent 100%); mask-image: linear-gradient(to bottom, transparent 0%, rgba(0, 0, 0, 0.2) 40%, rgba(0, 0, 0, 0.62) 70%, #000 91%, transparent 100%); }   /* a mist of the arcade's violet and pink along the city's foot */
.bg-arc2 { position: absolute; inset: 0; z-index: 1; visibility: hidden; overflow: hidden; pointer-events: none; }
/* a phone: the stage-2 pictures are a band across the scene; their lower edge fades into the live grid, and the mask goes while the picture grows to fill the screen */
.compact #arcSeq, .compact #arcSeqO { -webkit-mask-image: linear-gradient(to bottom, transparent, #000 14px, #000 calc(100% - 24px), transparent); mask-image: linear-gradient(to bottom, transparent, #000 14px, #000 calc(100% - 24px), transparent); }
.compact #arcSeq.zoomed, .compact #arcSeqO.zoomed { -webkit-mask-image: none; mask-image: none; }
#arcClip { position: absolute; left: 0; top: 0; width: 100%; height: 100%; overflow: hidden; }   /* the building and its haze: app.js cuts this box off at the horizon while the building is still rising out of it (clip-path) */
.bg-arc2 img { position: absolute; left: 0; top: 0; max-width: none; transform-origin: 0 0; opacity: 0; will-change: transform, opacity; }
#arcVeil { position: absolute; left: 0; top: 0; width: 2752px; height: 1560px; transform-origin: 0 0; opacity: 0; visibility: hidden; will-change: transform, opacity; pointer-events: none; background: radial-gradient(ellipse 50% 46% at 50% 56%, rgba(46, 22, 90, 0.97) 0%, rgba(46, 22, 90, 0.72) 48%, rgba(46, 22, 90, 0) 100%); }   /* haze over a far building (app.js): same place and scale as the building picture */
#arcSeq, #arcSeqO { position: absolute; visibility: hidden; display: block; }   /* placed and sized by app.js (the scene's own cover placement) */
#arcTop { position: absolute; visibility: hidden; display: block; pointer-events: none; }   /* phones: the building's top (sign, roof) above the band, under it (app.js, cvX); placed and sized by app.js */
/* the darkening layer: off on the entry screen, fades in when a visitor enters */
.bg::after { content: ""; position: absolute; inset: 0; background: #000008; opacity: 0; pointer-events: none; transition: opacity 0.9s steps(9, end); }
.entered .bg::after { opacity: var(--scene-dark); }

/* ---------- the films ---------- */
/* a clean window and nothing else: the films carry no visible writing (the title and lines stay in the page as hidden text for screen readers and search) */
.films { position: relative; min-height: 100vh; min-height: 100svh; display: grid; align-items: center; padding: clamp(3rem, 7vh, 5rem) 0; }
.films .wrap { width: min(1120px, 100% - 2 * max(var(--gut), 22px)); }
.film { display: grid; gap: clamp(0.9rem, 2.6vh, 1.8rem); }
.film + .film { margin-top: clamp(3.5rem, 9vh, 6rem); }
.film-screen { position: relative; max-width: min(1000px, max(520px, calc((100vh - 24rem) * 1.7778))); max-width: min(1000px, max(520px, calc((100svh - 24rem) * 1.7778))); margin-inline: auto; width: 100%; aspect-ratio: 16 / 9; background: #000;
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.14), 0 26px 70px rgba(0, 0, 0, 0.6); }
.film-play { position: absolute; inset: 0; display: block; cursor: pointer; overflow: hidden; }
.film-play img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 50%; transition: filter 0.2s ease; }
.film-play:hover img, .film-play:focus-visible img { filter: brightness(1.1); }
.film-screen iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; background: #000; }
/* the player lies over the thumbnail and fades in once it is really playing, so there is no black flash while it loads */
/* A player that is only cued (loaded, not playing) is not painted at all (visibility, not just opacity 0): a transparent cross-origin iframe that moves and scales with its film every frame still has to be composited, which cost
   most of the dropped frames when scrolling (measured in headless Chrome without a graphics card: 80 to 100 frames over 25 ms in 40 s of scrolling became 5 to 14). It still loads and answers. */
.film-frame { opacity: 0; visibility: hidden; pointer-events: none; transition: opacity 0.4s ease; }
.film.playing .film-frame { opacity: 1; visibility: visible; }
/* in scroll mode the player cannot be clicked or hovered, so YouTube's pause and hover overlays (title, channel, "More videos", logo) never appear;
   to let visitors click a film to pause it (at the price of those overlays showing then), add the rule
   .scroll-fx .film.live.playing .film-frame { pointer-events: auto; } (and controls=1 in startFilm() in app.js if they should also get the control bar) */
html:not(.scroll-fx) .film.playing .film-frame { pointer-events: auto; }
.film.playing .film-play { cursor: default; }
.film.playing .play, .film.starting .play { display: none; }
/* slow screens only (see "Slow screens" in app.js): while the page is moving, the playing picture gives way to the film's cover */
.lite.moving .film-frame { visibility: hidden; }
/* only a small play mark in the corner, so visitors can tell the picture plays (the middle of a thumbnail can have lettering of its own) */
.play { position: absolute; right: 3%; bottom: 6%; width: clamp(40px, 5vw, 56px); aspect-ratio: 1; display: grid; place-items: center; border-radius: 50%; background: rgba(0, 0, 0, 0.45); box-shadow: inset 0 0 0 2px rgba(255, 255, 255, 0.9); transition: transform 0.15s ease, background 0.15s ease; }
.play i { display: block; width: 0; height: 0; margin-left: 9%; border-style: solid; border-width: clamp(7px, 1vw, 10px) 0 clamp(7px, 1vw, 10px) clamp(11px, 1.6vw, 16px); border-color: transparent transparent transparent #fff; }
.film-play:hover .play, .film-play:focus-visible .play { transform: scale(1.08); background: rgba(0, 0, 0, 0.6); }
.film-play:focus-visible { outline: 3px solid #fff; outline-offset: 4px; }
/* the title under each film: white capitals as wide as the picture, wrapped to fit. The series or event line and the award stay hidden text (screen readers, search). */
.film-info { max-width: min(1000px, max(520px, calc((100vh - 24rem) * 1.7778))); max-width: min(1000px, max(520px, calc((100svh - 24rem) * 1.7778))); width: 100%; margin-inline: auto; text-align: center; color: #fff; }
.film-title { margin: 0; font-family: var(--film-display); font-weight: 400; text-transform: uppercase; line-height: 1.04; letter-spacing: 0.045em; font-size: clamp(1.4rem, 4.2vw, 3rem); text-wrap: balance; overflow-wrap: anywhere; color: #fff; }
.film-series { margin: 0.4em 0 0; font-family: var(--film-display); font-weight: 400; text-transform: uppercase; line-height: 1.05; letter-spacing: 0.07em; white-space: nowrap; font-size: clamp(0.85rem, 2.2vw, 1.4rem); color: rgba(255, 255, 255, 0.82); }
/* what Night Ryder 1983 did on the film: a small badge under the title (an outlined label with a little equalizer mark in the sunset pink), the same on every film so it reads as a credit while the films go by */
.film-credit { margin: 0.9em 0 0; display: inline-flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: 0.3em 0.65em; padding: 0.38em 0.85em 0.3em; font-family: var(--film-display); font-weight: 400; text-transform: uppercase; letter-spacing: 0.11em; line-height: 1.05; box-sizing: border-box; max-width: 100%; text-align: center; color: #fff; background: rgba(1, 2, 30, 0.62); border: 1px solid rgba(255, 255, 255, 0.6); border-radius: 0.35em; font-size: clamp(0.8rem, 1.9vw, 1.25rem); }
.film-credit .by { color: var(--pink); }
.film-credit::before { content: ""; flex: none; width: 1.04em; height: 0.82em; margin-top: -0.06em;
  background: linear-gradient(var(--pink), var(--pink)) 0 100% / 0.2em 55% no-repeat, linear-gradient(var(--pink), var(--pink)) 0.28em 100% / 0.2em 100% no-repeat,
    linear-gradient(var(--pink), var(--pink)) 0.56em 100% / 0.2em 70% no-repeat, linear-gradient(var(--pink), var(--pink)) 0.84em 100% / 0.2em 40% no-repeat; }
.film-event, .film-award { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.entered .films { animation: filmin 0.9s ease 0.5s both; }
@keyframes filmin { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }

/* ---------- scroll mode: the films stand on the grid like obstacles on a road; scrolling drives toward them ---------- */
/* (without JavaScript, or with reduced motion, none of this applies: the films are just stacked down the page) */
.scroll-fx .films { position: fixed; inset: 0; display: block; min-height: 0; padding: 0; overflow: hidden; pointer-events: none; animation: none; opacity: 0; transition: opacity 1.2s steps(8, end) 0.6s; }
.scroll-fx.entered .films { opacity: 1; }
.scroll-fx .films .wrap { position: absolute; inset: 0; width: auto; margin: 0; }
.scroll-fx .film { position: absolute; left: 0; top: 0; margin: 0; transform-origin: 0 0; opacity: 0; visibility: hidden; pointer-events: none; will-change: transform, opacity; }
.scroll-fx .film.live { pointer-events: auto; }
.scroll-fx .film-screen { max-width: none; }
/* the title follows the width of the film window (--fw is set by app.js), so it wraps the same way on every screen and the gap under the picture scales with it */
.scroll-fx .film { gap: calc(var(--fw, 640px) * 0.035); }
.scroll-fx .film-info { max-width: none; transform: scale(var(--ts, 1)); transform-origin: 50% 0; opacity: var(--to, 1); text-shadow: 0 2px 14px rgba(0, 0, 0, 0.9), 0 0 3px rgba(0, 0, 0, 0.8); }
/* (both are also capped by the screen's height, so that on a short screen such as a phone held sideways the two lines and the series line still fit under the picture) */
.scroll-fx .film-series { margin-top: calc(var(--fw, 640px) * 0.01); font-size: clamp(0.8rem, min(calc(var(--fw, 640px) * 0.037), 3vh), 1.7rem); font-size: clamp(0.8rem, min(calc(var(--fw, 640px) * 0.037), 3svh), 1.7rem); }
.scroll-fx .film-credit { margin-top: calc(var(--fw, 640px) * 0.022); font-size: clamp(0.76rem, min(calc(var(--fw, 640px) * 0.03), 2.6vh), 1.4rem); font-size: clamp(0.76rem, min(calc(var(--fw, 640px) * 0.03), 2.6svh), 1.4rem); }
.scroll-fx .film-title { font-size: clamp(1.25rem, min(calc(var(--fw, 640px) * 0.055), 5vh), 3rem); font-size: clamp(1.25rem, min(calc(var(--fw, 640px) * 0.055), 5svh), 3rem); }
/* the window stands on the grid: a dark contact shadow along its foot and a faint glow under it (no reflection in the floor) */
.scroll-fx .film-screen::after { content: ""; position: absolute; left: -3%; right: -3%; bottom: -1.6%; height: 4.5%; z-index: -1; background: radial-gradient(ellipse at 50% 30%, rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0) 72%); pointer-events: none; }
.scroll-fx .film-screen { box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.14), 0 14px 26px -10px rgba(120, 170, 255, 0.5), 0 26px 60px rgba(0, 0, 0, 0.55); }
/* a small cue that the page scrolls; it goes away at the first scroll */
.scroll-cue { position: fixed; left: 50%; bottom: max(18px, env(safe-area-inset-bottom)); width: 22px; height: 22px; margin-left: -11px; z-index: 20; pointer-events: none; opacity: 0; transition: opacity 0.6s ease; display: none; }
.scroll-fx .scroll-cue { display: block; }
.scroll-fx.entered:not(.scrolled) .scroll-cue { opacity: 0.8; transition-delay: 1.4s; }
.scroll-cue i { display: block; width: 100%; height: 100%; border-right: 2px solid #fff; border-bottom: 2px solid #fff; transform: rotate(45deg) scale(0.6); animation: cue 1.6s ease-in-out infinite; }
@keyframes cue { 0%, 100% { translate: 0 -4px; opacity: 0.45; } 50% { translate: 0 4px; opacity: 1; } }

/* sound switch (only shown when there is audio) */
.sound { position: fixed; right: max(14px, env(safe-area-inset-right)); bottom: max(14px, env(safe-area-inset-bottom)); z-index: 30; font-family: var(--pixel); font-size: 9px; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--cyan); background: rgba(1, 2, 30, 0.85); border: 0; padding: 12px 14px; cursor: pointer;
  box-shadow: 0 -3px 0 0 var(--cyan), 0 3px 0 0 var(--cyan), -3px 0 0 0 var(--cyan), 3px 0 0 0 var(--cyan), 0 0 18px rgba(110, 231, 255, 0.3); }
.sound[hidden] { display: none; }
.sound[aria-pressed="false"] { color: var(--dim); box-shadow: 0 -3px 0 0 #28338a, 0 3px 0 0 #28338a, -3px 0 0 0 #28338a, 3px 0 0 0 #28338a; }
.sound:hover { filter: brightness(1.25); }
#soundBtn:not([hidden]) ~ #filmSound { bottom: calc(max(14px, env(safe-area-inset-bottom)) + 54px); }   /* above the music switch when both show */

/* ---------- CRT glass over everything ---------- */
.crt { position: fixed; inset: 0; z-index: 50; pointer-events: none; overflow: hidden; }
.crt > i { position: absolute; display: block; }
.crt-flicker { inset: 0; background: #000; opacity: 0; animation: flicker 0.24s steps(1, end) infinite; }
@keyframes flicker { 0% { opacity: 0.02; } 25% { opacity: 0.06; } 50% { opacity: 0; } 75% { opacity: 0.04; } 100% { opacity: 0.02; } }
.crt-grain { inset: -80px; opacity: var(--grain); background-size: 256px 256px; background-image: var(--noise); animation: grain 0.9s steps(1, end) infinite; }
@keyframes grain {
  0% { transform: translate(0, 0); } 11% { transform: translate(-37px, 23px); } 22% { transform: translate(41px, -52px); } 33% { transform: translate(-18px, -61px); }
  44% { transform: translate(57px, 34px); } 55% { transform: translate(-63px, -14px); } 66% { transform: translate(26px, 58px); } 77% { transform: translate(-48px, 47px); }
  88% { transform: translate(19px, -27px); } 100% { transform: translate(0, 0); }
}
.crt-lines { inset: 0; background: repeating-linear-gradient(to bottom, rgba(0, 0, 0, 0) 0, rgba(0, 0, 0, 0) 2px, rgba(0, 0, 0, var(--scanlines)) 2px, rgba(0, 0, 0, var(--scanlines)) 3px); }
.crt-roll { left: 0; right: 0; top: 0; height: 22vh; background: linear-gradient(to bottom, rgba(255, 255, 255, 0), rgba(255, 255, 255, var(--roll)) 55%, rgba(255, 255, 255, 0)); animation: roll 7s linear infinite; }
@keyframes roll { from { transform: translateY(-30vh); } to { transform: translateY(110vh); } }
.crt-vignette { inset: 0; background: radial-gradient(ellipse 80% 75% at 50% 50%, rgba(0, 0, 0, 0) 58%, rgba(0, 0, 0, var(--vignette)) 100%); }
/* After Enter the screen settles: no brightness flicker and no rolling refresh bar. The grain, scanlines and vignette stay. (The entry screen keeps all five layers.) */
.entered .crt-flicker, .entered .crt-roll { display: none; }

/* Less motion: a still banner (the video is hidden), no animated noise, no flicker, no fades. */
@media (prefers-reduced-motion: reduce) {
  .crt-flicker, .crt-grain, .crt-roll { animation: none; }
  .crt-roll { display: none; }
  .bg video, .bg canvas { display: none; }
  .bg::after, .bg-home { transition: none; }
  .entered .films { animation: none; }
  .film-play img, .play, .film-frame { transition: none; }
  .scroll-cue { display: none !important; }
  .entry-tag .msg, .entry-tag .dot { animation: none; }
  .entry-tag .msg-a { opacity: 1; } .entry-tag .msg-b { opacity: 0; } .entry-tag .dot { opacity: 1; }
  .entry.ready .msg-a { opacity: 0; } .entry.ready .msg-c { animation: none; opacity: 1; }
  .entry.leaving .entry-ui { animation: none; opacity: 0; }
}

/* ---------- the arcade's interior as a game menu (hall.js) ---------- */
#hall { position: fixed; inset: 0; z-index: 25; overflow: hidden; visibility: hidden; pointer-events: none; }
#hallStage { position: absolute; left: 0; top: 0; width: 1920px; height: 1080px; transform-origin: 0 0; transition: transform 0.62s cubic-bezier(0.5, 0, 0.2, 1); }
#hallImg { position: absolute; left: 0; top: 0; width: 1920px; height: 1080px; max-width: none; user-select: none; -webkit-user-drag: none; }
.hs-cab { position: absolute; transform-origin: 0 0; pointer-events: none; mix-blend-mode: normal; filter: blur(0.35px) saturate(1.2) brightness(1.12) contrast(1.08); }   /* soft like a tube, not a sharp sticker */
.hs-bloom { mix-blend-mode: screen; filter: blur(4px) saturate(1.4) brightness(1.25); }
.hs-spot { position: absolute; padding: 0; margin: 0; border: 0; background: transparent; cursor: pointer; border-radius: 14px; pointer-events: none; font: inherit; color: inherit; -webkit-tap-highlight-color: transparent; }
#hall.on .hs-spot { pointer-events: auto; }
#hall.zoomed .hs-spot, #hall.clipping .hs-spot { pointer-events: none; }
.hs-spot:focus { outline: none; }
/* the selected machine: its own neon rim lights up and bleeds a halo (hall.js: the .hs-edge picture after the button, or after the button's sign); no frame is drawn round it */
.hs-edge { position: absolute; z-index: 5; pointer-events: none; opacity: 0; transition: opacity 0.18s ease-out; user-select: none; -webkit-user-drag: none; }
.hs-spot.sel + .hs-edge, .hs-spot.sel + .hs-sign + .hs-edge { opacity: 1; animation: hsedge 1.1s ease-in-out infinite; }
@keyframes hsedge { 50% { opacity: 0.74; } }
.hs-plate { position: absolute; left: 50%; bottom: 100%; margin-bottom: 40px; transform: translateX(calc(-50% + var(--dx, 0px))); white-space: nowrap; opacity: 0; pointer-events: none; font-family: var(--pixel); font-size: 22px; letter-spacing: 0.14em; color: #fff; background: rgba(1, 2, 30, 0.88); padding: 14px 20px 12px; border: 3px solid var(--cyan); box-shadow: 0 0 26px rgba(110, 231, 255, 0.6); text-shadow: 0 0 10px var(--pink); }
.hs-plate i { font-style: normal; color: var(--yellow); margin-right: 8px; }
.hs-arrow { position: absolute; left: 50%; bottom: 100%; margin-bottom: 4px; transform: translateX(-50%); font-size: 30px; color: var(--yellow); opacity: 0; pointer-events: none; text-shadow: 0 0 12px var(--yellow); }
.hs-spot.sel .hs-plate, .hs-spot.sel .hs-arrow { opacity: 1; }
.hs-spot.sel .hs-arrow { animation: hsbob 0.5s steps(2, end) infinite; }
@keyframes hsbob { 50% { transform: translate(-50%, 8px); } }
#hallDim { position: absolute; inset: 0; background: radial-gradient(ellipse at 50% 50%, rgba(1, 2, 24, 0.5), rgba(1, 2, 24, 0.86)); opacity: 0; transition: opacity 0.45s ease; pointer-events: none; }
#hall.zoomed #hallDim { opacity: 1; }
/* the menu's frame: title top left, key hints at the bottom */
#hallHud { position: absolute; inset: 0; pointer-events: none; opacity: 0; transition: opacity 0.4s ease; font-family: var(--pixel); text-transform: uppercase; }
#hall.on #hallHud { opacity: 1; }
#hall.zoomed #hallHud, #hall.zoomed .hs-plate, #hall.zoomed .hs-arrow, #hall.clipping #hallHud, #hall.clipping .hs-plate, #hall.clipping .hs-arrow { opacity: 0; }
.hh-top { position: absolute; left: clamp(14px, 2.6vw, 40px); top: clamp(14px, 3vh, 34px); display: grid; gap: 8px; text-shadow: 0 0 12px var(--pink), 0 2px 0 #000; }
.hh-top b { font-weight: 400; font-size: clamp(0.8rem, 1.5vw, 1.25rem); letter-spacing: 0.16em; color: #fff; }
.hh-top span { font-size: clamp(0.5rem, 0.9vw, 0.72rem); letter-spacing: 0.2em; color: var(--cyan); }
.hh-keys { position: absolute; left: 0; right: 0; bottom: clamp(16px, 3.4vh, 38px); display: flex; justify-content: center; gap: clamp(14px, 3vw, 44px); font-size: clamp(0.5rem, 0.85vw, 0.7rem); letter-spacing: 0.16em; color: #fff; text-shadow: 0 0 8px #000, 0 2px 0 #000; }
/* touch screens: no keyboard, no hovering: swipe to look around (only when the picture is wider than the window), tap a sign */
.hh-touch { display: none; position: absolute; left: 0; right: 0; bottom: clamp(16px, 3.4vh, 38px); flex-direction: column; align-items: center; gap: 10px; font-size: clamp(0.5rem, 0.85vw, 0.7rem); letter-spacing: 0.16em; color: #fff; text-shadow: 0 0 8px #000, 0 2px 0 #000; text-align: center; }
.hh-dots { display: none; position: absolute; left: 0; right: 0; bottom: calc(clamp(16px, 3.4vh, 38px) + 52px); justify-content: center; gap: 14px; }
.hh-dots i { width: 9px; height: 9px; border: 2px solid var(--cyan); transform: rotate(45deg); box-shadow: 0 0 6px rgba(0, 0, 0, 0.8); }
.hh-dots i.on { background: var(--cyan); box-shadow: 0 0 10px var(--cyan); }
#hall.paged .hh-dots { display: flex; }
.hh-swipe { display: none; color: var(--cyan); animation: hsblink 2.4s steps(1, end) infinite; }
#hall.pannable .hh-swipe { display: block; }
@media (hover: none) { .hh-keys { display: none; } .hh-touch { display: flex; font-size: clamp(0.55rem, 2vw, 0.78rem); } }
html.hall-active { touch-action: pan-y pinch-zoom; }   /* in the hall a sideways swipe is for looking around (hall.js); up and down still scroll the page */
#hall.dragging #hallStage { transition: none; }
#hall.paged:not(.zoomed) #hallStage { transition: transform 0.32s cubic-bezier(0.22, 1, 0.36, 1); }   /* a swipe settles on its page at once (quick, slowing down), not with the slow ease of the zoom */
#hall.pannable #hallStage { will-change: transform; }   /* the picture is moved by hand: keep it on its own layer */
#hall { -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; }
.hh-keys span { animation: hsblink 2.4s steps(1, end) infinite; }
.hh-keys span:nth-child(2) { animation-delay: 0.8s; } .hh-keys span:nth-child(3) { animation-delay: 1.6s; }
@keyframes hsblink { 0%, 80% { opacity: 1; } 90% { opacity: 0.55; } }
kbd { font-family: var(--pixel); font-size: inherit; display: inline-block; padding: 0.5em 0.7em 0.4em; margin-right: 0.35em; color: #fff; background: rgba(1, 2, 30, 0.78); border: 2px solid var(--cyan); box-shadow: 0 0 10px rgba(110, 231, 255, 0.45); }
#hall.has-sel .hh-keys span:first-child { opacity: 0.5; animation: none; }
/* the music that is playing */
@media (hover: none) { html.hall-active .sound { bottom: auto; top: max(14px, env(safe-area-inset-top)); } }
#hallToast { position: absolute; left: 50%; bottom: clamp(70px, 12vh, 120px); transform: translate(-50%, 8px); padding: 10px 16px; background: rgba(1, 2, 30, 0.88); border: 2px solid var(--cyan); box-shadow: 0 0 18px rgba(110, 231, 255, 0.5); font-family: var(--pixel); font-size: clamp(0.5rem, 0.85vw, 0.68rem); letter-spacing: 0.14em; color: #fff; white-space: nowrap; opacity: 0; pointer-events: none; transition: opacity 0.2s ease, transform 0.2s ease; z-index: 30; }
#hallToast.on { opacity: 1; transform: translate(-50%, 0); }
@keyframes hseq { 0% { height: 4px; } 50% { height: 16px; } 100% { height: 6px; } }
/* a machine's screen */
#hallScreen { position: absolute; inset: 0; display: grid; place-items: center; opacity: 0; transform: scale(0.5); transition: opacity 0.3s steps(5, end), transform 0.42s cubic-bezier(0.2, 0.8, 0.2, 1); pointer-events: none; }
#hallScreen.on { opacity: 1; transform: none; pointer-events: auto; }
.hs-frame { width: min(88vw, calc((100vh - 190px) * 16 / 9)); display: grid; gap: 0; background: #05062a; border: 4px solid var(--pink); box-shadow: 0 0 44px rgba(255, 60, 200, 0.55), 0 0 0 2px #000, inset 0 0 30px rgba(0, 0, 0, 0.8); }
.hs-bar { display: flex; align-items: center; gap: 14px; padding: 10px 14px; background: linear-gradient(#0d1048, #070933); border-bottom: 3px solid var(--cyan); font-family: var(--pixel); font-size: clamp(0.5rem, 1vw, 0.8rem); letter-spacing: 0.14em; color: #fff; }
.hs-no { color: var(--yellow); }
.hs-name { flex: 1; text-shadow: 0 0 10px var(--pink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hs-x { font: inherit; color: #fff; background: rgba(255, 60, 200, 0.2); border: 2px solid #fff; padding: 8px 12px; cursor: pointer; letter-spacing: 0.14em; }
.hs-x kbd { padding: 0.25em 0.45em; margin: 0 0 0 0.5em; font-size: 0.8em; }
.hs-x:hover, .hs-x:focus-visible { background: var(--pink); }
.hs-view { position: relative; aspect-ratio: 16 / 9; background: #000; overflow: hidden; }
.hs-view::after { content: ""; position: absolute; inset: 0; pointer-events: none; z-index: 5; background: repeating-linear-gradient(to bottom, rgba(0, 0, 0, 0) 0, rgba(0, 0, 0, 0) 2px, rgba(0, 0, 0, 0.18) 2px, rgba(0, 0, 0, 0.18) 3px), radial-gradient(ellipse at 50% 50%, rgba(0, 0, 0, 0) 60%, rgba(0, 0, 0, 0.4) 100%); }
.hs-view iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; background: #000; z-index: 3; }
.hs-film { position: absolute; inset: 0; }
.hs-thumb { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; max-width: none; }
.hs-play { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); display: grid; justify-items: center; gap: 12px; padding: 22px 34px 18px; background: rgba(1, 2, 30, 0.72); border: 3px solid #fff; color: #fff; cursor: pointer; font-family: var(--pixel); z-index: 2; box-shadow: 0 0 30px rgba(255, 60, 200, 0.7); }
.hs-play span { font-size: clamp(1.6rem, 4vw, 3rem); text-shadow: 0 0 16px var(--pink); line-height: 1; }
.hs-play i { font-style: normal; font-size: clamp(0.5rem, 1vw, 0.8rem); letter-spacing: 0.24em; animation: blink 1.2s steps(1, end) infinite; }
.hs-play:hover, .hs-play:focus-visible { background: var(--pink-dark); }
.hs-splash { position: absolute; inset: 0; z-index: 6; display: grid; place-content: center; text-align: center; gap: 14px; background: #02031c; font-family: var(--pixel); color: #fff; transition: opacity 0.18s steps(3, end); cursor: pointer; }
.hs-splash.gone { opacity: 0; pointer-events: none; }
.hs-splash b { font-weight: 400; font-size: clamp(1rem, 3.2vw, 2.6rem); letter-spacing: 0.2em; color: var(--yellow); text-shadow: 0 0 18px var(--yellow); animation: blink 0.6s steps(1, end) infinite; }
.hs-splash small { font-size: clamp(0.5rem, 1vw, 0.8rem); letter-spacing: 0.3em; color: var(--cyan); }
.hs-cap { padding: 14px 18px 16px; background: #070933; border-top: 3px solid var(--cyan); color: #fff; min-height: 74px; }
.hs-cap h3 { margin: 0; font-family: var(--film-display); font-weight: 400; text-transform: uppercase; letter-spacing: 0.06em; font-size: clamp(1.1rem, 2.4vw, 2rem); line-height: 1.05; }
.hs-cap p { margin: 6px 0 0; font-family: var(--pixel); font-size: clamp(0.45rem, 0.8vw, 0.64rem); letter-spacing: 0.14em; text-transform: uppercase; line-height: 1.5; }
.hc-series { color: var(--cyan); } .hc-credit { color: var(--pink); } .hc-event { color: var(--yellow); }
.hs-soon { position: absolute; inset: 0; display: grid; place-content: center; text-align: center; gap: 16px; background: linear-gradient(#0a0d5a, #1a0a52 60%, #05062a); font-family: var(--pixel); }
.hs-soon i { font-style: normal; color: var(--cyan); font-size: clamp(0.6rem, 1.4vw, 1.1rem); letter-spacing: 0.24em; }
.hs-soon b { font-family: var(--film-display); font-weight: 400; font-size: clamp(2rem, 7vw, 5.5rem); letter-spacing: 0.06em; color: #fff; text-shadow: 0 0 22px var(--pink), 0 0 6px #fff; }
.hs-soon small { color: var(--yellow); font-size: clamp(0.5rem, 1.1vw, 0.9rem); letter-spacing: 0.3em; animation: blink 1.2s steps(1, end) infinite; }
.hs-list { position: absolute; inset: 0; padding: 4% 6%; display: grid; align-content: center; gap: 1.2%; background: linear-gradient(#0a0d5a, #1a0a52 70%, #05062a); }
.hs-list h4 { margin: 0; font-family: var(--film-display); font-weight: 400; font-size: clamp(1.4rem, 4vw, 3.2rem); letter-spacing: 0.08em; color: #fff; text-shadow: 0 0 18px var(--pink); }
.hs-list p { margin: 0 0 2%; font-family: var(--pixel); font-size: clamp(0.5rem, 1vw, 0.8rem); letter-spacing: 0.2em; color: var(--cyan); text-transform: uppercase; }
.hs-list ul { list-style: none; display: grid; gap: 0.6vh; }
.hs-row { display: flex; align-items: center; gap: 1.6vw; width: 100%; text-align: left; font-family: var(--pixel); color: #fff; background: transparent; border: 0; border-left: 4px solid transparent; padding: 0.9vh 1vw; cursor: pointer; font-size: clamp(0.5rem, 1.15vw, 0.95rem); letter-spacing: 0.12em; text-transform: uppercase; }
.hs-row i { font-style: normal; color: var(--yellow); opacity: 0; }
.hr-n { color: var(--cyan); }
.hs-row:hover, .hs-row:focus-visible { background: rgba(255, 60, 200, 0.22); border-left-color: var(--yellow); outline: none; }
.hs-row:hover i, .hs-row:focus-visible i { opacity: 1; animation: blink 0.8s steps(1, end) infinite; }
/* the jukebox's screen (hall.js buildPlaylist): the track names as neon tubes hovering over the dimmed hall, the same layers, glow and float as the signs */
.pn { position: absolute; inset: 0; display: grid; place-items: center; padding: 3vh 5vw; cursor: pointer; }
.pn-box { display: grid; justify-items: start; cursor: default; }
.pn-head { justify-self: center; margin-bottom: 1.6vh; --c1: #ff3cc8; }
.pn-row { display: block; margin: 0; padding: 4px 16px 4px 0; border: 0; background: transparent; color: inherit; font: inherit; cursor: pointer; -webkit-tap-highlight-color: transparent; --c1: #6ee7ff; }
.pn-in { display: block; animation: pnfloat 4.3s ease-in-out var(--d, 0s) infinite; }
.pn svg, .pn-head svg { display: block; overflow: visible; filter: drop-shadow(0 0 2px var(--c1)) drop-shadow(0 0 10px var(--c1)); transition: opacity 0.2s ease, filter 0.2s ease; }
.pn-row svg { opacity: 0.8; }
.pn-row:hover svg, .pn-row:focus-visible svg, .pn-row.cur svg { opacity: 1; filter: drop-shadow(0 0 3px var(--c1)) drop-shadow(0 0 14px var(--c1)) drop-shadow(0 0 30px var(--c1)); }   /* lit */
.pn-row:focus-visible { outline: none; }
.pn svg g { fill: none; stroke-linecap: round; stroke-linejoin: round; }
.pn .s1 { stroke-width: 8; opacity: 0.4; } .pn .s2 { stroke-width: 3.4; } .pn .s3 { stroke: #fff; stroke-width: 1.2; opacity: 0.9; }
.pl-mk { opacity: 0; }
.pn-row.cur.on .pl-play, .pn-row.cur:not(.on) .pl-pause { opacity: 1; }
.pn-x { position: absolute; top: max(16px, 3vh); left: max(16px, 3vw);   /* top left: on a touch screen the Sound switch sits at the top right */
  padding: 6px 10px; border: 0; background: transparent; cursor: pointer; -webkit-tap-highlight-color: transparent; }
.pn-hint { margin: 2.2vh 0 0; justify-self: center; font-family: var(--pixel); font-size: clamp(0.45rem, 0.8vw, 0.62rem); letter-spacing: 0.16em; color: var(--cyan); text-shadow: 0 0 8px #000; text-align: center; opacity: 0.85; }
@keyframes pnfloat { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-3px); } }
/* the racer on a machine's screen (hall.js startGame): its own page, started at once */
@media (max-height: 520px) and (orientation: landscape) { .hs-frame.hs-fgm { width: min(94vw, calc((100vh - 70px) * 3 / 2)); } .hs-frame.hs-fgm .hs-cap { display: none; } .hs-frame.hs-fgm .hs-view.hs-gm { aspect-ratio: 3 / 2; } }   /* a phone on its side: the game takes the window (no caption, a 3:2 screen) */
.hs-view.hs-gm::after { display: none; }   /* the game draws its own CRT look */
/* the jukebox */
.hs-view { container-type: inline-size; }
@media (max-aspect-ratio: 1 / 1) and (max-width: 560px) { .hs-view.hs-gm { aspect-ratio: 3 / 4; } }   /* a portrait phone: a taller screen, so that eight tracks and the play bar fit (wider windows keep the 16:9 screen) */
html.hall-open, html.hall-open body { overflow: hidden; }
@media (prefers-reduced-motion: reduce) { #hallStage, #hallScreen, #hallDim { transition: none; } .hs-spot.sel + .hs-edge, .hs-spot.sel + .hs-sign + .hs-edge, .hs-spot.sel .hs-arrow, .hh-keys span, .hs-splash b, .hs-play i { animation: none; } }

/* ---------- walking up to a machine and standing in front of it (hall.js): the walk, the flash, the station ---------- */
#hallWalk { position: absolute; inset: 0; }
#hall.walking #hallWalk { animation: hswalk 0.64s ease-in infinite; }
@keyframes hswalk { 0% { transform: translateY(0); filter: blur(0); } 25% { transform: translateY(5px); } 50% { transform: translateY(0); filter: blur(1.4px); } 75% { transform: translateY(6px); } 100% { transform: translateY(0); filter: blur(0.6px); } }
#hall.walking #hallStage { transition-duration: 0.74s; transition-timing-function: cubic-bezier(0.55, 0, 0.35, 1); }
#hall.inside #hallWalk { visibility: hidden; animation: none; transition: visibility 0s linear 0.5s; }   /* stays up under the station's wipe (0.45 s) so the page's wide hall never shows between the zoom and the station */
.hs-spot.off { cursor: default; pointer-events: none !important; }
#hallFlash { position: absolute; inset: 0; z-index: 8; pointer-events: none; opacity: 0; background: radial-gradient(circle at 50% 46%, #fff 0, var(--fc, #6ee7ff) 38%, rgba(1, 2, 24, 0.9) 78%); transition: opacity 0.16s steps(4, end); }
#hallFlash.on { opacity: 1; }
#hallStation { position: absolute; inset: 0; z-index: 6; visibility: hidden; overflow: hidden; background: #02031c; --c1: #ff3cc8; --c2: #ffb347; }
#hallStation.on { visibility: visible; animation: stin 0.45s steps(8, end) both; }
@keyframes stin { from { clip-path: inset(0 0 100% 0); } to { clip-path: inset(0 0 0 0); } }
.st-bg { position: absolute; inset: 0; background: radial-gradient(ellipse at 50% 38%, #1b1f8a 0, #0a0c50 42%, #02031c 80%); overflow: hidden; }
.st-grid { position: absolute; left: -40%; right: -40%; bottom: -8%; height: 56%; background-image: linear-gradient(var(--c1) 1px, transparent 1px), linear-gradient(90deg, var(--c1) 1px, transparent 1px); background-size: 60px 60px; opacity: 0.32; transform: perspective(380px) rotateX(64deg); transform-origin: 50% 100%; animation: stgrid 2s linear infinite; mask-image: linear-gradient(to top, #000 30%, transparent); -webkit-mask-image: linear-gradient(to top, #000 30%, transparent); }
@keyframes stgrid { to { background-position: 0 60px, 0 0; } }
.st-haze { position: absolute; left: 50%; top: 34%; width: 70vmin; height: 70vmin; margin: -35vmin 0 0 -35vmin; border-radius: 50%; background: radial-gradient(circle, var(--c1), transparent 66%); opacity: 0.22; filter: blur(30px); }
.st-main { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; gap: clamp(20px, 5vw, 90px); padding: 4vh 4vw; }
.st-cab { position: relative; height: min(88vh, calc(88vw * 860 / 520 * 0.5)); aspect-ratio: 520 / 860; flex: none; container-type: inline-size; filter: drop-shadow(0 0 28px color-mix(in srgb, var(--c1) 60%, transparent)); }
.st-svg { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.st-marq { position: absolute; left: 13.5%; top: 6.05%; width: 73%; height: 10.9%; display: grid; place-items: center; }
.st-marq b { font-family: var(--film-display); font-weight: 400; font-size: 12.5cqw; letter-spacing: 0.1em; color: #fff; text-shadow: 0 0 14px var(--c1), 0 0 34px var(--c1); animation: stmarq 3.4s steps(1, end) infinite; }
@keyframes stmarq { 0%, 92% { opacity: 1; } 94% { opacity: 0.55; } 96% { opacity: 1; } 98% { opacity: 0.7; } }
.st-screen { position: absolute; left: 16.2%; top: 22.3%; width: 67.6%; height: 41.8%; overflow: hidden; background: #02031c; border-radius: 6px; display: grid; place-items: center; align-content: center; gap: 2cqw; text-align: center; opacity: var(--fl, 1); box-shadow: inset 0 0 24px rgba(0, 0, 0, 0.8); }
.st-fx { position: absolute; inset: 0; width: 100%; height: 100%; image-rendering: pixelated; opacity: 0.9; }
.st-screen::after { content: ""; position: absolute; inset: 0; pointer-events: none; background: repeating-linear-gradient(to bottom, rgba(0, 0, 0, 0) 0, rgba(0, 0, 0, 0) 2px, rgba(0, 0, 0, 0.2) 2px, rgba(0, 0, 0, 0.2) 3px), radial-gradient(ellipse at 50% 50%, rgba(0, 0, 0, 0) 55%, rgba(0, 0, 0, 0.5) 100%); }
.st-glyph { position: relative; width: 17cqw; height: 17cqw; filter: drop-shadow(0 0 10px var(--c1)); animation: stbob 2.4s steps(6, end) infinite; }
.st-glyph svg { width: 100%; height: 100%; display: block; }
@keyframes stbob { 50% { transform: translateY(-1.2cqw); } }
.st-name { position: relative; font-family: var(--film-display); font-size: 9cqw; letter-spacing: 0.1em; color: #fff; text-shadow: 0 0 12px var(--c1); line-height: 1; }
.st-handle { position: relative; font-family: var(--pixel); font-size: 2.2cqw; letter-spacing: 0.14em; color: var(--c2); }
.st-press { position: relative; font-family: var(--pixel); font-size: 2.4cqw; letter-spacing: 0.2em; color: #fff; animation: blink 0.9s steps(1, end) infinite; }
.st-btn { animation: stbtn 1.6s steps(1, end) infinite; } .st-btn.b2 { animation-delay: 0.4s; } .st-btn.b3 { animation-delay: 0.8s; } .st-btn.b4 { animation-delay: 1.2s; }
@keyframes stbtn { 0%, 70% { opacity: 1; } 80% { opacity: 0.35; } }
.st-slot { animation: stbtn 1.1s steps(1, end) infinite; } .st-slot.s2 { animation-delay: 0.55s; }
.st-floor { position: absolute; left: -12%; right: -12%; bottom: -5%; height: 6%; background: radial-gradient(ellipse at 50% 0, var(--c1), transparent 70%); opacity: 0.55; filter: blur(8px); }
.st-ui { display: grid; gap: 14px; align-content: center; justify-items: start; max-width: 430px; font-family: var(--pixel); color: #fff; }
.st-no { margin: 0; font-size: clamp(0.5rem, 0.9vw, 0.72rem); letter-spacing: 0.24em; color: var(--c2); }
.st-ui h3 { margin: 0; font-family: var(--film-display); font-weight: 400; font-size: clamp(2.4rem, 7vw, 6rem); line-height: 0.95; letter-spacing: 0.06em; text-shadow: 0 0 18px var(--c1), 0 0 40px var(--c1); }
.st-line { margin: 0; font-size: clamp(0.6rem, 1.1vw, 0.9rem); letter-spacing: 0.2em; color: var(--c2); }
.st-start { display: inline-flex; align-items: center; gap: 0.8em; margin-top: 10px; padding: 1.1em 1.6em; font: inherit; font-size: clamp(0.7rem, 1.3vw, 1.05rem); letter-spacing: 0.18em; color: #fff; text-decoration: none; background: color-mix(in srgb, var(--c1) 40%, #05062a); border: 3px solid #fff; box-shadow: 0 0 26px var(--c1), inset 0 0 18px rgba(255, 255, 255, 0.15); text-shadow: 0 0 10px #000; cursor: pointer; animation: stpulse 1.2s steps(2, end) infinite; }
.st-start i { font-style: normal; }
.st-start:hover, .st-start:focus-visible { background: var(--c1); outline: none; animation: none; }
.st-start.off { cursor: default; animation: none; opacity: 0.65; box-shadow: none; border-color: rgba(255, 255, 255, 0.5); }
@keyframes stpulse { 50% { box-shadow: 0 0 44px var(--c1), inset 0 0 18px rgba(255, 255, 255, 0.15); } }
.st-url { margin: 0; font-size: clamp(0.45rem, 0.75vw, 0.6rem); letter-spacing: 0.14em; color: rgba(255, 255, 255, 0.6); word-break: break-all; }
.st-back { margin-top: 22px; font: inherit; font-size: clamp(0.5rem, 0.85vw, 0.7rem); letter-spacing: 0.14em; color: #fff; background: rgba(255, 255, 255, 0.08); border: 2px solid rgba(255, 255, 255, 0.7); padding: 0.9em 1.2em; cursor: pointer; }
.st-back:hover, .st-back:focus-visible { background: var(--c1); outline: none; }
@media (max-width: 820px) { .st-main { flex-direction: column; gap: 14px; padding: 2vh 4vw; } .st-cab { height: 56vh; } .st-ui { justify-items: center; text-align: center; } .st-ui h3 { font-size: 2.6rem; } }
@media (prefers-reduced-motion: reduce) { #hall.walking #hallWalk, #hallStation.on, .st-grid, .st-glyph, .st-press, .st-btn, .st-slot, .st-marq b, .st-start { animation: none; } #hallFlash { transition: none; } }

/* ---------- the neon signs that hover above the machines (hall.js): tubes in the platform's colours, floating, clickable; the lights stay steady, only the position drifts ---------- */
.hs-sign { position: absolute; z-index: 20; pointer-events: none; cursor: pointer; transition: opacity 0.4s ease; }
.hs-sign::before { content: ""; position: absolute; inset: -16%; border-radius: 50%; background: radial-gradient(circle, rgba(2, 3, 28, 0.6) 0, rgba(2, 3, 28, 0.34) 46%, rgba(2, 3, 28, 0) 72%); }   /* a soft dark backing, so that the tubes read against the ceiling lights */
.hs-sign::after { content: ""; position: absolute; inset: -34%; border-radius: 50%; background: radial-gradient(circle, var(--c1) 0, rgba(0, 0, 0, 0) 62%); opacity: 0.22; pointer-events: none; }   /* the light the tubes throw on the air around them */
#hall.on .hs-sign { pointer-events: auto; }
#hall.zoomed .hs-sign, #hall.clipping .hs-sign { pointer-events: none; opacity: 0; }
.hs-sign-in { position: absolute; inset: 0; animation: hsfloat 3.9s ease-in-out var(--d, 0s) infinite; }
@keyframes hsfloat { 0%, 100% { transform: translateY(0) rotate(-1.4deg); } 50% { transform: translateY(calc(var(--sz) * -0.07)) rotate(1.4deg); } }
.hs-sign svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; transform-origin: 50% 50%; filter: drop-shadow(0 0 3px var(--c1)) drop-shadow(0 0 12px var(--c1)); transition: transform 0.18s ease, filter 0.18s ease; }
.hs-sign svg g { fill: none; stroke-linecap: round; stroke-linejoin: round; }
.hs-sign .s1 { stroke-width: 9; opacity: 0.3; }
.hs-sign .s2 { stroke-width: 4.4; }
.hs-sign .s3 { stroke: #fff; stroke-width: 1.5; opacity: 0.9; }
.hs-spot.sel + .hs-sign svg { transform: scale(1.16); filter: drop-shadow(0 0 4px var(--c1)) drop-shadow(0 0 20px var(--c1)) drop-shadow(0 0 42px var(--c1)); }
.hs-spot.has-sign .hs-arrow { display: none; }
#hall.zoomed .hs-spot.sel + .hs-sign, #hall.clipping .hs-spot.sel + .hs-sign { opacity: 1; animation: hsgo 0.6s ease-in forwards; }   /* the chosen sign swells and fades as the camera sets off */
@keyframes hsgo { 0% { transform: scale(1); opacity: 1; } 40% { transform: scale(1.5); opacity: 1; } 100% { transform: scale(2.3); opacity: 0; } }   /* transform and opacity only: animating a filter (or a blend) here repaints the whole stage every frame (a 0.8 s stall) */
@media (prefers-reduced-motion: reduce) { .hs-sign-in, #hall.zoomed .hs-spot.sel + .hs-sign, #hall.clipping .hs-spot.sel + .hs-sign { animation: none; } #hall.zoomed .hs-spot.sel + .hs-sign, #hall.clipping .hs-spot.sel + .hs-sign { opacity: 0; } }

/* ---------- the walk-up clips and the render station (hall.js): the clip plays in the hall's own picture, then dissolves into the close-up render with the live screen on its glass ---------- */
.hs-clip { position: absolute; left: 0; top: 0; width: 1920px; height: 1080px; object-fit: cover; opacity: 0; pointer-events: none; z-index: 15; transition: opacity 0.3s ease; background: #02031c; }
.hs-clip.on { opacity: 1; }
#hall.zoomed .hs-edge, #hall.clipping .hs-edge { opacity: 0 !important; animation: none; }   /* the lit edges go as the camera sets off (they would otherwise ride along with the zoom) */
#hall.clipping #hallStage { transition: transform 0.85s cubic-bezier(0.4, 0, 0.45, 1); }   /* a clip that begins closer: the hall's picture steps up to where it begins (transform only) */
#hall.clipping .hs-cab { opacity: 0 !important; transition: opacity 0.3s ease; }   /* the hall's live screens fade as the clip fades in (the clip's first picture is the hall) */
#hallSkip { position: absolute; inset: 0; z-index: 5; pointer-events: none; display: grid; align-items: end; justify-items: center; padding-bottom: 5vh; }
#hall.clipping #hallSkip { pointer-events: auto; cursor: pointer; }
#hallSkip span { font-family: var(--pixel); font-size: clamp(0.5rem, 0.8vw, 0.65rem); letter-spacing: 0.2em; color: rgba(255, 255, 255, 0.7); text-shadow: 0 0 8px #000; opacity: 0; transition: opacity 0.6s ease 0.8s; }
#hall.clipping #hallSkip span { opacity: 1; }
#hallStation.rs.on { animation: rsin 0.55s ease both; }
@keyframes rsin { from { opacity: 0; } to { opacity: 1; } }
.rs .st-render { position: absolute; left: 0; top: 0; width: 1920px; height: 1080px; transform-origin: 0 0; }
.rs .st-render.glide { transition: transform 0.8s cubic-bezier(0.5, 0, 0.2, 1); }
.rs .st-still { position: absolute; inset: 0; width: 100%; height: 100%; display: block; user-select: none; }
.rs .st-glow { position: absolute; left: 0; top: 0; transform-origin: 0 0; background: radial-gradient(ellipse, var(--c1), rgba(0, 0, 0, 0) 68%); opacity: 0.4; filter: blur(22px); mix-blend-mode: screen; pointer-events: none; }   /* the platform's colour spilling out of the glass onto the bezel (static) */
.rs .st-glass { position: absolute; left: 0; top: 0; transform-origin: 0 0; container-type: inline-size; filter: blur(0.4px) saturate(1.15) brightness(1.08); -webkit-mask-image: radial-gradient(ellipse at 50% 50%, #000 56%, rgba(0, 0, 0, 0) 100%); mask-image: radial-gradient(ellipse at 50% 50%, #000 56%, rgba(0, 0, 0, 0) 100%); }
.rs .st-screen { left: 0; top: 0; width: 100%; height: 100%; border-radius: 0; box-shadow: none; gap: 3cqw; background: color-mix(in srgb, var(--c1) 20%, #04051f); }
.rs .st-glyph { width: 25cqw; height: 25cqw; } .rs .st-name { font-size: 13cqw; } .rs .st-handle { font-size: 3.2cqw; } .rs .st-press { font-size: 3.5cqw; }
.rs .st-scrim { position: absolute; inset: 0; pointer-events: none; background: linear-gradient(to left, rgba(2, 3, 28, 0.84) 0, rgba(2, 3, 28, 0.55) 30%, rgba(2, 3, 28, 0) 58%); }
.rs.ui-left .st-scrim { background: linear-gradient(to right, rgba(2, 3, 28, 0.84) 0, rgba(2, 3, 28, 0.55) 30%, rgba(2, 3, 28, 0) 58%); }
.rs .st-ui { position: absolute; top: 50%; right: 5vw; transform: translateY(-50%); width: min(32vw, 430px); max-width: none; }
.rs.ui-left .st-ui { right: auto; left: 5vw; }
.st-sign { position: relative; width: clamp(64px, 9vw, 128px); aspect-ratio: 1; margin-bottom: 2px; animation: stfloat 3.9s ease-in-out infinite; }
@keyframes stfloat { 0%, 100% { transform: translateY(0) rotate(-1.4deg); } 50% { transform: translateY(-6px) rotate(1.4deg); } }
.st-sign svg { width: 100%; height: 100%; display: block; overflow: visible; filter: drop-shadow(0 0 4px var(--c1)) drop-shadow(0 0 16px var(--c1)); }
.st-sign svg g { fill: none; stroke-linecap: round; stroke-linejoin: round; }
.st-sign .s1 { stroke-width: 9; opacity: 0.3; } .st-sign .s2 { stroke-width: 4.4; } .st-sign .s3 { stroke: #fff; stroke-width: 1.5; opacity: 0.9; }
@media (max-width: 820px) { .rs .st-ui, .rs.ui-left .st-ui { top: auto; bottom: 3vh; left: 50%; right: auto; transform: translateX(-50%); width: 92vw; justify-items: center; text-align: center; } .rs .st-ui h3 { font-size: 2.6rem; } .rs .st-scrim, .rs.ui-left .st-scrim { background: linear-gradient(to top, rgba(2, 3, 28, 0.92) 0, rgba(2, 3, 28, 0.6) 40%, rgba(2, 3, 28, 0) 66%); } }
@media (prefers-reduced-motion: reduce) { #hallStation.rs.on, .st-sign { animation: none; } }
