/* Anand & Palak — palace-journey (scroll-scrubbed) layout + portal + veil.
 *
 * Two worlds, switched by the `.journey-mode` class that journey.js adds to <html>
 * synchronously at script-eval time (only when GSAP + ScrollTrigger loaded and motion
 * is allowed):
 *   • fallback (no .journey-mode)  → .journey / .journey__pin / .scene are inert
 *     pass-through blocks; the page is the original stacked-sections + CSS snap layout.
 *   • journey mode (.journey-mode) → .journey is a tall runway, .journey__pin is pinned
 *     to one viewport, the three .scene layers stack absolutely and GSAP scrubs between
 *     them. journey.js tweens ONLY .jny / scene / stage / portal / veil — never .plx,
 *     .enter or img (those belong to parallax, entrance/doors and ambient).
 *
 * The .jny channel geometry itself lives in styles.css (.plx > .jny). */

/* ---- Portal: "the hall beyond the doors" ------------------------------- *
 * Sits inside slide 1's stage, after the base (z 0) and before the doors (z 1&2).
 * Equal z-index to the base but later in the DOM, so it paints above the base and
 * below the closed doors — which fully cover it until they swing open. Geometry is
 * the door aperture in canvas %. It reads dim at rest; the journey scrub brightens it
 * (opacity only — NEVER animated blur, a mobile-compositing killer) as we push
 * "through" the doorway. */
.portal {
  position: absolute;
  left: 37.96%;
  top: 43.85%;
  width: 24.26%;
  height: 25.83%;
  z-index: 0;
  overflow: hidden;
  border-radius: 50% 50% 0 0 / 38% 38% 0 0; /* arch top */
  /* Rest look: the hall glimpsed through the seam — dimmed (opacity, not filter). */
  opacity: 0.6;
  pointer-events: none;
  -webkit-user-select: none;
  user-select: none;
}
.portal img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 20%;
}

/* ---- Day-to-night veil (injected by journey.js into slide 2's stage) --- *
 * Deep navy-black radial that the scrub fades up as the couple scene turns to dusk,
 * carrying the eye into the night palace. journey.js animates its opacity 0 → ~0.55. */
.journey-veil {
  position: absolute;
  inset: 0;
  z-index: 30;
  opacity: 0;
  pointer-events: none;
  background:
    radial-gradient(120% 90% at 50% 42%,
      rgba(8, 10, 24, 0) 0%,
      rgba(7, 9, 22, 0.35) 46%,
      rgba(4, 6, 16, 0.85) 78%,
      rgba(2, 3, 10, 0.96) 100%);
}

/* ---- "Tap to continue" cue (journey-level; injected into .journey__pin) ------- *
 * ONE reusable cue that guides the guest to TAP to advance to the next scene.
 * Appended to .journey__pin, NOT a .scene stage, so the timeline's scale/opacity
 * tweens never distort or fade it.
 *
 * Fixed to the BOTTOM-CENTRE of the viewport. z-index 45 sits BELOW the music toggle
 * (z 50); horizontal centring keeps it clear of the bottom-right music button. Show /
 * hide is driven from journey.js onProgress via `.is-visible`: shown only when settled
 * on the courtyard (0.02) or couple (0.53) holds, hidden while transitioning, during a
 * nav tween, and on the night hold (0.97 — no next scene). A downward chevron gently
 * bounces (transform/opacity only) as a directional hint. */
.journey-mode .journey-scrollcue {
  position: fixed;
  left: 50%;
  bottom: max(1.1rem, env(safe-area-inset-bottom));
  transform: translateX(-50%) translateY(8px);
  z-index: 45;                  /* below the music toggle (z 50) */
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 0.35em;
  padding: 0.55em 1.2em 0.5em;
  border-radius: 999px;
  background: linear-gradient(180deg, rgba(30, 16, 6, 0.36), rgba(20, 10, 4, 0.54));
  box-shadow: 0 2px 18px rgba(0, 0, 0, 0.38), inset 0 0 0 1px rgba(201, 164, 90, 0.42);
  cursor: pointer;
  opacity: 0;
  pointer-events: none;        /* inert until shown (.is-visible below) */
  -webkit-tap-highlight-color: transparent;
  -webkit-user-select: none;
  user-select: none;
  transition: opacity 480ms ease, transform 480ms ease;
}
.journey-scrollcue__label {
  font-family: "Cormorant Garamond", Georgia, "Times New Roman", serif;
  font-size: clamp(11px, 2.7vw, 15px);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: #ffe9bd;
  white-space: nowrap;
  text-shadow: 0 1px 6px rgba(0, 0, 0, 0.55);
}
/* Small downward chevron drawn from two gold strokes (no glyph font dependency).
   Wrapped so the base rotate(45deg) composes with the bounce translate below. */
