/* ─────────────────────────────────────────────────────────────────────────
 * scenes.css — the scroll scenes of the round-2 redesign.
 *
 * S3 (2026-07-19): PRELUDE + REALM HALL, ported from the approved mock
 * (handoff_website/mock/Sojourn Live Preview.dc.html) into the site's own
 * class + token style. Every measurement here was lifted from that mock.
 *
 * The pinned-section pattern (shared by every scene): a wrapper of height Nvh,
 * a `position:sticky; top:0; height:100vh` inner, and progress
 * p = -wrapper.top / (wrapper.height - vh) driven from ONE scroll handler in
 * realms.js (rAF'd by Lenis). Tokens live in base.css; realm accents there too.
 *
 * The `eqbar` keyframe is defined once, globally, in index.html's <style>.
 * ───────────────────────────────────────────────────────────────────────── */

/* ══ LISTENING MOMENT (founder 2026-07-21 polish) ═══════════════════════════
 * A soft page-wide veil dims non-playing content while a door plays; JS
 * (realms.js, off the shared audio's play/pause events) toggles .is-listening
 * on it and .is-listening-spot on whichever element IS the playing thing (the
 * NOW PLAYING plate, or the clicked door card), lifting that one element
 * above the veil so it alone stays lit. z-index 20: above ordinary page
 * content (the hero's own layers top out at 3; room content is unpositioned)
 * but below the warp-in overlay (40) and the atmosphere canvas (60), so
 * neither is ever dimmed by the cue it is itself driving. Off entirely under
 * reduced-motion/Save-Data (html.still) — a quieting cue is still motion. */
.listening-veil {
  position: fixed;
  inset: 0;
  z-index: 20;
  background: #020617;
  opacity: 0;
  pointer-events: none;
  transition: opacity 700ms ease;
}
.listening-veil.is-listening { opacity: 0.2; }
.is-listening-spot { z-index: 21; }
.rh-door.is-listening-spot { position: relative; z-index: 21; }
html.still .listening-veil { display: none !important; }

/* ══ PRELUDE ═══════════════════════════════════════════════════════════════
 * S6 (2026-07-21, designer handoff): a scroll-driven 3D coverflow carousel of
 * the four intent doors (SLEEP/FOCUS/UNWIND/ESCAPE), replacing the five-door
 * cycler row. The centre arch faces the viewer large; neighbours turn away
 * and recede along a sin/cos arc (drift + per-frame placement in
 * prelude-carousel.js's initPreludeCarousel, run from realms.js). Glass
 * treatment (chromatic edges + specular sheen + gloss + bevel), an even
 * accent halo behind the focused arch, and the focused door's painting
 * blurred full-bleed as atmosphere. NO audio, NO chip, NO click-to-play here
 * (sound stays in REALM HALL). Cosmos background + the site's atmosphere
 * particle canvas (atmosphere.js, a separate global overlay) are unchanged.
 * Values are 1:1 with the approved mock `Prelude Carousel Sim.dc.html`
 * (../handoff_prelude_carousel/README.md has the full motion breakdown). */
/* 820vh = 100vh pinned + 720vh SCROLL, split into 6 EQUAL 120vh-of-scroll
   beats: the intro wipe, the 4 doors, and (founder 2026-07-22 follow-up) a
   dedicated bridge-copy beat — see WIPE/BRIDGE in prelude-carousel.js. `p`
   (scroll progress) is measured over the SCROLL distance only (offsetHeight
   minus the 100vh viewport, see prog() in prelude-carousel.js), so a beat
   fraction of 1/6 means 1/6 of the 720vh scroll, i.e. 120vh — the exact
   same per-beat scroll distance the original 700vh/5-beats section had
   (600vh scroll / 5 = 120vh). Was 700vh; the bridge used to share the tail
   of the last door's range via a narrow opacity curve and a normal scroll
   flick skipped past it entirely. The wipe and 4 door beats keep their
   EXACT prior 120vh-of-scroll allotment each (only the bridge is new/
   appended), so the door-to-door pacing already tuned against founder
   feedback is untouched. */
/* Section height / beat count (founder 2026-07-22, "too easy to skip past
   the first door"): #prelude is 6 beats (the intro wipe, the 4 doors, the
   bridge) at 170vh each = 1020vh of actual scroll, +100vh for the pinned
   viewport. Was 820vh (120vh/beat); the bigger beat, combined with wider
   hold margins on the door sweep itself (prelude-carousel.js DOOR_LEAD_IN/
   DOOR_LEAD_OUT), gives every door beat more scroll room before a normal
   flick can carry a visitor past it, the first door especially. */
#prelude { height: 1120vh; position: relative; }

/* --pc-w lives here (not on .pc-arch) so .pc-caption can also read it to
   anchor itself off the arch's real geometry (founder 2026-07-21 #3). */
.pc-pin {
  --pc-w: min(clamp(240px, 22vw, 400px), calc(50vh * 5 / 7));
  position: sticky; top: 0; height: 100vh; overflow: hidden; background: #05070d;
}

/* Founder 2026-07-21 (#2): "just the cosmos, like the last part of our
   website at the very bottom" — match CLOSING's .cl-bg/.cl-scrim treatment
   exactly (opacity 0.35 + saturate/brightness filter, FLAT dim, never a
   radial vignette) instead of the prelude's own heavier wash. */
.pc-bg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: 0.35; filter: saturate(0.4) brightness(0.7); }

/* The focused-door blurred-art wash was the "glove" over the cosmos
   (founder 2026-07-21 #2) — retired. Elements stay in the DOM (JS still
   sets their per-frame opacity) so nothing else needs to change; they are
   just never shown. */
.pc-bd { display: none; }

