/**
 * Plexus.
 *
 * ── The banned list ──────────────────────────────────────────────────────
 *
 * Seven habits made an earlier run of themes read as one theme in different
 * colours. Banned here by name, each with the replacement stated, because
 * banning without replacing just produces a plainer version of the same page:
 *
 *  1. BANNED  uppercase, wide-tracked small mono labels.
 *     INSTEAD Sentence case at normal tracking. Where a marker is needed it is
 *             a project's own client-and-year credit, which is information.
 *
 *  2. BANNED  the display-serif / neutral-sans / mono-label trio.
 *     INSTEAD One variable grotesque across a very wide range. Contrast here is
 *             scale and weight, never typeface.
 *
 *  3. BANNED  hairline rules as the main separator, one centred column.
 *     INSTEAD The network itself is the separator: the ground visibly changes
 *             density between sections because the simulation is drawn to them.
 *
 *  4. BANNED  the row of huge statistics.
 *     INSTEAD No statistics at all. A studio is judged on its work.
 *
 *  5. BANNED  the h2-plus-grey-subtitle section head.
 *     INSTEAD Sections open on a sentence that means something on its own.
 *
 *  6. BANNED  the grid of equal cards.
 *     INSTEAD Work is laid out at the size each piece earns.
 *
 *  7. BANNED  a single accent colour used everywhere.
 *     INSTEAD One accent that appears only where the network is densest — it
 *             marks traffic rather than decorating.
 *
 * ── The ground ───────────────────────────────────────────────────────────
 *
 * The background is a live GPU simulation (assets/js/modules/network.js), not a
 * colour. Everything below assumes that: reading surfaces carry their own
 * legibility, and the fallback for the simulation not running is a flat paper
 * ground declared here. The safe state is the one that applies when no script
 * has run.
 *
 * @package Plexus
 */

/* ───────────────────────────  1. Tokens  ─────────────────────────────── */

:root {
	--paper: #f6f4ef;
	--paper-deep: #ebe7de;
	--ink: #17181a;
	/*
	 * A live ground costs you a tonal step, and this is the bill.
	 *
	 * The background is allowed to darken to #bc9f95 beneath any text on the
	 * page, and against that no light grey clears 4.5:1 — there is simply no
	 * room for a third tone. Rather than quiet the simulation down to make room,
	 * the hierarchy's third level is built from size and weight instead of
	 * colour, and these two tokens are deliberately the same value. Anything
	 * lighter would be a contrast failure dressed up as a design decision.
	 */
	--ink-soft: #33373d;
	--ink-faint: #33373d;
	--accent: #b4401f;
	/*
	 * Accent text, darkened away from the accent itself. The ground paints with
	 * --accent, so a link in that colour is at its worst exactly where the
	 * ground is at its worst. Deriving it means a buyer's own accent choice gets
	 * darkened for text automatically instead of quietly failing.
	 */
	--link: #63291a;
	--link: color-mix(in srgb, var(--accent) 48%, var(--ink));

	--sheet: rgba(246, 244, 239, 0.90);
	--sheet-strong: rgba(246, 244, 239, 0.97);
	--rule: rgba(23, 24, 26, 0.14);

	--sans: 'Plexus Grotesk', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;

	--pad: clamp(1.1rem, 4.5vw, 5rem);
	--measure: 34rem;
	--maxw: 104rem;

	--ease: cubic-bezier(0.22, 0.61, 0.36, 1);
	--out: cubic-bezier(0.16, 1, 0.3, 1);
}

/* ─────────────────────────  2. Base + type  ──────────────────────────── */

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
	margin: 0;
	background: var(--paper);
	color: var(--ink);
	font-family: var(--sans);
	font-size: clamp(1rem, 0.95rem + 0.22vw, 1.1rem);
	font-weight: 380;
	line-height: 1.6;
	overflow-x: hidden;
	-webkit-font-smoothing: antialiased;
}

.has-network body { background: transparent; }

img, svg, canvas, video { max-width: 100%; display: block; }
img { height: auto; }
a { color: inherit; }

h1, h2, h3, h4 {
	font-weight: 500;
	line-height: 1.02;
	letter-spacing: -0.025em;
	margin: 0;
	text-wrap: balance;
}

p { margin: 0 0 1em; }
p:last-child { margin-bottom: 0; }

::selection { background: var(--accent); color: var(--paper); }

:where(a, button, [tabindex]):focus-visible {
	outline: 2px solid var(--accent);
	outline-offset: 3px;
}

