/* ============================================================
   css/animations.css — Catchnode Keyframe Library
   "We Build the Web. You Run the Business."

   21 named keyframes. Every animation in the project lives here.
   Import order: main.css first, then animations.css.
   All animations respect prefers-reduced-motion — the
   suppression rule (0.001ms duration) lives in main.css §27.
   ============================================================ */


/* ============================================================
   1. preloaderDraw
   Used by: .preloader__circle (SVG stroke animation)
   The SVG circle stroke-dasharray is set to the circumference
   of the circle (≈ 300). Animates from fully hidden to fully
   drawn, then resets. Runs inside .preloader until .preloader--done.
   ============================================================ */
@keyframes preloaderDraw {
  0% {
    stroke-dashoffset: 300;
    opacity: 1;
  }
  85% {
    stroke-dashoffset: 0;
    opacity: 1;
  }
  100% {
    stroke-dashoffset: 0;
    opacity: 0;
  }
}


/* ============================================================
   2. preloaderFill
   Used by: .preloader__bar (progress bar fill)
   Grows the bar from 0% to 100% width over the load duration.
   JS can override width directly for real progress tracking;
   this keyframe is the CSS-only fallback.
   ============================================================ */
@keyframes preloaderFill {
  0% {
    width: 0%;
  }
  100% {
    width: 100%;
  }
}


/* ============================================================
   3. fadeIn
   Used by: pill labels, eyebrow text, badge overlays,
            general elements that need a simple opacity reveal.
   Pair with animation-fill-mode: both and animation-delay
   for staggered reveals.
   ============================================================ */
@keyframes fadeIn {
  0% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}


/* ============================================================
   4. fadeInUp
   Used by: hero headline, hero description, hero CTA buttons,
            hero social proof row. Primary entrance animation
            for above-the-fold content.
   Combine with animation-delay on siblings for stagger.
   ============================================================ */
@keyframes fadeInUp {
  0% {
    opacity: 0;
    transform: translateY(20px);
  }
  100% {
    opacity: 1;
    transform: translateY(0);
  }
}


/* ============================================================
   5. badgePulse
   Used by: .hero-float status dot / online indicator
   Produces a "ping" ripple — the dot scales up and fades out
   while the inner dot stays solid. Wrap in a relative container
   with a ::before pseudo-element for the ripple layer.
   ============================================================ */
@keyframes badgePulse {
  0% {
    transform: scale(1);
    opacity: 1;
  }
  60% {
    transform: scale(1.6);
    opacity: 0.2;
  }
  100% {
    transform: scale(1);
    opacity: 0;
  }
}


/* ============================================================
   6. floatA
   Used by: .hero-float--a (top-right badge card)
   Gentle vertical float. 3s cycle, ease-in-out so the motion
   feels organic rather than mechanical.
   DISABLED on mobile via main.css §9 + §27 prefers-reduced-motion.
   ============================================================ */
@keyframes floatA {
  0% {
    transform: translateY(0);
  }
  50% {
    transform: translateY(-12px);
  }
  100% {
    transform: translateY(0);
  }
}


/* ============================================================
   7. floatB
   Used by: .hero-float--b (bottom-left badge card)
   Slightly smaller amplitude and longer cycle than floatA
   so all three float badges move out of phase with each other.
   ============================================================ */
@keyframes floatB {
  0% {
    transform: translateY(0);
  }
  50% {
    transform: translateY(-8px);
  }
  100% {
    transform: translateY(0);
  }
}


/* ============================================================
   8. floatC
   Used by: .hero-float--c (mid-right badge card)
   Largest amplitude of the three float badges. The 4s cycle
   combined with the animation-delay on .hero-float--c ensures
   all three are never at the same Y position simultaneously.
   ============================================================ */
@keyframes floatC {
  0% {
    transform: translateY(0);
  }
  50% {
    transform: translateY(-15px);
  }
  100% {
    transform: translateY(0);
  }
}


