/* ============================================================================
   PAGES

   Components specific to one page each: home, /for-agencies, /about,
   /process, /contact, /work and /field-notes.
   ============================================================================ */

@layer pages {

/* --- Home ------------------------------------------------------------------
   The home page is the one page on the site that is composed rather than
   assembled. Every other page inherits .section rhythm; this one deliberately
   breaks it — a poster, a justified statement, a full-bleed lead case, a ruled
   index, a hard split, a pull quote — so that nothing on it reads as one more
   band in a stack of bands.

   Red is rationed. It appears full-bleed exactly once (the hero), as ink
   exactly twice (the knockout line and the statement's last sentence), and
   otherwise only in interactive states. Section kickers are .label.indexLabel,
   the section mark: the red .eyebrow that used to do that job is deleted,
   because seven red kickers in a column drain the identity colour of any
   meaning by the third one.                                                 */

.homeHero {
	/* Surface, scheme and text tokens come from .onBrand in 02-tokens — the
	   hero is a brand field, so its buttons resolve to their on-dark recipes
	   without needing a variant of their own. */
	min-height: 100lvh;
	padding-block: calc(var(--nav-height) + var(--space-2xl)) var(--space-l);
	position: relative;
	display: flex;
	flex-direction: column;
	overflow: hidden;
}

/* Matches the body behind the hero to its brand-red field, so mobile
   overscroll (and any gap above it) doesn't flash the plain page surface.
   --color-surface-brand isn't a light-dark() token, so this needs no
   color-scheme override — see .onBrand in 02-tokens.css.

   The hero paints no background of its own — this is where its red actually
   comes from. navTheme knows that: .homeHero is in its BRAND list, and when a
   brand field turns out not to paint, it resolves --color-surface-brand off
   the element rather than walking past a field that is plainly red. */
body:has(.homeHero) { background: var(--color-surface-brand); }

/* Everything in the field is anchored to the bottom-left corner: the type
   object, the lede and actions under it, the colophon on the bottom edge. The
   empty red is therefore one continuous L above and to the right of the block
   rather than two separate gaps — which is the shape a graphic or a motion
   treatment can be dropped into later without recomposing the hero. */
.homePosterInner {
	position: relative;
	z-index: 2;
	flex: 1;
	display: flex;
	flex-direction: column;
	gap: var(--space-xl);

	.posterHead { margin-block-start: auto; }
	.posterColophon { margin-block-start: var(--space-xl); }
}

/* The poster head. One type object, sentence case, set solid, holding the
   bottom-left corner of the field. The measure is what reserves the space to
   its right: capped in ch, so the reserved column is a proportion of the type
   rather than a number that only works at one viewport.

   It used to be two hand-broken .posterLine spans, one of them knocked out as
   a white slab. Both are gone — a white bar across a red field, a second case
   treatment and a full-bleed break-out were three loud devices stacked on the
   one element that was already the loudest thing on the site. */
.posterHead {
	color: var(--color-text-1);
	max-width: 13ch;
}

/* Lede left, buttons right — the row that closes the type block. */
.posterSub {
	display: grid;
	grid-template-columns: minmax(0, 1fr) auto;
	align-items: end;
	gap: var(--space-l) var(--space-xl);

	.lede {
		margin: 0;
		max-width: 46ch;
		font-size: var(--step-2);
		color: var(--color-text-1);
	}
	.btnRow { margin: 0; }

	/* Collapses at 1024, not at 860 like the rest of the page. The buttons are
	   an `auto` track, so between those two widths they took what they needed
	   and the lede paid for it — a --step-2 paragraph squeezed into a column
	   narrower than its own words for the whole tablet range. Everything else
	   on the page collapses against its own content; this row collapses against
	   the track beside it, which is a different question and gets a different
	   answer. */
	@media only screen and (max-width: 1024px) {
		grid-template-columns: 1fr;
		align-items: start;
	}
}

/* The colophon. A ruled band locked to the bottom of the field: three labelled
   columns, each on its own baseline. The previous version was one justified
   run-on of 10px caps, which stretched its word spaces and left an unresolved
   rag — caps at label size should never be justified. */
.posterColophon {
	margin: 0;
	padding-block-start: var(--space-m);
	/* A structural rule, not a hairline: --space-2xs of ink in the same colour
	   as the type it bounds. On the brand field --color-text-1 resolves to
	   solid white through .onBrand; everywhere else it follows the page's
	   scheme, so no dark-mode override is needed. */
	border-top: var(--space-2xs) solid var(--color-text-1);
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-m) var(--space-l);
	color: var(--color-text-1);

	& div {
		flex-basis: 26ch;
		flex-shrink: 1;
	}

	& div:first-child {
		flex-grow: 1;
	}
	& div:nth-child(2) {
		flex-grow: 2;
	}
	& div:nth-child(3) {
		flex-grow: 3;
	}

}
}

/* --- Home section heads ------------------------------------------------------
   The .indexLabel device itself is shared furniture now — three pages set
   sections with it — so it lives in 07-shell.css. What is left here is how far
   the home page's own heads stand off it.                                   */

.homeSectionHead {
	margin-bottom: var(--space-2xl);

	.indexLabel { margin-bottom: var(--space-m); }
	.lede { max-width: 34ch; margin: 0; }
}

/* --- Work ------------------------------------------------------------------
   Artifact-led. A case block that reserves one 21:9 well for a photograph is
   a picture of a case study; a contact sheet of captioned artifacts is the
   case study. The wells are bare — no border, no radius — over the page's
   darkest surface, and each carries two plates: the client's name set large
   at the bottom, the artifact's name as a micro-cap at the top. Both sit
   *behind* the image, so a real photograph covers them the day it lands and
   nothing has to be unwound.

   Every case number hangs off the top-right of its own primary well, in brand
   red, at the same size. Consistent placement is what makes a numeral that
   escapes its frame read as composed rather than as drift.                  */