.pc-scrim { position: absolute; inset: 0; background: linear-gradient(rgba(2, 6, 23, 0.4), rgba(2, 6, 23, 0.4)), linear-gradient(to bottom, #020617 0%, rgba(2, 6, 23, 0) 30%, rgba(2, 6, 23, 0.55) 75%, #020617 100%); }

.pc-intro {
  position: absolute; left: 0; right: 0; top: 5vh; z-index: 400;
  display: flex; flex-direction: column; align-items: center; gap: 16px;
  padding: 0 8vw; text-align: center; will-change: opacity, transform;
}
.pc-headline { font-family: var(--serif); font-size: clamp(28px, 3.4vw, 52px); line-height: 1.14; color: var(--text); max-width: 24ch; }
.pc-body { font-size: clamp(13px, 1.1vw, 17px); line-height: 1.6; color: var(--text-secondary); max-width: 60ch; }

/* the 3D arc */
.pc-persp { position: absolute; inset: 0; perspective: 1700px; perspective-origin: 50% 52%; }
.pc-stage { position: absolute; inset: 0; transform-style: preserve-3d; }

.pc-arch {
  /* Founder 2026-07-21: the arches were too tall and collided with the
     headline on laptop-height viewports. The width is now ALSO bounded by
     the viewport height (an arch is 5:7, so height = width * 1.4), and the
     block sits slightly lower in the frame (-0.58 rather than -0.7).
     --pc-w itself now lives on .pc-pin (see above) so .pc-caption can share
     it. */
  position: absolute; left: 50%; top: 50%;
  width: var(--pc-w); aspect-ratio: 5 / 7;
  margin-left: calc(var(--pc-w) / -2);
  margin-top: calc(var(--pc-w) * -0.28);
  transform-style: preserve-3d; will-change: transform, opacity;
}
/* even blurred halo behind the focused arch (JS fades opacity 0 -> ~0.26) */
.pc-glow {
  position: absolute; inset: -3%; pointer-events: none; opacity: 0; will-change: opacity;
  border-radius: 52% 52% 10px 10px / 31% 31% 4% 4%;
  background: rgb(var(--ac)); filter: blur(26px);
}
.pc-arch-inner {
  position: absolute; inset: 0; overflow: hidden;
  border-radius: 50% 50% 6px 6px / 32% 32% 3% 3%;
  box-shadow: 0 0 0 1px rgba(226,232,240,0.18), 0 40px 90px rgba(0,0,0,0.6); /* JS overrides per frame */
}
.pc-arch-inner img,
.pc-arch-inner .pc-arch-video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* Founder 2026-07-21 (#4): the FOCUSED arch plays its door's video loop;
   unfocused arches show the still <img> beneath. The video fades in over
   the still rather than swapping so a slow/failed load never shows a gap.
   prelude-carousel.js toggles .is-live and falls back to the still on a
   video `error` event. */
.pc-arch-video { opacity: 0; transition: opacity 420ms ease; }
.pc-arch-video.is-live { opacity: 1; }
html.still .pc-arch-video { display: none; }
/* chromatic-fringe hint (alche's per-channel lens distortion, faked with rims) */
.pc-fringe {
  position: absolute; inset: 0; pointer-events: none; mix-blend-mode: screen;
  box-shadow: inset 6px 0 20px rgba(255,64,64,0.42), inset -6px 0 20px rgba(72,208,255,0.42),
              inset 0 7px 18px rgba(120,255,180,0.24), inset 0 -7px 18px rgba(200,120,255,0.32);
}
/* diagonal specular sweep across the glass */
.pc-sheen {
  position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(118deg, rgba(255,255,255,0.24) 0%, rgba(255,255,255,0.05) 17%, transparent 38%, transparent 60%, rgba(255,255,255,0.09) 100%);
}
/* top gloss */
.pc-gloss {
  position: absolute; left: 0; right: 0; top: 0; height: 40%; pointer-events: none;
  background: linear-gradient(180deg, rgba(255,255,255,0.18), transparent); border-radius: inherit;
}
/* inner bevel rim + base shade */
.pc-bevel {
  position: absolute; inset: 0; pointer-events: none;
  box-shadow: inset 0 0 62px rgba(5,7,13,0.5), inset 0 2px 0 rgba(255,255,255,0.28), inset 0 -18px 40px rgba(5,7,13,0.4);
}

/* Play/pause chip (founder 2026-07-21, second follow-up; retuned
   2026-07-22 third follow-up: "i cant see a play button similar to the
   other doors") — the same visual language as REALM HALL's .rh-playing
   (bare accent glyph at rest, dark pill + moving bars while playing) but
   bound to the FOCUSED door's --ac (JS-set custom property, since this is
   now one shared element, not one per arch — see the markup comment:
   anything nested inside .pc-stage's `transform-style: preserve-3d`
   silently fails hit-testing in this browser, so the chip lives OUTSIDE
   that hierarchy and prelude-carousel.js repositions it in screen space
   (left/bottom, in px) every frame to track the focused arch's own real
   bottom-centre. Opacity/pointer-events are now a DEDICATED curve (see
   focusedChipOp in prelude-carousel.js), not the caption's own narrow one
   — measured at 0.335 at a normal reading position, because the caption's
   cop curve only opens up very close to exact centre, and the visitor
   rarely parks there. The resting glyph is also bigger now (was 24px,
   matching realm-hall's small door tiles) with a soft dark shadow/backing
   so it stays legible sitting directly over a big painting, which a bare
   glyph the size of a door-card icon could not manage. */
.pc-play {
  position: absolute; left: 0; bottom: 18px; transform: translateX(-50%); z-index: 20;
  display: flex; align-items: center; gap: 9px;
  background: rgba(2, 6, 23, 0.78); border: 1px solid color-mix(in srgb, rgb(var(--ac, 226 232 240)) 45%, transparent);
  border-radius: 999px; padding: 8px 16px 8px 10px; cursor: pointer;
  opacity: 0; pointer-events: none; will-change: opacity, left, bottom;
}
.pc-play:not(.is-playing) { gap: 0; padding: 0; background: none; border: none; }
.pc-play-glyph {
  width: 42px; height: 42px; border-radius: 50%; background: rgb(var(--ac, 226 232 240)); color: #05070d;
  display: flex; align-items: center; justify-content: center; font-size: 15px; padding-left: 3px;
  /* Soft dark backing (not a hard pill edge) so the accent circle reads
     over any of the four paintings, brightest included. */
  box-shadow: 0 2px 16px rgba(2, 6, 23, 0.55), 0 0 0 10px rgba(2, 6, 23, 0.22);
}
/* Playing state keeps its prior, smaller proportions (founder: "keep the
   playing state as-is") — it sits inside the dark pill + bars already, so
   it does not need the resting glyph's own backing. */
.pc-play.is-playing .pc-play-glyph {
  width: 24px; height: 24px; font-size: 9px; padding-left: 2px; box-shadow: none;
}
.pc-play-eq { display: none; align-items: flex-end; gap: 2px; height: 14px; }
.pc-play.is-playing .pc-play-eq { display: flex; }
.pc-play-eq span { width: 3px; height: 14px; background: rgb(var(--ac)); transform-origin: bottom; animation: eqbar 0.9s ease-in-out infinite; display: block; }
.pc-play-eq span:nth-child(2) { animation-duration: 1.2s; animation-delay: 0.15s; }
.pc-play-eq span:nth-child(3) { animation-duration: 0.7s; animation-delay: 0.3s; }
.pc-play-eq span:nth-child(4) { animation-duration: 1s; animation-delay: 0.45s; }
html.still .pc-play { display: none; }

/* Centred caption, one line-up crossfades to the focused arch. Founder
   2026-07-21 (round 1): was bottom-anchored and sat on top of the artwork's
   lower edge; moved top-anchored, clear above the arch.
   Founder 2026-07-21 (round 2, #3): a fixed clamp() from the viewport top
   left too big a gap at tall viewports since it never tracked the arch's
   OWN top edge; replaced with a top: formula anchored off the arch's
   STATIC CSS top.
   Founder 2026-07-21 (round 3, evening follow-up): that formula still read
   as touching the art. Measured with getBoundingClientRect: the FOCUSED
   arch is scaled 1.18x (scale: 0.66 + 0.52*focus, focus=1 at centre) by
   prelude-carousel.js's per-frame transform, around its own centre — which
   lifts its RENDERED top edge ~0.126*archHeight above the static CSS top
   the old formula assumed, and the caption's actual 3-line content (120.6px
   measured) was already a hair taller than the old fixed 118px track. Net
   result: the caption's last line landed ~20px BELOW the arch's real top
   edge (verified, not assumed).
   Fix: anchor the caption from the BOTTOM instead of the top, and let
   `.pc-cap`'s content grow upward from that anchor (no fixed track height
   to under-measure again). `.pc-caption`'s `bottom` is computed straight
   from the arch's own scaled-top formula (50vh - factor*pc-w, where factor
   folds in both the -0.28/-0.34 margin-top and the +0.126*pc-w scale lift)
   plus a flat 28px clearance — so the LAST line of the caption (not just
   its box) sits a real, verified 28px above the arch at every height.
   min() keeps a ceiling so short viewports never push the caption above
   the top of the screen. Applied to ALL FOUR beats via this one shared
   rule — to revert a single beat, add a `.pc-cap[data-pc-cap="N"]`
   override rather than touching this. */
.pc-caption {
  position: absolute; left: 0; right: 0; z-index: 400; display: flex; justify-content: center;
  bottom: min(calc(100vh - 150px), calc(50vh + (var(--pc-w) * 0.406) + 28px));
}
.pc-cap-track { position: relative; width: min(760px, 86vw); height: 0; text-align: center; }
/* bottom: 0 (not inset: 0) — the box grows upward from the track's bottom
   edge as content wraps, so extra text height never eats into the gap
   above the arch (only the top of the box moves, the floor never does). */
.pc-cap { position: absolute; left: 0; right: 0; bottom: 0; display: flex; flex-direction: column; align-items: center; gap: 9px; opacity: 0; will-change: opacity, transform; }
/* Founder 2026-07-22 (third follow-up): "make the sleep unwind escape focus
   text bigger" — it names what the app is FOR, so it should carry weight in
   the composition, not read as a caption chip. Scaled up from a flat 12px
   to a responsive clamp (roughly 15-21px) while keeping the spaced small-
   caps treatment, the accent colour, and staying clearly subordinate to the
   serif door name (clamp 30-50px) below it. Weight nudged 500->600 so the
   wider letterforms stay crisp at the larger size. */
.pc-eyebrow { font-size: clamp(15px, 1.7vw, 21px); letter-spacing: 0.42em; text-transform: uppercase; font-weight: 600; color: rgb(var(--ac)); }
.pc-name { font-family: var(--serif); font-size: clamp(30px, 3.4vw, 50px); line-height: 1.05; color: var(--text); }
/* "A door from the X realm." (founder 2026-07-22): set by JS, sits between
   the door name and its whispered place line, plain and quiet, no emphasis
   fighting the serif name above it. Empty (no text, no gap) until JS fills
   it in, so it costs nothing if that ever fails. */
.pc-realm:empty { display: none; }
.pc-realm { font-size: clamp(12px, 1.1vw, 14px); letter-spacing: 0.02em; color: var(--text-muted); }
.pc-place { font-family: var(--whisper); font-style: italic; font-size: clamp(15px, 1.4vw, 20px); color: var(--text-secondary); }

/* TYPOGRAPHY SETTLE (founder 2026-07-21 polish): the door name's letters,
   wrapped into spans at runtime by prelude-carousel.js, settle in as the
   caption comes into focus (.is-settled toggled per frame, ~100ms total
   stagger via each letter's own transition-delay set in JS). The real
   characters stay in the DOM (just distributed across spans); the parent
   .pc-name carries an aria-label with the plain name so the accessible name
   is unaffected by this wrapper being aria-hidden. */
.pc-name-letters { display: inline-block; }
.pc-letter { display: inline-block; opacity: 0; transform: translateY(4px); transition: opacity 260ms ease, transform 260ms ease; }
.pc-name-letters.is-settled .pc-letter { opacity: 1; transform: translateY(0); }
html.still .pc-letter { opacity: 1 !important; transform: none !important; transition: none !important; }

.pc-cue { position: absolute; left: 50%; bottom: 16px; transform: translateX(-50%); z-index: 400; font-size: 11px; letter-spacing: 0.3em; text-transform: uppercase; color: #64748b; }

/* WANDER cue at the last door (founder 2026-07-22): same visual language as
   the hero's `.hero-cue` (animated line + small-caps word) — reuses the
   `cue` keyframe defined alongside .hero-cue-line in index.html's inline
   styles, since @keyframes resolve globally across stylesheets. Opacity is
   driven per frame in prelude-carousel.js, visible only while the visitor
   is parked at Glass Sea. */
.pc-cue-wander {
  position: absolute; left: 50%; bottom: 34px; transform: translateX(-50%); z-index: 402;
  display: flex; flex-direction: column; align-items: center; gap: 10px;
  color: var(--text-secondary); font-family: var(--sans); font-size: 11px; letter-spacing: 2px; text-transform: uppercase;
  opacity: 0; pointer-events: none; will-change: opacity;
}
.pc-cue-wander-line {
  width: 1px; height: 46px;
  background: linear-gradient(to bottom, rgba(226, 232, 240, 0), var(--accent));
  animation: cue 2.6s ease-in-out infinite;
  transform-origin: top center;
}

/* Quiet mute affordance (founder 2026-07-21, #4): browsers block audio
   autoplay before a user gesture, so the door music + ambience only start
   after the visitor's first pointerdown/click/keydown (prelude-carousel.js).
   This lets them silence it afterward without hunting for a system control. */
.pc-mute {
  position: absolute; right: 20px; bottom: 16px; z-index: 401;
  display: flex; align-items: center; gap: 7px;
  background: rgba(2, 6, 23, 0.5); border: 1px solid rgba(226, 232, 240, 0.35);
  border-radius: 999px; padding: 7px 14px 7px 12px; cursor: pointer;
  font-family: var(--sans); font-weight: 700; font-size: 10px; letter-spacing: 0.2em;
  text-transform: uppercase; color: var(--text-secondary);
  transition: border-color 200ms ease, color 200ms ease;
}
.pc-mute:hover { border-color: rgba(226, 232, 240, 0.65); color: var(--text); }
.pc-mute-glyph { font-size: 12px; line-height: 1; opacity: 0.9; }
.pc-mute.is-muted .pc-mute-glyph { opacity: 0.4; }
html.still .pc-mute { display: none; }
@media (max-width: 760px) {
  .pc-mute { right: 12px; bottom: 12px; padding: 6px 11px 6px 10px; }
  .pc-mute-label { display: none; }
}

/* Hand-off into REALM HALL: the old room-preview bridge screen (founder
   2026-07-21: "get rid of this page after the prelude") is gone. In its
   place, a plain fade to near-black over the scroll's last ~7% (JS-driven,
   see prelude-carousel.js) so the cut into the next pinned section settles
   instead of jumping. */
.pc-fade { position: absolute; inset: 0; z-index: 600; background: #05070d; opacity: 0; pointer-events: none; will-change: opacity; overflow: hidden; }

/* The bridge's cosmos backdrop (founder 2026-07-22): mirrors CLOSING's own
   .cl-bg/.cl-scrim treatment exactly (same source image, same opacity/filter,
   same gradient) instead of the flat black the fade used to be. Sits inside
   .pc-fade so it fades in/out with the rest of the blackout beat. */
.pc-fade-bg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: 0.35; filter: saturate(0.4) brightness(0.7); }
.pc-fade-scrim {
  position: absolute; inset: 0;
  background:
    linear-gradient(rgba(2, 6, 23, 0.4), rgba(2, 6, 23, 0.4)),
    linear-gradient(to bottom, #020617 0%, rgba(2, 6, 23, 0) 30%, rgba(2, 6, 23, 0.55) 75%, #020617 100%);
}

/* Bridge copy (founder 2026-07-21, #5): the blackout used to leave an empty
   screen before REALM HALL took over. A short line now fades in as the
   blackout finishes and fades back out just before the cut (both driven by
   the same scroll progress in prelude-carousel.js, so it is scrub-
   reversible like everything else here). Sits above .pc-fade (600). */
.pc-bridge {
  position: absolute; inset: 0; z-index: 610;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 14px; padding: 0 8vw; text-align: center;
  opacity: 0; pointer-events: none; will-change: opacity;
}
.pc-bridge-eyebrow { font-family: var(--sans); font-weight: 700; font-size: 11px; letter-spacing: 0.35em; text-transform: uppercase; color: var(--text-secondary); }
.pc-bridge-line { font-family: var(--serif); font-size: clamp(20px, 2.4vw, 30px); line-height: 1.55; color: var(--text); max-width: 42ch; }

/* Same hero-cue idiom as .pc-cue-wander, reading EXPLORE THE REALMS here
   (founder 2026-07-22). A plain child of .pc-bridge, so it rides the same
   fade-in/hold/fade-out curve as the rest of the bridge copy. */
.pc-bridge-cue {
  display: flex; flex-direction: column; align-items: center; gap: 10px;
  margin-top: 6px;
  color: var(--text-secondary); font-family: var(--sans); font-size: 11px; letter-spacing: 2px; text-transform: uppercase;
}
.pc-bridge-cue-line {
  width: 1px; height: 46px;
  background: linear-gradient(to bottom, rgba(226, 232, 240, 0), var(--accent));
  animation: cue 2.6s ease-in-out infinite;
  transform-origin: top center;
}

/* Reveal items animate in on first intersection (realms.js sets the transition
   with its per-item delay, then toggles opacity/transform). Used elsewhere on
   the page; the prelude carousel drives its own opacity per frame instead. */
[data-reveal] {
  opacity: 0;
  transform: translateY(28px);
}

/* ── phones ─────────────────────────────────────────────────────────────── */
@media (max-width: 760px) {
  .pc-pin { --pc-w: min(62vw, calc(48vh * 5 / 7)); }
  .pc-arch { margin-top: calc(var(--pc-w) * -0.34); }
  .pc-name { font-size: clamp(26px, 7.5vw, 40px); }
  /* The phone arch uses a different top-offset multiplier (-0.34 vs -0.28),
     so the caption's bottom-anchored formula (#3) needs its own copy here
     to stay in sync: factor = 0.34 + 0.126 (the same scale-lift term). */
  .pc-caption { bottom: min(calc(100vh - 150px), calc(50vh + (var(--pc-w) * 0.466) + 28px)); }
}

/* ── still page (reduced-motion / Save-Data): un-pin, fan the four arches ── */
html.still #prelude { height: auto; }
html.still .pc-pin { position: relative; height: auto; min-height: 100vh; padding: 12vh 6vw; }
html.still .pc-persp, html.still .pc-cue, html.still .pc-cue-wander, html.still .pc-fade, html.still .pc-bridge, html.still .pc-mute { display: none; }
html.still .pc-intro { position: relative; top: auto; margin-bottom: 6vh; }
html.still .pc-stage { position: static; transform: none; display: flex; flex-wrap: wrap; justify-content: center; gap: 28px; }
html.still .pc-arch { position: static; margin: 0; width: min(230px, 42vw); transform: none !important; opacity: 1 !important; filter: none !important; }
html.still .pc-glow { opacity: 0 !important; }
html.still .pc-caption { position: static; margin-top: 5vh; display: block; }
html.still .pc-cap-track { width: auto; height: auto; }
html.still .pc-cap { position: static; opacity: 1 !important; transform: none !important; margin-bottom: 4vh; }

/* ══ REALM HALL ════════════════════════════════════════════════════════════
 * One stationary pinned screen; scroll crossfades four full-bleed rooms
 * (Cozy, Fantasy, Dreamscape, Cyberpunk). Copy and arches swap sides between
 * realms; the dots rail on the right takes the live realm's accent. */
#realm-hall {
  position: relative;
  height: 440vh;
}

.rh-pin {
  position: sticky;
  top: 0;
  height: 100vh;
  overflow: hidden;
  background: var(--bg);
}

.rh-rail {
  position: absolute;
  right: 26px;
  top: 50%;
  transform: translateY(-50%);
  z-index: 10;
  display: flex;
  flex-direction: column;
  gap: 12px;
  align-items: center;
}

.rh-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: rgba(148, 163, 184, 0.35);
  display: block;
  transition: background 500ms ease;
}

.rh-room {
  position: absolute;
  inset: 0;
  overflow: hidden;
  display: flex;
  align-items: center;
  opacity: 0;
  transition: opacity 700ms ease-in-out;
  pointer-events: none;
}

.rh-room[data-realm='cozy'] { --ra: var(--realm-cozy); }
.rh-room[data-realm='fantasy'] { --ra: var(--realm-fantasy); }
.rh-room[data-realm='dreamscape'] { --ra: var(--realm-dreamscape); }
.rh-room[data-realm='cyberpunk'] { --ra: var(--realm-cyberpunk); }

/* Two stacked layers per room (founder 2026-07-22: gate tabs swap the
   background art, not just the door cards). Only .is-active is visible;
   picking a gate crossfades the incoming layer in as the outgoing one fades
   out, in the same 220ms family as the door-card swap (realms.js setGate). */
.rh-room-bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 220ms ease;
}

.rh-room-bg.is-active { opacity: 0.5; }
.rh-room[data-realm='cozy'] .rh-room-bg.is-active { opacity: 0.55; }

.rh-scrim {
  position: absolute;
  inset: 0;
}

/* Vertical fade: solid at the top edge (dissolves into whatever sits above
   the pinned room) mirrored at the bottom edge (dissolves into the next
   section instead of cutting off hard against it), same 25%-of-viewport
   softness on both ends. Sits as a sibling overlay above the .rh-room-bg
   images, so it composites on top of whichever gate background is active
   when a gate tab swaps the art (founder 2026-07-22). */
.rh-scrim--l {
  background:
    linear-gradient(to right, rgba(2, 6, 23, 0.92) 0%, rgba(2, 6, 23, 0.55) 45%, rgba(2, 6, 23, 0.35) 100%),
    linear-gradient(to bottom, #020617 0%, rgba(2, 6, 23, 0) 25%, rgba(2, 6, 23, 0) 75%, #020617 100%);
}

.rh-scrim--r {
  background:
    linear-gradient(to left, rgba(2, 6, 23, 0.92) 0%, rgba(2, 6, 23, 0.55) 45%, rgba(2, 6, 23, 0.35) 100%),
    linear-gradient(to bottom, #020617 0%, rgba(2, 6, 23, 0) 25%, rgba(2, 6, 23, 0) 75%, #020617 100%);
}

.rh-row {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  width: 100%;
  max-width: 1320px;
  margin: 0 auto;
  padding: 40px;
  gap: 48px;
  transform-origin: 50% 50%;
}

.rh-copy {
  max-width: 400px;
}

.rh-copy--right {
  text-align: right;
}

.rh-eyebrow {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 3px;
  color: var(--ra);
}

.rh-name {
  font-family: var(--serif);
  font-size: 76px;
  line-height: 1.02;
  margin-top: 14px;
  color: var(--ra);
}

.rh-tag {
  font-family: var(--whisper);
  font-size: 23px;
  color: var(--accent-bright);
  margin-top: 14px;
}

.rh-desc {
  font-size: 14px;
  color: var(--text-secondary);
  margin-top: 16px;
  line-height: 1.7;
}

.rh-chips {
  display: flex;
  gap: 8px;
  margin-top: 22px;
  flex-wrap: wrap;
}

.rh-copy--right .rh-chips {
  justify-content: flex-end;
}

/* Gate tabs (founder 2026-07-21): were static <span> labels, now clickable
   <button>s (data-gate, wired in realms.js) that swap the 3 door cards. The
   button reset keeps the original span's look; .is-active is the one clear
   selected state (filled, per the founder's ask for "a clear active state"). */
.rh-chip {
  font: inherit;
  font-size: 11px;
  letter-spacing: 1.5px;
  color: var(--ra);
  background: transparent;
  border: 1px solid color-mix(in srgb, var(--ra) 40%, transparent);
  border-radius: 3px;
  padding: 4px 10px;
  cursor: pointer;
  transition: background 220ms ease, color 220ms ease;
}

.rh-chip:hover {
  border-color: var(--ra);
}

.rh-chip.is-active {
  background: var(--ra);
  color: var(--bg);
}

.rh-arches {
  display: flex;
  gap: 30px;
  align-items: flex-end;
}

.rh-door {
  display: block;
  text-decoration: none;
  color: inherit;
}

.rh-door-frame {
  position: relative;
  overflow: hidden;
  box-shadow: 0 24px 60px -16px rgba(0, 0, 0, 0.9);
  transition: transform 300ms ease, opacity 220ms ease;
}

/* Gate-tab swap (founder 2026-07-21): a gentle fade while realms.js rewrites
   the frame's image/caption underneath, in the site's existing 220ms family
   (matches the chip's own hover transition above). */
.rh-door-frame.rh-swap {
  opacity: 0;
}

.rh-door:hover .rh-door-frame {
  transform: translateY(-10px);
}



.rh-door img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.rh-door-name {
  text-align: center;
  margin-top: 12px;
  font-family: var(--serif);
  color: var(--ra);
  /* Fixed two-line reservation (founder 2026-07-22: side doors sat HIGHER on
     gates whose labels wrap - the row bottom-aligns whole cards, so a taller
     wrapped caption pushed its frame up. Reserving the same caption height on
     EVERY card keeps all frames aligned identically, wayfarers included). */
  line-height: 1.25;
  min-height: 2.5em;
}

.rh-door-gate {
  text-align: center;
  font-size: 10px;
  letter-spacing: 2px;
  margin-top: 3px;
  line-height: 1.4;
  min-height: 2.8em;
}

.rh-door--sm .rh-door-frame {
  width: 180px;
  height: 322px;
  border-radius: 90px 90px 14px 14px;
  border: 1px solid rgba(255, 255, 255, 0.14);
}

/* Names/gate labels pinned to the frame's own width (founder 2026-07-22:
   3-door spacing was off on corner-tables/emberside/somnia/wonderwhere but
   fine on wayfarers/neon-city/overcity). Root cause: .rh-door-name/.rh-door-gate
   had no width, so a door with a longer name (e.g. "The Rabbit's Cottage")
   rendered unwrapped wider than its 180/216px frame, and since .rh-door is
   an auto-sized flex item, that overflow widened the WHOLE card, throwing
   off the flex gap to its neighbours. Shorter names (Firefly Caravan,
   Vantage) happened to fit and looked fine by accident. Wrapping to a
   second line at the frame's width keeps every card the same footprint. */
.rh-door--sm .rh-door-name { font-size: 15px; width: 180px; }
.rh-door--sm .rh-door-gate { color: var(--text-muted); width: 180px; }

.rh-door--lg .rh-door-frame {
  width: 216px;
  height: 388px;
  border-radius: 108px 108px 16px 16px;
  border: 1px solid color-mix(in srgb, var(--ra) 50%, transparent);
  box-shadow:
    0 24px 60px -16px rgba(0, 0, 0, 0.9),
    0 0 70px -10px color-mix(in srgb, var(--ra) 45%, transparent);
}

.rh-door--lg .rh-door-name { font-size: 17px; width: 216px; }
.rh-door--lg .rh-door-gate { color: var(--text-secondary); width: 216px; }

/* The one PLAYING chip in the hall (mock: Cozy's centre door). */
.rh-playing {
  position: absolute;
  left: 50%;
  bottom: 18px;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 9px;
  background: rgba(2, 6, 23, 0.78);
  border: 1px solid color-mix(in srgb, var(--ra) 45%, transparent);
  border-radius: 999px;
  padding: 8px 16px 8px 10px;
}

/* At rest the chip is JUST the accent play glyph (founder 2026-07-21, #6:
   "remove the black or blue encompassing circle outline") — no dark pill
   background, no border ring behind it. .rh-playing-play still carries its
   own accent-filled circle; that IS the glyph, not the outline being
   removed. The PLAYING state (background/border restored, bars, label)
   is untouched below. */
.rh-playing:not(.is-playing) {
  gap: 0;
  padding: 0;
  background: none;
  border: none;
}

.rh-playing-play {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: var(--ra);
  color: var(--bg);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 9px;
  padding-left: 2px;
}

.rh-playing-eq {
  /* Hidden at rest (founder 2026-07-21: frozen bars "looks weird"). The chip
     shows just the play glyph until its door is the sounding one, then the
     bars appear already moving. Width collapses so the chip tightens up. */
  display: flex;
  align-items: flex-end;
  gap: 2px;
  height: 14px;
  display: none;
}
.rh-playing.is-playing .rh-playing-eq { display: flex; }

.rh-playing-eq span {
  width: 3px;
  height: 14px;
  background: var(--ra);
  transform-origin: bottom;
  animation: eqbar 0.9s ease-in-out infinite;
  /* Resting state (founder 2026-07-21): the chip rides every door from the
     start as the play affordance, but its bars only move once that door is
     the sounding one (.is-playing). Paused animation keeps the painted bar
     shape rather than collapsing it. */
  animation-play-state: paused;
  display: block;
}

.rh-playing.is-playing .rh-playing-eq span { animation-play-state: running; }
.rh-playing-eq span:nth-child(2) { animation-duration: 1.2s; animation-delay: 0.15s; }
.rh-playing-eq span:nth-child(3) { animation-duration: 0.7s; animation-delay: 0.3s; }
.rh-playing-eq span:nth-child(4) { animation-duration: 1s; animation-delay: 0.45s; }

.rh-playing-label {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 2px;
  color: var(--ra);
}

/* ── Phones: shrink the door groups so nothing overflows the viewport, and
 *    stack copy over arches. The pins clip on scroll, but the still page
 *    (below) makes the sections flow, so width must fit for real there. */
@media (max-width: 700px) {
  .rh-row {
    flex-direction: column;
    padding: 20px;
    gap: 24px;
  }
  .rh-copy,
  .rh-copy--right {
    max-width: none;
    text-align: center;
  }
  .rh-chips,
  .rh-copy--right .rh-chips { justify-content: center; }
  .rh-name { font-size: clamp(40px, 13vw, 60px); }
  .rh-tag { font-size: 19px; }
  .rh-arches { gap: 10px; }
  .rh-door--sm .rh-door-frame { width: 88px; height: 158px; border-radius: 44px 44px 8px 8px; }
  .rh-door--lg .rh-door-frame { width: 104px; height: 187px; border-radius: 52px 52px 9px 9px; }
  /* Same fix as desktop above, at the mobile frame widths (this is where the
     founder's report was worst: 12px type against short 88/104px columns
     overflows unwrapped much more readily than the 15/17px desktop type). */
  .rh-door--sm .rh-door-name,
  .rh-door--lg .rh-door-name { font-size: 12px; }
  .rh-door--sm .rh-door-name, .rh-door--sm .rh-door-gate { width: 88px; }
  .rh-door--lg .rh-door-name, .rh-door--lg .rh-door-gate { width: 104px; }
  .rh-rail { right: 12px; }

  /* The PLAYING chip was sized for the 216px desktop frame and stayed that
     width at the 104px mobile frame, bleeding onto the neighbouring doors
     (founder round-5 #16). Scale it down to fit inside the lg frame. */
  .rh-playing {
    gap: 5px;
    padding: 5px 9px 5px 5px;
    bottom: 10px;
  }
  .rh-playing-play { width: 16px; height: 16px; font-size: 6px; }
  .rh-playing-eq { height: 9px; gap: 1.5px; }
  .rh-playing-eq span { width: 1.5px; height: 9px; }
  .rh-playing-label { font-size: 7px; letter-spacing: 0.5px; }
}

/* ── Still page: reduced-motion + Save-Data visitors (realms.js adds
 *    html.still, and the media query covers no-JS reduced-motion). No pinned
 *    scroll traps: the wrappers collapse to auto height, the sticky inners go
 *    static, the four rooms flow one under another, and every reveal item is
 *    shown. The atmosphere layer is skipped entirely. */
html.still #realm-hall { height: auto; }

html.still .rh-pin {
  position: relative;
  height: auto;
  min-height: 100vh;
  overflow: hidden;
}

html.still .rh-room {
  position: relative;
  opacity: 1;
  pointer-events: auto;
  min-height: 100vh;
  transition: none;
}

html.still .rh-rail { display: none; }

html.still .rh-room-bg { transition: none; }

html.still [data-reveal] {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  #prelude,
  #realm-hall { height: auto; }

  .rh-pin {
    position: relative;
    height: auto;
    min-height: 100vh;
    overflow: hidden;
  }

  /* no-JS reduced-motion fallback for the carousel, mirroring the
     html.still .pc-* rules above (realms.js normally adds html.still
     itself, but this covers the flash before it runs). */
  .pc-pin { position: relative; height: auto; min-height: 100vh; padding: 12vh 6vw; overflow: hidden; }
  .pc-persp,
  .pc-cue,
  .pc-cue-wander,
  .pc-fade,
  .pc-bridge,
  .pc-mute { display: none; }
  .pc-intro { position: relative; top: auto; margin-bottom: 6vh; }
  .pc-stage { position: static; transform: none; display: flex; flex-wrap: wrap; justify-content: center; gap: 28px; }
  .pc-arch { position: static; margin: 0; width: min(230px, 42vw); transform: none !important; opacity: 1 !important; filter: none !important; }
  .pc-glow { opacity: 0 !important; }
  .pc-caption { position: static; margin-top: 5vh; display: block; }
  .pc-cap-track { width: auto; height: auto; }
  .pc-cap { position: static; opacity: 1 !important; transform: none !important; margin-bottom: 4vh; }

  .rh-room {
    position: relative;
    opacity: 1;
    pointer-events: auto;
    min-height: 100vh;
    transition: none;
  }

  .rh-rail { display: none; }

  [data-reveal] {
    opacity: 1;
    transform: none;
    transition: none !important;
  }

  .rh-door-frame { transition: none; }
  .rh-room-bg { transition: none; }

  .rh-playing-eq span { animation: none; transform: scaleY(0.7); }
}

/* ══ WANDERCORD ════════════════════════════════════════════════════════════
 * S4 (2026-07-19): the passport, treated as a hero prop. Closed nebula cover
 * sits centred; scroll rotates it open (rotateY 0 to -176deg about the spine,
 * perspective 1900) while the whole book slides to a centred spread. LEFT page
 * = frontispiece (the cover backface), RIGHT page = Door Visa No 001. Timing +
 * transforms in realms.js. Every measurement lifted from the approved mock.
 * "Wanderer" only, never a real user name (this is a marketing capture). */
/* 480vh (was 360vh, founder 2026-07-22: "an additional page... requires an
   additional scroll"). The extra 120vh is the realm-card beat inserted after
   the spread's dwell and before the cover swings shut (realms.js), the same
   size unit the prelude uses for one beat, so it reads as its own step
   rather than a rushed extra. Existing open/dwell/close/settle timings keep
   their prior absolute-vh pacing; see the wp fraction comments in realms.js. */
#wandercord {
  position: relative;
  height: 600vh;
}

.wc-pin {
  position: sticky;
  top: 0;
  height: 100vh;
  overflow: hidden;
  background: var(--bg);
}

.wc-bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0.16;
  filter: saturate(0.4) brightness(0.7);
}

.wc-scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom, #020617 0%, rgba(2, 6, 23, 0.4) 40%, #020617 100%);
}

.wc-intro {
  position: relative;
  text-align: center;
  padding-top: 5vh;
}

.wc-intro-eyebrow {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--text-muted);
}

