/*
 * enhance.css — the 2026 layer.
 *
 * style.css draws the site. This file makes it move, and adds the pieces that
 * did not exist in 2010: scroll-driven parallax and reveals, cross-document
 * view transitions, container queries, a reading ruler, blur-up images.
 *
 * Two rules hold throughout:
 *   1. Everything here is an enhancement. Remove this file and the site is
 *      still complete, legible and navigable — nothing starts hidden unless
 *      the browser has proved it can bring it back.
 *   2. Motion is driven by the browser's own scroll timeline wherever it is
 *      supported, so no scroll handler runs on the main thread.
 */

/* -------------------------------------------------------------------------
   0. Motion tokens
   ---------------------------------------------------------------------- */

:root {
	--hz-fast: 140ms;
	--hz-mid: 300ms;
	--hz-slow: 620ms;
	--hz-out: cubic-bezier(0.22, 0.61, 0.36, 1);
	--hz-spring: cubic-bezier(0.34, 1.28, 0.64, 1);
	--hz-lift: 0 2px 6px rgb(16 24 32 / 6%), 0 14px 34px rgb(16 24 32 / 10%);
}

html {
	scroll-behavior: smooth;
}

:target,
[id] {
	scroll-margin-top: clamp(1.5rem, 9vh, 5.5rem);
}

/* -------------------------------------------------------------------------
   1. Typography niceties the old stylesheet could not assume
   ---------------------------------------------------------------------- */

:is(h1, h2, h3, .hz-band__title, .hz-card__title, .hz-list__title) {
	text-wrap: balance;
}

.entry-content p,
.hz-list__excerpt,
.hz-card__text,
.hz-band__standfirst {
	text-wrap: pretty;
}

/* -------------------------------------------------------------------------
   2. View transitions between pages
   ---------------------------------------------------------------------- */

@view-transition {
	navigation: auto;
}

@media (prefers-reduced-motion: no-preference) {
	::view-transition-old(root) {
		animation: hz-vt-out 160ms var(--hz-out) both;
	}

	::view-transition-new(root) {
		animation: hz-vt-in 280ms var(--hz-out) both;
	}
}

@keyframes hz-vt-out {
	to { opacity: 0; }
}

@keyframes hz-vt-in {
	from { opacity: 0; transform: translateY(8px); }
	to { opacity: 1; transform: none; }
}

/* The masthead and the section band are the same object from page to page;
   naming them lets the browser move rather than redraw them. */
.hz-header {
	view-transition-name: hz-masthead;
}

.hz-band--top {
	view-transition-name: hz-band;
}

/* -------------------------------------------------------------------------
   3. Artwork: blur-up, focal crop
   ---------------------------------------------------------------------- */

.hz-art {
	display: block;
	position: relative;
	overflow: clip;
	background-image: var(--hz-art-lqip);
	background-size: cover;
	background-position: var(--hz-art-focus, 50% 50%);
}

/* The tiny placeholder is the element's own background; the real image paints
   over it as it decodes. Nothing is hidden waiting for a script. */
.hz-art::before {
	content: "";
	position: absolute;
	inset: -6%;
	background-image: inherit;
	background-size: cover;
	background-position: inherit;
	filter: blur(22px) saturate(1.1);
	transform: scale(1.06);
}

.hz-art img {
	position: relative;
	z-index: 1;
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: var(--hz-art-focus, 50% 50%);
}

.hz-art__credit,
.hz-art .hz-art__credit {
	margin: 0.55rem 0 0;
}

.hz-art__credit,
p.hz-art__credit {
	font-size: var(--wp--preset--font-size--xs);
	color: var(--wp--preset--color--contrast-2);
	line-height: 1.5;
}

.hz-art__credit cite {
	font-style: italic;
}

.hz-art__credit a {
	color: inherit;
	text-decoration-color: color-mix(in srgb, currentColor 40%, transparent);
}

/* -------------------------------------------------------------------------
   4. Section bands + parallax
   ---------------------------------------------------------------------- */

/* The picture, and then the words. Nothing is set over the artwork, so there
   is no scrim, no text shadow and no contrast floor to engineer: the painting
   is shown at the brightness it was painted at.

   The block wrapper carries `alignfull`, which already cancels the root
   padding — the band must not add a bleed of its own on top of it. */
