/* ==========================================================================
   MOTION — last layer, so it can always override a resting state.

   Everything here is gated on .has-motion, which header.php adds before
   first paint only when prefers-reduced-motion is no-preference. On a
   reduced-motion machine none of these rules match, so the resting state
   (everything at full strength) is the final state.

   Smooth and eased; time-based motion plays once and stops; copy changes
   opacity only, it never moves. See CLAUDE.md "Motion".
   ========================================================================== */

/* The service icons' progress (0 to 1), registered so it can ease; used in pages.css */
@property --p { syntax: "<number>"; inherits: true; initial-value: 0; }

@layer motion {

	/* ---- Homepage text: each line shows at 30%, then each character comes
	   up to full in reading order (assets/js/home.js splits the text). ---- */
	.has-motion .home .split { --c: var(--c-ink); --cd: color-mix(in srgb, var(--c-ink) 30%, transparent); color: var(--cd); }
	.has-motion .home p.split { --c: var(--c-muted); --cd: color-mix(in srgb, var(--c-muted) 30%, transparent); }
	.has-motion .home .svc-band .split, .has-motion .home .intro .split { --c: var(--c-ink); --cd: color-mix(in srgb, var(--c-ink) 30%, transparent); }
	.has-motion .home .logos .split { --c: var(--c-paper); --cd: color-mix(in srgb, var(--c-paper) 30%, transparent); }
	.has-motion .home .logos p.split { --c: var(--c-mist); --cd: color-mix(in srgb, var(--c-mist) 30%, transparent); }
	/* Safety net: if the script never runs, the dimmed text comes up to full after 4s */
	.has-motion .home .split { animation: split-safety 0.4s ease-out 4s forwards; }
	.has-motion .home .split:has(.ch) { animation: none; }
	@keyframes split-safety { to { color: var(--c); } }

	.has-motion .home .split .ch { color: var(--c); opacity: var(--dim); }
	.has-motion .home .play .ch { animation: char-in 0.55s ease-out var(--d, 0s) forwards; }
	.has-motion .home [data-played] .ch { animation: none; opacity: 1; }
	@keyframes char-in { from { opacity: var(--dim); } to { opacity: 1; } }

	/* ---- Service icons (Jarv, 24 Oct 2026): home.js adds .is-on and the
	   icon's pieces ease together (--p 0 to 1, see pages.css), once, then
	   stop. Mouse: each hover or keyboard focus flips it, and it stays; leaving
	   does nothing, so only one icon moves at a time. Touch: it plays as the
	   icon rises past 35% of the screen, clear of the thumb, and plays back
	   to the start when scrolled back below 40% (home.js). ---- */
	.has-motion .svc-icon { transition: --p 0.9s cubic-bezier(0.45, 0, 0.2, 1); }
	.has-motion .svc-band.is-on .svc-icon { --p: 1; }

	/* ---- Service links: on hover the arrow eases 5px right and back (mouse
	   and keyboard focus; the colour step is in pages.css) ---- */
	@media (hover: hover) {
		.has-motion .svc-link { transition: color 0.25s ease; }
		.has-motion .svc-link__arrow { transition: transform 0.25s cubic-bezier(0.3, 0, 0.2, 1); }
		.has-motion .svc-link:hover .svc-link__arrow, .has-motion .svc-link:focus-visible .svc-link__arrow { transform: translateX(5px); }
	}

	/* ---- Client logos: up from 30% to full in reading order, once ---- */
	.has-motion .logo-grid.fade img { opacity: var(--dim); }
	.has-motion .logo-grid.fade.play img { animation: char-in 0.6s ease-out var(--d, 0s) forwards; }

	/* ---- The printed scroll arrow: the ring fades in, the arrow fades down
	   into place, then nudges twice and stops ---- */
	.has-motion .cue-ring { opacity: 0; transition: opacity 0.6s ease; }
	.has-motion .cue-in .cue-ring { opacity: 1; }
	.has-motion .cue-arrow { opacity: 0; transform: translateY(-8px); transition: opacity 0.6s ease, transform 0.6s ease; }
	.has-motion .cue-in .cue-arrow { opacity: 1; transform: none; animation: nudge 1.1s ease-in-out 0.8s 2; }
	@keyframes nudge { 0%, 100% { transform: none; } 50% { transform: translateY(4px); } }   /* small, so it stays inside the ring */

	/* ---- Project pages: SVG tiles whose parts move (assets/js/portfolio.js).
	   float: parts drift on a slow loop; trace: every --cycle seconds each
	   icon lifts and tilts while its lines re-sweep, then rests, staggered
	   (--bd) into a wave. Lines never trim back more than 30%. These repeat
	   while on screen (as the prototype, approved by Jarv). ---- */
	.has-motion .tile-anim .fl { animation: float var(--fs, 8s) ease-in-out var(--fd, 0s) infinite; }
	.has-motion .tile-anim.is-trace svg { transform-origin: 50% 70%; animation: hop var(--cycle, 5s) cubic-bezier(0.3, 0, 0.2, 1) infinite; animation-delay: var(--bd, 0s); }
	.has-motion .tile-anim .tr { stroke-dasharray: 100 100; animation: sweep var(--cycle, 5s) ease-out infinite; animation-delay: calc(var(--bd, 0s) + var(--d, 0s)); }

	/* "Sending…" loader on Contact (components.css): the three shapes hop in
	   turn, only while a message is being sent, so nothing runs at rest */
	.has-motion .wpcf7 form.submitting .sending img { animation: sending-hop 0.9s ease-in-out infinite; }
	.has-motion .wpcf7 form.submitting .sending img:nth-child(2) { animation-delay: 0.15s; }
	.has-motion .wpcf7 form.submitting .sending img:nth-child(3) { animation-delay: 0.3s; }
	@keyframes sending-hop {
		0%, 60%, 100% { transform: translateY(0); }
		30% { transform: translateY(-7px); }
	}
}