.wc-intro-title {
  font-family: var(--serif);
  font-size: 38px;
  margin-top: 10px;
  color: var(--text);
}

.wc-intro-whisper {
  font-family: var(--whisper);
  font-style: italic;
  font-size: 19px;
  color: var(--accent);
  margin-top: 6px;
}

/* The book stage. 810x620 fixed; centred with left:50% + a -405px pull (robust
   when the stage is wider than a narrow viewport, unlike margin:auto). Scaled +
   slid by realms.js from transform-origin 50% 0. */
.wc-stage {
  position: relative;
  left: 50%;
  width: 810px;
  height: 620px;
  margin: 3vh 0 0 -405px;
  perspective: 1900px;
  transform-origin: 50% 0;
}

.wc-spine {
  position: absolute;
  left: 400px;
  top: 0;
  width: 10px;
  height: 620px;
  background: linear-gradient(to right, rgba(2, 6, 23, 0.9), #1a2342, rgba(2, 6, 23, 0.9));
}

/* Right page: the Door Visa, revealed as the cover flips off it. */
.wc-visa {
  position: absolute;
  left: 410px;
  top: 0;
  width: 400px;
  height: 620px;
  border-radius: 4px 14px 14px 4px;
  background: #0d1530;
  background-image:
    repeating-linear-gradient(45deg, rgba(165, 180, 252, 0.05) 0 1px, transparent 1px 14px),
    repeating-linear-gradient(-45deg, rgba(165, 180, 252, 0.05) 0 1px, transparent 1px 14px);
  border: 1px solid rgba(165, 180, 252, 0.22);
  padding: 28px 34px;
}

.wc-visa-head,
.wc-fp-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.wc-visa-no {
  font-size: 12px;
  letter-spacing: 1px;
  color: var(--accent-bright);
}

.wc-visa-label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 4px;
  color: var(--accent-bright);
}

