/**
 * animations.css — Wolliq Theme
 *
 * Scroll-reveal system, @keyframes, and prefers-reduced-motion override.
 * Loaded after components.css. Defines every animation that is not a
 * simple hover transition — those live in components.css alongside their
 * component so they can be read in context.
 *
 * Architecture:
 *   - .reveal        → initial hidden state (set in PHP templates, always on)
 *   - .is-visible    → final visible state (added by animations.js via IntersectionObserver)
 *   - Actual transition rules are wrapped in prefers-reduced-motion: no-preference
 *   - Reduced-motion block immediately reveals all .reveal elements and kills @keyframes
 *
 * Spec references:
 *   Section 7.2 — approved animation inventory
 *   Section 7.3 — forbidden (parallax, auto-play video motion, infinite loops*)
 *   Section 7.4 — prefers-reduced-motion: all animations inside no-preference block
 *   Section 12.2 — IntersectionObserver only, no scroll events
 *
 * * Exception: loading spinner uses a single-duration loop while the form
 *   is submitting. It is dismissed by JS on resolve.
 *
 * @package Wolliq
 */

/* ============================================================================
   01 — REVEAL: BASE HIDDEN STATE
   Always applied regardless of motion preference. The reduced-motion block
   (Section 04) overrides these for users who prefer no motion.
   ============================================================================ */

/**
 * .reveal is added directly in PHP templates (not by JS) so elements are
 * hidden from the first paint. H1 / LCP elements must NOT carry .reveal.
 *
 * Default axis: fade + slide up (translateY)
 */
.reveal {
  opacity: 0;
  transform: translateY(24px);
}

/**
 * Direction modifiers — change starting transform only.
 * Applied alongside .reveal: <div class="reveal reveal--left">
 */
.reveal--left  { transform: translateX(-32px); }
.reveal--right { transform: translateX(32px);  }
.reveal--scale { transform: scale(0.94);        }
.reveal--fade  { transform: none;               } /* Opacity-only, no translate */

/* ============================================================================
   02 — REVEAL: STAGGERED DELAYS
   Applied via [data-reveal-index="N"] attribute in PHP templates.
   Delay is read by the browser at the moment the transition starts
   (when .is-visible is added), so the stagger is correctly applied
   even though the attribute is present from first paint.

   Cap at index 5 (6 items). For longer grids the 6th+ item uses 0ms delay.
   ============================================================================ */

.reveal[data-reveal-index="0"] { transition-delay:   0ms; }
.reveal[data-reveal-index="1"] { transition-delay:  80ms; }
.reveal[data-reveal-index="2"] { transition-delay: 160ms; }
.reveal[data-reveal-index="3"] { transition-delay: 240ms; }
.reveal[data-reveal-index="4"] { transition-delay: 320ms; }
.reveal[data-reveal-index="5"] { transition-delay: 400ms; }

/* ============================================================================
   03 — NO-PREFERENCE ANIMATION BLOCK
   All transition and @keyframes rules live here.
   Users with prefers-reduced-motion: reduce never receive this block.
   ============================================================================ */

