/*!
 * Kolofon main stylesheet
 * All colours and fonts are driven by :root custom properties
 * injected inline from the Theme Options (see inc/dynamic-css.php).
 */

/* ------- Reset ------- */
*, *::before, *::after { box-sizing: border-box; }
html {
	-webkit-text-size-adjust: 100%;
	overflow-x: hidden;
}
body {
	margin: 0;
	background: var(--k-bg);
	color: var(--k-text);
	font-family: var(--k-font-body);
	font-size: 17px;
	line-height: 1.65;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
	overflow-wrap: break-word;
}
img, svg, video, iframe, embed, object { max-width: 100%; height: auto; display: block; }

/* Long unbroken strings (URLs, code identifiers) must not force a scrollbar. */
h1, h2, h3, h4, h5, h6, p, li, dd, dt, figcaption, blockquote {
	overflow-wrap: break-word;
	hyphens: auto;
}
a { overflow-wrap: break-word; }

/* Wide tables scroll inside their own box rather than stretching the page. */
.content table,
.e-content table {
	display: block;
	width: 100%;
	max-width: 100%;
	overflow-x: auto;
	-webkit-overflow-scrolling: touch;
	border-collapse: collapse;
}
.wp-block-table { overflow-x: auto; }

/* ------- Typography ------- */
h1, h2, h3, h4, h5, h6 {
	font-family: var(--k-font-heading);
	color: var(--k-text);
	line-height: 1.2;
	letter-spacing: -0.01em;
	margin: 2rem 0 0.75rem;
}
h1 { font-size: 2.25rem; }
h2 { font-size: 1.65rem; }
h3 { font-size: 1.25rem; }
p, ul, ol, blockquote, pre, figure { margin: 0 0 1.15rem; }
a {
	color: var(--k-accent);
	text-decoration: none;
	border-bottom: 1px solid transparent;
	transition: border-color 0.15s ease;
}
a:hover, a:focus { border-bottom-color: var(--k-accent); }
blockquote {
	border-left: 3px solid var(--k-rule);
	margin: 1.5rem 0;
	padding: 0.25rem 0 0.25rem 1.15rem;
	color: var(--k-muted);
}
blockquote.is-style-kolofon-accent { border-left-color: var(--k-accent); }
hr, hr.wp-block-separator {
	border: 0;
	border-top: 1px solid var(--k-rule);
	margin: 2rem 0;
}
hr.is-style-kolofon-hairline { border-top-width: 1px; opacity: 0.5; }
code, pre {
	font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
	font-size: 0.92em;
}
pre {
	background: var(--k-rule);
	padding: 1rem 1.15rem;
	overflow-x: auto;
	border-radius: 2px;
}
:not(pre) > code {
	background: var(--k-rule);
	padding: 0.1em 0.35em;
	border-radius: 2px;
}

/* ------- Skip link ------- */
.skip-link.screen-reader-text {
	position: absolute;
	left: -9999px;
	top: auto;
	overflow: hidden;
}
.skip-link.screen-reader-text:focus {
	left: 6px;
	top: 6px;
	background: var(--k-text);
	color: var(--k-bg);
	padding: 0.5rem 0.75rem;
	z-index: 100;
}

/* ------- Layout ------- */
.container {
	max-width: var(--k-container);
	margin: 0 auto;
	padding: 0 1.25rem;
}
.site-content { min-height: 60vh; }

/* ------- Header ------- */
.site-header {
	padding: 1.25rem 0;
	border-bottom: 1px solid var(--k-rule);
}
.site-header .container {
	max-width: none;
	padding: 0 2rem;
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 1.5rem;
	flex-wrap: wrap;
}
.site-title {
	margin: 0;
	font-family: var(--k-font-heading);
	font-size: 1.15rem;
	font-weight: 600;
	letter-spacing: -0.005em;
}
.site-title a {
	color: var(--k-text);
	border-bottom: 0;
}
.site-branding .custom-logo-link {
	display: inline-block;
	line-height: 0;
	border-bottom: 0;
}
.site-branding .custom-logo {
	max-height: 48px;
	width: auto;
}
.site-nav .nav-menu,
.footer-nav .nav-menu {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	gap: 1.25rem;
	flex-wrap: wrap;
}
.site-nav .nav-menu a,
.footer-nav .nav-menu a {
	color: var(--k-muted);
	font-size: 0.95rem;
	font-weight: 600;
	border-bottom: 0;
}
.site-nav .nav-menu a:hover,
.site-nav .nav-menu .current-menu-item a,
.footer-nav .nav-menu a:hover {
	color: var(--k-text);
}

/* ------- Hero ------- */
.hero-eyebrow {
	margin: 0 0 0.9rem;
	font-family: ui-monospace, "SF Mono", "Cascadia Mono", Menlo, Consolas, monospace;
	font-size: 0.78rem;
	font-weight: 500;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--k-accent);
}

/* A marked phrase inside a heading takes the accent colour. mark is the
   semantic element for this, so the browser default background is cleared
   rather than a span being invented to avoid it. */
.hero-heading mark,
.content mark,
.e-content mark {
	background: transparent;
	color: var(--k-accent);
	padding: 0;
}

.hero {
	padding: 4rem 0 3rem;
	border-bottom: 1px solid var(--k-rule);
	/* Gradient wash on the lede, derived entirely from the active scheme's own
	   tokens, so it recolours with Charcoal and Ivory (and any custom scheme)
	   and never introduces a hue the palette did not define. A faint accent
	   tint gathers at the top left and dissolves into the page background, so
	   the hero lifts without boxing itself off or sitting behind the reading
	   column below. color-mix keeps the accent low so it reads as atmosphere,
	   not a coloured panel. Stands down to the flat token background under
	   forced-colors. */
	background:
		radial-gradient(
			120% 80% at 15% 0%,
			color-mix( in srgb, var(--k-accent) 12%, transparent ) 0%,
			transparent 60%
		),
		linear-gradient(
			180deg,
			color-mix( in srgb, var(--k-accent) 5%, var(--k-bg) ) 0%,
			var(--k-bg) 100%
		);
}
@media ( forced-colors: active ) {
	.hero { background: var(--k-bg); }
}
.hero-inner {
	display: grid;
	grid-template-columns: minmax(0, 1fr) var(--k-portrait);
	gap: 4rem;
	align-items: center;
}
.hero-heading {
	font-size: clamp(var(--k-lede-heading-min), 4.5vw, var(--k-lede-heading-max));
	font-weight: 700;
	letter-spacing: -0.02em;
	line-height: 1.08;
	margin: 0 0 1.25rem;
	text-wrap: balance;
}
.hero-body {
	font-size: var(--k-lede-body);
	line-height: 1.7;
	color: var(--k-text);
	max-width: 60ch;
}
.hero-body p:last-child { margin-bottom: 0; }
/* Links inside the lede sit within the sentence rather than jumping out as
   accent-coloured words: text colour, bold, and a persistent soft accent
   underline that firms up on hover. Scheme-derived, so Charcoal underlines in
   gold and Ivory in navy. */
