/* ==========================================================================
   HELIOGRAPH — motion layer
   Two independent systems, deliberately kept apart:
   • CSS transitions, toggled by an `.is-in` class (IntersectionObserver or
     ScrollTrigger). Used for every generic reveal.
   • GSAP tweens, used for split text, parallax, counters, the horizontal
     case-study rail and the ambient loops. Nothing in this file transitions a
     property GSAP animates — that fight is always lost by the CSS.
   ========================================================================== */

/* --- reveal primitives ---------------------------------------------------- */
[data-reveal]{
  opacity:0;
  transition:
    opacity .9s var(--ease),
    transform .9s var(--ease),
    filter .9s var(--ease),
    clip-path 1.05s var(--ease);
  transition-delay:var(--reveal-delay,0ms);
  will-change:opacity,transform;
}
[data-reveal="up"]{transform:translate3d(0,32px,0)}
[data-reveal="down"]{transform:translate3d(0,-24px,0)}
[data-reveal="left"]{transform:translate3d(-32px,0,0)}
[data-reveal="right"]{transform:translate3d(32px,0,0)}
[data-reveal="scale"]{transform:scale(.94)}
[data-reveal="blur"]{filter:blur(12px);transform:translate3d(0,18px,0)}
[data-reveal="clip"]{clip-path:inset(0 0 100% 0);opacity:1}
[data-reveal="clip-x"]{clip-path:inset(0 100% 0 0);opacity:1}
[data-reveal="mask"]{clip-path:inset(0 0 100% 0);transform:scale(1.06);opacity:1}

[data-reveal].is-in{
  opacity:1;
  transform:none;
  filter:none;
  clip-path:inset(0 0 0 0);
}

/* stagger helper — children reveal in sequence */
[data-stagger] > *{
  opacity:0;
  transform:translate3d(0,26px,0);
  transition:opacity .8s var(--ease),transform .8s var(--ease);
}
[data-stagger].is-in > *{opacity:1;transform:none}
[data-stagger].is-in > *:nth-child(1){transition-delay:.02s}
[data-stagger].is-in > *:nth-child(2){transition-delay:.09s}
[data-stagger].is-in > *:nth-child(3){transition-delay:.16s}
[data-stagger].is-in > *:nth-child(4){transition-delay:.23s}
[data-stagger].is-in > *:nth-child(5){transition-delay:.3s}
[data-stagger].is-in > *:nth-child(6){transition-delay:.37s}
[data-stagger].is-in > *:nth-child(7){transition-delay:.44s}
[data-stagger].is-in > *:nth-child(8){transition-delay:.51s}
[data-stagger].is-in > *:nth-child(n+9){transition-delay:.58s}

/* failsafe — if the motion layer never boots, show everything */
html.reveal-all [data-reveal],
html.reveal-all [data-stagger] > *{
  opacity:1 !important;
  transform:none !important;
  filter:none !important;
  clip-path:none !important;
}

/* --- split text ----------------------------------------------------------- */
/* The splitter wraps lines in .line > span. GSAP owns the span transform, so
   no transition is declared here — only the mask. */
.split-line{display:block;overflow:hidden}
.split-line__inner{display:block;will-change:transform}
/* Never put background-clip:text on a split target — the wrapper carries it. */

/* --- keyframes ------------------------------------------------------------ */
@keyframes link-wipe{
  0%{transform:scaleX(1);transform-origin:right}
  49%{transform:scaleX(0);transform-origin:right}
  50%{transform:scaleX(0);transform-origin:left}
  100%{transform:scaleX(1);transform-origin:left}
}

@keyframes check-draw{to{stroke-dashoffset:0}}

@keyframes cue-drop{
  0%{transform:translateY(-100%)}
  60%,100%{transform:translateY(340%)}
}

@keyframes ping{
  0%{transform:scale(1);opacity:.9}
  70%,100%{transform:scale(4.2);opacity:0}
}

@keyframes prism-tick{
  0%{transform:rotate(0)}
  55%{transform:rotate(-14deg)}
  100%{transform:rotate(0)}
}

