@font-face {
	font-family: "Europa";
	src: url("assets/fonts/EuropaLight.woff2") format("woff2");
	font-weight: 300;
	font-display: swap;
}

@font-face {
	font-family: "Europa";
	src: url("assets/fonts/EuropaRegular.woff2") format("woff2");
	font-weight: 400;
	font-display: swap;
}

@font-face {
	font-family: "Europa";
	src: url("assets/fonts/EuropaBold.woff2") format("woff2");
	font-weight: 700;
	font-display: swap;
}

:root {
	--snow: #fcfdfe;
	--slate: #92a0b9;
	--dusk: #67789a;
	--night: #151f3b;
	--abyss: #121826;
	--accent: #0042ed;

	--fg: var(--night);
	--flake: var(--accent);
	--bg: var(--snow);
	--ui: var(--dusk);
	--ease-out: cubic-bezier(0.22, 1, 0.36, 1);
}

body[data-theme="dark"] {
	--fg: var(--snow);
	--flake: var(--snow);
	--bg: var(--abyss);
	--ui: var(--slate);
}

* {
	box-sizing: border-box;
}

/* The page itself scrolls, rather than a box inside it, so mobile Safari can tuck its bars away as the
   history plays. Its scrollbar and rubber-banding are hidden: the scroll only drives the scene. */
html {
	-webkit-text-size-adjust: 100%;
	text-size-adjust: 100%;
	overscroll-behavior: none;
	scrollbar-width: none;
}

html::-webkit-scrollbar {
	display: none;
}

html {
	background: var(--bg);
}

body {
	margin: 0;
}

button,
a {
	-webkit-tap-highlight-color: transparent;
	touch-action: manipulation;
}

body {
	font-family: "Europa", sans-serif;
	color: var(--fg);
	-webkit-font-smoothing: antialiased;
}

/* The page scrubs one continuous scene: a long, invisible scroll track drives it, and the scene stays
   fixed behind. Captions sit top-left, over the far city, because the stops fill the lower part of
   every frame. */

/* As tall as the viewport gets with Safari's bars tucked away, so the scene runs on underneath the bars
   instead of stopping short of them, and doesn't resize as they come and go. */
.history__stage {
	position: fixed;
	top: 0;
	left: 0;
	width: 100%;
	height: 100vh;
	height: 100lvh;
}

.history__layer {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	display: block;
}

.history__track {
	position: relative;
	z-index: 1;
}

body.is-low-motion .history__length {
	height: 100vh;
	height: 100svh;
}

.captions {
	position: fixed;
	inset: 0;
	z-index: 2;
	pointer-events: none;
}

/* Below the header row, where the low-motion switch sits. */
.caption {
	position: absolute;
	left: max(env(safe-area-inset-left), clamp(24px, 4vw, 64px));
	top: max(env(safe-area-inset-top), clamp(124px, 17vh, 176px));
	width: min(30rem, calc(100vw - 48px));
	opacity: 0;
	color: var(--fg);
	transition: color 700ms var(--ease-out);
}

.caption > * {
	position: relative;
	margin: 0;
}

/* A patch of mist behind the words, so they stay legible over the busy city below. */
.caption::before {
	content: "";
	position: absolute;
	inset: -48px -72px -48px -64px;
	background: radial-gradient(closest-side, color-mix(in srgb, var(--bg) 88%, transparent), transparent);
	transition: background 700ms var(--ease-out);
}

.caption__kicker {
	font-size: 10px;
	font-weight: 400;
	letter-spacing: 0.3em;
	text-transform: uppercase;
	color: var(--ui);
}

.caption__title {
	margin-top: 10px;
	font-size: clamp(19px, 1.7vw, 26px);
	font-weight: 700;
	letter-spacing: 0.01em;
	line-height: 1.15;
	text-wrap: balance;
}

.caption__quote {
	margin-top: 14px;
	font-size: clamp(15px, 1.15vw, 18px);
	font-weight: 300;
	line-height: 1.45;
	text-wrap: pretty;
	hanging-punctuation: first;
}

.caption__cite {
	margin-top: 8px;
	font-size: 11px;
	letter-spacing: 0.08em;
	color: var(--ui);
}

/* Logo centred, links on the right, and the links sit on the wordmark's baseline rather than level
   with the top of the snowflake. */