.hero-body a {
	color: var(--k-text);
	font-weight: 700;
	border-bottom: 1px solid color-mix( in srgb, var(--k-accent) 55%, transparent );
}
.hero-body a:hover,
.hero-body a:focus {
	color: var(--k-accent);
	border-bottom-color: var(--k-accent);
}
.hero-social {
	margin-top: 1.75rem;
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.9rem;
	color: var(--k-text);
	font-weight: 600;
}
.hero-social-label { margin-right: 0.25rem; }
.hero-social-icons {
	display: inline-flex;
	flex-wrap: wrap;
	gap: 0.75rem;
	align-items: center;
}
.hero-social-link {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 36px;
	height: 36px;
	border-radius: 50%;
	color: var(--k-muted);
	border: 1px solid var(--k-rule);
	background: transparent;
	transition: color 0.15s ease, border-color 0.15s ease, background 0.15s ease, transform 0.15s ease;
}
.hero-social-link:hover,
.hero-social-link:focus-visible {
	color: var(--k-bg);
	background: var(--k-accent);
	border-color: var(--k-accent);
	transform: translateY(-1px);
	outline: none;
}
.hero-social-link svg { display: block; }
.hero-portrait {
	width: var(--k-portrait);
	justify-self: end;
}
.hero-portrait img {
	width: 100%;
	height: auto;
	display: block;
}

/* Floating: transparent cut-out, no mask, no background. */
.hero-portrait.is-floating img {
	object-fit: contain;
	filter: drop-shadow(0 8px 24px rgba(0, 0, 0, 0.18));
}

/* Masked variants crop to a fixed square and fill the frame. */
.hero-portrait.is-circle,
.hero-portrait.is-rounded,
.hero-portrait.is-square {
	aspect-ratio: 1 / 1;
	overflow: hidden;
	background: var(--k-rule);
}
.hero-portrait.is-circle { border-radius: 50%; }
.hero-portrait.is-rounded { border-radius: 12px; }
.hero-portrait.is-square { border-radius: 0; }
.hero-portrait.is-circle img,
.hero-portrait.is-rounded img,
.hero-portrait.is-square img {
	height: 100%;
	object-fit: cover;
}
.intro-widget { margin-top: 1.5rem; }
.widget-title { font-size: 0.85rem; text-transform: uppercase; letter-spacing: 0.08em; color: var(--k-muted); }

/* ------- Section headings ------- */
.section-heading {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 1rem;
	color: var(--k-accent);
	font-size: 1.75rem;
	font-weight: 700;
	letter-spacing: -0.015em;
	border-bottom: 1px solid var(--k-rule);
	padding-bottom: 0.5rem;
	margin: 2rem 0 1rem;
}

/* ------- Post list ------- */
.post-list {
	list-style: none;
	padding: 0;
	margin: 0;
	position: relative;
}
.post-item { border-bottom: 1px solid var(--k-rule); }
.post-item a {
	display: flex;
	justify-content: space-between;
	align-items: baseline;
	gap: 1rem;
	padding: 0.85rem 0;
	color: var(--k-text);
	border-bottom: 0;
}
.post-item-main {
	display: flex;
	flex-direction: column;
	gap: 0.25rem;
	min-width: 0;
}
.post-item a:hover .post-title { color: var(--k-accent); }
.post-item .post-title { font-family: var(--k-font-heading); font-size: var(--k-list-title, 1.05rem); font-weight: 600; }
.post-item .post-dek { color: var(--k-muted); font-size: 0.95rem; line-height: 1.5; }
.post-item .post-date { color: var(--k-muted); font-size: 0.9rem; white-space: nowrap; }

/* ------- Hover preview -------
   The featured image, revealed as a floating peek beside the list on hover.
   Behaviour: zero reserved gutter by default. When any row in a list with
   previews is hovered, the list expands its right padding to make room, and
   the peek appears at a fixed anchor at the top of the list. Moving between
   rows swaps the preview image but the anchor stays put — the peek does not
   chase the cursor down the list.
   Pointer devices only. */
.post-preview { display: none; }

@media (hover: hover) and (pointer: fine) and (min-width: 1024px) {
	/* The list is the positioning context, owns the gutter, and anchors the
	   peek at its top edge. */
	.post-list.has-previews {
		position: relative;
		padding-right: 0;
		transition: padding-right 0.28s cubic-bezier(0.2, 0, 0.2, 1);
	}
	.post-list.has-previews:hover {
		padding-right: calc(var(--k-preview) + 1.5rem);
	}

	/* Preview is absolutely positioned within the list, not the row.
	   Same top for every row — this is the "fixed anchor" behaviour.
	   All preview rules scoped to `.has-previews` so the mechanic only
	   activates on lists that opt in — the blog page, for instance, opts
	   out because a full chronological archive is scanned, not previewed. */
	.post-list.has-previews .post-preview {
		display: block;
		position: absolute;
		top: 0;
		right: 0;
		width: var(--k-preview);
		aspect-ratio: 3 / 2;
		opacity: 0;
		transform: translateX(-4px);
		pointer-events: none;
		transition: opacity 0.18s ease 0.05s, transform 0.18s ease 0.05s;
		z-index: 10;
	}
	.post-list.has-previews .post-preview img {
		display: block;
		width: 100%;
		height: 100%;
		object-fit: cover;
		object-position: center;
		border-radius: 8px;
		background: var(--k-rule);
		box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
	}

	/* Typographic variant: rendered when the post has no featured image.
	   Same 3:2 anchor, same slot, but the peek is the post title over a
	   subtle palette background. Gives image-less posts a peek of their own
	   rather than showing nothing. */
	.post-list.has-previews .post-preview.is-typographic {
		container-type: inline-size;
		background:
			radial-gradient(
				120% 120% at 25% 15%,
				color-mix( in srgb, var(--k-accent) 14%, transparent ) 0%,
				transparent 65%
			),
			color-mix( in srgb, var(--k-text) 5%, var(--k-bg) );
		border: 1px solid var(--k-rule);
		border-radius: 8px;
		box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
		padding: 0;
		display: block;
		position: absolute;
		overflow: hidden;
	}
	/* The generated mark fills the card behind the title. currentColor is set
	   to the accent here, so the device recolours with the scheme. */
	.post-preview-device {
		position: absolute;
		inset: 0;
		width: 100%;
		height: 100%;
		color: var(--k-accent);
		opacity: 0.55;
	}
	/* Title anchored to the foot of the card, over a scrim so it stays legible
	   whatever the mark does behind it. */
	.post-preview-title {
		position: absolute;
		left: 0;
		right: 0;
		bottom: 0;
		z-index: 1;
		padding: 12cqw 7cqw 6cqw;
		font-family: var(--k-font-heading);
		/* Scales with the card, so the title reads the same at any
		   "Hover preview width" from 100px to 240px rather than looking
		   oversized on a small peek and lost on a large one. Falls back to a
		   sensible fixed size where container units are unsupported. */
		font-size: 0.95rem;
		font-size: clamp( 0.95rem, 8cqw, 1.25rem );
		font-weight: 700;
		line-height: 1.3;
		color: var(--k-text);
		background: linear-gradient(
			180deg,
			transparent 0%,
			color-mix( in srgb, var(--k-bg) 88%, transparent ) 55%,
			color-mix( in srgb, var(--k-bg) 96%, transparent ) 100%
		);
		display: -webkit-box;
		-webkit-line-clamp: 3;
		-webkit-box-orient: vertical;
		overflow: hidden;
		text-overflow: ellipsis;
	}
	@media ( forced-colors: active ) {
		.post-preview-device { display: none; }
	}

	.post-item.has-preview a:hover .post-preview,
	.post-item.has-preview a:focus-visible .post-preview,
	.post-item.has-preview:focus-within .post-preview {
		opacity: 1;
		transform: translateX(0);
	}
}