.wc-seal {
  width: 34px;
  height: 34px;
  border: 1.5px dashed rgba(165, 180, 252, 0.55);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.wc-seal-arch {
  width: 11px;
  height: 16px;
  border: 1.5px solid #cbd5e1;
  border-bottom: none;
  border-radius: 6px 6px 0 0;
  display: block;
}

/* Locked arch silhouette: 224x284, crown radius 112 = width/2. */
.wc-visa-archwrap {
  position: relative;
  width: 224px;
  height: 284px;
  margin: 24px auto 0;
}

.wc-visa-art {
  position: absolute;
  inset: 0;
  border-radius: 112px 112px 16px 16px;
  overflow: hidden;
  border: 1px solid rgba(165, 180, 252, 0.35);
  box-shadow: 0 0 40px -8px rgba(165, 180, 252, 0.3);
  display: block;
}

.wc-visa-art img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.wc-stamp-first {
  position: absolute;
  right: -32px;
  top: 0;
  border: 2px dashed rgba(248, 113, 113, 0.85);
  border-radius: 6px;
  transform: rotate(6deg);
  padding: 6px 11px;
  text-align: center;
  background: rgba(2, 6, 23, 0.45);
}

.wc-stamp-first-l1 {
  display: block;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 3px;
  color: #f87171;
}

.wc-stamp-first-l2 {
  display: block;
  font-size: 6.5px;
  font-weight: 700;
  letter-spacing: 2px;
  color: #f87171;
  margin-top: 3px;
}

.wc-stamp-arrived {
  position: absolute;
  left: -22px;
  bottom: 20px;
  width: 72px;
  height: 72px;
  border: 1.5px dashed rgba(226, 232, 240, 0.85);
  border-radius: 50%;
  transform: rotate(-8deg);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-size: 7.5px;
  font-weight: 700;
  letter-spacing: 1.5px;
  color: var(--text);
  text-align: center;
  background: rgba(2, 6, 23, 0.45);
}

.wc-visa-caption {
  text-align: center;
  margin-top: 22px;
}

.wc-visa-realm {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 3px;
  color: var(--text-secondary);
}

.wc-visa-door {
  font-family: var(--serif);
  font-size: 26px;
  margin-top: 6px;
  color: var(--text);
}

.wc-ledger {
  margin-top: 18px;
  display: flex;
  flex-direction: column;
  gap: 9px;
}

.wc-ledger-row {
  display: flex;
  align-items: baseline;
  gap: 10px;
}

.wc-ledger-row--tally {
  align-items: center;
}

.wc-ledger-key {
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 2px;
  color: var(--text-muted);
}

.wc-ledger-dash {
  width: 26px;
  border-bottom: 1px solid rgba(148, 163, 184, 0.4);
}

.wc-ledger-fill {
  flex: 1;
  border-bottom: 1px solid rgba(148, 163, 184, 0.4);
}

.wc-ledger-val {
  font-family: var(--whisper);
  font-size: 16px;
  color: var(--text);
}

.wc-ledger-val--right {
  flex: 1;
  text-align: right;
}

.wc-tally {
  display: flex;
  gap: 5px;
}

.wc-tally span {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: rgba(148, 163, 184, 0.35);
  display: block;
}

.wc-tally .wc-tally-on {
  background: var(--text);
}

/* Punched-holes column (founder 2026-07-22 round 2: "the hole punches on the
   left side are missing" vs the app's WandercordPage frame, which puts an
   8-hole column at its plate's binding edge — 9px holes, ~left:17,
   border rgba(232,235,248,0.35) over art). The site's book is a real
   two-page spread (the app is single-page), so the binding edge mirrors per
   side: right-hand pages (wc-visa, wc-rc-front) get holes on THEIR left
   (nearest the spine); left-hand pages (wc-cover-back, wc-rc-back) get them
   on THEIR right (also nearest the spine). Kept clear of the ARRIVED seal
   (bottom:20, 72px tall) with a generous bottom inset. */
.wc-holes {
  position: absolute;
  top: 60px;
  bottom: 110px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: center;
  pointer-events: none;
}

.wc-holes--left {
  left: 14px;
}

.wc-holes--right {
  right: 14px;
}

.wc-hole {
  width: 9px;
  height: 9px;
  border-radius: 4.5px;
  background: #03050f;
  border: 1px solid rgba(232, 235, 248, 0.35);
  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.8);
  flex: none;
}

