/* ============================================================
   TRIPLE A — immersive layer
   Sits on top of styles.css; never edits it. Every rule is scoped
   to a class that only exists once the feature can actually run:
     .js-anim       set in <head> before paint (existing)
     .js-immersive  set by immersive.js
     .webgl-on      set after the first WebGL frame has rendered
     .fx-pointer    fine pointer + motion allowed
   Brand tokens only: navy / teal / aqua / mint.
   ============================================================ */

/* ============================================================
   0. BRAND BALANCE
   Original light tokens (--ink/--body/--surface/--white/etc.) are
   left untouched — the site keeps the brand's 60% white·surface /
   30% ink navy / 10% teal·mint ratio. Only the hero, page-hero and
   dark .cta band are navy, exactly as the original design already
   had them; nothing else is force-darkened.
   ============================================================ */
:root{
  --font-mono:"JetBrains Mono",ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  --glow:0 0 0 1px rgba(45,212,191,.35),0 0 24px rgba(45,212,191,.28);
  --ease-cine:cubic-bezier(.2,.8,.1,1);
  /* Glass used only on the navy zones (hero/page-hero/cta panes) */
  --glass:linear-gradient(150deg,rgba(255,255,255,.14),rgba(255,255,255,.03) 60%,rgba(45,212,191,.05));
}

/* Display typography: bigger, tighter, more confident (colour untouched) */
h1{font-size:clamp(2.9rem,6.6vw,5.9rem);line-height:1.0;letter-spacing:-.045em}
h2{font-size:clamp(2.2rem,4.6vw,3.7rem);line-height:1.04;letter-spacing:-.035em}
h3{letter-spacing:-.015em}
.page-hero h1{font-size:clamp(2.6rem,5.4vw,4.7rem);line-height:1.02}

/* Floating glass capsule nav — a dark pill regardless of what's under
   it (reads fine over both the navy hero and the light sections, like
   the reference clip's bar). Content slides underneath it. */
.nav{background:transparent !important;border:0 !important;box-shadow:none !important;
  -webkit-backdrop-filter:none;backdrop-filter:none;padding-top:14px;margin-bottom:-86px}