/* Respect the reader's motion preference: no transitions, but the interaction
   still works — the gutter opens and the preview appears, just instantly. */
@media (hover: hover) and (pointer: fine) and (min-width: 1024px) and (prefers-reduced-motion: reduce) {
	.post-list.has-previews,
	.post-preview {
		transition: none;
	}
}

/* ------- Index list style -------
   Adapted from Book WP's TOC pattern. A hairline-ruled row list where the
   title carries the eye, the year sits right-aligned as a small annotation,
   and the excerpt wraps onto its own line. Hover shifts the whole row
   rightward by a rem so the reader senses the click target before landing
   on it. The row IS the click target; nothing else on the row is clickable. */
.post-item.is-index a {
	align-items: baseline;
	flex-wrap: wrap;
	gap: 0.5rem;
	padding: 1rem 0.4rem;
	transition: color 0.18s, padding-left 0.18s;
}
.post-item.is-index a:hover { padding-left: 1.4rem; }
.post-item.is-index .post-item-main { flex: 1 1 auto; min-width: 0; }
.post-item.is-index .post-title {
	font-family: var(--k-font-heading);
	font-size: calc( var(--k-list-title, 1.05rem) * 1.1 );
	line-height: 1.3;
	overflow-wrap: break-word;
}
.post-item.is-index .post-date {
	font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
	font-size: 0.75rem;
	font-style: italic;
	color: var(--k-muted);
	white-space: nowrap;
	margin-left: auto;
	align-self: baseline;
}
.post-item.is-index .post-dek {
	display: block;
	flex-basis: 100%;
	font-size: 0.9rem;
	font-style: italic;
	color: var(--k-muted);
	margin-top: 0.15rem;
	padding-left: 0.4rem;
	line-height: 1.5;
}

/* ------- Columns list style ------- */
/* Date and section in narrow monospace columns, then the title. The fixed
   widths are what make consecutive rows read as a table without being one. */
.post-item.is-columns a {
	align-items: baseline;
	justify-content: flex-start;
	gap: 1.25rem;
}
.post-col {
	font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
	font-size: 0.78rem;
	letter-spacing: 0.04em;
	white-space: nowrap;
	flex: 0 0 auto;
}
.post-col-date {
	width: 6.5rem;
	color: var(--k-muted);
	text-transform: uppercase;
	white-space: nowrap;
}
.post-col-section {
	width: 7.5rem;
	color: var(--k-accent);
	text-transform: uppercase;
	overflow: hidden;
	text-overflow: ellipsis;
}
.post-item.is-columns .post-item-main { flex: 1 1 auto; }

/* ------- Navigation badge ------- */
.nav-badge {
	display: inline-block;
	margin-left: 0.35rem;
	padding: 0.1rem 0.5rem;
	border: 1px solid var(--k-accent);
	border-radius: 999px;
	font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
	font-size: 0.62rem;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--k-accent);
	vertical-align: middle;
}

/* ------- Planned page notice -------
   The notice replaces the body of a page marked as planned. Editorial voice:
   the page still counts as content, so the notice is set with the same
   generous vertical rhythm as prose, centered, and framed as a soft
   informational block rather than a heavy warning. */
.planned-notice {
	background: color-mix(in srgb, var(--k-text) 3%, var(--k-bg));
	border: 1px solid var(--k-rule);
	border-radius: 10px;
	padding: 2.5rem 2rem;
	margin: 2rem 0;
	text-align: center;
}
.planned-notice .planned-badge-line { margin: 0 0 1.25rem; }
.planned-notice .planned-description {
	font-family: var(--k-font-heading);
	font-size: 1.2rem;
	color: var(--k-text);
	line-height: 1.4;
	margin: 0 auto 1rem;
	max-width: 30em;
}
.planned-notice .planned-note {
	color: var(--k-muted);
	margin: 0 auto;
	font-size: 0.95rem;
	line-height: 1.5;
	max-width: 32em;
}

/* ------- Tags ------- */

/* Section breakdown on a tag archive. */
.tag-sections {
	margin: 0.5rem 0 0;
	font-size: 0.9rem;
	color: var(--k-muted);
}
.tag-sections a { color: var(--k-accent); }

/* Browsable topic index. */
.tag-index {
	list-style: none;
	margin: 1rem 0 0;
	padding: 0;
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
}
.tag-index li { margin: 0; }
.tag-index a {
	display: inline-flex;
	align-items: baseline;
	gap: 0.4rem;
	padding: 0.3rem 0.7rem;
	border: 1px solid var(--k-rule);
	border-radius: 4px;
	font-size: 0.88rem;
	color: var(--k-muted);
}
.tag-index a:hover,
.tag-index a:focus-visible {
	color: var(--k-accent);
	border-color: var(--k-accent);
}
.tag-count {
	font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
	font-size: 0.72rem;
	opacity: 0.7;
}

/* ------- Section chooser ------- */
.section-chooser { margin: 0 0 1.5rem; }
.section-list {
	list-style: none;
	margin: 0;
	padding: 0 0 0.5rem;
	display: flex;
	flex-wrap: wrap;
	gap: 0.4rem 0.5rem;
	border-bottom: 1px solid var(--k-rule);
}
.section-item { margin: 0; }
.section-link {
	display: inline-flex;
	align-items: baseline;
	gap: 0.4rem;
	padding: 0.35rem 0.75rem;
	border: 1px solid var(--k-rule);
	border-radius: 999px;
	font-size: 0.9rem;
	font-weight: 600;
	color: var(--k-muted);
	background: transparent;
	transition: color 0.15s ease, border-color 0.15s ease, background 0.15s ease;
}
.section-link:hover,
.section-link:focus-visible {
	color: var(--k-accent);
	border-color: var(--k-accent);
}
.section-link.is-current {
	color: var(--k-bg);
	background: var(--k-accent);
	border-color: var(--k-accent);
}
.section-count {
	font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
	font-size: 0.75rem;
	opacity: 0.7;
	font-weight: 400;
}

/* ------- Recent section ------- */
.recent { padding: 2.5rem 0 3rem; }