/* ============================================================
   9. blink
   Used by: cursor blink in code/terminal UI elements,
            "typing" animated text caret.
   Uses step-end so the transition is instantaneous (no fade),
   matching the behavior of a real text cursor.
   ============================================================ */
@keyframes blink {
  0%, 100% {
    opacity: 1;
  }
  50% {
    opacity: 0;
  }
}

/* step-end variant for hard cursor blink — apply this class
   when you need a crisp on/off rather than a cross-fade:
   animation: blink 1s step-end infinite; */


/* ============================================================
   10. marqueeScroll
   Used by: .trusted__track (logo marquee belt)
   Translates the duplicated track by exactly -50% so the
   seam is invisible. The .trusted__track element must contain
   two identical sets of logos side-by-side for seamless looping.
   Hover-pause is applied via animation-play-state in main.css §11.
   ============================================================ */
@keyframes marqueeScroll {
  0% {
    transform: translateX(0);
  }
  100% {
    transform: translateX(-50%);
  }
}


/* ============================================================
   11. gradientBorder
   Used by: .cta-card-wrap::before (rainbow rotating border)
   Animates background-position on a 300%-wide gradient so the
   colours cycle smoothly. background-size must be set to 300% 100%
   on the element. DISABLED on mobile (main.css §9 + §19):
   falls back to solid var(--blue) background.
   ============================================================ */
@keyframes gradientBorder {
  0% {
    background-position: 0% 50%;
  }
  50% {
    background-position: 100% 50%;
  }
  100% {
    background-position: 0% 50%;
  }
}


/* ============================================================
   12. drawLine
   Used by: .process__step::after connector lines between steps
   Grows the pseudo-element from zero width to full width,
   creating a "drawing in" effect as the section scrolls into view.
   Trigger by adding .is-visible to the parent .process__steps
   container via the IntersectionObserver in main.js.
   ============================================================ */
@keyframes drawLine {
  0% {
    width: 0%;
    opacity: 0;
  }
  10% {
    opacity: 1;
  }
  100% {
    width: 100%;
    opacity: 1;
  }
}


/* ============================================================
   13. glowPulse
   Used by: .hero__glow--1, .hero__glow--2, .hero__glow--3
   Slowly breathes the background glow blobs so the hero
   background feels alive without being distracting.
   Long duration (4s) keeps the effect subliminal.
   ============================================================ */
@keyframes glowPulse {
  0%, 100% {
    opacity: 0.06;
    transform: scale(1);
  }
  50% {
    opacity: 0.14;
    transform: scale(1.05);
  }
}


/* ============================================================
   14. slideDown
   Used by: .nav (initial entrance), toast/notification banners,
            dropdown menus, mobile nav overlay entrance.
   ============================================================ */
@keyframes slideDown {
  0% {
    transform: translateY(-100%);
    opacity: 0;
  }
  100% {
    transform: translateY(0);
    opacity: 1;
  }
}


/* ============================================================
   15. spin
   Used by: button loading spinners (.btn--loading::after)
             AND auth page / dashboard loading overlay spinner
   IMPORTANT: This keyframe MUST be defined here because both
   the button loading state (main.css §4) and the dashboard
   auth loading spinner (dashboard-specific styles) reference it.
   Keeping it in one place prevents duplication bugs.

   Usage:
     animation: spin 0.7s linear infinite;
   ============================================================ */
@keyframes spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}


/* ============================================================
   16. ripple
   Used by: .btn::after on click (JavaScript adds .is-rippling)
   JS injects a positioned ::after layer at the click coordinates,
   then removes the class after 600ms. The element needs
   overflow: hidden and position: relative (both set in main.css §4).
   ============================================================ */
@keyframes ripple {
  0% {
    transform: scale(0);
    opacity: 0.35;
  }
  60% {
    transform: scale(4);
    opacity: 0.12;
  }
  100% {
    transform: scale(4);
    opacity: 0;
  }
}


