/* ═══════════════════════════════════════════════════════════════════
   CABANA · THE CANOPY GATE
   ───────────────────────────────────────────────────────────────────
   The arrival animation for /tours.

   It is a forest at first light that opens to let you through. Not a
   decoration on top of a loading screen — it IS the loading screen,
   so the time it spends is time the page was going to spend anyway.

   Three decisions worth stating.

   · The greens are not forest greens. Every leaf shadow falls to
     #062B31, which is --ct-deep, the colour the tours page already
     uses. Every leaf edge catches #5EEAD4, which is the Cabana mint.
     A stock jungle palette would have fought the brand; this one
     carries it. The sun is #F5B12E — the gold this platform prices
     in, promoted to a light source.

   · Light passing THROUGH a leaf is what makes a leaf look real. Flat
     fills read as paper. So every blade gets a translucent rim and an
     off-centre specular sheen, and the veins shift lighter on the lit
     side and darker on the shadowed one.

   · Everything that moves, moves on transform and opacity. No layout
     is read or written during the sequence. Layer blur is CSS filter
     on a whole group, never an SVG filter per leaf, because the first
     is composited on the GPU and the second is not.

   Scoped under .jg- so it cannot touch the page it opens onto.
   ═══════════════════════════════════════════════════════════════════ */

#jungle-gate{
  /* ── the forest, in six values ── */
  --jg-void:#02110F;      /* deepest shade between the trunks     */
  --jg-deep:#062B31;      /* the tours page's own deep teal       */
  --jg-moss:#17553F;      /* lamina in shade                      */
  --jg-leaf:#2E8B63;      /* lamina in light                      */
  --jg-lime:#7BD99A;      /* lamina in full sun                   */
  --jg-rim:#5EEAD4;       /* Cabana mint — light through the leaf */
  --jg-sun:#F5B12E;       /* Cabana gold — the light itself       */

  --jg-ease:cubic-bezier(.76,0,.24,1);        /* the parting        */
  --jg-ease-soft:cubic-bezier(.22,1,.36,1);   /* everything else    */

  position:fixed;
  inset:0;
  z-index:2147483000;
  overflow:hidden;
  background:var(--jg-void);
  contain:strict;
  cursor:pointer;
  -webkit-tap-highlight-color:transparent;
}

/* The gate paints before its stylesheet can possibly matter, so the
   lock is on <html> and removes itself on every exit path. */
html.jg-lock,
html.jg-lock body{ overflow:hidden !important; }

/* ═══ 1 · DEPTH ═════════════════════════════════════════════════════
   Air between the layers. Without this the leaves look pasted onto a
   colour; with it they look like they are standing in front of
   something.                                                        */