.wc-page-foot {
  position: absolute;
  left: 34px;
  right: 34px;
  bottom: 16px;
  display: flex;
  justify-content: space-between;
  font-size: 8px;
  letter-spacing: 2px;
  color: var(--text-muted);
}

.wc-page-foot-r {
  color: var(--text-secondary);
}

/* The realm-card page (founder 2026-07-22 passport-flip round): a second
   book leaf sitting in the same slot as .wc-visa (right page), directly
   above it. It shows first (its front, a full-bleed portrait "plate" behind
   top/bottom scrims, mirroring the app's Full Plate WandercordRealmPage
   layout); realms.js then rotates it -176deg on its own scroll beat, same
   rotateY idiom as .wc-cover, so its front swings away to reveal the Door
   Visa underneath while its back (.wc-rc-back) settles over the
   frontispiece. transform-style + perspective inherited from .wc-stage. */
.wc-realmcard {
  position: absolute;
  left: 410px;
  top: 0;
  width: 400px;
  height: 620px;
  transform-origin: left center;
  transform-style: preserve-3d;
  z-index: 3;
  will-change: transform;
}

.wc-rc-front,
.wc-rc-back {
  position: absolute;
  inset: 0;
  backface-visibility: hidden;
}

.wc-rc-front {
  border-radius: 4px 14px 14px 4px;
  overflow: hidden;
  border: 1px solid rgba(165, 180, 252, 0.22);
  background: #0d1530;
  padding: 28px 30px;
  display: flex;
  flex-direction: column;
}

