/* ═══════════════════════════════════════════════════════════════════
   SCROLL REVEAL — PRIMITIVES

   A vocabulary of verbs. This file names no component, so it ports to
   the next build unchanged; anything site-specific belongs in
   reveal-exceptions.css.

   Every rule is scoped to html.wr-reveal, which an inline <head> script
   adds only when IntersectionObserver exists and motion is not reduced.
   If that script never runs, nothing is ever hidden.

   Structural invariant: every resting rule requires an ancestor
   [data-reveal]; every entered rule requires that same ancestor with
   .is-in-view. An element carrying a verb outside a container is
   therefore never hidden in the first place.

   Markup API
     data-reveal[="verb"]      trigger on a section container
     data-reveal-item="verb"   one element's move
     data-reveal-seq="verb"    stagger this element's children (JS sets --i)
     data-reveal-text          word-by-word reveal on a heading
     data-reveal-lead="600"    ms before it starts
     data-reveal-step="180"    ms between children
   ═══════════════════════════════════════════════════════════════════ */

:root {
	/* One knob: multiplies every duration and delay in this file. */
	--sr-scale: 1;

	/* Held before ANY entrance starts, on top of each element's own lead.
	   Without it the move is over before the section is comfortably in
	   view — raise this if the reveals still feel like they have already
	   happened by the time you look at them. */
	--sr-lead-base: 260ms;

	--sr-ease: cubic-bezier(.16, 1, .3, 1);

	--sr-t-move: calc(1.55s * var(--sr-scale));
	--sr-t-wipe: calc(2s * var(--sr-scale));
	--sr-t-fade: calc(1.35s * var(--sr-scale));

	--sr-step: 175ms;
	--sr-word-step: 62ms;
}

/* Shared delay: lead + index * step, all scaled together. */
html.wr-reveal [data-reveal] [data-reveal-item],
html.wr-reveal [data-reveal] [data-reveal-seq] > *,
html.wr-reveal [data-reveal][data-reveal-item] {
	--sr-delay: calc((var(--sr-lead-base) + var(--lead, 0ms) + var(--i, 0) * var(--step, var(--sr-step))) * var(--sr-scale));
}

/* ── up — one block rises ─────────────────────────────────────── */
html.wr-reveal [data-reveal] [data-reveal-item="up"] {
	opacity: 0;
	transform: translateY(30px);
	transition: opacity var(--sr-t-move) var(--sr-ease) var(--sr-delay),
	            transform var(--sr-t-move) var(--sr-ease) var(--sr-delay);
}
html.wr-reveal [data-reveal].is-in-view [data-reveal-item="up"] {
	opacity: 1;
	transform: none;
}

/* ── glide — a larger object rises as a whole ─────────────────── */
html.wr-reveal [data-reveal] [data-reveal-item="glide"] {
	opacity: 0;
	transform: translateY(56px);
	transition: opacity var(--sr-t-move) var(--sr-ease) var(--sr-delay),
	            transform var(--sr-t-move) var(--sr-ease) var(--sr-delay);
}
html.wr-reveal [data-reveal].is-in-view [data-reveal-item="glide"] {
	opacity: 1;
	transform: none;
}

/* ── dissolve — opacity only, for anything a script transforms ── */
html.wr-reveal [data-reveal] [data-reveal-item="dissolve"] {
	opacity: 0;
	transition: opacity var(--sr-t-fade) var(--sr-ease) var(--sr-delay);
}
html.wr-reveal [data-reveal].is-in-view [data-reveal-item="dissolve"] {
	opacity: 1;
}

/* ── curtain — vertical clip wipe ─────────────────────────────── */
html.wr-reveal [data-reveal] [data-reveal-item="curtain"] {
	clip-path: inset(0 0 100% 0);
	transition: clip-path var(--sr-t-wipe) var(--sr-ease) var(--sr-delay);
}
html.wr-reveal [data-reveal].is-in-view [data-reveal-item="curtain"] {
	clip-path: inset(0 0 0 0);
}

/* ── unveil — horizontal clip wipe ────────────────────────────── */
html.wr-reveal [data-reveal] [data-reveal-item="unveil"] {
	clip-path: inset(0 100% 0 0);
	transition: clip-path var(--sr-t-wipe) var(--sr-ease) var(--sr-delay);
}
html.wr-reveal [data-reveal].is-in-view [data-reveal-item="unveil"] {
	clip-path: inset(0 0 0 0);
}

