/* Nobedan — the spec-sheet grammar.
 *
 * The whole language is three moves:
 *   1. a page grid with generous margins and a full-bleed escape hatch,
 *   2. label column left / content column right, sections divided by rules,
 *   3. rule weight as the only hierarchy marker — no boxes, cards or shadows.
 *
 * A proposal section, a price page and a colophon are all the same grammar
 * (DESIGN.md). Mobile-first: everything below stacks into one column and the
 * two-column spec form switches on at 48em.
 */

/* ── Page grid ────────────────────────────────────────────────────────────
 * Named lines rather than 100vw tricks: `grid-column: full` bleeds edge to
 * edge without ever overshooting by the width of a scrollbar.
 */

.page {
	display: grid;
	grid-template-columns:
		[full-start] minmax(var(--page-margin), 1fr)
		[sheet-start] minmax(0, var(--sheet-max))
		[sheet-end] minmax(var(--page-margin), 1fr)
		[full-end];
}

.page > * {
	grid-column: sheet;
}

.page > .bleed {
	grid-column: full;
}

/* Content inside a bleed re-aligns to the sheet column: same max width plus
 * the page margins it pays back as padding. */
.bleed-inner {
	max-width: calc(var(--sheet-max) + 2 * var(--page-margin));
	margin-inline: auto;
	padding-inline: var(--page-margin);
	padding-block: var(--space-2xl);
}

/* A colour block re-derives the roles it changes, so labels and notes inside
 * it stay legible against the new ground instead of fading toward a paper
 * that is no longer there. The rules do not fade at all: on any ground, a
 * rule is that ground's text colour, and width alone carries its rank. */
.bleed--accent {
	--ink-muted: color-mix(in oklab, var(--ink-base) 74%, var(--accent));
	--ink-faint: color-mix(in oklab, var(--ink-base) 54%, var(--accent));
	--rule-color: var(--ink-base);
	--rule-color-quiet: var(--ink-base);
	background: var(--accent-ground);
	color: var(--ink-base);
}

.bleed--ink {
	--ink: var(--paper-base);
	--paper: var(--ink-base);
	--ink-muted: color-mix(in oklab, var(--paper-base) 62%, var(--ink-base));
	--ink-faint: color-mix(in oklab, var(--paper-base) 44%, var(--ink-base));
	--rule-color: var(--paper-base);
	--rule-color-quiet: var(--paper-base);
	--rule-color-strong: var(--paper-base);
	background: var(--ink-base);
	color: var(--paper-base);
}

.bleed--flush > .bleed-inner {
	padding-block: 0;
}

/* A full-bleed photograph used as a section's ground: taller than a figure,
 * capped so it cannot eat a whole screen, and it carries no rule of its own
 * — a photograph is the interruption between ruled sections, not one. */
.bleed--photo > .figure-ground {
	aspect-ratio: 21 / 9;
	min-height: 18rem;
	max-height: 68vh;
}

/* ── Masthead ─────────────────────────────────────────────────────────────
 * The Syverson Industries invoice: wordmark left, a small stack of
 * label/value meta right, one heavy rule beneath. Nobedan alone — Syverson
 * Industries appears once per artifact, in the colophon.
 */

/* The one rule in the language that sits below what it names, and it is a
 * design element rather than a heading rule: the invoice's heavy rule is the
 * top edge of the sheet, not an underline of the wordmark. It keeps more air
 * above it than below it so it still reads as belonging to what follows. */
.masthead {
	padding-top: var(--space-xl);
	padding-bottom: var(--space-l);
	border-bottom: var(--rule-heavy-width) solid var(--rule-color-strong);
	display: grid;
	gap: var(--space-m);
	align-items: end;
}

.masthead-mark {
	min-width: 0;
}

.masthead-name {
	font-size: var(--text-masthead);
	font-weight: var(--weight-medium);
	letter-spacing: var(--track-display);
	line-height: 0.9;
	margin: 0;
}

.masthead-name .thin {
	font-weight: var(--weight-thin);
}

.masthead-eyebrow {
	display: block;
	margin-bottom: var(--space-xs);
	font-size: var(--text-caption);
	font-weight: var(--weight-bold);
	letter-spacing: var(--track-label);
	text-transform: uppercase;
	color: var(--ink-muted);
}