.homeWork {
	.caseLead {
		display: block;
		margin-block: 0 var(--space-3xl);
	}
	.caseMedia { position: relative; }

	/* The lead case's title, above its well. It was set *on* the well as an
	   overprint until a real image landed and the type stopped clearing
	   contrast over it; the fix for that was either art-directing every image
	   around a title or a scrim, and both make the picture serve the type.
	   Separate, the image can be anything. The heading still owns the lead —
	   it is the only .display in the section. */
	.caseLeadHead {
		padding-block-end: var(--space-l);

		& .labelSmall {
			display: block;
			color: var(--color-text-3);
			margin-bottom: var(--space-s);
		}
		& h3 { max-width: 16ch; }
	}

	/* Ratios are per-page editorial decisions, so they live with the page.
	   The plate itself is shared furniture — see .artifactPlate in 07-shell. */
	.ratioLead     { aspect-ratio: 21 / 9; }
	.ratioWide     { aspect-ratio: 3 / 2; }
	.ratioTall     { aspect-ratio: 4 / 5; }
	.ratioArtifact { aspect-ratio: 4 / 5; }

	/* Headline before evidence. The case's own title arrives first, then the
	   well, then this framing, then the contact sheet under that. Three images
	   of a project followed by the sentence explaining it is the wrong order,
	   however good the images are. */
	.caseLeadBody {
		display: grid;
		grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
		gap: var(--space-s) var(--space-2xl);
		align-items: start;
		padding-block-start: var(--space-m);

		& p {
			margin: 0;
			color: var(--color-text-2);
			max-width: 52ch;
		}
	}

	/* The contact sheet under the lead case. Three artifacts, one shared top
	   line, captions on one baseline. */
	/* 6 / 3 / 3, not three equal boxes — the primary artifact gets twice the
	   room and a landscape crop, the two supporting ones go portrait. */
	.artifactRow {
		display: grid;
		grid-template-columns: minmax(0, 6fr) minmax(0, 3fr) minmax(0, 3fr);
		gap: var(--space-m);
		margin-block-start: var(--space-l);
		/* Bottom-aligned, so the three captions land on one line even though
		   the wells are three different widths. Top-aligning them left the
		   captions at three different y positions, which reads unresolved. */
		align-items: end;

		& > :first-child .workCardMedia { aspect-ratio: 8 / 5; }

		@media only screen and (max-width: 767px) {
			grid-template-columns: 1fr;
		}
	}
	.artifact {
		margin: 0;

		& figcaption {
			display: block;
			margin-block-start: var(--space-xs);
			color: var(--color-text-3);
		}
	}


	/* subgrid keeps both cards' bodies on one baseline while the wells stay
	   different heights — the stagger is authored, not a byproduct of two
	   aspect ratios landing where they land. */
	/* Twelve columns, and the two supporting cases deliberately do not line
	   up: Scene+ takes 1–7 and Golf Pride takes 9–12, dropped a full band. An
	   asymmetric grid is the only reason to have a grid, and two cards forced
	   onto one baseline is the thing this page kept accidentally doing. */
	.caseRow {
		display: grid;
		grid-template-columns: repeat(12, minmax(0, 1fr));
		column-gap: var(--space-2xl);

		& > :first-child { grid-column: 1 / 8; }
		& > :last-child  { grid-column: 8 / -1; margin-block-start: var(--space-4xl); }

		@media only screen and (max-width: 767px) {
			grid-template-columns: 1fr;
			row-gap: var(--space-2xl);

			& > :first-child,
			& > :last-child { grid-column: 1; margin-block-start: 0; }
		}
	}
	.caseRow .workCardBody { padding-bottom: var(--space-m); }
	/* 02 and 03 carry the same ratio well, so the difference between them is
	   scale — 7 columns against 5 — rather than two aspect ratios landing
	   wherever they land and calling it a stagger. */
	.caseRow p { color: var(--color-text-2); margin: 0 0 var(--space-m); }
	.caseRow h3 { margin-bottom: var(--space-s); }

	.allWorkLink {
		margin-top: var(--space-2xl);
		padding-top: var(--space-m);
		/* Structural rule: full ink, the section-mark weight, and the only one
		   in this section. List separators elsewhere are a --color-rule
		   hairline. Two weights, two jobs. */
		border-top: var(--space-2xs) solid var(--color-text-1);
		width: 100%;
	}

	@media only screen and (max-width: 767px) {
		.caseLeadBody { grid-template-columns: 1fr; }
	}
}

/* --- The handoff tax --------------------------------------------------------
   A single-column numbered index at display scale, with the numerals hanging
   in the page margin. Every other band on this page is heading-left /
   copy-right; this one is a list, and it is allowed to look like one. That is
   the point — alternating a band's background colour is not rhythm, it is
   wallpaper, and structure is the only thing that actually breaks a page's
   shape.

   The rows are the shared ruled index (.capList / .capRow in 07-shell.css).
   This band was .capabilities, three rows of capability claims; it holds the
   five forms of the handoff tax now. Same job — mark, deck, index, closing
   note — so the rename is the whole change.

   TWO TIERS OF MICRO-CAP, held across the whole page: a section mark
   (.indexLabel — full ink, widest tracking) and a meta tag (.labelSmall —
   tertiary ink, one size down). Everything uppercase on this page is one or
   the other.                                                                */

.handoffIndex {
	padding-block: var(--space-2xl);

	.indexLabel { margin-bottom: var(--space-l); }

	/* The definition above the index and the through-line under it. Both carry
	   their own voice and measure from the markup (.lede, .body); the band only
	   says how far each one stands off the list, which is the same split
	   /process and /about make around this index. Direct children, so a .lede
	   inside a row can't pick these up. */
	& > .wrapWide > .lede { margin: 0 0 var(--space-xl); max-width: 46ch; }
	& > .wrapWide > .body { margin: var(--space-xl) 0 0; }

	/* The five forms are peers with no order to them, so this is the one use of
	   the ruled index that drops its numerals. Without a numeral in the margin
	   there is nothing to hang the rows off: an auto first column would size to
	   each row's own heading and start all five notes at a different place. So
	   the row is one column — the heading with its note under it, which is the
	   shape .capRow already takes below 767px — and the hairlines keep doing
	   the work the numerals were doing. */
	.capRow {
		grid-template-columns: minmax(0, 1fr);
		row-gap: var(--space-2xs);

		& p { grid-column: 1; }
	}
}

/* --- The two doors ----------------------------------------------------------
   .doorSplit / .doorHalf moved to 07-shell.css when /faq and /contact took the
   hard-split state too. Nothing in it was ever about this page.             */

