/*
 * WordPress-side additions to the compiled stylesheet (assets/css/main.css).
 * Keep this file small: anything visual that also exists in the original build
 * belongs in main.css, not here.
 */

/* ---------------------------------------------------------------- hive field */
.oh-field svg,
.oh-field canvas {
	display: block;
	width: 100%;
	height: 100%;
}

.oh-mark {
	transform-box: fill-box;
	transform-origin: center;
}

@keyframes oh-drift {
	from { transform: translateY(0); }
	to { transform: translateY(var(--oh-drift, -12px)); }
}

@keyframes oh-pulse {
	0%, 100% { transform: scale(1); }
	50% { transform: scale(1.07); }
}

@media (prefers-reduced-motion: no-preference) {
	/* Promoted only where something actually animates: the reduced-motion path used to leave 97
	 * static marks on their own compositor layers, for the users who asked for less work. */
	.oh-mark {
		animation: oh-drift var(--oh-dur, 12s) ease-in-out infinite alternate;
		animation-delay: var(--oh-delay, 0s);
		will-change: transform;
	}
	.oh-mark--coral {
		animation: oh-pulse 3.4s ease-in-out infinite;
	}
}

/* --------------------------------------------------------------- WordPress */

/* Logged-in admin bar sits above the fixed nav. */
body.admin-bar header.fixed {
	top: var(--wp-admin--admin-bar--height, 32px);
}

/* Honeypot field on the demo form: visually gone, still in the DOM for bots. */
.oh-hp {
	position: absolute !important;
	left: -9999px !important;
	width: 1px;
	height: 1px;
	overflow: hidden;
	opacity: 0;
}

/* Plain pages (anything outside /legal) get readable defaults in the brand voice. */
.legal-prose h2 {
	margin-top: 2.5rem;
	font-family: var(--font-display);
	font-weight: 900;
	font-size: clamp(1.5rem, 2.6vw, 2.25rem);
	letter-spacing: -0.04em;
	line-height: 1.1;
}
.legal-prose h3 {
	margin-top: 2rem;
	font-family: var(--font-display);
	font-weight: 700;
	font-size: 1.25rem;
	letter-spacing: -0.02em;
}
.legal-prose p,
.legal-prose li {
	margin-top: 1.25rem;
	font-size: 1.0625rem;
	line-height: 1.62;
	color: var(--ink-muted);
}
.legal-prose ul,
.legal-prose ol {
	padding-left: 1.25rem;
	list-style: disc;
}
.legal-prose ol {
	list-style: decimal;
}
.legal-prose a {
	color: var(--ink);
	text-decoration: underline;
	text-decoration-color: var(--rule-strong);
	text-underline-offset: 4px;
}
.legal-prose a:hover {
	text-decoration-color: var(--color-coral);
}
.legal-prose table {
	margin-top: 1.5rem;
	width: 100%;
	border-collapse: collapse;
	font-size: 0.9375rem;
}
.legal-prose th,
.legal-prose td {
	padding: 0.75rem 0.5rem;
	border-bottom: 1px solid var(--rule);
	text-align: left;
	vertical-align: top;
}

/* ---------------------------------------------------------- UI/UX fixes */
/* Note: main.css puts its utilities in @layer, so these unlayered rules win ties; keep every selector scoped. */

/* Anchor navigation, focus() and scrollIntoView clear the fixed nav. ScrollTrigger reads scrollY, unaffected. */
html {
	scroll-padding-top: 6rem;
}

/* ------------------------------------------------------------ Focus ring
 * main.css compiles :focus-visible to a coral outline. Coral measures 2.41:1 against the light
 * ground, so every header and footer control failed 1.4.11, and on a coral button the ring landed
 * in its own colour. A focus indicator has to be legible on every surface it can land on, so this
 * one follows the surface rather than the brand. Ocean sections are dark in both themes and get
 * the chalk ring; everything else takes the ring from the active theme.
 *
 * --oh-focus itself, and the Ocean-section override, now come from tokens/tokens.json via
 * main.css. The rule below is what uses them.
 */
:focus-visible {
	outline: 2px solid var(--oh-focus);
	outline-offset: 3px;
}
/* Tailwind's transition-colors includes outline-color, so the ring faded in from the element's own
 * colour: on the navy header CTA that meant ~150ms of chalk-on-cream, an indicator you cannot see
 * at the moment you need it. Everything else may still transition; the ring may not. */
:focus-visible {
	transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter;
}

/* -------------------------------------------------- Hero copy over the field
 * The field is decorative and must never sit on hero words. The section already washes it out with
 * a radial keyed to its own box, which leaves the eyebrow exposed: at phone widths a coral mark
 * lands squarely on it, and the eyebrow used to be coral too. This second wash follows the copy
 * block itself, so the words stay legible at every width while the field still reads around them.
 */
[data-hero-content] {
	position: relative;
}
[data-hero-content]::before {
	content: "";
	position: absolute;
	z-index: -1;
	inset: -2.5rem -1.5rem;
	pointer-events: none;
	background: radial-gradient(
		116% 96% at 24% 46%,
		color-mix(in srgb, var(--ground) 97%, transparent) 0%,
		color-mix(in srgb, var(--ground) 92%, transparent) 52%,
		color-mix(in srgb, var(--ground) 58%, transparent) 78%,
		transparent 100%
	);
}

/* ---------------------------------------------------- The mark, and the one line above the fold
 * Two places the brand's colour does real work rather than decorating. The logo's mark is a filled
 * shape, so it takes a brand colour itself; the eyebrow is type, so it takes the darkened Coral
 * that clears 4.5:1 on cream - brand Coral sets text at 2.41:1 and has no business being read.
 *
 * WHICH brand colour the mark takes is the theme's answer, not this file's: the brandbook draws the
 * lockup twice, Ocean on Chalk and Coral reversed, and this file used to ship the reversed mark on
 * both grounds. --oh-logo-mark is generated from tokens/tokens.json and turns with the theme, so
 * both headers and the footer lockup get the drawing the ground they sit on calls for.
 *
 * Only the mark turns: the wordmark beside it stays ink, because a two-tone logotype is a different
 * logo, not a coloured one. An uploaded Site Identity image replaces the whole lockup and is not
 * touched by this - a PNG has no currentColor to give.
 */
.oh-logo > svg {
	color: var(--oh-logo-mark);
}
/* Size and tracking now come from --oh-eyebrow, with the other four section eyebrows. */
.oh-hero-eyebrow {
	color: var(--coral-ink);
}

/* ------------------------------------------------------- Hero: the flow diagram
 * The headline's claim, drawn: what one departing employee knows passes through OakHive and reaches
 * the three groups who stay. Nodes are the brand mark's own aperture - a pointy-top hexagon with
 * flat left and right sides - rather than the full disc the roadmap uses, so the two diagrams on the
 * page never read as the same component.
 *
 * Built the way the journey is built: cells for the nodes, and the connectors as SVG lines with a
 * non-scaling stroke drawn from one node's centre to the next and cut back at both rims. The
 * alternative - one flat SVG with <text> in it - ignores the Customizer's text scale and comes
 * apart at 200%.
 *
 * The geometry that makes the fan land on its targets: the audience list is three equal rows, and
 * the connector column is the same height, so the ends at 16.667 / 50 / 83.333 sit on the three node
 * centres at any size. Source and hub hang their labels out of flow, which keeps both marks on the
 * stage's own centre line - and therefore on the middle branch.
 */
.oh-flow {
	/* Sized off the reference, which is what makes the fan read as a fan: the marks are a tenth of the
	 * drawing's width and the hub a quarter, which leaves a little over half of it for the two gaps -
	 * and the gap is the only thing that sets the angle the three branches leave at. Marks any larger
	 * eat the gap and the branches leave at 50-odd degrees, which reads as a bracket rather than a
	 * distribution.
	 *
	 * Enlarged by about a quarter from the first build, along with the column it lives in (see the
	 * 80rem query below), because at the old size it read as an appendix to the headline rather than
	 * as the headline's other half. A fifth and not a half: the two labelled audience rows carry
	 * their names beside their marks, so the node columns grow faster than the marks do, and past this
	 * the gaps are eaten and the three branches leave at 45 degrees instead of the reference's 35. */
	--oh-flow-node: clamp(2rem, 3.3vw, 2.625rem);
	--oh-flow-hub: calc(var(--oh-flow-node) * 2.4);
	--oh-flow-ink: var(--color-ocean);
	/* Lagoon, and the only Lagoon in the drawing: the three who stay are Ocean and the hub is Coral,
	 * so the one who leaves needs the third brand colour to be read as a different kind of node rather
	 * than as a paler member of the same set - which is what a lighter Ocean made of it. */
	--oh-flow-source: var(--color-lagoon);
	margin: 0;
	/* Room for the two labels that hang out of the band, in em so it keeps up with the text scale.
	 * It belongs to the wrapper and not to the band: everything is border-box here, so padding on the
	 * band would come out of the very height the fan's angle is measured from. Plus half a node,
	 * which is what the departing node's drop costs its label: that name travels down the stage with
	 * the mark it belongs to and would otherwise sit on whatever the hero puts underneath. */
	padding-bottom: calc(4em + var(--oh-flow-node) * 0.5);
}
:root[data-theme="dark"] .oh-flow {
	/* Ocean on the dark ground is a silhouette of itself; this is the same rung the roadmap steps to.
	 * Lagoon needs no such step - it is the one colour in the palette that carries on both grounds. */
	--oh-flow-ink: var(--color-ocean-100);
}
.oh-flow-stage {
	display: grid;
	/* The two gaps are no longer equal: the first is the longer one, which pushes the departing node
	 * out to the left and stretches the trunk into a run long enough for its rise to read as a climb
	 * rather than as a kink. It also tightens the fan's run, which is what brings the three branches
	 * up to the reference's own angle. */
	grid-template-columns: auto minmax(1.25rem, 1.45fr) auto minmax(1.25rem, 1fr) auto;
	/* One row, and it has to fill the height below - without this the row sizes to its own content
	 * and the height set here simply hangs off the bottom of a shorter band. */
	grid-template-rows: minmax(0, 1fr);
	align-items: stretch;
	/* Held to the height the three branches need rather than to whatever the tallest cell happens to
	 * be, because this height is the fan's rise and the gap beside it is the fan's run. The mark is
	 * 1.155 times as tall as it is wide, so three rows of 1.5 marks each leave half a mark of air
	 * between neighbours and put the branches at about 35 degrees - the reference's own angle. */
	height: calc(var(--oh-flow-node) * 4.5);
}
.oh-flow-cell {
	position: relative;
	display: grid;
	place-items: center;
}
/* The one who leaves sits low and left of everything else, so the transfer runs diagonally up into
 * the hub instead of straight across - the difference between a diagram and a bracket.
 *
 * The cell stretches to the stage's full height, so this 40% is 40% of the stage and the mark's
 * centre lands at 90% of it. That number is also written into the trunk connector as y1="90" in
 * section-hero.php, the same contract the fan keeps with 16.667 / 50 / 83.333: change one and the
 * line stops meeting the node. */
.oh-flow-cell--source {
	transform: translateY(40%);
}
.oh-flow-mark svg {
	display: block;
	width: var(--oh-flow-node);
	height: auto;
	max-width: none;
	color: var(--oh-flow-ink);
}
.oh-flow-mark--source svg {
	color: var(--oh-flow-source);
}
.oh-flow-mark--hub svg {
	width: var(--oh-flow-hub);
	color: var(--color-coral);
	/* The disc is exactly r=50 in a -50 -50 100 100 box, so it already touches all four edges and an
	 * SVG clips to its viewport by default. Without this the arrival ring is cut to nothing the
	 * instant it starts growing - the same reason .oh-flow-line opts out below. */
	overflow: visible;
}
.oh-flow-mark--hub {
	/* The hub cell sits between the two connector columns in source order, so the ring would expand
	 * underneath the fan. One step up is enough; nothing else in the figure is layered. */
	position: relative;
	z-index: 1;
}
.oh-flow-label {
	font-size: clamp(0.875rem, 1.05vw, 1rem);
	letter-spacing: -0.01em;
	line-height: 1.35;
	font-weight: 500;
	color: var(--ink);
}
.oh-flow-cell .oh-flow-label {
	position: absolute;
	top: 100%;
	margin-top: 0.9em;
	max-width: 9em;
	text-align: center;
}
/* The departing node's label is the one exception. The rule above hangs both names off the foot of
 * the cell, which puts them on one line under the drawing - right while both marks sit on the stage's
 * centre line, and wrong the moment one of them does not. Left alone it stranded the name most of the
 * stage below the mark it belongs to. Measured from the mark instead: half a mark down to clear it,
 * and a fifth of one for air.
 *
 * It has to come after that rule and not before it. Both selectors are one class and one class, so
 * specificity is a tie and source order is the whole argument; written above, this loses silently. */
.oh-flow-cell--source .oh-flow-label {
	top: 50%;
	margin-top: calc(var(--oh-flow-node) * 0.78);
}
/* ---------------------------------- The connectors: tied to the node centres, cut at the node rims
 * A branch is the segment between two centres, not between two column edges. Drawn edge to edge it
 * left the hub at whatever height the column boundary happened to cross it, so extending a branch
 * backwards missed the very node it came out of. Centre to centre it points at the thing it
 * connects, which is the only reading under which the three branches are one fan opening out of the
 * hub rather than three lines that happen to start nearby.
 *
 * Nothing may show inside a node, so every branch is trimmed at both ends by a mask with a circular
 * hole the size of the mark it meets. A hole and not a straight cut at the mark's box: the disc
 * curves back, so a vertical cut leaves the outer branches beginning a few pixels clear of it -
 * exactly the gap the old x1="-4" was there to paper over. The comets ride inside the same masks, so
 * a pip now slides out from under the hub instead of crossing it.
 *
 * Two elements with one hole each, and not one element with two mask layers: layers need
 * mask-composite: intersect to punch both holes, and anywhere that is not understood the layers are
 * added instead - each hole filled in by the other, and both branches drawn straight through both
 * nodes. Nested masks multiply with nothing to opt into.
 */
.oh-flow-link {
	position: relative;
}
.oh-flow-link--trunk {
	--oh-flow-from: var(--oh-flow-node);
	--oh-flow-from-y: 90%;
	--oh-flow-to: var(--oh-flow-hub);
	--oh-flow-to-y: 50%;
}
.oh-flow-link--fan {
	--oh-flow-from: var(--oh-flow-hub);
	--oh-flow-from-y: 50%;
	--oh-flow-to: var(--oh-flow-node);
	/* One fan branch per connector, each carrying its own --oh-flow-to-y in the markup beside the
	 * y2 it has to agree with. This is the middle one's, and the fallback if a branch omits it. */
	--oh-flow-to-y: 50%;
}
/* The band a branch is drawn in. It overhangs its column by half a mark at each end, so its own left
 * and right edges sit on the two node centres and a line from x=0 to x=100 in the connector's
 * stretched viewBox is the centre-to-centre segment itself. Vertically it is the stage, which is
 * what keeps y=90 on the departing node and 16.667 / 50 / 83.333 on the three who stay. */