.sr-only {
	position: absolute !important;
	width: 1px; height: 1px;
	margin: -1px; padding: 0;
	overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%);
	white-space: nowrap;
}
.sr-only:focus {
	position: fixed !important;
	top: 12px; left: 12px;
	width: auto; height: auto;
	clip: auto; clip-path: none;
	padding: 12px 18px;
	background: var(--paper);
	z-index: 200;
}

/* ─────────────────────────  3. The network  ──────────────────────────── */

.net {
	position: fixed;
	inset: 0;
	z-index: 0;
	pointer-events: none;
	contain: strict;
}

.net__canvas {
	width: 100%;
	height: 100%;
	opacity: 0;
	transition: opacity 1.6s var(--ease);
}
.net__canvas.is-ready { opacity: 1; }

/*
 * Legibility wash.
 *
 * The simulation has no idea where the words are, and left to itself it draws
 * at one strength everywhere — which turned the page into a uniform maze that
 * the headline had to fight through. This lays paper back over the reading
 * column and under the masthead, so the network stays full strength in the open
 * right-hand field and merely tints the ground beneath the type.
 *
 * It is a gradient of the paper colour rather than a translucent white, so it
 * holds up whatever the Customizer does to the palette.
 */
.net::after {
	content: '';
	position: absolute;
	inset: 0;
	background:
		linear-gradient( to bottom, var(--paper) 0, rgb( from var(--paper) r g b / 0) 18vh ),
		linear-gradient( 100deg, var(--paper) 4%, rgb( from var(--paper) r g b / 0.72) 34%, rgb( from var(--paper) r g b / 0) 62% );
}

/* Older engines without relative colour syntax get the plain vertical wash
   rather than an unparsed rule and no wash at all. */
@supports not ( background: linear-gradient( to bottom, rgb( from red r g b / 0 ), red ) ) {
	.net::after {
		background: linear-gradient( 100deg, var(--paper) 4%, transparent 58% );
	}
}

/* Content sits above the ground. A fixed painted canvas otherwise draws over
   ordinary static flow content whatever the document order says. */
.site-main,
.masthead,
.site-footer { position: relative; z-index: 1; }
.masthead { z-index: 60; }
.drawer { z-index: 70; }

/* ─────────────────────────  4. Reading surfaces  ─────────────────────── */

/*
 * There is a live simulation behind every pixel, so anything with body text on
 * it rides a sheet. Legibility is a structural rule here, not a per-section
 * decision.
 */
.sheet {
	background: var(--sheet);
	backdrop-filter: blur(4px) saturate(104%);
	-webkit-backdrop-filter: blur(4px) saturate(104%);
	padding: clamp(1.4rem, 3.5vw, 3rem);
}
.sheet--strong { background: var(--sheet-strong); backdrop-filter: none; -webkit-backdrop-filter: none; }

/* ─────────────────────────  5. Masthead  ────────────────────────────── */

.masthead {
	position: fixed;
	inset: 0 0 auto;
	padding: clamp(0.9rem, 1.8vw, 1.4rem) var(--pad);
	transition: transform 0.5s var(--out), background-color 0.4s var(--ease);
}
.masthead.is-settled {
	background: var(--sheet-strong);
	box-shadow: 0 1px 0 var(--rule);
}
.masthead.is-gone { transform: translateY(-104%); }

.masthead__inner {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 2rem;
	max-width: var(--maxw);
	margin-inline: auto;
}

.wordmark { text-decoration: none; display: flex; align-items: baseline; gap: 0.6rem; }
.wordmark__name { font-size: clamp(1.1rem, 1.4vw, 1.35rem); font-weight: 600; letter-spacing: -0.02em; }
.wordmark__what { font-size: 0.82rem; color: var(--ink-faint); }

.nav-list {
	display: flex;
	gap: clamp(1rem, 2.2vw, 2.2rem);
	list-style: none;
	margin: 0; padding: 0;
	font-size: 0.95rem;
}
.nav-list a {
	text-decoration: none;
	padding-block: 0.3rem;
	background-image: linear-gradient(var(--accent), var(--accent));
	background-size: 0 1.5px;
	background-repeat: no-repeat;
	background-position: 0 100%;
	transition: background-size 0.4s var(--out);
}
.nav-list a:hover, .nav-list a:focus-visible { background-size: 100% 1.5px; }
.nav-list .sub-menu { display: none; }

.masthead__end { display: flex; align-items: center; gap: 1rem; }

.drawer-toggle {
	display: none;
	background: none; border: 0; padding: 0.4rem; cursor: pointer; color: inherit;
}
.drawer-toggle i {
	display: block; width: 22px; height: 1.5px;
	background: currentColor; margin: 5px 0;
	transition: transform 0.35s var(--out);
}
.drawer-toggle[aria-expanded='true'] i:first-child { transform: translateY(3.25px) rotate(9deg); }
.drawer-toggle[aria-expanded='true'] i:last-child { transform: translateY(-3.25px) rotate(-9deg); }