/* --- The practice ---------------------------------------------------------- */

/* The page's one long exhale. Directly after the compressed door split and
   directly before the quote, so the scroll has a meter. */
/* No background of its own: .section already sits on --color-surface, and
   repainting it here only meant a second place to keep in sync. */
.studioBand {
	padding-block: calc(var(--space-4xl) * 1.25);
}
.studioLayout {
	display: grid;
	grid-template-columns: minmax(0, 7fr) minmax(0, 4fr);
	gap: var(--space-2xl);
	align-items: end;

	@media only screen and (max-width: 860px) { grid-template-columns: 1fr; }
}
.studioCopy {
	.indexLabel { margin-bottom: var(--space-l); }
	.prose { margin-top: var(--space-l); }
	.btnRow { margin-top: var(--space-l); }
}
/* The portrait itself is .portraitPlate in 07-shell — the same component, and
   the same view-transition name, as the one at the head of /about. It used to
   be a .mediaFrame here with the artifact plate's substrate copied onto its
   inner div; there is nothing page-specific left to say about it. */
/* --- The lab ----------------------------------------------------------------
   Self-initiated work, as a ruled index. Two more cards here would have made
   the fourth card grid on one page. */

/* Deliberately the tightest band on the page, directly after the airiest.
   That contrast is the meter — without it the scroll is a metronome. */
.labIndex {
	padding-block: var(--space-2xl);

	.indexLabel { margin-bottom: var(--space-l); }
}
.labList {
	list-style: none;
	margin: 0;
	padding: 0;

	/* Intrinsic columns. Every track here is interchangeable — same sizing
	   function, same content shape — which is exactly the case auto-fit is
	   for, so the row packs and collapses off its own available width and
	   there is no breakpoint to keep in sync with the minimum or the gap.
	   auto-fit rather than auto-fill deliberately: with two entries auto-fill
	   would hold a third, empty track open at wide widths and leave the two
	   real ones filling two thirds of the row. min() keeps the minimum from
	   overflowing a viewport narrower than itself. */
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 360px), 1fr));
	gap: var(--space-m) var(--space-2xl);

	& a {
		display: block;
		padding-block: var(--space-l) 0;
		color: var(--color-text-1);
		transition: color 0.25s ease;

		&:hover { color: var(--color-action-text); }
	}
	/* The entry's name. It is a <span> so the whole row can be one link, which
	   means it needs to be told to be a block before the type class's own
	   measure means anything. */
	& .displaySmall { display: block; }

	/* A name / description / status table is a settings screen, not an index.
	   Two blocks, each one a name with a note under it. */
	.labNote {
		display: block;
		margin-block-start: var(--space-s);
		color: var(--color-text-2);
		max-width: 38ch;
	}
	.labMeta {
		display: block;
		margin-block-start: var(--space-s);
		color: var(--color-text-3);
	}
}

/* --- /for-agencies ----------------------------------------------------------
   States, in order: the shared page head, the pledge as the page's one red
   field, the shared ruled index for what I plug into, the shared case index
   for proof, a compressed reference band, a ruled rate table, and one quiet
   operations band. The four bordered offer cards, the four-across icon row and
   the red tick list are all gone — an evenly weighted repeating unit is the
   most machine-legible thing you can put on a page.                         */

/* The non-solicitation statement, and the one full red field on the page. It
   removes the biggest objection in the partner channel, so it gets the field
   rather than a red-bordered box in the middle of a white band — .onBrand in
   02-tokens re-points the text, rule and control tokens, and .section.accent
   supplies the ground. Nothing here may declare a background: a background in
   @layer pages would beat the one .onBrand sets in @layer tokens. */
.pledgeBand {
	.pledgeGrid {
		display: grid;
		grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
		column-gap: var(--space-2xl);
		row-gap: var(--space-l);
		align-items: end;

		.indexLabel { grid-column: 1 / -1; margin-bottom: var(--space-l); }
		& h2 { margin: 0; }
		& p {
			margin: 0;
			max-width: 44ch;
			/* On red there is deliberately no opacity ramp — solid white is
			   4.99:1 and any transparency drops small text below 4.5. The
			   hierarchy here is size, not fading ink. */
			color: var(--color-text-1);
		}

		@media only screen and (max-width: 860px) {
			grid-template-columns: 1fr;
			align-items: start;
		}
	}
}

/* The four engagement shapes are the shared ruled index (.capList / .capRow),
   and proof is the shared case index (.caseIndex / .caseIndexRow) — both in
   07-shell. All that is left per page is how far the heads stand off them and
   which well ratio the rows carry. */
.agencyOffer,
.agencyProof,
.agencyRates,
.agencyOps {
	.indexLabel { margin-bottom: var(--space-l); }
}
/* The rate table's head is a stacked one, so the mark, the heading and the
   deck each need their own step off the next thing rather than one gap. */
.agencyRates {
	.sectionHead {
		margin-bottom: var(--space-xl);

		& h2 { margin: 0; }
		.lede { margin: var(--space-m) 0 0; max-width: 46ch; }
	}
	.todoNote { margin-top: var(--space-xl); }
}
.agencyOffer .lede { margin: 0 0 var(--space-xl); max-width: 46ch; }
.agencyProof {
	/* Head left, "all work" right — the one place on the page a section head
	   carries a link. */
	.sectionHeadRow { margin-bottom: var(--space-xl); }
	.sectionHeadRow .lede { margin: var(--space-m) 0 0; max-width: 46ch; }

	/* No lead row here. /work opens on one at twice the scale; this page is
	   three peers in role order, and promoting one of them would say something
	   about the client rather than about the arrangement. */
}

/* References. Compressed, and directly after the proof it belongs with — an
   agency trusts another agency's word above anything the page says itself. */
.agencyReferences {
	.indexLabel { margin-bottom: var(--space-l); }
	.lede { margin: 0 0 var(--space-xl); max-width: 46ch; }
}

/* The rate table is .engageGrid in 07-shell.css — it moved there when /process
   published its starting ranges with the same component. All that is left here
   is which page uses it.                                                    */

/* Tooling and vendor readiness sit in .opsSplit, which moved to 07-shell.css
   when /process published its money mechanics in the same two columns — the
   same move .capList, .engageGrid and .doorSplit all made on their second
   consumer. All that is left here is which page uses it. */