.oh-flow-span {
	position: absolute;
	top: 0;
	bottom: 0;
	left: calc(var(--oh-flow-from) / -2);
	right: calc(var(--oh-flow-to) / -2);
	-webkit-mask-image: radial-gradient(circle calc(var(--oh-flow-from) / 2) at 0 var(--oh-flow-from-y), transparent 98%, #000 100%);
	mask-image: radial-gradient(circle calc(var(--oh-flow-from) / 2) at 0 var(--oh-flow-from-y), transparent 98%, #000 100%);
}
.oh-flow-line {
	position: absolute;
	inset: 0;
	overflow: visible;
	/* the preflight puts max-width:100% on every svg, which would clip a connector at the column edge */
	max-width: none;
	width: 100%;
	height: 100%;
	stroke: var(--rule-strong);
	stroke-width: 1;
	stroke-linecap: round;
	-webkit-mask-image: radial-gradient(circle calc(var(--oh-flow-to) / 2) at 100% var(--oh-flow-to-y), transparent 98%, #000 100%);
	mask-image: radial-gradient(circle calc(var(--oh-flow-to) / 2) at 100% var(--oh-flow-to-y), transparent 98%, #000 100%);
}
/* The moving parts, both invisible until site.js drives them. The authored SVG attributes are the
 * diagram's finished state, so no-JS, reduced motion, the Elementor editor and a reverted matchMedia
 * context all land on a correct static drawing - as long as these two never show up on their own. */
.oh-flow-comet {
	stroke: var(--color-coral);
	stroke-width: 3;
	opacity: 0;
}
.oh-flow-ring {
	stroke: currentColor;
	stroke-width: 2;
	opacity: 0;
}
.oh-flow-audiences {
	display: grid;
	grid-template-rows: repeat(3, 1fr);
	list-style: none;
	margin: 0;
	padding: 0;
}
.oh-flow-audience {
	display: flex;
	align-items: center;
	gap: 0.6rem;
}

/* ------------------------------------------- 1280px and up: the diagram beside the headline
 * Two columns cost the headline its size, and there is no way around that: the display face was set
 * at 6rem against the full 1400px, where "the person, but the way" measures 1002px, and the copy
 * column here is never wider than 864. Left alone the line wraps and the headline's three authored
 * lines become four and a half.
 *
 * So the hero's display size is recomputed from the column it now lives in rather than from the
 * viewport: 1002px of line at 96px of type is 10.44px of line per px of type, and 0.092 leaves the
 * longest line about 18px of air inside the track at every width this rule applies at. It is capped
 * at the original 6rem so nothing grows, and the whole expression still runs through --oh-type-h so
 * the Customizer's text scale keeps working.
 *
 * The switch is at 1280 and not 1024 because at 1024 the same arithmetic puts the headline at 43px,
 * which is smaller than the section headings further down the page. Below 1280 the hero keeps its
 * full width and the diagram goes underneath.
 */
@media (min-width: 80rem) {
	.oh-hero-block {
		/* 616 = 64px of page padding + the 4.5rem gap + the 30rem column beside it. It was 536 while
		 * that column was 25rem; the column grew with the drawing in it, so the constant grew with the
		 * column. Get this wrong in either direction and the headline's three authored lines become
		 * four and a half. */
		--oh-display-1: calc(min(5.5rem, (min(1400px, 100vw) - 616px) * 0.092) * var(--oh-type-h));
		display: grid;
		grid-template-columns: minmax(0, 1fr) minmax(19rem, 30rem);
		gap: 4.5rem;
		align-items: center;
		max-width: none;
	}
}
/* ------------------------------------------- below 1280px: the drawing goes under the copy
 * Down to 48rem, where the phone rule below takes over and stands it down.
 *
 * There is no second column here, so the figure stops being the headline's other half and becomes
 * what every other drawing on the page already is at this width: a figure under its own heading.
 * That is also the roadmap's answer one section down - the journey turns rather than standing down.
 *
 * It did stand down once, on three grounds, and two of them no longer hold. "One geometry to animate
 * instead of two" was about the vertical twin that went with it, and nothing animates here at all:
 * the choreography in site.js is gated on (min-width: 80rem), and the authored SVG attributes are
 * the finished drawing, so this is the same static state no-JS and reduced motion already land on.
 * There is no tween below the gate and so nothing to strand. The height is 224px at 390, not the
 * 250-400 estimated: the node floors at 2rem, so the band is 144px and the hanging labels 80px. And
 * #top is min-h-[100dvh] items-end, so that height does not push the buttons down - it flips the
 * copy from bottom-aligned to top-aligned and pulls the headline up instead.
 *
 * Capped at 30rem, the column it was drawn for. Between 640 and 1280 the copy runs far wider than
 * the drawing needs, and without the cap the two gaps take the slack and the fan opens past the
 * angle the whole geometry is measured from.
 *
 * `not all and (min-width: 80rem)` and not `max-width: 79.99rem`: 79.99rem is 1279.84px, and at a
 * fractional viewport width - browser zoom, Windows display scaling - neither query would match and
 * the drawing would fall into that 0.16px seam. Negated, the two queries are exact complements, and
 * they match the JS gate in site.js word for word.
 */
@media not all and (min-width: 80rem) {
	.oh-flow {
		margin-top: 3.5rem;
		max-width: 30rem;
	}
	/* The departing node's name is centred on a 2rem mark that sits on the stage's own left edge, so
	 * centred it hangs past that edge: measured at 390 it started at x=5 while the headline, the
	 * eyebrow and the stage all start at 20. Below 1280 it stops being centred and hangs from the
	 * mark's left edge instead, which puts it on the same line as every other first character on the
	 * screen. The hub's name keeps its centring - it sits mid-stage, where centred is right. 7em
	 * breaks it to two lines rather than letting one long name set the column's minimum width. */
	.oh-flow-cell--source .oh-flow-label {
		max-width: 7em;
		justify-self: start;
		text-align: left;
	}
}

/* ------------------------------------------------------ phones: the drawing stands down
 * From 48rem up to the breakpoint it has a column wide enough to hold the fan's angle, and it reads
 * as a figure under its own heading. On a phone it is 224px of the one screen where height is
 * scarcest, and the hero has to spend that height on the headline and the two buttons instead.
 *
 * The band and not the figure, as always: display:none on the <figure> would take the <figcaption>
 * out of the accessibility tree with it, and that sentence is the only place the manager, the
 * successor and the team are named at all. The margin and the label padding go with it - both exist
 * to seat a drawing, and left behind they are 3.5rem and four ems of nothing under the buttons.
 *
 * 47.99rem, matching the boundary the rest of this file uses for a phone. */
@media (max-width: 47.99rem) {
	.oh-flow {
		margin-top: 0;
		padding-bottom: 0;
	}
	.oh-flow-stage {
		display: none;
	}
}

/* The two editors are the exception, in both places the stage is hidden: the phone rule above and
 * the short-window query below. A preview pane routinely reports one or the other - the Customizer's
 * is the screen less its controls - and the diagram's own strings are edited in there, two of them
 * through selective-refresh partials whose click-to-edit pencils live inside the stage. Hidden, they
 * would be unreachable exactly where they are meant to be used. Two classes against one, so this
 * wins on specificity wherever it sits in the file. Motion stays off: site.js leaves early in the
 * Elementor editor, and its width gate does not match a narrow preview. */
body.elementor-editor-active .oh-flow-stage,
body.oh-customize-preview .oh-flow-stage {
	display: grid;
}

/* ------------------------------------------------ Persistent call to action
 * The header CTA used to be hidden below 640px, so a phone visitor had 17 screens of page with
 * nothing to act on but the hamburger. It now shows at every width; on phones the logo falls back
 * to its mark and the pill tightens, which keeps the row clear of the menu button down to 320px.
 * Written here rather than as utilities: main.css is a compiled stylesheet that is never rebuilt,
 * so a class it does not already contain silently does nothing.
 */
@media (max-width: 39.99rem) {
	.oh-logo-word {
		display: none;
	}
	.oh-nav-cta {
		padding-inline: 0.875rem;
		padding-block: 0.5rem;
		font-size: 0.875rem;
		white-space: nowrap;
	}
}

/* ------------------------------------------------------- Cost slider target
 * The rail was 2px tall and the rail WAS the hit target: a range input's pointer area is its own
 * border box, so enlarging the thumb under a coarse pointer never widened it. The input now owns a
 * real box and the 2px rail is painted on the track, centred with a gradient so it holds at any
 * height. Keyboard control was already correct and is untouched.
 */
.cost-range {
	--oh-rail-h: 24px;
	height: var(--oh-rail-h);
	background: transparent;
	border-radius: 0;
}
.cost-range::-webkit-slider-runnable-track {
	height: var(--oh-rail-h);
	border-radius: 0;
	background: linear-gradient(
		to bottom,
		transparent calc(50% - 1px),
		#f6f3ee3d calc(50% - 1px),
		#f6f3ee3d calc(50% + 1px),
		transparent calc(50% + 1px)
	);
}
.cost-range::-moz-range-track {
	height: var(--oh-rail-h);
	border-radius: 0;
	background: linear-gradient(
		to bottom,
		transparent calc(50% - 1px),
		#f6f3ee3d calc(50% - 1px),
		#f6f3ee3d calc(50% + 1px),
		transparent calc(50% + 1px)
	);
}
.cost-range::-webkit-slider-thumb {
	margin-top: calc((var(--oh-rail-h) - 18px) / 2);
}
@media (pointer: coarse) {
	.cost-range {
		--oh-rail-h: 44px;
	}
	.cost-range::-webkit-slider-thumb {
		margin-top: calc((var(--oh-rail-h) - 24px) / 2);
	}
}

/* ------------------------------------------------ Twelve-column grids at large text
 * Eleven column gaps wider than the container collapse every track and drive column position from
 * gap arithmetic alone, which pushed the demo form off-screen. The gaps are rem-based, so a browser
 * text-size increase re-creates the same failure at desktop widths. Cap the column gap in px: at the
 * default root size min() picks the rem value, so nothing changes until the text is scaled up.
 */
@media (min-width: 48rem) {
	/* Scoped to the wide-gutter grids only. The teams cell grid is also grid-cols-12 but uses a 1px
	 * gap to draw its hairlines, and must never be widened. */
	[class*="md:grid-cols-12"][class*="md:gap-16"] {
		column-gap: min(4rem, 64px);
	}
	/* The footer grid carries its gap without a md: prefix. */
	[class*="md:grid-cols-12"][class*="gap-14"]:not([class*="md:gap-"]) {
		column-gap: min(3.5rem, 56px);
	}
}

/* At 200% text the nav row cannot fit on one line. Wrapping keeps every control reachable instead
 * of pushing the page into horizontal scroll; at normal sizes it still fits on one line. */
.nav-shell {
	flex-wrap: wrap;
	row-gap: 0.5rem;
}

/* ------------------------------------------------ The nav bar on a laptop, not a 27"
 * The desktop nav turns on at Tailwind's `lg:` (1024px) carrying the gap it was drawn with at 1400:
 * `gap-8`, a flat 32px between six items. Measured at 1024 with the shipped type: the row needs
 * 901px of a 915px track, so the two gutters either side of the nav come out at 7px each and the
 * shell wraps to a second line at 1010px - fourteen pixels below the width that turned the nav on.
 * Anything that moves the number moves it over: a 17px Windows scrollbar, a Customizer body scale
 * above 1, a browser at 110%. The wrap is the reflow safety net firing on a laptop at default text,
 * which is not what it is for.
 *
 * So the middle gets its own gap rather than the desktop one squeezed, the same way the twelve-column
 * grids below already get their own gutter: 20px at 1024, reaching 32px exactly at 1280, where the
 * shipped rules take over unchanged. That leaves 74px of slack at 1024 (37px per gutter) instead of
 * 14px, which is headroom for the scrollbar and the zoom level rather than a coincidence.
 *
 * In px on purpose, like the grid gutter above it: a fluid gap written in rem would grow with the
 * browser's text size and re-create the collapse the wrap rule exists to catch.
 */
@media (min-width: 64rem) and (max-width: 79.99rem) {
	nav[aria-label="Sections"] {
		column-gap: min(32px, max(20px, calc(20px + (100vw - 1024px) * 0.046875)));
	}
}

/* ------------------------------------------- The condensed shell's blur, on a layer of its own
 * `.nav-shell.is-condensed` carried `backdrop-filter: blur(14px)` in main.css. A backdrop-filter
 * makes the element a containing block for fixed-position descendants, and the shell is also a
 * scroll container (the reflow rule further down gives it `overflow-y: auto`). The Industries panel
 * is `position: fixed` and placed from viewport coordinates, so past 80px of scroll - every time a
 * visitor is actually reading - it resolved against the shell's padding box instead, landed below
 * the shell's own 72px clip box, and was cut away entirely. Measured on production at 1100px:
 * panel top 105, shell bottom 96, elementFromPoint through the middle of the panel returning the
 * hero behind it. The menu opened and nothing appeared.
 *
 * The blur and the condensed ground move to a layer behind the content, so the shell itself stays
 * an ordinary box and the panel keeps the viewport as its containing block - which is also what
 * frees it from the scroll container, since overflow only clips descendants it contains.
 *
 * Do not put filter, backdrop-filter, transform or will-change back on `.nav-shell`: any of them
 * re-creates this. And do not reach for `isolation: isolate` to place the layer - an isolated
 * ancestor cuts the backdrop off and the blur silently stops blurring.
 */
.nav-shell {
	position: relative;
}
.nav-shell.is-condensed {
	background-color: transparent;
	-webkit-backdrop-filter: none;
	backdrop-filter: none;
}
.nav-shell::before {
	content: "";
	position: absolute;
	z-index: -1;
	inset: 0;
	border-radius: inherit;
	pointer-events: none;
	transition: background-color 0.4s var(--ease-out-quart), backdrop-filter 0.4s var(--ease-out-quart);
}
.nav-shell.is-condensed::before {
	background-color: color-mix(in srgb, var(--ground) 84%, transparent);
	-webkit-backdrop-filter: blur(14px);
	backdrop-filter: blur(14px);
}

/* ---------------------------------------------------- Dark ground without JavaScript
 * The inline head script sets data-theme from storage or the OS. With JavaScript off no attribute
 * is ever set, so a system-dark visitor used to get the light page.
 *
 * The token half of that fallback — every value, plus the specimen's pin — is generated from
 * tokens/tokens.json now and reaches the page through main.css. It used to be a hand-kept mirror
 * of the scripted dark theme, and mirrors go stale: this copy had --ground-alt at #0a1015 while
 * main.src.css still said #0f171f. Only the rule below is left here, because it is a rule.
 */
@media (prefers-color-scheme: dark) {
	:root:not([data-theme]) .oh-nav-cta {
		border-color: var(--ink-muted);
	}
}

/* ------------------------------------------------------------ Why: the sources line
 * 258 characters of uppercase mono was the longest passage on the page and the hardest to read.
 * Same words, set as small text. The three figures it cites used to sit above it; they have their
 * own section now, but the prose in this column still quotes all three, so the citation stays.
 */
.oh-why-sources {
	margin-top: 1.5rem;
	max-width: 40ch;
	font-size: 0.8125rem;
	line-height: 1.6;
	color: var(--ink-faint);
}

/* ------------------------------------------------------ Why: one handover, four payoffs
 * Three sentences naming what the manager, the replacement and the team each receive used to be one
 * paragraph, then a hairline list inside the seven-column track. They are four now, cut by audience
 * rather than by artefact, and they close the section across its full width - because the reader is
 * one of these four people and should find their own row without reading the other three.
 *
 * Shell cards on the Chalk ground: the palette has five colours and white is not one of them, so the
 * lift comes from the ground's own second tone. The fourth card is the one most companies do not
 * expect, which is why it is the one that carries the mark in Coral.
 */
.oh-payoffs {
	margin-top: 4rem;
	border-top: 1px solid var(--rule-strong);
	padding-top: 2rem;
}
.oh-payoffs-eyebrow {
	color: var(--coral-ink);
}
.oh-payoffs-heading {
	max-width: 20ch;
}
.oh-payoff-grid {
	display: grid;
	gap: 1rem;
	margin: 2.5rem 0 0;
	padding: 0;
	list-style: none;
}
.oh-payoff {
	display: grid;
	grid-template-columns: 1.5rem minmax(0, 1fr);
	column-gap: 1rem;
	align-content: start;
	border-radius: 1.25rem;
	background: var(--ground-alt);
	padding: 1.75rem;
}
.oh-payoff--accent {
	box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--color-coral) 42%, transparent);
}
.oh-payoff-mark {
	grid-column: 1;
	grid-row: 1;
	line-height: 0;
	margin-top: 0.1rem;
}
.oh-payoff-mark svg {
	width: 1.5rem;
	height: 1.5rem;
	max-width: none;
}
.oh-payoff-audience {
	grid-column: 2;
	grid-row: 1;
	margin: 0;
	color: var(--ink-faint);
}
.oh-payoff--accent .oh-payoff-audience {
	/* Inside a Shell card, not on the Chalk ground the section sits on. */
	color: var(--coral-ink-paper);
}
.oh-payoff-title {
	grid-column: 2;
	margin-top: 0.875rem;
	font-size: 1.25rem;
	letter-spacing: -0.03em;
	line-height: 1.2;
	color: var(--ink);
}
.oh-payoff-body {
	grid-column: 2;
	margin: 0.625rem 0 0;
	max-width: 44ch;
	font-size: 0.9375rem;
	line-height: 1.6;
	color: var(--ink-muted);
}
@media (min-width: 48rem) {
	.oh-payoff-grid {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		gap: 1.25rem;
	}
}
/* The grid is a section of its own now (template-parts/section-payoffs.php). The top margin and the
 * hairline above belonged to a block sitting inside 'why', and the section that carries it brings its
 * own oh-rhythm. Undone here rather than by editing the rules above, because 'why' is parked and not
 * deleted: revive it and its markup must still be the markup those rules were written for. */
.oh-payoffs-section .oh-payoffs {
	margin-top: 0;
	border-top: 0;
	padding-top: 0;
}

/* ------------------------------------------------ The pain, when someone leaves: the opener
 * The headline's claim, in three photographs and three reasons. It took the slot the manifesto held
 * on /why-oakhive/; the sections it replaced are parked, not deleted (oakhive_parked_sections()).
 *
 * The collage is one tall frame beside two short ones rather than three equal tiles, because three
 * equal tiles read as a gallery - a set of things to look at - and this is one claim made three
 * times. The tall frame is the empty desk, which is the picture the sentence is about.
 *
 * The aspect ratio is on the grid and not on the frames: the frames then fill whatever the two
 * columns leave, so the collage can never disagree with the copy column's height by more than the
 * ratio, and a row whose photograph is missing simply does not draw rather than collapsing the rest.
 *
 * The marks are the brand hexagon stroked, with the glyph in Coral inside it. Ocean for the outline
 * and Coral for the glyph, rather than the other way round: the hexagon is the frame this whole site
 * draws things in, and Coral is reserved for the thing inside it that matters.
 */
.oh-pain-eyebrow {
	color: var(--coral-ink);
}
.oh-pain-heading {
	max-width: 18ch;
	/* The cap sets where the line can end; this sets where it should. While the section is one column
	 * the cap binds and the break is the cap's; once it splits in two the column is narrower than 18ch
	 * and the break was the container's, which is nobody's decision. */
	text-wrap: balance;
}
/* The lead's last line was "right away." on its own at 1440. */
.oh-pain-lead {
	text-wrap: pretty;
}
/* Both columns end on the same line.
 *
 * The collage sets the row's height - 636px wide at 1440, so 560px tall at its ratio - and the copy
 * needs 296px of it. The other 264px used to pile up under the lead as a hole, which is what made
 * the section look broken from across the room: a full column of photographs beside a column that
 * stops a third of the way down.
 *
 * The heading stays pinned to the top of the collage, because that shared line is the strongest
 * thing in the composition. The lead takes the slack instead and settles on the collage's bottom
 * edge, so the hairline below has two flush columns above it rather than one.
 *
 * No media query, deliberately. The rule has to hold exactly when the grid is two columns, and the
 * width at which THAT happens is not a number worth copying: measured on the live page, the section
 * grid is still one column at a client width of 889 and twelve at 1089, which is not where
 * `md:grid-cols-12` reads. A second guess at the breakpoint would be a third value to keep in step.
 * Free space is the honest signal instead: in one column the cell is as tall as its content, the
 * slack is zero, `auto` resolves to nothing and the lead sits where it always did.
 *
 * `padding-top` and not a margin, for the same reason: `margin-top: auto` eats the element's own
 * margin when there is no slack to take, and that would leave the lead against the heading.
 */
.oh-pain-copy {
	display: flex;
	flex-direction: column;
}
.oh-pain-copy .oh-pain-lead {
	margin-top: auto;
	padding-top: 2.5rem;
}
.oh-pain-collage {
	display: grid;
	grid-template-columns: 1.3fr 1fr;
	grid-template-rows: repeat(2, minmax(0, 1fr));
	gap: 0.75rem;
	aspect-ratio: 5 / 4.4;
}
.oh-pain-shot {
	margin: 0;
	overflow: hidden;
	border-radius: 1.25rem;
	/* Behind the picture while it loads, and behind the duotone's transparent tones after: the same
	 * ground every photograph on the site sits on. */
	background: var(--color-ocean);
}
.oh-pain-shot:first-child {
	grid-row: 1 / span 2;
}
.oh-pain-reasons {
	display: grid;
	gap: 2.5rem;
	/* Not a margin/padding shorthand: the element's own mt-16/pt-8 utilities set those, and theme.css
	 * is unlayered, so a shorthand here would quietly win and take the hairline's air with it. */
	padding-left: 0;
	list-style: none;
}
.oh-pain-mark {
	display: block;
	line-height: 0;
}
.oh-pain-mark svg {
	width: 3.25rem;
	height: auto;
	max-width: none;
}
.oh-pain-hex {
	fill: none;
	stroke: var(--color-ocean);
	stroke-width: 3;
	stroke-linejoin: round;
}
:root[data-theme="dark"] .oh-pain-hex {
	/* Ocean on the dark ground is a silhouette of itself; this is the rung the flow diagram steps to. */
	stroke: var(--color-ocean-100);
}
.oh-pain-glyph {
	fill: none;
	stroke: var(--color-coral);
	stroke-width: 3.2;
	stroke-linecap: round;
	stroke-linejoin: round;
}
/* The reason's name, in the role this site already has for the title of a three-up item: the
 * 1.25rem / -0.03em / 1.2 that .oh-payoff-title carries four rows further down THIS page. Weight
 * comes from `font-display font-black` on the element, the same way the payoff titles take it.
 *
 * It used to be .tracked-caps, which is the kicker tier: 11px of mono capitals in Coral. So the row
 * named its three ideas in the smallest type in the section and set each name below the picture of
 * it - mark 52px, name 11px, sentence 15px. The only thing the eye could rank was the decoration,
 * and the three reasons read as three captions rather than three claims.
 *
 * Ink, not Coral. The Coral in this row is the glyph inside each hexagon, which is where the note at
 * the top of this block says it belongs; a Coral title made three of them and left the row with no
 * colour hierarchy at all.
 */
.oh-pain-label {
	margin: 1.25rem 0 0;
	font-size: 1.25rem;
	letter-spacing: -0.03em;
	line-height: 1.2;
	color: var(--ink);
}
.oh-pain-body {
	margin: 0.625rem 0 0;
	/* 44ch, which is what .oh-payoff-body reads at. At 34ch all three sentences broke with two or
	 * three words alone on the last line at every width from 1024 up. */
	max-width: 44ch;
	font-size: 0.9375rem;
	line-height: 1.6;
	color: var(--ink-muted);
	text-wrap: pretty;
}
@media (min-width: 48rem) {
	.oh-pain-reasons {
		grid-template-columns: repeat(3, minmax(0, 1fr));
		gap: 3rem;
	}
}

/* ------------------------------------------------------ Do the math: the benchmark
 * Three published figures, then the profession's own cost formula with the one term nobody prices.
 *
 * Coral does the pointing here and it does it twice, which is once more than the palette likes - so
 * the two are different weights of the same job: the figures are large type and take the darkened
 * Coral that clears 3:1 on this ground, and the last plaque takes brand Coral as a fill, which is
 * what the eye lands on last and remembers.
 *
 * The terms are a wrapping row rather than a grid: seven plaques fit one line at full width and have
 * to break cleanly at every width below it, which a fixed column count cannot do.
 */
/* Everything Coral in this section sets type on --ground-alt, where --coral-ink measures 3.99:1.
 * --coral-ink-paper is the rung below it, cut for exactly this ground. */
.oh-math-eyebrow {
	color: var(--coral-ink-paper);
}
.oh-math-heading {
	max-width: 26ch;
}
.oh-math-stats {
	display: grid;
	gap: 2.5rem;
	margin: 3.5rem 0 0;
}
.oh-math-stat {
	/* Stacked, each figure is separated from the one above it; in a row they are separated from each
	 * other, which is a different line in a different place. */
	border-top: 1px solid var(--rule);
	padding-top: 1.5rem;
}
.oh-math-figure {
	font-size: clamp(2.5rem, 5vw, 3.5rem);
	letter-spacing: -0.045em;
	line-height: 1;
	color: var(--coral-ink-paper);
}
.oh-math-label {
	margin: 1rem 0 0;
	max-width: 30ch;
	font-size: 1rem;
	line-height: 1.5;
	color: var(--ink);
}
.oh-math-source {
	margin: 0.75rem 0 0;
	font-family: var(--font-mono);
	font-size: 0.75rem;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--ink-faint);
}
.oh-math-formula {
	margin-top: 4rem;
}
.oh-math-formula-label {
	color: var(--ink-faint);
}
/* The comb. Six known costs around the one nobody prices, which is the only Coral in the section and
 * the thing the sentence under it is about.
 *
 * One markup, two layouts. Wide, the cells are placed on a ring by the percentages PHP computed for
 * them and the whole thing is a square. Narrow, there is no width for a ring, so the same cells flow
 * as a two-column grid in the formula's own order - the six terms, then the one they surround, which
 * is how the line reads aloud anyway. Nothing is duplicated in the DOM to get that.
 *
 * The hexagons are the brand's orientation: a point at the top and flat sides left and right, which
 * is the aperture every other mark on the site is cut from. 1 / 1.1547 is what makes that regular.
 */
.oh-hive {
	margin-top: 1.5rem;
}
.oh-hive-ring {
	/* The fill is a property the cells inherit rather than a rule matched per cell, so the centre's
	 * own Coral cannot be out-specified by a ground override further down - which is exactly what the
	 * dark rule below did to it when both were written as descendant selectors. */
	--oh-hive-fill: var(--color-ocean);
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 0.5rem;
	margin: 0;
	/* Capped, because this two-column fallback runs all the way up to the 48rem the ring starts at.
	 * Uncapped, a 760px column gives each hexagon 335px of width to hold a thirteen-pixel label, and
	 * the comb stops being a comb and becomes six navy signs. */
	max-width: 20rem;
	padding: 0;
	list-style: none;
}
.oh-hive-hex {
	position: relative;
	z-index: 1;
	display: grid;
	place-items: center;
	aspect-ratio: 1 / 1.1547;
	clip-path: polygon(50% 0, 100% 25%, 100% 75%, 50% 100%, 0 75%, 0 25%);
	background: var(--oh-hive-fill);
	/* The waist is the widest the term may be, and the points are not: padding keeps a long one off
	 * the two sloping edges instead of letting it collide with them. */
	padding: 0 14%;
	text-align: center;
}
.oh-hive-name {
	font-size: clamp(0.6875rem, 1.05vw, 0.8125rem);
	line-height: 1.25;
	letter-spacing: -0.005em;
	color: var(--color-chalk);
}
.oh-hive-cell--core {
	--oh-hive-fill: var(--color-coral);
}
.oh-hive-cell--core .oh-hive-name {
	font-weight: 700;
	color: var(--color-slate);
}
/* The centre is the one that is not settled, so it is the one with a shadow under it. drop-shadow and
 * not box-shadow: the hexagon is a clip, and box-shadow would draw the square the clip cut it from. */
.oh-hive-cell--core .oh-hive-hex {
	filter: drop-shadow(0 8px 18px color-mix(in srgb, var(--color-slate) 26%, transparent));
}
/* The centre's reach into the comb. Exactly the size of the hexagon over it while the comb is closed,
 * so there is nothing to see until it opens. */
.oh-hive-halo {
	display: none;
}
:root[data-theme="dark"] .oh-hive-ring {
	/* This section's ground is the Shell, which in the dark is a step below the Slate the palette's
	 * Ocean already sits next to: unlifted, the six would be a shape you have to look for. The centre
	 * keeps its Coral, because it sets the value on itself and this one only sets the inherited default. */
	--oh-hive-fill: color-mix(in srgb, var(--color-ocean) 82%, var(--color-chalk));
}
.oh-math-note {
	margin: 1.25rem 0 0;
	max-width: 52ch;
	font-size: 0.875rem;
	line-height: 1.5;
	color: var(--coral-ink-paper);
}
.oh-math-closing {
	margin: 3.5rem 0 0;
	max-width: 42rem;
	font-size: clamp(1.25rem, 1.9vw, 1.75rem);
	letter-spacing: -0.03em;
	line-height: 1.25;
	color: var(--ink);
}
.oh-math-footnote {
	margin: 1.5rem 0 0;
	max-width: 52ch;
	font-size: 0.8125rem;
	line-height: 1.6;
	color: var(--ink-faint);
}
@media (min-width: 48rem) {
	.oh-math-stats {
		grid-template-columns: repeat(3, minmax(0, 1fr));
		gap: 2.5rem 3rem;
	}
	.oh-math-stat {
		border-top: 0;
		padding-top: 0;
	}
	.oh-math-stat + .oh-math-stat {
		border-left: 1px solid var(--rule);
		padding-left: 3rem;
		margin-left: -1.5rem;
	}
	/* The ring. Every cell carries its own seat as two percentages, so nothing here has to know how
	 * many of them there are; the core has no seat and falls back to the middle. --oh-hive-drift is
	 * how far that cell has travelled out along its own radius, and it is the only thing the opening
	 * below changes: the seat, the direction and the bearing are all authored in the markup. */
	.oh-hive-ring {
		position: relative;
		display: block;
		aspect-ratio: 1;
		max-width: 30rem;
	}
	.oh-hive-cell {
		--oh-hive-drift: 0px;
		position: absolute;
		left: var(--oh-hive-x, 50%);
		top: var(--oh-hive-y, 50%);
		width: 30%;
		transform: translate(
			calc(-50% + var(--oh-hive-dx, 0) * var(--oh-hive-drift)),
			calc(-50% + var(--oh-hive-dy, 0) * var(--oh-hive-drift))
		);
	}

	/* ------------------------------------------------------------------ the comb opens
	 * At rest this is a closed comb: the six touch, and there is nothing between them. Pointed at, the
	 * six drift out along their own radii and the centre grows into every gap that opens at once,
	 * which is the sentence under the drawing - the one term nobody prices is in all the spaces
	 * between the six that everybody does.
	 *
	 * The reach is the halo and not six spokes to the centre. Spokes were built first and cut: a closed
	 * comb leaves three pixels between the top hexagon and the middle one, so the only part of a spoke
	 * ever left uncovered is a hairline nobody sees. The halo has the whole gap.
	 *
	 * Emphasis is a promotion and never a demotion. Nothing dims when its neighbour is pointed at,
	 * because a dimmed cell is a Chalk label on a washed-out Ocean, and that is a contrast failure in a
	 * state nobody screenshots. The hovered cell travels further and takes a step towards Lagoon - both
	 * additions.
	 */
	.oh-hive-halo {
		display: block;
		position: absolute;
		inset: 0;
		z-index: 0;
		clip-path: polygon(50% 0, 100% 25%, 100% 75%, 50% 100%, 0 75%, 0 25%);
		background: var(--color-coral);
		transform: scale(1);
		opacity: 0;
	}
	.oh-hive:hover .oh-hive-cell {
		--oh-hive-drift: 9px;
	}
	/* Far enough to reach past the six, which is what puts Coral in every gap rather than in the six
	 * wedges nearest the middle. It sits under all of them, so the reach only ever shows where the comb
	 * has actually opened. */
	.oh-hive:hover .oh-hive-halo {
		transform: scale(1.95);
		opacity: 0.2;
	}
	.oh-hive-cell:hover {
		--oh-hive-drift: 18px;
	}
	/* The six rise; the centre never does. Raising the centre makes its cell a stacking context above
	 * the ring, and the halo inside it goes up with it - so the reach that is supposed to come through
	 * the gaps washes over the six instead, and the comb goes muddy. It has nothing to rise above
	 * anyway: the six travel away from it, not across it. */
	.oh-hive-cell:not(.oh-hive-cell--core):hover {
		z-index: 2;
	}
	/* The six, and not the one in the middle. .oh-hive-cell--core is an .oh-hive-cell, so written
	 * without the :not() this repainted the centre from Coral to a Lagoon-tinted Ocean while its label
	 * stayed Slate - about 1.5:1, on the one cell the whole drawing is about. Coral is that cell's
	 * identity and its contrast at the same time; it never changes hue for a pointer. */
	.oh-hive-cell:not(.oh-hive-cell--core):hover .oh-hive-hex {
		--oh-hive-fill: color-mix(in srgb, var(--color-ocean) 82%, var(--color-lagoon));
	}
	/* The centre answers differently because it cannot answer the same way: it has no seat on the ring
	 * and no radius to travel along, so it grows where the six move. Scale and the halo only - nothing
	 * that touches the fill under that Slate label. */
	.oh-hive-cell--core:hover .oh-hive-hex {
		transform: scale(1.07);
	}
	.oh-hive-cell--core:hover .oh-hive-halo {
		transform: scale(2.2);
		opacity: 0.3;
	}
	/* Everything above is a change of state, so it is the states that carry the easing - and only where
	 * motion is welcome. With reduced motion the comb still opens; it just arrives there. */
	@media (prefers-reduced-motion: no-preference) {
		.oh-hive-cell,
		.oh-hive-hex,
		.oh-hive-halo {
			transition: transform 0.55s var(--ease-out-quart), opacity 0.4s var(--ease-out-quart),
				background-color 0.4s var(--ease-out-quart);
		}
	}
}
/* Beside the label and the note rather than under them, which is the composition the comp draws and
 * also the only width at which a 30rem ring and a 52ch sentence both fit on one screen. The label sits
 * at the foot of its row and the note at the head of the next, so the pair meets the ring's middle. */
@media (min-width: 64rem) {
	.oh-math-formula {
		display: grid;
		grid-template-columns: minmax(0, 1fr) minmax(18rem, 30rem);
		grid-template-rows: auto auto;
		column-gap: 4rem;
	}
	.oh-math-formula-label {
		grid-column: 1;
		grid-row: 1;
		align-self: end;
	}
	.oh-math-note {
		grid-column: 1;
		grid-row: 2;
		align-self: start;
	}
	.oh-hive {
		grid-column: 2;
		grid-row: 1 / span 2;
		margin-top: 0;
	}
}

/* --------------------------------------------- See it in action: the interview, drawn
 * Step two of the roadmap, shown. The window is not a screenshot and does not pretend to be one: it
 * is the same kind of drawing the day-one artefacts use, in the site's five colours rather than the
 * product's neighbouring ones, and a capture uploaded to the widget replaces it outright.
 *
 * The stage is 16:10 because the product's is, and it is empty on purpose - a drawn face would be a
 * lie, and a play button over a still that plays nothing is worse than no button. What it carries
 * instead are the two things the window actually shows while someone is talking: who is on the other
 * side, and whose turn it is.
 */
.oh-action-eyebrow {
	color: var(--coral-ink);
}
.oh-action-heading,
.oh-action-lead {
	max-width: 34ch;
}
.oh-action-lead {
	max-width: 52ch;
}
.oh-action-stage {
	margin-top: 3.5rem;
}
.oh-action-caption {
	margin: 2rem 0 0;
	max-width: 52ch;
	font-size: 1rem;
	line-height: 1.6;
	color: var(--ink-muted);
}
/* The interview window: a video stage with the call's own chrome, and the transcript beside it.
 * These rules were dropped once, when the stage and the turns were replaced by a prose paragraph,
 * and are back with the markup that uses them. The stage is the placeholder a real capture set on
 * the section replaces (see template-parts/section-action.php). */
.oh-room {
	display: grid;
	gap: 2rem;
	border: 1px solid var(--rule);
	border-radius: 1.5rem;
	background: var(--ground-alt);
	padding: 1.25rem;
}
.oh-room-stage {
	position: relative;
	display: block;
	aspect-ratio: 16 / 10;
	border-radius: 1.125rem;
	/* The putty the product puts behind its picture, mixed here from ink and ground rather than from
	 * --color-shell-shade: that token is declared in the brand palette but absent from the compiled
	 * stylesheet, because nothing had used it. Mixing also means the stage darkens with the theme
	 * instead of staying a light grey on the dark ground. */
	background: color-mix(in srgb, var(--ink) 14%, var(--ground-alt));
}
.oh-room-pill {
	position: absolute;
	display: flex;
	align-items: center;
	gap: 0.5rem;
	margin: 0;
	border-radius: 999px;
	font-size: 0.75rem;
	line-height: 1.2;
	white-space: nowrap;
}
.oh-room-pill--who {
	top: 1rem;
	left: 1rem;
	background: color-mix(in srgb, var(--color-slate) 62%, transparent);
	padding: 0.45rem 0.85rem;
	color: var(--color-chalk);
}
.oh-room-pill--turn {
	bottom: 1rem;
	left: 50%;
	transform: translateX(-50%);
	background: var(--color-chalk);
	padding: 0.55rem 1rem;
	font-weight: 700;
	color: var(--color-slate);
	box-shadow: 0 4px 16px color-mix(in srgb, var(--color-slate) 16%, transparent);
}
.oh-room-dot {
	width: 0.5rem;
	height: 0.5rem;
	border-radius: 50%;
	background: var(--color-coral);
}
.oh-room-controls {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: center;
	gap: 0.75rem;
}
.oh-room-key {
	width: 2.25rem;
	height: 2.25rem;
	border: 1px solid var(--rule-strong);
	border-radius: 50%;
}
.oh-room-rule {
	width: 1px;
	height: 1.5rem;
	background: var(--rule-strong);
}
.oh-room-end {
	border: 1.5px solid var(--coral-ink-paper);
	border-radius: 999px;
	padding: 0.5rem 1.1rem;
	font-size: 0.8125rem;
	font-weight: 700;
	color: var(--coral-ink-paper);
}
.oh-room-reassure {
	margin: -1rem 0 0;
	text-align: center;
	font-size: 0.8125rem;
	color: var(--ink-faint);
}
.oh-room-transcript-head {
	margin: 0 0 1.25rem;
	color: var(--ink-faint);
}
.oh-room-turn {
	margin-top: 1.25rem;
}
.oh-room-turn:first-of-type {
	margin-top: 0;
}
/* The left bar marks what the person leaving said, which is the half of the conversation the whole
 * product is there to keep. It is the product's own treatment, and the one place a 2.5px coloured
 * edge is the design rather than a decoration borrowed from a card. */
.oh-room-turn--you {
	border-left: 2.5px solid var(--color-coral);
	padding-left: 0.875rem;
}
.oh-room-who {
	margin: 0 0 0.35rem;
	color: var(--ink-faint);
}
.oh-room-turn--you .oh-room-who {
	color: var(--coral-ink-paper);
}
.oh-room-said {
	margin: 0;
	max-width: 46ch;
	font-size: 0.9375rem;
	line-height: 1.55;
	color: var(--ink);
}
@media (min-width: 64rem) {
	.oh-room {
		grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
		gap: 2.5rem;
		padding: 1.5rem;
	}
	.oh-room-stage {
		grid-column: 1;
	}
	.oh-room-controls,
	.oh-room-reassure {
		grid-column: 1;
	}
	.oh-room-transcript {
		grid-column: 2;
		grid-row: 1 / -1;
		align-self: start;
	}
}

/* ---------------------------------------------------------- Reading measure
 * main.css sets `.measure { max-width: 68ch }`, which sounds right and is not. The `ch` unit is the
 * width of the font's "0", and Satoshi's figures are wide: 68ch computes to ~790px, and 790px of
 * this body copy actually sets 93-99 characters a line, well past the 65-75 a reader wants. `em` is
 * independent of glyph metrics, and 33em measures ~71 characters in this face at every size the
 * class is used at. Measured, not guessed: the body text runs 0.461em per character.
 */
.measure {
	max-width: 33em;
}

/* --------------------------------------------------------- Coral that carries type
 * Brand coral is #EC806B, which measures 2.41:1 on the cream ground: fine as a mark or a rule,
 * a contrast failure the moment it sets type, even at 44px/900 where the bar is only 3:1.
 * Use --coral-ink wherever coral is the text; keep --color-coral for marks, rules and fills.
 *
 * Both values come from tokens/tokens.json now. The static copy that used to sit here said
 * #ce381a, but oakhive_text_safe('#EC806B') returns #CD371A and oakhive_design_css() is appended
 * after this stylesheet, so #CD371A is what the page has always rendered. Two declarations of one
 * derived value, and only one of them was ever true.
 */

/* The navy pill measures 1.34:1 against the dark ground, so the control's own boundary vanishes
 * even though its label reads at 11.86:1. A hairline restores the edge and leaves the CTA colour
 * hierarchy alone: coral stays the body primary, navy the persistent one. The transparent border
 * is declared in both themes so switching theme never shifts the layout by 2px.
 */
.oh-nav-cta {
	border-width: 1px;
	border-style: solid;
	border-color: transparent;
}
:root[data-theme="dark"] .oh-nav-cta {
	border-color: var(--ink-muted);
}

/* ================================================================= The page's ground bands
 * Home read as one colour from the hero to the form. Two independent causes.
 *
 * The ladder had no rungs. In dark, --ground is #111a22 and --ground-alt was #0f171f: a contrast of
 * 1.028:1, two or three units on a channel. A section could alternate correctly and still be
 * invisible doing it. Light was never broken - chalk against shell measures 1.132:1 - so only the
 * dark values move, and they move to the step light already had.
 *
 * And cutting Home to six sections left two adjacent pairs holding the same token. That is fixed
 * under body.home below, not by editing the section templates: section-roadmap.php and
 * section-trust.php render other pages too, and those pages have their own neighbours.
 *
 * The ladder, measured against #111a22: --ground-alt sits 1.10:1 below it, --ground-band 1.10:1
 * above, ocean 1.30:1 above. Every adjacent pair on Home clears 1.10, and the deep-to-band step
 * where teams meets the process runs 1.21. Band is slate carried toward ocean and alt is slate
 * carried down, so both stay on the palette's own axis instead of going grey.
 *
 * Deepening --ground-alt widens every other surface drawn on it - the mobile nav's hover, the
 * capture frames on the act pages - in the direction that helps. The one place it must not move is
 * the interview specimen, which is being worked on elsewhere: it pins the old value locally and
 * renders exactly as it did.
 */
/* The three values that repair it, and the specimen's pin, are generated from
 * tokens/tokens.json now. tokens.json also carries the 1.08:1 floor as a build-time
 * check, so the ladder cannot lose its rungs again without the build saying so. */

/* Home's order: ground, deep, band, ground, ground, ocean. #trust keeps #action's ground on
 * purpose - it is a 145px strip carrying one sentence, and a colour of its own would read as an
 * offcut rather than a section. */
body.home .oh-roadmap {
	background: var(--ground-band);
}

/* The fourth cell closed the mosaic on the same colour as the third, with a 1px hairline between
 * them, so the bottom of the block read as one mass and the four peers stopped looking like peers.
 * It takes the band instead: slate, ocean, ground, band - four cells, four surfaces. */
.oh-cell--band {
	background: var(--ground-band);
}

/* ============================================================ Customizer-driven design
 * Everything below is driven from Appearance > Customize > "OakHive: design". The Customizer writes
 * these three numbers and the palette; nothing here should need editing by hand again. Display sizes
 * live as tier variables so a single scale moves every heading at once and the inline styles in the
 * templates stay overridable, which a plain stylesheet rule could not do.
 *
 * Which tier a heading takes, written down because it had drifted: a section <h2> is --oh-display-2
 * with letter-spacing -0.042em. It steps down to --oh-display-3, keeping the H2 tracking, only when
 * it sits in a track narrower than half the page - today that is #demo's md:col-span-5 form column,
 * 519px at 1440, where display-2 would break its three authored lines into four. --oh-display-3 with
 * -0.04em AND an explicit line-height is a different recipe: it is the card title (why's h3, the
 * teams lead's h3), and it must never appear on an <h2>. It had, on three - action, math and
 * payoffs - because section-payoffs.php was lifted out of section-why.php and its new <h2> kept the
 * <h3>'s style verbatim. #action is corrected; math and payoffs live on other pages and follow in a
 * pass of their own.
 */
:root {
	--oh-type-h: 1;
	--oh-type-body: 1;
	--oh-content-max: 1400px;
	--oh-display-1: clamp(calc(2.6rem * var(--oh-type-h)), calc(7.2vw * var(--oh-type-h)), calc(5.5rem * var(--oh-type-h)));
	--oh-display-2: clamp(calc(2.25rem * var(--oh-type-h)), calc(4.6vw * var(--oh-type-h)), calc(4rem * var(--oh-type-h)));
	--oh-display-3: clamp(calc(1.875rem * var(--oh-type-h)), calc(3.6vw * var(--oh-type-h)), calc(3rem * var(--oh-type-h)));
	--oh-display-4: clamp(calc(1.5rem * var(--oh-type-h)), calc(2.6vw * var(--oh-type-h)), calc(2.25rem * var(--oh-type-h)));
	/* The section eyebrow: the coral mono line that introduces a section heading. Five of them ship -
	 * hero, action, math, pain, payoffs - and until now the hero carried a hand-set size while the
	 * other four fell through to the .tracked-caps default, 15px against 11px for one role. The value
	 * here is the hero's, unchanged, because that size was a recorded decision: the client read the
	 * line as losing the hero to the max-weight H1 beneath it. Tracking eases off as the size goes up,
	 * which is why the pair travels together.
	 *
	 * The other tier - card kickers, step labels, form labels, captions - stays at .tracked-caps's own
	 * 0.6875rem / 0.16em and is deliberately not restated here. main.css is never rebuilt, but it is
	 * still that class's home, and a second copy of the number is exactly what this file keeps warning
	 * against. Neither tier runs through --oh-type-h, because .tracked-caps does not either: scaling
	 * one and not the other would put the drift straight back at every non-default text scale. */
	--oh-eyebrow: clamp(0.8125rem, 1.05vw, 0.9375rem);
	--oh-eyebrow-track: 0.13em;
}

/* Two classes, so this beats the unlayered .tracked-caps on specificity and not only on the order the
 * two stylesheets happen to load in. Colour is left with each section: the ground differs - the pages
 * set --coral-ink on --ground and --coral-ink-paper on --ground-alt - but the size does not. */
.oh-hero-eyebrow.tracked-caps,
.oh-action-eyebrow.tracked-caps,
.oh-math-eyebrow.tracked-caps,
.oh-pain-eyebrow.tracked-caps,
.oh-payoffs-eyebrow.tracked-caps {
	font-size: var(--oh-eyebrow);
	letter-spacing: var(--oh-eyebrow-track);
}

/* Body copy. These attribute selectors are unlayered, so they beat the compiled Tailwind utilities
 * on tie without !important, and they scale the size the utility would have set. */
[class*="text-[1.5rem]"] {
	font-size: calc(1.5rem * var(--oh-type-body));
}
[class*="text-[1.0625rem]"] {
	font-size: calc(1.0625rem * var(--oh-type-body));
}
[class*="text-[0.9375rem]"] {
	font-size: calc(0.9375rem * var(--oh-type-body));
}
[class*="text-[0.875rem]"] {
	font-size: calc(0.875rem * var(--oh-type-body));
}

/* Content width. */
[class*="max-w-[1400px]"] {
	max-width: var(--oh-content-max);
}

/* The hero body was capped in rem, so scaling the body text down left the box the same width and
 * pushed the line past 85 characters. em tracks the text, which is what a measure has to do. */
[data-hero-body][class*="max-w-[38rem]"] {
	max-width: 34em;
}

/* Section rhythm and fonts, both Customizer-driven. The rhythm keys off a class of its own rather
 * than the Tailwind padding utilities: an attribute match on "py-28" would also catch "md:py-28",
 * and a base rule would then beat the responsive one at every width. */
:root {
	--oh-space: 1;
}
.oh-rhythm {
	padding-block: calc(7rem * var(--oh-space));
}
.oh-rhythm--stage {
	padding-block: calc(6rem * var(--oh-space));
}
.oh-rhythm--tall {
	padding-block: calc(8rem * var(--oh-space));
}
@media (min-width: 48rem) {
	.oh-rhythm {
		padding-block: calc(10rem * var(--oh-space));
	}
	.oh-rhythm--stage {
		padding-block: calc(8rem * var(--oh-space));
	}
	.oh-rhythm--tall {
		padding-block: calc(16rem * var(--oh-space));
	}
}

/* Optional per-section picture from the Customizer. Nothing here applies until one is chosen. */
.oh-section-figure {
	margin: 4rem 0 0;
}
.oh-section-figure img {
	display: block;
	width: 100%;
	height: auto;
	border-radius: 1.5rem;
}
.oh-section-caption {
	margin-top: 1rem;
	color: var(--ink-faint);
}
.on-ocean .oh-section-caption,
section.bg-ocean .oh-section-caption {
	color: var(--color-ocean-100);
}
@media (min-width: 48rem) {
	.oh-section-figure {
		margin-top: 5rem;
	}
}

/* Skip-link target: focusable without a page-sized outline. */
main[tabindex="-1"]:focus {
	outline: none;
}

/* Header and footer buttons: 44px hit area around the 40px visual, every viewport. The ground
 * toggle moved out of the header and into the footer's bottom bar; .oh-hit already carries the same
 * shim unscoped, so this is belt and braces rather than the only thing holding the target up. */
footer button[aria-pressed],
header button[aria-controls="mobile-nav"] {
	position: relative;
}
footer button[aria-pressed]::before,
header button[aria-controls="mobile-nav"]::before {
	content: "";
	position: absolute;
	inset: -2px;
	border-radius: inherit;
}

/* The footer's bottom bar: the ground toggle sits with the copyright, the legal line stays right.
 * The row was baseline-aligned for two paragraphs; with a 40px control in it, centre is the only
 * alignment that does not leave the button hanging off the text's baseline. */
.oh-footer-bottom-left {
	display: flex;
	align-items: center;
	gap: 1rem;
}
@media (min-width: 40rem) {
	.oh-footer-bottom {
		align-items: center;
	}
}

/* Touch pointers: currency chips reach 44px, slider thumbs 24px. */
@media (pointer: coarse) {
	#cost [role="group"][aria-label="Currency"] button {
		min-height: 44px;
	}
	.cost-range::-webkit-slider-thumb {
		width: 24px;
		height: 24px;
	}
	.cost-range::-moz-range-thumb {
		width: 24px;
		height: 24px;
	}
}