.drawer {
	position: fixed; inset: 0;
	background: var(--sheet-strong);
	display: grid; place-items: center;
	opacity: 0; pointer-events: none;
	transition: opacity 0.4s var(--ease);
}
.drawer.is-open { opacity: 1; pointer-events: auto; }
.drawer ul { list-style: none; margin: 0; padding: 0; text-align: center; }
.drawer a {
	text-decoration: none;
	font-size: clamp(1.8rem, 7vw, 3rem);
	font-weight: 500; letter-spacing: -0.03em;
	display: block; padding: 0.35em 0;
}
.drawer .sub-menu { display: none; }

/* ─────────────────────────  6. Buttons  ─────────────────────────────── */

.btn {
	display: inline-block;
	font: inherit; font-size: 0.95rem; font-weight: 500;
	text-decoration: none;
	padding: 0.8em 1.5em;
	border: 1.5px solid currentColor;
	background: transparent; color: inherit; cursor: pointer;
	transition: background-color 0.35s var(--ease), color 0.35s var(--ease);
}
.btn:hover { background: var(--ink); color: var(--paper); border-color: var(--ink); }
.btn--fill { background: var(--ink); color: var(--paper); border-color: var(--ink); }
.btn--fill:hover { background: var(--accent); border-color: var(--accent); }

/* ─────────────────────────  7. Reveals  ─────────────────────────────── */

[data-reveal] {
	opacity: 0;
	transform: translateY(16px);
	transition: opacity 0.9s var(--out), transform 0.9s var(--out);
}
[data-reveal].is-shown { opacity: 1; transform: none; }

[data-reveal-words] .w { display: inline-block; overflow: hidden; vertical-align: bottom; }
[data-reveal-words] .w > i {
	display: inline-block; font-style: inherit;
	transform: translateY(104%);
	transition: transform 0.85s var(--out);
	transition-delay: calc(var(--i) * 42ms);
}
[data-reveal-words].is-shown .w > i { transform: none; }

/* ─────────────────────────  8. Opening  ─────────────────────────────── */

.opening {
	min-height: 100svh;
	display: grid;
	align-items: end;
	padding: 0 var(--pad) clamp(4rem, 12vh, 8rem);
}
.opening__inner { max-width: var(--maxw); margin-inline: auto; width: 100%; }
.opening__line {
	/*
	 * Sized for a sentence, not an aphorism. The scale was originally set
	 * against a six-word line; a headline that actually states what the studio
	 * does runs closer to nine, and at the old 8.5vw it filled the entire
	 * viewport and pushed the supporting copy off the first screen.
	 */
	font-size: clamp(2.3rem, 6.2vw, 6rem);
	font-weight: 500;
	letter-spacing: -0.038em;
	margin-bottom: 0.5em;
	max-width: 21ch;
}
.opening__sub {
	max-width: var(--measure);
	font-size: clamp(1rem, 1.3vw, 1.2rem);
	color: var(--ink-soft);
}

.opening__down {
	display: inline-flex;
	align-items: center;
	gap: 0.9rem;
	margin-top: clamp(2.4rem, 6vh, 4rem);
	text-decoration: none;
	color: var(--ink-faint);
	font-size: 0.95rem;
}
.opening__down svg { transition: transform 0.5s var(--out); }
.opening__down:hover { color: var(--ink); }
.opening__down:hover svg { transform: translateY(5px); }

/* ──────────────────  8b. The page's shared measures  ─────────────────── */

/*
 * One grid for the whole page. Sections differ by where they start and how far
 * they run across it, which is what keeps the composition diagonal without any
 * section needing a layout of its own.
 */
.stance,
.work,
.craft,
.studio,
.dispatch,
.ask {
	max-width: var(--maxw);
	margin-inline: auto;
	padding-inline: var(--pad);
	/*
	 * Half of the section's air, top and bottom, because two of these are
	 * always adjacent: at a full measure each the gap between sections came to
	 * twenty-four rems of nothing, which reads as a missing section rather than
	 * as breathing room.
	 */
	padding-block: clamp(3.5rem, 8vh, 6rem);
}
/* The first section after the hero, and the last before the footer, have no
   neighbour to share the gap with, so they keep the full measure. */
.stance { padding-top: clamp(6rem, 14vh, 10rem); }
.ask { padding-bottom: clamp(6rem, 14vh, 10rem); }

