/* =============================================================================
   nonprofit.omen.services / motion.css
   The motion layer. Owned by the craft lead. main.css is frozen and is not
   touched by anything in this file.

   Three rules govern every declaration below.

   1  Every initial hidden or offset state is scoped under `html.has-motion`.
      That class is added by js/motion.js only when JavaScript runs AND
      prefers-reduced-motion does not match. With scripting off, or with
      reduced motion on, not one rule in this file applies and the site
      renders fully static with all content visible.

   2  Only `opacity` and `transform` are ever animated. No width, height,
      top, left, margin, padding, filter, colour or background transitions
      appear anywhere in this file. Nothing here can shift layout.

   3  Every duration, easing and distance comes from the --motion-* tokens
      declared in main.css. No hardcoded timing values.
   ============================================================================= */


/* ==========================================================================
   1  REVEAL PRIMITIVE

   js/motion.js stamps `data-reveal="<kind>"` onto elements at runtime and
   sets `--motion-delay` inline for staggering. It never appears in the HTML,
   so the served markup has no opacity-0 defaults in it.

   Kinds:
     hero   rise + fade, slow duration. The hero group only.
     rise   rise + fade, base duration. The site default.
     fade   fade only, base duration. Figures, so images cannot shift.
     draw   a hairline drawing in from the left. Transform only.
   ========================================================================== */

html.has-motion [data-reveal] {
  opacity: 0;
  transition-property: opacity, transform;
  transition-duration: var(--motion-duration-base);
  transition-timing-function: var(--motion-ease);
  transition-delay: var(--motion-delay, 0ms);
}

/* Always upward, never sideways, never scaled. */
html.has-motion [data-reveal="hero"],
html.has-motion [data-reveal="rise"] {
  transform: translateY(var(--motion-distance));
}

/* The hero group is the only thing on the site that runs at slow duration. */
html.has-motion [data-reveal="hero"] {
  transition-duration: var(--motion-duration-slow);
}

/* A hairline rule drawing itself in. The amber terminator draws with it. */
html.has-motion [data-reveal="draw"] {
  transform: scaleX(0);
  transform-origin: left center;
}

/* The end state. Applied once, by script, and never taken away. */
html.has-motion [data-reveal].is-revealed {
  opacity: 1;
  transform: none;
}


/* ==========================================================================
   2  SHORT STATE TRANSITIONS
   Transform only, fast duration, uniform easing. main.css declares no
   transitions at all, so these are additive and cannot fight anything.

   The nav toggle's hamburger-to-cross morph is deliberately NOT transitioned:
   its open state moves `top` and `bottom` as well as `transform`, so easing
   the transform alone would desynchronise the two halves. Instant is correct.
   ========================================================================== */

html.has-motion .skip-link {
  transition: transform var(--motion-duration-fast) var(--motion-ease);
}

/* The FAQ disclosure chevron. <details> content itself never animates. */
html.has-motion .faq__q::after {
  transition: transform var(--motion-duration-fast) var(--motion-ease);
}


/* ==========================================================================
   3  THE FORM
   apply.html carries a six-step, roughly fifteen minute application. It is
   the most important page on the site and it gets almost no motion.

   Nothing in this file gives the form an initial hidden state. The step
   cross-fade is run imperatively by js/motion.js with the Web Animations
   API so that it cannot survive a JavaScript failure, cannot delay first
   paint, and cannot interfere with the focus management, validation, draft
   restore or conditional-field logic in js/main.js.

   These rules exist to guarantee that nothing above can ever reach into the
   form and animate something that must be instant:
     - the error summary, which receives focus the moment validation fails
     - inline .field__error messages
     - .form-status, the role="status" live region
     - .charcount
     - .form-progress, including the fill, which main.js sets via width
     - .draft-notice and .form-success
   ========================================================================== */

html.has-motion .error-summary,
html.has-motion .error-summary *,
html.has-motion .field__error,
html.has-motion .form-status,
html.has-motion .charcount,
html.has-motion .form-progress,
html.has-motion .form-progress__fill,
html.has-motion .draft-notice,
html.has-motion .form-success,
html.has-motion .form-step {
  opacity: 1;
  transform: none;
  transition: none;
}


/* ==========================================================================
   4  GUARANTEES

   Belt and braces. js/motion.js already refuses to add `has-motion` under
   reduced motion, and removes it if the setting changes mid-session. This
   block means that even if the class were present, nothing would be hidden.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  html.has-motion [data-reveal] {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }

  html.has-motion .skip-link,
  html.has-motion .faq__q::after {
    transition: none !important;
  }
}

/* Content that has not been scrolled to yet must still print. */
@media print {
  html.has-motion [data-reveal] {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
}