.jg-air{
  position:absolute; inset:-10%;
  background:
    radial-gradient(46% 34% at 62% 22%, rgba(255,238,190,.5), transparent 62%),
    radial-gradient(88% 62% at 62% 22%, rgba(245,177,46,.2), transparent 70%),
    radial-gradient(130% 92% at 50% 116%, rgba(0,5,4,.96), transparent 62%),
    linear-gradient(176deg, #07332C 0%, #031C18 42%, #000504 100%);
  transform:scale(1.04);
}

/* The sun itself, seen through leaves, so it is bloom rather than disc */
.jg-sun{
  position:absolute;
  top:14%; left:63%;
  width:min(56vw,340px); aspect-ratio:1;
  margin:-14vw 0 0 -28vw;
  border-radius:50%;
  background:radial-gradient(circle,
    rgba(255,253,244,1) 0%,
    rgba(255,233,168,.92) 20%,
    rgba(245,177,46,.55) 42%,
    rgba(245,177,46,.14) 62%,
    transparent 74%);
  filter:blur(10px);
  opacity:0;
  transform:scale(.72);
}

/* Haze that sits between the far canopy and the mid canopy. This is
   the layer doing most of the work of making the scene feel deep. */
.jg-haze{
  position:absolute; inset:0;
  background:linear-gradient(184deg,
    rgba(126,214,178,.16) 0%,
    rgba(94,234,212,.07) 32%,
    transparent 58%);
  opacity:0;
}

/* ═══ 2 · SHAFTS ════════════════════════════════════════════════════
   Light does not arrive in a forest as an even wash. It arrives in
   hard-edged columns with dust in them.                             */

.jg-rays{
  position:absolute; inset:-30% -20%;
  transform-origin:70% 0;
  opacity:0;
  will-change:transform,opacity;
}
.jg-ray{
  position:absolute; top:0;
  width:var(--w,7%); height:150%;
  background:linear-gradient(180deg,
    rgba(255,244,222,.62) 0%,
    rgba(245,177,46,.26) 40%,
    transparent 82%);
  filter:blur(var(--b,10px));
  transform:rotate(var(--r,14deg));
  opacity:var(--o,.7);
}

/* ═══ 3 · THE CANOPY ════════════════════════════════════════════════
   Four depths. Far is nearly a silhouette; near is close enough to be
   out of focus. Only the middle is sharp, which is where the eye rests.

   The three-element nesting below is load-bearing, not tidiness:

     .jg-plane   transform  · the parting
       .jg-sway  transform  · the idle breath
         .jg-blur  filter   · static, so its texture is cached once

   Animating anything inside .jg-blur re-runs a full-viewport filter
   every frame. That mistake measured 3.3 fps.                       */

.jg-plane{
  position:absolute; inset:0;
  will-change:transform;
  backface-visibility:hidden;
  transform:translateZ(0);
}
.jg-sway{
  position:absolute; inset:0;
  transform-origin:50% 92%;
  will-change:transform;
}
.jg-blur{
  position:absolute; inset:0;
  transform:translateZ(0);
}
.jg-blur svg{
  position:absolute; inset:0;
  width:100%; height:100%;
  display:block;
  overflow:visible;
}

/* Blur radii are half what they were. Past about 6px the cost climbs
   fast and the read barely changes, because these planes are already
   being separated by value and scale as much as by focus. */
.jg-far     { filter:saturate(.55) brightness(.32); opacity:.85; }
.jg-mid     { filter:brightness(.82); }
.jg-near    { filter:brightness(.6); }
.jg-foreblur{ filter:blur(4px) brightness(.26); opacity:.96; }

/* ═══ 4 · THE WORD ══════════════════════════════════════════════════ */

.jg-word{
  position:absolute;
  left:0; right:0; top:50%;
  transform:translateY(-50%);
  text-align:center;
  z-index:6;
  padding:0 24px;
  pointer-events:none;
  will-change:transform,opacity;
}
.jg-title{
  font-family:'Geist','Inter',system-ui,sans-serif;
  font-weight:500;
  font-style:italic;
  font-size:clamp(52px,17vw,116px);
  line-height:.92;
  letter-spacing:-.035em;
  color:#fff;
  opacity:0;
  transform:translateY(16px);
  text-shadow:0 6px 44px rgba(2,17,15,.6), 0 0 90px rgba(245,177,46,.28);
}
.jg-sub{
  margin-top:14px;
  font-family:'Geist','Inter',system-ui,sans-serif;
  font-size:clamp(11.5px,3vw,13.5px);
  font-weight:500;
  letter-spacing:.02em;
  color:rgba(233,255,246,.72);
  opacity:0;
  transform:translateY(10px);
}
/* A single hairline under the word, carrying the light of the scene.
   It grows from the centre as the title settles, then leaves with it. */
.jg-rule{
  width:0; height:1px;
  margin:20px auto 0;
  background:linear-gradient(90deg, transparent, var(--jg-rim), var(--jg-sun), transparent);
  opacity:.85;
}

/* ═══ 5 · DUST ══════════════════════════════════════════════════════
   Motes only exist where a shaft is. That is the whole reason they
   sell the light.                                                   */

.jg-motes{ position:absolute; inset:0; z-index:5; opacity:0; }
.jg-mote{
  position:absolute;
  width:var(--s,3px); aspect-ratio:1;
  border-radius:50%;
  background:radial-gradient(circle, rgba(255,247,224,.95), rgba(245,177,46,.25) 60%, transparent 72%);
  left:var(--x,50%); top:var(--y,50%);
  animation:jg-drift var(--d,9s) linear var(--dl,0s) infinite;
  will-change:transform;
}
@keyframes jg-drift{
  0%  { transform:translate3d(0,0,0)            scale(.6); opacity:0;   }
  14% { opacity:var(--o,.75); }
  86% { opacity:var(--o,.75); }
  100%{ transform:translate3d(var(--dx,24px),var(--dy,-190px),0) scale(1); opacity:0; }
}

/* ═══ 6 · THE FLOOD ═════════════════════════════════════════════════
   The half-second where the gap between the leaves becomes the whole
   screen. This is what makes it feel like stepping out, rather than
   like an overlay being switched off.                               */

.jg-flood{
  position:absolute; inset:0; z-index:7;
  background:radial-gradient(120% 62% at 50% 46%,
    rgba(255,252,243,.9) 0%,
    rgba(226,250,241,.55) 30%,
    rgba(94,234,212,.14) 58%,
    transparent 76%);
  opacity:0;
  transform:scale(.42);
  pointer-events:none;
  will-change:transform,opacity;
}

/* ═══ 7 · SKIP ══════════════════════════════════════════════════════ */

.jg-skip{
  position:absolute;
  top:max(18px,env(safe-area-inset-top,0px));
  right:16px;
  z-index:9;
  display:inline-flex; align-items:center; gap:7px;
  padding:9px 15px;
  border-radius:100px;
  border:1px solid rgba(233,255,246,.26);
  background:rgba(2,17,15,.52);
  color:rgba(233,255,246,.86);
  font-family:'Geist','Inter',system-ui,sans-serif;
  font-size:12.5px; font-weight:500;
  cursor:pointer;
  opacity:0;
  transition:opacity .4s ease, border-color .2s ease, color .2s ease;
}
.jg-skip:hover,
.jg-skip:focus-visible{ border-color:var(--jg-rim); color:#fff; }
.jg-skip:focus-visible{ outline:2px solid var(--jg-rim); outline-offset:3px; }
.jg-skip svg{ width:12px; height:12px; }

/* ═══════════════════════════════════════════════════════════════════
   THE SEQUENCE
   Driven by a class on the root so the whole thing is one timeline
   that can be started, skipped or abandoned at any frame.
   ═══════════════════════════════════════════════════════════════════ */

/* ── phase: light finds the seam ── */
#jungle-gate.jg-lit .jg-sun{
  animation:jg-bloom 1.5s var(--jg-ease-soft) forwards;
}
@keyframes jg-bloom{
  0%  { opacity:0; transform:scale(.72); }
  100%{ opacity:1; transform:scale(1); }
}
#jungle-gate.jg-lit .jg-haze{ animation:jg-fade-in 1.2s .18s ease forwards; }
#jungle-gate.jg-lit .jg-rays{ animation:jg-rays-in 1.6s .1s var(--jg-ease-soft) forwards; }
@keyframes jg-rays-in{
  0%  { opacity:0; transform:rotate(-5deg) scale(1.14); }
  100%{ opacity:.72; transform:rotate(0deg) scale(1); }
}
#jungle-gate.jg-lit .jg-motes{ animation:jg-fade-in 1.4s .35s ease forwards; }
@keyframes jg-fade-in{ to{ opacity:1; } }

#jungle-gate.jg-lit .jg-sway{
  animation:jg-breathe var(--sway,7s) ease-in-out var(--swd,0s) infinite alternate;
}
/* Once the canopy is opening, the breath is noise. Stopping it also
   frees the compositor for the one moment that matters. */