@media ( min-width: 62rem ) {
	.stance,
	.work,
	.craft,
	.studio,
	.dispatch {
		display: grid;
		grid-template-columns: repeat(12, 1fr);
		column-gap: clamp(1rem, 2vw, 2.2rem);
	}
}

/* ─────────────────────────  8c. Stance  ─────────────────────────────── */

.stance__line {
	font-size: clamp(1.7rem, 3.6vw, 3.3rem);
	font-weight: 420;
	line-height: 1.14;
	letter-spacing: -0.028em;
	margin: 0 0 clamp(2rem, 5vh, 3.4rem);
	text-wrap: balance;
}
.stance__note {
	color: var(--ink-soft);
	max-width: var(--measure);
}

@media ( min-width: 62rem ) {
	.stance__line { grid-column: 2 / 11; }
	.stance__note { grid-column: 2 / 7; }
}

/* ─────────────────────────  8d. Work  ───────────────────────────────── */

.work__head {
	font-size: clamp(1.4rem, 2.4vw, 2.1rem);
	font-weight: 430;
	line-height: 1.2;
	max-width: 22ch;
	margin-bottom: clamp(3rem, 8vh, 5rem);
}
.work__field {
	display: grid;
	gap: clamp(3rem, 8vh, 6rem) clamp(1rem, 2vw, 2.2rem);
}

@media ( min-width: 62rem ) {
	.work__head { grid-column: 1 / 7; }
	.work__field {
		grid-column: 1 / -1;
		grid-template-columns: repeat(12, 1fr);
		align-items: start;
	}
	/* Each piece at the size it earns, and never two the same in a row. */
	.piece--lead  { grid-column: 1 / 9; }
	.piece--aside { grid-column: 10 / 13; margin-top: clamp(4rem, 14vh, 10rem); }
	.piece--mid   { grid-column: 3 / 9; }
	.piece--wide  { grid-column: 1 / 13; }
	.piece--mid + .piece--aside { margin-top: 0; }
}

.piece__link {
	display: grid;
	gap: 1.1rem;
	text-decoration: none;
	color: inherit;
}
.piece__frame {
	display: block;
	overflow: hidden;
	background: var(--paper-deep);
	aspect-ratio: 4 / 3;
}
.piece--lead .piece__frame,
.piece--wide .piece__frame { aspect-ratio: 16 / 9; }
.piece--aside .piece__frame { aspect-ratio: 3 / 4; }

.piece__frame img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: transform 1.1s var(--out), filter 0.7s var(--ease);
	/* The photography is held slightly back so the ground stays the loudest
	   thing on the page until the reader chooses otherwise. */
	filter: saturate(0.88);
}
.piece__link:hover .piece__frame img,
.piece__link:focus-visible .piece__frame img {
	transform: scale(1.035);
	filter: saturate(1);
}

.piece__body { display: grid; gap: 0.35rem; }
.piece__name {
	font-size: clamp(1.15rem, 1.7vw, 1.6rem);
	font-weight: 480;
}
.piece--lead .piece__name { font-size: clamp(1.5rem, 2.8vw, 2.5rem); }
.piece__credit { color: var(--ink-faint); font-size: 0.92rem; }
.piece__note {
	color: var(--ink-soft);
	max-width: 40ch;
	margin-top: 0.4rem;
}
.piece--aside .piece__note { display: none; }

.more {
	display: inline-block;
	margin-top: clamp(3rem, 8vh, 5rem);
	color: var(--ink);
	text-decoration: none;
	font-size: clamp(1.1rem, 1.6vw, 1.4rem);
	border-bottom: 1px solid var(--rule);
	padding-bottom: 0.15em;
	transition: border-color 0.4s var(--ease);
}
.more:hover { border-color: var(--accent); }

@media ( min-width: 62rem ) {
	.work .more { grid-column: 1 / 6; }
}

/* ─────────────────────────  8e. Craft  ──────────────────────────────── */

.craft__head {
	font-size: clamp(1.4rem, 2.4vw, 2.1rem);
	font-weight: 430;
	max-width: 20ch;
	margin-bottom: clamp(2.5rem, 6vh, 4rem);
}
.craft__list {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: 0;
}
.craft__item + .craft__item { border-top: 1px solid var(--rule); }

.craft__link {
	display: grid;
	gap: 0.5rem;
	padding-block: clamp(1.5rem, 3.5vh, 2.4rem);
	text-decoration: none;
	color: inherit;
	transition: padding-inline-start 0.5s var(--out);
}
.craft__link:hover,
.craft__link:focus-visible { padding-inline-start: 1.2rem; }

