/* Terminal - monospace, hard edges, everything in a box.
 *
 * A third system, as far from the other two as the skeleton allows. One
 * typeface at one size, no radii, no shadows, no display type: hierarchy comes
 * from boxes, brackets and the accent, the way it does in a text-mode
 * interface. The hero is the only thing that scales up, and only because a name
 * is what the page is for.
 *
 * It also serves as the contract's proof: if a design system this different
 * needs no change to the markup, the markup really is skeleton.
 */

/* ---------------------------------------------------------------- tokens - */

:root {
	--font-mono: ui-monospace, "SF Mono", "Cascadia Code", "JetBrains Mono", Menlo, monospace;

	--step-display: clamp(2rem, 7vw, 4.5rem);
	--step-title: 1.0625rem;
	--step-body: 0.9375rem;
	--step-small: 0.8125rem;
	--step-label: 0.75rem;

	--space-1: 0.25rem;
	--space-2: 0.5rem;
	--space-3: 0.75rem;
	--space-4: 1rem;
	--space-6: 1.5rem;
	--space-8: 2rem;
	--space-12: 3rem;
	--space-16: 4rem;
	--space-24: 5rem;

	--measure: 68ch;
	/* A fixed length, not ch. `ch` resolves against each element's own
	 * font-size, so with margin-inline: auto a heading, a paragraph and the
	 * small-type footer each computed a different width and therefore a
	 * different left edge: three stripes instead of one. 45rem is what 80ch
	 * measured at this theme's body size. */
	--measure-post: 45rem;
	--frame: min(64rem, 100% - 2rem);

	--transition: 90ms linear;

	--bg: light-dark(
		oklch(0.965 var(--chroma-ghost) var(--hue-seed)),
		oklch(0.16 var(--chroma-ghost) var(--hue-seed))
	);
	--surface: light-dark(
		oklch(0.925 var(--chroma-ghost) var(--hue-seed)),
		oklch(0.215 var(--chroma-ghost) var(--hue-seed))
	);
	--ink: light-dark(
		oklch(0.2 var(--chroma-quiet) var(--hue-seed)),
		oklch(0.9 var(--chroma-ghost) var(--hue-seed))
	);
	--ink-2: light-dark(
		oklch(0.42 var(--chroma-quiet) var(--hue-seed)),
		oklch(0.72 var(--chroma-ghost) var(--hue-seed))
	);
	--ink-3: light-dark(
		oklch(0.55 var(--chroma-quiet) var(--hue-seed)),
		oklch(0.58 var(--chroma-ghost) var(--hue-seed))
	);
	--rule: light-dark(
		oklch(0.75 var(--chroma-quiet) var(--hue-seed)),
		oklch(0.34 var(--chroma-quiet) var(--hue-seed))
	);
	--accent: light-dark(
		oklch(0.46 var(--chroma-loud) var(--hue-match)),
		oklch(0.82 var(--chroma-loud) var(--hue-match))
	);
	--accent-ink: light-dark(oklch(0.98 0 0), oklch(0.16 0 0));
	--alert: light-dark(
		oklch(0.48 calc(var(--chroma-accent) + 0.1) var(--hue-alert)),
		oklch(0.78 calc(var(--chroma-accent) + 0.1) var(--hue-alert))
	);
	--focus: var(--accent);
}

/* ------------------------------------------------------------------ base - */

body {
	background: var(--bg);
	color: var(--ink);
	font-family: var(--font-mono);
	font-size: var(--step-body);
	line-height: 1.65;
}

a {
	color: inherit;
}

:focus-visible {
	outline: 2px solid var(--focus);
	outline-offset: 2px;
}

.skip {
	margin: var(--space-2);
	padding: var(--space-2) var(--space-4);
	background: var(--accent);
	color: var(--accent-ink);
	font-size: var(--step-small);
	text-decoration: none;
}

.frame {
	width: var(--frame);
	margin-inline: auto;
}

/* Section labels are bracketed rather than styled, which is the convention this
 * look borrows from. */
.eyebrow {
	margin: 0;
	font-size: var(--step-label);
	text-transform: uppercase;
	color: var(--ink-3);
}

.eyebrow::before {
	content: "[ ";
}

.eyebrow::after {
	content: " ]";
}

/* ---------------------------------------------------------------- header - */

.masthead {
	padding-block: var(--space-3);
	border-bottom: 1px solid var(--rule);
	position: relative;
	z-index: 2;
}

/* Wrapping, because the signed-in masthead carries four links, a name and a
 * sign-out control, and at 390px that is wider than the screen. Without
 * this the row overflowed the viewport and the whole document scrolled
 * sideways on a phone. */
.masthead__inner {
	flex-wrap: wrap;
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--space-4);
	font-size: var(--step-small);
}

.wordmark {
	color: var(--ink-2);
	text-decoration: none;
}

.wordmark::before {
	content: "$ ";
	color: var(--accent);
}

.wordmark b {
	color: var(--ink);
	font-weight: 700;
}

.wordmark__tld {
	color: var(--ink-3);
}

.masthead__nav {
	flex-wrap: wrap;
	min-width: 0;
	display: flex;
	align-items: center;
	gap: var(--space-4);
	font-size: var(--step-small);
}

/* Only the sign-out form, which is a direct child. The design switcher's
 * form is nested deeper and must keep its own box. */
.masthead__nav > form {
	display: contents;
}

.masthead__action {
	padding: 0;
	background: none;
	border: 0;
	color: var(--ink-2);
	font: inherit;
	text-decoration: none;
}

.masthead__action::before {
	content: "--";
	color: var(--ink-3);
}

.masthead__action:hover {
	color: var(--accent);
}

.masthead__who {
	color: var(--ink-3);
}

/* ------------------------------------------------------- masthead links - */

/* The kit's navigation: out of the way until the masthead is hovered or
 * holds focus. Screens without a pointer cannot hover, so there the links
 * are simply visible. */
.masthead__links {
	flex-wrap: wrap;
	display: flex;
	gap: var(--space-4);
	opacity: 0;
	pointer-events: none;
}

.masthead:hover .masthead__links,
.masthead:focus-within .masthead__links {
	opacity: 1;
	pointer-events: auto;
}

@media (hover: none) {
	.masthead__links {
		opacity: 1;
		pointer-events: auto;
	}
}

.masthead__link {
	color: var(--ink-2);
	text-decoration: none;
}

.masthead__link::before {
	content: "--";
	color: var(--ink-3);
}