.hz-band {
	position: relative;
	isolation: isolate;
	overflow: clip;
	background-color: var(--wp--preset--color--base-2);
}

/* A section page is a column of text, and a picture over it is a heading, not
   a view — so even the "tall" band stays well short of the screen. */
.hz-band--tall,
.hz-band--band { height: clamp(160px, 28vh, 280px); }
.hz-band--strip { height: clamp(130px, 22vh, 230px); }

/* The media box is taller than the band so there is something to travel. */
.hz-band__media {
	position: absolute;
	inset: -10% 0;
	z-index: 0;
	will-change: transform;
}

.hz-band__art {
	height: 100%;
	background-color: var(--wp--preset--color--base-2);
}

/* The band is full-bleed; its heading comes back onto the text column. */
.hz-band__head {
	width: min(100% - 2 * var(--wp--style--root--padding-left), var(--wp--style--global--content-size, 38rem));
	margin-inline: auto;
	padding-block: var(--wp--preset--spacing--30) 0;
}

.hz-band__title {
	margin: 0;
	font-size: var(--wp--preset--font-size--xxl);
	line-height: 1.06;
	letter-spacing: -0.022em;
}

.hz-band__standfirst {
	margin: 0.6rem 0 0;
	max-width: 44ch;
	color: var(--wp--preset--color--contrast-2);
	font-size: var(--wp--preset--font-size--base);
	font-style: italic;
	line-height: 1.35;
	text-wrap: pretty;
}

.hz-band__head .hz-art__credit {
	margin-top: var(--wp--preset--spacing--30);
	padding-top: 0.55rem;
	border-top: 1px solid var(--wp--preset--color--rule);
}

/* ---- the parallax itself ------------------------------------------------
   `view()` ties the animation to the element's own trip through the viewport.
   The browser runs it off the main thread; nothing listens to scroll.        */

@supports (animation-timeline: view()) {
	@media (prefers-reduced-motion: no-preference) {
		.hz-band__media {
			animation: hz-parallax linear both;
			animation-timeline: view();
			animation-range: cover 0% cover 100%;
		}
	}
}

@keyframes hz-parallax {
	from { transform: translate3d(0, -7%, 0); }
	to { transform: translate3d(0, 7%, 0); }
}

/* Browsers without scroll timelines get the same effect from one shared
   observer in motion.js, which sets --hz-shift on the element. */
html.no-scroll-timeline .hz-band__media {
	transform: translate3d(0, var(--hz-shift, 0%), 0);
}

/* ---- 4a. The band at the top of a page ---------------------------------
   The first thing on the About page, a section, or any page given a
   picture: a good part of the screen tall, the name and the sections set
   over its upper edge (style.css §2a), the credit over its lower one. As
   the page scrolls, the picture drifts down at a little under half the
   speed, so the paper seems to slide up over it — the homepage's effect,
   in a smaller frame. `--hz-band-h` is the height set in the editor.      */

.hz-band--top {
	height: var(--hz-band-h, clamp(300px, 52vh, 640px));
	view-timeline: --hz-top-band block;
}

.hz-band--top .hz-band__media {
	inset: 0;
}

/* Darkens the top, where the name and menu sit, and the foot, where the
   credit does, so white words read on any picture — a pale sky included. The
   top is measured in pixels, not as a share of the band: the name and menu
   are the same height however tall the band is set, and the shade has to
   cover them (a little more on a phone, where the menu wraps to two lines).
   The middle of the picture is left as painted. */
.hz-band--top::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 1;
	pointer-events: none;
	background:
		linear-gradient(
			to bottom,
			rgba(9, 12, 14, 0.66) 0,
			rgba(9, 12, 14, 0.5) 80px,
			rgba(9, 12, 14, 0.26) 160px,
			rgba(9, 12, 14, 0.08) 230px,
			rgba(9, 12, 14, 0) 290px
		),
		linear-gradient(
			to top,
			rgba(9, 12, 14, 0.46) 0,
			rgba(9, 12, 14, 0) 110px
		);
}

@media (max-width: 40rem) {
	.hz-band--top::after {
		background:
			linear-gradient(
				to bottom,
				rgba(9, 12, 14, 0.68) 0,
				rgba(9, 12, 14, 0.52) 110px,
				rgba(9, 12, 14, 0.26) 200px,
				rgba(9, 12, 14, 0) 300px
			),
			linear-gradient(
				to top,
				rgba(9, 12, 14, 0.5) 0,
				rgba(9, 12, 14, 0) 120px
			);
	}
}