.craft__name {
	font-size: clamp(1.3rem, 2.6vw, 2.3rem);
	font-weight: 440;
}
.craft__note {
	margin: 0;
	color: var(--ink-soft);
	max-width: 52ch;
}

@media ( min-width: 62rem ) {
	.craft__head { grid-column: 1 / 5; }
	.craft__list { grid-column: 5 / 13; }
	.craft__link { grid-template-columns: 1fr 1.1fr; gap: 2rem; align-items: baseline; }
}

/* ─────────────────────────  8f. Studio  ─────────────────────────────── */

.studio__head {
	font-size: clamp(1.4rem, 2.4vw, 2.1rem);
	font-weight: 430;
	max-width: 18ch;
	margin-bottom: 1.2rem;
}
.studio__note { color: var(--ink-soft); max-width: var(--measure); }

.studio__list {
	list-style: none;
	margin: clamp(3rem, 7vh, 4.5rem) 0 0;
	padding: 0;
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
	gap: clamp(1.5rem, 3vw, 2.6rem);
}
.face { display: grid; gap: 0.4rem; }
.face__frame {
	display: block;
	overflow: hidden;
	aspect-ratio: 4 / 5;
	background: var(--paper-deep);
}
.face__frame img { width: 100%; height: 100%; object-fit: cover; filter: grayscale(1) contrast(1.02); }
.face__name { font-weight: 480; }
.face__role { color: var(--ink-faint); font-size: 0.92rem; }

@media ( min-width: 62rem ) {
	.studio__said { grid-column: 1 / 6; }
	.studio__list { grid-column: 1 / 13; }
}

/* ─────────────────────────  8g. Dispatch  ───────────────────────────── */

.dispatch__head {
	font-size: clamp(1.4rem, 2.4vw, 2.1rem);
	font-weight: 430;
	margin-bottom: clamp(2.5rem, 6vh, 4rem);
}
.dispatch__list {
	display: grid;
	gap: clamp(2rem, 5vh, 3rem);
}
.note__link { display: grid; gap: 0.5rem; text-decoration: none; color: inherit; }
.note__name {
	font-size: clamp(1.15rem, 1.8vw, 1.55rem);
	font-weight: 460;
	transition: color 0.35s var(--ease);
}
.note__link:hover .note__name { color: var(--link); }
.note__sub { margin: 0; color: var(--ink-soft); }
.note__when { color: var(--ink-faint); font-size: 0.9rem; }

@media ( min-width: 62rem ) {
	.dispatch__head { grid-column: 1 / 5; }
	.dispatch__list { grid-column: 5 / 13; grid-template-columns: repeat(3, 1fr); gap: clamp(1rem, 2vw, 2.2rem); }
	/* A slight stagger, so three equal items still read as a composition. */
	.dispatch__list .note:nth-child(2) { margin-top: 2.4rem; }
	.dispatch__list .note:nth-child(3) { margin-top: 4.8rem; }
}

/* ─────────────────────────  8h. Ask  ────────────────────────────────── */

.ask { text-align: left; }
.ask__line {
	font-size: clamp(2.2rem, 6.4vw, 6rem);
	font-weight: 500;
	letter-spacing: -0.04em;
	max-width: 16ch;
	margin-bottom: clamp(1.6rem, 4vh, 2.6rem);
}
.ask__to {
	font-size: clamp(1.1rem, 2vw, 1.7rem);
	color: var(--link);
	text-decoration: none;
	border-bottom: 1px solid currentColor;
	padding-bottom: 0.1em;
}
.ask__note {
	margin-top: 1.6rem;
	color: var(--ink-soft);
	max-width: var(--measure);
}

/* ──────────────────  8i. Listings, prose and singles  ────────────────── */

.listing-top,
.single,
.case,
.talk {
	max-width: var(--maxw);
	margin-inline: auto;
	padding-inline: var(--pad);
}

.listing-top {
	padding-block: clamp(7rem, 18vh, 12rem) clamp(2.5rem, 6vh, 4rem);
}
.listing-title {
	font-size: clamp(2.2rem, 6vw, 5.2rem);
	letter-spacing: -0.038em;
	max-width: 18ch;
}
.listing-intro {
	margin-top: clamp(1.2rem, 3vh, 2rem);
	max-width: var(--measure);
	color: var(--ink-soft);
	font-size: clamp(1rem, 1.25vw, 1.15rem);
}
.listing-empty { color: var(--ink-soft); padding-block: 4rem; }

.work--archive,
.craft--archive,
.studio--archive,
.dispatch--archive { padding-block: 0 clamp(6rem, 14vh, 10rem); }

.craft__list--wide,
.studio__list--wide,
.dispatch__list--wide { grid-column: 1 / -1; }