/* ------- Single ------- */
.content-header { margin: 3rem 0 1.75rem; }
/* Archive (category and tag), blog, and Now page h1 titles take the accent
   colour so they match the "Recent Posts" section heading on the home page,
   which also uses var(--k-accent). The term span in an archive title
   ("Category: Foo") inherits it so the whole heading reads as one unit.
   Single posts and single pages are excluded: their title carries `p-name`
   (set in singular.php) and stays the default text colour. */
.content-header .post-title:not(.p-name),
.content-header .post-title:not(.p-name) .term {
	color: var(--k-accent);
}
/* The search query is the visitor's own input, not a site taxonomy, so it
   takes the plain text colour to stand apart from the accent-coloured
   "Search results for:" label. Archive terms keep the accent above. */
.content-header .post-title:not(.p-name) .term-query {
	color: var(--k-text);
}

/* ------- Page-index templates (404, blog listing, other stubs) -------
   These templates use `.page-index` as their root article class and expect
   the same vertical rhythm and centred column as a singular post, without
   inheriting the singular-post schema markup or e-content typography. */
/* `.page-index .content` was previously constrained to `max-width: 42em`
   as a reading-column, but three of its callers (index.php, page-blog.php,
   and 404.php) are post lists or minimal prose that want the full container
   width. Reading-column constraint moved to `.page-index .description`
   where prose actually lives. */
.page-index .content {
	line-height: 1.65;
}
.page-index .content > p { margin: 0 0 1.2rem; max-width: 42em; }
.page-index .content > p:last-child { margin-bottom: 0; }
.page-index .description {
	font-size: 1.05rem;
	color: var(--k-muted);
	max-width: 42em;
	line-height: 1.5;
	margin: 0.5rem 0 0;
}
.page-index .year-heading {
	font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
	font-size: 0.75rem;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--k-muted);
	margin: 2rem 0 0.5rem;
}
.page-index .year-group:first-child .year-heading { margin-top: 0; }

/* ------- 404 page -------
   Structured, not a fallback. Large numeric backdrop in the heading font sets
   the scene; content stack overlays it. All colours from the palette so it
   inherits scheme changes correctly. */
.page-index.is-404 { padding: 3rem 0 4rem; }
.not-found {
	position: relative;
	max-width: 42em;
	margin: 0 auto;
	text-align: center;
	padding: 2rem 0;
}
.not-found-backdrop {
	font-family: var(--k-font-heading);
	font-size: clamp(8rem, 22vw, 14rem);
	font-weight: 700;
	line-height: 0.9;
	letter-spacing: -0.03em;
	color: var(--k-rule);
	user-select: none;
	margin-bottom: -0.4em;
}
.not-found-body {
	position: relative;
}
.not-found-title {
	font-family: var(--k-font-heading);
	font-size: clamp(1.6rem, 3.5vw, 2.2rem);
	font-weight: 700;
	color: var(--k-text);
	margin: 0 0 0.75rem;
	letter-spacing: -0.015em;
}
.not-found-description {
	font-size: 1.05rem;
	color: var(--k-muted);
	line-height: 1.6;
	max-width: 30em;
	margin: 0 auto 2rem;
}
.not-found-actions {
	margin-bottom: 3rem;
}
.not-found-home {
	display: inline-block;
	padding: 0.6rem 1.4rem;
	border: 1px solid var(--k-accent);
	border-radius: 999px;
	color: var(--k-accent);
	font-size: 0.9rem;
	font-weight: 600;
	transition: color 0.15s ease, background 0.15s ease;
	border-bottom-width: 1px;
}
.not-found-home:hover,
.not-found-home:focus-visible {
	color: var(--k-bg);
	background: var(--k-accent);
}
.not-found-search {
	padding-top: 2rem;
	border-top: 1px solid var(--k-rule);
}
.not-found-search-label {
	font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
	font-size: 0.72rem;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--k-muted);
	margin: 0 0 1rem;
}
.not-found .search-form {
	max-width: 24em;
	margin: 0 auto;
}

/* Filter row on the blog index: post count on one line, section pills on
   the next. Adapted from Chris Wiegman's parent theme, category-filter
   pattern from 12.10.0. */
.content-meta {
	margin: 0 0 2.5rem;
	padding: 0.75rem 0;
	border-top: 1px solid var(--k-rule);
	border-bottom: 1px solid var(--k-rule);
}
.content-meta .post-count {
	margin: 0 0 0.75rem;
	font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
	font-size: 0.8rem;
	color: var(--k-muted);
	letter-spacing: 0.06em;
}

/* Native search form: WordPress renders `.search-form` with a label wrapping
   the input, then a submit button. The button inherits system font by
   default, which reads as a foreign element on a page in the site's font. */
.search-form { display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap; margin: 1.25rem 0; max-width: 420px; }
/* Hide the "Search for:" label. Its purpose is fulfilled by the placeholder
   plus the aria-label WordPress applies to the input. Follows the parent
   theme's convention of visually stripping the label rather than restyling
   around it, and stays accessible: screen-reader-text keeps it in the tree. */
.search-form label { position: absolute; left: -9999px; }
.search-form .search-field {
	flex: 1 1 auto;
	padding: 0.5rem 0.75rem;
	border: 1px solid var(--k-rule);
	border-radius: 4px;
	font-family: var(--k-font-body);
	font-size: 1rem;
	background: var(--k-bg);
	color: var(--k-text);
}
.search-form .search-submit {
	padding: 0.5rem 1.2rem;
	border: 0;
	border-radius: 4px;
	background: var(--k-text);
	color: var(--k-bg);
	font: inherit;
	font-size: 0.95rem;
	cursor: pointer;
}
.search-form .search-submit:hover,
.search-form .search-submit:focus-visible {
	background: var(--k-accent);
}

/* Section eyebrow above post titles. Reinforces which section the reader is
   in on a post arrived at from search or a share, where the section chooser
   is nowhere in sight. */
.section-eyebrow { margin-bottom: 1rem; }
.section-eyebrow-name {
	display: inline-block;
	font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
	font-size: 0.7rem;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--k-accent);
	border-bottom: 0;
}
.section-eyebrow-name:hover { color: var(--k-text); }
.section-eyebrow-desc {
	margin-top: 0.35rem;
	font-size: 0.92rem;
	font-style: italic;
	color: var(--k-muted);
	max-width: 42em;
	line-height: 1.5;
}
.post-title { margin: 0.25rem 0; }
.meta { color: var(--k-muted); font-size: 0.9rem; }
.dt-published { text-transform: uppercase; letter-spacing: 0.06em; font-size: 0.85rem; }
/* Tags at the foot of a post. Set off from the body by a hairline and framed by
   a small letterspaced label, then given the same rounded-pill language as the
   section chooser so the two read as one family. Tags stay lighter than
   sections, which are primary navigation: a soft accent tint rather than the
   solid accent fill a current section takes. */