.hz-band__foot {
	position: absolute;
	inset: auto 0 0 0;
	z-index: 2;
	padding-bottom: clamp(0.75rem, 2vh, 1.2rem);
}

.hz-band__foot .hz-art__credit {
	width: min(100% - 2 * var(--wp--style--root--padding-left), var(--wp--style--global--content-size, 40rem));
	margin: 0 auto;
	color: rgba(251, 250, 246, 0.74);
	font-style: italic;
}

.hz-band__foot .hz-art__credit cite {
	font-style: normal;
}

@supports (animation-timeline: view()) {
	@media (prefers-reduced-motion: no-preference) {
		.hz-band--top .hz-band__media {
			animation: hz-top-drift linear both;
			animation-timeline: --hz-top-band;
			animation-range: exit 0% exit 100%;
		}
	}
}

@keyframes hz-top-drift {
	from { transform: translate3d(0, 0, 0); }
	to { transform: translate3d(0, 45%, 0); }
}

html.no-scroll-timeline .hz-band--top .hz-band__media {
	transform: translate3d(0, var(--hz-drift, 0px), 0);
}

/* ---- 4b. The menu on a phone (style.css §3a) ----------------------------
   The sheet unrolls from the top edge and the page dims behind it. Only on
   the way in: closing is instant, the way a page turns. A clip, not a fade,
   so a browser that skips the transition shows the menu whole at once. */

@supports selector(:popover-open) {
	@media (max-width: 40rem) and (prefers-reduced-motion: no-preference) {
		.hz-menu--fold .hz-menu__panel:popover-open {
			clip-path: inset(0);
			transition: clip-path var(--hz-mid) var(--hz-out);
		}

		.hz-menu--fold .hz-menu__panel:popover-open::backdrop {
			transition: background-color var(--hz-mid) var(--hz-out);
		}

		@starting-style {
			.hz-menu--fold .hz-menu__panel:popover-open {
				clip-path: inset(0 0 100% 0);
			}

			.hz-menu--fold .hz-menu__panel:popover-open::backdrop {
				background-color: rgba(9, 12, 14, 0);
			}
		}
	}
}

/* -------------------------------------------------------------------------
   5. Reveals
   ---------------------------------------------------------------------- */

/* A reveal must never be able to leave content unreadable.
 *
 * The obvious version of this — fade from `opacity: 0` on a view() timeline —
 * has a trap in it: when a page is shorter than the viewport there is no
 * scroll range, the timeline never advances, and everything below the first
 * screen stays at its `from` state permanently. A section with two entries on
 * a tall monitor would render blank.
 *
 * So nothing here animates opacity. The reveal is a small rise and nothing
 * else; if the timeline never runs, the content simply sits 14px from where
 * it would have settled, which nobody will ever notice.
 */
@supports (animation-timeline: view()) {
	@media (prefers-reduced-motion: no-preference) {
		.hz-card,
		.hz-reveal,
		.hz-feature__lead {
			animation: hz-rise linear both;
			animation-timeline: view();
			animation-range: entry 4% entry 44%;
		}

		/* Rows get a much smaller move — a whole page of them lurching is
		   the thing that makes a site feel like a demo. */
		.hz-list__item,
		.hz-link {
			animation: hz-nudge linear both;
			animation-timeline: view();
			animation-range: entry 2% entry 26%;
		}
	}
}

@keyframes hz-rise {
	from { transform: translateY(14px) scale(0.994); }
	to { transform: none; }
}

@keyframes hz-nudge {
	from { transform: translateY(6px); }
	to { transform: none; }
}

/* Fallback path: motion.js adds .is-in as things arrive. Same rule — the
   transform moves, the opacity does not. */
html.js-reveal .hz-card,
html.js-reveal .hz-reveal,
html.js-reveal .hz-feature__lead,
html.js-reveal .hz-list__item,
html.js-reveal .hz-link {
	transform: translateY(12px);
	transition: transform var(--hz-slow) var(--hz-out);
}

