/* ============================================================================= Lightloom — stage.css · "La Sala" projection-room look & layout Built entirely on css/tokens.css. Warm darkness, amber projector glow. NEVER blue tech dark-mode. No frameworks, no build step. Sections: 0. Reset & base 4. Lobby (S0) + projector beam 1. Screens & geometry 5. The Set (S1): HUD, subtitles, stage-bar 2. Global post-FX 6. The Slate (hero clapperboard) + mobile sheet 3. Shared atoms 7. Theater / Showcase / About (pills, links) 8. Reduced motion + responsive/mobile ========================================================================== */ /* ---------- 0. Reset & base ------------------------------------------------ */ *, *::before, *::after { box-sizing: border-box; } html, body { margin: 0; height: 100%; } body { background: var(--bg); color: var(--ink); font-family: var(--font-ui); font-size: 16px; line-height: 1.5; -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; overflow: hidden; /* screens manage their own scroll */ } button { font: inherit; color: inherit; cursor: pointer; } a { color: var(--amber); text-decoration: none; } a:hover { text-decoration: underline; } :focus-visible { outline: 2px solid var(--amber); outline-offset: 2px; border-radius: 4px; } /* ---------- 1. Screens & geometry ----------------------------------------- */ #app { position: fixed; inset: 0; overflow: hidden; /* A faint warm floor-glow so the room is never flat black. */ background: radial-gradient(120% 80% at 50% 118%, rgba(232, 163, 61, 0.06), transparent 60%), var(--bg); } /* Each screen is a full-bleed layer; only .is-active is shown. We crossfade rather than hard-cut between screens (cinema, not tab-switch). */ .screen { position: absolute; inset: 0; display: flex; flex-direction: column; opacity: 0; visibility: hidden; pointer-events: none; transition: opacity var(--transition-ms) var(--ease), visibility 0s linear var(--transition-ms); } .screen.is-active { opacity: 1; visibility: visible; pointer-events: auto; transition: opacity var(--transition-ms) var(--ease), visibility 0s; } .screen__heading { font-family: var(--font-display); font-weight: 500; letter-spacing: 0.01em; margin: 0; } /* ---------- 2. Global post-FX (grain + vignette) -------------------------- */ /* These sit above all screens; pointer-events:none so they never block input. The animated film grain is a tiled SVG noise nudged every frame; the WebGL stage paints its own grain too, but this guarantees the whole ROOM grains. */ .fx { position: fixed; inset: 0; pointer-events: none; z-index: 50; } .fx--grain { opacity: var(--grain-opacity); mix-blend-mode: overlay; background-image: url("data:image/svg+xml;utf8,"); background-size: 160px 160px; animation: grain-shift 0.6s steps(4) infinite; will-change: transform; } @keyframes grain-shift { 0% { transform: translate(0, 0); } 25% { transform: translate(-3%, 2%); } 50% { transform: translate(2%, -4%); } 75% { transform: translate(-2%, 3%); } 100% { transform: translate(3%, -2%); } } /* Radial vignette ~12% (token --vignette) darkens the room edges. */ .fx--vignette { background: radial-gradient( 120% 100% at 50% 45%, transparent 55%, rgba(0, 0, 0, calc(var(--vignette) * 4)) 100% ); } /* ---------- 3. Shared atoms (pills, links, toast) ------------------------- */ .pill { display: inline-flex; align-items: center; gap: 0.5em; padding: 0.62em 1.05em; border: 1px solid var(--line); border-radius: var(--r-pill); background: rgba(245, 239, 230, 0.04); color: var(--ink-dim); font-size: 0.84rem; letter-spacing: 0.02em; line-height: 1; transition: color 0.25s var(--ease), border-color 0.25s var(--ease), background 0.25s var(--ease), box-shadow 0.25s var(--ease); } .pill:hover { color: var(--ink); border-color: var(--amber-soft); background: var(--amber-soft); } .pill[aria-pressed="true"] { color: var(--amber); border-color: rgba(232, 163, 61, 0.4); box-shadow: var(--halo-soft); } .pill__icon, .pill__flag { font-size: 0.95em; line-height: 1; } /* REC-accented call to action (Roll / Cut). */ .pill--rec { color: var(--ink); border-color: rgba(224, 68, 46, 0.5); background: rgba(224, 68, 46, 0.12); } .pill--rec:hover { border-color: var(--rec); background: rgba(224, 68, 46, 0.22); box-shadow: 0 0 20px rgba(224, 68, 46, 0.25); } .pill--lang { font-variant: tabular-nums; letter-spacing: 0.06em; } .pill--icon { padding: 0.5em 0.7em; } .ghostlink { display: inline-flex; align-items: center; gap: 0.5em; background: none; border: none; color: var(--ink-faint); font-size: 0.86rem; letter-spacing: 0.02em; padding: 0.4em 0; transition: color 0.25s var(--ease); } .ghostlink:hover { color: var(--amber); } .linklike { background: none; border: none; padding: 0; color: var(--amber); font-size: inherit; } .linklike:hover { text-decoration: underline; } /* Soft-error toast: amber, slides up from bottom-center. */ .toast { position: fixed; left: 50%; bottom: 6vh; transform: translate(-50%, 1.2rem); z-index: 80; max-width: min(90vw, 30rem); padding: 0.85em 1.3em; border: 1px solid rgba(232, 163, 61, 0.45); border-radius: var(--r-pill); background: rgba(27, 18, 6, 0.92); color: var(--ink); box-shadow: var(--halo); font-size: 0.9rem; text-align: center; opacity: 0; pointer-events: none; transition: opacity 0.4s var(--ease), transform 0.4s var(--ease); } .toast.is-visible { opacity: 1; transform: translate(-50%, 0); } /* ---------- 4. Lobby (S0) + volumetric projector beam --------------------- */ #lobby { padding: clamp(1.2rem, 3vw, 2.4rem); text-align: center; z-index: 10; } .lobby__top { display: flex; align-items: center; justify-content: space-between; z-index: 2; } .brandmark { display: inline-flex; align-items: center; gap: 0.55em; font-family: var(--font-display); font-weight: 600; font-size: 0.82rem; letter-spacing: var(--tracking-title); color: var(--ink-dim); } .brandmark__dot { width: 0.55em; height: 0.55em; border-radius: 50%; background: var(--rec); box-shadow: 0 0 10px rgba(224, 68, 46, 0.7); } /* Volumetric amber beam: a clipped cone from a top-right "lamp" sweeping down across the dim room. Layered cone + drifting dust + a glowing lamp source. */ .beam { position: absolute; inset: 0; overflow: hidden; pointer-events: none; z-index: 0; } .beam__cone { position: absolute; top: -16%; right: -6%; width: 86%; height: 150%; /* The cone narrows toward the lamp (top-right) and widens to the screen. */ background: conic-gradient( from 210deg at 96% 4%, transparent 0deg, rgba(232, 163, 61, 0.16) 14deg, rgba(232, 163, 61, 0.05) 30deg, transparent 44deg ); filter: blur(6px); mix-blend-mode: screen; transform-origin: top right; animation: beam-breathe 7s var(--ease) infinite; } .beam__dust { position: absolute; inset: 0; background-image: radial-gradient(1.5px 1.5px at 70% 30%, rgba(245, 239, 230, 0.5), transparent 60%), radial-gradient(1px 1px at 60% 55%, rgba(245, 239, 230, 0.4), transparent 60%), radial-gradient(1.5px 1.5px at 80% 65%, rgba(232, 163, 61, 0.5), transparent 60%), radial-gradient(1px 1px at 52% 40%, rgba(245, 239, 230, 0.35), transparent 60%); mix-blend-mode: screen; opacity: 0.7; animation: dust-drift 16s linear infinite; } .beam__lamp { position: absolute; top: 2%; right: 3%; width: 4.2rem; height: 4.2rem; border-radius: 50%; background: radial-gradient(circle, rgba(232, 163, 61, 0.85), rgba(232, 163, 61, 0.12) 60%, transparent 72%); filter: blur(2px); mix-blend-mode: screen; animation: lamp-flicker 4.5s steps(8) infinite; } @keyframes beam-breathe { 0%, 100% { opacity: 0.85; transform: rotate(0deg) scaleX(1); } 50% { opacity: 1; transform: rotate(0.6deg) scaleX(1.03); } } @keyframes dust-drift { from { transform: translateY(0); } to { transform: translateY(-3%); } } @keyframes lamp-flicker { 0%, 100% { opacity: 0.9; } 40% { opacity: 1; } 55% { opacity: 0.82; } 70% { opacity: 0.97; } } .lobby__center { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: clamp(1rem, 2.4vh, 1.8rem); z-index: 2; max-width: 56rem; margin: 0 auto; width: 100%; } .title { font-family: var(--font-display); font-weight: 600; font-size: clamp(3.2rem, 11vw, 8.2rem); line-height: 0.95; letter-spacing: 0.01em; margin: 0; text-shadow: var(--halo); } .title__word--amber { color: var(--amber); } .tagline { font-family: var(--font-display); font-style: italic; font-size: clamp(1.05rem, 2.5vw, 1.55rem); color: var(--ink-dim); margin: 0; max-width: 34ch; } /* The two doors. */ .doors { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: clamp(0.8rem, 2vw, 1.4rem); width: 100%; max-width: 42rem; margin-top: 0.4rem; } .door { display: flex; flex-direction: column; align-items: flex-start; gap: 0.45rem; text-align: left; padding: 1.3rem 1.4rem; border: 1px solid var(--line); border-radius: var(--r-panel); background: linear-gradient(160deg, rgba(245, 239, 230, 0.05), rgba(245, 239, 230, 0.015)); box-shadow: var(--panel-shadow); transition: transform 0.3s var(--ease), border-color 0.3s var(--ease), box-shadow 0.3s var(--ease); } .door:hover { transform: translateY(-3px); border-color: rgba(232, 163, 61, 0.45); box-shadow: var(--halo); } .door__icon { font-size: 1.7rem; } .door__title { font-family: var(--font-display); font-size: 1.2rem; font-weight: 600; color: var(--ink); } .door__sub { font-size: 0.86rem; color: var(--ink-faint); } /* Recital composer. */ .recital { width: 100%; max-width: 42rem; text-align: left; display: flex; flex-direction: column; gap: 0.6rem; padding: 1.1rem 1.2rem; border: 1px solid var(--line); border-radius: var(--r-panel); background: rgba(10, 10, 12, 0.6); box-shadow: var(--panel-shadow); } .recital__label { font-size: 0.74rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink-faint); } .recital__text { width: 100%; min-height: 8.5rem; resize: vertical; padding: 0.9rem 1rem; border: 1px solid var(--line); border-radius: 10px; background: rgba(10, 10, 12, 0.7); color: var(--ink); font-family: var(--font-display); font-size: 1.02rem; line-height: 1.6; } .recital__text:focus-visible { border-color: var(--amber); outline: none; box-shadow: var(--halo-soft); } .recital__cite { margin: 0; font-size: 0.76rem; color: var(--ink-faint); } .recital__actions { display: flex; justify-content: flex-end; } .lobby__foot { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 0.5rem 1rem; z-index: 2; font-size: 0.78rem; color: var(--ink-faint); } .foot__ledger strong { color: var(--ink-dim); font-variant: tabular-nums; } .foot__links { display: inline-flex; align-items: center; gap: 0.5rem; } .foot__sep { color: var(--line); } /* ---------- 5. The Set (S1): stage, HUD, subtitles, stage-bar ------------- */ #set { display: grid; /* The stage spans full width; the slate floats over its right edge on desktop; controls sit on a bottom rail. */ grid-template-rows: 1fr auto; padding: clamp(0.6rem, 1.6vw, 1.2rem); gap: clamp(0.6rem, 1.4vh, 1rem); } /* The 2.39:1 letterbox wrapper, centered. The black bars are the body bg, and the HUD lives in them. We size by available space and clamp to the aspect. */ .stage { position: relative; align-self: center; justify-self: center; width: min(100%, calc((100dvh - 9.5rem) * var(--aspect-film))); aspect-ratio: var(--aspect-film); max-height: calc(100dvh - 8.5rem); border-radius: 8px; overflow: hidden; background: #000; box-shadow: var(--halo), inset 0 0 120px rgba(0, 0, 0, 0.8); } .stage__canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; } /* HUD lives in the (effectively black) top/bottom regions of the stage. */ .hud { position: absolute; display: flex; align-items: center; gap: 0.6em; font-size: 0.72rem; letter-spacing: 0.16em; color: var(--ink-dim); z-index: 4; pointer-events: none; text-shadow: 0 1px 6px rgba(0, 0, 0, 0.9); } .hud--top { top: 0; left: 0; right: 0; justify-content: space-between; padding: 0.7rem 1rem 0; } .hud__title { font-family: var(--font-display); font-weight: 600; letter-spacing: var(--tracking-title); color: var(--ink); } .hud__counter { font-variant: tabular-nums; } .hud--budget { bottom: 0; left: 0; padding: 0 1rem 0.7rem; } .hud__rec { width: 0.5rem; height: 0.5rem; border-radius: 50%; background: var(--rec); box-shadow: 0 0 8px rgba(224, 68, 46, 0.8); animation: rec-pulse 1.6s var(--ease) infinite; } @keyframes rec-pulse { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: 0.35; transform: scale(0.78); } } .hud__budget-val { font-variant: tabular-nums; } /* JS adds .is-warning at 70% budget; the ledger turns amber. */ .hud--budget.is-warning { color: var(--amber); } .hud--budget.is-warning .hud__rec { background: var(--amber); } /* Subtitles: narrated words in Fraunces italic, AA-contrast scrim. */ .subtitles { position: absolute; left: 50%; bottom: 12%; transform: translateX(-50%); z-index: 5; width: min(82%, 46rem); text-align: center; font-family: var(--font-display); font-style: italic; font-size: clamp(1rem, 2.4vw, 1.6rem); line-height: 1.4; color: var(--ink); /* Layered text-shadow = readable over any frame without a hard box. */ text-shadow: 0 2px 10px rgba(0, 0, 0, 0.95), 0 0 24px rgba(0, 0, 0, 0.8); opacity: 0; transition: opacity 0.5s var(--ease); pointer-events: none; } .subtitles.is-visible { opacity: 1; } /* Micro-stage bar: thin amber rail with chips that light up in sequence. */ .stage-bar { position: absolute; left: 50%; bottom: 3%; transform: translateX(-50%); z-index: 5; display: flex; gap: 0.4rem; padding: 0.35rem 0.5rem; border-radius: var(--r-pill); background: rgba(0, 0, 0, 0.45); backdrop-filter: blur(4px); opacity: 0; transition: opacity 0.4s var(--ease); } .stage-bar.is-active { opacity: 1; } .stage-bar__chip { font-size: 0.6rem; letter-spacing: 0.14em; padding: 0.32em 0.7em; border-radius: var(--r-pill); color: var(--ink-faint); background: transparent; transition: color 0.3s var(--ease), background 0.3s var(--ease), box-shadow 0.3s var(--ease); } .stage-bar__chip.is-on { color: var(--bg); background: var(--amber); box-shadow: var(--halo-soft); } .stage-bar__chip.is-done { color: var(--amber); } /* Bottom control rail. */ .controls { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 0.55rem; padding-bottom: env(safe-area-inset-bottom); } /* ---------- 6. The Slate (hero clapperboard) ------------------------------ */ /* On desktop the slate floats over the stage's right edge — a real prop in the room. Chalk-on-slate body with an amber accent and clapper sticks on top. */ .slate { position: absolute; top: clamp(0.8rem, 4vh, 3rem); right: clamp(0.8rem, 2vw, 2rem); z-index: 20; width: clamp(15rem, 22vw, 18.5rem); padding: 0.9rem 1.1rem 1.1rem; border: 1px solid var(--line); border-radius: var(--r-panel); /* Slate-stone gradient, warm not blue. */ background: linear-gradient(165deg, rgba(34, 32, 30, 0.96), rgba(18, 17, 16, 0.97)); box-shadow: var(--panel-shadow), inset 0 1px 0 rgba(245, 239, 230, 0.05); font-size: 0.82rem; /* Subtle chalk grain. */ background-blend-mode: normal; } .slate__hinge { position: absolute; top: -6px; left: 1.1rem; right: 1.1rem; height: 6px; border-radius: 3px 3px 0 0; background: linear-gradient(180deg, #3a3631, #211f1c); } /* Diagonal clapper sticks — the unmistakable clapperboard silhouette. */ .slate__sticks { position: absolute; top: -6px; left: 1.1rem; right: 1.1rem; height: 1.05rem; display: flex; gap: 0; overflow: hidden; border-radius: 3px 3px 0 0; transform-origin: left center; transition: transform 0.35s var(--ease); background: repeating-linear-gradient( -55deg, var(--ink) 0 0.85rem, #1b1a18 0.85rem 1.7rem ); } .slate__sticks span { display: none; } /* When the decision flips, JS toggles .is-clapping for a quick snap. */ .slate.is-clapping .slate__sticks { animation: clap 0.32s var(--ease); } @keyframes clap { 0% { transform: rotate(-9deg); } 55% { transform: rotate(2deg); } 100% { transform: rotate(0deg); } } .slate__head { display: flex; align-items: baseline; justify-content: space-between; margin-top: 0.35rem; padding-bottom: 0.5rem; border-bottom: 1px dashed rgba(245, 239, 230, 0.16); } .slate__label { font-size: 0.62rem; letter-spacing: 0.2em; color: var(--ink-faint); } .slate__shot { font-family: var(--font-display); font-weight: 600; font-size: 0.92rem; color: var(--amber); font-variant: tabular-nums; } /* The hero decision chip: a flip card. CONTINUITY (amber) <-> CUT (red). */ .slate__decision { display: flex; justify-content: center; margin: 0.8rem 0; perspective: 600px; } .decision-chip { position: relative; display: inline-block; min-width: 9.5rem; height: 2.5rem; transform-style: preserve-3d; transition: transform 0.45s var(--ease); } .decision-chip__face { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; border-radius: var(--r-pill); font-family: var(--font-display); font-weight: 700; font-size: 1rem; letter-spacing: 0.08em; backface-visibility: hidden; } /* Front face = CONTINUITY (amber). */ .decision-chip__face--front { color: var(--bg); background: var(--amber); box-shadow: 0 0 22px rgba(232, 163, 61, 0.4); } /* Back face = CUT (red), pre-rotated so the flip reveals it. */ .decision-chip__face--back { color: var(--ink); background: var(--rec); box-shadow: 0 0 22px rgba(224, 68, 46, 0.45); transform: rotateX(180deg); } /* JS sets data-decision="cut" to flip to the red CUT face. */ .decision-chip[data-decision="cut"] { transform: rotateX(180deg); } .slate__grid { margin: 0; display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem 0.7rem; } .slate__row { min-width: 0; } .slate__row--wide { grid-column: 1 / -1; } .slate__row dt { font-size: 0.56rem; letter-spacing: 0.16em; color: var(--ink-faint); margin-bottom: 0.12rem; } .slate__row dd { margin: 0; font-size: 0.88rem; color: var(--ink); /* Camera/scale read as crisp chalk. */ font-family: var(--font-ui); font-weight: 500; overflow-wrap: anywhere; } .slate__palette { display: flex; gap: 0.4rem; margin-top: 0.85rem; } .swatch { flex: 1; height: 1.4rem; border-radius: 5px; border: 1px solid rgba(245, 239, 230, 0.12); background: var(--line); transition: background 0.5s var(--ease); } .slate__translation { margin: 0.7rem 0 0; font-size: 0.74rem; font-style: italic; color: var(--ink-faint); } /* ---------- 7. Theater / Showcase / About --------------------------------- */ /* Theater: a red curtain that parts (1.2s) to reveal the film. */ #theater { align-items: center; justify-content: center; } .curtain { position: absolute; inset: 0; z-index: 30; pointer-events: none; } .curtain__half { position: absolute; top: 0; bottom: 0; width: 52%; background: repeating-linear-gradient(90deg, rgba(0,0,0,0.28) 0 14px, transparent 14px 38px), linear-gradient(180deg, #7d1d16, #4a0f0b); box-shadow: inset 0 0 60px rgba(0, 0, 0, 0.6); transition: transform 1.2s var(--ease); } .curtain__half--left { left: 0; transform-origin: left; } .curtain__half--right { right: 0; transform-origin: right; } /* JS adds .is-open on #theater to part the curtain. */ #theater.is-open .curtain__half--left { transform: translateX(-101%); } #theater.is-open .curtain__half--right { transform: translateX(101%); } .theater__inner { display: flex; flex-direction: column; align-items: center; gap: 1rem; width: min(94%, 60rem); z-index: 5; } .theater__screen { width: 100%; aspect-ratio: var(--aspect-film); border-radius: 8px; background: #000; box-shadow: var(--halo); display: grid; place-items: center; overflow: hidden; } .theater__placeholder { color: var(--ink-faint); font-family: var(--font-display); font-style: italic; } .theater__transport { display: flex; flex-wrap: wrap; justify-content: center; gap: 0.55rem; } .theater__note { margin: 0; font-size: 0.76rem; color: var(--ink-faint); } /* Showcase: grid of pre-rendered film cards, each visibly stamped. */ #showcase { padding: clamp(1.2rem, 3vw, 2.4rem); overflow-y: auto; } .showcase__banner { margin-bottom: 1.2rem; padding: 0.9rem 1.2rem; border: 1px solid rgba(232, 163, 61, 0.4); border-radius: var(--r-panel); background: var(--amber-soft); color: var(--ink); font-size: 0.92rem; } .showcase__head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; margin-bottom: 1.4rem; } .showcase__head .screen__heading { font-size: clamp(1.6rem, 4vw, 2.4rem); } .showcase__grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr)); gap: 1.2rem; } .film-card { position: relative; border: 1px solid var(--line); border-radius: var(--r-panel); overflow: hidden; background: rgba(245, 239, 230, 0.03); box-shadow: var(--panel-shadow); transition: transform 0.3s var(--ease), box-shadow 0.3s var(--ease); } .film-card:hover { transform: translateY(-3px); box-shadow: var(--halo); } .film-card__thumb { aspect-ratio: var(--aspect-film); background: radial-gradient(80% 120% at 70% 20%, var(--amber-soft), transparent 60%), linear-gradient(160deg, #161821, #0c0d10); } .film-card__stamp { position: absolute; top: 0.7rem; left: 0.7rem; padding: 0.28em 0.7em; border: 1px solid rgba(232, 163, 61, 0.6); border-radius: var(--r-pill); background: rgba(10, 10, 12, 0.7); color: var(--amber); font-size: 0.6rem; letter-spacing: 0.16em; transform: rotate(-3deg); } .film-card__title { margin: 0.8rem 1rem 0.2rem; font-family: var(--font-display); font-size: 1.2rem; } .film-card__src { margin: 0 1rem 1rem; font-size: 0.78rem; color: var(--ink-faint); } /* About: a centered overlay panel above a dimmed room. */ .screen--overlay { background: rgba(6, 6, 8, 0.78); backdrop-filter: blur(8px); z-index: 60; align-items: center; justify-content: center; padding: clamp(1rem, 4vw, 2.5rem); } .about__panel { width: min(94%, 44rem); max-height: 86dvh; overflow-y: auto; padding: clamp(1.2rem, 3vw, 2rem); border: 1px solid var(--line); border-radius: var(--r-panel); background: linear-gradient(165deg, rgba(20, 19, 22, 0.98), rgba(12, 12, 14, 0.98)); box-shadow: var(--halo); } .about__head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 1rem; } .about__head .screen__heading { font-size: clamp(1.6rem, 4vw, 2.2rem); } .about__intro { font-size: 0.92rem; color: var(--ink-dim); margin: 0 0 1.2rem; } .about__table { width: 100%; border-collapse: collapse; font-size: 0.86rem; } .about__table th, .about__table td { text-align: left; padding: 0.5rem 0.6rem; border-bottom: 1px solid var(--line); } .about__table th { font-size: 0.66rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink-faint); } .about__table tfoot td { border-bottom: none; color: var(--amber); font-variant: tabular-nums; } .about__engine { margin: 1.2rem 0 0; font-size: 0.88rem; color: var(--ink-dim); } /* ---------- 8. Reduced motion --------------------------------------------- */ /* Triggered by body.reduced-motion (manual toggle) OR prefers-reduced-motion. Kills the grain shimmer, beam breathing, dust drift, REC pulse, chip flip animation timing — crossfade-only, static grain. (Parallax k=0 is handled in the WebGL stage module via the same body class.) */ body.reduced-motion .fx--grain { animation: none; } body.reduced-motion .beam__cone, body.reduced-motion .beam__dust, body.reduced-motion .beam__lamp, body.reduced-motion .hud__rec { animation: none; } body.reduced-motion .decision-chip, body.reduced-motion .slate__sticks { transition-duration: 0.18s; } body.reduced-motion .slate.is-clapping .slate__sticks { animation: none; } @media (prefers-reduced-motion: reduce) { .fx--grain, .beam__cone, .beam__dust, .beam__lamp, .hud__rec { animation: none; } } /* ---------- 8b. Responsive / mobile --------------------------------------- */ @media (max-width: 860px) { .doors { grid-template-columns: 1fr; } /* Mobile letterbox switches to 16:9. */ .stage, .theater__screen, .film-card__thumb { --aspect-film: var(--aspect-film-mobile); } .stage { width: 100%; max-height: calc(100dvh - 12rem); } /* The slate becomes a bottom sheet docked under the stage. */ #set { grid-template-rows: 1fr auto auto; } .slate { position: static; width: 100%; order: 2; border-radius: var(--r-panel) var(--r-panel) 0 0; /* Sheet handle look. */ border-bottom: none; } .slate__decision { margin: 0.6rem 0; } .controls { order: 3; } .subtitles { bottom: 16%; font-size: 1.05rem; } .hud { font-size: 0.62rem; letter-spacing: 0.1em; } .lobby__foot { justify-content: center; text-align: center; } } /* Very narrow phones: tighten the control rail so it never wraps awkwardly. */ @media (max-width: 480px) { .controls .pill span:not(.pill__icon):not(.pill__flag):not(.pill__lang) { display: none; /* icon-only controls; lang pill keeps its label */ } .pill--rec span:not(.pill__icon) { display: inline; /* keep the primary CTA labeled */ } }