/* ==========================================================================
   Animations - 1:1 port of the IX3 interaction data
   (extracted from the exported runtime; see js/main.js for the triggers).

   Conventions
   - `html.js` gates every initial "hidden" state so the site is fully visible
     without JavaScript.
   - All motion is wrapped in prefers-reduced-motion: no-preference. The
     original interactions declared "don't animate" / "skip to end" for
     reduced motion, which resolves to the same visible end state.
   - Durations/eases/delays come straight from the interaction data. Stagger
     delays that depend on element counts are set inline by js/main.js via
     `transition-delay`.
   ========================================================================== */

:root {
  /* GSAP eases used by the original timelines, as cubic beziers */
  --ease-custom: cubic-bezier(0.19, 0.65, 0.42, 0.99); /* authored CustomEase */
  --ease-quad-out: cubic-bezier(0.25, 0.46, 0.45, 0.94); /* power1.out (GSAP default) */
  --ease-quad-in-out: cubic-bezier(0.455, 0.03, 0.515, 0.955); /* power1.inOut */
  --ease-cubic-out: cubic-bezier(0.215, 0.61, 0.355, 1); /* power2.out / outCubic */
  --ease-cubic-in-out: cubic-bezier(0.645, 0.045, 0.355, 1); /* power2.inOut */
  --ease-quint-out: cubic-bezier(0.23, 1, 0.32, 1); /* power4.out */
}

