/* ═══════════════════════════════════════════════════════════════════════════
   TOUR ATMOSPHERE

   Two background effects from the Effects Library, placed in the tour and
   driven by scroll position rather than left to run on their own clock.

     .tour-fx-aurora   one fixed field of light behind the whole experience
     .tour-fx-waves    a swelling horizon under the closing scene

   ── Nothing here is animated by JavaScript ────────────────────────────────

   tour-fx.js writes custom properties and nothing else, the same contract the
   stage atmosphere in tour.css already uses. Scroll position becomes a number,
   the number becomes paint. No transform is touched, so nothing can contend
   with a property a GSAP timeline owns, and every value reverses for free
   because it is derived from progress rather than played.

   ── Why the aurora only appears halfway in ────────────────────────────────

   It is not hidden deliberately at the start — it is COVERED. The welcome,
   the globe and the type scene all paint opaque backgrounds, because each is
   a sticky scene that would show the page sliding underneath if it did not.
   The chapter sections do not. So light arrives exactly when the product
   does, which is the right beat for it, and no existing scene had to be
   restyled to get that.

   ── Default state is invisible ────────────────────────────────────────────

   --fx-au-op is 0 until the script sets it. If tour-fx.js never runs, or
   ScrollTrigger is missing, the tour renders exactly as it does today. This
   is decoration: absent is the correct failure, and the opposite default
   would drop a full-strength aurora over the dark opening.
   ═══════════════════════════════════════════════════════════════════════════ */


/* ─── The fixed layer ─────────────────────────────────────────────────────── */
/* Positioned, z-index 0, and first in the document — so every section after it
   paints above it without any of them needing a z-index of their own. */

.tour-fx {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;

  /* Driven by tour-fx.js. */
  --fx-au-op: 0;        /* 0 → 1  strength                                  */
  --fx-au-swell: 1;     /* local multiplier, for scenes that want a bloom   */
  --fx-au-shift: 0%;    /* phase between the two gradient layers            */
  --fx-au-mx: 100%;     /* where the light is coming from, horizontally     */
  --fx-au-my: 0%;       /* and vertically                                   */
}


/* ─── Aurora ──────────────────────────────────────────────────────────────── */

.tour-fx-aurora {
  /* Bands of the page's own background, cutting the light into ribbons. */
  --band: repeating-linear-gradient(100deg,
      var(--bg, #050508) 0%,  var(--bg, #050508) 7%,
      transparent        10%, transparent        12%,
      var(--bg, #050508) 16%);

  /* The tour's own palette, ordered so neighboring stops are near-neighbors
     on the wheel. That is what reads as light rather than as a rainbow. */
  --colors: repeating-linear-gradient(100deg,
      #5667bb        10%,
      #7084d1        15%,
      var(--cyan)    20%,
      var(--violet)  25%,
      #5ee3fd        30%);

  position: absolute;
  inset: -10px;                    /* overscan, so the blur never shows an edge */

  background-image: var(--band), var(--colors);
  background-size: 300%, 200%;

  /* Scroll drives the phase of the static layer while the moving layer keeps
     its own clock. The two sliding against each other at a rate the visitor
     controls is what makes this read as responding rather than merely playing. */
  background-position:
    calc(50% + var(--fx-au-shift)) 50%,
    calc(50% + var(--fx-au-shift)) 50%;

  filter: blur(10px);

  /* Two independent inputs multiplied rather than one shared number: arrival
     is written by the chapter trigger and the bloom by whichever scene wants
     one, so neither has to know the other exists or restore the other's value. */
  opacity: calc(var(--fx-au-op) * var(--fx-au-swell) * 0.52);
  will-change: opacity, background-position;

  /* The mask is the light source, and scroll walks it across the window. */
  -webkit-mask-image: radial-gradient(ellipse at var(--fx-au-mx) var(--fx-au-my), #000 8%, transparent 66%);
          mask-image: radial-gradient(ellipse at var(--fx-au-mx) var(--fx-au-my), #000 8%, transparent 66%);
}

/* The moving half, difference-blended against the static one. blur() on the
   parent already builds a stacking context, so the blend is contained and
   cannot reach the page behind it.

   background-attachment:fixed — which the original component uses — is
   deliberately absent. Inside an element that is itself position:fixed it
   buys nothing, and it is the single most expensive line in the effect. */
.tour-fx-aurora::after {
  content: '';
  position: absolute;
  inset: 0;
  background-image: var(--band), var(--colors);
  background-size: 200%, 100%;
  mix-blend-mode: difference;
  animation: tour-fx-aurora 72s linear infinite;
}

/* Slower than the library default. This one plays under a scroll that takes
   minutes, so it has to sit below the threshold of being noticed as a loop. */
@keyframes tour-fx-aurora {
  from { background-position: 50%  50%, 50%  50%; }
  to   { background-position: 350% 50%, 350% 50%; }
}


/* ─── Waves ───────────────────────────────────────────────────────────────── */
/* A horizon under the closing scene. Anchored to the bottom and masked into
   the section rather than filling it, so it reads as something the page is
   resting on. */

.tour-fx-waves {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 72%;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;

  opacity: var(--fx-wv-op, 0);
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 52%);
          mask-image: linear-gradient(to bottom, transparent, #000 52%);
}

.tour-fx-waves canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  /* On the element, not on the 2D context: one GPU composite instead of a CPU
     re-blur per stroke, and no browser sniff for Safari.

     A wider blur also spreads the same light over more pixels, so it lowers
     the peak brightness rather than only softening the edges. */
  filter: blur(17px);
}

/* The closing copy has to clear the horizon. .te-inner is already relative;
   this only gives it a layer to sit on. */
.tour-end .te-inner { z-index: 1; }


/* ─── Reduced motion ──────────────────────────────────────────────────────── */
/* Both effects stay — they are color and depth, which nobody asked to lose.
   Only the movement stops. tour-fx.js additionally paints the waves once and
   then leaves them, and skips every scroll subscription. */

@media (prefers-reduced-motion: reduce) {
  .tour-fx-aurora::after { animation: none; }
  .tour-fx { --fx-au-op: 0.85; --fx-au-mx: 72%; --fx-au-my: 14%; }
  .tour-fx-waves { opacity: 0.5; }
}


/* ─── Small screens ───────────────────────────────────────────────────────── */
/* A phone is painting the same full-viewport blurred layer on a fraction of
   the GPU. The aurora is cheap enough to keep at a smaller blur; the waves
   lose the band entirely, because at this width the closing scene is a
   stacked column and a horizon under it has nothing to be a horizon to. */

@media (max-width: 900px) {
  .tour-fx-aurora { filter: blur(7px); opacity: calc(var(--fx-au-op) * 0.42); }
  .tour-fx-waves { display: none; }
}
