/* ==========================================================================================================
   WashVantage hero: CSS neon wash arches (no pictures, no JavaScript needed to show it)
   ----------------------------------------------------------------------------------------------------------
   README for the page builder

   What this is
     A night wash tunnel drawn only with CSS: 9 glowing LED arches in teal and cool white, with ONE amber arch
     (amber = look here: it is the arch that frames the sample audit page at the end of the scroll), on the navy
     base, a wet floor that mirrors them, depth fog and a soft teal light at the far end.
     It replaces the rendered frame sequence (frames/manifest.js sets window.WV_FRAMES = null).
     Without JavaScript, with reduced motion, or before GSAP loads, it simply shows the tunnel standing still,
     which is the designed still look. frames/poster-desktop.webp and frames/poster-phone.webp are pictures of
     exactly this resting state (no grain layer), for places that need an image (noscript, a print style).

   Markup (copy as is; it is decoration only, so the whole block is aria-hidden)
     <link rel="stylesheet" href="hero_arches.css">          (in <head>)

     <header class="hero">                                     (the hero needs position:relative; the tunnel
       <div class="wv-tunnel" aria-hidden="true">               fills it with position:absolute; inset:0)
         <div class="wv-tunnel__floor"></div>
         <div class="wv-tunnel__exit"></div>
         <div class="wv-tunnel__arches">
           <i class="wv-arch"></i> <i class="wv-arch"></i> <i class="wv-arch"></i>
           <i class="wv-arch"></i> <i class="wv-arch"></i> <i class="wv-arch"></i>
           <i class="wv-arch"></i> <i class="wv-arch"></i> <i class="wv-arch"></i>
         </div>
         <div class="wv-tunnel__fog"></div>             (optional: depth fog over the far arches)
         <div class="wv-tunnel__haze"></div>
         <div class="wv-tunnel__grain"></div>
         <div class="wv-tunnel__scrim"></div>
       </div>
       ... the real H1, lead text and buttons go here, AFTER the tunnel, with position:relative; z-index:1 ...
     </header>

     Keep the parts in this order (it is the paint order). 8, 9 or 10 arches all work; 9 is the default.
     Nothing inside the tunnel is text, so screen readers and the page's word checks never see it.

   The arches
     Every arch is an element with class wv-arch and a CSS variable --z (a plain number, no unit).
     --z is measured in "arch gaps": 0 is the nearest arch, -1 the next one back, -8 the ninth.
     This file already gives the n-th arch --z: 0, -1, -2 ... and the colours teal, white, teal, white ... with the
     9th arch amber, so the markup needs no inline styles. To force a colour: class="wv-arch wv-arch--amber"
     (teal/white/amber; red and blue still work but are off-brand).

   Moving through the tunnel with GSAP (the z-scrub)
     The easy way: tween ONE number on the tunnel. --wv-travel is added to every arch's --z and also slides
     the conveyor, so arches and floor always move together.

       gsap.to(".wv-tunnel", { "--wv-travel": 4, ease: "none",
         scrollTrigger: { trigger: ".hero", start: "top top", end: "+=150%", scrub: 0.6, pin: true } });

     0 to 4 drives calmly past four arches. 0 to 8.6 drives all the way to the teal exit light.
     Per-arch control also works (each arch keeps its own --z), for example:
       gsap.to(".wv-arch", { "--z": "+=2", ease: "none", stagger: 0, scrollTrigger: { ... } });
     Arches fade out by themselves as they pass the viewer and fade in from the haze far away.
     --wv-power (0 to 1, default 1) dims arches, for an LED "power on" flicker:
       gsap.from(".wv-arch", { "--wv-power": 0, duration: 0.12, repeat: 1, stagger: 0.05 });

     Put the scrub inside gsap.matchMedia() with "(min-width: 768px) and (prefers-reduced-motion: no-preference)"
     so phones and reduced-motion visitors get the still tunnel (the plan's fallbacks).

   Knobs (set them on .wv-tunnel, or on the hero, they inherit)
     --wv-vx / --wv-vy   where the tunnel vanishes on screen (default 64% 46% on wide screens, 50% 40% on phones)
     --wv-travel         how far the viewer has driven, in arch gaps (default 0)
     --wv-power          arch brightness 0..1 (default 1)
     .wv-tunnel--center  keeps the vanishing point in the middle on wide screens too
     .wv-tunnel--no-scrim / the __scrim element can be dropped if the text sits elsewhere

   Colours used: navy base #07131C / #050D13, teal #14B8A6 (clean), a cool LED white, and amber #F5A524
   (look here) for one arch only. Sizes follow the hero's own height (container
   query units, with a vh fallback), so the same tunnel fits a 390 px phone and a 1920 px screen.
   ========================================================================================================== */

