/* =========================================================
   APTIKA — ANIMATION UTILITIES
   Scroll-reveal states set by JS (animations.js) via
   IntersectionObserver / GSAP ScrollTrigger toggling
   these classes. Kept in CSS so they degrade cleanly
   with prefers-reduced-motion.
   ========================================================= */

[data-reveal]{
  opacity: 0;
  transform: translateY(36px);
  transition: opacity 1s var(--ease), transform 1s var(--ease);
  will-change: transform, opacity;
}
[data-reveal].is-visible{
  opacity: 1;
  transform: translateY(0);
}

[data-reveal="fade"]{ transform: none; }

[data-reveal="scale"]{ transform: scale(.96); }
[data-reveal="scale"].is-visible{ transform: scale(1); }

[data-reveal-stagger] > *{
  opacity: 0;
  transform: translateY(28px);
  transition: opacity .8s var(--ease), transform .8s var(--ease);
}
[data-reveal-stagger].is-visible > *{ opacity: 1; transform: translateY(0); }
[data-reveal-stagger].is-visible > *:nth-child(1){ transition-delay: 0s; }
[data-reveal-stagger].is-visible > *:nth-child(2){ transition-delay: .08s; }
[data-reveal-stagger].is-visible > *:nth-child(3){ transition-delay: .16s; }
[data-reveal-stagger].is-visible > *:nth-child(4){ transition-delay: .24s; }
[data-reveal-stagger].is-visible > *:nth-child(5){ transition-delay: .32s; }
[data-reveal-stagger].is-visible > *:nth-child(6){ transition-delay: .4s; }

/* line-split headline reveal: JS wraps words in <span class="line-word"> */
.split-line{ overflow: hidden; display: block; }
.line-word{
  display: inline-block;
  transform: translateY(110%);
  transition: transform .9s var(--ease);
}
.split-line.is-visible .line-word{ transform: translateY(0); }

/* image clip reveal: ivory panel slides away to uncover image */
.clip-reveal{ position: relative; overflow: hidden; }
.clip-reveal::before{
  content: "";
  position: absolute; inset: 0;
  background: var(--ivory);
  transform-origin: right;
  transform: scaleX(1);
  transition: transform 1.1s var(--ease);
  z-index: 2;
}
.clip-reveal.is-visible::before{ transform: scaleX(0); }
.clip-reveal img{
  transform: scale(1.12);
  transition: transform 1.6s var(--ease);
}
.clip-reveal.is-visible img{ transform: scale(1); }

/* subtle parallax hook — JS sets --py via scroll progress */
[data-parallax]{ transform: translateY(var(--py, 0)); }

/* hero entrance sequence */
.hero__label,
.hero__sub,
.hero__actions{
  opacity: 0;
  transform: translateY(20px);
  transition: opacity 1s var(--ease), transform 1s var(--ease);
}
.hero.is-loaded .hero__label{ opacity: 1; transform: none; transition-delay: .5s; }
.hero.is-loaded .hero__title .line span{ transition-delay: .3s; }
.hero.is-loaded .hero__sub{ opacity: 1; transform: none; transition-delay: .85s; }
.hero.is-loaded .hero__actions{ opacity: 1; transform: none; transition-delay: 1.05s; }

.hero__title .line span{
  transform: translateY(100%);
  transition: transform 1s var(--ease);
}
.hero.is-loaded .hero__title .line span{ transform: translateY(0); }

.hero__media img{
  transition: transform 1.8s var(--ease);
}
.hero.is-loaded .hero__media img{ transform: scale(1); }

/* ---- hero Ken Burns ----
   The entrance transition above settles the image from its initial
   scale(1.08) down to scale(1) over 1.8s. Once that transition's
   animation-delay elapses, this infinite keyframe loop quietly takes
   over the same property for a slow, continuous breathing zoom —
   the two never overlap, so there's no fighting over `transform`. */
@keyframes hero-kenburns{
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.08); }
}
.hero.is-loaded .hero__media img{
  animation: hero-kenburns 26s var(--ease) infinite;
  animation-delay: 1.8s;
}

/* ---- scroll cue pulse ---- */
@keyframes scroll-cue-pulse{
  0%, 100% { opacity: .55; transform: translateY(0); }
  50%      { opacity: 1; transform: translateY(5px); }
}
.hero__scroll{ animation: scroll-cue-pulse 2.6s ease-in-out infinite; }

/* ---- line-by-line paragraph reveal ----
   animations.js wraps eligible <p data-reveal> text in .reveal-word
   spans and drives them with a GSAP stagger (y:24→0, opacity 0→1,
   a beat apart per word) instead of the single-block fade above.
   The parent is neutralised here so the two systems don't double up. */
.reveal-lines{ opacity: 1 !important; transform: none !important; }
.reveal-word{ display: inline-block; will-change: transform, opacity; }

/* page fade-in on load */
body{ opacity: 1; }
body.is-transitioning{ opacity: 1; }

/* respect reduced motion globally */
@media (prefers-reduced-motion: reduce){
  *, *::before, *::after{
    animation-duration: .001s !important;
    animation-iteration-count: 1 !important;
    transition-duration: .15s !important;
    scroll-behavior: auto !important;
  }
  [data-reveal], [data-reveal-stagger] > *, .line-word, .clip-reveal img, .clip-reveal::before,
  .hero__label, .hero__sub, .hero__actions, .hero__title .line span, .hero__media img,
  .hero__scroll, .reveal-word{
    transform: none !important;
    opacity: 1 !important;
  }
  .cursor{ display: none !important; }
}