#jungle-gate.jg-open .jg-sway{ animation:none; }
@keyframes jg-breathe{
  from{ transform:rotate(var(--a1,-.7deg)) translate3d(0,0,0); }
  to  { transform:rotate(var(--a2,.7deg))  translate3d(0,var(--sy,-4px),0); }
}

#jungle-gate.jg-lit .jg-skip{ opacity:1; }

/* ── phase: the word ── */
#jungle-gate.jg-say .jg-title{ animation:jg-rise .9s var(--jg-ease-soft) forwards; }
#jungle-gate.jg-say .jg-sub  { animation:jg-rise .8s .13s var(--jg-ease-soft) forwards; }
#jungle-gate.jg-say .jg-rule { animation:jg-rule .9s .1s var(--jg-ease-soft) forwards; }
@keyframes jg-rise{ to{ opacity:1; transform:translateY(0); } }
@keyframes jg-rule{ to{ width:min(46vw,190px); } }

/* ── phase: the canopy parts ───────────────────────────────────────
   Each plane leaves at its own rate. The near plane travels furthest
   because it is closest to the camera; that difference is the only
   thing making this read as depth rather than as two sliding images. */

#jungle-gate.jg-open .jg-L-far  { animation:jg-part-L 1.2s  var(--jg-ease) forwards; --tx:-34%;  --rot:-4deg;  --sc:1.08; }
#jungle-gate.jg-open .jg-R-far  { animation:jg-part-R 1.2s  var(--jg-ease) forwards; --tx:34%;   --rot:4deg;   --sc:1.08; }
#jungle-gate.jg-open .jg-L-mid  { animation:jg-part-L 1.15s var(--jg-ease) forwards; --tx:-66%;  --rot:-9deg;  --sc:1.16; }
#jungle-gate.jg-open .jg-R-mid  { animation:jg-part-R 1.15s var(--jg-ease) forwards; --tx:66%;   --rot:9deg;   --sc:1.16; }
#jungle-gate.jg-open .jg-L-near { animation:jg-part-L 1.05s var(--jg-ease) forwards; --tx:-104%; --rot:-15deg; --sc:1.32; }
#jungle-gate.jg-open .jg-R-near { animation:jg-part-R 1.05s var(--jg-ease) forwards; --tx:104%;  --rot:15deg;  --sc:1.32; }
#jungle-gate.jg-open .jg-fore  { animation:jg-fore-out 1s var(--jg-ease) forwards; }