/* --- /about -----------------------------------------------------------------
   States, in order: a hard split for the head, the shared statement band, one
   full-measure plate with its copy above it, the shared ruled index for the
   beliefs, and a compressed fact band for the resume. Nothing on the page is
   heading-left / paragraph-right twice.                                     */

/* The head is a hard split. The page's one .display heading and its deck sit
   on the site measure in the seven columns; the portrait takes the five and
   runs off the right edge of the viewport rather than sitting inset in it.

   That is also the argument for the edge: the home page's practice band holds
   the same portrait in a small inset well, and both name it studio-portrait,
   so arriving here morphs a four-column plate into a page-head one. Two inset
   rectangles of the same size would have nothing to show. */
.studioHead {
	display: grid;
	grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
	column-gap: var(--space-2xl);
	align-items: end;

	/* It clears the fixed nav itself, the same way .pageHead does — nothing
	   else on a page knows the nav height. */
	padding-block: calc(var(--nav-height) + var(--space-2xl)) 0;
	/* The copy lands on the site measure even though the band is full-bleed:
	   the inset is whatever the .wrapWide margin is at this width. The right
	   column has no matching inset, which is what puts the plate on the edge. */
	padding-inline-start: max(5vw, calc((100vw - 1440px) / 2));

	.studioHeadCopy {
		display: flex;
		flex-direction: column;
		align-items: start;
		gap: var(--space-l);
		/* The copy stands off the bottom of the band; the plate runs to it. */
		padding-block-end: var(--space-2xl);
	}
	& h1 { margin: 0; }
	.lede { margin: 0; max-width: 42ch; }
	.btnRow { margin: 0; }

	@media only screen and (max-width: 860px) {
		grid-template-columns: 1fr;
		row-gap: var(--space-2xl);
		padding-inline: 5vw;

		.studioHeadCopy { padding-block-end: 0; }
	}
}

/* Why the breadth: the copy first, the evidence under it at the full measure.
   The only wide photograph on the page, and the band is compressed either
   side of it so the plate is the thing that opens up rather than the padding. */
.aboutProcess {
	.aboutProcessHead {
		display: grid;
		grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
		column-gap: var(--space-2xl);
		row-gap: var(--space-l);
		align-items: start;
		margin-bottom: var(--space-xl);

		.indexLabel { grid-column: 1 / -1; margin-bottom: var(--space-l); }
		& h2 { margin: 0; }
		/* The copy column is dropped a band rather than topped out with the
		   heading — the asymmetry is the point of having a grid, and bottoming
		   the two out together instead left a hole under the heading the height
		   of the paragraph beside it. */
		.prose { margin: var(--space-2xl) 0 0; }
	}

	/* A per-page editorial ratio, as the plate's own documentation asks for —
	   the component sets none of its own. */
	.ratioProcess { aspect-ratio: 3 / 2; }

	.aboutProcessFigure {
		margin: 0;

		& figcaption {
			display: block;
			margin-block-start: var(--space-s);
			color: var(--color-text-3);
		}
	}

	@media only screen and (max-width: 767px) {
		.aboutProcessHead {
			grid-template-columns: 1fr;

			.prose { margin-top: 0; }
		}
		.ratioProcess { aspect-ratio: 3 / 2; }
	}
}

/* The beliefs are the shared ruled index (.capList / .capRow in 07-shell), so
   there is nothing left to say here but how far the head stands off them.
   .beliefList — a 56px counter column with a headingSmaller beside it — is
   gone: five near-body-size headings in a row was the flattest hierarchy on
   the site, and the index does the same job at the scale the page can afford. */
.beliefIndex {
	.indexLabel { margin-bottom: var(--space-l); }
	.lede { margin: 0 0 var(--space-xl); max-width: 46ch; }
}

/* The resume. The band doing noticeably less: no display heading, no image,
   four columns of hairline rows under one mark. */
.aboutBackground {
	.indexLabel { margin-bottom: var(--space-l); }
	.prose { margin: 0 0 var(--space-2xl); }
}
.creds {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
	gap: var(--space-l) var(--space-l);

	/* The meta tier of the two-tier micro-cap system — the section mark above
	   is the other. The rows themselves are .factList in 07-shell. */
	& h3 {
		color: var(--color-text-3);
		margin: 0 0 var(--space-s);
	}
}

/* --- /process ----------------------------------------------------------------
   States, in order: the shared page head, the shared ruled index for the seven
   phases, the schedule ask as the page's one red field, the shared rate
   table for the ranges, and the accordion on the narrow measure. Open, open, compressed, compressed, open.

   .phaseList — a 190px meta column beside a .headingSmall — is gone: seven
   near-body-size headings down a page whose whole subject is those seven steps
   was the flattest hierarchy on the site. The four bordered .priceCard boxes
   went with it; the ranges are the ruled table in 07-shell, because an evenly
   weighted repeating unit takes no position on what is in it.              */

.phaseIndex {
	.indexLabel { margin-bottom: var(--space-l); }
	& > .wrapWide > .lede { margin: 0 0 var(--space-xl); max-width: 46ch; }

	/* Two things the shared ruled index doesn't carry, because only a phase
	   has them: when it happens, and what comes out of it. Both hang in the
	   row's copy column, the timing on the heading's own baseline step and the
	   deliverables under the note. */
	.capRow {
		.capWhen {
			grid-column: 2;
			display: block;
			margin-block-start: var(--space-2xs);
			color: var(--color-text-3);
		}
		.phaseDeliverables {
			grid-column: 2;
			margin-block-start: var(--space-l);
		}

		@media only screen and (max-width: 767px) {
			.capWhen, .phaseDeliverables { grid-column: 1; }
		}
	}
}

/* What makes a project late, as the one full red field on the page. It is the
   only place this page asks the client for something, and the single most
   useful thing it has to say, so it gets the field rather than a paragraph
   sitting beside a placeholder photograph. Nothing here may declare a
   background — a background in @layer pages would beat the one .onBrand sets
   in @layer tokens. */