/* ============================================================
   17. skeletonPulse
   Used by: .skeleton, .skeleton-text, .skeleton-circle,
            .skeleton-card, .case-card.is-skeleton children,
            .testimonial-card.is-skeleton children
   Gentle opacity pulse that communicates "loading" without
   being visually aggressive. 1.5s cycle is the industry sweet spot.
   ============================================================ */
@keyframes skeletonPulse {
  0%, 100% {
    opacity: 0.4;
  }
  50% {
    opacity: 0.8;
  }
}


/* ============================================================
   18. mobileNavItem
   Used by: .nav__mobile-link items when .nav__mobile.is-open
   Each link slides in from the left with a staggered delay
   (applied per nth-child in main.css §8).
   ============================================================ */
@keyframes mobileNavItem {
  0% {
    opacity: 0;
    transform: translateX(-20px);
  }
  100% {
    opacity: 1;
    transform: translateX(0);
  }
}


/* ============================================================
   19. gradientShimmer
   Used by: .skeleton shimmer variant, loading placeholders
            that need a "shine" sweep rather than a pulse.
   The element needs:
     background: linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.05) 50%, transparent 100%);
     background-size: 200% 100%;
   ============================================================ */
@keyframes gradientShimmer {
  0% {
    background-position: -200% center;
  }
  100% {
    background-position: 200% center;
  }
}


/* ============================================================
   20. particleDrift
   Used by: CSS-only particle fallback when canvas is disabled
            (screens < 768px per motion rules in Part 0).
   Particle elements are small absolute-positioned dots generated
   by JS and given random left positions. This keyframe drifts
   them upward while fading in then out, simulating the canvas
   particle field without GPU-heavy canvas rendering on mobile.
   ============================================================ */
@keyframes particleDrift {
  0% {
    opacity: 0;
    transform: translateY(0) scale(0.8);
  }
  20% {
    opacity: 0.5;
  }
  80% {
    opacity: 0.3;
  }
  100% {
    opacity: 0;
    transform: translateY(-80px) scale(1.2);
  }
}


/* ============================================================
   21. fadeInDown
   Used by: auth page loading message (e.g. "Verifying session…"),
            dashboard loading overlay text, toast notification
            entries that drop in from above.
   Mirrors fadeInUp but inverted — slides in from above rather
   than from below, which feels more natural for overlay messages.
   ============================================================ */
@keyframes fadeInDown {
  0% {
    opacity: 0;
    transform: translateY(-10px);
  }
  100% {
    opacity: 1;
    transform: translateY(0);
  }
}


/* ============================================================
   ANIMATION UTILITY CLASSES
   Ready-to-apply classes so HTML can reference animations
   without inline styles. All durations/delays can be overridden
   with CSS custom properties or inline style where needed.
   ============================================================ */

/* Fade in */
.anim-fade-in {
  animation: fadeIn 0.5s ease both;
}

/* Fade in up — primary hero entrance */
.anim-fade-in-up {
  animation: fadeInUp 0.65s cubic-bezier(0.22, 1, 0.36, 1) both;
}

/* Fade in down — auth / overlay messages */
.anim-fade-in-down {
  animation: fadeInDown 0.45s ease both;
}

/* Slide down — nav entrance, banners */
.anim-slide-down {
  animation: slideDown 0.4s cubic-bezier(0.22, 1, 0.36, 1) both;
}

/* Spin — standalone spinner elements */
.anim-spin {
  animation: spin 0.7s linear infinite;
}

/* Skeleton pulse — standalone usage */
.anim-skeleton {
  animation: skeletonPulse 1.5s ease-in-out infinite;
}

/* Gradient shimmer — shine variant skeleton */
.anim-shimmer {
  background: linear-gradient(
    90deg,
    transparent 0%,
    rgba(255, 255, 255, 0.05) 50%,
    transparent 100%
  );
  background-size: 200% 100%;
  animation: gradientShimmer 1.8s ease-in-out infinite;
}