.post-tags {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.5rem;
	margin: 2.5rem 0 0;
	padding-top: 1.25rem;
	border-top: 1px solid var(--k-rule);
}
.post-tags-label {
	font-size: 0.7rem;
	font-weight: 700;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--k-muted);
	margin-right: 0.15rem;
}
.tags { list-style: none; padding: 0; margin: 0; display: flex; flex-wrap: wrap; gap: 0.4rem 0.5rem; }
.tags li { margin: 0; }
.tags li a {
	display: inline-block;
	padding: 0.3rem 0.8rem;
	border: 1px solid color-mix( in srgb, var(--k-accent) 30%, var(--k-rule) );
	border-radius: 999px;
	background: color-mix( in srgb, var(--k-accent) 7%, transparent );
	font-size: 0.82rem;
	letter-spacing: 0.015em;
	color: var(--k-text);
	transition: color 0.15s ease, border-color 0.15s ease, background 0.15s ease;
}
.tags li a:hover,
.tags li a:focus-visible {
	border-color: var(--k-accent);
	background: color-mix( in srgb, var(--k-accent) 18%, transparent );
	color: var(--k-accent);
}
@media ( forced-colors: active ) {
	.tags li a { background: none; }
}
.featured-image { margin: 1.5rem 0; }
.e-content h2 { margin-top: 2.5rem; }

/* Post body copy is justified with no hyphenation. This will produce visible
   rivers of word-spacing on narrow lines, particularly on monospaced stacks
   where the browser can only redistribute at word boundaries. That is the
   honest cost of full justification without CSS hyphenation, and is the
   deliberate choice: a print manuscript wears the same ragged word-spacing
   rather than mangling words at the syllable, and the theme follows suit.
   Scoped to running post text only — headings, figures, blockquotes, and
   list items keep their own alignment. */
.e-content > p,
.e-content > ul li,
.e-content > ol li { text-align: justify; }

/* Exception at phone widths: below 640px, the column is too narrow for
   justification to distribute space without producing broken rivers, and
   the trade tips the wrong way. Fall back to left-aligned. This is the
   only breakpoint-conditional typography rule in the theme, and the
   justification changelog entry (2.8.3) specifically named this as the
   signal to reconsider. */
@media (max-width: 640px) {
	.e-content > p,
	.e-content > ul li,
	.e-content > ol li { text-align: left; }
}

/* ------- Pagination ------- */
.pagination {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 1rem;
	flex-wrap: wrap;
	margin-top: 2rem;
	padding-top: 1rem;
	border-top: 1px solid var(--k-rule);
}
.pagination-count {
	margin: 0;
	font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
	font-size: 0.82rem;
	letter-spacing: 0.04em;
	color: var(--k-muted);
}
.pagination-controls { display: flex; gap: 0.5rem; }
.pagination-link {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 36px;
	height: 36px;
	border: 1px solid var(--k-rule);
	border-radius: 6px;
	color: var(--k-muted);
	border-bottom: 1px solid var(--k-rule);
	transition: color 0.15s ease, border-color 0.15s ease;
}
.pagination-link:hover,
.pagination-link:focus-visible {
	color: var(--k-accent);
	border-color: var(--k-accent);
}
.pagination-link.is-disabled { opacity: 0.35; }

/* ------- Callout pattern ------- */
.menj-callout,
.kolofon-callout {
	border-left: 3px solid var(--k-accent);
	background: color-mix(in srgb, var(--k-accent) 6%, var(--k-bg));
	border-radius: 0 6px 6px 0;
}
.menj-callout > *:last-child,
.kolofon-callout > *:last-child { margin-bottom: 0; }

/* ------- Post navigation ------- */
.post-nav {
	display: flex;
	justify-content: space-between;
	gap: 1rem;
	padding: 2rem 1.25rem 3rem;
	color: var(--k-muted);
	font-size: 0.95rem;
}

/* ------- Blog index page (year groups) ------- */
.year-group { margin-bottom: 2rem; }
.year-heading {
	font-family: var(--k-font-heading);
	font-size: 1rem;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--k-muted);
	margin: 2rem 0 0.5rem;
}

/* ------- Search form ------- */
.search-form input[type="search"] {
	flex: 1;
	padding: 0.5rem 0.75rem;
	background: transparent;
	border: 1px solid var(--k-rule);
	color: var(--k-text);
	font: inherit;
	border-radius: 2px;
}
.search-form input[type="search"]:focus { outline: 2px solid var(--k-accent); outline-offset: 1px; }

/* ------- Footer ------- */
.site-footer {
	margin-top: 4rem;
	padding: 2rem 0 2.5rem;
	background: color-mix(in srgb, var(--k-text) 4%, var(--k-bg));
	border-top: 1px solid var(--k-rule);
	color: var(--k-muted);
	font-size: 0.9rem;
	text-align: center;
}
.site-footer .container {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 0.85rem;
}
.site-footer .footer-nav .nav-menu {
	gap: 2rem;
	justify-content: center;
}
.footer-text { color: var(--k-muted); }
.footer-text a { color: var(--k-muted); border-bottom: 1px solid var(--k-rule); }
.footer-text a:hover { color: var(--k-accent); border-bottom-color: var(--k-accent); }

/* ------- Alignment for block editor ------- */
.alignwide { max-width: calc(var(--k-container) + 200px); margin-left: auto; margin-right: auto; }
.alignfull { max-width: 100%; }
.aligncenter { margin-left: auto; margin-right: auto; text-align: center; }

/* ------- Sidebar layout ------- */
/* The rail-and-card arrangement. Grid on body, card sticky in the rail so it
   stays in view while the content scrolls. Below 1024px the grid dissolves
   and the card becomes an ordinary header block, at which point the existing
   768px navigation collapse takes over. */
@media (min-width: 1025px) {
	body.layout-sidebar {
		display: grid;
		grid-template-columns: 300px minmax(0, 1fr);
		gap: 2.5rem;
		max-width: calc(var(--k-container) + 340px);
		margin: 0 auto;
		padding: 1.5rem;
	}

	body.layout-sidebar .sidebar-card {
		grid-column: 1;
		grid-row: 1 / span 2;
		align-self: start;
		position: sticky;
		top: 1.5rem;
		max-height: calc(100vh - 3rem);
		overflow-y: auto;
	}

	body.layout-sidebar .site-content { grid-column: 2; }
	body.layout-sidebar .site-footer  { grid-column: 2; }

	/* The content column already limits itself; the rail took its share. */
	body.layout-sidebar .container {
		max-width: none;
		padding-left: 0;
		padding-right: 0;
	}
}

.sidebar-card {
	background: color-mix(in srgb, var(--k-text) 3%, var(--k-bg));
	border: 1px solid var(--k-rule);
	border-radius: 16px;
	padding: 1.75rem 1.5rem;
	box-shadow: 0 8px 28px rgba(0, 0, 0, 0.07);
}
.sidebar-card .site-branding { margin-bottom: 1.25rem; }
.sidebar-card .site-title {
	margin: 0;
	font-family: var(--k-font-heading);
	font-size: 1.45rem;
	font-style: italic;
}
.sidebar-card .site-nav .nav-menu {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: 0.15rem;
}
.sidebar-card .site-nav .nav-menu a {
	display: flex;
	align-items: center;
	gap: 0.6rem;
	padding: 0.5rem 0.65rem;
	border-radius: 8px;
	color: var(--k-text);
	font-weight: 600;
	font-size: 0.95rem;
	border-bottom: 0;
}
.sidebar-card .site-nav .nav-menu a:hover,
.sidebar-card .site-nav .nav-menu a:focus-visible {
	background: color-mix(in srgb, var(--k-text) 5%, var(--k-bg));
	color: var(--k-accent);
}
.sidebar-card .site-nav .current-menu-item > a,
.sidebar-card .site-nav .current_page_item > a {
	background: color-mix(in srgb, var(--k-text) 6%, var(--k-bg));
}