.masthead__link:hover {
	color: var(--accent);
}

.masthead__link[aria-current="page"] {
	color: var(--ink);
}

/* -------------------------------------------------------------- designer - */

.designer__form {
	display: grid;
	gap: var(--space-4);
	font-size: var(--step-small);
}

/* The background's own block. Every group here is already a box, so a second
 * box around four of them would be a frame around a frame; the section is
 * marked by a heading and a dashed rule instead, the way a TUI separates a
 * region from the widgets inside it. */
.designer__section {
	display: grid;
	gap: var(--space-4);
	padding-top: var(--space-3);
	border-top: 1px dashed var(--rule);
}

.designer__section-head {
	display: grid;
	gap: var(--space-1);
}

.designer__section-title {
	margin: 0;
	font-size: var(--step-small);
	font-weight: 400;
	text-transform: uppercase;
	color: var(--ink);
}

/* The bracket is content, not decoration: everything else in this theme that
 * names a region is bracketed, and a bare word here would be the odd one. */
.designer__section-title::before {
	content: "[ ";
}

.designer__section-title::after {
	content: " ]";
}

.designer__section-note {
	margin: 0;
	font-size: var(--step-small);
	line-height: 1.5;
	color: var(--ink-3);
}

/* flow-root, not grid: a rendered <legend> is placed above its fieldset's box
 * and quietly eats the space between one group and the next. The legend below
 * is floated back into normal flow instead, and flow-root is what makes the
 * fieldset contain it. */
.designer__group {
	display: flow-root;
	padding: var(--space-3);
	border: 1px solid var(--rule);
}

.designer__group > * + * {
	clear: both;
	margin-top: var(--space-2);
}

/* The legend sits in the border, the way a titled box does in a TUI. */
.designer__legend {
	float: left;
	width: auto;
	margin: calc(var(--space-3) * -1 - 0.8em) 0 0 calc(var(--space-3) * -1);
	padding: 0 var(--space-2);
	background: var(--bg);
	font-size: var(--step-label);
	text-transform: uppercase;
	color: var(--ink-3);
}

.designer__radio {
	position: absolute;
	width: 1px;
	height: 1px;
	opacity: 0;
	pointer-events: none;
}

.designer__themes {
	display: grid;
}

.designer__theme {
	display: block;
	padding: var(--space-1) 0;
	cursor: pointer;
}

.designer__theme-body {
	display: grid;
}

.designer__theme-name::before {
	content: "( ) ";
	color: var(--ink-3);
}

.designer__theme:has(:checked) .designer__theme-name::before {
	content: "(x) ";
	color: var(--accent);
}

.designer__theme:has(:checked) .designer__theme-name {
	color: var(--accent);
}

.designer__theme-note {
	padding-left: 4ch;
	font-size: var(--step-label);
	line-height: 1.4;
	color: var(--ink-3);
}

.designer__theme:has(:focus-visible) {
	outline: 2px solid var(--focus);
	outline-offset: 1px;
}

.designer__swatches {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
	gap: var(--space-1);
}

.designer__swatch {
	height: 1.6rem;
	min-width: 0;
	padding: 0;
	border: 1px solid transparent;
	background: light-dark(
		oklch(0.55 calc(var(--swatch-chroma) * 2.6) var(--swatch-hue)),
		oklch(0.76 calc(var(--swatch-chroma) * 2.6) var(--swatch-hue))
	);
}

.designer__swatch--on {
	border-color: var(--ink);
	outline: 1px solid var(--ink);
	outline-offset: 1px;
}

.designer__swatch-name {
	position: absolute;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
}

.designer__dial {
	display: grid;
	gap: var(--space-1);
}

.designer__dial-head {
	display: flex;
	justify-content: space-between;
	font-size: var(--step-label);
	text-transform: uppercase;
	color: var(--ink-3);
}

.designer__dial-value {
	color: var(--accent);
}

.designer__range {
	-webkit-appearance: none;
	appearance: none;
	width: 100%;
	height: 14px;
	margin: 0;
	background: transparent;
	cursor: ew-resize;
}

.designer__range::-webkit-slider-runnable-track {
	height: 10px;
	border: 1px solid var(--rule);
}

.designer__range::-moz-range-track {
	height: 10px;
	border: 1px solid var(--rule);
}

.designer__range::-webkit-slider-thumb {
	-webkit-appearance: none;
	appearance: none;
	width: 8px;
	height: 16px;
	margin-top: -4px;
	border: 0;
	background: var(--ink);
}

.designer__range::-moz-range-thumb {
	width: 8px;
	height: 16px;
	border: 0;
	border-radius: 0;
	background: var(--ink);
}

.designer__range--hue::-webkit-slider-runnable-track {
	background: linear-gradient(
		to right,
		oklch(0.62 0.16 0),
		oklch(0.62 0.16 60),
		oklch(0.62 0.16 120),
		oklch(0.62 0.16 180),
		oklch(0.62 0.16 240),
		oklch(0.62 0.16 300),
		oklch(0.62 0.16 360)
	);
}

.designer__range--hue::-moz-range-track {
	background: linear-gradient(
		to right,
		oklch(0.62 0.16 0),
		oklch(0.62 0.16 60),
		oklch(0.62 0.16 120),
		oklch(0.62 0.16 180),
		oklch(0.62 0.16 240),
		oklch(0.62 0.16 300),
		oklch(0.62 0.16 360)
	);
}

.designer__range--chroma::-webkit-slider-runnable-track {
	background: linear-gradient(to right, oklch(0.66 0 var(--hue-seed)), oklch(0.66 0.18 var(--hue-seed)));
}

.designer__range--chroma::-moz-range-track {
	background: linear-gradient(to right, oklch(0.66 0 var(--hue-seed)), oklch(0.66 0.18 var(--hue-seed)));
}

.designer__chips {
	display: flex;
	flex-wrap: wrap;
	gap: 0 var(--space-3);
}

.designer__chip {
	font-size: var(--step-label);
	text-transform: uppercase;
	color: var(--ink-3);
	cursor: pointer;
}

.designer__chip:has(:checked) {
	color: var(--accent-ink);
	background: var(--accent);
}

.designer__chip:has(:focus-visible) {
	outline: 2px solid var(--focus);
	outline-offset: 1px;
}

.designer__note {
	margin: 0;
	font-size: var(--step-label);
	line-height: 1.4;
	color: var(--ink-3);
}