@keyframes jg-part-L{
  0%  { transform:translate3d(0,0,0) rotate(0) scale(1); }
  100%{ transform:translate3d(var(--tx),3%,0) rotate(var(--rot)) scale(var(--sc)); }
}
@keyframes jg-part-R{
  0%  { transform:translate3d(0,0,0) rotate(0) scale(1); }
  100%{ transform:translate3d(var(--tx),3%,0) rotate(var(--rot)) scale(var(--sc)); }
}
@keyframes jg-fore-out{
  0%  { transform:scale(1) translate3d(0,0,0); opacity:.92; }
  100%{ transform:scale(1.9) translate3d(0,14%,0); opacity:0; }
}

/* The scene used to push past the camera with a scale on .jg-stage.
   That re-rasterised all four filtered planes every frame for an
   effect the per-plane scales below already deliver. */

/* the word steps back rather than fading in place */
#jungle-gate.jg-open .jg-word{ animation:jg-word-out .5s var(--jg-ease-soft) forwards; }
@keyframes jg-word-out{
  0%  { opacity:1; transform:translateY(-50%) scale(1); filter:blur(0); }
  100%{ opacity:0; transform:translateY(-50%) scale(1.14); filter:blur(6px); }
}

#jungle-gate.jg-open .jg-skip{ opacity:0; }
#jungle-gate.jg-open .jg-rays{ animation:jg-rays-out 1.1s var(--jg-ease) forwards; }
#jungle-gate.jg-open .jg-sun { animation:jg-sun-out .9s .25s var(--jg-ease) forwards; }
@keyframes jg-sun-out{ to{ opacity:0; transform:scale(2.2); } }
@keyframes jg-rays-out{ to{ opacity:0; transform:scale(1.5); } }