/* Phones: text controls 44px tall (the textarea already is). */
@media (max-width: 47.99rem) {
	form[data-demo-form] input:not(.oh-hp),
	form[data-demo-form] select {
		min-height: 44px;
	}
}

/* Focused field: the 1px hairline plus a 1px shadow makes a 2px coral rule, no layout shift. */
form[data-demo-form] input:not(.oh-hp):focus,
form[data-demo-form] select:focus,
form[data-demo-form] textarea:focus {
	box-shadow: 0 1px 0 0 var(--color-coral);
}

/* Inline field errors (coral on ocean, 4.9:1). */
.oh-field-error {
	margin-top: 0.5rem;
	font-size: 0.875rem;
	line-height: 1.4;
	color: var(--color-coral);
}
form[data-demo-form] [aria-invalid="true"] {
	border-color: var(--color-coral);
}

/* Current section in the desktop nav: the hover underline, held. */
nav[aria-label="Sections"] a[aria-current] {
	color: var(--ink);
}
nav[aria-label="Sections"] a[aria-current]::after {
	width: 100%;
}

/* Rail markers are buttons that jump to their act; preflight gives buttons no cursor and centred text. */
[data-act-marker] {
	cursor: pointer;
	text-align: left;
}

/* Reduced motion: the pinned stage never plays, so acts 2 and 3 must not sit on top of act 1. */