.designer__actions {
	display: flex;
	gap: var(--space-2);
}

.designer__apply,
.designer__reset,
.designer__save {
	flex: 1;
	padding: var(--space-2);
	border: 1px solid var(--rule);
	background: none;
	color: var(--ink-2);
	font: inherit;
	font-size: var(--step-label);
	text-transform: uppercase;
}

.designer__apply {
	background: var(--accent);
	border-color: var(--accent);
	color: var(--accent-ink);
}

.designer__reset:hover {
	border-color: var(--ink);
	color: var(--ink);
}

/* The operator's control for promoting the current selection to the site-wide
 * default. Accented, because it is the one button here that changes what
 * other people see. */
.designer__actions--default {
	flex-direction: column;
	gap: var(--space-2);
}

.designer__save {
	color: var(--accent);
	border-color: var(--accent);
}

.designer__save:hover {
	background: var(--accent);
	color: var(--accent-ink);
	border-color: var(--accent);
}

.designer__note--saved {
	color: var(--accent);
}

/* ------------------------------------------------------------------ hero - */

.hero {
	padding-block: var(--space-16) var(--space-12);
}

.hero__name {
	margin: 0;
	font-size: var(--step-display);
	font-weight: 700;
	line-height: 1.02;
	letter-spacing: -0.03em;
	text-transform: uppercase;
}

.hero__name span {
	display: block;
}

.hero__name span::before {
	content: "> ";
	color: var(--accent);
}

.hero__name span + span {
	color: var(--ink-2);
}

/* A row of dashes, drawn as a repeating gradient so it stays a rule rather than
 * becoming text nobody asked to read. */
.hero__rule {
	height: 1px;
	margin-block: var(--space-8) var(--space-6);
	border: 0;
	background: repeating-linear-gradient(
		to right,
		var(--rule) 0 8px,
		transparent 8px 14px
	);
}

.hero__thesis {
	max-width: var(--measure);
	margin: 0;
	font-size: var(--step-title);
	line-height: 1.6;
	color: var(--ink-2);
}

.hero__meta {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-1) var(--space-4);
	margin-top: var(--space-6);
	font-size: var(--step-small);
	color: var(--ink-3);
}

.hero__meta a {
	color: var(--ink-2);
	text-decoration: none;
}

.hero__meta a::before {
	content: "@";
	color: var(--ink-3);
}

.hero__meta a:hover {
	color: var(--accent);
}

/* ----------------------------------------------------------------- index - */

.index {
	padding-block: var(--space-6) var(--space-24);
}

.index__head {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: var(--space-4);
	margin-bottom: var(--space-4);
}

/* The rail is drawn in characters: the origin, then one entry per line, each
 * prefixed like a tree listing. */
.rail {
	border: 1px solid var(--rule);
}

.rail__origin {
	display: flex;
	align-items: center;
	gap: var(--space-2);
	margin: 0;
	padding: var(--space-2) var(--space-4);
	background: var(--surface);
	border-bottom: 1px solid var(--rule);
	font-size: var(--step-small);
	color: var(--ink-2);
}

.rail__cap {
	flex: none;
	width: 0.55em;
	height: 0.9em;
	background: var(--accent);
}

.rail__list {
	list-style: none;
	margin: 0;
	padding: 0;
}

.branch {
	position: relative;
	padding: var(--space-3) var(--space-4) var(--space-3) 4ch;
	border-bottom: 1px solid var(--rule);
	transition: background var(--transition);
}

.branch:last-child {
	border-bottom: 0;
}

.branch::before {
	content: "├─";
	position: absolute;
	left: var(--space-4);
	top: var(--space-3);
	color: var(--ink-3);
}

.branch:last-child::before {
	content: "└─";
}

.branch--live:hover {
	background: var(--surface);
}

.branch__link {
	display: block;
	text-decoration: none;
	color: inherit;
}

.branch__link::after {
	content: "";
	position: absolute;
	inset: 0;
}

.branch__top {
	display: flex;
	align-items: baseline;
	flex-wrap: wrap;
	gap: var(--space-3);
}

.branch__name {
	margin: 0;
	font-size: var(--step-title);
	font-weight: 700;
}

.branch--live .branch__name {
	color: var(--accent);
}

.branch--planned .branch__name,
.branch--down .branch__name {
	color: var(--ink-2);
}

.branch__path {
	font-size: var(--step-small);
	color: var(--ink-3);
}

.branch__summary {
	max-width: var(--measure);
	margin: var(--space-1) 0 0;
	font-size: var(--step-small);
	color: var(--ink-2);
}

.tag {
	padding: 0 var(--space-2);
	border: 1px solid var(--rule);
	font-size: var(--step-label);
	text-transform: uppercase;
	color: var(--ink-3);
	white-space: nowrap;
}

.tag--operator {
	border-color: var(--accent);
	color: var(--accent);
}

.tag--down {
	border-color: var(--alert);
	color: var(--alert);
}

/* ------------------------------------------------------------ empty state - */

.empty {
	margin: 0;
	padding: var(--space-6) var(--space-4);
	max-width: var(--measure);
	color: var(--ink-2);
}

/* ----------------------------------------------------------------- login - */

.login {
	display: flex;
	align-items: center;
	min-height: 66vh;
	padding-block: var(--space-16);
}

.login__panel {
	width: 100%;
	max-width: 26rem;
	padding: var(--space-6);
	border: 1px solid var(--rule);
}

.login__title {
	margin: var(--space-4) 0 var(--space-6);
	font-size: var(--step-title);
	font-weight: 700;
	text-transform: uppercase;
}

.login__title::before {
	content: "> ";
	color: var(--accent);
}

.field {
	display: block;
	margin-bottom: var(--space-4);
}

.field__label {
	display: block;
	margin-bottom: var(--space-1);
	font-size: var(--step-label);
	text-transform: uppercase;
	color: var(--ink-3);
}

.field__input {
	width: 100%;
	padding: var(--space-2) var(--space-3);
	background: var(--surface);
	color: var(--ink);
	border: 1px solid var(--rule);
	font: inherit;
}

.field__input:focus {
	outline: none;
	border-color: var(--accent);
}

.button {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 100%;
	padding: var(--space-2) var(--space-4);
	background: var(--accent);
	color: var(--accent-ink);
	border: 1px solid var(--accent);
	font: inherit;
	text-transform: uppercase;
}

.button:hover {
	background: none;
	color: var(--accent);
}

