/* ==========================================================================
   Site-wide motion system
   Driven by assets/js/animations.js (IntersectionObserver adds .is-visible)
   Everything here degrades to "just visible" if JS fails to load, since the
   base state below is opacity:1 and only .evo-anim resets it to hidden.
   ========================================================================== */

.evo-anim {
	opacity: 0;
	transform: translateY(24px);
	transition: opacity var(--evo-speed-slow) var(--evo-ease), transform var(--evo-speed-slow) var(--evo-ease);
}
.evo-anim.is-visible { opacity: 1; transform: translateY(0); }

/* Staggered children within a .evo-anim-group (product grids, tile grids,
   feature grids) — JS assigns --evo-i per child, capped so long grids
   don't take forever to finish animating in. */
.evo-anim-group > * {
	opacity: 0;
	transform: translateY(20px);
	transition: opacity var(--evo-speed-base) var(--evo-ease), transform var(--evo-speed-base) var(--evo-ease);
	transition-delay: calc(var(--evo-i, 0) * 70ms);
}
.evo-anim-group.is-visible > * { opacity: 1; transform: translateY(0); }

/* Hero load-in (no scroll trigger needed, runs on page load) */
.hero__content > * { animation: evo-fade-up var(--evo-speed-slow) var(--evo-ease) both; }
.hero__content > *:nth-child(2) { animation-delay: 90ms; }
.hero__content > *:nth-child(3) { animation-delay: 160ms; }

@keyframes evo-fade-up {
	from { opacity: 0; transform: translateY(18px); }
	to { opacity: 1; transform: translateY(0); }
}

/* Count-up stat numbers — JS drives the number itself; this just keeps the
   element from popping in with a hard cut. */
.stat-row__number { transition: opacity var(--evo-speed-base) var(--evo-ease); }

@media (prefers-reduced-motion: reduce) {
	.evo-anim,
	.evo-anim-group > * {
		opacity: 1 !important;
		transform: none !important;
		transition: none !important;
	}
	.hero__content > * { animation: none !important; opacity: 1; }
}