/* ------------------------------------------------- How it works: the connected journey
 * The brand's symbol graph, walked as a path. Wide screens run it left to right: an even band of
 * connected nodes with each step's copy under its own node. Below 1280px four columns get too
 * narrow to read, so the same path turns vertical and the copy sits beside it. Connectors are SVG
 * lines with a non-scaling stroke, so the 2px Slate-12% hairline holds at any width. Both ends of
 * every connector are pulled back by the radius of the mark they join, so the line meets each ring
 * instead of crossing the transparent hexagon at its centre. Nodes step down the tint ladder; the
 * last one is Coral, and it is the only one.
 *
 * Three tints, not four: four steps means three of them are unaccented, and a ladder longer than
 * the run it colours just leaves a rung nothing ever lands on.
 */
.oh-roadmap {
	--oh-tint-1: var(--color-ocean);
	--oh-tint-2: var(--color-ocean-200);
	--oh-tint-3: var(--color-lagoon);
}
:root[data-theme="dark"] .oh-roadmap {
	--oh-tint-1: var(--color-ocean-100);
	--oh-tint-2: var(--color-ocean-200);
	--oh-tint-3: var(--color-lagoon);
}

.oh-journey {
	/* The rail is an indent, so at 200% text it took 184px of a 390px phone and left the step titles
	 * 126px to live in. The vw ceilings are above the rem value at every default-text width, so they
	 * bind only once the text has outgrown the viewport - the mark and the indent share the same
	 * variable and stay aligned either way. */
	--oh-rail: min(4.5rem, 22vw);
	--oh-node: min(2.5rem, 12vw);
	--oh-gap: min(1.25rem, 6vw);
	--oh-top: 0.25rem;
	list-style: none;
	padding: 0;
}
.oh-journey-step {
	/* radius of this step's mark and of the next one, both as a share of --oh-node */
	--oh-rad: calc(var(--oh-node) * var(--oh-r, 0.5));
	--oh-rad-next: calc(var(--oh-node) * var(--oh-r-next, 0.5));
}
.oh-journey-line {
	overflow: visible;
	/* the preflight puts max-width:100% on every svg, which would clip the connector at the column edge */
	max-width: none;
	stroke: var(--rule);
	stroke-width: 2;
	stroke-linecap: round;
}
.oh-journey-node svg {
	width: var(--oh-node);
	height: var(--oh-node);
	max-width: none;
	transition: transform 0.6s var(--ease-out-quart);
}
.oh-journey-step--accent .oh-journey-node svg {
	width: calc(var(--oh-node) * 1.4);
	height: calc(var(--oh-node) * 1.4);
}
/* The step number, set inside the mark's hexagonal aperture. The aperture is a regular hexagon with
 * its vertices at 33 of the 100 viewBox units, so its inscribed circle is 28.6 across - room for the
 * single digit the steps are numbered with, and still room should a run ever reach ten. It is
 * painted in ink rather than a fixed colour because the aperture is transparent: what sits behind it
 * is the section ground, in either theme. The accent node scales up, and its number scales with it -
 * which is the emphasis, not a bug.
 */