.button[aria-busy="true"] {
	opacity: 0.7;
	pointer-events: none;
}

.notice {
	margin-bottom: var(--space-4);
	padding: var(--space-2) var(--space-3);
	border: 1px solid var(--alert);
	font-size: var(--step-small);
	color: var(--alert);
}

.notice::before {
	content: "! ";
}

.notice:empty {
	display: none;
}

/* ---------------------------------------------------------------- footer - */

.colophon {
	padding-block: var(--space-4);
	border-top: 1px solid var(--rule);
	font-size: var(--step-label);
	color: var(--ink-3);
}

.colophon__inner {
	display: flex;
	flex-wrap: wrap;
	justify-content: space-between;
	gap: var(--space-1) var(--space-4);
}

/* ---------------------------------------------------------- small screens - */

@media (max-width: 40rem) {
	:root {
		--frame: min(64rem, 100% - 1.5rem);
	}

	.masthead__inner {
		flex-wrap: wrap;
	}

	/* A heading and its kicker side by side have no room on a phone, so
	 * they stack instead of squeezing each other into ragged columns. */
	.index__head {
		flex-direction: column;
		align-items: flex-start;
		gap: var(--space-1);
	}
}

/* ------------------------------------------------------------ the nearby - */

/* A box lights its own fill as the pointer passes. Nothing else moves, because
 * nothing else in this look moves. */
:root {
	--nearby: light-dark(
		oklch(0.55 var(--chroma-loud) var(--hue-match) / 0.16),
		oklch(0.6 var(--chroma-loud) var(--hue-match) / 0.18)
	);
}

.branch__link::after,
.kit__panel::after,
.playground::after {
	content: "";
	position: absolute;
	inset: 0;
	pointer-events: none;
	background-image: var(--nearby-image);
	background-attachment: fixed;
	opacity: var(--nearby-on);
	transition: opacity 400ms ease;
}

.kit__panel,
.playground {
	position: relative;
}

/* -------------------------------------------------------------- the kit - */

.kit {
	padding-block: var(--space-8) var(--space-24);
}

.page__masthead {
	max-width: var(--measure);
	margin-bottom: var(--space-12);
}

.page__title {
	margin: 0 0 var(--space-3);
	font-size: clamp(1.6rem, 5vw, 2.6rem);
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: -0.02em;
}

/* A no-break space, not an ordinary one. The gap after the marker is the only
 * break opportunity between it and the name, so an ordinary space is where the
 * line breaks first on a narrow screen - leaving the prompt alone on a line
 * above the title, which reads as a stray character rather than as a prompt.
 * Tied to the name, the marker goes wherever the name goes. */
.page__title::before {
	content: ">\00a0";
	color: var(--accent);
}

.page__lede {
	margin: 0;
	line-height: 1.6;
	color: var(--ink-2);
}

/* The controls and the proof, side by side: a third for the switcher, the
 * rest for the samples. The switcher stays pinned while the samples scroll,
 * so a change and its effect share the viewport. */
.kit__layout {
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
	gap: var(--space-8);
	align-items: start;
}

.kit__controls {
	position: sticky;
	top: var(--space-4);
	max-height: calc(100vh - var(--space-8));
	overflow-y: auto;
	overscroll-behavior: contain;
}

@media (max-width: 60rem) {
	.kit__layout {
		grid-template-columns: minmax(0, 1fr);
	}

	.kit__controls {
		position: static;
		max-height: none;
		overflow: visible;
	}
}

.kit__section {
	margin-bottom: var(--space-12);
}

.kit__head {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: var(--space-4);
	margin-bottom: var(--space-3);
}

.kit__panel {
	position: relative;
	display: grid;
	gap: var(--space-4);
	padding: var(--space-4);
	border: 1px solid var(--rule);
}

.kit__heading {
	margin: 0;
	font-size: var(--step-title);
	font-weight: 700;
	text-transform: uppercase;
}

.prose {
	max-width: var(--measure);
	color: var(--ink-2);
}

.prose > * {
	margin: 0;
}

.prose > * + * {
	margin-top: var(--space-3);
}

.prose ul {
	padding-left: 3ch;
	list-style: none;
}

.prose li::before {
	content: "- ";
	color: var(--ink-3);
}

.prose a {
	color: var(--accent);
	text-underline-offset: 3px;
}

.prose code {
	padding: 0 var(--space-1);
	background: var(--surface);
	color: var(--ink);
}

.prose blockquote {
	padding: var(--space-2) var(--space-3);
	border-left: 2px solid var(--accent);
	background: var(--surface);
	color: var(--ink);
}

.kit__row {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 1fr));
	gap: var(--space-3);
}

.kit__panel .field {
	margin-bottom: 0;
}

select.field__input {
	appearance: none;
	border-radius: 0;
	background-image: linear-gradient(45deg, transparent 50%, var(--ink-3) 50%),
		linear-gradient(135deg, var(--ink-3) 50%, transparent 50%);
	background-position: calc(100% - 16px) center, calc(100% - 11px) center;
	background-size: 5px 5px;
	background-repeat: no-repeat;
	padding-right: var(--space-8);
}

textarea.field__input {
	resize: vertical;
	min-height: 5rem;
}

.field__input:disabled {
	background: none;
	color: var(--ink-3);
	cursor: not-allowed;
}

.kit__controls {
	display: grid;
	gap: var(--space-1);
}

/* Drawn the way a text-mode interface draws them, in characters, so the state
 * is legible even with the colour taken away. */
.control {
	display: inline-flex;
	align-items: baseline;
	gap: var(--space-2);
	font-size: var(--step-small);
	color: var(--ink-2);
	cursor: pointer;
}

.control input {
	appearance: none;
	width: 0;
	height: 0;
	margin: 0;
}

.control span::before {
	content: "[ ] ";
	color: var(--ink-3);
}

.control:has(input[type="radio"]) span::before {
	content: "( ) ";
}

.control:has(input:checked) span::before {
	content: "[x] ";
	color: var(--accent);
}

.control:has(input[type="radio"]:checked) span::before {
	content: "(x) ";
	color: var(--accent);
}

.control:has(input:focus-visible) {
	outline: 2px solid var(--focus);
	outline-offset: 1px;
}

.kit__actions {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-2);
}

.kit__actions .button {
	width: auto;
}

.button--quiet {
	background: none;
	border-color: var(--rule);
	color: var(--ink-2);
}

