/**
 * Sabine — stylesheet.
 *
 * THE ONE RULE THAT SHAPES EVERYTHING HERE
 *
 * The background of this site is a live acoustic field on a fixed WebGL2
 * canvas behind the whole document. So no section is allowed to paint over it.
 *
 * Every section is `background: transparent`. Where running text needs a
 * legible floor it gets a GLASS PANEL — a scrim of the page's own ink at 70-80%
 * with a backdrop blur — so the field is still visible through and around it,
 * dimmed rather than replaced. If you find yourself writing
 * `background: var(--ink)` on a section, that is the bug this theme was built
 * to stop: it turns a living background back into a flat fill with a canvas
 * hidden behind it.
 *
 * THE LAYOUT ARCHETYPE: the octave-band grid.
 *
 * An acoustician's every drawing, table and chart is organised by octave band —
 * 125, 250, 500, 1k, 2k, 4k Hz. The page grid is those bands: an eight-column
 * measure with the band frequencies set as a persistent tick rail, and blocks
 * that span named bands rather than arbitrary column counts.
 */

/* ------------------------------------------------------------------ tokens */

:root {
	/**
	 * --ink must match the shader's uInk exactly. Where the field is quiet it
	 * paints this colour, and any difference shows up as a visible seam between
	 * the canvas and anything drawn over it.
	 */
	--ink:        #080B0F;
	--ink-2:      #0D1218;
	--ink-3:      #131A22;

	--text:       #E8EDF2;
	--muted:      #93A3B3;
	/**
	 * --faint carries the tick labels, chart axes, table headers and colophon —
	 * all of it SMALL text, so it needs the 4.5:1 threshold rather than the 3:1
	 * one. #64748B measured 4.14:1 on the ink and only 3.22:1 through a glass
	 * panel over a bright wavefront, which fails in exactly the places this
	 * colour is used. #8494AC measures 6.40:1 and 4.97:1.
	 */
	--faint:      #8494AC;

	--line:       #1E2A36;
	--line-2:     #2C3B4A;

	/* The two signal colours, taken from the field so page and background agree.
	   Warm is compression, cool is rarefaction — the convention every acoustic
	   plot uses. */
	--warm:       #FF9E47;
	--cool:       #4DB8F0;
	--cool-ink:   #7FC6F2;   /* the one safe for small text on --ink */

	--glass:      color-mix( in srgb, var( --ink ) 78%, transparent );
	--glass-soft: color-mix( in srgb, var( --ink ) 58%, transparent );
	--glass-hard: color-mix( in srgb, var( --ink ) 90%, transparent );

	/* Type: one base, one ratio (1.25), seven steps. Nothing outside this set. */
	--t-0: 0.76rem;
	--t-1: 1rem;
	--t-2: 1.25rem;
	--t-3: 1.56rem;
	--t-4: 1.95rem;
	--t-5: 2.44rem;
	--t-6: 3.05rem;
	--t-7: 3.81rem;

	--display: 'Newsreader', Georgia, 'Times New Roman', serif;
	--ui: 'Space Grotesk', system-ui, -apple-system, 'Segoe UI', sans-serif;

	/* Space: multiples of 4. */
	--s-1: 8px;
	--s-2: 16px;
	--s-3: 24px;
	--s-4: 32px;
	--s-5: 48px;
	--s-6: 64px;
	--s-7: 96px;
	--s-8: 128px;

	--shell: 1400px;
	--gutter: clamp( 20px, 5vw, 56px );
	--section-y: clamp( 72px, 10vw, 148px );

	--ease: cubic-bezier( 0.22, 0.61, 0.36, 1 );
	--ease-out: cubic-bezier( 0.16, 1, 0.3, 1 );
}

/* ------------------------------------------------------------------- reset */

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media ( prefers-reduced-motion: reduce ) { html { scroll-behavior: auto; } }

body {
	margin: 0;
	background: var( --ink );
	color: var( --text );
	font-family: var( --ui );
	font-size: var( --t-1 );
	line-height: 1.6;
	font-synthesis-weight: none;
	-webkit-font-smoothing: antialiased;
	/* Entrances arrive from translateX, which widens the document for the
	   duration of the animation. Contained here rather than by shortening the
	   animation, because the motion is worth more than the scrollbar. */
	overflow-x: hidden;
}

img, svg, video, canvas { display: block; max-width: 100%; }
img { height: auto; }
a { color: inherit; text-underline-offset: 0.2em; text-decoration-thickness: from-font; }
button, input, select, textarea { font: inherit; color: inherit; }