.oh-journey-num {
	fill: var(--ink);
	font-family: var(--font-display);
	font-size: 30px;
	font-weight: 900;
	letter-spacing: -0.04em;
}
.oh-journey-title {
	font-size: clamp(1.5rem, 2.6vw, 2.25rem);
	letter-spacing: -0.04em;
	max-width: 18ch;
}
.oh-journey-body {
	font-size: 1.0625rem;
	line-height: 1.62;
	/* Not 68ch: `ch` is the width of Satoshi's zero, which is wide, so 68ch computes to about 790px
	 * and sets 90-odd characters to a line. `em` is glyph-independent, the same correction `.measure`
	 * carries against main.css. */
	max-width: 33em;
}
.oh-journey-closing {
	margin-top: 3rem;
	max-width: 46rem;
	font-size: clamp(1.25rem, 1.9vw, 1.75rem);
	letter-spacing: -0.03em;
	line-height: 1.25;
}
/* The short version's way on, in place of the coral button. A link and not a button on purpose: the
 * page it sits on already ends with the booking form, and a second filled CTA halfway up competes
 * with the ask instead of leading to it. The arrow is the one the nav panel uses for "All
 * industries", so "there is more of this over here" looks the same wherever the site says it. */
.oh-journey-more {
	display: inline-flex;
	align-items: center;
	gap: 0.5rem;
	font-size: 1.0625rem;
	font-weight: 700;
	color: var(--ink);
	text-decoration: underline;
	text-decoration-color: transparent;
	text-decoration-thickness: 1px;
	text-underline-offset: 5px;
	transition: text-decoration-color 0.3s var(--ease-out-quart);
}
.oh-journey-more:hover {
	text-decoration-color: var(--color-coral);
}
.oh-journey-more svg {
	width: 16px;
	height: 16px;
	color: var(--color-coral);
	transition: transform 0.3s var(--ease-out-quart);
}
.oh-journey-more:hover svg {
	transform: translateX(3px);
}
@media (prefers-reduced-motion: reduce) {
	.oh-journey-more svg,
	.oh-journey-more:hover svg {
		transition: none;
		transform: none;
	}
}

/* ------------------------------------------- up to 1280px: the path runs down beside the copy */
@media (max-width: 79.99rem) {
	.oh-journey-step {
		position: relative;
		padding-left: calc(var(--oh-rail) + var(--oh-gap));
		padding-bottom: 3rem;
	}
	.oh-journey-step:last-child {
		padding-bottom: 0;
	}
	.oh-journey-line--h {
		display: none;
	}
	.oh-journey-line--v {
		position: absolute;
		left: 0;
		top: calc(var(--oh-top) + var(--oh-node) / 2 + var(--oh-rad));
		width: var(--oh-rail);
		height: calc(100% - var(--oh-rad) - var(--oh-rad-next));
	}
	.oh-journey-node {
		position: absolute;
		left: 0;
		top: var(--oh-top);
		width: var(--oh-rail);
		height: var(--oh-node);
	}
	.oh-journey-node svg {
		position: absolute;
		top: 50%;
		left: calc(var(--oh-rail) * var(--oh-x, 50) / 100);
		transform: translate(-50%, -50%);
	}
	.oh-journey-content {
		display: flex;
		flex-direction: column;
		gap: 1rem;
	}
	/* Without the step paragraph the rows have far less to say, and the 3rem gutter that separated
	 * four blocks of prose separates four single lines instead. */
	.oh-roadmap--compact .oh-journey-step {
		padding-bottom: 2rem;
	}
}
@media (min-width: 48rem) and (max-width: 79.99rem) {
	.oh-journey {
		--oh-rail: 7rem;
		--oh-node: 3rem;
		--oh-gap: 2.5rem;
		--oh-top: 0.5rem;
	}
	.oh-journey-step {
		padding-bottom: 3.5rem;
	}
}
/* The step's label-and-title column beside its body. It was set at 48rem, where a fixed 22rem column
 * took a 541px row down to 141px of body and 16 characters to a line; the split only earns its keep
 * once the row can spare the column and still leave the body a measure. Below this the content
 * stacks and the body takes the width. */
@media (min-width: 64rem) and (max-width: 79.99rem) {
	.oh-journey-content {
		display: grid;
		grid-template-columns: minmax(0, 18rem) minmax(0, 1fr);
		gap: 2.5rem;
		align-items: start;
	}
	/* The split exists to put the body beside the title. The short version has no body, so the grid
	 * would crush the title into an 18rem column next to an empty gutter. */
	.oh-roadmap--compact .oh-journey-content {
		display: flex;
		flex-direction: column;
		gap: 1rem;
	}
}

/* ------------------------------------------- 1280px and up: the path runs left to right */
@media (min-width: 80rem) {
	.oh-journey {
		--oh-band: 11rem;
		--oh-node: 3rem;
		display: grid;
		/* Follows however many steps the repeater holds instead of insisting on five. The design ships
		 * five and this renders them identically - same 242px columns, same height, measured - but a
		 * sixth step added in Elementor used to wrap onto a second row and take the path with it. */
		grid-auto-flow: column;
		grid-auto-columns: minmax(0, 1fr);
		gap: 0 2rem;
		align-items: start;
	}
	.oh-journey-step {
		position: relative;
		padding-top: var(--oh-band);
	}
	.oh-journey-line--v {
		display: none;
	}
	.oh-journey-line--h {
		position: absolute;
		top: 0;
		left: calc(50% + var(--oh-rad));
		width: calc(100% + 2rem - var(--oh-rad) - var(--oh-rad-next));
		height: var(--oh-band);
	}
	.oh-journey-node {
		position: absolute;
		top: calc(var(--oh-band) * var(--oh-y, 50) / 100);
		left: 50%;
		transform: translate(-50%, -50%);
		line-height: 0;
	}
	.oh-journey-content {
		display: flex;
		flex-direction: column;
		gap: 1.25rem;
	}
	/* Home's short version keeps only a caption and a title per step, so each column is a short block
	 * standing under its own mark. Ranged left it hangs off to one side of the node; centred it sits
	 * under it and the band of four reads as one row. The full process page keeps its left edge - a
	 * paragraph of prose centred is a paragraph nobody finishes. */
	.oh-roadmap--compact .oh-journey-content {
		align-items: center;
		text-align: center;
	}
	/* Two-line time labels must not push their title out of line with the others. */
	.oh-journey-content .tracked-caps {
		display: block;
		line-height: 1.5;
		min-height: 3em;
	}
	.oh-journey-title {
		font-size: clamp(1.125rem, 1.5vw, 1.5rem);
		letter-spacing: -0.03em;
		line-height: 1.1;
		max-width: 16ch;
	}
	.oh-journey-body {
		font-size: 0.9375rem;
		line-height: 1.6;
	}
	.oh-journey-closing {
		margin-top: 4rem;
	}
}

/* ------------------------------------------------ Control boundaries (WCAG 1.4.11)
 * --rule-strong is a decorative hairline: 1.83:1 on cream, 2.57:1 on slate. Correct for a section
 * divider, and short of the 3:1 a control's own edge needs, because that edge is the only thing
 * identifying the theme toggle, the menu button and the outline buttons as controls at all. They
 * carry --control-line; every divider keeps --rule-strong, so the page's hairline grid is untouched.
 * Hover is restated here because these unlayered rules outrank Tailwind's layered hover:border-coral.
 *
 * --control-line itself comes from tokens/tokens.json now, with its measured ratios; the rules
 * below are what carry it.
 */
.oh-control {
	border-color: var(--control-line);
}
.oh-control:hover {
	border-color: var(--color-coral);
}

/* Demo fields: the hairline IS the field - no fill, no other edge - so it answers to 1.4.11 too.
 * chalk at 30% measured 2.42:1 on ocean; 42% reads at 3.38:1 and still sits under the text. */
form[data-demo-form] input:not(.oh-hp),
form[data-demo-form] select,
form[data-demo-form] textarea {
	border-bottom-color: rgba(246, 243, 238, 0.42);
	/* iOS zooms the page when a focused control is under 16px. The Customizer body scale can take
	 * 1.0625rem below that (15.3px at 90%), so the controls floor at 16px and scale up from there. */
	font-size: max(1rem, calc(1.0625rem * var(--oh-type-body)));
}

/* The one <select> on the site. appearance:none strips the native arrow, and the field language in
 * this form is a hairline and nothing else - so the control was a text input that happened to open a
 * menu, sitting between three that do not. Restoring appearance:auto is not the way back: it brings
 * a full platform bezel with it and throws the hairline away.
 *
 * The chevron is an inline SVG on currentColor, the same mark .oh-journey-more draws, and not a
 * background-image: a data-URI cannot take currentColor, so the field's colour would have to be
 * written out a second time, somewhere the focus rule below could never reach it. pointer-events:none
 * keeps the whole control clickable through the mark, so it stays an affordance and not a dead zone.
 *
 * Two grounds, the same shape .oh-section-caption uses. The form only ever renders on ocean today;
 * this is what keeps it right if it one day does not. */
.oh-select {
	position: relative;
	display: block;
	margin-top: 0.75rem; /* the mt-3 the <select> used to carry */
}
.oh-select-chevron {
	position: absolute;
	right: 0;
	/* On the value, not on the box. The field carries 0.75rem of padding under the text, so its box
	 * centre sits well below its line; measured at 1440 the value's centre is 19px up from the
	 * bottom edge and the mark is 0.875rem, which puts its foot here. */
	bottom: 1.1875rem;
	width: 0.875rem;
	height: 0.875rem;
	color: var(--ink-faint);
	pointer-events: none;
	transition: color 300ms ease;
}
.on-ocean .oh-select-chevron {
	color: var(--color-ocean-100);
}
/* :focus-within and not :focus - the mark is the control's sibling, not its descendant. The hairline
 * already goes coral on focus; the mark goes with it rather than staying behind. */