/* Glow pulse — decorative blobs */
.anim-glow-pulse {
  animation: glowPulse 4s ease-in-out infinite;
}

/* Badge ping — online/live status dot */
.anim-badge-pulse {
  animation: badgePulse 2s ease-out infinite;
}

/* Blink — cursor / caret */
.anim-blink {
  animation: blink 1s step-end infinite;
}

/* Marquee — logo belt */
.anim-marquee {
  animation: marqueeScroll 40s linear infinite;
}

/* Draw line — process step connector */
.anim-draw-line {
  animation: drawLine 0.6s ease forwards;
}


/* ============================================================
   STAGGER DELAY HELPERS
   Add data-delay or these classes to children for entrance stagger.
   Mirrors the [data-delay] system in main.css §25.
   ============================================================ */

.anim-delay-50  { animation-delay: 0.05s; }
.anim-delay-100 { animation-delay: 0.10s; }
.anim-delay-150 { animation-delay: 0.15s; }
.anim-delay-200 { animation-delay: 0.20s; }
.anim-delay-250 { animation-delay: 0.25s; }
.anim-delay-300 { animation-delay: 0.30s; }
.anim-delay-350 { animation-delay: 0.35s; }
.anim-delay-400 { animation-delay: 0.40s; }
.anim-delay-500 { animation-delay: 0.50s; }
.anim-delay-600 { animation-delay: 0.60s; }
.anim-delay-700 { animation-delay: 0.70s; }
.anim-delay-800 { animation-delay: 0.80s; }


/* ============================================================
   ANIMATION DURATION HELPERS
   ============================================================ */

.anim-dur-200  { animation-duration: 0.20s; }
.anim-dur-300  { animation-duration: 0.30s; }
.anim-dur-400  { animation-duration: 0.40s; }
.anim-dur-500  { animation-duration: 0.50s; }
.anim-dur-600  { animation-duration: 0.60s; }
.anim-dur-700  { animation-duration: 0.70s; }
.anim-dur-800  { animation-duration: 0.80s; }
.anim-dur-1000 { animation-duration: 1.00s; }
.anim-dur-1500 { animation-duration: 1.50s; }
.anim-dur-2000 { animation-duration: 2.00s; }


/* ============================================================
   FILL MODE HELPERS
   ============================================================ */

.anim-fill-both     { animation-fill-mode: both; }
.anim-fill-forwards { animation-fill-mode: forwards; }
.anim-fill-none     { animation-fill-mode: none; }


/* ============================================================
   EASING REFERENCE (CSS custom properties)
   Use these on elements that define their own animation shorthand
   and need project-consistent easing curves.
   ============================================================ */

:root {
  --ease-out-expo:   cubic-bezier(0.16, 1, 0.3, 1);
  --ease-out-circ:   cubic-bezier(0, 0.55, 0.45, 1);
  --ease-spring:     cubic-bezier(0.34, 1.56, 0.64, 1);
  --ease-in-out:     cubic-bezier(0.4, 0, 0.2, 1);
  --ease-snappy:     cubic-bezier(0.22, 1, 0.36, 1);
}


/* ============================================================
   END OF css/animations.css
   ============================================================ */

/* SSR content animations — play once on page load without JS */
@keyframes ssrFadeRight {
  from { opacity: 0; transform: translateX(32px); }
  to   { opacity: 1; transform: none; }
}

@keyframes ssrFadeLeft {
  from { opacity: 0; transform: translateX(-32px); }
  to   { opacity: 1; transform: none; }
}

.ssr-fade-right {
  animation: ssrFadeRight 0.6s ease forwards;
}

.ssr-fade-left {
  animation: ssrFadeLeft 0.6s ease forwards;
}

.ssr-fade-right[data-delay="100"],
.ssr-fade-left[data-delay="100"] {
  animation-delay: 0.1s;
  opacity: 0;
}