/* Pre-rotated 180 so it reads upright once the leaf has turned, same trick
   as .wc-cover-back. Carries the Moonlit Garden Door Visa (round 2, founder
   2026-07-22): reuses the SAME .wc-visa-* classes wc-visa itself uses below,
   just with left-page rounding + padding instead of right-page. */
.wc-rc-back {
  position: relative;
  transform: rotateY(180deg);
  border-radius: 22px 6px 6px 22px;
  background: #0d1530;
  background-image:
    repeating-linear-gradient(45deg, rgba(165, 180, 252, 0.05) 0 1px, transparent 1px 14px),
    repeating-linear-gradient(-45deg, rgba(165, 180, 252, 0.05) 0 1px, transparent 1px 14px);
  border: 1px solid rgba(165, 180, 252, 0.22);
  padding: 28px 34px;
}

.wc-rc-art {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.wc-rc-scrim-top {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: 46%;
  background: linear-gradient(to bottom, rgba(2, 6, 23, 0.88) 0%, rgba(2, 6, 23, 0) 100%);
}

.wc-rc-scrim-bottom {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 54%;
  background: linear-gradient(to top, rgba(2, 6, 23, 0.92) 0%, rgba(2, 6, 23, 0) 100%);
}

/* Ghost guilloché weave over the realm card's full-plate art, matching the
   app's plateArt pages (weave ghosts to 0.03 alpha over a painting, from
   0.045 on a plain plate — WandercordPage.tsx). */
.wc-rc-weave {
  position: absolute;
  inset: 0;
  background-image:
    repeating-linear-gradient(45deg, rgba(232, 235, 248, 0.035) 0 1px, transparent 1px 14px),
    repeating-linear-gradient(-45deg, rgba(232, 235, 248, 0.035) 0 1px, transparent 1px 14px);
}

.wc-rc-topgroup {
  position: relative;
  text-align: center;
}

.wc-rc-eyebrow {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 3px;
  color: var(--accent-bright);
  text-shadow: 0 1px 5px rgba(0, 0, 0, 0.85);
}

.wc-rc-title {
  font-family: var(--serif);
  font-size: 27px;
  margin-top: 8px;
  color: var(--text);
  text-shadow: 0 2px 10px rgba(0, 0, 0, 0.85);
}

.wc-rc-block {
  position: relative;
  margin-top: auto;
}

.wc-rc-stamps {
  position: absolute;
  right: 0;
  top: -46px;
  display: flex;
}

.wc-rc-stamp {
  width: 58px;
  height: 58px;
  border-radius: 50%;
  border: 1.5px dashed rgba(165, 180, 252, 0.6);
  background: rgba(2, 6, 23, 0.55);
  display: flex;
  align-items: center;
  justify-content: center;
}

.wc-rc-stamp--gate {
  margin-right: -14px;
  transform: rotate(8deg);
}

.wc-rc-stamp--realm {
  transform: rotate(-9deg);
}

.wc-rc-stamp-inner {
  width: 48px;
  height: 48px;
  border-radius: 50%;
  border: 1px solid rgba(165, 180, 252, 0.4);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1px;
}

.wc-rc-stamp-word {
  font-size: 5.5px;
  font-weight: 700;
  letter-spacing: 1.4px;
  color: rgba(226, 232, 240, 0.95);
}

.wc-rc-realm {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 2.6px;
  color: rgba(255, 255, 255, 0.95);
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.9);
}