.oh-select:focus-within .oh-select-chevron {
	color: var(--color-coral);
}
/* Room for the mark, so the longest value can never run under it. */
form[data-demo-form] select {
	padding-right: 1.5rem;
}

/* ------------------------------------------------------ Reflow (WCAG 1.4.10)
 * Everything below binds only when content already exceeds its box, so default text renders
 * identically. Verified with scripts/one-off/probe-overflow.mjs at a 32px root.
 *
 * The header is fixed, so anything past the viewport edge was unreachable at 150-200% text: the
 * menu button simply went off-screen with nothing to scroll. Cap the header at the viewport and
 * let the two panes that already take pointer events scroll themselves.
 */
header.fixed {
	max-height: 100dvh;
}
header.fixed > .nav-shell,
header.fixed > #mobile-nav {
	max-height: calc(100dvh - 2rem);
	overflow-y: auto;
	overscroll-behavior: contain;
}

/* The calculator head put its title and the currency pill on one shrink-0 row; at 200% text the
 * pill left the card and took the page 37px wider than the viewport. Both wrap now. The pill keeps
 * its shape either way: at one row the browser clamps 1.25rem to half the height, which is the
 * pill it already was, and at two rows it reads as the rounded block it has become. */
/* "A bit smaller", as asked. The card keeps its grid cell (six of twelve, starting at seven)
 * and comes in from the right of it instead, so the arithmetic stays beside the prose rather
 * than being restacked. Unlayered, so it beats the p-7/md:p-10 utilities on the element. */
@media (min-width: 48rem) {
	[data-arithmetic] {
		max-width: 34rem;
		margin-left: auto;
		padding: 2rem;
	}
}
[data-arithmetic] .flex.justify-between {
	flex-wrap: wrap;
	row-gap: 0.5rem;
}
[data-arithmetic] > .flex.justify-between {
	row-gap: 1rem;
}
[role="group"][aria-label="Currency"] {
	flex-wrap: wrap;
	max-width: 100%;
	border-radius: 1.25rem;
}

/* The header's action group (CTA, menu) is one shrink-0 row that runs past a 390px phone at 200%
 * text. It wraps to the right edge instead of scrolling the shell sideways. It used to carry the
 * ground toggle too, which is now in the footer's bottom bar - the row is 40px narrower for it. */
.nav-shell > .flex.items-center.gap-2\.5 {
	flex-wrap: wrap;
	justify-content: flex-end;
	row-gap: 0.5rem;
}

/* A grid or flex child keeps min-width:auto, so it refuses to shrink under its widest word. At 200%
 * text that pushed section columns past their track, and main's overflow-x:clip then cut the words
 * off rather than scrolling to them. Text columns may shrink; their content wraps instead. */
main .grid > *,
main .grid > * > .flex.flex-col {
	min-width: 0;
}

/* Footer legal links ("Subscription Agreement") are wider than a twelfth-grid column at large text.
 * Let them wrap between words, and break inside one only when a single word is itself too wide. */
footer nav a {
	overflow-wrap: anywhere;
}

/* ------------------------------------------------------ Nav dropdown: the Industries pages
 * The nav item stays a link to the hub; a small caret beside it discloses the pages. Hover opens it
 * for a mouse, click or Enter for everyone else, Escape and a click outside close it. The panel is
 * hidden with the attribute, so a document without JavaScript simply shows the link.
 *
 * The desktop panel is fixed, not absolute: the nav shell scrolls itself at 200% text (the reflow
 * rule below), and a scroll container clips an absolutely positioned child. site.js writes
 * --oh-nav-x / --oh-nav-y from the item's box, the same way the day-one tabs place their indicator.
 *
 * Fixed only escapes that scroll container while the viewport is still the panel's containing block.
 * The condensed shell's blur took that away and the panel disappeared; see the blur-layer rule above
 * for what may and may not go on `.nav-shell`.
 */
nav[aria-label="Sections"] .oh-nav-group {
	position: relative;
	display: flex;
	align-items: center;
	gap: 0.25rem;
}
.oh-nav-caret {
	appearance: none;
	background: none;
	border: 0;
	padding: 0.35rem;
	margin: 0;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	color: var(--ink-faint);
	cursor: pointer;
	border-radius: 999px;
	transition: color 0.3s ease;
}
.oh-nav-caret svg {
	width: 13px;
	height: 13px;
	transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1);
}
.oh-nav-group:hover .oh-nav-caret,
.oh-nav-caret:hover {
	color: var(--ink);
}
.oh-nav-group.is-open .oh-nav-caret {
	color: var(--color-coral);
}
.oh-nav-group.is-open .oh-nav-caret svg {
	transform: rotate(180deg);
}
.oh-nav-panel,
.oh-nav-panel ul {
	list-style: none;
	margin: 0;
	padding: 0;
}
nav[aria-label="Sections"] .oh-nav-panel {
	position: fixed;
	top: var(--oh-nav-y, 5rem);
	left: var(--oh-nav-x, 1rem);
	z-index: 60;
	width: 16rem;
	max-height: calc(100dvh - var(--oh-nav-y, 5rem) - 1.5rem);
	overflow-y: auto;
	overscroll-behavior: contain;
	padding: 0.5rem;
	border: 1px solid var(--rule);
	border-radius: 1.25rem;
	background: var(--ground);
	box-shadow: 0 24px 48px -28px rgba(17, 26, 34, 0.45);
	animation: oh-nav-panel-in 0.24s cubic-bezier(0.16, 1, 0.3, 1) both;
}
@keyframes oh-nav-panel-in {
	from { opacity: 0; transform: translateY(-6px); }
	to { opacity: 1; transform: none; }
}
.oh-nav-panel a {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 1rem;
	padding: 0.55rem 0.75rem;
	border-radius: 0.75rem;
	font-size: calc(0.9375rem * var(--oh-type-body, 1));
	color: var(--ink-muted);
	text-decoration: none;
	transition: background-color 0.25s ease, color 0.25s ease;
}
.oh-nav-panel a:hover {
	background: var(--ground-alt);
	color: var(--ink);
}
.oh-nav-panel a[aria-current] {
	color: var(--ink);
	font-weight: 700;
}
.oh-nav-panel-all {
	margin-top: 0.25rem;
	padding-top: 0.4rem;
	border-top: 1px solid var(--rule);
}
.oh-nav-panel-all a {
	font-weight: 700;
	color: var(--ink);
}
.oh-nav-panel-all svg {
	width: 14px;
	height: 14px;
	color: var(--color-coral);
}
/* The mobile sheet: the pages open under the item as a plain indented list, no floating card. */
#mobile-nav .oh-nav-group-row {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 1rem;
}
#mobile-nav .oh-nav-caret {
	min-width: 44px;
	min-height: 44px;
	color: var(--ink-muted);
}
#mobile-nav .oh-nav-caret svg {
	width: 16px;
	height: 16px;
}
#mobile-nav .oh-nav-panel {
	margin: 0 0 0.75rem;
	padding-left: 0.75rem;
	border-left: 1px solid var(--rule);
}
#mobile-nav .oh-nav-panel a {
	padding: 0.5rem 0.25rem;
	font-size: 1rem;
	min-height: 44px;
}
#mobile-nav .oh-nav-panel a:hover {
	background: none;
}
@media (prefers-reduced-motion: reduce) {
	nav[aria-label="Sections"] .oh-nav-panel {
		animation: none;
	}
	.oh-nav-caret svg {
		transition: none;
	}
}

/* The hero lead is the page's thesis and was rendering at the same size as the body beneath it
 * (and smaller than it, once the Customizer's 90% body scale hit the utility class but not the
 * hard-coded industry sizes). One step up, and the buttons stop being the smallest text on the page. */
.oh-industry-hero [data-hero-body] {
	font-size: calc(1.25rem * var(--oh-type-body, 1));
	line-height: 1.5;
	max-width: 34ch;
}
.oh-industry-hero [data-hero-action] a {
	font-size: max(1rem, calc(0.9375rem * var(--oh-type-body, 1)));
}

/* ------------------------------------------------------ Industry pairs
 * Four pairs, one beat each: what leaves with the person on one side, the artifact that caught it on
 * the other. The mechanism is never explained on this page because it is demonstrated four times.
 * Pairs alternate sides so the eye crosses the page rather than running down one gutter; on phones
 * each artifact follows its own scene. An artifact with no real capture renders its drawn stand-in.
 */
.oh-pairs-head {
	max-width: 46rem;
}
.oh-pairs-mechanism {
	margin: 1.75rem 0 0;
	max-width: 34ch;
	font-size: calc(1.0625rem * var(--oh-type-body, 1));
	line-height: 1.6;
	color: var(--ink);
}
.oh-pairs {
	margin-top: 4.5rem;
	display: grid;
	gap: 4.5rem;
}
.oh-pair {
	display: grid;
	grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
	gap: 2.5rem;
	align-items: start;
	padding-top: 4.5rem;
	border-top: 1px solid var(--rule);
}
.oh-pair:first-child {
	padding-top: 0;
	border-top: 0;
}
.oh-pair--flip {
	/* Swapping only the order left the artifact in the narrow column on alternate rows, so it
	 * rendered 29% smaller and its container-scaled text dropped with it. The columns swap too. */
	grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
}
.oh-pair--flip .oh-pair-scene {
	order: 2;
}
.oh-pair-title {
	margin: 0;
	/* The display scale multiplies the clamp minimum as well as the maximum, so at 390 this step
	 * lands under the hero lead and the title stops out-ranking the paragraph beneath it. Floored the
	 * way .oh-index-name on the hub already is. */
	font-size: max(1.25rem, var(--oh-display-4));
	font-weight: 900;
	letter-spacing: -0.035em;
	line-height: 1.06;
	text-wrap: balance;
	color: var(--ink);
}
.oh-pair-body {
	margin: 1rem 0 0;
	font-size: calc(1.0625rem * var(--oh-type-body, 1));
	line-height: 1.62;
	color: var(--ink-muted);
}
.oh-pair-caption {
	display: flex;
	align-items: flex-start;
	gap: 0.75rem;
	margin: 1.25rem 0 0;
	font-size: calc(0.9375rem * var(--oh-type-body, 1));
	line-height: 1.55;
	color: var(--ink-muted);
}
.oh-mark--pair {
	flex: 0 0 auto;
	width: 0.9rem;
	height: 0.9rem;
	margin-top: 0.25rem;
}
/* The artifact carries the argument, so it gets the room and the weight the old row-list never did. */
.oh-pair-capture.oh-specimen,
.oh-pair-capture img {
	width: 100%;
}
/* The chat runs four turns on an industry page and the 16/10 box was never derived from its contents
 * — it left the two-turn version half empty and clipped the four-turn one. Here it takes the height
 * it needs. Home's day-one tabs keep the fixed box, because there all three panels share a row. */
.oh-pair-capture.oh-specimen--chat {
	aspect-ratio: auto;
}
.oh-pair-capture.oh-specimen--chat .oh-doc {
	height: auto;
}
.oh-pairs-close {
	margin-top: 5rem;
	padding-top: 4rem;
	border-top: 1px solid var(--rule);
}
.oh-pairs-close .oh-industry-note {
	margin-top: 0;
}
.oh-pairs-close .oh-industry-closing {
	margin-top: 0;
	padding-top: 0;
	border-top: 0;
}
@media (max-width: 63.99rem) {
	.oh-pair {
		grid-template-columns: minmax(0, 1fr);
		gap: 2rem;
		padding-top: 3.5rem;
	}
	.oh-pair--flip {
		grid-template-columns: minmax(0, 1fr);
	}
	.oh-pair--flip .oh-pair-scene {
		order: 0;
	}
	.oh-pairs {
		margin-top: 3.5rem;
		gap: 3.5rem;
	}
	.oh-pairs-close {
		margin-top: 3.5rem;
		padding-top: 3rem;
	}
	/* The artifact carries the whole argument on this page. A 620px card behind a sideways scroller
	 * kept the type legible but put the authored line — the one that makes the artifact answer its
	 * scene — up to 302px off the right edge, on every pair, with no affordance and no keyboard
	 * reach. So below the two-column breakpoint the card fills the width and grows as tall as its
	 * contents instead: the 16/10 box and the fixed height come off, and the internal sizes carry
	 * their own floors (see .oh-doc-*), which is what kept the type readable in the first place. */
	.oh-pair-scroll {
		overflow: visible;
	}
	.oh-pair-scroll > .oh-pair-capture {
		width: 100%;
		max-width: none;
	}
	.oh-pair-capture.oh-specimen {
		aspect-ratio: auto;
		height: auto;
	}

	.oh-pair-capture .oh-doc {
		height: auto;
		padding: 1.5rem 1.25rem;
	}
	.oh-pair-capture .oh-doc-ask {
		margin-top: 1.5rem;
	}
}

/* ------------------------------------------------------ Industry pages (/aviation ... and /industries/)
 * Home's grammar in a shorter room: the hero's breadcrumb where an eyebrow would sit, examples as
 * ruled rows with the hive mark (they are not a sequence, so no numbers), the who-to-interview note on
 * the coral rule, the closing line on the site's closing pattern, and a ruled index on the hub.
 */
.oh-crumbs ol {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-wrap: wrap;
	gap: 0.6rem;
	font-size: calc(0.9375rem * var(--oh-type-body, 1));
	color: var(--ink-faint);
}
.oh-crumbs li + li::before {
	content: "/";
	margin-right: 0.6rem;
	color: var(--rule-strong);
}
.oh-crumbs a {
	color: var(--ink-muted);
	text-decoration: none;
	transition: color 0.3s ease;
}
.oh-crumbs a:hover {
	color: var(--ink);
}
.oh-crumbs [aria-current] {
	color: var(--ink);
	font-weight: 500;
}
.oh-industry-frame {
	margin: 1.5rem 0 0;
	max-width: 34ch;
	font-size: calc(1.0625rem * var(--oh-type-body, 1));
	line-height: 1.6;
	color: var(--ink-muted);
}
.oh-mark {
	display: block;
	width: 1.25rem;
	height: 1.25rem;
	color: var(--color-coral);
	margin-top: 0.3rem;
}
.oh-industry-note {
	margin-top: 2.25rem;
	max-width: 30rem;
	border-left: 1px solid var(--color-coral);
	padding-left: 1.25rem;
}
.oh-industry-note p {
	margin: 0;
	font-size: calc(0.9375rem * var(--oh-type-body, 1));
	line-height: 1.6;
	color: var(--ink-muted);
}
.oh-industry-note-h {
	font-weight: 700;
	color: var(--ink) !important;
	margin-bottom: 0.4rem !important;
}
.oh-industry-body {
	margin: 0;
	font-size: calc(1.0625rem * var(--oh-type-body, 1));
	line-height: 1.62;
	color: var(--ink-muted);
}
.oh-industry-body + .oh-industry-body {
	margin-top: 1.1rem;
}
.oh-industry-closing {
	display: flex;
	align-items: center;
	gap: 1rem;
	margin: 3rem 0 0;
	padding-top: 2rem;
	border-top: 1px solid var(--rule);
	/* Floored for the same reason as .oh-pair-title: unfloored this lands level with the section
	 * heading it is meant to crown. */
	font-size: max(1.75rem, var(--oh-display-3));
	letter-spacing: -0.042em;
	line-height: 1.05;
	text-wrap: balance;
	color: var(--ink);
}
.oh-mark--closing {
	flex: 0 0 auto;
	margin-top: 0;
}
.oh-related {
	padding: 4rem 0 6rem;
}
.oh-related-heading {
	font-size: 1.25rem;
	letter-spacing: -0.02em;
}
.oh-related-links {
	display: flex;
	flex-wrap: wrap;
	gap: 1.25rem 2.5rem;
	margin-top: 1.25rem;
}
.oh-related-links a,
.oh-industry-more a {
	display: inline-flex;
	align-items: center;
	gap: 0.5rem;
	font-weight: 700;
	color: var(--ink);
	text-decoration: underline;
	text-decoration-color: var(--rule-strong);
	text-underline-offset: 4px;
	transition: text-decoration-color 0.3s ease;
}
.oh-related-links a:hover,
.oh-industry-more a:hover {
	text-decoration-color: var(--color-coral);
}
.oh-related-links svg,
.oh-industry-more svg,
.oh-index-arrow svg {
	width: 14px;
	height: 14px;
	color: var(--color-coral);
}
/* Home's accordion: the link to the row's own page, on the ocean ground. */
.oh-industry-more {
	margin: -0.5rem 0 1.75rem;
	font-size: 0.9375rem;
}
.oh-industry-more a {
	color: var(--color-chalk);
	text-decoration-color: rgba(246, 243, 238, 0.35);
}
.oh-index {
	list-style: none;
	margin: 0;
	padding: 0;
	border-top: 1px solid var(--rule);
}
.oh-index a {
	display: grid;
	grid-template-columns: minmax(0, 5fr) minmax(0, 6fr) 2rem;
	gap: 2rem;
	align-items: baseline;
	padding: 1.75rem 0;
	border-bottom: 1px solid var(--rule);
	text-decoration: none;
	color: var(--ink);
}
.oh-index-name {
	grid-column: 1;
	grid-row: 1;
	font-size: max(1.25rem, var(--oh-display-4));
	letter-spacing: -0.035em;
	line-height: 1.06;
	transition: color 0.3s ease;
}
.oh-index-teaser {
	grid-column: 2;
	grid-row: 1;
	font-size: calc(1.0625rem * var(--oh-type-body, 1));
	line-height: 1.5;
	color: var(--ink-muted);
}
.oh-index-arrow {
	grid-column: 3;
	grid-row: 1;
	justify-self: end;
	transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1);
}
.oh-index a:hover .oh-index-name {
	color: var(--ink-muted);
}
.oh-index a:hover .oh-index-arrow {
	transform: translateX(4px);
}
/* The trust note directly under the hero.
 *
 * Deliberately not on .oh-rhythm: the hero above it already owns a full viewport, and this section's
 * ten rems of rhythm padding would read as an empty screen between the headline and the first real
 * section. It still scales with the Customizer's section-spacing control through --oh-space, so it
 * keeps pace when the rest of the page is loosened or tightened.
 *
 * The measure is capped in em, not rem: the body scale is a published Customizer setting, and a rem
 * cap stretches the line length as the text shrinks. See HANDOFF.md on the hero paragraph. */