.journey-scrollcue__chevron {
  width: 0.86em;
  height: 0.86em;
  border-right: 2px solid var(--gold, #c9a45a);
  border-bottom: 2px solid var(--gold, #c9a45a);
  transform: rotate(45deg);
  margin-top: -0.1em;
}

/* Shown state: journey.js adds .is-visible when settled on a non-last hold. Re-enables
   pointer events for the tap-advance; starts the chevron bounce. */
.journey-mode .journey-scrollcue.is-visible {
  opacity: 0.96;
  transform: translateX(-50%) translateY(0);
  pointer-events: auto;
}
.journey-mode .journey-scrollcue.is-visible .journey-scrollcue__chevron {
  animation: journey-scrollcue-bounce 1.5s ease-in-out infinite;
}

.journey-scrollcue:focus-visible {
  outline: 2px solid var(--focus, #ffd27a);
  outline-offset: 4px;
}

/* Downward nudge — GPU only (transform + opacity), composed with the base 45° rotate. */
@keyframes journey-scrollcue-bounce {
  0%, 100% { transform: rotate(45deg) translate(0, 0); opacity: 0.9; }
  50%      { transform: rotate(45deg) translate(3px, 3px); opacity: 1; }
}

/* Reduced motion: static chevron (no bounce), still a clear labelled prompt. (Journey
   mode does not run under reduced motion, so this won't normally render there — this
   guards the bounce regardless, per the motion rules.) */
@media (prefers-reduced-motion: reduce) {
  .journey-mode .journey-scrollcue.is-visible .journey-scrollcue__chevron {
    animation: none;
  }
}

/* ---- TAP-ONLY navigation: block manual scroll ----------------------------- *
 * The 400svh runway remains programmatically scrollable (journey:goto dispatches
 * st.scroll()) but the user cannot scroll it with touch, wheel, or scrollbar drag.
 * JS blocks wheel/touchmove/scroll-keys; CSS hides the scrollbar and disables
 * touch-scroll gestures on the journey container. */
.journey-mode {
  scrollbar-width: none;
  -ms-overflow-style: none;
  overscroll-behavior: none;
}
.journey-mode::-webkit-scrollbar { display: none; }

/* =======================================================================
 * JOURNEY MODE — pinned runway + stacked scenes
 * ======================================================================= */
.journey-mode .journey {
  position: relative;
  width: 100%;
  height: 400svh;          /* runway length; ScrollTrigger end is derived from the pin */
  touch-action: none;      /* prevent touch-scroll gestures; taps still work */
}

.journey-mode .journey__pin {
  position: relative;
  height: 100svh;
  overflow: hidden;
}

/* Scenes stack; each keeps its own flex centering of the .stage from styles.css. */
.journey-mode .scene {
  position: absolute;
  inset: 0;
  min-height: 0;           /* override the fallback 100svh min-height */
  width: 100%;
  height: 100svh;
  will-change: opacity;
}

/* GSAP sets scene opacity inline; scenes 2 & 3 start hidden so a mid-load paint
   (before the timeline sets values) doesn't flash them over scene 1. */
.journey-mode .scene--2,
.journey-mode .scene--3 { opacity: 0; }

/* The stage is the unit the journey scales ("through the door" / "arriving"),
   so hint the compositor and give scene-1 doors a perspective for the .jny rotateY. */
.journey-mode .scene .stage { will-change: transform, opacity; }
.journey-mode .scene--1 .plx[data-hero^="door"] { perspective: 900px; }

/* Stacked scenes: an invisible upper scene (opacity:0) still captures taps, which
   would swallow taps meant for the visible scene below (e.g. the slide-1 door
   button). Only the active scene is interactive. The descendant `*` is required
   because interactions.js sets pointer-events:auto on tappable light heroes (.plx),
   and an explicit auto on a child re-enables it even under a none parent — so the
   whole inactive subtree must be forced inert. */
.journey-mode .scene:not(.is-active),
.journey-mode .scene:not(.is-active) * { pointer-events: none; }

/* Perf: pause a scene's ambient particle loops while it is not the active scene. */
.journey-mode .scene:not(.is-active) :is(.amb-petal, .amb-firefly, .amb-shootingstar, .sparkle) {
  animation-play-state: paused;
}

/* Perf: also pause continuous ambient HERO keyframes (glow/flicker/sway run `filter`
   animations on every hero, visible or not) on the inactive scene. Journey mode only;
   the fallback stacked layout is unaffected. */
.journey-mode .scene:not(.is-active) img.ly.hero { animation-play-state: paused; }

/* Perf: on touch devices the .plx will-change hint is pure compositing cost —
   scroll-parallax is disabled in journey mode and pointer-parallax needs a fine
   pointer. (Override lives here; interactions.css is untouched.) */
@media (pointer: coarse) {
  .journey-mode .plx { will-change: auto; }
}

/* Reduced motion never enters journey mode (journey.js bails), so no extra guard
   is needed here — the page stays in the fallback stacked layout. */
