/*
Theme Name: heiko-saxo
Theme URI:
Author: Claus Ernst
Author URI:
Description: Heiko-Saxo-Website
Requires at least: 7.1
Tested up to: 7.1
Requires PHP: 5.7
Version: 0.18.2
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: heiko-saxo
*/

:root {
	--gutter: clamp(1.25rem, 4vw, 7rem);
	--header-height: 5rem;
	--ease: cubic-bezier(0.2, 0.7, 0.2, 1);
	--light-70: color-mix(in srgb, var(--wp--preset--color--light) 70%, transparent);
	--light-55: color-mix(in srgb, var(--wp--preset--color--light) 55%, transparent);
	--hairline: color-mix(in srgb, var(--wp--preset--color--light) 14%, transparent);
}

html {
	background-color: #0a0a0a;
	color-scheme: dark;
	scrollbar-gutter: stable;
}

.wp-site-blocks {
	display: flex;
	flex-direction: column;
	min-height: 100dvh;
}

/* Sections run edge to edge, so the block gap between them would expose the
   page background as a stripe. On the front page the sections are page content,
   which nests them one level deeper inside the post content wrapper. */
.wp-site-blocks > * + *,
.wp-site-blocks > main > * + *,
body.home .wp-block-post-content > * + * {
	margin-block-start: 0;
}

.wp-site-blocks > footer {
	margin-top: auto;
}

:where(a, button, input, textarea, select, summary):focus-visible {
	outline: 2px solid var(--wp--preset--color--gold);
	outline-offset: 4px;
}

/* Headings are short enough for the browser to even the lines out rather than
   filling each one before starting the next. Without it a title like "Privacy
   and Cookies Policy" leaves its last word stranded on a line of its own. */
:is(h1, h2, h3, h4) {
	text-wrap: balance;
}

/* ---------------------------------------------------------------- Header */

.wp-site-blocks > header {
	position: fixed;
	inset-inline: 0;
	top: 0;
	z-index: 100;
	background-color: rgba(10, 10, 10, 0.18);
	backdrop-filter: blur(14px) saturate(140%);
	-webkit-backdrop-filter: blur(14px) saturate(140%);
	border-bottom: 1px solid transparent;
	transition: background-color 0.5s var(--ease), border-color 0.5s var(--ease);
}

.site-header__inner {
	padding-inline: var(--gutter);
	padding-block: clamp(0.85rem, 1.7vw, 1.5rem);
	transition: padding-block 0.5s var(--ease);
}

body.is-scrolled > .wp-site-blocks > header {
	background-color: rgba(10, 10, 10, 0.78);
	border-bottom-color: var(--hairline);
}

body.is-scrolled .site-header__inner {
	padding-block: clamp(0.6rem, 1.1vw, 1rem);
}

.wordmark {
	margin: 0;
	font-size: clamp(1.15rem, 1.25vw, 1.6rem);
	line-height: 0.95;
	letter-spacing: 0.22em;
	text-transform: uppercase;
	color: var(--wp--preset--color--gold);
	/* Gruppo ships a single weight, so the strokes are thickened with an
	   outline rather than left to the browser's faux bold. */
	-webkit-text-stroke: 0.022em currentColor;
}

.wordmark a {
	display: inline-block;
	color: inherit;
	transition: color 0.4s var(--ease);
}

.wordmark a:hover {
	color: var(--wp--preset--color--light);
}

.wordmark img {
	display: block;
	height: clamp(2.15rem, 3.25vw, 2.86rem);
	width: auto;
}

/* The menu is set in the same voice as the eyebrows: small, wide, quiet, and
   gold only where it points at something. */
.site-nav {
	font-weight: 500;
	letter-spacing: 0.2em;
	text-transform: uppercase;
}

.site-nav .wp-block-navigation-item__content {
	color: var(--light-70);
	transition: color 0.4s var(--ease);
}

.site-nav .wp-block-navigation-item__content:hover,
.site-nav .current-menu-item .wp-block-navigation-item__content {
	color: var(--wp--preset--color--gold);
}

/* The word rather than a burger: it is legible without being learned, and it
   is set in the same voice as the entries it opens. Built in JavaScript, so a
   page without it never shows a control that cannot do anything. */
.site-nav__toggle {
	display: none;
	/* Grown to a thumb-sized target and pulled back again, so the bar stays as
	   tall as the wordmark rather than as tall as the button. */
	padding-block: 0.75rem;
	margin-block: -0.75rem;
	padding-inline: 0;
	border: 0;
	background: none;
	font: inherit;
	font-size: var(--wp--preset--font-size--micro);
	font-weight: 500;
	letter-spacing: 0.2em;
	text-transform: uppercase;
	color: var(--light-70);
	cursor: pointer;
	transition: color 0.4s var(--ease);
}

.site-nav__toggle:hover,
.site-nav__toggle[aria-expanded="true"] {
	color: var(--wp--preset--color--gold);
}

/* Three entries already crowd the wordmark here, and the menu is meant to
   grow. Raising this number is all it takes to hand more room back to the
   inline row. */