@property --wv-travel { syntax: "<number>"; inherits: true; initial-value: 0; }
@property --wv-power { syntax: "<number>"; inherits: true; initial-value: 1; }

.wv-tunnel {
  /* colours as R G B triplets, so each can be used at any strength */
  --wv-base: 7 19 28;                      /* #07131C navy base */
  --wv-deep: 5 13 19;                      /* #050D13 tunnel black */
  --wv-red: 229 72 77;                     /* #E5484D */
  --wv-red-hot: 255 214 215;
  --wv-blue: 64 132 255;
  --wv-blue-hot: 218 233 255;
  --wv-amber: 245 165 36;                  /* #F5A524 */
  --wv-amber-hot: 255 236 196;
  --wv-teal: 20 184 166;                   /* #14B8A6 */
  --wv-teal-hot: 214 250 244;
  --wv-white: 150 205 225;                 /* cool LED white: the glow */
  --wv-white-hot: 244 252 255;             /* and the tube itself */

  --wv-travel: 0;
  --wv-power: 1;

  /* geometry, all from the hero's height (H) */
  --wv-h: 100vh;
  --wv-w: 100vw;
  --wv-vx: 65%;
  --wv-vy: 46%;
  --wv-persp: calc(var(--wv-h) * .95);     /* camera lens */
  --wv-gap: calc(var(--wv-h) * .62);       /* distance between two arches */
  --wv-arch-w: calc(var(--wv-h) * 1.06);
  --wv-arch-h: calc(var(--wv-h) * .80);
  --wv-floor-y: calc(var(--wv-h) * .34);   /* how far below the vanishing point the floor line sits */
  --wv-line: max(2px, calc(var(--wv-h) * .0052));   /* LED tube thickness on the nearest arch */

  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  isolation: isolate;
  pointer-events: none;
  user-select: none;
  container-type: size;
  contain: strict;
  background:
    radial-gradient(120% 70% at var(--wv-vx) var(--wv-vy), rgb(var(--wv-base)) 0%, rgb(var(--wv-deep)) 70%),
    rgb(var(--wv-deep));
}
@supports (height: 1cqh) {
  .wv-tunnel { --wv-h: 100cqh; --wv-w: 100cqw; }
}
.wv-tunnel--center { --wv-vx: 50%; }

/* ---------- shared 3D stage settings (floor and arches use the same camera) ---------- */
.wv-tunnel__floor,
.wv-tunnel__arches {
  position: absolute;
  inset: 0;
  perspective: var(--wv-persp);
  perspective-origin: var(--wv-vx) var(--wv-vy);
}
.wv-tunnel__arches { transform-style: preserve-3d; }

/* ---------- the wet floor: a long plane laid flat (::before), plus a thin layer of drain grates (::after) that slides
   toward the viewer with --wv-travel. The grates move by transform only, so scrolling never repaints the floor. ---------- */