/* The boxed digit. aria-hidden, since it duplicates position for sighted
   users and advertises the shortcut. */
.nav-num {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 1.45rem;
	height: 1.45rem;
	border: 1px solid var(--k-rule);
	border-radius: 5px;
	font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
	font-size: 0.72rem;
	font-weight: 400;
	color: var(--k-muted);
	flex: 0 0 auto;
}

/* Stay in touch. */
.sidebar-social { margin-top: 1.5rem; }
.sidebar-social-heading {
	margin: 0 0 0.5rem;
	font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
	font-size: 0.7rem;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--k-muted);
}
.sidebar-social-list {
	list-style: none;
	margin: 0;
	padding: 0;
}
.sidebar-social-list li { border-top: 1px solid var(--k-rule); }
.sidebar-social-link {
	display: flex;
	align-items: center;
	justify-content: space-between;
	padding: 0.55rem 0.15rem;
	color: var(--k-text);
	font-size: 0.92rem;
	border-bottom: 0;
}
.sidebar-social-link:hover,
.sidebar-social-link:focus-visible { color: var(--k-accent); }
.sidebar-social-arrow {
	color: var(--k-muted);
	font-size: 0.8rem;
}

/* ------- Typewriter-accurate rhythm -------
   Real typewriters advanced the platen by 1.5x to 2x the character height per
   line-feed; "double-spaced" was the default for manuscript work. Monospaced
   type also has a taller x-height relative to em than proportional type, so
   tight leading reads crowded. Three stacks use monospace or typewriter faces
   and inherit this rhythm: Typed (special-elite), Office memo (typewriter
   hybrid), and Plaintext (mono). Editorial serif and XCharter keep the
   default 1.65 because they are proportional. */
body.font-special-elite,
body.font-typewriter,
body.font-mono { line-height: 1.9; }

/* The hero body, index-style excerpts, blog year groups, and content column
   all set their own line-height. Scoped overrides so the rhythm carries
   through consistently instead of only applying at the root. */
body.font-special-elite .hero-body,
body.font-typewriter .hero-body,
body.font-mono .hero-body,
body.font-special-elite .content,
body.font-typewriter .content,
body.font-mono .content,
body.font-special-elite .e-content,
body.font-typewriter .e-content,
body.font-mono .e-content,
body.font-special-elite .page-index .content,
body.font-typewriter .page-index .content,
body.font-mono .page-index .content { line-height: 1.9; }

/* Paragraph spacing tightens slightly to keep the rhythm rather than double
   it: at 1.9 line-height, the extra bottom margin from 1.2rem starts to feel
   like a section break rather than a paragraph break. */
body.font-special-elite .content > p,
body.font-typewriter .content > p,
body.font-mono .content > p,
body.font-special-elite .e-content > p,
body.font-typewriter .e-content > p,
body.font-mono .e-content > p { margin-bottom: 1rem; }

/* Post-list dek text (used on the index style) also carries the typewriter
   rhythm so the entire row reads as one document. */
body.font-special-elite .post-item .post-dek,
body.font-typewriter .post-item .post-dek,
body.font-mono .post-item .post-dek { line-height: 1.85; }

/* ==================================================================
   RESPONSIVE

   Three content breakpoints, plus capability queries for pointer type.

     1024px  tablet landscape and small laptops
      768px  tablet portrait, navigation collapses here
      560px  phones

   The hover-preview block above uses (hover: hover) and (pointer: fine)
   rather than a width alone, because the deciding factor there is whether
   a hover state exists at all, not how wide the screen is.
   ================================================================== */

/* ------- Search ------- */
/* Search toggle: a quiet icon in the header that opens the full-screen
   overlay. Matches the navigation toggle's 44px target and token colours.
   Hidden until the script marks the header, so no-JS visitors see nothing
   that cannot act. */
.search-toggle {
	display: none;
	align-items: center;
	justify-content: center;
	width: 44px;
	height: 44px;
	padding: 0;
	margin-left: 0.5rem;
	background: transparent;
	border: 1px solid var(--k-rule);
	border-radius: 6px;
	color: var(--k-text);
	cursor: pointer;
}
.search-toggle:hover { border-color: var(--k-accent); color: var(--k-accent); }
.search-toggle:focus-visible {
	outline: 2px solid var(--k-accent);
	outline-offset: 2px;
}
.site-header.has-search-toggle .search-toggle { display: inline-flex; }

/* Full-screen search overlay. Covers the viewport, tinted from the background
   token so it reads as the same site rather than a foreign layer. Fades and
   lifts slightly on open; the transition is removed under reduced motion.

   Closed state is load-bearing: the overlay is fixed and covers the viewport,
   so at rest it MUST NOT catch clicks. opacity alone does not stop that (an
   opacity:0 element still receives pointer events), and the HTML hidden
   attribute is overridden by the display value below, so neither can be relied
   on. visibility:hidden plus pointer-events:none is what actually removes it
   from hit-testing between openings. */
.search-overlay {
	position: fixed;
	inset: 0;
	z-index: 1000;
	display: flex;
	align-items: flex-start;
	justify-content: center;
	padding: 12vh 1.5rem 1.5rem;
	background: color-mix(in srgb, var(--k-bg) 92%, transparent);
	backdrop-filter: blur(6px);
	opacity: 0;
	visibility: hidden;
	pointer-events: none;
	transition: opacity 0.18s ease, visibility 0s linear 0.18s;
}
.search-overlay.is-open {
	opacity: 1;
	visibility: visible;
	pointer-events: auto;
	transition: opacity 0.18s ease;
}
.search-overlay-inner {
	position: relative;
	width: 100%;
	max-width: 640px;
	transform: translateY(-8px);
	transition: transform 0.18s ease;
}
.search-overlay.is-open .search-overlay-inner { transform: translateY(0); }
.search-overlay-heading {
	font-family: var(--k-font-heading);
	font-size: 0.8rem;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--k-muted);
	margin: 0 0 0.75rem;
}
.search-overlay-close {
	position: absolute;
	top: -3.25rem;
	right: 0;
	width: 44px;
	height: 44px;
	font-size: 1.75rem;
	line-height: 1;
	background: transparent;
	border: 1px solid var(--k-rule);
	border-radius: 6px;
	color: var(--k-text);
	cursor: pointer;
}
.search-overlay-close:hover { border-color: var(--k-accent); color: var(--k-accent); }
.search-overlay-close:focus-visible {
	outline: 2px solid var(--k-accent);
	outline-offset: 2px;
}
/* Inside the overlay the form spans the panel and reads larger than the inline
   version, since it is the sole focus of the screen. */