.button--quiet:hover {
	background: none;
	border-color: var(--ink);
	color: var(--ink);
}

.button:disabled {
	background: none;
	border-color: var(--rule);
	color: var(--ink-3);
	cursor: not-allowed;
}

.kit__marks {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--space-3);
	margin: 0;
}

.kit__note {
	max-width: var(--measure);
	margin: 0;
	font-size: var(--step-small);
	color: var(--ink-3);
}

.kit__ramp {
	list-style: none;
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(7rem, 100%), 1fr));
	gap: var(--space-2);
	margin: 0;
	padding: 0;
}

.kit__hue {
	display: grid;
	gap: var(--space-1);
}

.kit__hue-swatch {
	width: 100%;
	height: 2.5rem;
	border: 1px solid var(--rule);
	background: light-dark(
		oklch(0.55 var(--chroma-accent) var(--of)),
		oklch(0.76 var(--chroma-accent) var(--of))
	);
}

.kit__hue-label {
	font-size: var(--step-label);
	text-transform: uppercase;
	color: var(--ink-3);
}

.playground {
	position: relative;
	display: grid;
	align-content: center;
	gap: var(--space-2);
	min-height: 20rem;
	padding: var(--space-8) var(--space-4);
	border: 1px dashed var(--rule);
}

.playground__hint {
	max-width: var(--measure);
	margin: 0;
	color: var(--ink-2);
}

.playground__hint::before {
	content: "# ";
	color: var(--ink-3);
}

.playground__hint--quiet {
	font-size: var(--step-small);
	color: var(--ink-3);
}

@media (max-width: 40rem) {
	.playground {
		min-height: 14rem;
	}
}

/* ------------------------------------------------------- the introduction - */

.hero__lede {
	max-width: var(--measure);
	margin: var(--space-4) 0 0;
	color: var(--ink-2);
}

.offer,
.method {
	padding-block: var(--space-6);
}

/* Offers are boxes, because everything here is a box. */
.offer__list {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(16rem, 100%), 1fr));
	gap: var(--space-4);
}

.offer__item {
	padding: var(--space-4);
	border: 1px solid var(--rule);
}

.offer__name {
	margin: 0;
	font-size: var(--step-title);
	font-weight: 700;
	color: var(--accent);
}

.offer__name::before {
	content: "> ";
	color: var(--ink-3);
}

.offer__note {
	margin: var(--space-2) 0 0;
	color: var(--ink-2);
}

/* The steps read as a numbered log. The counter comes from the list itself,
 * so the numbering can never disagree with the order. */
.method__list {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: 0;
	border: 1px solid var(--rule);
}

.method__step {
	position: relative;
	padding: var(--space-3) var(--space-4) var(--space-3) 6ch;
	border-bottom: 1px solid var(--rule);
}

.method__step:last-child {
	border-bottom: 0;
}

.method__step::before {
	content: "[" counter(list-item) "]";
	position: absolute;
	left: var(--space-4);
	top: var(--space-3);
	color: var(--ink-3);
}

.method__name {
	margin: 0;
	font-size: var(--step-title);
	font-weight: 700;
	color: var(--accent);
}

.method__note {
	max-width: var(--measure);
	margin: var(--space-1) 0 0;
	color: var(--ink-2);
}

/* The period under a chronology entry: metadata, not substance, so it takes
 * the small size and the quietest ink. */
.method__when {
	margin: var(--space-1) 0 0;
	font-size: var(--step-small);
	color: var(--ink-3);
}

/* Only the kit places the two lists directly against each other; the front
 * page seats each in its own section. */
.offer__list + .method__list {
	margin-top: var(--space-6);
}

/* The chronology reuses the method list, without its counters: the numbering
 * that suits an ordered process would rank a career, and the most recent role
 * is not the last step towards anything. */
.method__list--plain .method__step {
	padding-left: 0;
}

.method__list--plain .method__step::before {
	content: none;
}

/* The materials, set close together so the eye reads one list rather than ten
 * separate claims. */
.method__tools {
	list-style: none;
	margin: var(--space-7, 3rem) 0 0;
	padding: var(--space-5, 1.5rem) 0 0;
	border-top: 1px solid color-mix(in oklab, currentColor 15%, transparent);
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-2);
}

.method__tool {
	font-family: var(--font-mono);
	font-size: 0.8125rem;
	line-height: 1;
	color: var(--ink-2);
	padding: 0.45em 0.75em;
	border: 1px solid color-mix(in oklab, currentColor 20%, transparent);
	border-radius: var(--radius-2, 0);
}

/* ---------------------------------------------------------- the inventory -
 *
 * The projects page as a directory listing, because that is what it is: a
 * band heading is a prompt, a repository is a row, and the metadata is the
 * columns after the name. Everything is already monospace here, so nothing
 * needs a second face to look like a listing.
 */
.works {
	padding-block: var(--space-8) var(--space-16);
}

.works__band {
	margin-top: var(--space-12);
}

.works__band:first-of-type {
	margin-top: 0;
}

.works__band-name {
	margin: 0;
	font-size: var(--step-title);
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: -0.02em;
}

.works__band-name::before {
	content: "> ";
	color: var(--accent);
}

.works__band-note {
	max-width: var(--measure);
	margin: var(--space-1) 0 0;
	font-size: var(--step-small);
	color: var(--ink-3);
}

/* The rule sits on the list rather than under the note, so it spans the rows
 * it introduces instead of stopping wherever the prose measure ends. */
.works__list {
	margin: var(--space-2) 0 0;
	border-top: 1px solid var(--rule);
	padding: 0;
	list-style: none;
}

/* Indented to the width of the marker below, so the name, the note and the
 * facts all line up on one column and the markers sit outside it. */
.work {
	position: relative;
	padding: var(--space-3) var(--space-2) var(--space-3) 4ch;
	border-bottom: 1px solid var(--rule);
	transition: background var(--transition);
}

.work::before {
	content: "──";
	position: absolute;
	left: 0;
	top: var(--space-3);
	color: var(--rule);
}

.work:last-child {
	border-bottom: 0;
}

.work:hover {
	background: var(--surface);
}

.work__top {
	display: flex;
	min-width: 0;
	align-items: baseline;
	flex-wrap: wrap;
	gap: var(--space-3);
	margin: 0;
}

.work__link {
	text-decoration: none;
	color: inherit;
}

