/**
 * PS Design System — Tier-2 motion layer (gated: body.ps-ds).
 *
 * One motion language, "the press pass": content settles into registration —
 * a short rise (or directional drift) + fade on the brand ease, replacing the
 * demo's full-viewport animate.css slides. Two mechanisms share it:
 *
 *   1. Re-skin: elements with Elementor entrance animations keep Elementor's
 *      own waypoint trigger (.elementor-invisible → .animated.slideInX); the
 *      slideIn* names are re-pointed to the ps-drift keyframes below, so no
 *      content/DB change and zero FOUC risk.
 *   2. Reveal: elements with NO entrance animation are tagged .ps-reveal by
 *      ps-motion.js and revealed via IntersectionObserver in staggered
 *      batches. Hidden states apply ONLY under body.ps-motion-armed (added by
 *      the script), so if JS never runs — or FlyingPress delays it — the page
 *      is simply fully visible. Never hide content with CSS alone here.
 */

/* ---- smooth anchors ---------------------------------------------------- */

@media (prefers-reduced-motion: no-preference) {
	html:has(body.ps-ds) {
		scroll-behavior: smooth;
	}
}

/* ---- press-pass keyframes ---------------------------------------------- */

@keyframes ps-drift-up {
	from {
		opacity: 0;
		transform: translate3d(0, 28px, 0);
	}
	to {
		opacity: 1;
		transform: translate3d(0, 0, 0);
	}
}

@keyframes ps-drift-down {
	from {
		opacity: 0;
		transform: translate3d(0, -28px, 0);
	}
	to {
		opacity: 1;
		transform: translate3d(0, 0, 0);
	}
}

@keyframes ps-drift-left {
	from {
		opacity: 0;
		transform: translate3d(-28px, 0, 0);
	}
	to {
		opacity: 1;
		transform: translate3d(0, 0, 0);
	}
}

@keyframes ps-drift-right {
	from {
		opacity: 0;
		transform: translate3d(28px, 0, 0);
	}
	to {
		opacity: 1;
		transform: translate3d(0, 0, 0);
	}
}

/* ---- re-skin Elementor entrance animations ------------------------------ */

/* Direction semantics preserved; amplitude and timing unified. */
.ps-ds .animated {
	animation-duration: 0.65s !important;
	animation-timing-function: var(--ps-ease) !important;
}

.ps-ds .animated.slideInUp {
	animation-name: ps-drift-up !important;
}

.ps-ds .animated.slideInDown {
	animation-name: ps-drift-down !important;
}

.ps-ds .animated.slideInLeft {
	animation-name: ps-drift-left !important;
}

.ps-ds .animated.slideInRight {
	animation-name: ps-drift-right !important;
}

/* ---- hero card compositions: no entrance act --------------------------- */

/* The floating-card compositions (homepage hero 65fcbf6 + the lower band
   74af690) played TWO motions back to back: an Elementor entrance slide,
   then the continuous hero-float. One motion only (user call, 2026-07-15):
   the cards are simply present from first paint and the float provides the
   life — hero-float's getAnimations() gate sees no running animation and
   starts immediately. Gated by body.ps-hero-calm (Customizer toggle "Hero
   cards: skip entrance animation"); the extra class also outranks the
   slideIn* re-skin rules above on specificity, not just source order. */
.ps-ds.ps-hero-calm .elementor-element-65fcbf6 .elementor-invisible,
.ps-ds.ps-hero-calm .elementor-element-74af690 .elementor-invisible {
	visibility: visible !important;
}

.ps-ds.ps-hero-calm .elementor-element-65fcbf6 .animated,
.ps-ds.ps-hero-calm .elementor-element-74af690 .animated {
	animation: none !important;
}

/* ---- scroll reveals (script-armed) -------------------------------------- */

body.ps-ds.ps-motion-armed .ps-reveal {
	opacity: 0;
	transform: translate3d(0, 26px, 0);
}

body.ps-ds.ps-motion-armed .ps-reveal.ps-in {
	opacity: 1;
	transform: translate3d(0, 0, 0);
	transition-property: opacity, transform;
	transition-duration: 0.6s;
	transition-timing-function: var(--ps-ease);
	transition-delay: var(--ps-rd, 0ms);
}

/* Elements already in view when the script arms reveal with no animation. */
body.ps-ds.ps-motion-armed .ps-reveal.ps-in.ps-noanim {
	transition: none;
}

/* ---- header depth on scroll --------------------------------------------- */

.ps-ds #haru-header {
	transition-property: box-shadow;
	transition-duration: 0.25s;
	transition-timing-function: var(--ps-ease);
}

body.ps-ds.ps-scrolled #haru-header {
	box-shadow: 0 1px 0 rgba(var(--ps-ink-rgb), 0.04), 0 12px 28px -20px rgba(var(--ps-ink-rgb), 0.22);
}

/* ---- banner card image zoom ---------------------------------------------- */

/* Radius matches the img treatment in ps-components.css so the clip is
   concentric with the card. */
.ps-ds .haru-banner .haru-banner__image {
	overflow: hidden;
	border-radius: calc(var(--ps-r-lg) - 6px);
}

.ps-ds .haru-banner .haru-banner__image img {
	transition-property: transform;
	transition-duration: 0.5s;
	transition-timing-function: var(--ps-ease);
}

.ps-ds .haru-banner:hover .haru-banner__image img {
	transform: scale(1.03);
}

/* ---- reduced motion ------------------------------------------------------ */

@media (prefers-reduced-motion: reduce) {
	/* Entrance animations show content instantly (Elementor's waypoint still
	   removes .elementor-invisible; the safety rule covers a JS failure). */
	.ps-ds .animated {
		animation: none !important;
	}

	.ps-ds .elementor-invisible {
		visibility: visible !important;
	}

	/* The reveal script bails on reduced motion; belt-and-braces if the
	   armed class ever lands anyway. */
	body.ps-ds.ps-motion-armed .ps-reveal {
		opacity: 1;
		transform: none;
		transition: none;
	}

	.ps-ds .haru-banner .haru-banner__image img,
	.ps-ds #haru-header {
		transition: none;
	}

	.ps-ds .haru-banner:hover .haru-banner__image img {
		transform: none;
	}
}