.masthead-meta {
	display: grid;
	grid-template-columns: max-content max-content;
	column-gap: var(--space-m);
	row-gap: var(--space-3xs);
	align-content: end;
	font-size: var(--text-caption);
	line-height: var(--leading-tight);
}

.masthead-meta dt {
	font-size: var(--text-caption);
	font-weight: var(--weight-bold);
	letter-spacing: var(--track-label);
	text-transform: uppercase;
	color: var(--ink-muted);
	padding-top: 0.15em;
}

.masthead-meta dd {
	font-variant-numeric: tabular-nums;
}

@media (min-width: 48em) {
	.masthead {
		grid-template-columns: 1fr max-content;
	}

	.masthead-meta {
		justify-items: end;
		text-align: right;
	}

	.masthead-meta dt {
		text-align: right;
	}
}

/* ── Masthead, as the accent block ────────────────────────────────────────
 * Header option (b), chosen 2026-08-24. A rule immediately followed by a
 * colour block draws a line the block was already drawing, so instead of
 * putting the hue below the masthead we put the masthead *in* it: Nobedan
 * sets on the accent, the title moment moves onto the shoot photograph
 * (`.bleed--title-on-photo`), and the heavy rule goes away along with the
 * seam it was making.
 *
 * That leaves the artifact with no 5px rule at all, which is correct rather
 * than a loss: the heavy rule's job was to be the top edge of the sheet, and
 * a full-bleed colour block is a harder edge than any rule.
 *
 * `masthead--accent` goes on the existing <header class="masthead">; no
 * other markup changes. It is already a direct child of `.page`, which is
 * what the bleed needs.
 */

.masthead--accent {
	grid-column: full;
	border-bottom: none;
	/* Full-bleed ground, content still on the sheet measure — the padding
	 * takes up whatever is left once the sheet has its width, so no inner
	 * wrapper is needed. */
	padding-inline: max(
		var(--page-margin),
		calc((100% - var(--sheet-max)) / 2)
	);
	padding-block: var(--space-xl) var(--space-l);
	background: var(--accent-ground);
	color: var(--ink-base);
	--ink-muted: color-mix(in oklab, var(--ink-base) 74%, var(--accent));
	--ink-faint: color-mix(in oklab, var(--ink-base) 54%, var(--accent));
	--rule-color: var(--ink-base);
	--rule-color-quiet: var(--ink-base);
	--rule-color-strong: var(--ink-base);
}

/* ── The spec sheet: label column + content column ───────────────────── */

.sheet {
	display: block;
}

/* A row's rule is the row's own heading rule: it is drawn on the grid
 * container, so it crosses the gutter between the label column and the
 * content column in one unbroken line — from the label's left edge to the
 * end of the row — and it sits close under the heading it introduces
 * (--row-lead) and far below the copy it left behind (--row-trail). */
.row {
	display: grid;
	gap: var(--space-xs) var(--gutter);
	padding-top: var(--row-lead);
	padding-bottom: var(--row-trail);
	border-top: var(--rule-hairline-width) solid var(--rule-color);
	align-items: start;
	min-width: 0;
}

/* Grid and flex items default to min-width:auto, which lets one wide table
 * push the whole page sideways. The page body never scrolls horizontally;
 * wide content scrolls inside its own .scroll-x box. */
.row-body,
.row-label,
.bleed-inner {
	min-width: 0;
}

/* The first row after the masthead's heavy rule does not repeat a rule. */
.masthead + .sheet > .row:first-child,
.row--flush {
	border-top: none;
}

/* Rule weight is rank. A numbered section opens on the medium rule; every
 * subordinate row inside it takes the hairline. Colour is the same ink in
 * both cases — the page's structural rules are never sub-pixel, because a
 * sub-pixel rule antialiases on a 1x display and reads as the grey this
 * language does not use. The fine weight exists for one job only: the
 * deepest indent of a nested ledger, where a lighter rule IS the meaning. */
.row:has(> h2.row-label),
.row--strong {
	border-top-width: var(--rule-medium-width);
}

/* A subordinate row inside a section. It takes the hairline — the same rule
 * an unmodified `.row` gets — and the declaration is written out so the class
 * in the markup names something rather than looking like a leftover. */