@media (prefers-reduced-motion: no-preference) {

  /* --------------------------------------------------------------------------
     03a  REVEAL: Default (fade + slide up)
     -------------------------------------------------------------------------- */

  .reveal {
    transition:
      opacity  600ms ease-out,
      transform 600ms ease-out;
  }

  .reveal.is-visible {
    opacity: 1;
    transform: none; /* Resets translateY, translateX, and scale */
  }

  /* --------------------------------------------------------------------------
     03b  REVEAL: Direction-specific transitions
     Direction modifiers share the same .is-visible end state (transform: none)
     but may use a slightly different easing to match their axis.
     -------------------------------------------------------------------------- */

  /* Horizontal slides use a snappier curve */
  .reveal--left,
  .reveal--right {
    transition:
      opacity  500ms ease-out,
      transform 500ms cubic-bezier(0.25, 0.46, 0.45, 0.94);
  }

  /* Scale-up entrance */
  .reveal--scale {
    transition:
      opacity  450ms ease-out,
      transform 450ms cubic-bezier(0.34, 1.30, 0.64, 1); /* slight overshoot */
  }

  /* Fade-only: no transform, just opacity */
  .reveal--fade {
    transition: opacity 500ms ease-out;
  }

  /* --------------------------------------------------------------------------
     03c  SECTION HEADER: slightly slower so content cards stagger after it
     -------------------------------------------------------------------------- */

  .section__header.reveal {
    transition-duration: 500ms;
    transition-delay: 0ms; /* Headers always lead — no inherited stagger */
  }

  /* --------------------------------------------------------------------------
     03d  HERO: Above-fold reveal
     Hero subtext / actions / trust have .reveal but are already in viewport.
     IntersectionObserver fires immediately after DOM ready, so the first
     render is: H1 visible → ~100ms → subtext/actions fade in.
     A shorter duration keeps the hero feeling alive without a long wait.
     -------------------------------------------------------------------------- */

  .hero__subtext.reveal,
  .hero__actions.reveal  {
    transition-duration: 500ms;
    transition-timing-function: ease-out;
  }

  .hero__trust.reveal {
    transition-duration: 400ms;
    transition-delay: 80ms; /* Trust row trails the CTA buttons slightly */
  }

  /* --------------------------------------------------------------------------
     03e  STATS BAND: Counter digits
     CSS prepares the visual state. JS (counter.js) drives the number via
     requestAnimationFrame. The digit wrapper fades in with the reveal system
     (.stats-band__stat uses .reveal via the section's is-visible parent).
     -------------------------------------------------------------------------- */

  .stats-band__number {
    transition:
      color var(--transition-slow),
      opacity var(--transition-slow);
  }

  /* --------------------------------------------------------------------------
     03f  NAV: Header scroll shadow
     The .site-header--scrolled class is toggled by nav.js on scroll.
     Transition is defined here (scroll-triggered) not in components.css.
     -------------------------------------------------------------------------- */

  .site-header {
    transition: box-shadow var(--transition-normal);
  }

  /* --------------------------------------------------------------------------
     03g  BLOG CARD: Image zoom on hover
     Defined here because it is a sub-element transition that animations.js
     may also gate via is-visible. The card hover transition (border, shadow)
     is in components.css; the image zoom is isolated here.
     -------------------------------------------------------------------------- */

  .blog-preview__card-img {
    transition: transform var(--transition-slow);
  }

  .blog-preview__card:hover .blog-preview__card-img {
    transform: scale(1.05);
  }

  /* --------------------------------------------------------------------------
     03h  FORM SUBMISSION: Loading state
     .is-loading on the form wrapper activates the spinner overlay.
     -------------------------------------------------------------------------- */

  .contact-form__submit.is-loading .btn-label {
    opacity: 0;
  }

  .contact-form__submit.is-loading::after {
    content: '';
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    animation: spin 700ms linear infinite;
  }

  /* --------------------------------------------------------------------------
     03i  @KEYFRAMES
     All keyframes are defined inside this block so they are never parsed
     by browsers in reduced-motion mode (Section 7.4).
     -------------------------------------------------------------------------- */

  /**
   * fadeInUp — used as CSS animation fallback for critical above-fold reveals
   * that need to work without IntersectionObserver (no-JS, very early paint).
   * Apply via: animation: fadeInUp 600ms ease-out forwards;
   */
  @keyframes fadeInUp {
    from {
      opacity: 0;
      transform: translateY(24px);
    }
    to {
      opacity: 1;
      transform: translateY(0);
    }
  }

  /**
   * fadeIn — pure opacity. Use on overlays, tooltips, dropdown content.
   * Apply via: animation: fadeIn 200ms ease-out forwards;
   */
  @keyframes fadeIn {
    from { opacity: 0; }
    to   { opacity: 1; }
  }

  /**
   * slideDown — top-to-current-position. Used on notices / alerts that
   * appear after form validation.
   * Apply via: animation: slideDown 300ms ease-out forwards;
   */
  @keyframes slideDown {
    from {
      opacity: 0;
      transform: translateY(-12px);
    }
    to {
      opacity: 1;
      transform: translateY(0);
    }
  }

  /**
   * slideRight — left-to-current-position. Used on mobile nav accordion
   * sub-panels if they ever need a directional entrance.
   */
  @keyframes slideRight {
    from {
      opacity: 0;
      transform: translateX(-16px);
    }
    to {
      opacity: 1;
      transform: translateX(0);
    }
  }

  /**
   * scaleIn — grows from 94% to 100%. Used on modal / dialog entrances.
   * Apply via: animation: scaleIn 250ms cubic-bezier(0.34, 1.30, 0.64, 1) forwards;
   */
  @keyframes scaleIn {
    from {
      opacity: 0;
      transform: scale(0.94);
    }
    to {
      opacity: 1;
      transform: scale(1);
    }
  }

  /**
   * shimmer — skeleton loading effect. Sweeps a highlight left to right.
   * Apply via: animation: shimmer 1400ms ease-in-out infinite;
   * Use: .skeleton { background: linear-gradient(...); animation: shimmer... }
   */
  @keyframes shimmer {
    0%   { background-position: -200% center; }
    100% { background-position:  200% center; }
  }

  /**
   * spin — 360° rotation for loading spinners.
   * Apply via: animation: spin 700ms linear infinite;
   */
  @keyframes spin {
    to { transform: rotate(360deg); }
  }

  /**
   * pulse — gentle scale throb. Use for attention / highlight elements.
   * Apply via: animation: pulse 2000ms ease-in-out infinite;
   */
  @keyframes pulse {
    0%, 100% { transform: scale(1);    opacity: 1; }
    50%       { transform: scale(1.04); opacity: 0.85; }
  }

  /**
   * countUp — used by counter.js as a CSS animation cue. The actual number
   * counting is done in JS via requestAnimationFrame. This animation simply
   * controls the visual entrance of the digit wrapper.
   * Apply via: animation: countUp 800ms ease-out forwards;
   */
  @keyframes countUp {
    from {
      opacity: 0;
      transform: translateY(16px);
    }
    to {
      opacity: 1;
      transform: translateY(0);
    }
  }

  /* --------------------------------------------------------------------------
     03j  UTILITY ANIMATION CLASSES
     Apply directly in PHP/Twig templates for one-off CSS-driven animations
     that do NOT use the IntersectionObserver reveal system.
     -------------------------------------------------------------------------- */

  /* Notice banner entrance — slide down from above */
  .animate-slide-down {
    animation: slideDown 300ms ease-out both;
  }

  /* Overlay / modal backdrop entrance */
  .animate-fade-in {
    animation: fadeIn 200ms ease-out both;
  }

  /* Modal / dialog entrance */
  .animate-scale-in {
    animation: scaleIn 250ms cubic-bezier(0.34, 1.30, 0.64, 1) both;
  }

  /* Skeleton loading state */
  .skeleton {
    background: linear-gradient(
      90deg,
      var(--color-border)     25%,
      var(--color-surface-2)  50%,
      var(--color-border)     75%
    );
    background-size: 200% 100%;
    animation: shimmer 1400ms ease-in-out infinite;
    border-radius: var(--r-sm);
    color: transparent;
  }

  /* Inline loading spinner element */
  .spinner {
    display: inline-block;
    width: 18px;
    height: 18px;
    border: 2px solid currentColor;
    border-top-color: transparent;
    border-radius: 50%;
    animation: spin 700ms linear infinite;
    vertical-align: middle;
  }

  /* --------------------------------------------------------------------------
     03k  BLOG PREVIEW CARD: Staggered entrance (data-reveal-index applied
     by PHP on each card, covered by Section 02). Additional definition here
     narrows the transition duration so cards in a 3-col grid feel snappy.
     -------------------------------------------------------------------------- */

  .blog-preview__card.reveal {
    transition-duration: 500ms;
  }

  /* --------------------------------------------------------------------------
     03l  SERVICE GRID CARD: First card (highlight) subtly scales rather than
     sliding up, making it feel more featured.
     -------------------------------------------------------------------------- */

  .service-grid__card--highlight.reveal {
    transform: scale(0.97);
    transition-duration: 700ms;
  }

  .service-grid__card--highlight.reveal.is-visible {
    transform: scale(1);
  }

  /* --------------------------------------------------------------------------
     03m  HOW IT WORKS: Step numbers spin/scale in for added personality.
     Pair with reveal on the parent .how-it-works__step — the number
     inherits the stagger from [data-reveal-index].
     -------------------------------------------------------------------------- */

  .how-it-works__step.reveal .how-it-works__step-number {
    transition:
      transform 500ms cubic-bezier(0.34, 1.20, 0.64, 1),
      opacity   400ms ease-out;
    transform: scale(0.7) rotate(-15deg);
    opacity: 0;
  }

  .how-it-works__step.is-visible .how-it-works__step-number {
    transform: scale(1) rotate(0deg);
    opacity: 1;
  }

  /* --------------------------------------------------------------------------
     03n  WHY WOLLIQ CARDS: Icon container scales in slightly after the card.
     -------------------------------------------------------------------------- */

  .why-wolliq__card.reveal .why-wolliq__card-icon {
    transition:
      transform 400ms cubic-bezier(0.34, 1.20, 0.64, 1) 150ms,
      opacity   300ms ease-out 150ms;
    transform: scale(0.75);
    opacity: 0;
  }

  .why-wolliq__card.is-visible .why-wolliq__card-icon {
    transform: scale(1);
    opacity: 1;
  }

} /* end @media (prefers-reduced-motion: no-preference) */