.masthead {
	position: fixed;
	top: max(env(safe-area-inset-top), clamp(28px, 6.5vh, 72px));
	left: max(env(safe-area-inset-left), clamp(24px, 4vw, 64px));
	right: max(env(safe-area-inset-right), clamp(24px, 4vw, 64px));
	z-index: 3;
	display: grid;
	grid-template-columns: 1fr auto 1fr;
	align-items: last baseline;
	pointer-events: none;
}

.lockup__title {
	grid-column: 2;
	margin: 0;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: clamp(12px, 1.6vh, 18px);
	font-size: clamp(11px, 0.95vw, 15px);
	line-height: 1;
	font-weight: 300;
	letter-spacing: 0.34em;
	text-transform: uppercase;
	color: var(--fg);
	transition: color 700ms var(--ease-out);
	animation: lockup-in 1800ms var(--ease-out) 250ms both;
}

.lockup__flake {
	width: clamp(26px, 2.3vw, 36px);
	height: auto;
	fill: var(--flake);
	transition: fill 700ms var(--ease-out);
	animation: flake-in 2200ms var(--ease-out) both;
}

.lockup__word {
	white-space: nowrap;
	/* Tracking adds trailing space after the last letter; pull it back so the line centres optically. */
	margin-right: -0.34em;
}

.lockup__valor {
	font-weight: 700;
}

@keyframes lockup-in {
	from {
		opacity: 0;
		letter-spacing: 0.6em;
	}
}

@keyframes flake-in {
	from {
		opacity: 0;
		transform: rotate(-30deg) scale(0.8);
	}
}

.site-nav {
	grid-column: 3;
	grid-row: 1;
	justify-self: end;
	pointer-events: auto;
	display: flex;
	align-items: baseline;
	gap: 14px;
	font-size: clamp(10px, 0.8vw, 12px);
	font-weight: 400;
	letter-spacing: 0.24em;
	text-transform: uppercase;
	animation: fade-in 1200ms var(--ease-out) 600ms both;
}

.site-nav__link {
	color: var(--fg);
	text-decoration: none;
	padding: 6px 0;
	transition:
		color 700ms var(--ease-out),
		opacity 160ms var(--ease-out);
}

.site-nav__link:hover {
	opacity: 0.6;
}

.site-nav__link:focus-visible {
	outline: 1px solid var(--accent);
	outline-offset: 4px;
}

/* Bottom left: play the history on its own, or switch to low motion. */
.controls {
	position: fixed;
	z-index: 3;
	left: max(env(safe-area-inset-left), clamp(24px, 4vw, 64px));
	bottom: max(env(safe-area-inset-bottom), clamp(22px, 4vh, 48px));
	display: flex;
	align-items: baseline;
	gap: 28px;
}

/* The same patch of mist the captions have, so the controls read over a dark city. */
.controls::before {
	content: "";
	position: absolute;
	inset: -28px -48px;
	background: radial-gradient(closest-side, color-mix(in srgb, var(--bg) 85%, transparent), transparent);
	pointer-events: none;
}

.controls > * {
	position: relative;
}

.autoplay {
	padding: 6px 0;
	border: 0;
	background: none;
	color: var(--fg);
	font: inherit;
	font-size: clamp(10px, 0.8vw, 12px);
	font-weight: 400;
	letter-spacing: 0.24em;
	text-transform: uppercase;
	cursor: pointer;
	animation: fade-in 1200ms var(--ease-out) 600ms both;
}

.autoplay:hover {
	opacity: 0.6;
}

.autoplay:focus-visible {
	outline: 1px solid var(--accent);
	outline-offset: 4px;
}

body.is-low-motion .autoplay {
	display: none;
}

.motion-toggle {
	pointer-events: auto;
	display: inline-flex;
	align-items: baseline;
	gap: 10px;
	padding: 6px 0;
	border: 0;
	background: none;
	color: var(--fg);
	font: inherit;
	font-size: clamp(10px, 0.8vw, 12px);
	font-weight: 400;
	letter-spacing: 0.24em;
	text-transform: uppercase;
	cursor: pointer;
	transition:
		color 700ms var(--ease-out),
		opacity 160ms var(--ease-out);
	animation: fade-in 1200ms var(--ease-out) 600ms both;
}

.motion-toggle:hover {
	opacity: 0.6;
}