/* A repository name is one unbreakable token in mono at title size, and
 * UnityDotsAuthoringGenerator is 363px of it, so at 390px the row pushed the
 * whole document sideways. overflow-wrap rather than word-break: break-all,
 * which ignores the break opportunities a word already has - see pit-0004.
 * min-width on the flex parent because a flex item will not shrink below its
 * content without it, whatever the child allows. */
.work__name {
	overflow-wrap: anywhere;
	font-size: var(--step-title);
	font-weight: 700;
	transition: color var(--transition);
}

.work__link:hover .work__name,
.work__link:focus-visible .work__name {
	color: var(--accent);
}

.work__note {
	max-width: var(--measure);
	margin: var(--space-1) 0 0;
	font-size: var(--step-small);
	color: var(--ink-2);
}

.work__meta {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-3);
	margin: var(--space-1) 0 0;
	font-size: var(--step-small);
	color: var(--ink-3);
}

/* The separator trails the fact it belongs to rather than leading the next
 * one. On a line that wraps, a leading separator lands at the start of the new
 * line with nothing before it - a dot hanging in the margin. */
.work__meta span:not(:last-child)::after {
	content: " ·";
}


/* ------------------------------------------------------- the project page -
 *
 * Two columns: the argument on the left, the evidence on the right.
 *
 * The rail is a fixed reading width rather than a fraction, because everything
 * in it - a date, a hash, a language name - is short and of known length, and
 * a proportional rail would set that content in a different measure on every
 * screen. The prose column takes what is left.
 *
 * Below the breakpoint the two stack, prose first, which is the source order:
 * nothing here is positioned against the flow, so a narrow screen and a screen
 * reader get the same document.
 */
.project {
	padding-block: var(--space-8) var(--space-16);
}

.project__back {
	margin: 0 0 var(--space-6);
	font-size: var(--step-small);
}

.project__layout {
	display: grid;
	gap: var(--space-12);
	align-items: start;
}

@media (min-width: 62rem) {
	.project__layout {
		grid-template-columns: minmax(0, 1fr) 20rem;
	}

	/* The rail is NOT sticky, and that is a correction rather than an omission.
	 *
	 * It used to be, on the argument that the facts are what the prose is being
	 * read against. That argument was sound while the rail fit on a screen. It
	 * stopped being sound when the written pages added a plate and an at-a-glance
	 * block: the rail is now around 1755px against a 900px viewport, and a sticky
	 * element taller than the viewport pins at its offset and then cannot move
	 * until its bottom edge finally clears - so the commits at the foot of it were
	 * unreachable until the reader had scrolled to the end of a 9880px page.
	 *
	 * One column that scrolls and one that refuses to reads as two scroll
	 * behaviours on one page, which is worse than losing the sticky facts. The
	 * alternative that keeps them - a capped height with its own overflow - buys
	 * the facts back by introducing a second scrollbar, which is the same fault
	 * stated honestly instead of by accident.
	 */
}

.project__main {
	min-width: 0;
}

.project__head {
	max-width: var(--measure);
}

.project__marks {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-3);
	margin: var(--space-4) 0 0;
}

.project__quiet {
	max-width: var(--measure);
	margin: var(--space-8) 0 0;
	color: var(--ink-3);
}

/* --------------------------------------------------------------- the rail - */

.project__rail {
	min-width: 0;
	display: grid;
	gap: var(--space-8);
}

.project__block {
	min-width: 0;
}

.project__heading {
	margin: 0 0 var(--space-3);
	font-size: var(--step-label);
	letter-spacing: var(--tracking-label, 0.08em);
	text-transform: uppercase;
	color: var(--ink-3);
}

/* Two columns of facts in the rail: six labelled values in one column is a
 * tall stack of mostly white space, and the values are short enough to pair. */
.project__facts {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: var(--space-4);
}

.project__fact {
	min-width: 0;
}

.project__fact-label {
	margin: 0 0 var(--space-1);
	font-size: var(--step-label);
	letter-spacing: var(--tracking-label, 0.08em);
	text-transform: uppercase;
	color: var(--ink-3);
}

.project__fact-value {
	margin: 0;
	font-family: var(--font-mono);
	font-size: var(--step-small);
	color: var(--ink-2);
	overflow-wrap: anywhere;
}

/* -------------------------------------------------------------- the plate - */

/* A fixed frame whichever of the two forms fills it, so the rail starts at the
 * same height on every project and a page with a picture is not a different
 * layout from a page without one. */
.plate {
	margin: 0;
	overflow: hidden;
	border-radius: 0;
	border: 1px solid var(--rule);
}

.plate__shot,
.plate__mix,
.plate__empty {
	display: block;
	width: 100%;
	aspect-ratio: 16 / 10;
}

.plate__shot {
	object-fit: cover;
}

/* The composition, drawn: one band per language, its height its share. The
 * same numbers the legend states, given the room to be read at a glance. */
.plate__mix {
	display: flex;
	flex-direction: column;
}

.plate__band {
	flex-basis: 0;
	min-height: 2px;
}

.plate__caption {
	padding: var(--space-2) var(--space-3);
	font-family: var(--font-mono);
	font-size: var(--step-label);
	color: var(--ink-3);
}

/* --------------------------------------------------------- the written page - */

/* A dossier is the tier above the snapshot: prose somebody wrote about this
 * project, and the drawings that prose is describing. The readme below it was
 * written for a reader who has already decided to clone the repository; this is
 * written for one deciding whether the project is worth understanding at all.
 *
 * Prose is held to the measure like every other run of prose on the site. The
 * figures are the exception, on the same rule the readme's tables and code
 * blocks are: a diagram squeezed into a reading column to keep the paragraphs
 * comfortable is a diagram nobody can read.
 */
.dossier {
	margin: var(--space-8) 0 0;
}

.dossier__standfirst {
	max-width: var(--measure);
	margin: 0;
	color: var(--ink-2);
	text-wrap: pretty;
}

.dossier__chapter {
	margin-block-start: var(--space-12);
}

.dossier__title {
	max-width: var(--measure);
	margin: 0 0 var(--space-4);
	font-size: var(--step-title);
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: -0.02em;
}

.dossier__para {
	max-width: var(--measure);
	margin: 0 0 var(--space-4);
	text-wrap: pretty;
}

.dossier__points {
	max-width: var(--measure);
	margin: 0 0 var(--space-4);
	padding-inline-start: var(--space-6);
	display: grid;
	gap: var(--space-2);
}

.dossier__point {
	color: var(--ink-2);
}