.wv-tunnel__floor::before,
.wv-tunnel__floor::after {
  content: "";
  position: absolute;
  left: var(--wv-vx);
  transform-origin: 50% 100%;
  backface-visibility: hidden;
}
.wv-tunnel__floor::before {
  top: calc(var(--wv-vy) + var(--wv-floor-y) - var(--wv-gap) * 12.25);
  width: calc(var(--wv-arch-w) * 2.4);
  height: calc(var(--wv-gap) * 12.25);                       /* from 1.25 gaps in front of the first arch to 11 behind it */
  transform: translateX(-50%) translateZ(calc(var(--wv-gap) * 1.25)) rotateX(90deg);
  background:
    /* the teal exit light running back along the wet lane */
    linear-gradient(90deg, transparent 39%, rgb(var(--wv-teal) / .10) 50%, transparent 61%),
    /* wet concrete: a soft sheen in the lane, near black at the sides */
    linear-gradient(90deg, rgb(var(--wv-deep) / 0) 4%, rgb(11 29 41) 30%, rgb(13 34 47) 50%, rgb(11 29 41) 70%, rgb(var(--wv-deep) / 0) 96%);
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 34%, #000 100%);
          mask-image: linear-gradient(180deg, transparent 0%, #000 34%, #000 100%);
}
.wv-tunnel__floor::after {
  top: calc(var(--wv-vy) + var(--wv-floor-y) - var(--wv-gap) * 11.75);
  width: calc(var(--wv-arch-w) * .62);
  height: calc(var(--wv-gap) * 11.75);
  transform: translateX(-50%) translateZ(calc(var(--wv-gap) * .75)) rotateX(90deg);
  /* thin lines across the lane, two per arch gap, sitting between the arches */
  background: linear-gradient(180deg, rgb(170 205 220 / .055) 0 calc(var(--wv-line) * .6), transparent calc(var(--wv-line) * .6))
    50% 100% / 100% calc(var(--wv-gap) / 2) repeat-y;
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 40%), linear-gradient(90deg, transparent, #000 20%, #000 80%, transparent);
          mask-image: linear-gradient(180deg, transparent 0%, #000 40%), linear-gradient(90deg, transparent, #000 20%, #000 80%, transparent);
  -webkit-mask-composite: source-in;
          mask-composite: intersect;
  will-change: transform;
}
@supports (transform: translateZ(calc(mod(1.2, .5) * 1px))) {
  .wv-tunnel__floor::after {
    transform: translateX(-50%) translateZ(calc(var(--wv-gap) * (.75 + mod(var(--wv-travel), .5)))) rotateX(90deg);
  }
}

/* ---------- the light at the end of the tunnel (teal = clean): a soft glow standing on the floor past the last arch.
   It sits in the same 3D space, so it grows as the viewer drives toward it. Gradients only, no hard edges. ---------- */
.wv-tunnel__exit {
  position: absolute;
  inset: 0;
  perspective: var(--wv-persp);
  perspective-origin: var(--wv-vx) var(--wv-vy);
}
.wv-tunnel__exit::before,
.wv-tunnel__exit::after {
  content: "";
  position: absolute;
  left: var(--wv-vx);
  top: calc(var(--wv-vy) + var(--wv-floor-y) - var(--wv-arch-h));
  width: var(--wv-arch-w);
  height: calc(var(--wv-arch-h) * 2);             /* the floor line is in the middle of this box */
  transform: translate3d(-50%, 0, calc(min(var(--wv-travel) - 10.2, -1.4) * var(--wv-gap)));
  backface-visibility: hidden;
}
/* the opening: light pooling where the far end meets the floor */
.wv-tunnel__exit::before {
  background:
    radial-gradient(28% 6% at 50% 50%, rgb(var(--wv-teal-hot) / .4), rgb(var(--wv-teal-hot) / 0) 100%),
    radial-gradient(40% 22% at 50% 50%, rgb(var(--wv-teal) / .38), rgb(var(--wv-teal) / .12) 50%, rgb(var(--wv-teal) / 0) 100%),
    radial-gradient(46% 40% at 50% 50%, rgb(var(--wv-teal) / .10), rgb(var(--wv-teal) / 0) 100%);
  opacity: calc(.75 + var(--wv-travel) * .03);
}
/* its wide halo in the spray */
.wv-tunnel__exit::after {
  width: calc(var(--wv-arch-w) * 3);
  background: radial-gradient(50% 36% at 50% 50%, rgb(var(--wv-teal) / .10), rgb(var(--wv-teal) / 0));
}

/* ---------- the arches ---------- */
.wv-arch {
  --z: 0;
  --c: var(--wv-teal);
  --c-hot: var(--wv-teal-hot);
  --wz: calc(var(--z) + var(--wv-travel));
  --near: clamp(0, calc((.95 - var(--wz)) * 2), 1);        /* fades out as it passes the viewer */
  --far: clamp(0, calc((var(--wz) + 9.6) / 5.4), 1);        /* fades in out of the haze */

  position: absolute;
  left: var(--wv-vx);
  top: calc(var(--wv-vy) + var(--wv-floor-y) - var(--wv-arch-h));
  width: var(--wv-arch-w);
  height: var(--wv-arch-h);
  box-sizing: border-box;
  display: block;
  border: var(--wv-line) solid rgb(var(--c-hot));
  border-bottom-color: transparent;   /* not 0: a zero-width side leaves a faint seam on far arches */
  border-radius: 50% 50% 0 0 / 30% 30% 0 0;
  transform: translate3d(-50%, 0, calc(var(--wz) * var(--wv-gap)));
  opacity: calc(min(var(--near), var(--far)) * var(--wv-power));
  filter:
    drop-shadow(0 0 calc(var(--wv-line) * .5) rgb(var(--c)))
    drop-shadow(0 0 calc(var(--wv-line) * 2) rgb(var(--c)))
    drop-shadow(0 0 calc(var(--wv-line) * 6) rgb(var(--c) / .8))
    drop-shadow(0 0 calc(var(--wv-line) * 18) rgb(var(--c) / .5));
  will-change: transform, opacity;
  backface-visibility: hidden;
}
/* the second, thinner LED strip just inside the main tube */
.wv-arch::before {
  content: "";
  position: absolute;
  inset: calc(var(--wv-line) * 3.2) calc(var(--wv-line) * 3.2) 0;
  border: max(1px, calc(var(--wv-line) * .45)) solid rgb(var(--c-hot) / .55);
  border-bottom-color: transparent;   /* not 0: a zero-width side leaves a faint seam on far arches */
  border-radius: 50% 50% 0 0 / 30% 30% 0 0;
}
/* the arch mirrored in the wet floor, fading away from the floor line */
.wv-arch::after {
  content: "";
  position: absolute;
  top: 100%;
  left: calc(var(--wv-line) * -1);
  right: calc(var(--wv-line) * -1);
  height: 90%;
  border: calc(var(--wv-line) * 1.5) solid rgb(var(--c-hot) / .9);
  border-top-color: transparent;
  border-radius: 0 0 50% 50% / 0 0 30% 30%;
  transform: translateY(calc(var(--wv-line) * -1));
  opacity: .6;
  filter: blur(calc(var(--wv-line) * 1.1));
  -webkit-mask-image: linear-gradient(180deg, #000 0%, rgb(0 0 0 / .55) 14%, rgb(0 0 0 / .22) 32%, transparent 58%);
          mask-image: linear-gradient(180deg, #000 0%, rgb(0 0 0 / .55) 14%, rgb(0 0 0 / .22) 32%, transparent 58%);
}

/* default depth and colour for each arch (red, blue, amber, repeating) */
.wv-arch:nth-child(1)  { --z: 0; }
.wv-arch:nth-child(2)  { --z: -1; }
.wv-arch:nth-child(3)  { --z: -2; }
.wv-arch:nth-child(4)  { --z: -3; }
.wv-arch:nth-child(5)  { --z: -4; }
.wv-arch:nth-child(6)  { --z: -5; }
.wv-arch:nth-child(7)  { --z: -6; }
.wv-arch:nth-child(8)  { --z: -7; }
.wv-arch:nth-child(9)  { --z: -8; }
.wv-arch:nth-child(10) { --z: -9; }
.wv-arch:nth-child(even) { --c: var(--wv-white); --c-hot: var(--wv-white-hot); }
.wv-arch:nth-child(9)    { --c: var(--wv-amber); --c-hot: var(--wv-amber-hot); }   /* the one amber arch */
.wv-arch.wv-arch--teal  { --c: var(--wv-teal); --c-hot: var(--wv-teal-hot); }
.wv-arch.wv-arch--white { --c: var(--wv-white); --c-hot: var(--wv-white-hot); }
.wv-arch.wv-arch--red   { --c: var(--wv-red); --c-hot: var(--wv-red-hot); }
.wv-arch.wv-arch--blue  { --c: var(--wv-blue); --c-hot: var(--wv-blue-hot); }
.wv-arch.wv-arch--amber { --c: var(--wv-amber); --c-hot: var(--wv-amber-hot); }

/* ---------- air: coloured spray haze and a low mist over the floor ---------- */
.wv-tunnel__haze {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(28% 22% at var(--wv-vx) calc(var(--wv-vy) + 6%), rgb(var(--wv-teal) / .08), transparent 70%),
    radial-gradient(36% 34% at calc(var(--wv-vx) + 18%) calc(var(--wv-vy) - 16%), rgb(var(--wv-white) / .05), transparent 70%),
    radial-gradient(30% 22% at calc(var(--wv-vx) + 6%) calc(var(--wv-vy) + 26%), rgb(var(--wv-amber) / .04), transparent 70%),
    linear-gradient(180deg, transparent calc(var(--wv-vy) + 4%), rgb(150 190 210 / .05) calc(var(--wv-vy) + 14%), transparent calc(var(--wv-vy) + 30%));
  mix-blend-mode: screen;
}
/* depth fog: the far end of the tunnel sinks into the dark, so the arches read as receding, not as flat outlines */
.wv-tunnel__fog {
  position: absolute;
  inset: 0;
  background: radial-gradient(calc(var(--wv-arch-w) * .30) calc(var(--wv-arch-h) * .34) at var(--wv-vx) calc(var(--wv-vy) - 1%),
    rgb(var(--wv-deep) / .72) 0%, rgb(var(--wv-deep) / .4) 48%, rgb(var(--wv-deep) / 0) 100%);
  opacity: clamp(.25, calc(1 - var(--wv-travel) * .1), 1);   /* thins out as the viewer drives toward the exit */
}

/* ---------- film grain (tiny SVG noise, drawn once; leave it out for a poster picture) ---------- */
.wv-tunnel__grain {
  position: absolute;
  inset: 0;
  opacity: .16;                            /* fine grain: also hides colour banding in the dark gradients */
  background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPScxODAnIGhlaWdodD0nMTgwJz48ZmlsdGVyIGlkPSduJz48ZmVUdXJidWxlbmNlIHR5cGU9J2ZyYWN0YWxOb2lzZScgYmFzZUZyZXF1ZW5jeT0nLjg1JyBudW1PY3RhdmVzPScyJyBzdGl0Y2hUaWxlcz0nc3RpdGNoJy8+PGZlQ29sb3JNYXRyaXggdmFsdWVzPScwIDAgMCAwIDEgMCAwIDAgMCAxIDAgMCAwIDAgMSAwIDAgMCAxLjYgLS4zJy8+PC9maWx0ZXI+PHJlY3Qgd2lkdGg9JzEwMCUnIGhlaWdodD0nMTAwJScgZmlsdGVyPSd1cmwoI24pJy8+PC9zdmc+");
  background-size: 180px 180px;
}

/* ---------- scrim: keeps the headline readable and melts the hero into the page below ---------- */
.wv-tunnel__scrim {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(0deg, rgb(var(--wv-base)) 0%, rgb(var(--wv-base) / 0) 20%),
    linear-gradient(180deg, rgb(var(--wv-deep) / .7) 0%, rgb(var(--wv-deep) / 0) 16%),
    linear-gradient(90deg, rgb(var(--wv-deep) / .9) 0%, rgb(var(--wv-deep) / .72) 26%, rgb(var(--wv-deep) / .2) 46%, rgb(var(--wv-deep) / 0) 58%),
    radial-gradient(140% 120% at var(--wv-vx) var(--wv-vy), transparent 52%, rgb(var(--wv-deep) / .55) 100%);
}
.wv-tunnel--no-scrim .wv-tunnel__scrim { display: none; }

/* ---------- phones and narrow screens: centred tunnel, text sits low over the floor ---------- */
@media (max-width: 767px) {
  .wv-tunnel {
    --wv-vx: 50%;
    --wv-vy: 38%;
    --wv-arch-w: calc(var(--wv-h) * .78);
    --wv-arch-h: calc(var(--wv-h) * .62);
    --wv-floor-y: calc(var(--wv-h) * .22);
    --wv-gap: calc(var(--wv-h) * .46);
    --wv-persp: calc(var(--wv-h) * .8);
    --wv-line: max(1.5px, calc(var(--wv-h) * .0042));
  }
  .wv-tunnel__scrim {
    background:
      linear-gradient(0deg, rgb(var(--wv-base)) 0%, rgb(var(--wv-base) / .9) 22%, rgb(var(--wv-deep) / .55) 44%, rgb(var(--wv-deep) / 0) 62%),
      linear-gradient(180deg, rgb(var(--wv-deep) / .75) 0%, rgb(var(--wv-deep) / 0) 14%),
      radial-gradient(150% 110% at var(--wv-vx) var(--wv-vy), transparent 50%, rgb(var(--wv-deep) / .6) 100%);
  }
}

/* High-contrast (forced colours) mode: the glow means nothing there, so show a plain background. */
@media (forced-colors: active) {
  .wv-tunnel { display: none; }
}