.lateBand {
	.lateGrid {
		display: grid;
		grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
		column-gap: var(--space-2xl);
		row-gap: var(--space-l);
		align-items: end;

		.indexLabel { grid-column: 1 / -1; margin-bottom: var(--space-l); }
		& h2 { margin: 0; }
	}
	/* The two paragraphs are one grid item: as two they would auto-place into
	   two different columns and the second would land back under the heading. */
	.lateCopy {
		max-width: 46ch;

		& p {
			margin: 0;
			/* On red there is deliberately no opacity ramp — solid white is
			   4.99:1 and any transparency drops small text below 4.5. The
			   hierarchy here is size, not fading ink. */
			color: var(--color-text-1);
		}
		& p + p { margin-top: var(--space-m); }
	}

	@media only screen and (max-width: 860px) {
		.lateGrid {
			grid-template-columns: 1fr;
			align-items: start;
		}
	}
}

/* The ranges. Compressed and on the alternate surface: the band between the
   page's spine and its one red field should do less than either of them. */
.priceBand {
	/* The money mechanics, under the ranges they belong with, in the same
	   quiet register /for-agencies uses for vendor readiness. .opsSplit is in
	   07-shell.css. */
	.opsSplit { margin-top: var(--space-2xl); }
	.todoNote { margin-top: var(--space-xl); }
}

/* --- /build-test -------------------------------------------------------------
   States, in order: the shared page head, the shared ruled index for the seven
   questions, the statement for the two that matter most, the two-column fact
   band for how to run it, and the closing band. Open, open, compressed,
   compressed. Red is the statement's closing line and nothing else.

   The questions sit at card tier (.headingMedium) rather than .displaySmall,
   which is where /process sets its phases: a phase is two words and a question
   here runs to a hundred characters, and at --step-5 on the ruled index's 20ch
   measure the longest broke over five lines. The measure opens back up to the
   headings' own 34ch, and the numeral comes down a step so it still reads as
   the larger of the two.                                                     */

.buildTestIndex {
	--cap-num-size: var(--step-5);

	.capRow :is(h2, h3) { max-width: 34ch; }
}

/* --- /contact ----------------------------------------------------------------
   States, in order: the shared page head, the form as an asymmetric split with
   the practical facts hanging beside it, the shared ruled index for what
   happens after you send it, and the shared hard split for the two pages that
   answer most of a first email. The two bordered .door cards are gone with the
   grid they sat in — /contact was the last page carrying them.

   No closing CTA band: the page is the call to action, and asking again under
   the form would be the site talking to itself.                            */

.contactSplit {
	display: grid;
	/* The same 7/5 every other band on the site is built on. The form is the
	   page, so it takes the seven; the aside answers the questions that would
	   otherwise stop someone filling it in. */
	grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
	gap: var(--space-2xl);
	align-items: start;

	@media only screen and (max-width: 900px) {
		grid-template-columns: 1fr;
	}
}

.form {

	display: flex;
	flex-direction: column;
	gap: var(--space-l); /*match the gap with the gap of .formRow so when it flows to a single column all the fields are consistently spaced */

	.formRow {
		/* auto-fit, not a fixed repeat(2, …): both fields are meant to be
		   the same width, so the row can size itself off that one shared
		   minimum instead of a hand-picked breakpoint. It packs 2 columns
		   when 2×240px + gap fit, and collapses to 1 the instant they
		   don't — reacting to whatever width .form actually has, no
		   container query needed. */
		display: grid;
		grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
		gap: var(--space-l) var(--space-s);
	}
	.formField {
		display: flex;
		flex-direction: column;
		gap: var(--space-2xs);
	}
	& label {
		color: var(--color-text-2);
	}
	& input, & select, & textarea {
		font-family: var(--font);
		/* --step-1, and it has to stay at or above --step-1: iOS Safari zooms
		   the viewport when a focused control computes under 16px, and this
		   step's floor is exactly 1rem for that reason. See the type scale
		   note in 02-tokens.css before you step this down. */
		font-size: var(--step-1);
		color: var(--color-text-1);
		border: 1px solid var(--color-border-control);
		/* Squared, like the buttons: a rounded field against Gotham Bold and
		   hairline rules is the language the redesign took off the buttons. */
		border-radius: var(--radius-xs);
		padding: var(--space-xs);
		width: 100%;
		transition: border-color 0.2s ease, box-shadow 0.2s ease;
		-webkit-appearance: none;
		appearance: none;
		background-color: var(--color-surface-2);

		&::placeholder { 
			color: var(--color-text-3); 
		}
		&:focus {
			border-color: var(--color-focus);
			box-shadow: 0 0 0 3px var(--color-brand-wash);
		}
	}
	& select {
		background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath fill='%23878787' d='M1 1l5 5 5-5'/%3E%3C/svg%3E");
		background-repeat: no-repeat;
		background-position: right var(--space-m) center;
		background-size: 12px;
		padding-right: var(--space-2xl);
	}
	& textarea {
		min-height: 160px;
		resize: vertical;
	}

	.formConsent {
		display: flex;
		align-items: flex-start;
		gap: var(--space-s);
		font-size: var(--step-0);
		line-height: 1.55;
		color: var(--color-text-3);
		font-weight: 300;
		margin-bottom: var(--space-l);

		& input[type="checkbox"] {
			width: 18px;
			height: 18px;
			flex-shrink: 0;
			margin-top: 0.15em;
			accent-color: var(--color-action);
			-webkit-appearance: auto;
			appearance: auto;
		}
	}
}

/* The aside. Hairline rows under meta-tier heads — the same quiet register as
   /about's resume and /for-agencies' vendor readiness, so nothing beside the
   form competes with it for attention. */
.contactAside {
	.contactBlock {
		border-top: 1px solid var(--color-rule);
		padding: var(--space-l) 0;

		& h2 {
			color: var(--color-text-3);
			margin: 0 0 var(--space-s);
		}
		& p {
			margin: 0 0 var(--space-m);
			color: var(--color-text-2);
			max-width: 40ch;

			&:last-child { margin-bottom: 0; }
		}
		.factList { margin-top: var(--space-s); }
	}

	/* The address is the fallback for everyone who won't use the form, so it
	   is the one piece of scale in the column. A mail address is a figure
	   rather than a heading — like .engageRate it sits below the page's three
	   heading tiers instead of joining them. */
	.contactEmail {
		display: block;
		color: var(--color-text-1);
		max-width: none;
		overflow-wrap: anywhere;
		transition: color 0.25s ease;

		&:hover { color: var(--color-action-text); }
	}
}