/* ── settle — scales up from .96 ──────────────────────────────── */
html.wr-reveal [data-reveal] [data-reveal-item="settle"] {
	opacity: 0;
	transform: scale(.96);
	transition: opacity var(--sr-t-move) var(--sr-ease) var(--sr-delay),
	            transform var(--sr-t-move) var(--sr-ease) var(--sr-delay);
}
html.wr-reveal [data-reveal].is-in-view [data-reveal-item="settle"] {
	opacity: 1;
	transform: none;
}

/* ── converge — two halves meeting from opposite sides ────────── */
html.wr-reveal [data-reveal] [data-reveal-item="converge-l"] {
	opacity: 0;
	transform: translateX(-44px);
	transition: opacity var(--sr-t-move) var(--sr-ease) var(--sr-delay),
	            transform var(--sr-t-move) var(--sr-ease) var(--sr-delay);
}
html.wr-reveal [data-reveal] [data-reveal-item="converge-r"] {
	opacity: 0;
	transform: translateX(44px);
	transition: opacity var(--sr-t-move) var(--sr-ease) var(--sr-delay),
	            transform var(--sr-t-move) var(--sr-ease) var(--sr-delay);
}
html.wr-reveal [data-reveal].is-in-view [data-reveal-item="converge-l"],
html.wr-reveal [data-reveal].is-in-view [data-reveal-item="converge-r"] {
	opacity: 1;
	transform: none;
}

@media (max-width: 899px) {
	/* Stacked columns have no sides to converge from. */
	html.wr-reveal [data-reveal] [data-reveal-item="converge-l"],
	html.wr-reveal [data-reveal] [data-reveal-item="converge-r"] {
		transform: translateY(30px);
	}
}

/* ── cascade — staggered rise of a parent's children ──────────── */
html.wr-reveal [data-reveal] [data-reveal-seq="cascade"] > * {
	opacity: 0;
	transform: translateY(34px);
	transition: opacity var(--sr-t-move) var(--sr-ease) var(--sr-delay),
	            transform var(--sr-t-move) var(--sr-ease) var(--sr-delay);
}
html.wr-reveal [data-reveal].is-in-view [data-reveal-seq="cascade"] > * {
	opacity: 1;
	transform: none;
}

/* ── drift — staggered children, opacity only ─────────────────── */
html.wr-reveal [data-reveal] [data-reveal-seq="drift"] > * {
	opacity: 0;
	transition: opacity var(--sr-t-fade) var(--sr-ease) var(--sr-delay);
}
html.wr-reveal [data-reveal].is-in-view [data-reveal-seq="drift"] > * {
	opacity: 1;
}

/* ── riser — staggered children, clip wipe ────────────────────── */
html.wr-reveal [data-reveal] [data-reveal-seq="riser"] > * {
	clip-path: inset(0 0 100% 0);
	transition: clip-path var(--sr-t-wipe) var(--sr-ease) var(--sr-delay);
}
html.wr-reveal [data-reveal].is-in-view [data-reveal-seq="riser"] > * {
	clip-path: inset(0 0 0 0);
}

/* ── read-in — per-word mask ──────────────────────────────────── */
.wr-w {
	display: inline-block;
	overflow: hidden;
	vertical-align: bottom;
	/* Descenders hang below the baseline and the mask would slice them
	   off; the padding gives them room and the negative margin takes
	   that height back out of the line box. */
	padding-bottom: .16em;
	margin-bottom: -.16em;
}

html.wr-reveal [data-reveal] [data-reveal-text] .wr-w__i {
	display: inline-block;
	transform: translateY(105%);
	transition: transform var(--sr-t-move) var(--sr-ease)
	            calc((var(--sr-lead-base) + var(--lead, 0ms) + var(--i, 0) * var(--step, var(--sr-word-step))) * var(--sr-scale));
}
html.wr-reveal [data-reveal].is-in-view [data-reveal-text] .wr-w__i {
	transform: none;
}

/* ── Reduced motion, for a mid-session change ─────────────────── */
@media (prefers-reduced-motion: reduce) {
	html.wr-reveal [data-reveal] [data-reveal-item],
	html.wr-reveal [data-reveal] [data-reveal-seq] > *,
	html.wr-reveal [data-reveal] [data-reveal-text] .wr-w__i {
		clip-path: none !important;
		opacity: 1 !important;
		transform: none !important;
		transition: none !important;
	}
}
