/*
 * Scroll reveals (reveal.js), after thirdway.com: large headings rise line by
 * line from a mask, blocks fade up, card groups follow one another, and the
 * Home intro fills in word by word with the scroll.
 *
 * The hidden state only exists on elements the script marked pending: below
 * the screen when the page opened. Without the script, with reduced motion and
 * in the first screen, nothing hides. Only transforms, opacity and clip-path
 * change, so the layout never moves.
 */

:root {
	--reveal-line-duration: 0.8s;
	--reveal-block-duration: 1s;
	--reveal-ease: cubic-bezier(0.16, 1, 0.3, 1); /* lines: strong ease-out, as the reference */
	--reveal-block-ease: cubic-bezier(0.42, 0, 0.58, 1); /* blocks and cards: ease in and out, slower (designer, 2026-10-09) */
	--reveal-line-stagger: 0.1s;
	--reveal-group-stagger: 0.1s;
	--reveal-rise: 24px;
}

/* Lines: each line clips its inner span (extended past the glyphs, so accents and descenders stay whole). */
.reveal-mask {
	clip-path: inset(-0.3em -0.5em -0.35em -0.5em);
}

.reveal-line {
	display: block;
}

.reveal-pending .reveal-line {
	opacity: 0;
	translate: 0 100%;
}

/* Blocks rise with transform: some already place themselves with translate (.slider-card__texts), which adds up with it. */
[data-reveal="up"].reveal-pending {
	opacity: 0;
	transform: translateY(var(--reveal-rise));
}

/* While playing: the transitions exist only then, so nothing else on these elements animates. */
.reveal-run .reveal-line {
	transition:
		opacity var(--reveal-line-duration) var(--reveal-ease),
		translate var(--reveal-line-duration) var(--reveal-ease);
	transition-delay: calc(var(--reveal-delay, 0s) + var(--reveal-i, 0) * var(--reveal-line-stagger));
}

[data-reveal="up"].reveal-run {
	transition:
		opacity var(--reveal-block-duration) var(--reveal-block-ease),
		transform var(--reveal-block-duration) var(--reveal-block-ease);
	transition-delay: var(--reveal-delay, 0s);
}

/*
 * Word fill (Home intro): a scroll-driven animation moves --fill from 0 to 1
 * while the paragraph crosses the screen; each word (index --reveal-i of
 * --reveal-words) runs from 30% to full opacity in reading order. Browsers
 * without scroll-driven animations keep --fill at 1: the text shows as normal.
 */
@property --fill {
	syntax: "<number>";
	inherits: true;
	initial-value: 1;
}

@keyframes cliff-fill {
	from {
		--fill: 0;
	}

	to {
		--fill: 1;
	}
}

@supports (animation-timeline: view()) {
	.reveal-fill {
		animation: cliff-fill linear both;
		animation-timeline: view();
		animation-range: entry 20% cover 55%;
	}

	.reveal-fill .reveal-word {
		opacity: clamp(0.3, calc(var(--fill) * var(--reveal-words) - var(--reveal-i)), 1);
	}
}

@media (prefers-reduced-motion: reduce) {
	.reveal-pending .reveal-line {
		opacity: 1;
		translate: none;
	}

	[data-reveal="up"].reveal-pending {
		opacity: 1;
		transform: none;
	}

	.reveal-fill {
		animation: none;
	}
}