.oh-trust {
	padding-block: calc(2.5rem * var(--oh-space, 1)) calc(3.5rem * var(--oh-space, 1));
	border-top: 1px solid var(--rule);
}
.oh-trust-inner {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: 0.75rem 2.5rem;
}
.oh-trust-note {
	margin: 0;
	max-width: 52em;
}
@media (min-width: 48rem) {
	.oh-trust {
		padding-block: calc(3rem * var(--oh-space, 1)) calc(4.5rem * var(--oh-space, 1));
	}
}
/* Home's Industries index: the hub's ruled list, re-toned for the ocean ground and stacked into the
 * section's seven-column track. Same markup and same rules as /industries/, with one set of
 * overrides - a second list component would have drifted from the hub within a release.
 *
 * Stacked at every width, not only the narrow one the hub stacks at: the name and its line do not
 * fit side by side in seven columns. The arrows stay chalk rather than coral because this section
 * already spends its one accent on the note's coral rail, and fourteen coral arrows beside it would
 * be fourteen more focal points. */
.oh-index--stacked a {
	grid-template-columns: minmax(0, 1fr) 1.25rem;
	gap: 0.4rem 1rem;
	padding: 1.35rem 0;
	align-items: start;
}
.oh-index--stacked .oh-index-teaser {
	grid-column: 1;
	grid-row: 2;
}
.oh-index--stacked .oh-index-arrow {
	grid-column: 2;
	grid-row: 1 / 3;
	align-self: center;
}
/* The chalk alphas are the ones section-industries.php already hand-writes for its own hairlines;
 * see HANDOFF.md on --rule-on-dark, which the compiled stylesheet does not carry yet. */
.oh-index--on-ocean {
	border-top-color: rgba(246, 243, 238, 0.2);
}
.oh-index--on-ocean a {
	color: var(--color-chalk);
	border-bottom-color: rgba(246, 243, 238, 0.2);
}
.oh-index--on-ocean .oh-index-teaser {
	color: var(--color-ocean-100);
}
.oh-index--on-ocean .oh-index-arrow svg {
	color: rgba(246, 243, 238, 0.55);
}
.oh-index--on-ocean a:hover .oh-index-name {
	color: var(--color-lagoon);
}
.oh-hub-closing {
	margin-top: 5rem;
	padding-top: 4rem;
	border-top: 1px solid var(--rule);
}
.oh-hub-note {
	margin: 2rem 0 0;
	max-width: 30rem;
	border-left: 1px solid var(--color-coral);
	padding-left: 1.25rem;
	font-size: calc(0.9375rem * var(--oh-type-body, 1));
	line-height: 1.6;
	color: var(--ink-muted);
}
.oh-hub-note a {
	color: var(--ink);
	text-decoration: underline;
	text-decoration-color: var(--rule-strong);
	text-underline-offset: 4px;
	transition: text-decoration-color 0.3s ease;
}
.oh-hub-note a:hover {
	text-decoration-color: var(--color-coral);
}
/* The caret is 24x24 by design; the hit area around it is not. */
.oh-nav-caret {
	position: relative;
}
.oh-nav-caret::after {
	content: "";
	position: absolute;
	inset: -10px;
}
@media (max-width: 47.99rem) {
	/* Touch: the breadcrumb sat at 19px tall and the related links at 26px. */
	.oh-crumbs a,
	.oh-crumbs [aria-current],
	.oh-related-links a,
	.oh-industry-more a {
		min-height: 44px;
		display: inline-flex;
		align-items: center;
	}
	.oh-related-links {
		gap: 0.25rem 2.5rem;
	}
	.oh-hub-closing {
		margin-top: 3.5rem;
		padding-top: 3rem;
	}
	.oh-industry-closing {
		/* Was 1.6rem, which put the closing line level with the section heading it is meant to crown
		 * once the display scale compressed the ladder at this width. */
		font-size: 1.75rem;
	}
	.oh-index a {
		grid-template-columns: minmax(0, 1fr) 1.25rem;
		gap: 0.4rem 1rem;
		padding: 1.35rem 0;
	}
	.oh-index-teaser {
		grid-column: 1;
		grid-row: 2;
	}
	.oh-index-arrow {
		grid-column: 2;
		grid-row: 1 / 3;
		align-self: center;
	}
	.oh-related {
		padding: 3rem 0 4rem;
	}
}
@media (prefers-reduced-motion: reduce) {
	.oh-index-arrow, .oh-crumbs a, .oh-index-name {
		transition: none;
	}
}

/* --------------------------------------------------------- Text pages under the fixed header
 * /faq, the legal documents, the 404, search and the archives. The header is fixed on every page:
 * its shell's bottom edge sits at 96px, so a page that begins at the template's pt-14/md:pt-20
 * (56/80px) begins underneath it. These are the landing sections' own 160px, and they win over
 * those utilities because theme.css is unlayered.
 *
 * This used to be written once, on .oh-faq-page alone, under a comment about the fixed header -
 * correct for the shell but not for the page, which rendered the static header until that header
 * was retired. One class on every text template is the version that cannot drift again.
 */
.oh-textpage {
	padding-top: 7.5rem;
}
@media (min-width: 48rem) {
	.oh-textpage {
		padding-top: 10rem;
	}
}

/* The legal clauses carry scroll-mt-28 (112px) on all 380 of their anchor targets, from the same
 * era. It adds to html's scroll-padding-top rather than replacing it, so a clause used to land
 * 208px down with 112px of nothing above it. scroll-padding-top is already exactly the shell's
 * bottom edge and is the site's one answer to this; the per-target margin is the double count. */
#main .scroll-mt-28 {
	scroll-margin-top: 0;
}

/* The legal documents' table of contents sticks at lg:top-10 (40px), which the fixed shell now
 * covers. It rests below the shell instead. */
@media (min-width: 64rem) {
	nav[aria-label="On this page"].lg\:sticky {
		top: 7rem;
	}
}

/* ------------------------------------------------------ Questions people ask (#faq on Home, and /faq)
 * The security accordion's rows on the cream ground: ink for the question, the rule tokens for the
 * lines, hover dims rather than colours (coral on cream is not a text colour). /faq lists every answer
 * open, one reading measure, one rule per group.
 */
.oh-questions .oh-faq-item button > span:first-child {
	color: var(--ink);
}
.oh-questions .oh-faq-item button:hover > span:first-child {
	color: var(--ink-muted);
}
/* The plus/minus is what tells a sighted reader whether a row is open, so it is a state indicator and
 * owes 3:1 as a graphical object. Brand coral on the cream ground measures 2.41:1; --coral-ink is
 * 4.51:1. Only the light rows change: the security and industries accordions sit on the ocean ground,
 * where brand coral already measures 4.92:1 and --coral-ink would drop to 2.63:1. */
.oh-faq--light .oh-faq-item button > span[aria-hidden="true"] {
	color: var(--coral-ink);
}
.oh-questions-updated,
.oh-faq-updated {
	margin-top: 2rem;
	color: var(--ink-faint);
}
.oh-questions-updated time,
.oh-faq-updated time {
	color: var(--ink-muted);
}
.oh-questions-all {
	display: inline-flex;
	align-items: center;
	gap: 0.5rem;
	font-weight: 700;
	color: var(--ink);
	text-decoration: underline;
	text-decoration-color: var(--rule-strong);
	text-underline-offset: 4px;
	transition: text-decoration-color 0.3s ease;
}
.oh-questions-all:hover {
	text-decoration-color: var(--color-coral);
}
.oh-questions-all svg {
	width: 14px;
	height: 14px;
	color: var(--color-coral);
}
/* The head and the groups used to cap at 46rem with no auto margin, which held the whole page in a
 * 736px column against the left edge of a 1400px container. The template's 5/7 grid - the homepage
 * section's own grid - owns the columns now, and .measure owns the reading width inside them.
 * The page's top clearance is .oh-textpage, with every other text template. */
.oh-faq-updated {
	margin-top: 1.5rem;
}
.oh-faq-intro {
	margin-top: 2rem;
}
.oh-faq-group {
	margin-top: 4rem;
	padding-top: 2.5rem;
	border-top: 1px solid var(--rule);
}
.oh-faq-group:first-child {
	margin-top: 0;
	padding-top: 0;
	border-top: 0;
}
.oh-faq-entries {
	margin-top: 1.75rem;
}
.oh-faq-entry + .oh-faq-entry {
	margin-top: 2.5rem;
}
.oh-faq-entry h3 {
	font-size: 1.25rem;
	letter-spacing: -0.02em;
	line-height: 1.25;
	text-wrap: balance;
	color: var(--ink);
}
.oh-faq-entry p {
	margin-top: 0.75rem;
	font-size: 1.0625rem;
	line-height: 1.65;
	color: var(--ink-muted);
}
@media (min-width: 48rem) {
	.oh-faq-group {
		margin-top: 5rem;
	}
	.oh-faq-group:first-child {
		margin-top: 0;
	}
}

/* ------------------------------------------------------ Day one: one desk, three tabs
 * The section scrolls like the rest of the page. Header, subheader, then the three labels as a real
 * horizontal tablist on every screen; one panel shows at a time, its capture (or specimen) beside its
 * copy on wide screens. On phones the panels become swipe cards and the tab row is the indicator. The
 * closing line is the section's conclusion, full width under a rule. No pin, no snap, nothing moves unasked.
 */
.oh-tabs-head h2 {
	text-wrap: balance;
	/* Wider than the max-w-[22ch] utility on the element, which was cut for a six-word heading. The
	 * override lives here rather than in the class attribute because main.css is compiled Tailwind and
	 * an arbitrary value it does not already carry would do nothing at all, silently. */
	max-width: 30ch;
}
.oh-tabs-frame {
	margin: 1.25rem 0 0;
	max-width: 36ch;
	font-size: 1.25rem;
	line-height: 1.5;
	color: var(--ink-muted);
}
.oh-tabs {
	position: relative;
	display: flex;
	flex-wrap: wrap;
	gap: 0;
	margin-top: 2.5rem;
	border-bottom: 1px solid var(--rule);
}
.oh-tab {
	appearance: none;
	background: none;
	border: 0;
	padding: 0.8rem 1.5rem 0.9rem 0;
	margin: 0 1rem 0 0;
	min-height: 44px;
	cursor: pointer;
	text-align: left;
	display: flex;
	align-items: baseline;
	gap: 0.6rem;
	color: var(--ink-faint);
	font: inherit;
	white-space: nowrap;
	transition: color 0.25s ease;
}
.oh-tab-label {
	font-size: 1.0625rem;
	font-weight: 700;
	letter-spacing: -0.01em;
	line-height: 1.2;
	transition: transform 0.25s cubic-bezier(0.16, 1, 0.3, 1);
}
.oh-tab:hover {
	color: var(--ink);
}
.oh-tab:hover .oh-tab-label {
	transform: translateY(-1px);
}
.oh-tab[aria-selected="true"] {
	color: var(--ink);
}
.oh-tab:hover .tracked-caps,
.oh-tab[aria-selected="true"] .tracked-caps {
	color: var(--coral-ink);
}
/* One coral indicator slides along the row (site.js writes --oh-tab-x / --oh-tab-w from the selected tab). */
.oh-tabs-indicator {
	position: absolute;
	left: 0;
	bottom: -1px;
	height: 2px;
	width: var(--oh-tab-w, 0px);
	background: var(--color-coral);
	transform: translateX(var(--oh-tab-x, 0px));
	transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1), width 0.3s cubic-bezier(0.16, 1, 0.3, 1);
	pointer-events: none;
}
.oh-viewer {
	margin-top: 2.5rem;
}
.oh-panel {
	outline-offset: 6px;
}
.oh-panel[hidden] {
	display: none;
}
.oh-capture {
	margin: 0;
}
.oh-capture img {
	display: block;
	width: 100%;
	height: auto;
	aspect-ratio: 16 / 10;
	object-fit: cover;
	border: 1px solid var(--rule-strong);
	border-radius: 1rem;
	background: var(--ground-alt);
	box-shadow: 0 24px 48px -32px rgba(17, 26, 34, 0.35);
	transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.3s ease;
}
.oh-panel:hover .oh-capture img {
	transform: translateY(-2px);
	box-shadow: 0 30px 56px -30px rgba(17, 26, 34, 0.4);
}
.oh-capture + .oh-panel-copy {
	margin-top: 1.75rem;
}
.oh-panel-title {
	font-size: var(--oh-display-4);
	color: var(--ink);
	text-wrap: balance;
	max-width: 22ch;
}
.oh-panel.is-entering {
	animation: oh-panel-in 0.22s ease both;
}
@keyframes oh-panel-in {
	from { opacity: 0; transform: translateY(8px); }
	to { opacity: 1; transform: none; }
}
/* A grid and not a row, because the conclusion is two lines now: the claim, and the sentence that
 * answers the objection it invites. The mark keeps the first row to itself so it stays level with the
 * claim rather than drifting to the centre of both; with no note there is only one row and nothing
 * about the old arrangement changes. */