@media ( min-width: 62rem ) {
	.dispatch__list--wide {
		/* Wide enough that a summary gets a readable measure rather than three
		   words a line, which is what 17rem produced at this type size. */
		grid-template-columns: repeat(auto-fill, minmax(21rem, 1fr));
		gap: clamp(2.4rem, 5vh, 3.4rem) clamp(1.4rem, 2.5vw, 2.6rem);
	}
	/* The front page staggers three notes for rhythm; a full archive of them
	   would just look misaligned, so the stagger stops here. */
	.dispatch__list--wide .note:nth-child(n) { margin-top: 0; }
}

.note__frame {
	display: block;
	overflow: hidden;
	aspect-ratio: 4 / 3;
	background: var(--paper-deep);
	margin-bottom: 0.3rem;
}
.note__frame img { width: 100%; height: 100%; object-fit: cover; }

.face__link { display: grid; gap: 0.4rem; text-decoration: none; color: inherit; }

/* The reading surface itself is defined once, in section 4. Long-form pages
   only need to bound its width so the measure does not run away on a wide
   screen. */
.single .sheet,
.case .sheet { max-width: calc(var(--measure) + 8rem); }

.prose { max-width: var(--measure); }
/*
 * Flow spacing, and why it is written this way.
 *
 * The margin reset has to live on `.prose > *`, not on `.prose p`. A type
 * selector adds specificity, so `.prose p` scores (0,1,1) and beats the
 * (0,1,0) of `.prose > * + *` no matter which order they appear in — its
 * `margin: 0` shorthand silently won and every article rendered as one
 * unbroken block. Both selectors below score the same, so the adjacent-sibling
 * rule wins on order, which is what was intended all along.
 */
.prose > * { margin: 0; }
.prose > * + * { margin-top: 1.1em; }
.prose p { font-size: clamp(1rem, 1.15vw, 1.12rem); line-height: 1.68; }
.prose h2 { font-size: clamp(1.35rem, 2.2vw, 1.9rem); margin-top: 2em; font-weight: 460; }
.prose h3 { font-size: clamp(1.12rem, 1.6vw, 1.35rem); margin-top: 1.6em; font-weight: 470; }
.prose a { color: var(--link); text-underline-offset: 0.18em; }
.prose ul, .prose ol { padding-inline-start: 1.3em; }
.prose li + li { margin-top: 0.4em; }
.prose blockquote {
	margin: 2em 0;
	padding-inline-start: 1.2em;
	border-inline-start: 2px solid var(--accent);
	font-size: 1.1em;
	color: var(--ink-soft);
}
.prose img, .prose figure { margin-block: 2em; }
.prose figcaption { color: var(--ink-faint); font-size: 0.9rem; margin-top: 0.5rem; }
.prose code {
	font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
	font-size: 0.9em;
	background: var(--paper-deep);
	padding: 0.1em 0.35em;
}
.prose pre {
	background: var(--paper-deep);
	padding: 1.1rem 1.3rem;
	overflow-x: auto;
}
.prose pre code { background: none; padding: 0; }
.prose table { width: 100%; border-collapse: collapse; }
.prose th, .prose td { text-align: start; padding: 0.6rem 0.8rem; border-bottom: 1px solid var(--rule); }

/* ─────────────────────────  8j. Single  ─────────────────────────────── */

.single__top,
.case__top { padding-block: clamp(7rem, 18vh, 12rem) clamp(2rem, 5vh, 3.4rem); }

.single__title,
.case__title {
	font-size: clamp(2.2rem, 5.6vw, 5rem);
	letter-spacing: -0.038em;
	max-width: 17ch;
}
.single__role,
.single__when,
.case__summary {
	margin-top: 1.2rem;
	color: var(--ink-soft);
	max-width: var(--measure);
}

.single__hero,
.case__hero {
	margin: 0 0 clamp(2.5rem, 7vh, 4.5rem);
	max-width: var(--maxw);
}
.single__hero img,
.case__hero img { width: 100%; }
.single .single__hero { max-width: 42rem; }

.single__near {
	display: flex;
	flex-wrap: wrap;
	justify-content: space-between;
	gap: 1.5rem;
	padding-block: clamp(3rem, 8vh, 5rem) clamp(5rem, 12vh, 8rem);
	border-top: 1px solid var(--rule);
	margin-top: clamp(3rem, 8vh, 5rem);
}
.single__near a { text-decoration: none; color: var(--ink-soft); }
.single__near a:hover { color: var(--ink); }

/* ─────────────────────────  8k. Case study  ─────────────────────────── */

