/* CSS-only animations + reduced-motion guards — design.md §9.14 */

/* Scroll-reveal: gated on the `fwh-motion` class that an inline script in
   header.php adds to <html> as soon as the page parses. If JS is disabled,
   broken, or stalled, the class never lands and elements stay visible by
   default — no flash-of-blank-content for slow-network or reduced-motion users. */
.fwh-motion [data-reveal] {
	opacity: 0;
	transform: translateY(24px);
	transition:
		opacity   var(--motion-duration-reveal) var(--motion-ease-entrance),
		transform var(--motion-duration-reveal) var(--motion-ease-entrance);
}
.fwh-motion [data-reveal].is-visible {
	opacity: 1;
	transform: none;
}

/* Staggered children reveal (Pick3-Lessons §8): add data-reveal-stagger to any
   grid container; cards fade in with a cascading delay so motion feels designed,
   not chaotic. The IntersectionObserver in motion-wrapper.js adds .is-revealed
   to the container when it scrolls into view. Gated on .fwh-motion for the
   same flash-of-blank-content reason as [data-reveal] above. */
.fwh-motion [data-reveal-stagger] > * {
	opacity: 0;
	transform: translateY(24px);
	transition:
		opacity   700ms cubic-bezier(0.22, 1, 0.36, 1),
		transform 700ms cubic-bezier(0.22, 1, 0.36, 1);
	will-change: opacity, transform;
}
.fwh-motion [data-reveal-stagger].is-revealed > * {
	opacity: 1;
	transform: translateY(0);
}
[data-reveal-stagger].is-revealed > *:nth-child(1) { transition-delay:   0ms; }
[data-reveal-stagger].is-revealed > *:nth-child(2) { transition-delay:  80ms; }
[data-reveal-stagger].is-revealed > *:nth-child(3) { transition-delay: 160ms; }
[data-reveal-stagger].is-revealed > *:nth-child(4) { transition-delay: 240ms; }
[data-reveal-stagger].is-revealed > *:nth-child(5) { transition-delay: 320ms; }
[data-reveal-stagger].is-revealed > *:nth-child(6) { transition-delay: 400ms; }
[data-reveal-stagger].is-revealed > *:nth-child(7) { transition-delay: 480ms; }
[data-reveal-stagger].is-revealed > *:nth-child(8) { transition-delay: 560ms; }

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

/* Defensive guard: hero displays must always be visible regardless of any
   motion-system bug (Pick3-Lessons §10 — letter-rise spring config once left
   titles stuck at opacity:0). */
.hero__title,
.hero__title-main,
.hero__title-sub {
	opacity: 1 !important;
	transform: none !important;
}

/* Hero character — breathing loop. */
.hero__character {
	animation: hero-breathe 4s ease-in-out infinite alternate;
	transform-origin: 50% 60%;
	will-change: transform;
}
@keyframes hero-breathe {
	from { transform: scale(1); }
	to   { transform: scale(1.015); }
}

/* Spinner */
.spinner {
	display: inline-block;
	width: 18px; height: 18px;
	border-radius: 50%;
	border: 2px solid currentColor;
	border-top-color: transparent;
	animation: spin 0.6s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* Reduced motion overrides — design.md §9.14 */
@media (prefers-reduced-motion: reduce) {
	*,
	*::before,
	*::after {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
		scroll-behavior: auto !important;
	}
	.card:hover { transform: none; }
	.hero__texture, .hero__illustration { transform: none !important; }
	.hero__character { animation: none !important; transform: none !important; }
	[data-reveal] { opacity: 1; transform: none; }

	/* Critical feedback still animates briefly. */
	.spinner { animation: spin 1.2s linear infinite !important; }
	.result-number.is-flashing { animation: result-flash 120ms ease-out !important; }
	.field__error { animation-duration: 120ms !important; }
}

/* Sticky header transition target */
.site-header { transition: transform var(--motion-duration-base) var(--motion-ease-entrance); }