.wc-rc-gate {
  font-family: var(--serif);
  font-size: 21px;
  margin-top: 4px;
  color: var(--accent-bright);
  text-shadow: 0 1px 6px rgba(0, 0, 0, 0.9);
}

.wc-rc-gate-desc {
  font-family: var(--whisper);
  font-style: italic;
  font-size: 14px;
  line-height: 1.35;
  color: rgba(226, 232, 240, 0.9);
  margin-top: 3px;
  max-width: 280px;
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.9);
}

.wc-rc-caption {
  font-family: var(--whisper);
  font-style: italic;
  font-size: 13px;
  color: var(--text-secondary);
  margin-top: 10px;
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.9);
}

.wc-rc-divider {
  position: relative;
  height: 1px;
  margin-top: 14px;
  background: rgba(165, 180, 252, 0.25);
}

.wc-realmcard .wc-page-foot {
  position: relative;
  left: 0;
  right: 0;
  bottom: 0;
  margin-top: 11px;
}

/* The cover: front = nebula cover, back = frontispiece. Flips about its left
   edge (the spine). */
.wc-cover {
  position: absolute;
  left: 405px;
  top: -8px;
  width: 412px;
  height: 636px;
  transform-origin: left center;
  transform-style: preserve-3d;
  z-index: 5;
  will-change: transform;
}

.wc-cover-front,
.wc-cover-back {
  position: absolute;
  inset: 0;
  backface-visibility: hidden;
}

.wc-cover-front {
  border-radius: 6px 22px 22px 6px;
  overflow: hidden;
  border: 1px solid rgba(165, 180, 252, 0.35);
  box-shadow: 0 40px 90px -25px rgba(0, 0, 0, 0.95), 0 0 70px -20px rgba(165, 180, 252, 0.25);
}

.wc-cf-art {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 62% 50%;
}

.wc-cf-wash {
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom, rgba(13, 21, 48, 0.55) 0%, rgba(13, 21, 48, 0.2) 45%, rgba(13, 21, 48, 0.6) 100%);
  display: block;
}

.wc-cf-hatch {
  position: absolute;
  inset: 0;
  background-image:
    repeating-linear-gradient(45deg, rgba(165, 180, 252, 0.05) 0 1px, transparent 1px 14px),
    repeating-linear-gradient(-45deg, rgba(165, 180, 252, 0.05) 0 1px, transparent 1px 14px);
  display: block;
}

.wc-cf-sojourn {
  position: absolute;
  left: 0;
  right: 0;
  top: 70px;
  text-align: center;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 6px;
  color: var(--accent-bright);
}

.wc-cf-seal {
  position: absolute;
  left: 50%;
  top: 124px;
  transform: translateX(-50%);
  width: 112px;
  height: 112px;
  border: 1.5px dashed rgba(203, 213, 225, 0.55);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.wc-cf-seal-inner {
  width: 88px;
  height: 88px;
  border: 1px solid rgba(203, 213, 225, 0.3);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.wc-cf-seal-arch {
  width: 26px;
  height: 40px;
  border: 2px solid #cbd5e1;
  border-bottom: none;
  border-radius: 13px 13px 0 0;
  display: block;
}

.wc-cf-title {
  position: absolute;
  left: 0;
  right: 0;
  top: 280px;
  text-align: center;
  font-family: var(--serif);
  font-size: 36px;
  letter-spacing: 10px;
  color: var(--text);
  text-indent: 10px;
}

.wc-cf-pill {
  position: absolute;
  left: 50%;
  top: 346px;
  transform: translateX(-50%);
  border: 1px solid rgba(226, 232, 240, 0.4);
  border-radius: 999px;
  padding: 4px 16px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 1px;
  color: var(--accent-bright);
  background: rgba(2, 6, 23, 0.3);
}

.wc-cf-year {
  position: absolute;
  left: 0;
  right: 0;
  top: 392px;
  text-align: center;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 4px;
  color: var(--text-secondary);
}

.wc-cf-name {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 66px;
  text-align: center;
  font-family: var(--whisper);
  font-style: italic;
  font-size: 26px;
  color: #cbd5e1;
}

.wc-cf-issued {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 34px;
  text-align: center;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 3px;
  color: var(--text-secondary);
}

/* Frontispiece = the cover backface, pre-rotated 180 so it reads upright once
   the cover swings open. */
.wc-cover-back {
  transform: rotateY(180deg);
  border-radius: 22px 6px 6px 22px;
  background: #0d1530;
  background-image:
    repeating-linear-gradient(45deg, rgba(165, 180, 252, 0.05) 0 1px, transparent 1px 14px),
    repeating-linear-gradient(-45deg, rgba(165, 180, 252, 0.05) 0 1px, transparent 1px 14px);
  border: 1px solid rgba(165, 180, 252, 0.22);
  padding: 32px 36px;
}

.wc-fp-title {
  font-family: var(--serif);
  font-size: 24px;
  text-align: center;
  margin-top: 20px;
  color: var(--text);
}

.wc-accent {
  color: var(--accent);
}

/* Locked arch silhouette: 126x146, crown radius 63 = width/2, no feet. */
.wc-fp-archwrap {
  position: relative;
  width: 126px;
  height: 146px;
  margin: 28px auto 0;
}

.wc-fp-arch {
  position: absolute;
  inset: 0;
  border: 1.5px solid rgba(196, 207, 255, 0.9);
  border-bottom: none;
  border-radius: 63px 63px 0 0;
  box-shadow: 0 0 34px -4px rgba(165, 180, 252, 0.55), inset 0 0 26px -8px rgba(165, 180, 252, 0.35);
  display: block;
}

.wc-fp-arch-base {
  position: absolute;
  left: -16px;
  bottom: 0;
  width: 158px;
  height: 1px;
  background: linear-gradient(to right, transparent, rgba(165, 180, 252, 0.7), transparent);
  display: block;
}

.wc-fp-stamp {
  position: absolute;
  right: -52px;
  top: -14px;
  width: 66px;
  height: 66px;
  border: 1.5px dashed rgba(226, 232, 240, 0.75);
  border-radius: 50%;
  transform: rotate(12deg);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-size: 7.5px;
  font-weight: 700;
  letter-spacing: 1.5px;
  color: var(--accent-bright);
  text-align: center;
  background: rgba(2, 6, 23, 0.5);
}

.wc-fp-arrived {
  text-align: center;
  margin-top: 26px;
}

.wc-fp-arrived-eyebrow {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 3px;
  color: var(--accent);
}

.wc-fp-welcome {
  font-family: var(--serif);
  font-size: 26px;
  margin-top: 8px;
  line-height: 1.25;
  color: var(--text);
}

.wc-fp-welcome-em {
  font-style: italic;
  color: var(--lavender);
}

.wc-fp-blurb {
  font-family: var(--whisper);
  font-style: italic;
  font-size: 14px;
  color: var(--text-secondary);
  margin-top: 10px;
  line-height: 1.5;
}

.wc-fp-ledger {
  margin-top: 22px;
}

.wc-fp-ledger .wc-ledger-val {
  font-size: 15px;
}

.wc-fp-ledger .wc-ledger-val--sign {
  font-size: 17px;
  font-style: italic;
}

.wc-cover-back .wc-page-foot {
  left: 36px;
  right: 36px;
  bottom: 18px;
}

.wc-hint {
  position: absolute;
  left: 50%;
  bottom: 22px;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  color: var(--text-secondary);
  font-size: 10px;
  letter-spacing: 2px;
  text-transform: uppercase;
  transition: opacity 500ms ease;
}

.wc-hint-line {
  display: block;
  width: 1px;
  height: 28px;
  background: linear-gradient(to bottom, rgba(226, 232, 240, 0), var(--accent));
  animation: cue 2.6s ease-in-out infinite;
  transform-origin: top center;
}

/* ══ GALLERIA ══════════════════════════════════════════════════════════════
 * Sanctuary wall backdrop; four gold museum-hang shelves with brass plates
 * that hang in one by one on scroll-down and un-hang on scroll-up (realms.js:
 * threshold p >= 0.1 + i*0.2, 600ms, scrub-reversible). */
#galleria {
  position: relative;
  height: 320vh;
}

.g-pin {
  position: sticky;
  top: 0;
  height: 100vh;
  overflow: hidden;
}

.g-bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0.85;
}

.g-scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom, #020617 0%, rgba(2, 6, 23, 0.55) 30%, rgba(2, 6, 23, 0.65) 100%);
}