.case__body { padding-bottom: clamp(3rem, 8vh, 5rem); }

@media ( min-width: 62rem ) {
	.case__body {
		display: grid;
		grid-template-columns: minmax(0, 1fr) 15rem;
		gap: clamp(2rem, 5vw, 5rem);
		align-items: start;
	}
	/*
	 * Prose left, facts right — the reverse of the source order, and of the
	 * first attempt.
	 *
	 * The legibility wash sits over the left of the viewport, so putting the
	 * sidebar there spent all the calm on four short labels and left the entire
	 * article sitting in the busiest part of the field. Placing them explicitly
	 * rather than reordering the markup keeps the facts before the argument for
	 * a screen reader, which is the order that makes sense read aloud.
	 */
	.case__body .prose { grid-column: 1; grid-row: 1; }
	.case__facts { grid-column: 2; grid-row: 1; position: sticky; top: 6rem; }
}

.case__facts dl { margin: 0; display: grid; gap: 0.9rem; }
.case__facts dt { color: var(--ink-faint); font-size: 0.88rem; }
.case__facts dd { margin: 0.1rem 0 0; }
.case__tags {
	list-style: none;
	margin: 1.6rem 0 0;
	padding: 0;
	display: flex;
	flex-wrap: wrap;
	gap: 0.4rem 0.9rem;
	font-size: 0.9rem;
}
.case__tags a { color: var(--ink-faint); text-decoration: none; border-bottom: 1px solid var(--rule); }
.case__tags a:hover { color: var(--link); }

.case__outcome {
	padding-block: clamp(3rem, 8vh, 5rem);
}
.case__outcome h2 {
	font-size: clamp(1.3rem, 2.2vw, 1.9rem);
	font-weight: 440;
	margin-bottom: 1.2rem;
}

.case__said {
	margin: 0;
	padding-block: clamp(3rem, 9vh, 6rem);
	max-width: 46rem;
}
.case__said blockquote {
	margin: 0;
	font-size: clamp(1.35rem, 3vw, 2.3rem);
	line-height: 1.24;
	letter-spacing: -0.024em;
	font-weight: 420;
}
.case__said blockquote p { margin: 0; }
.case__said figcaption { margin-top: 1.2rem; color: var(--ink-faint); }

.case__near { padding-block: clamp(3rem, 8vh, 5rem) clamp(6rem, 14vh, 9rem); border-top: 1px solid var(--rule); }
.case__near-head { font-size: clamp(1.2rem, 1.9vw, 1.6rem); font-weight: 440; margin-bottom: 2rem; }
.case__near-list { display: grid; gap: clamp(2rem, 5vh, 3rem); }
@media ( min-width: 48rem ) {
	.case__near-list { grid-template-columns: repeat(3, 1fr); gap: clamp(1rem, 2vw, 2rem); }
	/* Inside this row the pieces are peers, so the front page's sizing is off. */
	.case__near-list .piece--mid { grid-column: auto; }
	.case__near-list .piece__frame { aspect-ratio: 4 / 3; }
}

/* ────────────────  8l. Search, pager and discussion  ─────────────────── */

.searchform { display: flex; gap: 0.6rem; max-width: 26rem; }
.searchform__field {
	flex: 1;
	font: inherit;
	color: inherit;
	padding: 0.7rem 0.9rem;
	background: var(--sheet-strong);
	border: 1px solid var(--rule);
}
.searchform__field:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.searchform__go {
	font: inherit;
	cursor: pointer;
	padding: 0.7rem 1.2rem;
	background: var(--ink);
	color: var(--paper);
	border: 1px solid var(--ink);
}

.pager {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	margin-top: clamp(3rem, 8vh, 5rem);
}
.pager .page-numbers {
	display: inline-grid;
	place-items: center;
	min-width: 2.6rem;
	padding: 0.5rem 0.7rem;
	text-decoration: none;
	border: 1px solid var(--rule);
	color: var(--ink-soft);
}
.pager .page-numbers:hover { color: var(--ink); border-color: var(--ink); }
.pager .page-numbers.current { background: var(--ink); border-color: var(--ink); color: var(--paper); }