@media (max-width: 52rem) {
	.site-nav__toggle {
		display: block;
	}

	/* The wordmark and the button keep the bar to themselves; the menu drops
	   onto a full-width row below, which is what gives the header something
	   to unfold into. */
	header .site-header__inner {
		flex-wrap: wrap;
		row-gap: 0;
	}

	/* A row measured in fractions can be animated, where one measured in
	   pixels would need a height nobody knows in advance. */
	nav.site-nav {
		flex-basis: 100%;
		display: grid;
		/* Without a column of its own the list is only as wide as its longest
		   word, and the navigation block's right-justification then parks that
		   column at the edge instead of laying the entries across the panel. */
		grid-template-columns: minmax(0, 1fr);
		grid-template-rows: 0fr;
		/* The navigation block centres its list, which in a row of no height
		   leaves the entries hanging out above and below it instead of being
		   squeezed away by it. */
		align-items: stretch;
		transition: grid-template-rows 0.5s var(--ease);
	}

	.wp-site-blocks > header.is-open nav.site-nav {
		grid-template-rows: 1fr;
	}

	/* The collapsing row has to clip what it can no longer show, and this is
	   also what lets it shrink past the height of its own contents. */
	/* Padding here would survive the collapse — a row of no height still has
	   to make room for it — and leave a sliver of menu showing while shut.
	   The hairline above the first entry does the separating instead. */
	.site-nav .wp-block-navigation__container {
		overflow: hidden;
		flex-direction: column;
		/* The navigation wraps by default, which in a column means wrapping
		   sideways. While the panel is still unfolding there is not yet the
		   height for three entries, so they would spread into columns beside
		   one another and only fall into line once the animation ends. */
		flex-wrap: nowrap;
		align-items: stretch;
		gap: 0;
	}

	/* Full-width rows separated by hairlines, so the panel reads as a list of
	   places rather than a line of words that happened to wrap. Each item is a
	   flex row of its own, in which the link would otherwise stay as narrow as
	   its label and carry a rule only that wide. */
	.site-nav .wp-block-navigation-item {
		display: block;
	}

	.site-nav .wp-block-navigation-item__content {
		display: block;
		padding-block: clamp(0.7rem, 2.5vw, 1rem);
		border-block-start: 1px solid var(--hairline);
	}

	/* Unfolding over the hero, an 18% veil would leave the entries unreadable,
	   so the panel darkens to the value the header reaches once scrolled. */
	.wp-site-blocks > header.is-open {
		background-color: rgba(10, 10, 10, 0.78);
		border-bottom-color: var(--hairline);
	}
}

/* Non-front templates sit below the fixed header. Designed pages carry the
   page-canvas class and keep clear of this: they run edge to edge and let their
   own opening section make room for the header, exactly like the front page. */

body:not(.home) .wp-site-blocks > main:not(.page-canvas) {
	padding-top: calc(var(--header-height) + clamp(2rem, 5vw, 5rem));
	padding-inline: var(--gutter);
}

/* ------------------------------------------------------------------ Hero */

.hero {
	position: relative;
	display: flex;
	align-items: flex-end;
	min-height: max(88svh, 50vw);
	padding-block: calc(var(--header-height) + clamp(2rem, 6vw, 6rem)) clamp(3rem, 7vw, 6.5rem);
	padding-inline: var(--gutter);
	/* Slides, scrim and text are layered by z-index; a private stacking context
	   keeps that ordering from reaching into the rest of the page. */
	isolation: isolate;
}

/* All slides occupy the same box. Which one is opaque is decided below.
   Clipping matters here: the zoom below scales the slides past their box, and
   without it the widened image would push a horizontal scrollbar onto the page.
   The descendant selector is what outweighs the editor's own rule, which gives
   every block position: relative and would otherwise drop this out of place. */
.hero .hero__slides {
	position: absolute;
	inset: 0;
	z-index: 0;
	overflow: hidden;
}

.hero__slides :is(.wp-block-image, .wp-block-video) {
	position: absolute;
	inset: 0;
	margin: 0;
	transition: opacity 1.2s var(--ease);
}

/* Until the script has taken over, the first slide carries the hero alone. */
.hero__slides :is(.wp-block-image, .wp-block-video):not(:first-child) {
	opacity: 0;
}

/* Afterwards .is-active is the only thing that decides, so these two rules have
   to outrank the one above. They match with equal specificity and win on order.  */
.hero__slides.is-running :is(.wp-block-image, .wp-block-video) {
	opacity: 0;
}