.g-stage {
  position: relative;
  transform-origin: 50% 0;
}

.g-intro {
  position: relative;
  text-align: center;
  padding-top: 36px;
}

/* Matches .wc-intro-title's size/family exactly (founder 2026-07-22: "YOUR
   GALLERIA text on website too small make it same size as the wandercord
   text") — same serif heading treatment as the Wandercord section's own
   opener, not the small-caps label it used to be. */
.g-intro-eyebrow {
  font-family: var(--serif);
  font-size: 38px;
  color: var(--text);
}

.g-intro-title {
  font-family: var(--serif);
  font-size: 48px;
  margin-top: 4px;
  color: var(--text);
}

.g-intro-whisper {
  font-family: var(--whisper);
  font-style: italic;
  font-size: 21px;
  color: var(--lavender);
  margin-top: 10px;
}

.g-shelves {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 38px;
  margin-top: 44px;
}

.g-shelf {
  opacity: 0;
  transform: translateY(44px);
  transition: opacity 600ms ease, transform 600ms cubic-bezier(0.16, 1, 0.3, 1);
  width: 560px;
}

.g-shelf:not(:first-child) {
  transition:
    opacity 600ms ease 80ms,
    transform 600ms cubic-bezier(0.16, 1, 0.3, 1) 80ms;
}

.g-shelf-art {
  height: 120px;
  border: 6px solid #8a6d3b;
  border-image: linear-gradient(135deg, #a9884e, #6d5428, #c9a86a, #7a5f30) 1;
  box-shadow: 0 18px 44px -12px rgba(0, 0, 0, 0.85), inset 0 0 24px rgba(0, 0, 0, 0.6);
  overflow: hidden;
}

.g-shelf-art img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.g-shelf-plate {
  display: flex;
  justify-content: center;
  margin-top: -14px;
  position: relative;
}

.g-plate {
  background: linear-gradient(to bottom, #e8d5a8, #c9a86a);
  color: #3a2d14;
  font-family: var(--serif);
  font-size: 15px;
  padding: 5px 22px;
  border-radius: 3px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.6);
}

.g-plate-sub {
  font-family: var(--sans);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 2px;
}

/* ══ CLOSING ═══════════════════════════════════════════════════════════════
 * Cosmos, a glowing door outline, the keep-the-doors copy, the STEP THROUGH
 * pill into the REAL app (/app/), and store-badge placeholders. Not pinned:
 * a normal full-height panel. The site footer below carries the real legal
 * links. Reveal items rise + fade via the shared IntersectionObserver. */
#closing {
  position: relative;
  min-height: 100vh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.cl-bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0.35;
  filter: saturate(0.4) brightness(0.7);
}

/* ADDENDUM-2 §3: FLAT dim (rgba 0.4), never a radial vignette. */
.cl-scrim {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(rgba(2, 6, 23, 0.4), rgba(2, 6, 23, 0.4)),
    linear-gradient(to bottom, #020617 0%, rgba(2, 6, 23, 0) 30%, rgba(2, 6, 23, 0.55) 75%, #020617 100%);
}

.cl-inner {
  position: relative;
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 90px 24px 40px;
}

/* Glowing door outline: locked silhouette, crown radius 37 = width/2. */
.cl-door {
  position: relative;
  width: 74px;
  height: 130px;
  border: 1.5px solid rgba(165, 180, 252, 0.6);
  border-bottom: none;
  border-radius: 37px 37px 0 0;
  box-shadow: 0 0 50px -8px rgba(165, 180, 252, 0.5), inset 0 0 30px -10px rgba(165, 180, 252, 0.35);
}

.cl-door-base {
  position: absolute;
  left: 50%;
  bottom: -1px;
  transform: translateX(-50%);
  width: 130px;
  height: 1px;
  background: linear-gradient(to right, transparent, rgba(165, 180, 252, 0.6), transparent);
  display: block;
}

.cl-title {
  font-family: var(--serif);
  font-size: clamp(32px, 4.4vw, 46px);
  line-height: 1.2;
  max-width: 18ch;
  margin-top: 44px;
  color: var(--text);
}

.cl-whisper {
  font-family: var(--whisper);
  font-style: italic;
  font-size: 21px;
  color: var(--accent);
  margin-top: 14px;
}

.cl-cta {
  display: inline-block;
  margin-top: 36px;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 3px;
  color: var(--bg);
  background: var(--accent-bright);
  border-radius: 999px;
  padding: 16px 44px;
  box-shadow: 0 10px 44px rgba(165, 180, 252, 0.25);
  transition: background 300ms ease;
}

/* Keep the pill legible: the global a:hover would recolour the text to the
   same near-white as the pill. */
.cl-cta:hover {
  color: var(--bg);
  background: #fff;
}

.cl-cta-sub {
  font-size: 13px;
  color: var(--text-secondary);
  margin-top: 14px;
}

/* Waitlist block (2026-07-23): the "Coming soon" line + the email form.
   Form/input/button styles are shared with the footer repeat (base.css .wl-*);
   here only the closing-scene placement. */
.cl-wait {
  margin-top: 48px;
}

.cl-wait-line {
  font-family: var(--whisper);
  font-style: italic;
  font-size: 20px;
  color: var(--text-secondary);
  margin-bottom: 18px;
}

/* The early-keepsake hook beneath the join button (founder 2026-07-24). */
.cl-wait-sub {
  font-family: var(--whisper);
  font-style: italic;
  font-size: 15px;
  line-height: 1.5;
  color: var(--accent-gold, #c9a86a);
  margin-top: 16px;
  max-width: 34ch;
  margin-left: auto;
  margin-right: auto;
}

.cl-badges-wrap {
  margin-top: 52px;
}

.cl-badges-eyebrow {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 3px;
  color: var(--text-secondary);
}

.cl-badges {
  display: flex;
  gap: 16px;
  justify-content: center;
  margin-top: 18px;
  flex-wrap: wrap;
}

.cl-badge {
  display: flex;
  align-items: center;
  gap: 12px;
  border: 1px solid rgba(226, 232, 240, 0.35);
  border-radius: 12px;
  padding: 10px 22px;
  background: rgba(2, 6, 23, 0.6);
  color: var(--accent-bright);
  cursor: default;
  transition: border-color 300ms ease;
}

.cl-badge:hover {
  border-color: var(--accent-bright);
}

.cl-badge svg {
  fill: currentColor;
  flex-shrink: 0;
}

.cl-badge-text {
  text-align: left;
  display: flex;
  flex-direction: column;
}

.cl-badge-sm {
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 1.5px;
  color: var(--text-secondary);
}

.cl-badge-lg {
  font-size: 16px;
  font-weight: 500;
  color: var(--text);
}

/* ── Phones: fit the fixed-width props to narrow viewports (house rule: no
 *    horizontal scroll). The Wandercord stage is width-scaled in realms.js;
 *    here we shrink the Galleria shelves (the g-stage is full width, so the
 *    560px shelves must come down by CSS) and the type. */
@media (max-width: 700px) {
  .wc-intro-title { font-size: 26px; }
  .wc-intro-whisper { font-size: 16px; }

  .g-intro-eyebrow { font-size: 26px; }
  .g-intro-title { font-size: clamp(30px, 9vw, 48px); }
  .g-intro-whisper { font-size: 18px; }
  .g-shelf { width: 88vw; }
  .g-shelf-art { height: 88px; }
  .g-plate { font-size: 13px; padding: 5px 16px; }

  .cl-whisper { font-size: 18px; }
  .cl-badges { gap: 10px; }
  .cl-badge { padding: 9px 16px; }
  .cl-wait-line { font-size: 17px; }
}

/* ── Still page (reduced-motion / Save-Data): un-pin the new sections, show the
 *    Wandercord open (both pages readable) and every Galleria shelf hung.
 *    realms.js sets the open/scaled transforms in its still branch; these are
 *    the CSS backstops (and cover the no-JS reduced-motion case). */
html.still #wandercord,
html.still #galleria {
  height: auto;
}

html.still .wc-pin,
html.still .g-pin {
  position: relative;
  height: auto;
  min-height: 100vh;
  overflow: hidden;
}

html.still .wc-hint {
  display: none;
}

html.still .g-shelf {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  #wandercord,
  #galleria {
    height: auto;
  }

  .wc-pin,
  .g-pin {
    position: relative;
    height: auto;
    min-height: 100vh;
    overflow: hidden;
  }

  .wc-cover,
  .wc-realmcard {
    transform: rotateY(-176deg);
  }

  .wc-hint {
    display: none;
  }

  .g-shelf {
    opacity: 1;
    transform: none;
  }

  .wc-cover,
  .wc-realmcard,
  .wc-stage,
  .g-shelf {
    transition: none;
  }
}