/* The overlay form carries the theme's character rather than the plain inline
   look: a display-font heading, a larger field with an accent focus ring, and
   an accent-gradient submit button matching the gradient language used in the
   hero and admin. Everything is mixed from the active scheme's own --k-accent,
   --k-bg, and --k-text, so both Charcoal and Ivory (and any custom scheme) get
   a coherent, palette-correct treatment. */
.search-overlay-heading {
	font-family: var(--k-font-heading);
}
.search-overlay .search-form {
	max-width: none;
	margin: 0;
	width: 100%;
	gap: 0.85rem;
}
.search-overlay .search-form input[type="search"],
.search-overlay .search-form .search-field {
	flex: 1 1 auto;
	font-family: var(--k-font-body);
	font-size: 1.2rem;
	padding: 0.9rem 1.1rem;
	border: 1px solid color-mix( in srgb, var(--k-accent) 45%, var(--k-rule) );
	border-radius: 8px;
	background: color-mix( in srgb, var(--k-accent) 4%, var(--k-bg) );
	color: var(--k-text);
	box-shadow: 0 1px 2px rgba( 0, 0, 0, 0.12 );
	transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.search-overlay .search-form input[type="search"]::placeholder,
.search-overlay .search-form .search-field::placeholder {
	color: var(--k-muted);
}
.search-overlay .search-form input[type="search"]:focus,
.search-overlay .search-form .search-field:focus {
	outline: none;
	border-color: var(--k-accent);
	box-shadow: 0 0 0 3px color-mix( in srgb, var(--k-accent) 30%, transparent );
}
/* Accent-gradient submit, matching the theme's gradient language. Text colour
   is the background token so it stays legible on the accent in both schemes. */
.search-overlay .search-form .search-submit {
	padding: 0.9rem 1.6rem;
	border: 0;
	border-radius: 8px;
	font-family: var(--k-font-heading);
	font-size: 1rem;
	font-weight: 700;
	letter-spacing: 0.01em;
	color: var(--k-bg);
	cursor: pointer;
	background: linear-gradient(
		135deg,
		var(--k-accent) 0%,
		color-mix( in srgb, var(--k-accent) 70%, #000 ) 100%
	);
	box-shadow: 0 1px 3px rgba( 0, 0, 0, 0.2 );
	transition: filter 0.15s ease;
}
.search-overlay .search-form .search-submit:hover,
.search-overlay .search-form .search-submit:focus-visible {
	filter: brightness( 1.08 );
	outline: none;
}
.search-overlay .search-form .search-submit:focus-visible {
	box-shadow: 0 0 0 3px color-mix( in srgb, var(--k-accent) 35%, transparent );
}
@media ( forced-colors: active ) {
	.search-overlay .search-form input[type="search"],
	.search-overlay .search-form .search-field,
	.search-overlay .search-form .search-submit {
		background: Canvas;
		color: CanvasText;
		border: 1px solid CanvasText;
	}
}
/* Locks background scroll while the overlay is open. */
body.search-overlay-open { overflow: hidden; }

@media ( prefers-reduced-motion: reduce ) {
	.search-overlay,
	.search-overlay-inner {
		transition: none;
	}
	.search-overlay-inner { transform: none; }
}

/* ------- Navigation toggle ------- */
/* The button is injected by assets/js/nav-toggle.js. Without JavaScript the
   class is never added, the button never exists, and the menu stays visible
   as a wrapping list. */
.nav-toggle {
	display: none;
	align-items: center;
	justify-content: center;
	width: 44px;
	height: 44px;
	padding: 0;
	margin-left: auto;
	background: transparent;
	border: 1px solid var(--k-rule);
	border-radius: 6px;
	color: var(--k-text);
	cursor: pointer;
}
.nav-toggle:focus-visible {
	outline: 2px solid var(--k-accent);
	outline-offset: 2px;
}
.nav-toggle-bars {
	display: block;
	width: 18px;
	height: 12px;
	position: relative;
}
.nav-toggle-bars span {
	position: absolute;
	left: 0;
	width: 100%;
	height: 2px;
	background: currentColor;
	border-radius: 2px;
	transition: transform 0.18s ease, opacity 0.18s ease;
}
.nav-toggle-bars span:nth-child(1) { top: 0; }
.nav-toggle-bars span:nth-child(2) { top: 5px; }
.nav-toggle-bars span:nth-child(3) { top: 10px; }

.nav-is-open .nav-toggle-bars span:nth-child(1) { transform: translateY(5px) rotate(45deg); }
.nav-is-open .nav-toggle-bars span:nth-child(2) { opacity: 0; }
.nav-is-open .nav-toggle-bars span:nth-child(3) { transform: translateY(-5px) rotate(-45deg); }

/* ------- Tablet landscape ------- */
@media (max-width: 1024px) {
	.site-header .container { padding: 0 1.5rem; }

	/* Sidebar card dissolves into an ordinary header. */
	.sidebar-card {
		border-radius: 0;
		border-left: 0;
		border-right: 0;
		border-top: 0;
		box-shadow: none;
		padding: 1rem 1.25rem;
	}
	.sidebar-card .site-nav .nav-menu { flex-direction: row; flex-wrap: wrap; gap: 0.25rem 0.75rem; }
	.sidebar-card .sidebar-social { display: none; }
	.nav-num { display: none; }
	.hero { padding: 3rem 0 2.5rem; }
	.hero-inner { gap: 2.5rem; }
}

/* ------- Tablet portrait ------- */
@media (max-width: 768px) {
	body { font-size: 16px; }

	.container { padding: 0 1.25rem; }
	.site-header { padding: 0.85rem 0; }
	.site-header .container {
		padding: 0 1.25rem;
		flex-wrap: wrap;
		align-items: center;
	}

	/* Collapse the menu, but only once the toggle exists to reopen it. */
	.site-header.has-nav-toggle .nav-toggle { display: inline-flex; }
	.site-header.has-nav-toggle .site-nav {
		flex-basis: 100%;
		max-height: 0;
		overflow: hidden;
		opacity: 0;
		transition: max-height 0.22s ease, opacity 0.22s ease;
	}
	.site-header.has-nav-toggle.nav-is-open .site-nav {
		max-height: 70vh;
		opacity: 1;
		overflow-y: auto;
		margin-top: 0.75rem;
	}
	.site-nav .nav-menu {
		flex-direction: column;
		gap: 0;
	}
	.site-nav .nav-menu li { border-top: 1px solid var(--k-rule); }
	.site-nav .nav-menu a {
		display: block;
		padding: 0.75rem 0;
		font-size: 1rem;
	}

	/* Hero stacks, portrait leads. */
	.hero { padding: 2.25rem 0 2rem; }
	.hero-inner {
		grid-template-columns: 1fr;
		gap: 1.75rem;
	}
	.hero-portrait {
		order: -1;
		width: min(var(--k-portrait), 190px);
		justify-self: start;
	}
	.hero-body { max-width: none; }

	.section-heading { font-size: 1.4rem; }
	.content-header { margin: 2rem 0 1.5rem; }

	.post-nav { flex-direction: column; gap: 0.5rem; }
	.site-footer .footer-nav .nav-menu { gap: 1.25rem; }
}

/* ------- Phones ------- */
@media (max-width: 560px) {
	.container { padding: 0 1rem; }
	.site-header .container { padding: 0 1rem; }

	.hero { padding: 1.75rem 0 1.5rem; }
	.hero-portrait { width: min(var(--k-portrait), 150px); }

	/* Tighter transition from hero into the Recent Posts section on phones:
	   the default 2.5rem 0 3rem padding on `.recent` reads as excessive
	   vertical breathing room when combined with the hero's own bottom
	   padding on a narrow viewport. Halve it. */
	.recent { padding: 1.25rem 0 2rem; }
	.section-chooser { margin-bottom: 1rem; }

	/* Columns collapse: the two meta columns move above the title. */
	.post-item.is-columns a { flex-wrap: wrap; gap: 0.2rem 1rem; }
	.post-item.is-columns .post-item-main { flex-basis: 100%; }

	/* Title over date, so neither is squeezed. */
	.post-item a {
		flex-direction: column;
		align-items: flex-start;
		gap: 0.2rem;
		padding: 0.8rem 0;
	}
	.post-item .post-date { font-size: 0.82rem; }

	.section-heading {
		flex-direction: column;
		align-items: flex-start;
		gap: 0.25rem;
	}

	.section-list {
		flex-wrap: nowrap;
		overflow-x: auto;
		-webkit-overflow-scrolling: touch;
		scrollbar-width: none;
		padding-bottom: 0.6rem;
	}
	.section-list::-webkit-scrollbar { display: none; }
	.section-item { flex: 0 0 auto; }

	.search-form { flex-direction: column; max-width: none; }
	.search-form .search-submit { width: 100%; }

	.site-footer { margin-top: 2.5rem; padding: 1.5rem 0 2rem; }
	.site-footer .footer-nav .nav-menu { gap: 1rem; justify-content: center; }

	.tags { gap: 0.4rem; }
	pre { padding: 0.85rem 1rem; font-size: 0.85em; }
}

/* ------- Touch targets -------
   Pointer-coarse devices need larger hit areas than a mouse does. 44px is the
   figure both Apple and WCAG 2.2 settle on. */
@media (pointer: coarse) {
	.hero-social-link {
		width: 44px;
		height: 44px;
	}
	.site-nav .nav-menu a,
	.footer-nav .nav-menu a {
		padding-top: 0.6rem;
		padding-bottom: 0.6rem;
	}
	.tags li a { padding: 0.4rem 0.7rem; }
}

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

/* ------- Email guard ------- */
/* Placeholder anchors are inert until the decoder runs. */
a.k-email[data-mbe] { cursor: pointer; }
a.k-email.is-resolved { cursor: auto; }


/* ------- Print -------
   The screen design is palette-driven and often dark, which prints as a solid
   block of toner. Print resets to black on white, drops navigation and
   interactive chrome that cannot be used on paper, and reveals link targets
   after the anchor text so a printed page stays useful as a reference.

   Colours here are literal rather than custom properties: the point is to
   escape the palette, not to follow it. */
/* Print branding elements are inert on screen; only the print block below
   reveals them. */
.print-letterhead,
.print-colophon {
	display: none;
}

@media print {
	/* A named page with generous margins and a running footer carrying the
	   site name and page number, so every sheet is identifiably yours. */
	@page {
		margin: 20mm 18mm 22mm;
	}

	:root {
		--k-bg: #ffffff;
		--k-text: #000000;
		--k-muted: #444444;
		--k-accent: #000000;
		--k-rule: #cccccc;
	}

	html,
	body {
		background: #fff;
		color: #000;
		font-size: 11pt;
		line-height: 1.45;
	}

	/* Chrome that cannot be acted on from paper. */
	.site-header,
	.site-footer,
	.nav-toggle,
	.skip-link,
	.section-chooser,
	.content-meta,
	.post-nav,
	.pagination,
	.search-form,
	.hero-social,
	.post-preview,
	.not-found-search,
	.planned-notice .planned-badge-line {
		display: none;
	}

	/* Body copy prints left-aligned. Justification without hyphenation opens
	   rivers at print measure for the same reason it does below 640px. */
	.e-content > p,
	.e-content > ul li,
	.e-content > ol li {
		text-align: left;
	}

	a {
		color: #000;
		border-bottom: 0;
		text-decoration: underline;
	}

	/* Reveal destinations, since a printed link is otherwise a dead end.
	   Internal fragment and same-page anchors are excluded: their targets add
	   noise without adding information. */
	.e-content a[href^="http"]::after {
		content: " (" attr(href) ")";
		font-size: 0.85em;
		word-break: break-all;
	}

	h1,
	h2,
	h3 {
		page-break-after: avoid;
		break-after: avoid;
	}

	img,
	figure,
	blockquote,
	pre,
	table {
		page-break-inside: avoid;
		break-inside: avoid;
	}

	img {
		max-width: 100% !important;
	}

	.post-title {
		font-size: 18pt;
	}

	/* Letterhead: the site identity as a document masthead on the first page.
	   A rule beneath it sets it apart from the article title that follows. */
	.print-letterhead {
		display: block;
		margin: 0 0 8mm;
		padding: 0 0 3mm;
		border-bottom: 1.5pt solid #000;
	}
	.print-letterhead-name {
		display: block;
		font-family: var(--k-font-heading, Georgia, serif);
		font-size: 15pt;
		font-weight: 700;
		letter-spacing: 0.01em;
	}
	.print-letterhead-tag {
		display: block;
		margin-top: 1mm;
		font-size: 9pt;
		font-style: italic;
		color: #444;
	}

	/* Colophon: the citation block at the foot of the article. Kept together on
	   one page and set off with a rule, so it reads as apparatus rather than
	   body text. */
	.print-colophon {
		display: block;
		margin: 10mm 0 0;
		padding: 4mm 0 0;
		border-top: 0.5pt solid #999;
		page-break-inside: avoid;
		break-inside: avoid;
		font-size: 9pt;
		line-height: 1.4;
	}
	.print-colophon-label {
		margin: 0 0 2mm;
		font-family: var(--k-font-heading, Georgia, serif);
		font-size: 8pt;
		font-weight: 700;
		letter-spacing: 0.12em;
		text-transform: uppercase;
		color: #444;
	}
	.print-colophon-citation {
		margin: 0 0 1.5mm;
	}
	.print-colophon-site {
		font-style: italic;
	}
	.print-colophon-source {
		margin: 0;
		color: #444;
		word-break: break-all;
	}

	/* The 404 backdrop is a decorative watermark; on paper it is a giant
	   grey number with no purpose. */
	.not-found-backdrop {
		display: none;
	}
}