.hero__slides.is-running :is(.wp-block-image, .wp-block-video).is-active {
	opacity: 1;
}
.hero__slides :is(img, video) {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.hero__slides figcaption {
	display: none;
}

/* The hero photograph is already dark (mean luminance ~35/255), so the scrim
   only needs enough weight to carry the text in the lower left corner. */
.hero__slides::after {
	content: "";
	position: absolute;
	inset: 0;
	opacity: 0.4;
	z-index: 1;
	background-image:
		linear-gradient(180deg, rgba(10, 10, 10, 0.45) 0%, rgba(10, 10, 10, 0) 26%),
		radial-gradient(
			130% 110% at -10% 110%,
			rgba(10, 10, 10, 0.95) 0%,
			rgba(10, 10, 10, 0.85) 30%,
			rgba(10, 10, 10, 0.6) 55%,
			rgba(10, 10, 10, 0.2) 78%,
			rgba(10, 10, 10, 0) 100%
		);
}

/* The text column is a flex item sized from its content, which inline-size
   containment hides. An explicit basis keeps it full width. */
.hero .hero__content {
	/* A quarter under the original display size. "Golden Hearts" measures
	   8.57em in Gruppo, so 8.4cqi still keeps the headline on two lines. */
	--hero-title-size: min(calc(var(--wp--preset--font-size--display) * 0.75), 8.4cqi);
	--hero-gap: max(1.1rem, calc(var(--hero-title-size) * 0.3));
	position: relative;
	z-index: 1;
	flex-basis: 100%;
	container-type: inline-size;
	/* The hero is a group, so its block gap would otherwise land on this, the
	   only child in the flow. The slides are positioned and need no gap. */
	margin-block: 0;
}

/* Trimmed leading turns the margin below into the actual optical distance, so
   label, headline, rule and credo sit on four equal gaps. */
.hero .hero__content > *:not(.hero__media) {
	text-box: trim-both cap alphabetic;
}

.hero .hero__content > * + * {
	margin-block-start: var(--hero-gap);
}

/* A collapsed control row must not leave its sibling gap on the eyebrow. */
.hero .hero__content > .hero__media[hidden] + * {
	margin-block-start: 0;
}

/* Gruppo's capital G sits 0.053em inside its advance width, so the label needs
   the same offset to align with the headline stem below it. */
.hero .hero__label,
.hero .hero__media {
	margin-inline-start: calc(var(--hero-title-size) * 0.053);
}

.hero .hero__media {
	display: flex;
	align-items: center;
	gap: 0.65rem;
}

.hero .hero__media[hidden] {
	display: none;
}

.hero .hero__media button {
	display: grid;
	place-items: center;
	width: 2.5rem;
	height: 2.5rem;
	padding: 0;
	border: 0;
	background: none;
	color: var(--light-55);
	cursor: pointer;
	transition: color 0.4s var(--ease);
}

.hero .hero__media button:hover {
	color: var(--wp--preset--color--gold);
}

.hero .hero__media svg {
	display: block;
	width: 1.15rem;
	height: 1.15rem;
	fill: currentColor;
}

.hero .hero__media :is(.hero__audio-wave, .hero__audio-off) {
	fill: none;
	stroke: currentColor;
	stroke-width: 1.75;
	stroke-linecap: round;
}

.hero .hero__play:not(.is-paused) .hero__play-icon--play,
.hero .hero__play.is-paused .hero__play-icon--pause,
.hero .hero__audio.is-muted .hero__audio-wave,
.hero .hero__audio:not(.is-muted) .hero__audio-off {
	display: none;
}

.hero .hero__title {
	font-size: var(--hero-title-size);
	text-transform: uppercase;
	letter-spacing: 0.005em;
	line-height: 0.92;
}

.hero :is(.hero__label, .hero__title, .hero__credo) {
	text-shadow: 0 0.4rem 1.4rem rgba(0, 0, 0, 0.7);
}

/* On a work page the label is the way back to all works. */
.hero .hero__label a {
	color: inherit;
	text-decoration: none;
	transition: color 0.4s var(--ease);
}

.hero .hero__label a:hover {
	color: var(--wp--preset--color--light);
}

/* ------------------------------------------------------- Editorial block */

.editorial {
	padding-inline: var(--gutter);
	padding-block: clamp(4.5rem, 9vw, 11rem);
}

.editorial__grid {
	gap: clamp(2.5rem, 5vw, 7rem);
	align-items: start;
}

/* Both columns start on the same optical line: the leading above the first
   line is trimmed, so the columns align by cap height, not by line box. */
.editorial__aside > :first-child,
.editorial__copy > :first-child {
	text-box: trim-start cap alphabetic;
}

.editorial__aside {
	container-type: inline-size;
}

.editorial__aside > * + * {
	margin-block-start: clamp(1.5rem, 2.5vw, 2.5rem);
}

/* Sized against the column, not the viewport, so long words never break. */
.editorial .statement {
	font-size: clamp(1.75rem, 11.5cqi, 5.5rem);
	text-transform: uppercase;
	line-height: 1.12;
	letter-spacing: 0.01em;
}

.editorial__copy > * + * {
	margin-block-start: clamp(1.1rem, 1.6vw, 1.75rem);
}

.editorial__copy p {
	max-width: 64ch;
}

.editorial__copy > .arrow-link {
	margin-block-start: clamp(2rem, 3.5vw, 3.75rem);
}

/* -------------------------------------------------------- Featured works */

.featured {
	padding-block-start: clamp(4rem, 8vw, 9rem);
}

.featured__intro {
	position: relative;
	padding-inline: var(--gutter);
	padding-block-end: clamp(2.5rem, 5vw, 4.5rem);
	container-type: inline-size;
}

.featured__intro > * + * {
	margin-block-start: clamp(1.25rem, 2.2vw, 2.25rem);
}

.featured__eyebrow {
	display: flex;
	align-items: center;
	gap: clamp(1rem, 2vw, 1.75rem);
}

.featured__eyebrow::after {
	content: "";
	width: clamp(2.5rem, 5vw, 4.5rem);
	height: 1px;
	background-color: var(--wp--preset--color--gold);
}

/* "Created to Inspire." measures 12.5em in Gruppo, so 8cqi holds the statement
   to two lines from the narrowest phone up to ultra-wide screens. */
.featured__title {
	font-size: min(var(--wp--preset--font-size--x-large), 8cqi);
	text-transform: uppercase;
	line-height: 1.1;
	letter-spacing: 0.01em;
}

/* A short, muted line beneath an opening. Kept narrow so on the front page it
   never runs under the band's arrows on the right. */
.featured__lede,
.page-hero__lede {
	max-width: 40ch;
	color: var(--light-55);
	text-wrap: balance;
}

.page-hero__lede {
	max-width: 64ch;
}

/* The band runs edge to edge and scrolls sideways, so the number of works no
   longer decides the layout. The single pixel gap lets the section background
   through as a hairline seam between the frames. */
.featured .featured__band {
	display: grid;
	grid-auto-flow: column;
	/* The minimum is set below a clean division of the viewport, so as soon as
	   the works overflow, the following card is cut off at the right edge —
	   that sliver is the only cue that the band continues. As long as they all
	   fit, the fr maximum lets them share the leftover space and the band looks
	   exactly like the fixed row it replaces. */
	grid-auto-columns: minmax(78%, 1fr);
	gap: 1px;
	overflow-x: auto;
	scroll-snap-type: x mandatory;
	/* Keeps a swipe that runs out of band from turning into a page or history
	   gesture on touchpads and phones. */
	overscroll-behavior-x: contain;
	/* The band carries its own progress bar below it, so the native one would
	   only duplicate it and eat into the frames. */
	scrollbar-width: none;
	cursor: grab;
}

.featured .featured__band.is-static {
	cursor: default;
}

/* Suppressing selection only while the band is held keeps the labels
   selectable the rest of the time. */
.featured .featured__band.is-grabbing,
.featured .featured__progress.is-grabbing {
	cursor: grabbing;
	user-select: none;
}

.featured .featured__band::-webkit-scrollbar {
	display: none;
}

.featured__band > * {
	margin-block-start: 0;
	scroll-snap-align: start;
}

@media (min-width: 40rem) {
	.featured .featured__band {
		grid-auto-columns: minmax(42%, 1fr);
	}
}

@media (min-width: 64rem) {
	.featured .featured__band {
		grid-auto-columns: minmax(23%, 1fr);
	}
}

/* Arrows and progress bar are built by the script, so they exist only where
   they can actually do something. */
.featured__nav {
	display: none;
}

/* Below this width the band is almost always operated by thumb, and the arrows
   would collide with the headline. */
@media (min-width: 64rem) {
	.featured__nav:not([hidden]) {
		position: absolute;
		right: var(--gutter);
		bottom: clamp(2.5rem, 5vw, 4.5rem);
		display: flex;
		gap: 0.9rem;
	}
}

.featured__nav button,
.hero__pager button {
	display: grid;
	place-items: center;
	width: clamp(3.75rem, 4.5vw, 5rem);
	aspect-ratio: 1;
	padding: 0;
	/* The ring stays a hairline at any size, like every other rule on the
	   page. */
	border: 1px solid var(--hairline);
	border-radius: 50%;
	background: none;
	color: inherit;
	font-size: 1.5rem;
	line-height: 1;
	cursor: pointer;
	transition:
		border-color 0.4s var(--ease),
		color 0.4s var(--ease),
		opacity 0.4s var(--ease);
}

.featured__nav button:hover:not(:disabled),
.hero__pager button:hover {
	border-color: var(--wp--preset--color--gold);
	color: var(--wp--preset--color--gold);
}

.featured__nav button:disabled {
	opacity: 0.25;
	cursor: default;
}

/* A hairline the width of the section with a gold thumb on it: same read as a
   scrollbar, in the same language as the rules elsewhere on the page. The box
   itself is a finger-tall, invisible grab area, because a one pixel target
   cannot be hit; the rules are drawn centred inside it, so thickening them on
   hover moves nothing around them. */
.featured .featured__progress {
	position: relative;
	height: 1rem;
	margin-block-start: calc(clamp(1.75rem, 3vw, 3rem) - 0.5rem);
	margin-inline: var(--gutter);
	cursor: grab;
}

.featured .featured__progress::before,
.featured .featured__progress::after {
	content: "";
	position: absolute;
	top: 50%;
	height: 1px;
	transform: translateY(-50%);
	transition: height 0.3s var(--ease);
}

.featured .featured__progress::before {
	inset-inline: 0;
	background-color: var(--hairline);
}

.featured .featured__progress::after {
	left: var(--thumb-start, 0%);
	width: var(--thumb-size, 100%);
	background-color: var(--wp--preset--color--gold);
}

.featured .featured__progress:hover::before,
.featured .featured__progress:hover::after,
.featured .featured__progress.is-grabbing::before,
.featured .featured__progress.is-grabbing::after {
	height: 3px;
}

.work-card__media {
	margin: 0;
	overflow: clip;
}

.work-card__media img {
	display: block;
	width: 100%;
	aspect-ratio: 1.1;
	object-fit: cover;
	transition: transform 0.9s var(--ease);
}

.work-card:hover .work-card__media img {
	transform: scale(1.04);
}

.work-card__label {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 1rem;
	margin-block-start: 0;
	padding-block: clamp(1rem, 1.8vw, 1.5rem);
	padding-inline: clamp(1rem, 1.6vw, 1.75rem);
	border-block-end: 1px solid var(--hairline);
	font-weight: 500;
	letter-spacing: 0.2em;
	text-transform: uppercase;
}

.work-card__label::after {
	content: "";
	flex: none;
	width: clamp(1.75rem, 3vw, 3rem);
	height: 1px;
	background-color: var(--wp--preset--color--gold);
	transition: width 0.5s var(--ease);
}

.work-card:hover .work-card__label::after {
	width: clamp(2.5rem, 4.5vw, 4.5rem);
}

/* The label carries the link, but the picture above it is what people click.
   Stretched over the whole card, the link catches both. */
.work-card {
	position: relative;
}

.work-card__label a::before {
	content: "";
	position: absolute;
	inset: 0;
}

/* -------------------------------------------------------------- Work page */

/* Built by the script for any hero with more than one slide. */
.hero__pager {
	position: absolute;
	right: var(--gutter);
	bottom: clamp(3rem, 7vw, 6.5rem);
	z-index: 2;
	display: flex;
	align-items: center;
	gap: clamp(0.75rem, 1.4vw, 1.25rem);
}

.hero__count {
	min-width: 5.5em;
	font-size: var(--wp--preset--font-size--micro);
	font-weight: 500;
	font-variant-numeric: tabular-nums;
	letter-spacing: 0.2em;
	text-align: center;
	color: var(--light-70);
}

/* Room for the pager beside the title, so a long name wraps before it. */
@media (min-width: 46rem) {
	.hero--work .hero__content {
		padding-inline-end: 18rem;
	}
}

/* On a phone the title needs the full width, and the thumb swipes anyway. */
@media (max-width: 46rem) {
	.hero__pager {
		display: none;
	}
}

.hero .hero__slides {
	touch-action: pan-y;
}

.work-intro {
	gap: clamp(2.5rem, 5vw, 7rem);
	margin: 0;
	padding-inline: var(--gutter);
	padding-block: clamp(4rem, 8vw, 9rem);
}

.work-intro__text > * {
	max-width: 60ch;
	color: var(--light-70);
}

/* The opening sentence speaks in the display face, like the quotes on Press. */
.work-intro__text > .work-intro__lede {
	max-width: 30ch;
	font-family: var(--wp--preset--font-family--display);
	font-size: clamp(1.4rem, 2.4vw, 2.1rem);
	line-height: 1.3;
	color: var(--wp--preset--color--light);
}

/* A museum label: each paragraph is one row, its bold word the caption. */
.work-facts p {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 1.5rem;
	margin: 0;
	padding-block: clamp(0.85rem, 1.4vw, 1.2rem);
	border-block-start: 1px solid var(--hairline);
	text-align: end;
}

.work-facts p:last-child {
	border-block-end: 1px solid var(--hairline);
}

.work-facts strong {
	flex: none;
	font-size: var(--wp--preset--font-size--micro);
	font-weight: 500;
	letter-spacing: 0.2em;
	text-transform: uppercase;
	color: var(--light-55);
}

.work-gallery {
	padding-block-end: clamp(3.5rem, 7vw, 7rem);
}

.work-gallery .wp-block-gallery {
	margin: 0;
	padding-inline: var(--gutter);
}

/* The way on to the next work, set as large as a chapter heading so the page
   ends on a door rather than on the footer. */
.next-work {
	padding-inline: var(--gutter);
	padding-block: clamp(3rem, 6vw, 6rem);
	border-block-start: 1px solid var(--hairline);
}

.next-work__link {
	display: inline-flex;
	flex-direction: column;
	gap: clamp(1rem, 1.6vw, 1.5rem);
	color: inherit;
	text-decoration: none;
}

.next-work__label {
	font-size: var(--wp--preset--font-size--micro);
	font-weight: 500;
	letter-spacing: 0.2em;
	text-transform: uppercase;
	color: var(--wp--preset--color--gold);
}

.next-work__title {
	display: inline-flex;
	align-items: center;
	gap: clamp(1.25rem, 2.5vw, 2.5rem);
	font-size: clamp(1.9rem, 3.2vw, 3rem);
	line-height: 1.08;
	letter-spacing: 0.01em;
	text-transform: uppercase;
	transition: color 0.4s var(--ease);
}

.next-work__title::after {
	content: "";
	flex: none;
	width: clamp(2.5rem, 5vw, 4.5rem);
	height: 1px;
	background-color: var(--wp--preset--color--gold);
	transition: width 0.5s var(--ease);
}

a.next-work__link:hover .next-work__title {
	color: var(--wp--preset--color--gold);
}

a.next-work__link:hover .next-work__title::after {
	width: clamp(3.5rem, 7vw, 6.5rem);
}

/* --------------------------------------------------------- Page openings */

/* Subpages open on type alone, against the same black the front page hero
   fades into. The top padding stands in for the fixed header, which the
   page-canvas main deliberately does not account for. */
.page-hero {
	padding-inline: var(--gutter);
	padding-block: calc(var(--header-height) + clamp(4rem, 9vw, 9rem)) clamp(2.5rem, 5vw, 5rem);
	container-type: inline-size;
}

/* Trimmed leading turns the block gap into the actual optical distance, so
   label, headline, rule and span sit on three equal gaps. */
.page-hero > * {
	text-box: trim-both cap alphabetic;
}

/* Same measure as the front page headline, so both openings set at one size. */
.page-hero__title {
	font-size: min(calc(var(--wp--preset--font-size--display) * 0.75), 8.4cqi);
	text-transform: uppercase;
	letter-spacing: 0.005em;
	line-height: 0.92;
}

/* On a phone the width-bound measure shrinks the headline to body-text scale.
   10.5cqi still keeps "Golden Hearts" (8.57em) on one line. The display preset
   is fluid and shrinks on its own here, so the cap is its full desktop value. */
@media (max-width: 46rem) {
	.hero .hero__content {
		--hero-title-size: min(3.75rem, 10.5cqi);
	}

	.page-hero__title {
		font-size: min(3.75rem, 10.5cqi);
	}
}

.page-hero__lede a {
	color: var(--wp--preset--color--light);
	text-decoration: underline;
	text-decoration-color: var(--hairline);
	text-underline-offset: 0.25em;
	transition: text-decoration-color 0.4s var(--ease);
}

.page-hero__lede a:hover {
	text-decoration-color: var(--wp--preset--color--gold);
}

/* Alone on its page — 404, coming soon — the opening would leave the footer
   riding up under it. */
.page-hero.page-hero--solo {
	display: flex;
	flex-direction: column;
	justify-content: center;
	min-height: 78svh;
}

.page-hero__span {
	color: var(--light-55);
	letter-spacing: 0.16em;
	text-transform: uppercase;
}

/* --------------------------------------------------- Chapters and plates */

/* Long pages are divided into chapters — decades on References, years on
   Press. The rule runs from the heading to the right edge, the same gesture
   that ends the eyebrow above the featured works. */
.chapter {
	display: flex;
	align-items: center;
	gap: clamp(1.25rem, 2.5vw, 2.5rem);
	padding-inline: var(--gutter);
	padding-block: clamp(4rem, 8vw, 8rem) clamp(2rem, 4vw, 3.5rem);
	letter-spacing: 0.02em;
}

.chapter::after {
	content: "";
	flex: 1;
	height: 1px;
	background-color: var(--hairline);
}

/* One photograph opens a chapter, edge to edge and short enough to stay a
   band rather than a second hero. */
.plate {
	margin: 0;
}

.plate img {
	display: block;
	width: 100%;
	height: clamp(16rem, 40vw, 40rem);
	object-fit: cover;
}

/* -------------------------------------------------------------- Chronicle */

/* The entry carries no block gap of its own, so the distance between the year
   and its list is the grid's alone — stacked below and columnar above. */
.chronicle__year {
	display: grid;
	row-gap: clamp(1.1rem, 3vw, 1.6rem);
	padding-inline: var(--gutter);
	padding-block: clamp(2rem, 3.5vw, 3.25rem);
	border-block-start: 1px solid var(--hairline);
}

/* The chapter already draws a rule of its own, and the plate is a hard edge. */
.chapter + .chronicle__year,
.plate + .chronicle__year {
	border-block-start: 0;
}

.chronicle__number {
	font-size: clamp(2.25rem, 3.6vw, 3.5rem);
	line-height: 1;
}

.chronicle__items {
	margin: 0;
	padding: 0;
	list-style: none;
	/* Long enough for the sprawling entries of 2007 and 2009 to stay readable
	   without running the full width of a wide screen. */
	max-width: 66ch;
	color: var(--light-70);
}

.chronicle__items li + li {
	margin-block-start: clamp(0.7rem, 1.2vw, 1.15rem);
}

.chronicle__items li {
	position: relative;
	padding-inline-start: clamp(1.6rem, 2.4vw, 2.25rem);
}

/* A short gold rule in place of a bullet, sitting on the cap height of the
   first line — the same mark that closes the eyebrows and the card labels. */
.chronicle__items li::before {
	content: "";
	position: absolute;
	inset-inline-start: 0;
	top: 0.78em;
	width: clamp(0.7rem, 1.3vw, 1.15rem);
	height: 1px;
	background-color: var(--wp--preset--color--gold);
}

/* Wide enough for two columns once the entries still have a readable measure
   beside a year that is legible at a glance. */
@media (min-width: 52rem) {
	.chronicle__year {
		/* Wide enough for "The year of Golden Hearts Never Die", the longest of
		   the forty-two, to fall on three lines rather than four. */
		grid-template-columns: minmax(0, 15rem) minmax(0, 1fr);
		column-gap: clamp(2.5rem, 5.5vw, 7rem);
	}

	/* Anything added below the list in the editor, a picture say, belongs
	   with the entries rather than under the year. */
	.chronicle__year > :not(.chronicle__marker) {
		grid-column: 2;
	}

	/* Sticky measures against the year's own box, so the marker travels for
	   exactly as long as its entries last and is then pushed out by the next
	   year. A grid item stretches to the row height by default, which would
	   leave it nothing to travel in — hence the explicit start alignment. */
	.chronicle__marker {
		position: sticky;
		top: calc(var(--header-height) + clamp(1rem, 2vw, 2rem));
		align-self: start;
	}
}

/* ------------------------------------------------------------------ Press */

/* One story per event: the picture, what happened, and who wrote about it.
   The publications are the whole point of the page, so they stand in a column
   of their own instead of being buried under the prose. */
.press-story__body {
	display: grid;
	row-gap: clamp(2.25rem, 4vw, 3.5rem);
	padding-inline: var(--gutter);
	padding-block: clamp(2.25rem, 4vw, 3.5rem) clamp(3.5rem, 7vw, 7rem);
}

@media (min-width: 56rem) {
	.press-story__body {
		grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
		column-gap: clamp(3rem, 6vw, 7rem);
		align-items: start;
	}
}

/* A shade below the year numbers on References: this is a headline within a
   page, not the marker that organises one. */
.press-story__title {
	font-size: clamp(1.9rem, 3.2vw, 3rem);
	text-transform: uppercase;
	letter-spacing: 0.01em;
	line-height: 1.08;
}

.press-story__text {
	max-width: 54ch;
	color: var(--light-70);
}

/* Where the artist speaks for himself the page changes voice: the display
   face at full brightness, against the muted body text above it. The core
   block arrives with a border and indent of its own, which the rule replaces. */
.press-story__quote {
	/* More air than the group's block gap: the change of voice needs a pause
	   in front of it, or the rule below reads as an underline on the prose. */
	margin-inline: 0;
	margin-block: clamp(1.75rem, 3vw, 2.75rem) 0;
	padding: 0;
	border: 0;
	max-width: 42ch;
	font-family: var(--wp--preset--font-family--display);
	font-size: clamp(1.2rem, 1.9vw, 1.6rem);
	line-height: 1.35;
	color: var(--wp--preset--color--light);
}

/* The same gold rule that opens the page hero and closes the mastheads, here
   announcing that the sentence below is quoted rather than narrated. */
.press-story__quote::before {
	content: "";
	display: block;
	width: clamp(2.5rem, 4.5vw, 4.5rem);
	height: 1px;
	margin-block-end: clamp(1rem, 1.8vw, 1.5rem);
	background-color: var(--wp--preset--color--gold);
}

/* Names the column without competing with it — the gold in here belongs to the
   mastheads, which are what a reader actually scans for. */
.press-list__label {
	color: var(--light-55);
}

/* The label hugs its own entries, so a second group needs to be pushed clear
   of the one above it. Only Getty has two, for now. */
:is(.press-entry, .press-article) + .press-list__label {
	margin-block-start: clamp(1.75rem, 3vw, 2.75rem);
}

/* Every entry is a block of its own — a plain link or an article that opens —
   so the two can be mixed and reordered freely in the editor. Together they
   read as one ruled list: a rule above each, and one below the last. */
.press-entry,
.press-article {
	border-block-start: 1px solid var(--hairline);
}

:is(.press-entry, .press-article) + :is(.press-entry, .press-article) {
	margin-block-start: 0;
}

:is(.press-entry, .press-article):not(:has(+ .press-entry, + .press-article)) {
	border-block-end: 1px solid var(--hairline);
}

.press-entry {
	padding-block: clamp(0.9rem, 1.6vw, 1.4rem);
}

/* On a press page the masthead carries the authority, not the headline, so it
   is set in the eyebrow voice and sits above the line it belongs to. */
.press-entry strong,
.press-article summary strong {
	display: flex;
	align-items: center;
	gap: clamp(0.65rem, 1.2vw, 1rem);
	margin-block-end: 0.4rem;
	font-weight: 500;
	font-size: var(--wp--preset--font-size--micro);
	letter-spacing: 0.2em;
	text-transform: uppercase;
	color: var(--wp--preset--color--gold);
}

.press-entry a {
	color: var(--light-70);
	transition: color 0.4s var(--ease);
}

/* The masthead above is already gold, so the link brightens instead of
   colouring — otherwise the two would run into one another. */
.press-entry a:hover {
	color: var(--wp--preset--color--light);
}

/* The rule closes the masthead and grows on hover, the same gesture as the
   arrow link on the front page. Being a flex sibling rather than trailing
   text, it sits beside the whole masthead instead of joining the last line —
   so a name that wraps on a phone cannot leave it stranded on its own. */
.press-entry strong::after,
.press-article summary strong::after {
	content: "";
	flex: 1;
	max-width: clamp(1.75rem, 3vw, 3rem);
	height: 1px;
	background-color: var(--wp--preset--color--gold);
	transition: max-width 0.5s var(--ease);
}

/* Only the headline is clickable, so the row reacts to the link and not to
   itself — hovering the dead space beside it would promise a target. */
.press-entry:has(a:hover) strong::after,
.press-article summary:hover strong::after {
	max-width: clamp(2.5rem, 4.5vw, 4.5rem);
}

/* A press entry that opens to the article itself. Closed, it reads as one
   more row of the list; the plus on the right is the only sign that it holds
   more. */
.press-article summary {
	position: relative;
	padding-block: clamp(0.9rem, 1.6vw, 1.4rem);
	padding-inline-end: 2.5rem;
	list-style: none;
	color: var(--light-70);
	cursor: pointer;
	transition: color 0.4s var(--ease);
}

.press-article summary::-webkit-details-marker {
	display: none;
}

.press-article summary:hover {
	color: var(--wp--preset--color--light);
}

.press-article summary::after {
	content: "+";
	position: absolute;
	inset-inline-end: 0.25rem;
	top: 50%;
	font-size: 1.5rem;
	font-weight: 300;
	line-height: 1;
	color: var(--wp--preset--color--gold);
	transform: translateY(-50%);
	transition: transform 0.4s var(--ease);
}

.press-article[open] summary::after {
	transform: translateY(-50%) rotate(45deg);
}

.press-article > :not(summary) {
	max-width: 60ch;
	color: var(--light-70);
}

.press-article > :not(summary) + * {
	margin-block-start: 1em;
}

.press-article > :last-child {
	padding-block-end: clamp(1.5rem, 2.6vw, 2.25rem);
}

.press-article__title {
	margin-block: 0.5rem 1.25rem;
	font-size: clamp(1.3rem, 2vw, 1.7rem);
	line-height: 1.2;
	text-transform: uppercase;
	letter-spacing: 0.01em;
	color: var(--wp--preset--color--light);
}

.press-article__source {
	font-size: var(--wp--preset--font-size--micro);
	letter-spacing: 0.08em;
	color: var(--light-55);
}

.press-article__source a {
	color: inherit;
	text-decoration: underline;
	text-underline-offset: 0.2em;
}

.press-article__source a:hover {
	color: var(--wp--preset--color--gold);
}

/* ----------------------------------------------------------- Video facade */

/* A film shows a poster until it is asked for. Works on an image block that
   links to YouTube and on a video block with a file of its own. Poster, play
   button and, once started, the player share one grid cell; the caption takes
   the row below. */
.video-facade {
	display: grid;
	max-width: 54ch;
	margin-block-start: clamp(1.75rem, 3vw, 2.75rem);
}

.video-facade > :not(figcaption) {
	grid-area: 1 / 1;
}

.video-facade > a {
	display: block;
}

.video-facade img,
.video-facade video,
.video-facade iframe {
	display: block;
	width: 100%;
	height: auto;
	aspect-ratio: 16 / 9;
	object-fit: cover;
	border: 0;
	transition: filter 0.6s var(--ease);
}

.video-facade:not(.is-playing) :is(img, video) {
	filter: brightness(0.7);
}

.video-facade:not(.is-playing):hover :is(img, video) {
	filter: brightness(0.85);
}

/* The filter on the poster lifts it into a layer of its own, which would
   otherwise paint over the overlay and catch its clicks. */
.video-facade__overlay {
	position: relative;
	z-index: 1;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: clamp(0.75rem, 1.4vw, 1.1rem);
	padding: 1rem;
	cursor: pointer;
}

.video-facade__play {
	padding: 0;
	border: 0;
	background: none;
	color: var(--wp--preset--color--light);
	cursor: pointer;
}

.video-facade__notice {
	max-width: 34ch;
	margin: 0;
	font-size: var(--wp--preset--font-size--micro);
	line-height: 1.5;
	text-align: center;
	text-shadow: 0 1px 6px rgba(0, 0, 0, 0.8);
	color: var(--wp--preset--color--light);
}

.video-facade__notice a {
	color: inherit;
	text-decoration: underline;
	text-underline-offset: 0.2em;
}

.video-facade__notice a:hover {
	color: var(--wp--preset--color--gold);
}

/* The same hairline ring as the arrows of the featured band, with a veil
   behind it so it holds up on a bright frame. */
.video-facade__ring {
	display: grid;
	place-items: center;
	width: clamp(4rem, 6vw, 5.5rem);
	aspect-ratio: 1;
	border: 1px solid var(--light-70);
	border-radius: 50%;
	background-color: rgba(10, 10, 10, 0.35);
	backdrop-filter: blur(4px);
	transition:
		border-color 0.4s var(--ease),
		color 0.4s var(--ease),
		transform 0.6s var(--ease);
}

.video-facade__ring svg {
	width: 34%;
	fill: currentColor;
}

.video-facade__overlay:hover .video-facade__ring,
.video-facade__play:focus-visible .video-facade__ring {
	border-color: var(--wp--preset--color--gold);
	color: var(--wp--preset--color--gold);
	transform: scale(1.06);
}

.video-facade figcaption {
	margin-block: clamp(0.9rem, 1.6vw, 1.25rem) 0;
	font-size: var(--wp--preset--font-size--micro);
	letter-spacing: 0.16em;
	text-align: start;
	text-transform: uppercase;
	color: var(--light-55);
}

/* ----------------------------------------------------------- Legal pages */

/* Imprint and privacy are read, not looked at: one column at a comfortable
   measure, starting where every other page starts, and headings that do
   nothing but mark where a section begins. */
.legal {
	padding-inline: var(--gutter);
	padding-block: clamp(2.5rem, 5vw, 5rem) clamp(5rem, 10vw, 10rem);
	color: var(--light-70);
}

.legal > * {
	max-width: 68ch;
}

.legal h2 {
	margin-block-start: clamp(2.75rem, 5vw, 4.5rem);
	font-size: clamp(1.3rem, 2.2vw, 1.75rem);
	letter-spacing: 0.02em;
	text-transform: uppercase;
	color: var(--wp--preset--color--light);
}

.legal h3 {
	margin-block-start: clamp(1.75rem, 3vw, 2.75rem);
	font-size: var(--wp--preset--font-size--lead);
	color: var(--wp--preset--color--light);
}

/* A heading brings its own distance from what came before, which the first
   one would otherwise put between itself and the page opening. */
.legal > :first-child {
	margin-block-start: 0;
}

/* A section heading that opens a section rather than interrupting one: the
   full distance would read as though the two were unrelated. */
.legal h2 + h3 {
	margin-block-start: clamp(1.1rem, 2vw, 1.6rem);
}

.legal ul {
	padding-inline-start: 0;
	list-style: none;
}

.legal ol {
	padding-inline-start: clamp(1.6rem, 2.4vw, 2.25rem);
}

.legal ol li::marker {
	color: var(--wp--preset--color--gold);
}

.legal li + li {
	margin-block-start: 0.6rem;
}

.legal ul li {
	position: relative;
	padding-inline-start: clamp(1.6rem, 2.4vw, 2.25rem);
}

/* The same gold dash that carries the References entries. */
.legal ul li::before {
	content: "";
	position: absolute;
	inset-inline-start: 0;
	top: 0.78em;
	width: clamp(0.7rem, 1.3vw, 1.15rem);
	height: 1px;
	background-color: var(--wp--preset--color--gold);
}

/* Dense prose swallows a link that is only marked by colour, so these carry a
   gold underline instead. */
.legal a {
	color: var(--wp--preset--color--light);
	text-decoration: underline;
	text-decoration-color: var(--wp--preset--color--gold);
	text-underline-offset: 0.2em;
}

/* ---------------------------------------------------------------- Footer */

.site-footer {
	padding-inline: var(--gutter);
	padding-block: clamp(4.5rem, 8vw, 10rem) clamp(2rem, 3vw, 3.5rem);
	container-type: inline-size;
}

.site-footer > * + * {
	margin-block-start: clamp(1.5rem, 3vw, 3rem);
}

.footer__title {
	margin: 0;
	font-size: min(var(--wp--preset--font-size--x-large), 11.2cqi);
	line-height: 1.05;
	letter-spacing: 0.02em;
	text-transform: uppercase;
}

.footer__heart {
	margin-block-start: clamp(0.6rem, 1.2vw, 1.1rem);
}

/* Large enough for the HSW monogram inside the crest to stay legible. */
.footer__heart img {
	display: block;
	width: calc(var(--wp--preset--font-size--small) * 10.6);
	height: auto;
}

.footer__meta {
	margin-block-start: clamp(4.5rem, 8vw, 7.5rem);
	gap: clamp(2rem, 4vw, 6rem);
}

/* The three blocks need 546px side by side. Below that the flex wrap would
   strand the contact block on its own line, so they stack as a set. */
@media (max-width: 40rem) {
	.footer__meta {
		flex-direction: column;
	}
}

.footer__block > * + * {
	margin-block-start: 0.7rem;
}

.footer__block p:not(.eyebrow) {
	color: var(--light-70);
}

.footer__legal {
	margin-block-start: clamp(2.5rem, 5vw, 5rem);
	gap: clamp(1rem, 2vw, 2.5rem);
	color: var(--light-55);
	letter-spacing: 0.08em;
	text-transform: uppercase;
}

.footer__legal p {
	margin: 0;
}

/* A shade brighter than the copyright beside them, or nothing would suggest
   these two are meant to be clicked. */
.footer__links {
	display: flex;
	flex-wrap: wrap;
	gap: clamp(1.25rem, 2.5vw, 2.5rem);
}

.footer__links a {
	color: var(--light-70);
}

/* ------------------------------------------------------ Shared utilities */

.eyebrow {
	margin: 0;
	font-weight: 500;
	letter-spacing: 0.2em;
	text-transform: uppercase;
	color: var(--light-70);
}

.eyebrow.has-gold-color {
	color: var(--wp--preset--color--gold);
	letter-spacing: 0.24em;
}

.editorial .eyebrow {
	color: var(--wp--preset--color--muted);
}

.wp-block-separator.rule-gold {
	border: 0;
	border-top: 1px solid var(--wp--preset--color--gold);
	opacity: 0.55;
}

.wp-block-separator.rule-gold:not(.is-style-wide):not(.is-style-dots) {
	width: clamp(3rem, 6vw, 6rem);
	max-width: none;
	margin-inline: 0;
}

.arrow-link {
	font-weight: 500;
	letter-spacing: 0.2em;
	text-transform: uppercase;
}

.arrow-link a {
	display: inline-flex;
	align-items: center;
	gap: clamp(1rem, 2vw, 1.75rem);
}

.arrow-link a::after {
	content: "";
	width: clamp(2.5rem, 5vw, 4.5rem);
	height: 1px;
	background-color: var(--wp--preset--color--gold);
	transition: width 0.5s var(--ease);
}

.arrow-link a:hover::after {
	width: clamp(3.5rem, 7vw, 6.5rem);
}

/* ---------------------------------------------------------------- Motion */

.hero .hero__content > *:not(.hero__media) {
	animation: rise 1.1s var(--ease) both;
}

.hero .hero__label {
	animation-delay: 0.15s;
}

.hero .hero__title {
	animation-delay: 0.28s;
}

.hero .hero__rule {
	animation-delay: 0.44s;
}

.hero .hero__credo {
	animation-delay: 0.54s;
}

/* Every slide zooms while it is on screen. The animation exists only for as
   long as the class does, which is what makes it restart on each turn. It runs
   slightly longer than a slide is shown, so the scale is back to almost 1 by
   the time the class goes away and the reset stays invisible. */
.hero__slides.is-running .wp-block-image.is-active img {
	animation: settle 7.2s var(--ease) both;
}

/* The script starts that animation at its first frame. Parking the first slide
   on the same scale beforehand means the handover produces no jump. */
@media (prefers-reduced-motion: no-preference) {
	.hero__slides:not(.is-running) .wp-block-image:first-child img {
		transform: scale(1.07);
	}
}

/* Page changes cross-fade, and the card a work was opened from grows into its
   hero (site.js names the card). The scrim belongs to the slides, so naming
   the whole stack keeps the picture from brightening once the morph lands. */
@media (prefers-reduced-motion: no-preference) {
	@view-transition {
		navigation: auto;
	}
}

.hero--work .hero__slides {
	view-transition-name: work-image;
}

::view-transition-group(work-image) {
	animation-duration: 0.7s;
	animation-timing-function: var(--ease);
}

::view-transition-old(work-image),
::view-transition-new(work-image) {
	height: 100%;
	object-fit: cover;
}

/* The plate is a narrow window onto a taller picture: while it crosses the
   viewport the picture pans from its lower to its upper edge. */
@media (prefers-reduced-motion: no-preference) {
	.plate img {
		animation: pan linear both;
		animation-timeline: view();
	}
}

@keyframes pan {
	from {
		object-position: 50% 100%;
	}
	to {
		object-position: 50% 0%;
	}
}

@keyframes rise {
	from {
		opacity: 0;
		transform: translateY(1.75rem);
	}
}

@keyframes settle {
	from {
		transform: scale(1.07);
	}
}

.has-js .reveal {
	opacity: 0;
	transform: translateY(1.75rem);
	transition:
		opacity 0.9s var(--ease),
		transform 0.9s var(--ease);
}

.has-js .reveal.is-revealed {
	opacity: 1;
	transform: none;
}

@media (prefers-reduced-motion: reduce) {
	*,
	*::before,
	*::after {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
	}

	.has-js .reveal {
		opacity: 1;
		transform: none;
	}
}