html.js-reveal :is(.hz-card, .hz-reveal, .hz-feature__lead, .hz-list__item, .hz-link).is-in {
	transform: none;
}

/* -------------------------------------------------------------------------
   6. Reading ruler — pure CSS, scroll-timeline driven
   ---------------------------------------------------------------------- */

.hz-progress {
	position: fixed;
	inset: env(safe-area-inset-top, 0px) 0 auto 0;
	height: 2px;
	z-index: 60;
	background: var(--wp--preset--color--accent);
	transform-origin: 0 50%;
	scale: 0 1;
	pointer-events: none;
}

@supports (animation-timeline: scroll()) {
	.hz-progress {
		animation: hz-progress linear both;
		animation-timeline: scroll(root block);
	}
}

@keyframes hz-progress {
	from { scale: 0 1; }
	to { scale: 1 1; }
}

html.no-scroll-timeline .hz-progress {
	scale: var(--hz-read, 0) 1;
	transition: scale 90ms linear;
}

@media (prefers-reduced-motion: reduce) {
	.hz-progress { transition: none; }
}

/* -------------------------------------------------------------------------
   7. Icons
   ---------------------------------------------------------------------- */

.hz-icon {
	display: inline-block;
	vertical-align: -0.16em;
	flex: none;
	color: inherit;
}

.hz-icon--inline {
	vertical-align: -0.12em;
	margin-inline-end: 0.35em;
}

/* -------------------------------------------------------------------------
   8. Links that draw themselves
   ---------------------------------------------------------------------- */

@media (prefers-reduced-motion: no-preference) {
	.entry-content a:where(:not(.wp-element-button)),
	.hz-list__excerpt a,
	.hz-band__standfirst a {
		text-decoration-color: color-mix(in srgb, currentColor 32%, transparent);
		text-underline-offset: 0.18em;
		transition: text-decoration-color var(--hz-mid) var(--hz-out), color var(--hz-fast) linear;
	}

	.entry-content a:where(:not(.wp-element-button)):hover {
		text-decoration-color: currentColor;
	}
}

/* -------------------------------------------------------------------------
   9. Cards
   ---------------------------------------------------------------------- */

.hz-card {
	position: relative;
	container-type: inline-size;
	transition: background-color var(--hz-mid) var(--hz-out);
}

/* A section icon is the only thing on a card that says which section it is
   before you read the word, so it stays — drawn on the baseline in the text
   colour, not floated in a tinted circle. */
.hz-card__icon {
	display: block;
	margin-bottom: 0.55rem;
	color: var(--wp--preset--color--contrast-2);
}

.hz-card__more {
	display: inline-flex;
	align-items: center;
	gap: 0.4em;
}

.hz-card__more .hz-icon {
	display: none; /* the words already say where the link goes */
}

/* Only a genuinely tiny card drops its blurb. The threshold is measured
   against the card's content box, which is its track width minus 3rem of
   padding — set it at 15rem and a perfectly ordinary four-column grid
   silently loses every description. */
@container (max-width: 10rem) {
	.hz-card__text { display: none; }
}

/* -------------------------------------------------------------------------
   9b. The feature: one piece given the room a front page owes its best thing
   ---------------------------------------------------------------------- */

.hz-feature {
	display: grid;
	gap: clamp(1.75rem, 4vw, 3rem);
	align-items: start;
}

@media (min-width: 900px) {
	.hz-feature {
		grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
	}
}

/* Not a card: the lead gets its emphasis from size and from the rule above
   it, the way a standfirst does in print. */
.hz-feature__lead {
	position: relative;
	display: grid;
	gap: 0.6rem;
	padding-block: 1.2rem 1.6rem;
	border-top: 2px solid var(--wp--preset--color--contrast);
}

.hz-feature__kicker {
	display: inline-flex;
	align-items: center;
	gap: 0.4em;
	margin: 0;
	font-size: var(--wp--preset--font-size--sm);
	font-style: italic;
	color: var(--wp--preset--color--contrast-2);
}

.hz-feature__title {
	margin: 0;
	font-size: var(--wp--preset--font-size--xl);
	font-weight: 500;
	line-height: 1.12;
}

.hz-feature__title a {
	color: var(--wp--preset--color--contrast);
	text-decoration: none;
}

.hz-feature__title a::after {
	content: "";
	position: absolute;
	inset: 0;
	border-radius: inherit;
}