/* What happens after you send it, as the shared ruled index. It was a numbered
   list inside the aside, which put the four things that actually answer "what
   am I signing up for" in the quietest column on the page. */
.contactNext {
	.indexLabel { margin-bottom: var(--space-l); }
}

/* --- /work index ------------------------------------------------------------
   A ruled index, not a wall of cards. The lead case takes a full-measure plate
   with its title under it; the remaining cases run as plate-left / copy-right
   rows separated by hairlines. Two row scales and no mirroring — alternating
   the image side down a list is the most-copied composition in this genre and
   takes no position on the work.

   The cases are a list rather than a positioned grid for a functional reason
   as well: filtering hides a row and the list closes up, where a card placed
   in an explicit column would leave a hole behind it.

   scripts.js toggles .isActive on the buttons and .isHidden on the cards. It
   only ever filters #workGrid — the archive band below carries its own section
   mark and is deliberately always visible.                                  */

.filterBar {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-2xs);
	margin-block: var(--space-m) var(--space-l);

	/* Layout and colour only — the buttons carry .label in the markup, so the
	   voice is the same one every other control-sized cap line on the site
	   uses. This block used to set its own font-size and tracking. */
	& button {
		color: var(--color-text-3);
		background: transparent;
		border: 1px solid var(--color-rule);
		border-radius: var(--radius-xs);
		padding: var(--space-2xs) var(--space-s);
		transition: color 0.2s ease, border-color 0.2s ease,
		            background-color 0.2s ease;

		&:hover {
			color: var(--color-text-1);
			border-color: var(--color-border-control);
		}
		&.isActive {
			background: var(--color-action);
			border-color: var(--color-action);
			color: var(--color-on-action);
		}
	}
}
/* Every transition on this site is inert under reduced motion. */
@media (prefers-reduced-motion: reduce) {
	.filterBar button { transition: none; }
}

.workItem.isHidden { display: none; }

.workEmpty {
	display: none;
	color: var(--color-text-3);
	padding: var(--space-3xl) 0;
	border-top: 1px solid var(--color-rule);

	&.isShown { display: block; }
}

/* The archive. Eight quiet tiles as one contact sheet — this band is doing
   noticeably less than the index above it, on purpose, and it is the only
   place on the page carrying real artwork rather than a plate. Square wells,
   because every one of those images is a 300px square. */
.archiveHead {
	margin-bottom: var(--space-2xl);

	.indexLabel { margin-bottom: var(--space-m); }
	.lede { margin: 0; max-width: 46ch; }
}
.workArchive {
	display: grid;
	grid-template-columns: repeat(4, minmax(0, 1fr));
	gap: var(--space-l) var(--space-m);

	.workCardMedia { aspect-ratio: 1 / 1; }
	/* No tag row down here, so the description is the last thing in the tile. */
	.workCardBody > p:last-child { margin-bottom: 0; }

	@media only screen and (max-width: 860px) { grid-template-columns: repeat(2, minmax(0, 1fr)); }
	@media only screen and (max-width: 479px) { grid-template-columns: 1fr; }
}

/* --- /bookmarkapp -------------------------------------------------------------
   The first of the legacy project pages on the new art direction. States, in
   order: the shared page head with a meta strip, the four stills, a 7/5 pair
   of paragraphs, the four demo loops on the alternate surface, the features
   as ruled rows, and the shared closing band. Nothing in
   10-project-detail.css applies to it any more.                              */

/* The meta strip runs the full measure under the head's two columns, set off
   by a divider rather than a structural rule — the section mark above it is
   the structure. */
.bookmarkHead .metaGrid {
	grid-column: 1 / -1;
	padding-top: var(--space-l);
	border-top: 1px solid var(--color-rule); /* divider */
}

/* A row of phone screens, stills or video. Four across, because there are
   four of each and the count is the page's decision; under 768px it becomes
   a snap-scroller rather than a stack, since four phone-height screens one
   under another is four viewports of scrolling for one idea. */
.phoneRow {
	display: grid;
	grid-template-columns: repeat(4, minmax(0, 1fr));
	gap: var(--space-l);

	& figure { margin: 0; }

	/* Every still is 1179 × 2556 and every loop 886 × 1920 — the same screen
	   ratio — so one aspect-ratio holds both and a video reserves its height
	   before it loads. The corner is the phone's own: elliptical percentages
	   of the screen, so it scales with the well instead of being a fixed
	   radius that looks right at one width. The previous page also rotated
	   and drop-shadowed these; both went with that art direction. */
	& img, & video {
		display: block;
		width: 100%;
		height: auto;
		aspect-ratio: 1179 / 2556;
		object-fit: cover;
		border: 1px solid var(--color-rule);
		border-radius: 14% / 6.5%;
	}
	& figcaption {
		margin-top: 1em;
		color: var(--color-text-3);
	}

	@media only screen and (max-width: 767px) {
		grid-template-columns: none;
		grid-auto-flow: column;
		grid-auto-columns: min(62vw, 260px);
		overflow-x: auto;
		scroll-snap-type: x mandatory;
		overscroll-behavior-x: contain;
		padding-bottom: var(--space-m);

		& > * { scroll-snap-align: start; }
	}
}

/* The idea in the seven, the role dropped to its baseline in the five — the
   page head's composition, one tier down. */
.bookmarkIntro {
	display: grid;
	grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
	gap: var(--space-l) var(--space-2xl);
	align-items: end;

	& p { margin: 0; }
	.body { color: var(--color-text-2); }

	@media only screen and (max-width: 860px) {
		grid-template-columns: minmax(0, 1fr);
		align-items: start;
	}
}

/* The features. Four peers with no order between them, so not the numbered
   .capList; and the heading is the whole of the left-hand entry, so not
   .noteRow, whose margin column holds a label filed beside a heading. 5/7
   rather than 3/9 because a card-tier heading needs the room a micro-cap
   doesn't. */