/* The figure carries the plate's frame, so a drawing in the flow and a drawing
 * in the rail read as the same kind of object rather than two conventions on
 * one page. */
.dossier__figure {
	max-width: var(--measure);
	margin: var(--space-6) 0 0;
	overflow: hidden;
	border: 1px solid var(--rule);
	border-radius: 0;
}

/* Wide figures break the measure, because that is the width they were drawn
 * at. Nothing else on the page does. */
.dossier__figure--wide {
	max-width: 100%;
}

.dossier__open {
	display: block;
}

.dossier__image {
	display: block;
	width: 100%;
	height: auto;
}

.dossier__caption {
	padding: var(--space-2) var(--space-3);
	font-family: var(--font-mono);
	font-size: var(--step-label);
	color: var(--ink-3);
}

/* The seam between the page that was written here and the readme that was
 * found in the repository. Stated rather than blurred: the two are addressed to
 * different readers, and running one into the other reads as the written page
 * continuing in somebody else's voice. */
.project__seam {
	max-width: var(--measure);
	margin: var(--space-16) 0 var(--space-6);
	padding-block-start: var(--space-6);
	border-block-start: 1px solid var(--rule);
	font-size: var(--step-label);
	letter-spacing: var(--tracking-label, 0.08em);
	text-transform: uppercase;
	color: var(--ink-3);
}


/* ------------------------------------------------------------- the legend - */

.mix__legend {
	display: grid;
	gap: var(--space-2);
	margin: 0;
	padding: 0;
	list-style: none;
	font-size: var(--step-small);
}

.mix__entry {
	display: grid;
	grid-template-columns: 0.65rem 1fr auto;
	align-items: center;
	gap: var(--space-3);
}

.mix__key {
	width: 0.65rem;
	height: 0.65rem;
	border-radius: 2px;
}

.mix__name {
	min-width: 0;
	overflow-wrap: anywhere;
}

.mix__share {
	font-family: var(--font-mono);
	color: var(--ink-3);
}

/* ---------------------------------------------------------------- the log - */

/* In the rail the log is date over subject rather than three columns: a
 * twenty-rem column cannot hold a date, a hash and a sentence side by side,
 * and the hash is the one of the three nobody reads here. */
.log {
	display: grid;
	gap: var(--space-3);
	margin: 0;
	padding: 0;
	list-style: none;
	font-size: var(--step-small);
}

.log__line {
	display: grid;
	gap: var(--space-1);
	min-width: 0;
}

.log__date {
	font-family: var(--font-mono);
	font-size: var(--step-label);
	color: var(--ink-3);
}

.log__subject {
	min-width: 0;
	color: var(--ink-2);
	overflow-wrap: anywhere;
}

.project__snapshot {
	margin: 0;
	font-size: var(--step-label);
	color: var(--ink-3);
}

/* -------------------------------------------------------------- the readme - */

/* The prose is held to the measure, but the things that are not prose are not.
 * A readme's tables and code blocks are the parts that were written wide, and
 * squeezing them into a reading column to keep one rule tidy makes them
 * unreadable to keep the paragraphs comfortable. */
.project__readme {
	margin-top: var(--space-8);
}

.project__readme > * {
	max-width: var(--measure);
}

.project__readme > table,
.project__readme > pre {
	max-width: 100%;
}

.project__readme img {
	max-width: 100%;
	height: auto;
}

.project__readme pre {
	overflow-x: auto;
}

.project__readme table {
	display: block;
	overflow-x: auto;
	border-collapse: collapse;
	font-size: var(--step-small);
}

.project__readme th,
.project__readme td {
	padding: var(--space-2) var(--space-4) var(--space-2) 0;
	border-bottom: 1px solid var(--rule);
	text-align: left;
	vertical-align: top;
}

.project__readme th {
	color: var(--ink-3);
	font-weight: 600;
	white-space: nowrap;
}

.project__readme tr:last-child td {
	border-bottom: 0;
}

.project__origin {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-6);
	margin-top: var(--space-8);
	padding-top: var(--space-6);
	border-top: 1px solid var(--rule);
	font-size: var(--step-small);
}

/* The mix's colours come off the palette's own hue roles, so a language bar is
 * never a second colour scheme arguing with the page. Everything past the
 * fifth shares one neutral: a legend with nine distinguishable colours is a
 * legend nobody can read. */
.plate,
.mix__legend {
	--mix-one: light-dark(oklch(0.62 var(--chroma-accent) var(--hue-seed)), oklch(0.74 var(--chroma-accent) var(--hue-seed)));
	--mix-two: light-dark(oklch(0.70 var(--chroma-accent) var(--hue-match)), oklch(0.80 var(--chroma-accent) var(--hue-match)));
	--mix-three: light-dark(oklch(0.62 var(--chroma-full) var(--hue-counter)), oklch(0.74 var(--chroma-full) var(--hue-counter)));
	--mix-four: light-dark(oklch(0.70 var(--chroma-full) var(--hue-warm)), oklch(0.80 var(--chroma-full) var(--hue-warm)));
	--mix-five: light-dark(oklch(0.62 var(--chroma-quiet) var(--hue-cool)), oklch(0.74 var(--chroma-quiet) var(--hue-cool)));
	--mix-rest: light-dark(oklch(0.72 0 0), oklch(0.45 0 0));
}

.mix__part--one, .mix__key--one { background: var(--mix-one); }
.mix__part--two, .mix__key--two { background: var(--mix-two); }
.mix__part--three, .mix__key--three { background: var(--mix-three); }
.mix__part--four, .mix__key--four { background: var(--mix-four); }
.mix__part--five, .mix__key--five { background: var(--mix-five); }
.mix__part--rest, .mix__key--rest { background: var(--mix-rest); }

.plate__empty {
	background: var(--rule);
}

/* A repository name is one long unbreakable word often enough that the title
 * cannot share a line with anything. Left alone, the terminal theme's prompt
 * marker is pushed onto a line of its own above the name, which reads as a
 * stray character rather than as a prompt.
 *
 * anywhere rather than break-word, and that distinction is the whole fix:
 * break-word only breaks a word that will not fit on a line *of its own*, so
 * the name still moves down as a unit first and the marker is still left
 * behind. anywhere is counted in the intrinsic minimum width, so the name
 * shrinks to share the line it starts on.
 *
 * And anywhere rather than break-all, which was the first fix and was worse
 * than the fault: break-all ignores the break opportunities a word already
 * has, so a hyphenated name split as ROSENBOHM-DE / V - a title broken one
 * character past the obvious place, which reads as a rendering fault rather
 * than as a wrap. anywhere takes the hyphen first and only cuts a word open
 * when there is nowhere else to cut. */