.hz-feature__lead:hover .hz-feature__title a {
	text-decoration: underline;
	text-underline-offset: 0.14em;
}

.hz-feature__text {
	margin: 0;
	color: var(--wp--preset--color--contrast-2);
	max-width: 46ch;
}

.hz-feature__more {
	display: none; /* the whole lead is the link; a "read it" label repeats it */
}

.hz-feature__rest .hz-list__item:first-child {
	border-top: 0;
	padding-top: 0;
}

.hz-feature__rest .hz-list__title {
	font-size: var(--wp--preset--font-size--base);
}

/* -------------------------------------------------------------------------
   10. Rows
   ---------------------------------------------------------------------- */

.hz-list__item {
	position: relative;
	transition: background-color var(--hz-mid) var(--hz-out);
}

.hz-list__title a::after {
	content: "";
	position: absolute;
	inset: 0;
}

/* Not a flex row: a title that wraps to two lines would otherwise push its
   outward arrow to the far right of the column, a long way from the words it
   belongs to. */
.hz-list__title {
	display: block;
}

/* The outward arrow marks a row whose link leaves the site. It is permanent
   information, so it is permanently visible rather than sliding in on hover. */
.hz-list__title .hz-icon {
	color: var(--wp--preset--color--contrast-2);
	margin-left: 0.3em;
	vertical-align: 0.02em;
}

/* Hovering a row underlines its title. That is the whole of it: a flooded
   background on every row turns a page of writing into a page of buttons. */
@media (hover: hover) {
	.hz-list__item:hover .hz-list__title a {
		text-decoration: underline;
		text-underline-offset: 0.16em;
		text-decoration-thickness: 1px;
	}
}

/* Any meta item carrying an icon needs the icon set off from its word. */
.hz-list__meta > span,
.hz-list__meta > a {
	display: inline-flex;
	align-items: baseline;
	gap: 0.32em;
}

.hz-list__meta .hz-icon {
	align-self: center;
}

.hz-pin {
	color: var(--wp--preset--color--accent-2);
	font-weight: 500;
}

.hz-entry-meta {
	gap: 0.9em;
}

/* -------------------------------------------------------------------------
   11. Topic chips
   ---------------------------------------------------------------------- */

.hz-chips {
	display: flex;
	flex-wrap: wrap;
	column-gap: 1.2rem;
	row-gap: 0.35rem;
	margin: 0;
	padding: 0;
	list-style: none;
}

/* A topic is a link, not a pill. Setting it as one saves seven borders and
   reads as an index entry, which is what it is. */
.hz-chip {
	display: inline-flex;
	align-items: baseline;
	gap: 0.3em;
	font-size: var(--wp--preset--font-size--sm);
	line-height: 1.5;
	color: var(--wp--preset--color--contrast);
	text-decoration: underline;
	text-decoration-color: var(--wp--preset--color--rule);
	text-underline-offset: 0.2em;
	transition: text-decoration-color var(--hz-fast) linear;
}

.hz-chip:hover,
.hz-chip.is-current {
	text-decoration-color: currentColor;
}

.hz-chip__count {
	color: var(--wp--preset--color--contrast-2);
	font-size: var(--wp--preset--font-size--xs);
	font-variant-numeric: tabular-nums;
	text-decoration: none;
}

/* 13. `content-visibility: auto` was here on every row. It bought nothing on
   lists of five to twenty-five items and cost a scroll-anchoring jump and an
   unreliable print, so it is deliberately absent. */

/* -------------------------------------------------------------------------
   14. Everything above, switched off
   ---------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
	html { scroll-behavior: auto; }

	.hz-band__media {
		transform: none !important;
		animation: none !important;
	}

	html.js-reveal :is(.hz-card, .hz-reveal, .hz-feature__lead, .hz-list__item, .hz-link) {
		transform: none;
		transition: none;
	}

	.hz-card:hover { transform: none; }
}

@media print {
	.hz-progress,
	.hz-band__media,
	.hz-art__credit { display: none !important; }

	.hz-band { min-height: 0 !important; }
	.hz-band::after { display: none; }
	.hz-band--top { display: none !important; }
	.hz-band__title, .hz-band__standfirst { color: #000 !important; text-shadow: none !important; }
}