.featureIndex {
	list-style: none;
	margin: 0;
	padding: 0;
}
.featureRow {
	display: grid;
	grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
	column-gap: var(--space-2xl);
	align-items: baseline;
	padding-block: var(--space-l);
	border-bottom: 1px solid var(--color-rule); /* divider */

	&:last-child { border-bottom: 0; }

	& h2, & p { margin: 0; }
	& p { color: var(--color-text-2); }

	@media only screen and (max-width: 767px) {
		grid-template-columns: 1fr;
		row-gap: var(--space-s);
	}
}

/* --- /field-notes -------------------------------------------------------------
   States, in order: the shared page head, the reading list as a ruled index,
   the framed gallery wall, and the shared closing band on the brand field.

   .fieldGrid — a three-column masonry of loose photographs — is gone with this
   rebuild. It had no consumer: the page it was written for shows its
   photographs in the frames below, and a second, unframed grid of the same
   pictures was never on it.                                                  */

/* The reading list. Hairline rows: what kind of piece it is on the left, the
   title and its one-line note on the right, and a quiet marker where a link
   would be until the piece exists.

   Not the shared .capList — that index numbers its rows, and numerals imply a
   reading order this list doesn't have. Not the .caseIndex either: these rows
   carry no image. What's left is the asymmetry, which is the part worth
   keeping.

     <ol class="noteIndex">
       <li class="noteRow">
         <span class="labelSmall noteKind">Essay</span>
         <div>
           <h3 class="displaySmall">…</h3>
           <p>…</p>
           <span class="labelSmall casePending">Not published yet</span>
         </div>
       </li>
     </ol>
                                                                              */
/* The reading list runs straight off the page head with no mark and no deck of
   its own — the head has already said what the page is, and a second heading
   saying it again one screen later is the site talking to itself. All this
   band carries is the note to Tom, while there is one. */
.noteBand {
	.todoNote { margin-bottom: var(--space-xl); }
}

.noteIndex {
	list-style: none;
	margin: 0;
	padding: 0;
}
.noteRow {
	display: grid;
	grid-template-columns: minmax(0, 3fr) minmax(0, 9fr);
	column-gap: var(--space-2xl);
	align-items: baseline;
	padding-block: var(--space-l);
	border-bottom: 1px solid var(--color-rule); /* divider */

	&:last-child { border-bottom: 0; }

	/* The kind sits in the margin column on the title's own baseline, the way
	   the ruled index hangs its numerals — it is the label the row is filed
	   under, not a kicker above the heading. */
	.noteKind { color: var(--color-text-3); }

	& h3 { margin: 0; max-width: 22ch; }
	& p {
		margin: var(--space-s) 0 0;
		color: var(--color-text-2);
		/* Narrow against a display-size title, so the row reads as a headline
		   with a note under it rather than as two columns of copy. */
		max-width: 52ch;
	}

	@media only screen and (max-width: 767px) {
		grid-template-columns: 1fr;
		row-gap: var(--space-2xs);
	}
}

/* --- /field-notes · the framed gallery wall -----------------------------------
   The one skeuomorphic thing on the site, and deliberately so: photographs
   that are not a service being sold are hung on a wall rather than laid into
   a grid, and the frames are the joke. Everything else on the page is the
   same flat, ruled system as the rest of the site, which is what keeps this
   band reading as a set piece instead of as a different website.

   The slider runs full-bleed out of its band — the head above it stays on the
   site measure — so the row of frames can carry off both edges of the
   viewport. Scroll-snapping is native; there is no JavaScript behind it.

   Was .portfolioSection, a centred gradient band with an <h1> in it, from
   before Field Notes was split off the home page. The band is a normal
   .section now and the section mark does what its heading did; the frames
   themselves are unchanged.                                                  */

.fieldWall {
	/* The mark stands alone above the frames — no heading, no deck. A row of
	   framed photographs does not need a line explaining that it is a row of
	   framed photographs. It takes the wider step down because what follows is
	   a band, not a list. */
	.indexLabel { margin-bottom: var(--space-xl); }

	.portfolioSlider {
		margin: 0;
		display: flex;
		flex-direction: row;
		flex-wrap: nowrap;
		align-items: start;
		gap: var(--space-l);
		/* The band's own margin on the leading edge, so the first frame starts
		   on the site measure and the rest run off the right. */
		padding: var(--space-l) max(5vw, calc((100vw - 1440px) / 2));
		overflow-x: auto;
		overflow-y: hidden;
		position: relative;
		scroll-snap-type: x mandatory;
		overscroll-behavior-x: contain;

		&::-webkit-scrollbar { display: none; }
	}

	.portfolioSlide {
		flex: 0 0 85vw;
		width: 85vw;
		max-width: 480px;
		scroll-snap-align: center;
		display: flex;
		align-items: center;
		justify-content: center;
		flex-direction: column;
		position: relative;
		margin: 0;

		/* A frame is a physical object, so its colours are fixed rather than
		   themed — see the frame tokens in 02-tokens.css. */
		.frame {
			width: 100%;
			aspect-ratio: 2/3;
			display: flex;
			align-items: center;
			justify-content: center;
			flex-direction: column;
			border: 12px solid var(--color-frame-moulding);
			background: var(--color-frame-mount);
			box-shadow:
				inset 3px 6px 8px var(--color-frame-shadow),
				4px 8px 12px var(--color-frame-shadow);
			padding: var(--space-l);
			position: relative;

			/* gallery lighting: in dark mode the frame catches a little shadow
			   at its edges so the wall reads as a lit room */
			@media (prefers-color-scheme: dark) {
				&::before {
					content: "";
					position: absolute;
					top: 0;
					left: 0;
					right: 0;
					bottom: 0;
					background:
						linear-gradient(to right,
							rgba(0, 0, 0, 10%) 0%,
							rgba(0, 0, 0, 0) 20%,
							rgba(0, 0, 0, 0) 80%,
							rgba(0, 0, 0, 10%) 100%),
						linear-gradient(to bottom,
							rgba(0, 0, 0, 30%) 0%,
							rgba(0, 0, 0, 0) 10%,
							rgba(0, 0, 0, 0) 70%,
							rgba(0, 0, 0, 20%) 100%),
						radial-gradient(circle at 50% 30%,
							transparent 50%,
							rgba(0, 0, 0, 20%) 80%);
					pointer-events: none;
					z-index: 1;
				}
			}
		}

		.frameMatte {
			padding: var(--space-xs);
			box-shadow: inset 1px 2px 4px var(--color-frame-bevel);
			display: flex;
			width: 100%;
			max-width: 100%;
			max-height: 100%;
			position: relative;
		}

		.imgContainer {
			position: relative;
			background-color: transparent;
			display: flex;
			width: 100%;
			max-width: 100%;
			max-height: 100%;

			/* the inset shadow sits above the image */
			&::before {
				content: "";
				position: absolute;
				inset: 0;
				box-shadow: inset 1px 2px 4px var(--color-frame-bevel);
				pointer-events: none;
				z-index: 1;
			}
		}

		& img {
			width: 100%;
			height: auto;
			max-width: 100%;
			max-height: 100%;
			display: block;
			margin: auto;
			position: relative;
			z-index: 0;
		}

		/* The caption hangs off the frame, not inside it — a gallery label on
		   the wall beside the picture. Two tiers: the picture's name, and what
		   it is. Voices come from the type set. */
		.projectInfo {
			width: 100%;
			padding: var(--space-m) 0 0;
			text-align: right;
			display: flex;
			flex-direction: column;
			gap: var(--space-3xs);

			.noteTitle { color: var(--color-text-1); }
			.noteMeta  { color: var(--color-text-3); }
		}

		/* per-project frame treatments, for slides that aren't photographs */
		&.informalGamers .frame {
			border-color: #025691;
			padding: 20%;
			border-width: 8px;

			.frameMatte { padding: var(--space-xl); }
		}
		&.nicethings .frame {
			background-color: hsl(51, 25%, 90%);
			border-width: 24px;

			.frameMatte { padding: var(--space-m); }
		}
		&.exhibitionGuide .frame {
			border-color: #dbdbdb;

			.frameMatte {
				padding: var(--space-m);
				background-color: #ffffff;
			}
		}
	}
}