/* the gap becomes the screen */
#jungle-gate.jg-open .jg-flood{ animation:jg-flood .95s .38s var(--jg-ease) forwards; }
@keyframes jg-flood{
  0%  { opacity:0; transform:scale(.5); }
  60% { opacity:.7; }
  100%{ opacity:1; transform:scale(1.6); }
}

/* ── phase: gone ── */
#jungle-gate.jg-gone{
  animation:jg-gone .5s ease forwards;
  pointer-events:none;
}
@keyframes jg-gone{ to{ opacity:0; } }

/* ═══════════════════════════════════════════════════════════════════
   ABBREVIATED  ·  after the first arrival in a session
   The full sequence is a welcome. Played on every navigation it would
   become a toll. Same scene, opened almost immediately.
   ═══════════════════════════════════════════════════════════════════ */
#jungle-gate.jg-brief .jg-sun  { animation-duration:.5s; }
#jungle-gate.jg-brief .jg-rays { animation-duration:.55s; animation-delay:0s; }
#jungle-gate.jg-brief .jg-haze { animation-duration:.4s; animation-delay:0s; }
#jungle-gate.jg-brief .jg-title,
#jungle-gate.jg-brief .jg-sub,
#jungle-gate.jg-brief .jg-rule,
#jungle-gate.jg-brief .jg-motes,
#jungle-gate.jg-brief .jg-skip { display:none; }
#jungle-gate.jg-brief.jg-open .jg-L-far,
#jungle-gate.jg-brief.jg-open .jg-R-far,
#jungle-gate.jg-brief.jg-open .jg-L-mid,
#jungle-gate.jg-brief.jg-open .jg-R-mid,
#jungle-gate.jg-brief.jg-open .jg-L-near,
#jungle-gate.jg-brief.jg-open .jg-R-near{ animation-duration:.8s; }
#jungle-gate.jg-brief.jg-open .jg-flood{ animation-duration:.8s; animation-delay:.05s; }

/* ═══════════════════════════════════════════════════════════════════
   REDUCED MOTION
   Not a degraded version: a still photograph of the same forest, held
   briefly, then crossfaded. Nothing translates, rotates or scales.
   ═══════════════════════════════════════════════════════════════════ */
@media (prefers-reduced-motion:reduce){
  #jungle-gate .jg-sun,
  #jungle-gate .jg-haze,
  #jungle-gate .jg-rays{ opacity:1; transform:none; animation:none !important; }
  #jungle-gate .jg-motes{ display:none; }
  #jungle-gate .jg-sway { animation:none !important; }
  #jungle-gate .jg-title,
  #jungle-gate .jg-sub  { opacity:1; transform:none; animation:none !important; }
  #jungle-gate .jg-rule { width:min(46vw,190px); animation:none !important; }
  #jungle-gate.jg-open .jg-plane,
  #jungle-gate.jg-open .jg-sway,
  #jungle-gate.jg-open .jg-stage,
  #jungle-gate.jg-open .jg-word,
  #jungle-gate.jg-open .jg-flood{ animation:none !important; transform:none; }
  #jungle-gate.jg-open{ animation:jg-gone .45s ease forwards; }
}

/* ═══════════════════════════════════════════════════════════════════
   VIEWPORT
   The scene is authored portrait-first, because that is how it is
   actually seen. On a wide screen the planes are pulled apart rather
   than stretched, so the leaves keep their proportions.
   ═══════════════════════════════════════════════════════════════════ */
.jg-stage{
  position:absolute; inset:0;
  transform-origin:50% 52%;
  will-change:transform;
}
@media (min-width:820px){
  #jungle-gate .jg-blur svg{ transform:scale(1.02); transform-origin:50% 50%; }
  .jg-sun{ width:min(34vw,420px); margin:-9vw 0 0 -17vw; }
}
@media (max-width:420px){
  .jg-title{ font-size:clamp(46px,16vw,72px); }
}