.project__head .page__title {
	overflow-wrap: anywhere;
}

.plate__open {
	display: block;
	line-height: 0;
}

/* ------------------------------------------------------------- the writing - */

/* The blog is the one part of this site addressed to a stranger, so it is the
 * one part with no chrome competing with the words: one column, held to the
 * measure, nothing beside it.
 *
 * The index is a stack rather than a grid of cards. A card forces every post
 * into the same rectangle and then truncates the one sentence that has to do
 * the work of selling it; a stack lets that sentence be read whole, which is
 * the only thing a reader is deciding on.
 */
.writing {
	padding-block: var(--space-12) var(--space-24);
}

.writing__list {
	list-style: none;
	margin: var(--space-12) 0 0;
	padding: 0;
	display: grid;
	gap: var(--space-12);
}

.writing__item {
	max-width: var(--measure);
	padding-block-start: var(--space-8);
	border-block-start: 1px solid var(--rule);
}

.writing__item:first-child {
	padding-block-start: 0;
	border-block-start: 0;
}

.writing__kicker,
.post__kicker {
	margin: 0 0 var(--space-2);
	font-family: var(--font-mono);
	font-size: var(--step-label);
	letter-spacing: var(--tracking-label, 0.08em);
	text-transform: uppercase;
	color: var(--ink-3);
}

.writing__name {
	margin: 0 0 var(--space-3);
	font-size: var(--step-title);
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: -0.02em;
}

.writing__stand {
	margin: 0 0 var(--space-4);
	color: var(--ink-2);
	text-wrap: pretty;
}

.writing__meta,
.post__meta {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-4);
	margin: 0;
	font-family: var(--font-mono);
	font-size: var(--step-label);
	color: var(--ink-3);
}

.writing__quiet {
	max-width: var(--measure);
	margin: var(--space-8) 0 0;
	color: var(--ink-3);
}

/* ---------------------------------------------------------------- one post - */

.post {
	padding-block: var(--space-12) var(--space-24);
}

.post__back {
	max-width: var(--measure-post);
	margin: 0 auto var(--space-8);
	font-size: var(--step-small);
}

.post__head {
	max-width: var(--measure-post);
	margin-inline: auto;
}

.post__head .page__lede {
	margin-block: var(--space-4);
}

/* The hero breaks the measure because it is a picture and pictures are not
 * prose. Everything below it is held to the column. */
.post__hero {
	margin: var(--space-12) 0 0;
	overflow: hidden;
	border: 1px solid var(--rule);
	border-radius: 0;
}

.post__hero img {
	display: block;
	width: 100%;
	height: auto;
}

/* A post is a wide container holding a narrow text column, not one narrow
 * column holding everything. Prose keeps a measure it can be read at; the
 * things that were drawn or written wide - a figure, a code block, a table -
 * get the whole frame, which is what the hero has always had.
 *
 * Before this the body was held to --measure, so a nine-figure post drew every
 * diagram at 38rem inside a 72rem frame: the page was mostly empty and the
 * figures were smaller on the site than in the files they came from. */
.post__body {
	max-width: 100%;
	margin-block-start: var(--space-12);
}

.post__body > * {
	max-width: var(--measure-post);
	margin-inline: auto;
}

/* goldmark gives an image its own paragraph, so that paragraph is the figure
 * and is exempt from the measure. A paragraph holding an image plus words is
 * prose and stays in the column. */
.post__body > p:has(> img:only-child) {
	max-width: 100%;
}

/* A long read needs its sections to be findable at a glance, so headings get
 * more space above them than the paragraphs they follow, and the deepest level
 * stops looking like a heading and starts looking like a label. */
.post__body h2 {
	margin-block-start: var(--space-12);
	font-size: var(--step-title);
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: -0.02em;
}

.post__body h3 {
	margin-block-start: var(--space-8);
	font-size: var(--step-body);
	font-weight: 700;
}

.post__body p,
.post__body ul,
.post__body ol,
.post__body blockquote {
	line-height: 1.65;
}

.post__body ol {
	padding-left: var(--space-6);
}

.post__body li + li {
	margin-top: var(--space-2);
}

/* A pull quote is the one place a post speaks in a voice that is not its own,
 * or repeats itself on purpose. Set apart rather than decorated. */
/* margin-inline is auto rather than 0 because the body centres its children
 * on the text column; 0 would remove the browser default and then park the
 * quote at the frame edge, a 224px jog out of the stripe. */
.post__body blockquote {
	margin-inline: auto;
	padding-inline-start: var(--space-6);
	border-inline-start: 2px solid var(--rule);
	color: var(--ink-3);
}

/* Code and tables were written wide and are not prose, so they are exempt from
 * the measure for the same reason a readme's are. */
.post__body > pre,
.post__body > table,
.post__body > .table-wrap {
	max-width: 100%;
	overflow-x: auto;
}

.post__body pre {
	padding: var(--space-4);
	font-size: var(--step-small);
	border: 1px solid var(--rule);
	border-radius: 0;
}

.post__body img {
	max-width: 100%;
	height: auto;
}

.post__body table {
	border-collapse: collapse;
	font-size: var(--step-small);
}

.post__body th,
.post__body td {
	padding: var(--space-2) var(--space-3);
	text-align: left;
	border-block-end: 1px solid var(--rule);
}

.post__body th {
	font-family: var(--font-mono);
	font-size: var(--step-label);
	letter-spacing: var(--tracking-label, 0.08em);
	text-transform: uppercase;
	color: var(--ink-3);
}

.post__foot {
	max-width: var(--measure-post);
	margin-inline: auto;
	margin-block-start: var(--space-16);
	padding-block-start: var(--space-6);
	border-block-start: 1px solid var(--rule);
	font-size: var(--step-small);
	color: var(--ink-3);
}

/* A featured row is a repository row that has something to read behind it, so
 * it carries a standfirst instead of a one-line description and sits at the
 * head of the inventory. The accent marks it without a second layout: the same
 * row, weighted. */
.work--featured {
	padding-inline-start: var(--space-4);
	border-inline-start: 2px solid var(--accent);
}

.work--featured .work__note {
	color: var(--ink-2);
	text-wrap: pretty;
}