.nav__inner{
  min-height:62px;padding:0 10px 0 22px;border-radius:999px;
  background:rgba(9,18,33,.86);
  -webkit-backdrop-filter:blur(18px) saturate(160%);backdrop-filter:blur(18px) saturate(160%);
  border:1px solid rgba(153,240,223,.14);
  box-shadow:0 12px 40px rgba(11,22,40,.22),inset 0 1px 0 rgba(255,255,255,.06);
  max-width:calc(var(--container) - 32px);
}
@media(max-width:767px){.nav{padding-top:10px}.nav__inner{margin-inline:12px;width:auto;padding:0 8px 0 16px;min-height:58px}}
.nav__links a{color:#C7D6E3}
.nav__links a:hover{color:#fff}
.nav__links a[aria-current="page"]{color:var(--blue-tint)}
.nav__links a::after{background:linear-gradient(90deg,#2DD4BF,#99F0DF)}
.nav__right .nav__cta{border-radius:999px}
@media(min-width:960px){.nav__right .nav__cta{min-height:46px;padding:10px 22px;font-size:.94rem}}
.nav__dd-menu,.svc-pop{background:rgba(10,20,36,.97);-webkit-backdrop-filter:blur(16px);backdrop-filter:blur(16px);border-color:rgba(153,240,223,.16);color:#C7D6E3}
.nav__dd-menu a,.svc-pop a,.svc-pop dt,.svc-pop dd{color:#C7D6E3}
.mobile-menu{inset:0 0 0;padding-top:96px;background:rgba(7,14,26,.98);-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px)}
.mobile-menu a{color:#C7D6E3}
/* The full-bleed backdrop above sits above the nav pill (z-index 200 vs
   100), which silently ate taps on the ✕ toggle button once the menu was
   open — there was no way to close it on a touch device. Lift the nav
   pill above the backdrop only while the menu is open, so the button
   stays clickable. */
body[data-menu-open="true"] .nav{z-index:calc(var(--z-menu) + 1)}
/* The 3 bars use currentColor, which styles.css sets to --blue-dark
   (#0B1628, near-black) for the original light-background nav. On our
   dark glass pill that's a near-invisible near-black icon on a
   near-black pill — brighten it to white so it actually reads. */
.menu-btn{border-radius:999px;border-color:rgba(153,240,223,.2);color:#fff}
.menu-btn:hover{background:rgba(255,255,255,.1);border-color:var(--blue-light)}
/* Only the floating NAV pill needs the light wordmark (it's a dark
   glass capsule wherever it sits). The footer keeps its own logo
   (styles.css already points it at the on-light/navy variant) since
   the footer's background is white — the light variant would wash
   out there. */
.nav .brand__logo{content:url("logo-triple-a-ondark.svg")}

/* Heroes sit under the floating nav (already navy by original design) */
.page-hero{padding-top:calc(var(--s-9) + 70px)}
@media(max-width:767px){.page-hero{padding-top:calc(var(--s-8) + 70px)}}
.hero{padding-top:calc(var(--s-8) + 70px)}
/* Inner headers: text on the left, the right side is the 3D stage */
.page-hero__inner{max-width:var(--container)}
.page-hero__inner > *{max-width:780px}

/* ------------------------------------------------------------
   1. WebGL world canvas — confined to the navy zones only.
   Every other section keeps its original opaque light background
   so the 3D world never bleeds into the light 60% of the page.
   ------------------------------------------------------------ */
.world-canvas{
  position:fixed;inset:0;width:100vw;height:100vh;
  z-index:-1;display:block;pointer-events:none;
  opacity:0;transition:opacity 900ms ease-out;
}
.webgl-on .world-canvas{opacity:1}

.webgl-on .hero,
.webgl-on .page-hero,
.webgl-on .cta:not(.cta--light){background:transparent}
.webgl-on .hero__bg{background:transparent}

main > section:not(.hero):not(.page-hero):not(.cta):not(.surface){background:var(--white)}
main > section.surface{background:var(--surface)}

/* Readability scrims over the 3D, heavier where the text sits */
.webgl-on .page-hero::before,
.webgl-on .cta:not(.cta--light)::before{
  content:"";position:absolute;inset:0;pointer-events:none;z-index:0;
}
.webgl-on .page-hero::before{
  background:
    linear-gradient(100deg,rgba(7,14,26,.9) 0%,rgba(7,14,26,.8) 48%,rgba(7,14,26,.4) 68%,rgba(7,14,26,.06) 88%),
    linear-gradient(180deg,rgba(7,14,26,.35),transparent 30%,transparent 70%,rgba(7,14,26,.55));
}
.webgl-on .cta:not(.cta--light)::before{
  background:radial-gradient(760px 420px at 50% 50%,rgba(7,14,26,.78),rgba(7,14,26,.35) 70%,rgba(7,14,26,.15));
}
@media(max-width:979px){
  .webgl-on .page-hero::before{background:linear-gradient(180deg,rgba(7,14,26,.82),rgba(7,14,26,.66))}
}

/* ------------------------------------------------------------
   2. Grid spotlight that follows the cursor on dark sections
   ------------------------------------------------------------ */
.fx-pointer .hero::after,
.fx-pointer .page-hero::after,
.fx-pointer .cta:not(.cta--light)::after{
  background-image:
    linear-gradient(rgba(153,240,223,.09) 1px,transparent 1px),
    linear-gradient(90deg,rgba(153,240,223,.09) 1px,transparent 1px);
  -webkit-mask-image:radial-gradient(420px 320px at var(--mx,30%) var(--my,30%),#000 0%,rgba(0,0,0,.35) 45%,transparent 75%);
          mask-image:radial-gradient(420px 320px at var(--mx,30%) var(--my,30%),#000 0%,rgba(0,0,0,.35) 45%,transparent 75%);
}

/* ------------------------------------------------------------
   3. HUD overlay
   ------------------------------------------------------------ */
.hud{position:absolute;inset:18px;pointer-events:none;z-index:2;
  font-family:var(--font-mono);font-size:.68rem;letter-spacing:.14em;color:rgba(153,240,223,.62)}
.hud__c{position:absolute;width:22px;height:22px;border:1.5px solid rgba(45,212,191,.55)}
.hud__c--tl{top:0;left:0;border-right:0;border-bottom:0}
.hud__c--tr{top:0;right:0;border-left:0;border-bottom:0}
.hud__c--bl{bottom:0;left:0;border-right:0;border-top:0}
.hud__c--br{bottom:0;right:0;border-left:0;border-top:0}
.hud__r{position:absolute;display:inline-flex;align-items:center;gap:8px;white-space:nowrap}
.hud__r em{font-style:normal;color:#E6FFFA;font-variant-numeric:tabular-nums}
.hud__r--tl{top:4px;left:34px}
.hud__r--tr{top:4px;right:34px}
.hud__r--br{bottom:4px;right:34px}
.hud__dot{width:6px;height:6px;border-radius:50%;background:#2DD4BF;box-shadow:0 0 8px #2DD4BF;animation:hudBlink 1.6s steps(2,jump-none) infinite}
@keyframes hudBlink{50%{opacity:.25}}
/* The home hero is pinned under the sticky nav; keep its HUD clear of it */
.hero .hud{inset:96px 22px 22px}
.page-hero .hud{inset:96px 18px 18px}
@media(max-width:700px){
  .hud{inset:10px}
  .hud__r{display:none}
  .hud__c{width:14px;height:14px}
}
.js-immersive .page-hero__inner,
.js-immersive .cta__inner,
.js-immersive .hero__inner{z-index:3}

/* Eyebrows read as machine labels */
.js-immersive .eyebrow{font-family:var(--font-mono);font-weight:500;letter-spacing:.16em}
.js-immersive .eyebrow::before{content:"//";opacity:.55;letter-spacing:0}
.js-immersive .hero__tagline{font-family:var(--font-mono);font-size:.78rem;letter-spacing:.06em}

/* ------------------------------------------------------------
   4. Home hero — cinematic scroll
   --hp (0→1) is written by immersive.js across the pinned run.
   ------------------------------------------------------------ */
.js-immersive .hero__bg{clip-path:none !important}
@media(min-width:980px){
  .js-immersive.js-heroscroll .hero__copy{
    transform:perspective(1400px) rotateY(calc(var(--cx,0) * 3.5deg)) rotateX(calc(var(--cy,0) * -2.5deg))
              translate3d(calc(var(--hp,0) * -40px),calc(var(--hp,0) * -70px),0) scale(calc(1 - var(--hp,0) * .12));
    transition:transform 500ms cubic-bezier(.2,.8,.1,1);
    opacity:calc(1 - var(--hp,0) * 1.35);
    filter:blur(calc(var(--hp,0) * 7px));
    transform-origin:0 50%;
    will-change:transform,opacity;
  }
  .js-immersive.js-heroscroll .scene{
    transform:translate3d(calc(var(--hp,0) * -18%),calc(var(--hp,0) * 4%),0) scale(calc(1 + var(--hp,0) * .42));
    opacity:calc(1 - max(0, var(--hp,0) - .6) * 3.4);
    will-change:transform,opacity;
  }
  /* layers fly apart smoothly as --depth grows */
  .js-immersive.js-heroscroll .pane,
  .js-immersive.js-heroscroll .core,
  .js-immersive.js-heroscroll .beam{transition:transform 120ms linear}
  .js-immersive .hero .hud{opacity:calc(1 - var(--hp,0) * .6)}
}

/* Holographic glass on the hero panes */
.js-immersive .pane{
  background:linear-gradient(145deg,rgba(153,240,223,.16),rgba(45,212,191,.04) 60%,rgba(255,255,255,.06));
  border-color:rgba(153,240,223,.32);
  box-shadow:0 18px 40px rgba(3,22,44,.42),inset 0 0 0 1px rgba(255,255,255,.04),0 0 30px rgba(45,212,191,.12);
  overflow:hidden;
}
.js-immersive .pane::before{            /* chromatic edge */
  content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;
  box-shadow:inset 1.5px 0 0 rgba(153,240,223,.55),inset -1.5px 0 0 rgba(14,148,136,.55);
  mix-blend-mode:screen;
}
.js-immersive .pane::after{             /* scanlines + sweeping light */
  content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;
  background:
    linear-gradient(105deg,transparent 30%,rgba(230,255,250,.22) 48%,transparent 62%) 0 0/250% 100% no-repeat,
    repeating-linear-gradient(180deg,rgba(153,240,223,.07) 0 1px,transparent 1px 3px);
  animation:holoSweep 5.5s var(--ease-cine) infinite;
}
.js-immersive .pane--in2::after{animation-delay:1.1s}
.js-immersive .pane--in3::after{animation-delay:2.2s}
.js-immersive .pane--out::after{animation-delay:.4s}
@keyframes holoSweep{0%{background-position:120% 0,0 0}60%,100%{background-position:-60% 0,0 0}}
.js-immersive .pane--out b{
  background:linear-gradient(180deg,#fff 20%,#99F0DF);-webkit-background-clip:text;background-clip:text;color:transparent;
  text-shadow:0 0 22px rgba(45,212,191,.35);
}
.js-immersive .core__orb{box-shadow:0 0 0 1px rgba(153,240,223,.5),0 0 60px 14px rgba(45,212,191,.5),0 0 120px 30px rgba(14,148,136,.25),0 26px 50px rgba(3,22,44,.5)}

/* Headline accent: slow data-shimmer through the mint */
.js-immersive .hero h1 em:not(:has(.sw)),
.js-immersive .hero h1 em .sw__i{
  background:linear-gradient(100deg,#99F0DF 0%,#99F0DF 35%,#E6FFFA 45%,#2DD4BF 52%,#99F0DF 62%,#99F0DF 100%);
  background-size:250% 100%;
  -webkit-background-clip:text;background-clip:text;color:transparent;
  animation:shimmer 7s ease-in-out infinite;
  filter:drop-shadow(0 0 18px rgba(45,212,191,.28));
}
@keyframes shimmer{0%{background-position:100% 0}55%,100%{background-position:-50% 0}}

/* ------------------------------------------------------------
   5. Inner page header depth (--php 0→1 as it scrolls away)
   ------------------------------------------------------------ */
.js-immersive .page-hero__inner{
  transform:translate3d(0,calc(var(--php,0) * 90px),0);
  opacity:calc(1 - var(--php,0) * 1.15);
}
.js-immersive .page-hero h1{text-shadow:0 0 40px rgba(45,212,191,.18)}

/* ------------------------------------------------------------
   6. 3D reveals — content rises out of depth
   (same .reveal / .is-visible contract as styles.css)
   ------------------------------------------------------------ */
.js-anim .reveal{
  opacity:0;
  transform:perspective(1100px) translate3d(0,46px,-90px) rotateX(14deg);
  transform-origin:50% 100%;
  filter:blur(8px);
}
.js-anim .reveal.is-visible{
  opacity:1;transform:none;filter:none;
  transition:opacity 900ms var(--ease-cine),transform 1100ms var(--ease-cine),filter 900ms var(--ease-cine);
  transition-delay:calc(var(--delay,0ms) + var(--intro-delay,0ms));
}
/* preserve-3d scenes and sticky panels: no blur (it would flatten them) */
.js-anim .hero__visual.reveal,
.js-anim .calc__out.reveal{filter:none}

/* ------------------------------------------------------------
   8. Card tilt + glare + neon edge
   ------------------------------------------------------------ */
.fx-pointer .tilt{position:relative;transform-style:preserve-3d}
.tilt__glare{
  position:absolute;inset:0;border-radius:inherit;pointer-events:none;
  opacity:0;transition:opacity 300ms ease-out;
  background:radial-gradient(420px circle at var(--gx,50%) var(--gy,50%),rgba(45,212,191,.16),rgba(153,240,223,.05) 35%,transparent 60%);
}
.tilt.is-tilting{z-index:5;border-color:rgba(45,212,191,.55) !important;
  box-shadow:0 0 0 1px rgba(45,212,191,.25),0 18px 44px rgba(11,22,40,.14),0 0 38px rgba(45,212,191,.18) !important}
.tilt.is-tilting .tilt__glare{opacity:1}
/* keep the "jobs we've done" popover above neighbouring cards */
.svc-card.tilt:focus-within,.svc-card.tilt:hover{z-index:6}

/* ------------------------------------------------------------
   9. Buttons — magnetic pull + light sheen
   ------------------------------------------------------------ */
.fx-pointer .magnetic{transition:translate 260ms var(--ease-cine),background var(--dur-fast) var(--ease-out),color var(--dur-fast) var(--ease-out),box-shadow var(--dur-mid) var(--ease-out),transform var(--dur-fast) var(--ease-out)}
.js-immersive .btn--primary,.js-immersive .btn--onDark{position:relative;overflow:hidden;isolation:isolate}
.js-immersive .btn--primary::after,.js-immersive .btn--onDark::after{
  content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;
  background:linear-gradient(110deg,transparent 35%,rgba(255,255,255,.35) 50%,transparent 65%) 150% 0/250% 100% no-repeat;
  transition:background-position 700ms var(--ease-cine);
}
.js-immersive .btn--onDark::after{background-image:linear-gradient(110deg,transparent 35%,rgba(45,212,191,.28) 50%,transparent 65%)}
.js-immersive .btn--primary:hover::after,.js-immersive .btn--onDark:hover::after{background-position:-60% 0}
.js-immersive .btn--primary{box-shadow:0 2px 8px rgba(14,148,136,.24),0 8px 24px rgba(14,148,136,.18),0 0 0 1px rgba(45,212,191,.25)}

/* ------------------------------------------------------------
   10. Nav scroll progress
   ------------------------------------------------------------ */
.scroll-progress{
  position:fixed;left:0;right:0;top:0;height:2px;pointer-events:none;z-index:101;
  background:linear-gradient(90deg,#0E9488,#2DD4BF 60%,#99F0DF);
  box-shadow:0 0 10px rgba(45,212,191,.7);
  transform:scaleX(0);transform-origin:0 50%;
}

/* ------------------------------------------------------------
   11. Cinematic entrance + page transitions
   Pure CSS curtains, so they always lift even if a script fails.
   .intro-boot = first page of a visit (the mark assembles, then the
   screen splits open); .intro-wipe = arriving from another page.
   ------------------------------------------------------------ */
:root{--intro-delay:0ms}
.intro-boot{--intro-delay:1450ms}
.intro-wipe{--intro-delay:380ms}
.intro-boot body::after,
.intro-wipe body::after{
  content:"";position:fixed;inset:0;z-index:10000;pointer-events:none;
  background:
    radial-gradient(700px 420px at 50% 50%,rgba(45,212,191,.10),transparent 70%),
    repeating-linear-gradient(180deg,rgba(153,240,223,.035) 0 1px,transparent 1px 4px),
    #070E1A;
}
.intro-boot body::before,
.intro-wipe body::before{
  content:"";position:fixed;left:50%;top:50%;z-index:10001;pointer-events:none;
  background:center/contain no-repeat;
}
.intro-boot body::after{animation:splitOpen 900ms 1250ms cubic-bezier(.76,0,.24,1) forwards}
.intro-boot body::before{
  width:132px;height:118px;margin:-59px 0 0 -66px;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='80 110 350 310'%3E%3Cstyle%3Epath%7Btransform-box:fill-box;transform-origin:50%25 100%25;animation:r .75s cubic-bezier(.2,.8,.1,1) both%7D.b2%7Banimation-delay:.12s%7D.b3%7Banimation-delay:.24s%7D.b4%7Banimation-delay:.4s;transform-origin:50%25 0%7Drect%7Btransform-box:fill-box;transform-origin:0 50%25;animation:l 1s .15s cubic-bezier(.6,0,.2,1) both%7D%40keyframes r%7Bfrom%7Btransform:scaleY(0);opacity:0%7D%7D%40keyframes l%7Bfrom%7Btransform:scaleX(0)%7D%7D%3C/style%3E%3Cpath class='b1' d='M102.4,379.73 L137.68,379.73 L168.27,282.82 L132.98,282.82 Z' fill='%230F7490'/%3E%3Cpath class='b2' d='M160.74,379.73 L196.02,379.73 L250.36,207.54 L215.07,207.54 Z' fill='%2311998B'/%3E%3Cpath class='b3' d='M218.13,379.73 L253.41,379.73 L331.51,132.27 L296.22,132.27 Z' fill='%231FBFA5'/%3E%3Cpath class='b4' d='M296.22,132.27 L331.51,132.27 L409.6,379.73 L374.32,379.73 Z' fill='%232DD4BF'/%3E%3Crect x='102' y='404' width='308' height='3' rx='1.5' fill='%2399F0DF'/%3E%3C/svg%3E");
  filter:drop-shadow(0 0 22px rgba(45,212,191,.45));
  animation:bootMark 1500ms cubic-bezier(.6,0,.2,1) forwards;
}
.intro-wipe body::after{animation:wipeUp 700ms 60ms cubic-bezier(.76,0,.24,1) forwards}
.intro-wipe body::before{
  width:54px;height:44px;margin:-22px 0 0 -27px;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='90 120 330 270'%3E%3Cpath d='M102.4,379.73 L137.68,379.73 L168.27,282.82 L132.98,282.82 Z' fill='%230F7490'/%3E%3Cpath d='M160.74,379.73 L196.02,379.73 L250.36,207.54 L215.07,207.54 Z' fill='%2311998B'/%3E%3Cpath d='M218.13,379.73 L253.41,379.73 L331.51,132.27 L296.22,132.27 Z' fill='%231FBFA5'/%3E%3Cpath d='M296.22,132.27 L331.51,132.27 L409.6,379.73 L374.32,379.73 Z' fill='%232DD4BF'/%3E%3C/svg%3E");
  animation:markOut 380ms 40ms ease-in forwards;
}
/* Fail-safe: once JS marks the entrance done, the curtain is gone no matter
   how slowly a weak device has been playing the animation. */
.intro-done body::after,.intro-done body::before{animation:none;visibility:hidden}
@keyframes splitOpen{
  0%{clip-path:inset(0 0 0 0)}
  100%{clip-path:inset(50% 0 50% 0);visibility:hidden}
}
@keyframes bootMark{
  0%,72%{opacity:1;transform:none}
  100%{opacity:0;transform:scale(1.35);filter:blur(6px) drop-shadow(0 0 22px rgba(45,212,191,.45));visibility:hidden}
}
@keyframes wipeUp{
  0%{clip-path:inset(0 0 0 0)}
  100%{clip-path:inset(0 0 100% 0);visibility:hidden}
}
@keyframes markOut{to{opacity:0;transform:translateY(-14px);visibility:hidden}}

/* Leaving a page: the panel sweeps up from the bottom, then we navigate */
.page-wipe{
  position:fixed;inset:0;z-index:10000;pointer-events:none;
  background:
    radial-gradient(700px 420px at 50% 50%,rgba(45,212,191,.10),transparent 70%),
    repeating-linear-gradient(180deg,rgba(153,240,223,.035) 0 1px,transparent 1px 4px),
    #070E1A;
  clip-path:inset(100% 0 0 0);
  transition:clip-path 460ms cubic-bezier(.76,0,.24,1);
}
.page-wipe i{
  position:absolute;left:50%;top:50%;width:54px;height:44px;margin:-22px 0 0 -27px;
  background:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='90 120 330 270'%3E%3Cpath d='M102.4,379.73 L137.68,379.73 L168.27,282.82 L132.98,282.82 Z' fill='%230F7490'/%3E%3Cpath d='M160.74,379.73 L196.02,379.73 L250.36,207.54 L215.07,207.54 Z' fill='%2311998B'/%3E%3Cpath d='M218.13,379.73 L253.41,379.73 L331.51,132.27 L296.22,132.27 Z' fill='%231FBFA5'/%3E%3Cpath d='M296.22,132.27 L331.51,132.27 L409.6,379.73 L374.32,379.73 Z' fill='%232DD4BF'/%3E%3C/svg%3E") center/contain no-repeat;opacity:0;transition:opacity 200ms 220ms;
}
.is-leaving .page-wipe{clip-path:inset(0 0 0 0)}
.is-leaving .page-wipe i{opacity:1}
.is-leaving main{transition:transform 460ms cubic-bezier(.76,0,.24,1),opacity 460ms;transform:scale(.97) translateY(-12px);opacity:.4}

/* Hero core + beams fly in from depth once the curtain opens.
   `translate` composes with each element's own translateZ positioning.
   The notification cards (.pane--in1/2/3, .pane--out) are handled by
   their own always-on, looping pop-in below instead of this one-shot
   reveal — their first cycle doubles as the intro. */
.js-anim.js-immersive .hero .core,
.js-anim.js-immersive .hero .beam{
  animation:flyIn 1300ms cubic-bezier(.16,1,.3,1) both;
  animation-delay:calc(var(--intro-delay,0ms) + 350ms);
}
.js-anim.js-immersive .hero .core{animation-delay:calc(var(--intro-delay,0ms) + 700ms);animation-name:coreIn}
.js-anim.js-immersive .hero .beam{animation-name:fadeIn;animation-delay:calc(var(--intro-delay,0ms) + 1100ms)}
@keyframes flyIn{from{translate:0 40px 520px;opacity:0}}
@keyframes coreIn{from{translate:0 0 -200px;scale:.2;opacity:0}}
@keyframes fadeIn{from{opacity:0}}

/* Notification cards pop in like phone alerts arriving — one after
   another with a springy overshoot, then hold so they can be read,
   then dismiss together and pause before the cycle repeats. `scale`
   is its own CSS property (distinct from `transform`), so it composes
   cleanly with each pane's static `transform:translateZ(...)` depth
   positioning instead of fighting it. */
.js-immersive .hero .pane--in1{animation:notifPop1 8s ease-in-out calc(var(--intro-delay,0ms) + 300ms) infinite,cardFloat1 3.4s ease-in-out calc(var(--intro-delay,0ms) + 900ms) infinite}
.js-immersive .hero .pane--in2{animation:notifPop2 8s ease-in-out calc(var(--intro-delay,0ms) + 300ms) infinite,cardFloat2 3.8s ease-in-out calc(var(--intro-delay,0ms) + 1300ms) infinite}
.js-immersive .hero .pane--in3{animation:notifPop3 8s ease-in-out calc(var(--intro-delay,0ms) + 300ms) infinite,cardFloat3 4.1s ease-in-out calc(var(--intro-delay,0ms) + 1700ms) infinite}
.js-immersive .hero .pane--out{animation:notifPopOut 8s ease-in-out calc(var(--intro-delay,0ms) + 300ms) infinite,cardFloat4 3.6s ease-in-out calc(var(--intro-delay,0ms) + 2100ms) infinite}
@keyframes notifPop1{
  0%,3.1%{scale:.001;opacity:0}
  7.6%{scale:1.08;opacity:1}
  10%,81.9%{scale:1;opacity:1}
  88.1%,100%{scale:.001;opacity:0}
}
@keyframes notifPop2{
  0%,8.1%{scale:.001;opacity:0}
  12.6%{scale:1.08;opacity:1}
  15%,81.9%{scale:1;opacity:1}
  88.1%,100%{scale:.001;opacity:0}
}
@keyframes notifPop3{
  0%,13.1%{scale:.001;opacity:0}
  17.6%{scale:1.08;opacity:1}
  20%,81.9%{scale:1;opacity:1}
  88.1%,100%{scale:.001;opacity:0}
}
@keyframes notifPopOut{
  0%,21.9%{scale:.001;opacity:0}
  26.8%{scale:1.06;opacity:1}
  29.4%,81.9%{scale:1;opacity:1}
  88.1%,100%{scale:.001;opacity:0}
}
/* A quiet, continuous float on top of the pop/dismiss cycle above —
   different property (`translate`, not `scale`), so the two layer
   together via the multi-value animation shorthand without fighting.
   This is what keeps a landed card feeling alive (gently breathing)
   through its ~6.5s hold, instead of sitting frozen once popped in. */
@keyframes cardFloat1{0%,100%{translate:0 0}50%{translate:0 -5px}}
@keyframes cardFloat2{0%,100%{translate:0 0}50%{translate:0 -6px}}
@keyframes cardFloat3{0%,100%{translate:0 0}50%{translate:0 -4px}}
@keyframes cardFloat4{0%,100%{translate:0 0}50%{translate:0 -5px}}
@media(prefers-reduced-motion:reduce){
  .js-immersive .hero .pane--in1,.js-immersive .hero .pane--in2,
  .js-immersive .hero .pane--in3,.js-immersive .hero .pane--out{animation:none}
}
/* HUD frames draw in */
.js-anim .hud__c{animation:hudIn 900ms cubic-bezier(.16,1,.3,1) both;animation-delay:calc(var(--intro-delay,0ms) + 200ms)}
.js-anim .hud__r{animation:fadeIn 900ms both;animation-delay:calc(var(--intro-delay,0ms) + 700ms)}
@keyframes hudIn{from{opacity:0;scale:2.2}}

/* ------------------------------------------------------------
   13. Kinetic typography — headings rise word by word in 3D
   ------------------------------------------------------------ */
.sw{display:inline-block;vertical-align:bottom;overflow:hidden;perspective:700px;
  padding:.1em .04em .14em;margin:-.1em -.04em -.14em}
.sw__i{display:inline-block;transform-origin:50% 100%}
.js-anim .sw-host .sw__i{
  transform:translate3d(0,108%,0) rotateX(-75deg);opacity:0;
}
.js-anim .reveal.is-visible .sw__i,
.js-anim .reveal.is-visible.sw-host .sw__i{
  transform:none;opacity:1;
  transition:transform 1100ms cubic-bezier(.16,1,.3,1),opacity 700ms ease-out;
  transition-delay:calc(var(--delay,0ms) + var(--intro-delay,0ms) + var(--i,0) * 55ms);
}
/* a split heading animates its words, not itself */
.js-anim .reveal.sw-host{transform:none;filter:none}
.js-anim .reveal.sw-host.is-visible{transition:opacity 300ms}
.js-immersive .hero h1 em:has(.sw){background:none;animation:none;filter:none;color:#99F0DF}
.js-immersive .hero h1 em .sw{filter:drop-shadow(0 0 16px rgba(45,212,191,.25))}

/* ------------------------------------------------------------
   14. Sections lean back into depth as they leave (--ex 0→1)
   ------------------------------------------------------------ */
.depth-exit{
  transform:perspective(1400px) translate3d(0,calc(var(--ex,0) * -46px),calc(var(--ex,0) * -180px)) rotateX(calc(var(--ex,0) * 8deg));
  transform-origin:50% 100%;
  opacity:calc(1 - var(--ex,0) * .75);
}

/* ------------------------------------------------------------
   15. Cursor ring (fine pointers; native cursor is kept)
   ------------------------------------------------------------ */
.cursor-ring{
  position:fixed;left:0;top:0;z-index:9000;pointer-events:none;
  width:0;height:0;
}
.cursor-ring::before{
  content:"";position:absolute;left:-17px;top:-17px;width:34px;height:34px;border-radius:50%;
  border:1.5px solid #fff;mix-blend-mode:difference;
  transition:transform 380ms cubic-bezier(.16,1,.3,1),opacity 200ms,background-color 300ms;
}
.cursor-ring.is-link::before{transform:scale(1.7);background:rgba(255,255,255,.12)}
.cursor-ring:not(.is-live)::before,.cursor-ring.is-text::before,.cursor-ring.is-out::before{opacity:0}

/* ------------------------------------------------------------
   12. Reduced motion: static and calm
   ------------------------------------------------------------ */
@media (prefers-reduced-motion:reduce){
  .js-anim .reveal{opacity:1;transform:none;filter:none}
  .js-immersive .pane::after,.js-immersive .hero h1 em,.hud__dot{animation:none !important}
  .js-immersive .page-hero__inner{transform:none;opacity:1}
  .depth-exit{transform:none;opacity:1}
  .cursor-ring,.page-wipe{display:none}
}

/* ------------------------------------------------------------
   16. Hero stage: the animated Triple A mark (WebGL glass-and-metal
   logo sculpture) IS the hero visual. The site's own CSS glass scene
   (input panes → beams → core → outcome card) steps aside for it here
   — it stays defined for the reduced-motion / no-WebGL fallback below.
   ------------------------------------------------------------ */
@media(min-width:980px){
  .hero__visual::before{
    content:"";position:absolute;inset:-15%;z-index:-1;pointer-events:none;
    background:radial-gradient(closest-side,rgba(45,212,191,.16),transparent 72%);
    filter:blur(20px);
  }
}
/* The hero's own CSS scene (this exact markup) is the source of truth
   for the notification-card visual on every screen size — the WebGL
   world no longer draws its own copy over it (see world.js), so this
   never needs hiding. */

/* ------------------------------------------------------------
   17. Scene index (right edge, wide screens)
   ------------------------------------------------------------ */
.scene-index{position:fixed;right:14px;top:50%;transform:translateY(-50%);z-index:90;
  display:none;flex-direction:column;gap:2px;
  padding:10px 8px;border-radius:999px;
  background:rgba(9,18,33,.5);
  -webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);
  border:1px solid rgba(153,240,223,.14);
  box-shadow:0 8px 24px rgba(11,22,40,.16);
}
@media(min-width:1180px){.scene-index{display:flex}}
.scene-index button{
  display:flex;align-items:center;justify-content:flex-end;gap:10px;
  background:none;border:0;padding:6px 4px;cursor:pointer;
  font-family:var(--font-mono);font-size:.66rem;letter-spacing:.12em;color:rgba(199,214,227,.55);
}
.scene-index i{display:block;width:14px;height:1px;background:currentColor;transition:width 400ms cubic-bezier(.16,1,.3,1)}
.scene-index button:hover,.scene-index button.is-active{color:#99F0DF}
.scene-index button.is-active i{width:34px;box-shadow:0 0 8px rgba(45,212,191,.8)}
.scene-index button:focus-visible{outline:2px solid var(--blue-light);outline-offset:2px}
.js-anim .scene-index{animation:fadeIn 900ms both;animation-delay:calc(var(--intro-delay,0ms) + 900ms)}