.oh-tabs-closing {
	margin-top: 4rem;
	padding-top: 2.5rem;
	border-top: 1px solid var(--rule);
	display: grid;
	grid-template-columns: auto minmax(0, 1fr);
	align-items: center;
	column-gap: 1.25rem;
}
.oh-tabs-closing-mark {
	grid-column: 1;
	grid-row: 1;
	width: 22px;
	height: 22px;
	color: var(--color-coral);
}
.oh-tabs-closing-line {
	grid-column: 2;
	grid-row: 1;
	margin: 0;
	/* One step down: it was set at the section-heading size and out-shouted the section. */
	font-size: var(--oh-display-3);
	letter-spacing: -0.042em;
	line-height: 1;
	text-wrap: balance;
}
.oh-tabs-closing-note {
	grid-column: 2;
	grid-row: 2;
	margin: 1rem 0 0;
	max-width: 46ch;
	font-size: 1.0625rem;
	line-height: 1.6;
	color: var(--ink-muted);
}
@media (min-width: 48rem) {
	/* The tab already labels the panel; the kicker inside it would say it twice. */
	.oh-panel-copy > .tracked-caps {
		display: none;
	}
}
/* Panels never ship with the hidden attribute (Tailwind's preflight makes [hidden] !important, so no
 * rule could undo it without JavaScript). Resting panels carry data-rest; the head script adds .js
 * before first paint, this rule hides them until site.js takes over with the real hidden state, and
 * a document without JavaScript simply shows all three, stacked. */
html.js .oh-panel[data-rest] {
	display: none;
}
html:not(.js) .oh-panel + .oh-panel {
	margin-top: 3rem;
}
/* Wide screens: the capture beside its copy, so title and body sit above the fold. */
@media (min-width: 64rem) {
	.oh-panel--capture {
		display: grid;
		grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
		gap: 3.5rem;
		align-items: start;
	}
	.oh-panel--capture[hidden] {
		display: none;
	}
	.oh-panel--capture .oh-capture + .oh-panel-copy {
		margin-top: 0.25rem;
	}
}
/* Phones: swipe cards with a peek of the next; the tab row follows the card in view. */
@media (max-width: 47.99rem) {
	.oh-tabs-section {
		overflow-x: clip;
	}
	.oh-tabs-frame {
		font-size: 1.125rem;
	}
	.oh-viewer {
		display: flex;
		gap: 1rem;
		overflow-x: auto;
		scroll-snap-type: x mandatory;
		scroll-padding-inline: 1.25rem; /* snap to the text margin, not the scrollport edge */
		margin: 2rem -1.25rem 0;
		padding: 0.25rem 1.25rem 1rem;
		scrollbar-width: none;
	}
	.oh-viewer::-webkit-scrollbar {
		display: none;
	}
	.oh-panel,
	html.js .oh-panel[data-rest] {
		display: block;
		flex: 0 0 86%;
		scroll-snap-align: start;
	}
	/* A trailing spacer (the 14% the last card leaves, minus one gap) lets it snap to the same 20px margin as the first. */
	.oh-viewer::after {
		content: "";
		flex: 0 0 calc(14% - 1rem);
	}
	/* Three equal columns, number over label, so the row never needs to scroll — down to 320px. */
	.oh-tabs {
		margin: 2rem -1.25rem 0;
		padding: 0 1.25rem;
	}
	.oh-tab {
		flex: 1 1 0;
		flex-direction: column;
		align-items: center;
		justify-content: center;
		gap: 0.2rem;
		padding: 0.7rem 0.25rem 0.8rem;
		margin: 0;
		text-align: center;
		white-space: normal;
	}
	.oh-tab-label {
		font-size: 0.9375rem;
	}
	.oh-tab:hover .oh-tab-label {
		transform: none;
	}
}
@media (prefers-reduced-motion: reduce) {
	.oh-panel.is-entering {
		animation: none;
	}
	.oh-tab, .oh-tab .oh-tab-label, .oh-tabs-indicator, .oh-capture img {
		transition: none;
	}
}

/* ------------------------------------------------------ Day one: the specimens
 * Until the owner sets a capture on an act, its slot holds a typographic document in the site's own
 * language: the guide's first page, the session's chapter list, the chat's not-covered reply. They
 * scale with the slot (container units), so the same markup reads at 540px and at 300px. Nothing in
 * them is app chrome, and every line comes from copy already on the page.
 */
.oh-specimen {
	container-type: inline-size;
	aspect-ratio: 16 / 10;
	border: 1px solid var(--rule-strong);
	border-radius: 1rem;
	background: var(--ground-alt);
	box-shadow: 0 24px 48px -32px rgba(17, 26, 34, 0.35);
	overflow: hidden;
	transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.3s ease;
}
/* The drawings scale with their slot in container units, which holds down to roughly a 300px
 * slot. Below that the max() rem floors take over, the text stops shrinking with the box, and a
 * fixed 16:10 frame clips it - on a 375px phone the guide lost its fourth row and the chat lost
 * its ask field. Same failure the interview window had, so the same answer: on a phone the card
 * takes the height its content needs and the frame follows it. */
@media (max-width: 47.99rem) {
	.oh-specimen {
		aspect-ratio: auto;
	}
}
/* The interview window is not one of the four artefacts, and it must not be shaped like one.
 * .oh-specimen exists for those: a 16:10 frame with overflow hidden, which is right for a page of a
 * document and wrong for a window that is taller than it is wide once the transcript stacks under
 * the stage. Left inherited it clipped 604px of an 810px window on a 375px phone - the whole
 * conversation - and on a wide screen it padded 166px of dead space under the content instead. The
 * frame comes off with it; .oh-room draws the only one.
 */
.oh-specimen--interview {
	aspect-ratio: auto;
	container-type: normal;
	overflow: visible;
	border: 0;
	border-radius: 0;
	background: none;
	box-shadow: none;
}
.oh-specimen--interview:hover {
	transform: none;
	box-shadow: none;
}
.oh-panel:hover .oh-specimen {
	transform: translateY(-2px);
	box-shadow: 0 30px 56px -30px rgba(17, 26, 34, 0.4);
}
.oh-doc {
	height: 100%;
	display: flex;
	flex-direction: column;
	padding: 5cqw 6cqw;
	color: var(--ink);
}
.oh-doc-head {
	display: flex;
	justify-content: space-between;
	gap: 1em;
	font-family: var(--font-mono);
	font-size: max(0.75rem, 2.1cqw);
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--ink-faint);
	padding-bottom: 3cqw;
	border-bottom: 1px solid var(--rule);
}
/* The guide is a reference you look things up in, so it draws a heading and the line under it
 * per row, divided by rules. It replaced an opening line over a numbered contents list. */
.oh-doc-rows {
	margin: 2.5cqw 0 0;
}
.oh-doc-row-label {
	font-weight: 700;
	font-size: max(0.8125rem, 2.8cqw);
	line-height: 1.3;
	color: var(--ink);
}
.oh-doc-row-note {
	margin: 1cqw 0 0;
	font-size: max(0.75rem, 2.4cqw);
	line-height: 1.45;
	color: var(--ink-muted);
}
.oh-doc-row-note + .oh-doc-row-label {
	margin-top: 2cqw;
	padding-top: 2cqw;
	border-top: 1px solid var(--rule);
}
.oh-doc-list {
	list-style: none;
	margin: 4cqw 0 0;
	padding: 0;
	display: flex;
	flex-direction: column;
}
.oh-doc-list li {
	display: flex;
	align-items: baseline;
	gap: 2.4cqw;
	padding: 2.2cqw 0;
	border-top: 1px solid var(--rule);
	font-size: max(0.875rem, 2.8cqw);
	line-height: 1.3;
	color: var(--ink-muted);
}
.oh-doc-list li:first-child {
	border-top: 0;
}
.oh-doc-num {
	font-family: var(--font-mono);
	font-size: max(0.75rem, 2.1cqw);
	letter-spacing: 0.16em;
	color: var(--ink-faint);
}
.oh-doc-list--chapters li.is-open {
	color: var(--ink);
	font-weight: 700;
}
/* The row goes bold when it is the open chapter, and the numeral inherited that. There is no 700
 * JetBrains Mono in the theme, so the browser was synthesising one by smearing the 500 - on a
 * two-digit numeral at 0.16em tracking, which is where faux bold shows worst. */
.oh-doc-list--chapters li.is-open .oh-doc-num {
	color: var(--coral-ink-paper);
	font-weight: 500;
}
.oh-doc-list--summary li.is-flagged {
	color: var(--ink);
	font-weight: 700;
}
.oh-doc-list--summary li.is-flagged .oh-doc-num {
	color: var(--coral-ink-paper);
	font-weight: 500;
}
/* Where the answer came from, set inside the chat flow so the bubble gap spaces it. */
.oh-doc-source {
	margin: 0;
	align-self: flex-start;
	font-family: var(--font-mono);
	font-size: max(0.6875rem, 2cqw);
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--coral-ink-paper);
}
/* Pushed to the foot of the card, the way .oh-doc-ask is on the session and summary. */
.oh-doc-input {
	margin: auto 0 0;
	border: 1px solid var(--rule-strong);
	border-radius: 999px;
	padding: 1.9cqw 3.4cqw;
	font-size: max(0.875rem, 2.8cqw);
	color: var(--ink-faint);
}
.oh-doc-ask {
	margin: auto 0 0;
	padding-top: 3cqw;
}
.oh-doc-ask span {
	display: inline-block;
	font-family: var(--font-mono);
	font-size: max(0.75rem, 2.1cqw);
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--ink);
	border: 1px solid var(--control-line);
	border-radius: 999px;
	padding: 1.6cqw 3cqw;
}
.oh-doc-chat {
	margin-top: 3cqw;
	display: flex;
	flex-direction: column;
	gap: 2.2cqw;
}
.oh-doc-turn {
	margin: 0;
	max-width: 78%;
	font-size: max(0.875rem, 2.8cqw);
	line-height: 1.4;
	padding: 2.2cqw 3.4cqw;
	border-radius: 2.6cqw;
}
.oh-doc-turn--you {
	align-self: flex-end;
	background: var(--ink);
	color: var(--ground);
	border-bottom-right-radius: 0.6cqw;
}
.oh-doc-turn--oakhive {
	align-self: flex-start;
	background: var(--ground);
	color: var(--ink);
	border: 1px solid var(--rule-strong);
	border-bottom-left-radius: 0.6cqw;
}
@media (prefers-reduced-motion: reduce) {
	.oh-specimen {
		transition: none;
	}
}

/* ------------------------------------------------------------------------------ Touch targets
 * The header's controls stay 40px: the nav shell's proportions are built on that circle. Each one
 * carries an invisible 44x44 hit area instead, centred on the control, so a finger lands where the
 * eye aims. WCAG 2.2 AA asks 24x24 and is already met; 44 is the figure Apple and Material both set.
 * Scoped to .oh-hit so the 24px nav caret, which sits inside a link, never grows a box that would
 * swallow clicks meant for the link beside it.
 */
.oh-hit {
	position: relative;
}
.oh-hit::after {
	content: "";
	position: absolute;
	left: 50%;
	top: 50%;
	width: max(100%, 44px);
	height: max(100%, 44px);
	transform: translate(-50%, -50%);
}

/* The drawn artifacts' screen-reader text. The compiled utility omits `position`, and these captions
 * sit inside a `container-type: inline-size` figure, where a 1px in-flow box still takes a line. */
.oh-visually-hidden {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

/* ==================================================================== Screen sizes: the middle tier
 * The site had two states, phone and desktop, and the switch between them was Tailwind's `md:` at
 * 768px. That is where the twelve-column grid turns on, and its gutter is a fixed 4rem. Eleven of
 * those come to 704px inside a container that is 693px wide at 768, so every track resolved to zero
 * and each column's position came from gap arithmetic alone. Measured on the live page at 768:
 * `md:col-span-5` rendered 256px and `md:col-span-7` 384px, the two together 11px wider than the row
 * holding them; the demo form was 320px of a 693px section, the cost copy set 27 characters to a
 * line, and the manifesto's photo ran 144px past the right edge of the document.
 *
 * The middle now gets a tier of its own rather than a squeezed copy of the desktop one:
 *
 *   below 64rem   one column. A 5/7 editorial split needs about 1000px before either half breathes
 *                 at this type scale, which is the same boundary the industry pages' `.oh-pair`
 *                 already stacks at.
 *   64rem and up  the two-column grid, with a gutter that grows with the viewport instead of sitting
 *                 at 4rem all the way down: 2rem at 1024px, reaching 4rem exactly at 1280px, where
 *                 the shipped desktop rules take over unchanged.
 *
 * The arithmetic is in px on purpose. The cap above this file exists because rem gaps re-create the
 * collapse at 200% browser text, and a fluid gutter written in rem would re-create it too.
 */
@media (max-width: 63.99rem) {
	[class*="md:grid-cols-12"][class*="md:gap-16"] {
		grid-template-columns: minmax(0, 1fr);
	}
	/* This file is unlayered, so `grid-column: auto` beats the compiled `md:col-span-*` utilities
	 * without !important. Without it those spans would ask a one-column grid for columns 1 to 5 and
	 * the implicit tracks would put the collapsed layout straight back. */
	[class*="md:grid-cols-12"][class*="md:gap-16"] > * {
		grid-column: auto;
	}
}
@media (min-width: 64rem) and (max-width: 79.99rem) {
	[class*="md:grid-cols-12"][class*="md:gap-16"] {
		column-gap: min(64px, max(32px, calc(32px + (100vw - 1024px) * 0.125)));
	}
}

/* The note on the coral rule had no measure of its own: the 256px rail it sat in was the measure. With
 * the rail stacked it had the whole width and ran 96 characters to a line. `.oh-industry-note` already
 * answers this on the industry pages at 30rem, so the same figure, on the same pattern. Scoped to the
 * stacked tier: above it the column is 465px at its widest and the cap would have no work to do. */
@media (max-width: 63.99rem) {
	.oh-rail-note {
		max-width: 30rem;
	}
}

/* The footer is four `md:col-span-3` columns, which at 768px left each one 131px wide — narrower
 * than "Data Processing Agreement" is long. Below the two-column boundary the brand block takes the
 * full width and the three link columns share a row of their own. Below 40rem the grid is off
 * entirely and the blocks stack, which is what a phone should do with it. */
@media (min-width: 40rem) and (max-width: 63.99rem) {
	footer [class*="md:grid-cols-12"][class*="gap-14"] {
		display: grid;
		grid-template-columns: repeat(6, minmax(0, 1fr));
		column-gap: 2.5rem;
	}
	footer [class*="md:grid-cols-12"][class*="gap-14"] > :first-child {
		grid-column: 1 / -1;
	}
	footer [class*="md:grid-cols-12"][class*="gap-14"] > nav {
		grid-column: span 2;
	}
}

/* A phone held sideways. The viewport is 390px tall and the hero carries 10rem of padding above the
 * first word and 7rem below the buttons — figures that seat the headline in a tall window and are
 * only distance in a short one. Measured at 844x390: the section ran 947px and the eyebrow sat below
 * the fold. Nothing is hidden; the room comes off the padding, which is what the room was.
 * `rem` in a media query resolves against the initial 16px, not the root, so this stays put when the
 * Customizer's text scale moves. */
@media (max-height: 34rem) and (min-width: 30rem) {
	#top {
		min-height: 0;
		padding-top: 6rem;
		padding-bottom: 2.5rem;
	}
}

/* The same short window. The query above buys the headline its room back out of the padding; 224px
 * of diagram underneath would hand it straight back. Bounded below by 48rem, where the phone rule
 * has already stood the drawing down, and above by the breakpoint, because at 1280 and up the
 * drawing is the hero's second column and removing it would leave that column empty. So this covers
 * exactly one case the other two rules do not: a tablet, or a phone held sideways, wide enough to
 * pass 48rem and too short to afford the height. */
@media (max-height: 34rem) and (min-width: 48rem) and (max-width: 79.99rem) {
	.oh-flow {
		margin-top: 0;
		padding-bottom: 0;
	}
	.oh-flow-stage {
		display: none;
	}
}

/* Touch pointers: a standalone link in a list is a target, not prose. These sit on a 21px line with
 * a 14px gap between rows, which is 35px of pitch against the 44px a finger needs. The height goes
 * on the link and most of it comes back off the list's own gap, so the column grows by a few pixels
 * rather than by a third. Links inside a sentence are left alone; WCAG exempts them and padding
 * would break the line. */
@media (pointer: coarse) {
	footer nav[aria-label] > ul > li > a,
	.oh-questions-all,
	.oh-industry-more > a {
		display: inline-flex;
		align-items: center;
		min-height: 44px;
	}
	footer nav[aria-label] > ul {
		gap: 0.25rem;
	}
}