/* Font rendering (carried over from the previous shared stylesheet) */
* {
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* Generic form state helper (success/error blocks toggled by JS) */
.w-form-done.is-visible,
.w-form-fail.is-visible {
  display: block;
}

/* Split-text: wrappers produced by js/main.js */
.split-line {
  display: block;
}
.split-word,
.split-char {
  display: inline-block;
  white-space: pre;
}

@media (prefers-reduced-motion: no-preference) {
  /* ========================================================================
     LOAD ANIMATIONS - play once `html.is-loaded` is set (window load)
     ======================================================================== */

  /* Navbar slide-down: y -25% -> 0, opacity 0 -> 1, 1.3s power4.out.
     The original interaction was disabled below 992px. */
  @media (min-width: 992px) {
    html.js:not(.is-loaded) .navbar {
      opacity: 0;
      transform: translateY(-25%);
    }
    html.js .navbar {
      transition:
        opacity 1.3s var(--ease-quint-out),
        transform 1.3s var(--ease-quint-out);
    }
  }

  /* load-label: chars fade in (0.5s, staggered over 0.3s, +0.1s offset).
     Elements with child markup are animated per-child (.split-block) instead
     of per-char - text splitting would destroy the markup. */
  html.js [data-animate='load-label']:not(.split-ready) {
    opacity: 0;
  }
  html.js [data-animate='load-label'] .split-char,
  html.js [data-animate='load-label'] > .split-block {
    opacity: 0;
    transition: opacity 0.5s var(--ease-quad-out);
  }
  html.js.is-loaded [data-animate='load-label'] .split-char,
  html.js.is-loaded [data-animate='load-label'] > .split-block {
    opacity: 1;
  }

  /* load-fade-down: lines fade in 0.6s + slide from -1rem 0.8s (custom ease) */
  html.js [data-animate='load-fade-down']:not(.split-ready) {
    opacity: 0;
  }
  html.js [data-animate='load-fade-down'] .split-line,
  html.js [data-animate='load-fade-down'] > .split-block {
    opacity: 0;
    transform: translateY(-1rem);
    transition:
      opacity 0.6s var(--ease-quad-out),
      transform 0.8s var(--ease-custom);
  }
  html.js.is-loaded [data-animate='load-fade-down'] .split-line,
  html.js.is-loaded [data-animate='load-fade-down'] > .split-block {
    opacity: 1;
    transform: translateY(0);
  }

  /* load-fade-down-2: element-level fade 0.4s + slide from -1rem 0.8s */
  html.js [data-animate='load-fade-down-2'] {
    opacity: 0;
    transform: translateY(-1rem);
    transition:
      opacity 0.4s var(--ease-quad-out),
      transform 0.8s var(--ease-custom);
  }
  html.js.is-loaded [data-animate='load-fade-down-2'] {
    opacity: 1;
    transform: translateY(0);
  }

  /* load-fade-up: fade 0.4s (custom ease) + rise from 1rem 0.5s */
  html.js [data-animate='load-fade-up'] {
    opacity: 0;
    transform: translateY(1rem);
    transition:
      opacity 0.4s var(--ease-custom),
      transform 0.5s var(--ease-custom);
  }
  html.js.is-loaded [data-animate='load-fade-up'] {
    opacity: 1;
    transform: translateY(0);
  }

  /* load-fade-in: fade 0.4s */
  html.js [data-animate='load-fade-in'] {
    opacity: 0;
    transition: opacity 0.4s var(--ease-quad-out);
  }
  html.js.is-loaded [data-animate='load-fade-in'] {
    opacity: 1;
  }

  /* load-fade-in-delay: fade 0.4s, 0.3s after load */
  html.js [data-animate='load-fade-in-delay'] {
    opacity: 0;
    transition: opacity 0.4s var(--ease-quad-out) 0.3s;
  }
  html.js.is-loaded [data-animate='load-fade-in-delay'] {
    opacity: 1;
  }

  /* load-rotate: fade + rotate from -45deg, 0.5s, 0.05s after load */
  html.js [data-animate='load-rotate'] {
    opacity: 0;
    transform: rotate(-45deg);
    transition:
      opacity 0.5s var(--ease-quad-out) 0.05s,
      transform 0.5s var(--ease-quad-out) 0.05s;
  }
  html.js.is-loaded [data-animate='load-rotate'] {
    opacity: 1;
    transform: rotate(0deg);
  }

  /* word-swap (hero headline): all words share one absolute stack + invisible sizer */
  .home-header_words {
    position: relative;
    display: inline-block;
    vertical-align: bottom;
  }
  .home-header_sizer {
    visibility: hidden;
    display: block;
    letter-spacing: -0.06em;
    pointer-events: none;
    user-select: none;
  }
  .home-header_word {
    position: absolute;
    left: 0;
    bottom: 0;
    margin: 0;
    white-space: nowrap;
  }

  /* FOUC guard: only the first word shows until JS arms the swap */
  html.js .home-header_swap:not(.is-swap-armed) [data-animate='word-swap-2'],
  html.js .home-header_swap:not(.is-swap-armed) [data-animate='word-swap-3'] {
    visibility: hidden;
  }

  [data-animate^='word-swap'] .split-char {
    transition:
      opacity 0.25s var(--ease-quad-out),
      transform 0.25s var(--ease-quad-out);
  }
  [data-animate^='word-swap'].swap-hidden {
    visibility: hidden;
  }
  [data-animate^='word-swap'].swap-hidden .split-char {
    opacity: 0;
    transform: translateY(0.75rem);
    transition: none;
  }
  [data-animate^='word-swap'].swap-out .split-char {
    opacity: 0;
    transform: translateY(-0.75rem);
  }

  /* ========================================================================
     SCROLL-INTO-VIEW REVEALS - IntersectionObserver adds .is-inview
     (original ScrollTrigger: start "top 95%", play once)
     ======================================================================== */

  /* reveal-heading: lines rise from 1.5rem 0.8s (custom) + fade 0.4s */
  html.js [data-animate='reveal-heading']:not(.split-ready) {
    opacity: 0;
  }
  html.js [data-animate='reveal-heading'] .split-line,
  html.js [data-animate='reveal-heading'] > .split-block {
    opacity: 0;
    transform: translateY(1.5rem);
    transition:
      opacity 0.4s var(--ease-quad-out),
      transform 0.8s var(--ease-custom);
  }
  html.js [data-animate='reveal-heading'].is-inview .split-line,
  html.js [data-animate='reveal-heading'].is-inview > .split-block {
    opacity: 1;
    transform: translateY(0);
  }

  /* reveal-text: lines fade 0.4s + rise from 1.5rem 0.8s */
  html.js [data-animate='reveal-text']:not(.split-ready) {
    opacity: 0;
  }
  html.js [data-animate='reveal-text'] .split-line,
  html.js [data-animate='reveal-text'] > .split-block {
    opacity: 0;
    transform: translateY(1.5rem);
    transition:
      opacity 0.4s var(--ease-quad-out),
      transform 0.8s var(--ease-custom);
  }
  html.js [data-animate='reveal-text'].is-inview .split-line,
  html.js [data-animate='reveal-text'].is-inview > .split-block {
    opacity: 1;
    transform: translateY(0);
  }

  /* reveal-label: chars fade 0.5s, staggered over 0.35s */
  html.js [data-animate='reveal-label']:not(.split-ready) {
    opacity: 0;
  }
  html.js [data-animate='reveal-label'] .split-char,
  html.js [data-animate='reveal-label'] > .split-block {
    opacity: 0;
    transition: opacity 0.5s var(--ease-quad-out);
  }
  html.js [data-animate='reveal-label'].is-inview .split-char,
  html.js [data-animate='reveal-label'].is-inview > .split-block {
    opacity: 1;
  }

  /* reveal-rotate: chars fade + rotate from -45deg, staggered over 0.35s */
  html.js [data-animate='reveal-rotate']:not(.split-ready) {
    opacity: 0;
  }
  html.js [data-animate='reveal-rotate'] .split-char,
  html.js [data-animate='reveal-rotate'] > .split-block {
    opacity: 0;
    transform: rotate(-45deg);
    transition:
      opacity 0.5s var(--ease-quad-out),
      transform 0.5s var(--ease-quad-out);
  }
  html.js [data-animate='reveal-rotate'].is-inview .split-char,
  html.js [data-animate='reveal-rotate'].is-inview > .split-block {
    opacity: 1;
    transform: rotate(0deg);
  }

  /* reveal-fade-up-1..4: fade 0.3s (power1.inOut) + rise from 2rem 0.75s
     (custom ease); 1-4 differ only in delay: 0 / 0.1s / 0.2s / 0.3s */
  html.js [data-animate='reveal-fade-up-1'],
  html.js [data-animate='reveal-fade-up-2'],
  html.js [data-animate='reveal-fade-up-3'],
  html.js [data-animate='reveal-fade-up-4'] {
    opacity: 0;
    transform: translateY(2rem);
    transition:
      opacity 0.3s var(--ease-quad-in-out),
      transform 0.75s var(--ease-custom);
  }
  html.js [data-animate='reveal-fade-up-2'] {
    transition-delay: 0.1s, 0.1s;
  }
  html.js [data-animate='reveal-fade-up-3'] {
    transition-delay: 0.2s, 0.2s;
  }
  html.js [data-animate='reveal-fade-up-4'] {
    transition-delay: 0.3s, 0.3s;
  }
  html.js [data-animate='reveal-fade-up-1'].is-inview,
  html.js [data-animate='reveal-fade-up-2'].is-inview,
  html.js [data-animate='reveal-fade-up-3'].is-inview,
  html.js [data-animate='reveal-fade-up-4'].is-inview {
    opacity: 1;
    transform: translateY(0);
  }

  /* reveal-fade-up-stagger: direct children fade 0.4s + rise from 2rem 1s,
     staggered 0.2s each */
  html.js [data-animate='reveal-fade-up-stagger'] > * {
    opacity: 0;
    transform: translateY(2rem);
    transition:
      opacity 0.4s var(--ease-quad-out),
      transform 1s var(--ease-custom);
  }
  html.js [data-animate='reveal-fade-up-stagger'].is-inview > * {
    opacity: 1;
    transform: translateY(0);
  }

  /* reveal-fade-up-stagger-2: children fade 0.5s + rise from 1rem 1s,
     staggered 0.15s each */
  html.js [data-animate='reveal-fade-up-stagger-2'] > * {
    opacity: 0;
    transform: translateY(1rem);
    transition:
      opacity 0.5s var(--ease-quad-out),
      transform 1s var(--ease-custom);
  }
  html.js [data-animate='reveal-fade-up-stagger-2'].is-inview > * {
    opacity: 1;
    transform: translateY(0);
  }

  /* .line divider: width 0 -> 100%, 1s custom ease (trigger: top 90%) */
  html.js .line {
    width: 0%;
    transition: width 1s var(--ease-custom);
  }
  html.js .line.is-inview {
    width: 100%;
  }

  /* ========================================================================
     SCROLL-SCRUBBED ZOOM - transform driven by js/main.js; own compositor
     layer so per-frame scaling never repaints the page
     ======================================================================== */

  html.js [data-animate='scroll-zoom'] {
    will-change: transform;
  }

  /* ========================================================================
     MARQUEES (load, infinite)
     ======================================================================== */

  /* Footer wordmark: x 0 -> -100% over 120s, linear, infinite */
  html.js .footer_name-wrap {
    animation: marquee 120s linear infinite;
  }
  /* Client logos (home): x 0 -> -100% over 60s, linear, infinite */
  html.js .clients_group {
    animation: marquee 60s linear infinite;
  }
  @keyframes marquee {
    from {
      transform: translateX(0%);
    }
    to {
      transform: translateX(-100%);
    }
  }

  /* ========================================================================
     SCROLL DIRECTION - navbar hide/show (IX2 "Navbar move in/out", 750ms outCubic)
     ======================================================================== */

  .navbar_content {
    transition: transform 0.75s var(--ease-cubic-out);
  }
  .navbar.nav-hidden .navbar_content {
    transform: translateY(-150%);
  }
  .navbar_bg {
    transition: opacity 0.75s var(--ease-cubic-out);
  }
  .navbar.nav-hidden .navbar_bg {
    opacity: 0;
  }

  /* ========================================================================
     BUTTON HOVER (desktop only, as in the original interaction):
     chars of text 1 fade out (0.25s, 0.02s/char), text 2 fades in +0.3s
     ======================================================================== */

  @media (min-width: 992px) and (hover: hover) {
    .button .button_text._1 .split-char {
      opacity: 1;
      transition: opacity 0.25s var(--ease-quad-out);
    }
    html.js .button .button_text._2 {
      display: block;
    }
    .button .button_text._2 .split-char {
      opacity: 0;
      transition: opacity 0.25s var(--ease-quad-out);
    }
    .button:hover .button_text._1 .split-char {
      opacity: 0;
    }
    .button:hover .button_text._2 .split-char {
      opacity: 1;
    }
  }
}

/* ==========================================================================
   STATE-DRIVEN UI (functional even with reduced motion; transitions are
   simply instant when the blocks above don't apply)
   ========================================================================== */

/* FAQ accordion: answer height 0 <-> auto (0.5s power1.inOut, driven by JS
   measuring the content), plus icon rotate 90 -> 180deg (0.35s) */
html.js .faq_answer-wrap {
  height: 0;
  opacity: 0;
  visibility: hidden;
  overflow: hidden;
}
html.js .faq_accordion.is-open .faq_answer-wrap {
  opacity: 1;
  visibility: visible;
}
@media (prefers-reduced-motion: no-preference) {
  html.js .faq_answer-wrap {
    transition:
      height 0.5s var(--ease-quad-in-out),
      opacity 0.5s var(--ease-quad-in-out),
      visibility 0.5s;
  }
  .faq_button-line.is-second {
    transform: rotate(90deg);
    transition: transform 0.35s var(--ease-quad-in-out);
  }
}
html:not(.js) .faq_answer-wrap {
  height: auto;
}
.faq_button-line.is-second {
  transform: rotate(90deg);
}
.faq_accordion.is-open .faq_button-line.is-second {
  transform: rotate(180deg);
}
.faq_question-block {
  cursor: pointer;
}

/* Mobile blog slider */
html.js .slider-mobile_mask {
  position: relative;
}
html.js .slider-mobile_slide {
  position: absolute;
  top: 0;
  left: 0;
  opacity: 0;
  pointer-events: none;
}
html.js .slider-mobile_slide.w-active {
  position: relative;
  opacity: 1;
  pointer-events: auto;
}
/* Keep active-slide blog cards visible even if scroll-reveal never rebinds */
html.js .slider-mobile_slide.w-active [data-animate='reveal-fade-up-stagger-2'] > *,
html.js .slider-mobile_slide.w-active [data-animate='reveal-fade-up-stagger-2'].is-inview > * {
  opacity: 1;
  transform: translateY(0);
}
@media (prefers-reduced-motion: no-preference) {
  html.js .slider-mobile_slide {
    transition: opacity 0.25s ease;
  }
}
html.js .slide-nav {
  display: block;
  text-align: center;
}
.w-slider-dot {
  border: 0;
  padding: 0;
  background-color: #0003;
}
.w-slider-dot.w-active {
  background-color: #000;
}