@keyframes drift{
  0%{transform:translate3d(0,0,0) scale(1)}
  50%{transform:translate3d(2%,-3%,0) scale(1.06)}
  100%{transform:translate3d(0,0,0) scale(1)}
}

@keyframes spectrum-slide{
  0%{background-position:0% 50%}
  100%{background-position:200% 50%}
}

@keyframes marquee-fallback{
  from{transform:translate3d(0,0,0)}
  to{transform:translate3d(-50%,0,0)}
}

@keyframes float-soft{
  0%,100%{transform:translateY(0)}
  50%{transform:translateY(-10px)}
}

@keyframes fade-up-in{
  from{opacity:0;transform:translate3d(0,18px,0)}
  to{opacity:1;transform:none}
}

/* --- ambient loops -------------------------------------------------------- */
/* The CTA aurora drifts on its own; GSAP adds pointer parallax on top by
   translating the parent, never this element. */
.cta__aurora{animation:drift 22s var(--ease-soft) infinite}

.spectrum-run{
  background:linear-gradient(90deg,var(--s1),var(--s2),var(--s3),var(--s4),var(--s5),var(--s6),var(--s1));
  background-size:200% 100%;
  animation:spectrum-slide 9s linear infinite;
}

.float-soft{animation:float-soft 6s var(--ease-soft) infinite}

/* marquee: GSAP drives it when present, CSS keeps it alive when it is not */
html.no-gsap .marquee__track{animation:marquee-fallback 38s linear infinite}
.marquee:hover .marquee__track{animation-play-state:paused}

/* --- particles ------------------------------------------------------------ */
.particles{
  position:absolute;inset:0;z-index:-1;pointer-events:none;
  opacity:.6;
}

/* --- hover / interaction motion ------------------------------------------- */
.lift{transition:transform .5s var(--ease),box-shadow .5s var(--ease)}
.lift:hover{transform:translateY(-5px);box-shadow:var(--shadow-lg)}

.tilt{transform-style:preserve-3d;will-change:transform}
.tilt__inner{transform:translateZ(28px)}

.hover-iris{position:relative;overflow:hidden}
.hover-iris::before{
  content:"";position:absolute;inset:0;z-index:1;
  background:var(--spectrum);
  opacity:0;
  clip-path:circle(0% at 50% 50%);
  transition:clip-path .7s var(--ease),opacity .5s var(--ease);
  mix-blend-mode:overlay;
}
.hover-iris:hover::before{clip-path:circle(85% at 50% 50%);opacity:.5}

/* underline that wipes right-to-left then in from the left */
.wipe-underline{position:relative}
.wipe-underline::after{
  content:"";position:absolute;left:0;bottom:-2px;width:100%;height:1px;
  background:currentColor;transform:scaleX(0);transform-origin:right;
  transition:transform .5s var(--ease);
}
.wipe-underline:hover::after{transform:scaleX(1);transform-origin:left}

/* --- page transition ------------------------------------------------------ */
html.is-leaving{cursor:progress}

/* --- reduced motion ------------------------------------------------------- *
   Everything above collapses to a plain, fully visible page. JS reads the same
   media query and skips GSAP timelines, so nothing is left mid-tween.        */
@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{
    animation-duration:.001ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.001ms !important;
    scroll-behavior:auto !important;
  }
  [data-reveal],[data-stagger] > *{
    opacity:1 !important;transform:none !important;
    filter:none !important;clip-path:none !important;
  }
  .split-line__inner{transform:none !important}
  .cta__aurora,.spectrum-run,.float-soft,.marquee__track{animation:none !important}
  .scroll-cue__track::after{animation:none;transform:translateY(0)}
  .studio-map__pin i{animation:none;opacity:0}
  .preloader{display:none !important}
  .curtain{display:none !important}
  .cursor{display:none !important}
  .hero__bg video{display:none}
  .work__media img,.post__media img,.case__media img,.member__media img{transform:none !important}
}