/* --- /faq --------------------------------------------------------------------
   States, in order: the shared page head, a quiet fact band of short answers,
   the accordion in three marked groups on the narrow measure, and the shared
   hard split out to the two pages that own cost and terms. The red group
   headings are gone: a group head is a section mark like every other one on
   the site, and seven red kickers down a page drain the identity colour.  */

.faqFacts {
	.indexLabel { margin-bottom: var(--space-l); }

	/* The meta tier of the two-tier micro-cap system; the mark above is the
	   other. The rows themselves are .factList in 07-shell. */
	& h3 {
		color: var(--color-text-3);
		margin: 0 0 var(--space-s);
	}
}
/* Interchangeable tracks — same sizing function, same content shape — so the
   row packs off its own width rather than a hand-picked breakpoint. */
.faqFactGrid {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
	gap: var(--space-xl) var(--space-2xl);
	align-items: start;
}

/* The three groups read as one continuous index rather than three bands, so
   the space between them is a group gap and not a full band's padding. The
   two-class selector is what beats .faqSection's own padding — both are in
   this layer and .faqSection is declared later in the file. */
.faqSection.faqGroup {
	padding-block: var(--space-2xl) 0;

	&:last-of-type { padding-bottom: var(--space-4xl); }

	.indexLabel { margin-bottom: var(--space-l); }
}

/* --- /faq and /process · the accordion -------------------------------------
   Collapsed by default; scripts.js sets max-height inline on open so the
   answer can transition to its real height.                                  */

/* The questions take the seven columns of the page's own measure rather than a
   centred .wrapNarrow band. Every section mark on the site starts at the page
   margin, and a centred column halfway down a page that is left-aligned for
   its whole length reads as a second template. Same measure as before — it
   just comes off the grid instead of off the centre of the viewport. */
.faqList {
	max-width: 720px;
}

.faqSection {
	padding-top: var(--space-2xl);
	padding-bottom: var(--space-2xl);

	.faq {
		--icon-thickness: 3px;
		--icon-size: 15px;

		border-top: 1px solid var(--color-rule);
		color: var(--color-text-1);
		padding: var(--space-l) 0;

		&:last-of-type { border-bottom: 1px solid var(--color-rule); }

		.faq__question {
			position: relative;
			padding: 0 56px 0 0; /* room for the plus/minus */
			margin: 0;
			cursor: pointer;
			user-select: none;

			/* scripts.js wraps the question text in a real <button> so the
			   control is focusable and operable by keyboard. It carries no
			   appearance of its own — the heading is still what you see. */
			.faqToggle {
				font: inherit;
				letter-spacing: inherit;
				color: inherit;
				background: none;
				border: 0;
				margin: 0;
				padding: 0;
				width: 100%;
				text-align: left;
				cursor: pointer;
			}

			/* horizontal bar */
			&::after {
				content: "";
				position: absolute;
				right: 0;
				top: 50%;
				width: var(--icon-size);
				height: var(--icon-thickness);
				background: var(--color-border-control);
				border-radius: var(--icon-thickness);
				transform: translateY(-50%);
				opacity: 1;
				transition: opacity 0.25s ease, background 0.25s ease;
			}
			/* vertical bar — rotates away to make a minus */
			&::before {
				content: "";
				position: absolute;
				right: calc((var(--icon-size) - var(--icon-thickness)) / 2);
				top: 50%;
				width: var(--icon-thickness);
				height: var(--icon-size);
				background: var(--color-border-control);
				border-radius: var(--icon-thickness);
				transform: translateY(-50%) rotate(0deg);
				transform-origin: center;
				transition: transform 0.25s ease, background 0.25s ease;
			}
		}

		& p {
			margin: 0;
			padding: 0;
			overflow: hidden;
			max-height: 0;
			opacity: 0;
			transition: max-height 250ms ease, opacity 250ms ease, margin-top 250ms ease;
		}

		&.is-open {
			.faq__question {
				&::before { transform: translateY(-50%) rotate(90deg); }
				&::after  { opacity: 0; }
			}
			& p {
				opacity: 1;
				margin-top: var(--space-xs);
			}
		}
	}
}

@container offer (min-width: 460px) {
	.offer h3 { font-size: var(--step-3); }
}
@container pillar (min-width: 420px) {
	.pillar p { max-width: 52ch; }
}

} /* @layer pages */