.row--quiet {
	border-top-width: var(--rule-hairline-width);
}

.row-label {
	font-size: var(--text-caption);
	font-weight: var(--weight-bold);
	letter-spacing: var(--track-label);
	line-height: var(--leading-tight);
	text-transform: uppercase;
	margin: 0;
	/* Optical baseline match with the first line of body copy. */
	padding-top: 0.4em;
}

/* A subhead is the same size as a section head — there is no fourth type
 * size to spend on rank — so it steps down a weight instead, and does
 * without the number. */
h3.row-label {
	font-weight: var(--weight-medium);
}

.row-label a {
	text-decoration: none;
}

.row-label .row-number {
	display: block;
	font-weight: var(--weight-regular);
	color: var(--ink-faint);
}

/* The section number is where a numbered section head outranks a subhead:
 * heading size, Light, full ink, standing above its own name. It is the
 * document's only heading-size numeral outside a card. */
h2.row-label {
	padding-top: 0;
}

h2.row-label .row-number {
	margin-bottom: var(--space-2xs);
	font-size: var(--text-heading);
	font-weight: var(--weight-light);
	letter-spacing: var(--track-head);
	line-height: 1;
	text-transform: none;
	color: var(--ink);
	font-variant-numeric: tabular-nums lining-nums;
}

/* The label column doubles as the section index: on a tall row the label
 * rides down with the reader instead of scrolling away. */
.row-label--sticky {
	position: sticky;
	top: var(--space-m);
}

.row-body > * + * {
	margin-top: var(--space-s);
}

/* The stack's uniform gap would centre a rule between the two things it
 * separates, and would let a heading start without any more air than a new
 * paragraph. Both are law two: the space belongs ABOVE the heading and above
 * the rule that introduces it, and almost none belongs between them. These
 * out-specify the stack rule above; do not reorder them. */
.row-body > * + h3,
.row-body > * + h4,
.row-body > * + hr {
	margin-top: var(--space-xl);
}

.row-body > hr {
	margin-bottom: 0;
}

.row-body > hr + *,
.row-body > h3 + *,
.row-body > h4 + * {
	margin-top: var(--space-xs);
}

@media (min-width: 48em) {
	.row {
		grid-template-columns: var(--label-col) minmax(0, 1fr);
	}

	/* A row that wants the full measure — a display moment, a table —
	 * keeps the label in place and lets the body span both columns. */
	.row--wide {
		grid-template-columns: var(--label-col) minmax(0, 1fr);
	}

	.row--wide .row-body {
		max-width: none;
	}

	/* No label: the content column stays in its column so the left edge of
	 * the sheet never moves. */
	.row--unlabelled {
		grid-template-columns: var(--label-col) minmax(0, 1fr);
	}

	.row--unlabelled .row-body {
		grid-column: 2;
	}
}

/* ── Label/value lists — the same grammar, one size down ─────────────── */

.spec-list {
	display: grid;
	grid-template-columns: max-content minmax(0, 1fr);
	column-gap: var(--space-m);
	row-gap: var(--space-2xs);
	max-width: var(--measure);
	margin: 0;
}

.spec-list dt {
	font-size: var(--text-caption);
	font-weight: var(--weight-bold);
	letter-spacing: var(--track-label);
	text-transform: uppercase;
	color: var(--ink-muted);
	padding-top: 0.3em;
	line-height: var(--leading-tight);
}

.spec-list dd {
	margin: 0;
}

/* The rule crosses the gutter. A grid column-gap would cut it in two —
 * a rule never breaks for a column gap — so the ruled variant closes the
 * gap to zero and re-opens it as padding inside the label cell, where the
 * border can run straight through it.
 *
 * Every pair gets a rule, the first included: the rule belongs to the pair
 * below it, so leaving the first one off would be leaving that pair without
 * its own heading rule. */
.spec-list--ruled {
	row-gap: 0;
	column-gap: 0;
}

.spec-list--ruled > dt,
.spec-list--ruled > dd {
	border-top: var(--rule-hairline-width) solid var(--rule-color);
	padding-block: var(--space-xs) var(--space-s);
}

.spec-list--ruled > dt {
	padding-right: var(--space-m);
	padding-top: calc(var(--space-xs) + 0.3em);
}