:where( a, button, input, select, textarea, summary, [tabindex] ):focus-visible {
	outline: 2px solid var( --cool );
	outline-offset: 3px;
	border-radius: 2px;
}

.screen-reader-text {
	position: absolute !important;
	width: 1px; height: 1px;
	overflow: hidden; clip-path: inset( 50% );
	white-space: nowrap;
}

.skip-link {
	position: absolute;
	left: var( --s-2 ); top: -100px;
	z-index: 999;
	background: var( --text );
	color: var( --ink );
	padding: var( --s-1 ) var( --s-3 );
}
.skip-link:focus { top: var( --s-2 ); }

/* --------------------------------------------------------------- the field */

/**
 * The background. One canvas, fixed, behind everything, never rebuilt between
 * sections. `z-index: 0` with the page shell at 1 rather than a negative index
 * so it stays inside the normal stacking context and cannot be knocked behind
 * the body's own background on any engine.
 */
.field {
	position: fixed;
	inset: 0;
	width: 100vw;
	height: 100vh;
	height: 100dvh;
	z-index: 0;
	display: block;
	/* Present before the first frame renders, and the entire visual under
	   reduced motion or without WebGL2. Deliberately not a flat colour. */
	background:
		radial-gradient( 120% 80% at 50% 8%, #16222E 0%, rgba( 8, 11, 15, 0 ) 62% ),
		radial-gradient( 90% 60% at 12% 96%, #10202B 0%, rgba( 8, 11, 15, 0 ) 58% ),
		var( --ink );
}

.site-header, .site-main, .site-footer { position: relative; z-index: 1; }

/**
 * There are two .field elements by design: the <div> the template always
 * prints (the no-JS / no-WebGL ground) and the <canvas> stage.js inserts when
 * the simulation can run. They share z-index 0, and the div comes LATER in the
 * document, so it painted on top of the live canvas — a fully working field,
 * completely invisible.
 *
 * Worth remembering how this got past a check: the probe reported
 * `field-live: true` and a 1224x850 canvas, both true, and the page was still
 * black. Element state is not the same as pixels.
 */
body.field-live div.field { display: none; }

/* -------------------------------------------------------------- typography */

h1, h2, h3, h4 {
	font-family: var( --display );
	font-weight: 300;
	line-height: 1.08;
	letter-spacing: -0.018em;
	text-wrap: balance;
	margin: 0 0 var( --s-3 );
}
h1 { font-size: clamp( var( --t-5 ), 5.6vw, var( --t-7 ) ); }
h2 { font-size: clamp( var( --t-4 ), 4vw, var( --t-6 ) ); }
h3 { font-size: clamp( var( --t-3 ), 2.4vw, var( --t-4 ) ); }
h4 { font-size: var( --t-2 ); letter-spacing: -0.008em; }

p { margin: 0 0 var( --s-3 ); }

.lede {
	font-family: var( --display );
	font-size: clamp( var( --t-2 ), 1.9vw, var( --t-3 ) );
	line-height: 1.45;
	color: #C6D2DD;
	max-width: 38ch;
}

.prose { max-width: 68ch; }
.prose > * + * { margin-top: var( --s-3 ); }
.prose a { color: var( --cool-ink ); }

/* The tracked-out label. Every measurement on this site is titled in one. */
.eyebrow, .meta, .btn, .bands th, .tick {
	font-family: var( --ui );
	font-size: var( --t-0 );
	font-weight: 500;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	line-height: 1.5;
	font-variant-numeric: tabular-nums;
}
.eyebrow { color: var( --cool-ink ); display: block; margin-bottom: var( --s-2 ); }
.meta { color: var( --muted ); }

/* Figures are the content here, so they get their own face and alignment. */
.num {
	font-family: var( --ui );
	font-variant-numeric: tabular-nums;
	font-feature-settings: 'zero' 1;
	letter-spacing: -0.01em;
}

/* ------------------------------------------------------------------ glass */

/**
 * The scrim that makes the field readable behind text.
 *
 * NOT a section background — a panel around a block of content, so the field
 * continues past its edges. The blur is what stops a bright wavefront crossing
 * behind a paragraph and taking the contrast with it.
 */
.glass {
	background: var( --glass );
	backdrop-filter: blur( 16px ) saturate( 1.15 );
	-webkit-backdrop-filter: blur( 16px ) saturate( 1.15 );
	border: 1px solid var( --line );
	border-radius: 2px;
	padding: clamp( 22px, 3vw, 40px );
}
.glass--soft { background: var( --glass-soft ); backdrop-filter: blur( 10px ); }
.glass--hard { background: var( --glass-hard ); }
.glass--plain { border-color: transparent; }

@supports not ( backdrop-filter: blur( 4px ) ) {
	/* Without a blur the scrim has to carry the contrast on its own. */
	.glass, .glass--soft { background: color-mix( in srgb, var( --ink ) 92%, transparent ); }
}

/* -------------------------------------------------------- layout primitives */

.shell {
	max-width: var( --shell );
	margin-inline: auto;
	padding-inline: var( --gutter );
}

.section { padding-block: var( --section-y ); }

/**
 * The octave-band grid. Eight columns because there are eight bands on an
 * acoustician's page, and blocks are placed by band rather than by an
 * arbitrary column count.
 */
.bandgrid {
	display: grid;
	grid-template-columns: repeat( 8, minmax( 0, 1fr ) );
	gap: var( --s-4 ) var( --s-3 );
	align-items: start;
}
.b-1-3 { grid-column: 1 / span 3; }
.b-1-4 { grid-column: 1 / span 4; }
.b-1-5 { grid-column: 1 / span 5; }
.b-1-8 { grid-column: 1 / span 8; }
.b-4-5 { grid-column: 4 / span 5; }
.b-5-4 { grid-column: 5 / span 4; }
.b-6-3 { grid-column: 6 / span 3; }
.b-3-4 { grid-column: 3 / span 4; }

@media ( max-width: 900px ) {
	.bandgrid { grid-template-columns: minmax( 0, 1fr ); }
	.b-1-3, .b-1-4, .b-1-5, .b-1-8, .b-4-5, .b-5-4, .b-6-3, .b-3-4 { grid-column: 1 / -1; }
}

/* The tick rail: the band frequencies, set as a measure the eye can align to. */
.tickrail {
	display: grid;
	grid-template-columns: repeat( 8, minmax( 0, 1fr ) );
	gap: var( --s-3 );
	border-top: 1px solid var( --line );
	padding-top: var( --s-1 );
	margin-bottom: var( --s-5 );
	color: var( --faint );
}
.tickrail span { position: relative; padding-top: var( --s-1 ); }
.tickrail span::before {
	content: '';
	position: absolute;
	top: calc( -1 * var( --s-1 ) - 1px );
	left: 0;
	width: 1px; height: 7px;
	background: var( --line-2 );
}
@media ( max-width: 700px ) { .tickrail { display: none; } }

/* ---------------------------------------------------------------- buttons */

.btn {
	display: inline-flex;
	align-items: center;
	gap: 0.7em;
	padding: 0.9em 1.6em;
	border: 1px solid var( --text );
	background: var( --text );
	color: var( --ink );
	text-decoration: none;
	cursor: pointer;
	transition: background 0.26s var( --ease ), color 0.26s var( --ease ), border-color 0.26s var( --ease );
}
.btn:hover { background: transparent; color: var( --text ); }

.btn--ghost {
	background: color-mix( in srgb, var( --ink ) 55%, transparent );
	backdrop-filter: blur( 8px );
	-webkit-backdrop-filter: blur( 8px );
	color: var( --text );
	border-color: var( --line-2 );
}
.btn--ghost:hover { border-color: var( --text ); background: var( --text ); color: var( --ink ); }

.tlink {
	text-decoration: none;
	background-image: linear-gradient( var( --cool ), var( --cool ) );
	background-size: 0 1px;
	background-position: 0 100%;
	background-repeat: no-repeat;
	transition: background-size 0.4s var( --ease-out );
	padding-bottom: 2px;
	color: var( --cool-ink );
}
.tlink:hover { background-size: 100% 1px; }

/* ----------------------------------------------------------------- header */

.site-header {
	position: sticky;
	top: 0;
	z-index: 40;
	background: color-mix( in srgb, var( --ink ) 72%, transparent );
	backdrop-filter: blur( 14px );
	-webkit-backdrop-filter: blur( 14px );
	border-bottom: 1px solid var( --line );
}

.site-header__inner {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var( --s-4 );
	min-height: 72px;
}

.brand {
	font-family: var( --display );
	font-size: var( --t-3 );
	font-weight: 300;
	letter-spacing: 0.02em;
	text-decoration: none;
	white-space: nowrap;
}
.brand img { max-height: 38px; width: auto; }
.brand sup { font: 500 var( --t-0 ) / 1 var( --ui ); letter-spacing: 0.16em; color: var( --cool-ink ); margin-left: 0.5em; vertical-align: super; }

.nav ul { list-style: none; display: flex; gap: var( --s-4 ); margin: 0; padding: 0; }
.nav a {
	text-decoration: none;
	font-size: 0.92rem;
	letter-spacing: 0.01em;
	padding-block: var( --s-1 );
	position: relative;
	color: #C6D2DD;
}
.nav a:hover { color: var( --text ); }
.nav a::after {
	content: '';
	position: absolute;
	left: 0; right: 0; bottom: 0;
	height: 1px;
	background: var( --cool );
	transform: scaleX( 0 );
	transform-origin: left;
	transition: transform 0.38s var( --ease-out );
}
.nav a:hover::after, .nav .current-menu-item > a::after { transform: scaleX( 1 ); }

.nav ul ul {
	position: absolute;
	display: none;
	flex-direction: column;
	gap: 0;
	background: var( --ink-2 );
	border: 1px solid var( --line );
	padding: var( --s-2 ) 0;
	min-width: 230px;
	z-index: 5;
}
.nav li { position: relative; }
.nav li:hover > ul, .nav li:focus-within > ul { display: flex; }
.nav ul ul a { display: block; padding: var( --s-1 ) var( --s-3 ); }

.nav-toggle {
	display: none;
	background: none;
	border: 1px solid var( --line-2 );
	color: var( --text );
	padding: 0.65em 1em;
	cursor: pointer;
	font-size: var( --t-0 );
	letter-spacing: 0.16em;
	text-transform: uppercase;
}

@media ( max-width: 980px ) {
	.nav-toggle { display: inline-block; }
	/**
	 * ABSOLUTE, not fixed. The header carries a backdrop-filter, and a
	 * filtered ancestor becomes the containing block for fixed descendants —
	 * a mobile menu declared `fixed` in here collapses to a sliver. That bug
	 * has shipped on this catalogue before.
	 */
	.nav {
		position: absolute;
		left: 0; right: 0; top: 100%;
		background: var( --ink-2 );
		border-bottom: 1px solid var( --line );
		max-height: 0;
		overflow: hidden;
		transition: max-height 0.34s var( --ease );
	}
	.nav.is-open { max-height: 72vh; overflow-y: auto; }
	.nav ul { flex-direction: column; gap: 0; padding: var( --s-2 ) var( --gutter ); }
	.nav a { display: block; padding: 0.7em 0; border-bottom: 1px solid var( --line ); }
	.nav ul ul { position: static; display: flex; border: 0; padding: 0 0 0 var( --s-3 ); background: none; }
}

/* ------------------------------------------------------------------- hero */

.hero { padding-block: clamp( 64px, 12vh, 160px ) var( --section-y ); }
.hero__title em { font-style: italic; color: var( --cool-ink ); }
.hero__actions { display: flex; gap: var( --s-2 ); flex-wrap: wrap; margin-top: var( --s-5 ); }

/* Taxonomy filter row. Its own class rather than a borrowed hero one, so
   restyling the hero cannot silently restyle the archive filters. */
.filters { display: flex; gap: var( --s-2 ); flex-wrap: wrap; margin-bottom: var( --s-5 ); }
.filters a {
	display: inline-flex; align-items: center;
	padding: 0.5em 0.95em;
	border: 1px solid var( --line-2 );
	text-decoration: none;
	font-size: var( --t-0 ); letter-spacing: 0.14em; text-transform: uppercase;
	color: #C6D2DD;
	transition: border-color 0.25s var( --ease ), color 0.25s var( --ease );
}
.filters a:hover { border-color: var( --text ); color: var( --text ); }
.filters a[aria-current="page"] { background: var( --text ); color: var( --ink ); border-color: var( --text ); }

/* The room the field is currently solving, named. Changes as you scroll. */
.roomtag {
	display: inline-flex;
	align-items: baseline;
	gap: 0.7em;
	margin-top: var( --s-5 );
	padding: 0.55em 0.95em;
	border: 1px solid var( --line-2 );
	background: var( --glass-hard );
	backdrop-filter: blur( 8px );
	-webkit-backdrop-filter: blur( 8px );
}
.roomtag b { font: 500 var( --t-0 ) / 1.5 var( --ui ); letter-spacing: 0.16em; text-transform: uppercase; color: var( --cool-ink ); }
.roomtag span { color: var( --muted ); font-size: 0.86rem; }

/* --------------------------------------------------------------- the bands */

.bands {
	width: 100%;
	border-collapse: collapse;
	font-family: var( --ui );
	font-variant-numeric: tabular-nums;
	font-size: 0.92rem;
}
.bands caption { text-align: left; color: var( --muted ); font-size: var( --t-0 ); letter-spacing: 0.16em; text-transform: uppercase; padding-bottom: var( --s-2 ); }
.bands th, .bands td { padding: 0.6em 0.5em; border-bottom: 1px solid var( --line ); text-align: right; }
.bands thead th { color: var( --faint ); font-weight: 500; border-bottom-color: var( --line-2 ); }
.bands tbody th { text-align: left; font-weight: 400; color: var( --muted ); text-transform: none; letter-spacing: 0; font-size: 0.92rem; white-space: nowrap; }
.bands td { color: var( --text ); }
.bands tr:last-child th, .bands tr:last-child td { border-bottom: 0; }
.bands td[data-over="1"] { color: var( --warm ); }

/**
 * The reverberation curve.
 *
 * Class names follow the markup `sab_rt_curve()` actually emits — an earlier
 * draft of this stylesheet invented `.rtplot`, which meant the theme's single
 * most important data graphic rendered completely unstyled. Check the tag, not
 * the intention.
 */
.rt-curve { margin: 0 0 var( --s-4 ); }
.rt-curve__svg { width: 100%; height: auto; display: block; overflow: visible; }
.rt-curve__grid { stroke: var( --line ); stroke-width: 1; }
.rt-curve__axis { stroke: var( --line-2 ); stroke-width: 1; }
/* The design target is a band, not a number: a hall at the bottom of the range
   is not a failed hall, it is a drier one. */
.rt-curve__target { fill: var( --cool ); opacity: 0.14; }
.rt-curve__line { stroke: var( --cool ); stroke-width: 2; stroke-linejoin: round; }
.rt-curve__dot { fill: var( --cool ); }
/* A measured curve is drawn dashed against the computed one, so the two are
   never mistaken for each other. */
.rt-curve--measured .rt-curve__line { stroke: var( --warm ); stroke-dasharray: 5 4; }
.rt-curve--measured .rt-curve__dot { fill: var( --warm ); }
.rt-curve__xtick, .rt-curve__ytick, .rt-curve__unit {
	fill: var( --faint );
	font: 500 10px var( --ui );
	letter-spacing: 0.08em;
	font-variant-numeric: tabular-nums;
}
.rt-curve__unit { fill: var( --muted ); text-transform: uppercase; letter-spacing: 0.16em; }
.rt-curve__caption { margin-top: var( --s-2 ); font-size: 0.86rem; color: var( --muted ); }

/* --------------------------------------------------------------- the bench */

.bench { display: grid; grid-template-columns: minmax( 0, 5fr ) minmax( 0, 7fr ); gap: var( --s-5 ); }
@media ( max-width: 980px ) { .bench { grid-template-columns: minmax( 0, 1fr ); } }

.bench__controls { display: grid; gap: var( --s-3 ); }
.bench__row { display: grid; grid-template-columns: 12ch 1fr 7ch; gap: var( --s-2 ); align-items: center; }
.bench__row label { font-size: var( --t-0 ); letter-spacing: 0.14em; text-transform: uppercase; color: var( --muted ); }
.bench__row input[type="range"] { width: 100%; accent-color: var( --cool ); }
.bench__row output { text-align: right; font-variant-numeric: tabular-nums; color: var( --text ); }
@media ( max-width: 560px ) {
	.bench__row { grid-template-columns: 1fr 6ch; }
	.bench__row label { grid-column: 1 / -1; }
}

.bench__surfaces { display: grid; gap: var( --s-1 ); margin-top: var( --s-2 ); }
.surface {
	display: grid;
	grid-template-columns: 1fr 8ch 5ch;
	gap: var( --s-2 );
	align-items: center;
	padding: 0.45em 0;
	border-bottom: 1px solid var( --line );
	font-size: 0.9rem;
}
.surface select { background: var( --ink-2 ); border: 1px solid var( --line ); color: var( --text ); padding: 0.35em 0.5em; width: 100%; }
.surface input[type="number"] { background: transparent; border: 0; border-bottom: 1px solid var( --line ); color: var( --text ); width: 100%; text-align: right; font-variant-numeric: tabular-nums; padding: 0.3em 0; }
.surface button { background: none; border: 0; color: var( --faint ); cursor: pointer; }
.surface button:hover { color: var( --warm ); }

.verdict { margin-top: var( --s-3 ); font-size: 0.95rem; color: var( --muted ); }
.verdict b { color: var( --text ); font-weight: 500; }
.verdict[data-state="over"] b { color: var( --warm ); }
.verdict[data-state="ok"] b { color: var( --cool-ink ); }

/* ------------------------------------------------------------------ cards */

.cards { display: grid; grid-template-columns: repeat( auto-fill, minmax( 300px, 1fr ) ); gap: var( --s-5 ) var( --s-4 ); }
.card { display: grid; gap: var( --s-2 ); text-decoration: none; }
.card__media { aspect-ratio: 16 / 9; overflow: hidden; background: var( --ink-2 ); border: 1px solid var( --line ); }
.card__media img { width: 100%; height: 100%; object-fit: cover; transition: transform 1s var( --ease-out ), opacity 0.5s var( --ease ); opacity: 0.86; }
.card:hover .card__media img { transform: scale( 1.04 ); opacity: 1; }
.card h3 { font-size: var( --t-2 ); margin: 0; }
.card h3 a { text-decoration: none; }
.card p { color: var( --muted ); margin: 0; font-size: 0.94rem; }
.card__meta { display: flex; gap: var( --s-2 ); flex-wrap: wrap; color: var( --faint ); font-size: var( --t-0 ); letter-spacing: 0.12em; text-transform: uppercase; }

/* ------------------------------------------------------------------ figure */

.figure { margin: 0; }
.figure img { width: 100%; border: 1px solid var( --line ); }
.figure figcaption { margin-top: var( --s-2 ); font-size: 0.86rem; color: var( --muted ); border-left: 1px solid var( --cool ); padding-left: var( --s-2 ); }

.steps { list-style: none; margin: 0; padding: 0; counter-reset: step; display: grid; gap: var( --s-4 ); }
.steps li { counter-increment: step; display: grid; grid-template-columns: 3.4rem minmax( 0, 1fr ); gap: var( --s-3 ); padding-bottom: var( --s-4 ); border-bottom: 1px solid var( --line ); }
.steps li::before { content: counter( step, decimal-leading-zero ); font-family: var( --ui ); font-variant-numeric: tabular-nums; font-size: var( --t-2 ); color: var( --cool-ink ); line-height: 1.2; }
.steps h3 { font-size: var( --t-2 ); margin-bottom: var( --s-1 ); }
.steps p { margin: 0; color: var( --muted ); }

.quote { margin: 0; font-family: var( --display ); font-weight: 300; font-size: clamp( var( --t-3 ), 2.6vw, var( --t-5 ) ); line-height: 1.28; max-width: 24ch; }
.quote cite { display: block; font: 500 var( --t-0 ) / 1.5 var( --ui ); letter-spacing: 0.16em; text-transform: uppercase; color: var( --muted ); margin-top: var( --s-3 ); font-style: normal; }

/* ------------------------------------------------------------------ forms */

.form { display: grid; gap: var( --s-3 ); }
.form__row { display: grid; gap: var( --s-3 ); grid-template-columns: repeat( 2, minmax( 0, 1fr ) ); }
@media ( max-width: 620px ) { .form__row { grid-template-columns: minmax( 0, 1fr ); } }

.field-row { display: grid; gap: var( --s-1 ); }
.field-row label { font-size: var( --t-0 ); letter-spacing: 0.16em; text-transform: uppercase; color: var( --muted ); }
.field-row input, .field-row textarea, .field-row select {
	background: transparent;
	border: 0;
	border-bottom: 1px solid var( --line-2 );
	padding: 0.65em 0;
	color: var( --text );
	transition: border-color 0.3s var( --ease );
}
.field-row input:focus, .field-row textarea:focus, .field-row select:focus { border-bottom-color: var( --cool ); outline: none; }
.field-row input::placeholder, .field-row textarea::placeholder { color: var( --faint ); }
.field-row select option { background: var( --ink-2 ); }

/* Hidden from people, present for bots. Clipped rather than parked off-canvas:
   left:-9999px still contributes to scroll width on some engines. */
.hp { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset( 50% ); opacity: 0; pointer-events: none; }

.form__status { min-height: 1.6em; font-size: 0.92rem; }
.form__status[data-state="ok"] { color: var( --cool-ink ); }
.form__status[data-state="err"] { color: #F0866E; }

/* --------------------------------------------------------- inner templates */

.page-head { padding-block: clamp( 56px, 9vw, 128px ) var( --s-6 ); border-bottom: 1px solid var( --line ); }
.page-head h1 { margin-bottom: var( --s-2 ); }

.crumbs { font-size: var( --t-0 ); letter-spacing: 0.14em; text-transform: uppercase; color: var( --muted ); margin-bottom: var( --s-3 ); }
.crumbs a { text-decoration: none; }
.crumbs a:hover { color: var( --cool-ink ); }
.crumbs__list { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; align-items: baseline; }
.crumbs__item + .crumbs__item::before { content: '/'; margin: 0 0.6em; color: var( --line-2 ); }
.crumbs__item--current { color: #C6D2DD; }

.entry { padding-block: var( --section-y ); }
.entry__content > * + * { margin-top: var( --s-3 ); }
.entry__content h2 { margin-top: var( --s-6 ); }
.entry__content blockquote { margin: var( --s-5 ) 0; padding-left: var( --s-4 ); border-left: 1px solid var( --cool ); font-family: var( --display ); font-size: var( --t-3 ); line-height: 1.35; }
.entry__content img { margin-block: var( --s-4 ); border: 1px solid var( --line ); }
.entry__content ul, .entry__content ol { padding-left: 1.3em; }
.entry__content li + li { margin-top: var( --s-1 ); }
.entry__content code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.9em; background: var( --ink-3 ); padding: 0.15em 0.4em; }

.entry__footer {
	margin-top: var( --s-6 );
	padding-top: var( --s-3 );
	border-top: 1px solid var( --line );
	display: flex; flex-wrap: wrap; gap: var( --s-2 ) var( --s-4 );
	font-size: var( --t-0 ); letter-spacing: 0.14em; text-transform: uppercase; color: var( --muted );
}
.entry__meta, .entry__meta-item, .entry__date, .entry__author, .entry__cats, .entry__tags, .entry__terms, .entry__edit { display: inline-flex; gap: 0.5em; flex-wrap: wrap; }
.entry__edit a { color: var( --cool-ink ); }
.entry__footer a { color: var( --text ); text-decoration: none; border-bottom: 1px solid var( --line-2 ); }
.entry__footer a:hover { border-bottom-color: var( --cool ); }

.pagination, .pager, .navigation {
	margin-top: var( --s-7 );
	border-top: 1px solid var( --line );
	padding-top: var( --s-4 );
}
.pagination .nav-links, .pager .nav-links, .navigation .nav-links,
.pagination__list { display: flex; gap: var( --s-2 ); flex-wrap: wrap; align-items: center; }
.pagination__list { list-style: none; margin: 0; padding: 0; }
.pagination__item { display: inline-flex; }
.pagination__item a, .pagination__item span {
	padding: 0.5em 0.9em; border: 1px solid var( --line-2 ); text-decoration: none; font-size: 0.9rem;
	font-variant-numeric: tabular-nums;
	transition: border-color 0.25s var( --ease ), background 0.25s var( --ease ), color 0.25s var( --ease );
}
.pagination__item a:hover { border-color: var( --text ); }
.pagination__item .current { background: var( --text ); color: var( --ink ); border-color: var( --text ); }
.pagination a, .pagination .current, .pager a, .pager .current,
.navigation .nav-links a, .navigation .nav-links .current {
	padding: 0.5em 0.9em; border: 1px solid var( --line-2 ); text-decoration: none; font-size: 0.9rem;
	transition: border-color 0.25s var( --ease ), background 0.25s var( --ease ), color 0.25s var( --ease );
}
.pagination a:hover, .pager a:hover, .navigation .nav-links a:hover { border-color: var( --text ); }
.pagination .current, .pager .current, .navigation .nav-links .current { background: var( --text ); color: var( --ink ); border-color: var( --text ); }
.pagination .dots, .pager .dots, .navigation .dots { border: 0; color: var( --faint ); }

.comments { padding-block: var( --section-y ); border-top: 1px solid var( --line ); }
.comment-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var( --s-4 ); }
.comment-list ul.children { list-style: none; padding-left: var( --s-4 ); margin-top: var( --s-4 ); display: grid; gap: var( --s-4 ); }
.comment-body { border-bottom: 1px solid var( --line ); padding-bottom: var( --s-3 ); }

/* ----------------------------------------------------------------- footer */

.site-footer {
	border-top: 1px solid var( --line );
	background: color-mix( in srgb, var( --ink ) 82%, transparent );
	backdrop-filter: blur( 14px );
	-webkit-backdrop-filter: blur( 14px );
	padding-block: var( --s-7 ) var( --s-5 );
	color: var( --muted );
}
.site-footer a { color: #C6D2DD; text-decoration: none; }
.site-footer a:hover { color: var( --cool-ink ); }
.footer__grid { display: grid; grid-template-columns: 1.5fr repeat( 3, 1fr ); gap: var( --s-5 ) var( --s-4 ); }
@media ( max-width: 900px ) { .footer__grid { grid-template-columns: repeat( 2, minmax( 0, 1fr ) ); } }
@media ( max-width: 520px ) { .footer__grid { grid-template-columns: minmax( 0, 1fr ); } }
.footer__grid h2, .widget__title {
	font: 500 var( --t-0 ) / 1.5 var( --ui );
	letter-spacing: 0.16em; text-transform: uppercase; color: var( --faint );
	margin: 0 0 var( --s-2 );
}
.site-footer ul { list-style: none; margin: 0; padding: 0; display: grid; gap: var( --s-1 ); }
.site-footer .brand { color: var( --text ); font-size: var( --t-4 ); }
.colophon {
	margin-top: var( --s-6 ); padding-top: var( --s-3 );
	border-top: 1px solid var( --line );
	display: flex; justify-content: space-between; gap: var( --s-3 ); flex-wrap: wrap;
	font-size: 0.84rem; color: var( --faint );
}

/* ------------------------------------------------------------------ motion */

/**
 * Entrances are CSS scroll-driven animations, declared only inside @supports.
 *
 * The resting state of every element is therefore fully visible in browsers
 * without the feature, with JavaScript blocked, under reduced motion, and to
 * crawlers. Nothing is hidden unless the thing that un-hides it is known to
 * exist — an earlier theme in this catalogue hid article bodies behind an
 * observer whose threshold a tall element could never satisfy, and the text
 * simply never appeared.
 *
 * Direction is authored per element: left-hand columns arrive from the left,
 * right-hand ones from the right, wide blocks rise. One uniform fade-up on
 * everything is the fingerprint of a template.
 */
@supports ( animation-timeline: view() ) {
	@media ( prefers-reduced-motion: no-preference ) {
		@keyframes sab-rise  { from { opacity: 0; transform: translate3d( 0, 24px, 0 ); } to { opacity: 1; transform: none; } }
		@keyframes sab-left  { from { opacity: 0; transform: translate3d( -30px, 0, 0 ); } to { opacity: 1; transform: none; } }
		@keyframes sab-right { from { opacity: 0; transform: translate3d(  30px, 0, 0 ); } to { opacity: 1; transform: none; } }
		@keyframes sab-grow  { from { transform: scaleX( 0 ); } to { transform: scaleX( 1 ); } }

		[data-in] { animation: sab-rise linear both; animation-timeline: view(); animation-range: entry 8% cover 32%; }
		[data-in="left"]  { animation-name: sab-left; }
		[data-in="right"] { animation-name: sab-right; }

		[data-stagger] > * { animation: sab-rise linear both; animation-timeline: view(); }
		[data-stagger] > *:nth-child( 3n+1 ) { animation-range: entry 6% cover 28%; }
		[data-stagger] > *:nth-child( 3n+2 ) { animation-range: entry 10% cover 32%; }
		[data-stagger] > *:nth-child( 3n+3 ) { animation-range: entry 14% cover 36%; }

		.rule-draw {
			border-top: 1px solid var( --line-2 );
			transform-origin: left;
			animation: sab-grow linear both;
			animation-timeline: view();
			animation-range: entry 0% cover 24%;
		}
	}
}

/* ------------------------------------------------------------------- misc */

.alignwide { width: min( 100%, calc( var( --shell ) - 2 * var( --gutter ) ) ); }
.alignfull { width: 100vw; margin-inline: calc( 50% - 50vw ); }
.wp-caption-text, .wp-block-image figcaption { font-size: 0.86rem; color: var( --muted ); }
.gallery { display: grid; grid-template-columns: repeat( auto-fit, minmax( 160px, 1fr ) ); gap: var( --s-2 ); }
