/* ==========================================================================
   Hero — welcome animation.

   Modern rather than terminal: masked word reveal with blur resolve, a signal
   hairline that draws itself, and a soft glow that settles once. Deliberately
   a different register from the boot sequence, which stays retro.

   Everything is CSS. The sentence is complete in the HTML, so no-JS visitors
   read it normally and search engines see plain text.
   ========================================================================== */

:root {
	/* Overshoot easing — the thing that separates "modern" from "faded in". */
	--ease-out-back: cubic-bezier(0.16, 1, 0.3, 1);
}

#hero,
.section--hero { position: relative; }

/* Glow ---------------------------------------------------------------------
   Sits behind the headline. Barely visible on light, does real work on OLED
   black where a pure #000 field otherwise has nothing to catch the eye. */
#hero::before,
.section--hero::before {
	content: "";
	position: absolute;
	inset-block-start: -8vh;
	inset-inline-start: -12vw;
	width: min(70vw, 52rem);
	height: min(70vw, 52rem);
	pointer-events: none;
	z-index: -1;
	background: radial-gradient(
		circle at 30% 30%,
		color-mix(in srgb, var(--signal) 16%, transparent) 0%,
		transparent 62%
	);
	opacity: 0;
	animation: hero-glow 2.4s var(--ease-out-back) 240ms forwards;
}

@keyframes hero-glow {
	from { opacity: 0; transform: scale(0.86); }
	to   { opacity: 1; transform: scale(1); }
}

/* Masked word reveal -------------------------------------------------------
   Each word sits in an overflow-hidden box and rises into it. The blur resolve
   is what reads as contemporary; a plain translate reads as 2016. */

.hero__lead {
	display: flex;
	flex-wrap: wrap;
	gap: 0 0.28em;
}

.hero__w {
	display: inline-block;
	overflow: hidden;
	vertical-align: bottom;
	padding-block-end: 0.08em;
	margin-block-end: -0.08em;
}

/* Resting state. Words are hidden only once JS confirms it can reveal them —
   without JS and without scroll-timeline support they simply read normally. */
.hero__w > span {
	display: inline-block;
	will-change: transform, filter, opacity;
}

.js .hero__w > span {
	transform: translateY(105%);
	filter: blur(10px);
	opacity: 0;
}

/*
 * Fallback: the reveal fires when the hero scrolls into view, not on page
 * load. #hero is the second stacked panel, so a load-time animation finishes
 * long before anyone reaches it — the effect existed but was never seen.
 */
.js #hero.is-in .hero__w > span,
.js .section--hero.is-in .hero__w > span {
	animation: hero-word 1.05s var(--ease-out-back) forwards;
	animation-delay: calc(var(--i, 0) * 55ms);
}

@keyframes hero-word {
	to { transform: translateY(0); filter: blur(0); opacity: 1; }
}

/*
 * Preferred: tie each word to scroll position rather than to a timer, so the
 * line assembles as the reader scrolls and reverses if they scroll back. Each
 * word gets its own slice of the range via --i, which is what produces the
 * word-by-word cascade instead of one block fading in.
 */
@supports (animation-timeline: view()) {
	@media (prefers-reduced-motion: no-preference) {
		.js #hero .hero__w > span,
		.js .section--hero .hero__w > span {
			animation: hero-word 1s linear both;
			animation-timeline: view();
			animation-range:
				entry calc(18% + var(--i, 0) * 4%)
				entry calc(52% + var(--i, 0) * 4%);
			animation-delay: 0s;
		}
	}
}

/* Hairline that draws itself under the headline. */
.hero__lead::after {
	content: "";
	display: block;
	flex: 0 0 100%;
	height: 1px;
	margin-block-start: var(--s-5);
	background: linear-gradient(
		90deg,
		var(--signal) 0%,
		color-mix(in srgb, var(--signal) 30%, transparent) 60%,
		transparent 100%
	);
	transform-origin: left center;
	transform: scaleX(0);
	animation: hero-rule 1.1s var(--ease-out-back) 620ms forwards;
}

@keyframes hero-rule {
	to { transform: scaleX(1); }
}

/* Everything else fades up behind the headline — also on entry, not on load. */
.js .eyebrow,
.js .hero__name,
.js .hero__body,
.js .hero__links-wrap,
.js .hero__links { opacity: 0; }

.js #hero.is-in .eyebrow,
.js #hero.is-in .hero__name,
.js #hero.is-in .hero__body,
.js #hero.is-in .hero__links-wrap,
.js #hero.is-in .hero__links,
.js .section--hero.is-in .eyebrow,
.js .section--hero.is-in .hero__name,
.js .section--hero.is-in .hero__body,
.js .section--hero.is-in .hero__links-wrap,
.js .section--hero.is-in .hero__links {
	animation: hero-rise 0.9s var(--ease-out-back) forwards;
}

.eyebrow          { animation-delay: 80ms; }
.hero__name       { animation-delay: 40ms; }
.hero__body       { animation-delay: 760ms; }
.hero__links-wrap,
.hero__links      { animation-delay: 900ms; }

@keyframes hero-rise {
	from { opacity: 0; transform: translateY(14px); }
	to   { opacity: 1; transform: translateY(0); }
}

/* Pointer parallax — added by hero.js, never required. */
.section--hero[data-hero-parallax] .hero__lead,
.section--hero[data-hero-parallax] .hero__name {
	transform: translate3d(
		calc(var(--px, 0) * 1px),
		calc(var(--py, 0) * 1px),
		0
	);
	transition: transform 600ms cubic-bezier(0.2, 0, 0.2, 1);
}

/* Reduced motion: everything is simply present. No exceptions, no partial
   animation — a reduced-motion visitor should see a finished page. */
@media (prefers-reduced-motion: reduce) {
	.section--hero::before,
	.js .hero__w > span,
	.hero__w > span,
	.hero__lead::after,
	.eyebrow,
	.hero__name,
	.hero__body,
	.hero__links-wrap,
	.hero__links,
	.js .eyebrow,
	.js .hero__name,
	.js .hero__body,
	.js .hero__links-wrap,
	.js .hero__links {
		animation: none !important;
		opacity: 1 !important;
		transform: none !important;
		filter: none !important;
	}
	.section--hero[data-hero-parallax] .hero__lead,
	.section--hero[data-hero-parallax] .hero__name {
		transform: none !important;
		transition: none !important;
	}
}

/* No JS at all: the CSS above still runs, so nothing here depends on it. */