.talk { padding-block: clamp(3rem, 8vh, 5rem) clamp(6rem, 14vh, 9rem); }
.talk__head { font-size: clamp(1.2rem, 1.9vw, 1.6rem); font-weight: 440; margin-bottom: 1.6rem; }
.talk__list { list-style: none; margin: 0 0 3rem; padding: 0; display: grid; gap: 1.6rem; }
.talk__list .children { list-style: none; margin: 1.2rem 0 0 1.4rem; padding: 0; display: grid; gap: 1.2rem; }
.talk__list .comment-body { background: var(--sheet); padding: 1.2rem 1.4rem; }
.talk__list .comment-meta { font-size: 0.88rem; color: var(--ink-faint); margin-bottom: 0.5rem; }
.talk__list .comment-meta a { color: inherit; }
.talk__shut { color: var(--ink-faint); }
.talk .comment-form { display: grid; gap: 1rem; max-width: 40rem; }
.talk .comment-form input:not([type="submit"]):not([type="checkbox"]),
.talk .comment-form textarea {
	font: inherit;
	color: inherit;
	width: 100%;
	padding: 0.7rem 0.9rem;
	background: var(--sheet-strong);
	border: 1px solid var(--rule);
}
.talk .comment-form label { display: block; margin-bottom: 0.3rem; color: var(--ink-soft); font-size: 0.92rem; }
.talk .comment-form .submit {
	font: inherit;
	cursor: pointer;
	justify-self: start;
	padding: 0.75rem 1.6rem;
	background: var(--ink);
	color: var(--paper);
	border: 1px solid var(--ink);
}

/* ─────────────────────────  9. Footer  ──────────────────────────────── */

.site-footer {
	margin-top: clamp(4rem, 10vw, 9rem);
	background: var(--sheet-strong);
	padding: clamp(3rem, 7vw, 6rem) var(--pad) clamp(2rem, 4vw, 3rem);
}
.site-footer__inner { max-width: var(--maxw); margin-inline: auto; }
.footer__grid {
	display: grid;
	grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr) minmax(0, 1fr);
	gap: clamp(1.6rem, 4vw, 4rem);
	align-items: start;
}
.footer__line { font-size: clamp(1.3rem, 2.6vw, 2.2rem); letter-spacing: -0.025em; max-width: 20ch; margin-bottom: 1.2rem; }
.footer-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.4rem; }
.footer-list a { text-decoration: none; }
.footer-list a:hover { color: var(--accent); }
.footer__base {
	margin-top: clamp(2.5rem, 6vw, 5rem);
	padding-top: 1.4rem;
	border-top: 1px solid var(--rule);
	display: flex; flex-wrap: wrap; gap: 0.6rem 2rem; justify-content: space-between;
	font-size: 0.85rem; color: var(--ink-faint);
}

/* ─────────────────────────  10. Utilities  ──────────────────────────── */

/*
 * The no-image state.
 *
 * This is what a buyer sees on a fresh install before a single photograph has
 * been uploaded, and on the demo it is a sixteen-by-nine block of it, so a flat
 * grey rectangle is not good enough. It fills its frame rather than imposing
 * 4:3, and carries a faint ruled grain so it reads as prepared paper waiting
 * for an image instead of as a failed load.
 */
.img-absent {
	display: block;
	width: 100%;
	height: 100%;
	min-height: 100%;
	background-color: var(--paper-deep);
	background-image:
		repeating-linear-gradient(
			118deg,
			rgb( from var(--ink) r g b / 0.045 ) 0 1px,
			transparent 1px 9px
		),
		radial-gradient( 130% 90% at 28% 12%, rgb( from var(--paper) r g b / 0.85 ), transparent 62% );
}

/* Without relative colour syntax the grain is dropped rather than guessed at;
   the paper tone underneath is still correct. */
@supports not ( color: rgb( from red r g b / 0.5 ) ) {
	.img-absent {
		background-image: radial-gradient( 130% 90% at 28% 12%, rgba(255,255,255,0.7), transparent 62% );
	}
}

/* The frame already declares the aspect ratio each piece runs at, so the
   placeholder must not fight it with one of its own. */
.piece__frame .img-absent,
.face__frame .img-absent,
.note__frame .img-absent { aspect-ratio: auto; }

.wrap { max-width: var(--maxw); margin-inline: auto; padding-inline: var(--pad); }

/* ─────────────────────────  11. Responsive  ─────────────────────────── */

@media (max-width: 900px) {
	.nav-list { display: none; }
	.drawer-toggle { display: block; }
	.footer__grid { grid-template-columns: minmax(0, 1fr); }
}

/* ─────────────────────────  12. Reduced motion  ─────────────────────── */

@media (prefers-reduced-motion: reduce) {
	.net { display: none; }
	.has-network body { background: var(--paper); }
	[data-reveal] { opacity: 1; transform: none; transition: none; }
	[data-reveal-words] .w > i { transform: none; transition: none; }
	* { animation-duration: 0.001ms !important; transition-duration: 0.001ms !important; }
}

body[data-motion='calm'] .net { display: none; }
body[data-motion='calm'] { background: var(--paper); }
