/* ==========================================================================
   ANIMATIONS — keyframes + scroll-reveal states
   Everything here is neutralised by the reduced-motion block at the bottom.
   ========================================================================== */

/* ==========================================================================
   1. SCROLL REVEAL
   ========================================================================== */
[data-animate] {
  opacity: 0;
  transition:
    opacity var(--dur-reveal) var(--ease-out),
    transform var(--dur-reveal) var(--ease-out),
    clip-path var(--dur-reveal) var(--ease-out),
    filter var(--dur-reveal) var(--ease-out);
  transition-delay: calc(var(--i, 0) * 70ms);
}

[data-animate="fade-up"]     { transform: translate3d(0, 42px, 0); }
[data-animate="fade-down"]   { transform: translate3d(0, -32px, 0); }
[data-animate="fade-right"]  { transform: translate3d(-48px, 0, 0); }
[data-animate="fade-left"]   { transform: translate3d(48px, 0, 0); }
[data-animate="scale-in"]    { transform: scale(0.90); }
[data-animate="blur-in"]     { filter: blur(14px); transform: translate3d(0, 20px, 0); }
/* The clip is applied to the INNER image, never to the observed element.
   Clipping the observed element to zero width makes its IntersectionObserver
   intersection rect empty, so it would never be reported as visible and would
   never receive .in-view — a deadlock that leaves the image permanently hidden. */
[data-animate="clip-reveal"] { opacity: 1; }
[data-animate="clip-reveal"] img {
  clip-path: inset(0 100% 0 0);
  transition: clip-path var(--dur-reveal) var(--ease-out);
  transition-delay: calc(var(--i, 0) * 70ms);
}
[data-animate="clip-reveal"].in-view img { clip-path: inset(0 0 0 0); }
[data-animate="rise-3d"]     { transform: perspective(900px) rotateX(-16deg) translate3d(0, 46px, 0); transform-origin: bottom; }
[data-animate="fade"]        { /* opacity only */ }

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

/* ==========================================================================
   2. KEYFRAMES
   ========================================================================== */

/* Hero headline words rising in 3D */
@keyframes word-up {
  from { transform: translateY(100%) rotateX(-70deg); opacity: 0; }
  to   { transform: translateY(0) rotateX(0); opacity: 1; }
}

/* Above-the-fold hero content animates on LOAD, not on scroll. A scroll observer
   would leave the primary CTA invisible on short viewports where it starts just
   below the fold and the user never scrolls. */
[data-hero-in] {
  opacity: 0;
  transform: translate3d(0, 26px, 0);
}
.is-loaded [data-hero-in] {
  animation: hero-in 780ms var(--ease-out) forwards;
  animation-delay: calc(var(--i, 0) * 110ms + 480ms);
}
@keyframes hero-in {
  to { opacity: 1; transform: translate3d(0, 0, 0); }
}

/* The gradient phrase animates as a single unit (see animations.js) so that
   background-clip:text keeps painting and the phrase can still wrap. */
.hero__title .hl-anim {
  display: inline;
  opacity: 0;
  will-change: opacity, transform;
}
.is-loaded .hero__title .hl-anim {
  animation: phrase-up 900ms var(--ease-out) forwards;
  animation-delay: calc(var(--i, 0) * 55ms + 250ms);
}
@keyframes phrase-up {
  from { opacity: 0; transform: translateY(24px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Mobile menu rows */
@keyframes menu-in {
  from { opacity: 0; transform: translateY(18px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Gradient sweep across text / borders */
@keyframes sweep {
  0%   { background-position: 0% 50%; }
  50%  { background-position: 100% 50%; }
  100% { background-position: 0% 50%; }
}

/* Continuous rotation — hero gear, spinner */
@keyframes spin {
  to { transform: rotate(360deg); }
}

/* Client marquee */
@keyframes marquee {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}

/* Ambient floating wireframes */
@keyframes float {
  0%   { transform: translate3d(0, 0, 0) rotate(0deg); }
  50%  { transform: translate3d(18px, -26px, 0) rotate(7deg); }
  100% { transform: translate3d(-14px, 20px, 0) rotate(-5deg); }
}

/* Preloader logo */
@keyframes breathe {
  0%, 100% { transform: scale(1); opacity: 0.85; }
  50%      { transform: scale(1.06); opacity: 1; }
}

/* Scroll cue line */
@keyframes cue {
  0%   { transform: scaleY(0); opacity: 0; }
  40%  { transform: scaleY(1); opacity: 1; }
  100% { transform: scaleY(1); opacity: 0; }
}

/* WhatsApp attention ring */
@keyframes pulse-ring {
  0%       { transform: translate(-50%,-50%) scale(0.72); opacity: 0.85; }
  55%, 100%{ transform: translate(-50%,-50%) scale(1.7);  opacity: 0; }
}

/* Button click ripple */
@keyframes ripple-out {
  to { transform: scale(3.2); opacity: 0; }
}

/* Invalid field */
@keyframes shake {
  0%, 100%     { transform: translateX(0); }
  20%, 60%     { transform: translateX(-6px); }
  40%, 80%     { transform: translateX(6px); }
}

/* Star fill on entry */
@keyframes star-pop {
  from { transform: scale(0) rotate(-40deg); opacity: 0; }
  to   { transform: scale(1) rotate(0); opacity: 1; }
}
.in-view .stars svg {
  animation: star-pop 420ms var(--ease-spring) backwards;
}
.in-view .stars svg:nth-child(1) { animation-delay: 60ms; }
.in-view .stars svg:nth-child(2) { animation-delay: 130ms; }
.in-view .stars svg:nth-child(3) { animation-delay: 200ms; }
.in-view .stars svg:nth-child(4) { animation-delay: 270ms; }
.in-view .stars svg:nth-child(5) { animation-delay: 340ms; }

/* Ken Burns on static hero imagery */
@keyframes ken-burns {
  from { transform: scale(1.0) translate3d(0, 0, 0); }
  to   { transform: scale(1.12) translate3d(-1.5%, -1.5%, 0); }
}
.ken-burns { animation: ken-burns 26s var(--ease-inout) infinite alternate; }

/* ==========================================================================
   3. REDUCED MOTION — hard stop
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  [data-animate],
  [data-animate="clip-reveal"] img {
    opacity: 1 !important;
    transform: none !important;
    filter: none !important;
    clip-path: none !important;
    transition: none !important;
  }

  [data-hero-in],
  .hero__title .word > span,
  .hero__title .hl-anim {
    animation: none !important;
    transform: none !important;
    opacity: 1 !important;
  }

  .mobile-menu__link { opacity: 1 !important; transform: none !important; animation: none !important; }

  .hero__gear,
  .float-shape,
  .marquee__track,
  .ken-burns,
  .loader__logo,
  .scroll-cue__line,
  .mobile-bar__btn--wa::before,
  .modal__card::before,
  .hero__title .hl,
  .in-view .stars svg {
    animation: none !important;
  }

  .hero__title .hl {
    background: none;
    -webkit-text-fill-color: currentColor;
    color: var(--azure);
  }

  /* Freeze the marquee mid-track so content stays readable */
  .marquee__track { transform: none !important; }

  .step:hover .step__inner,
  .step:focus-within .step__inner { transform: none !important; }
  .step__face--back { display: none; }

  .timeline.in-view .timeline__line::after { transform: scaleX(1) !important; transition: none !important; }

  .tilt { transform: none !important; }
  .tilt__sheen { display: none; }

  .progress { display: none; }
  .cursor, .cursor-dot { display: none !important; }
  .loader { display: none !important; }
}