/* ============================================================================
   04 — REDUCED-MOTION OVERRIDE
   Users who have opted into reduced motion receive this block only.
   These rules:
   1. Make all .reveal elements immediately visible (no hidden-then-show).
   2. Kill every CSS animation and transition in the entire document.
   The !important usage here is the documented exception (Section 7.4 /
   Section 12.1) — required to override component-level transition rules
   in components.css and any third-party stylesheet.
   ============================================================================ */

@media (prefers-reduced-motion: reduce) {

  /* Show all reveal elements instantly — no hiding at all */
  .reveal,
  .reveal--left,
  .reveal--right,
  .reveal--scale,
  .reveal--fade {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
    transition-delay: 0ms !important;
  }

  /* Kill sub-element reveals (step numbers, icons) */
  .how-it-works__step .how-it-works__step-number,
  .why-wolliq__card .why-wolliq__card-icon {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }

  /* Global transition + animation kill
     Covers everything in components.css, nav.js, counter.js hover states, etc.
     transition-duration: 0.01ms keeps elements "technically animated" but
     imperceptibly fast, which is safer than 0ms (avoids some browser quirks). */
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    animation-delay: 0ms !important;
    transition-duration: 0.01ms !important;
    transition-delay: 0ms !important;
    scroll-behavior: auto !important;
  }

  /* Skeleton still needs a background but no sweep animation */
  .skeleton {
    animation: none !important;
    background: var(--color-border) !important;
  }

} /* end @media (prefers-reduced-motion: reduce) */