.motion-toggle:focus-visible {
	outline: 1px solid var(--accent);
	outline-offset: 4px;
}

.motion-toggle__switch {
	position: relative;
	align-self: center;
	width: 22px;
	height: 12px;
	border: 1px solid currentColor;
	border-radius: 6px;
	transition:
		background 200ms var(--ease-out),
		border-color 200ms var(--ease-out);
}

.motion-toggle__switch::after {
	content: "";
	position: absolute;
	top: 2px;
	left: 2px;
	width: 6px;
	height: 6px;
	border-radius: 50%;
	background: currentColor;
	transition:
		transform 200ms var(--ease-out),
		background 200ms var(--ease-out);
}

.motion-toggle[aria-pressed="true"] .motion-toggle__switch {
	background: var(--accent);
	border-color: var(--accent);
}

.motion-toggle[aria-pressed="true"] .motion-toggle__switch::after {
	transform: translateX(10px);
	background: var(--bg);
}

.site-nav__rule {
	color: var(--ui);
}

/* On a narrow screen the captions drop below the lockup and links instead of colliding with them. */
@media (max-width: 760px) {
	.caption {
		top: max(env(safe-area-inset-top), 132px);
	}

	/* The logo fills the header on a phone, so the switch and the links share the bottom edge. */
	.site-nav {
		position: fixed;
		bottom: max(env(safe-area-inset-bottom), 22px);
		right: max(env(safe-area-inset-right), 24px);
	}

	.controls {
		bottom: max(env(safe-area-inset-bottom), 22px);
		left: max(env(safe-area-inset-left), 24px);
		gap: 18px;
	}

	.cue {
		display: none;
	}
}

.cue {
	position: fixed;
	z-index: 3;
	left: 50%;
	bottom: max(env(safe-area-inset-bottom), 22px);
	width: 1px;
	height: 44px;
	background: color-mix(in srgb, var(--ui) 35%, transparent);
	overflow: hidden;
	animation: fade-in 900ms var(--ease-out) 2200ms both;
}

.cue::after {
	content: "";
	position: absolute;
	left: 0;
	top: -14px;
	width: 1px;
	height: 14px;
	background: var(--fg);
	animation: cue-drop 2.4s var(--ease-out) infinite;
}

@keyframes cue-drop {
	to {
		transform: translateY(58px);
	}
}

@keyframes fade-in {
	from {
		opacity: 0;
	}
}

@media (prefers-reduced-motion: reduce) {
	.lockup__title,
	.lockup__flake,
	.site-nav,
	.motion-toggle,
	.cue,
	.cue::after {
		animation: none;
	}

	.motion-toggle__switch,
	.motion-toggle__switch::after {
		transition: none;
	}
}

/* Low motion: the painting alone, standing still. The captions stay readable to screen readers. */
body.is-low-motion .history__layer,
body.is-low-motion .cue {
	display: none;
}

/* Low motion tells the whole story in one panel over the still painting. */
.still-story {
	display: none;
}

body.is-low-motion .still-story {
	display: block;
	position: fixed;
	z-index: 2;
	left: max(env(safe-area-inset-left), clamp(24px, 4vw, 64px));
	top: max(env(safe-area-inset-top), clamp(124px, 17vh, 176px));
	width: min(32rem, calc(100vw - 48px));
	color: var(--fg);
}

.still-story > * {
	position: relative;
	margin: 0;
}

.still-story::before {
	content: "";
	position: absolute;
	inset: -48px -72px -48px -64px;
	background: radial-gradient(closest-side, color-mix(in srgb, var(--bg) 90%, transparent), transparent);
}

.still-story__body {
	margin-top: 14px;
	font-size: clamp(15px, 1.1vw, 17px);
	font-weight: 300;
	line-height: 1.5;
	text-wrap: pretty;
}

@media (max-width: 760px) {
	body.is-low-motion .still-story {
		top: max(env(safe-area-inset-top), 132px);
	}
}

body.is-low-motion .caption {
	opacity: 0 !important;
}

body.is-low-motion .motion-toggle__switch,
body.is-low-motion .motion-toggle__switch::after {
	transition: none;
}

/* Without WebGL2, or in low motion, the page shows the painting the scene comes to rest on. */
body.is-static .history__stage,
body.is-low-motion .history__stage {
	background: var(--bg) url("assets/plate.jpg") 51.5% center / cover no-repeat;
}
