/* -----------------------------------------------------------------------
   pages.css — sections used by the inner-page templates.

   The design: "Builder Procurement & Comparison", desktop (1440x5707)
   and mobile (390x8247).

   The design supplies exactly two widths, so every measurement here is one of
   three things: a value the design states at BOTH widths (written as a plain
   px literal), a value that differs between them (written with the --gap-n /
   --section-py clamps from base.css, whose two ends are the design's two
   modes), or a proportion of the 1280 content column (written as a
   percentage, so it lands on the design's pixel at 1440 and stays in
   proportion elsewhere).

   Breakpoint: 1024px, matching the rest of the theme.
   ----------------------------------------------------------------------- */

/* Shared shell for every band on these templates. */
.page-banner__inner,
.intro-cards__inner,
.media-checklist__inner,
.process__inner,
.faq__inner {
	position: relative;
	width: 100%;
	max-width: calc(var(--container-max) + var(--gutter) * 2);
	margin-inline: auto;
}

/*
 * These sections take the design's "Gap/Gap 4" between eyebrow and heading (32
 * desktop, 24 mobile). The shared .section-head is tuned for the homepage,
 * which uses Gap 5 there, so it is re-stated rather than changed.
 */
.intro-cards .section-head,
.media-checklist .section-head,
.process .section-head {
	gap: var(--gap-4);
}

/*
 * Every photograph on these templates sits in a box whose height comes from an
 * aspect-ratio or from the flex row, so the image is taken OUT OF FLOW. A
 * static image would otherwise set the box's min-height (flex items default to
 * min-height:auto) and a portrait upload would push the box past its designed
 * height — which is exactly what a 1232x1174 photograph did to the media band.
 */
.intro-cards__figure,
.media-checklist__media,
.process__media,
.faq__media {
	position: relative;
	overflow: hidden;
}

.intro-cards__figure img,
.media-checklist__media img,
.process__media img,
.faq__media img {
	position: absolute;
	inset: 0;
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/*
 * The design trims these headings to the cap height and the alphabetic baseline
 * ([text-box-trim:trim-both] [text-box-edge:cap_alphabetic] on the nodes), so
 * the half-leading above the first line and the descender space below the last
 * are not part of the block. Without this every trimmed heading measures about
 * 20px taller than the design and pushes the whole band down with it. Browsers
 * without text-box-trim simply keep the leading, as before.
 *
 * Service Areas is trimmed too, but its rule lives in home.css — this file is
 * only loaded on the inner-page templates, and that band is on the front page
 * as well.
 */
.intro-cards .section-head__title,
.media-checklist .section-head__title,
.process .section-head__title,
.process__title,
.faq__title,
.faq__indicator,
.solutions-grid__title,
/* Scoped to this band: the same card in the homepage carousel is not trimmed,
   and trimming it there would shift measurements already signed off. */
.solutions-grid .solution-card__label {
	text-box-trim: trim-both;
	text-box-edge: cap alphabetic;
}

/* ===================================================== inner-page hero ==
   the design / — 648px tall at BOTH widths.
   ======================================================================= */

.page-banner {
	position: relative;
	display: flex;
	align-items: flex-end;
	min-height: 648px;
	overflow: hidden;
	background-color: var(--c-bg);
}

.page-banner__media {
	position: absolute;
	inset: 0;
}

.page-banner__image {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* Transparent at the top, landing on the page ground so the band has no edge. */
.page-banner__media::after {
	content: "";
	position: absolute;
	inset: 0;
	background-image: linear-gradient(180deg, rgba(25, 24, 27, 0) 0%, var(--title) 100%);
}

.page-banner__inner {
	display: flex;
	flex-direction: column;
	gap: var(--gap-4);
	padding: 48px var(--gutter);
}

.page-banner__head {
	display: flex;
	flex-direction: column;
	gap: 24px;
}

.page-banner__crumbs ol {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	list-style: none;
	margin: 0;
	padding: 0;
	color: var(--c-ink);
	font-size: var(--fs-small);
	font-weight: 500;
	line-height: var(--lh-body);
}

/* The design sets the separator as literal text — two spaces either side. */
.page-banner__crumbs li+li::before {
	content: "  |  ";
	white-space: pre;
}

.page-banner__crumbs a {
	color: inherit;
	text-decoration: none;
	transition: color var(--transition);
}

.page-banner__crumbs a:hover {
	color: var(--c-accent);
}

.page-banner__title {
	color: var(--c-ink);
	font-size: var(--fs-h1);
	line-height: var(--lh-h1);
	/* The design's H1 carries a flat -2px in BOTH modes, so it does not scale. */
	letter-spacing: -2px;
	text-transform: uppercase;
}

/*
 * Zero-height in the design too, with the stroke drawn above the box. The line
 * is a pseudo-element rather than a box-shadow: a shadow takes the shape of the
 * border box, and the border box here has NO height, so there is nothing to
 * cast and the rule renders as nothing at all. An absolutely positioned child
 * paints while still costing the layout no height.
 */
.page-banner__rule {
	position: relative;
	width: 100%;
	height: 0;
	margin: 0;
	border: 0;
	/* Chrome's UA sheet sets hr { overflow: hidden }, which clips the line
	   below out of a box that has no height to clip it into. */
	overflow: visible;
}

.page-banner__rule::before {
	content: "";
	position: absolute;
	right: 0;
	bottom: 0;
	left: 0;
	border-top: 1px solid var(--c-line);
}

/*
 * Desktop is one row, button left and blurb right. Mobile stacks them the
 * other way up — blurb first — so the markup follows the mobile order and the
 * button is reordered here rather than written twice.
 */
.page-banner__foot {
	display: flex;
	align-items: flex-start;
	justify-content: space-between;
	gap: var(--gap-6);
}

.page-banner__blurb {
	max-width: 519px;
	/*
	 * The blurb is pinned to the right of the band in every banner design. It
	 * used to get there only as the second child of a space-between row — so on
	 * a solution page, which has no CTA beside it, it slid back to the left
	 * gutter. An auto margin holds it right whether or not the button is there,
	 * and changes nothing when it is.
	 */
	margin-left: auto;
	color: var(--c-ink);
	font-size: var(--fs-small);
	font-weight: 300;
	line-height: var(--lh-body);
}

.page-banner__cta {
	order: -1;
	flex: 0 0 auto;
}

@media (max-width: 1024px) {
	.page-banner__foot {
		flex-direction: column;
		gap: 16px;
	}

	.page-banner__cta {
		order: 0;
		align-self: flex-start;
	}

	.page-banner__blurb {
		max-width: none;
		/* Stacked here, so the auto margin would push it off the gutter. */
		margin-left: 0;
	}
}

/* ================================================== intro + card row ====
   the design /.
   ======================================================================= */

.intro-cards {
	background-color: var(--c-bg);
}

.intro-cards__inner {
	display: flex;
	flex-direction: column;
	gap: 48px;
	padding: var(--section-py) var(--gutter);
}

.intro-cards__top {
	display: flex;
	align-items: center;
	gap: 24px;
}

/* 564 of the 1280 content column. */
.intro-cards__copy {
	display: flex;
	flex: 0 0 44.0625%;
	flex-direction: column;
	gap: 31px;
	min-width: 0;
}

.intro-cards__body {
	color: var(--c-ink);
	font-size: var(--fs-body);
	font-weight: 300;
	line-height: var(--lh-body);
	opacity: 0.8;
}

/*
 * Two equal columns, but the right-hand photograph is SHORTER than the left
 * (440 against 512) and pinned to the top of a full-height column, which is
 * what leaves the gap underneath for the button while both columns still
 * finish level.
 */
.intro-cards__stack {
	display: flex;
	flex: 1 0 0;
	align-items: stretch;
	gap: 24px;
	min-width: 0;
}


.intro-cards__figure--1 {
	flex: 1 0 0;
	min-width: 0;
	aspect-ratio: 334 / 512;
}

.intro-cards__col {
	display: flex;
	flex: 1 0 0;
	flex-direction: column;
	align-items: flex-end;
	justify-content: space-between;
	gap: 24px;
	min-width: 0;
}

.intro-cards__figure--2 {
	width: 100%;
	aspect-ratio: 334 / 440;
}

.intro-cards__list {
	display: flex;
	gap: 8px;
	list-style: none;
	margin: 0;
	padding: 0;
}

.intro-card {
	display: flex;
	flex: 1 0 0;
	flex-direction: column;
	gap: 16px;
	min-width: 0;
	padding: 24px;
	background-color: rgba(255, 255, 255, 0.06);
}

.intro-card__head {
	display: flex;
	flex-direction: column;
	gap: 16px;
}

.intro-card__icon,
.intro-card__icon svg {
	display: block;
	width: 32px;
	height: 32px;
}

.intro-card__title {
	color: var(--c-ink);
	font-size: var(--fs-h5);
	line-height: var(--lh-heading);
	text-transform: uppercase;
}

.intro-card__text {
	color: var(--c-ink);
	font-size: var(--fs-small);
	font-weight: 300;
	line-height: var(--lh-body);
	opacity: 0.8;
}

@media (max-width: 1024px) {
	.intro-cards__top {
		flex-direction: column;
		align-items: stretch;
		gap: var(--gap-4);
	}

	.intro-cards__copy {
		flex: 0 0 auto;
	}

	/*
	 * The right-hand column stops existing on mobile: its two children become
	 * siblings of the first photograph so all three sit in one stack.
	 */
	.intro-cards__col {
		display: contents;
	}

	.intro-cards__stack {
		flex-direction: column;
		align-items: stretch;
		gap: 16px;
	}

	.intro-cards__figure--1,
	.intro-cards__figure--2 {
		flex: 0 0 auto;
		width: 100%;
		aspect-ratio: 342 / 280;
	}

	/*
	 * The design leaves 24 above the button but 16 between the photographs,
	 * and one stack cannot have two row gaps — so the button makes up the
	 * remaining 8.
	 */
	.intro-cards__cta {
		align-self: flex-start;
		margin-top: 8px;
	}

	.intro-cards__list {
		flex-direction: column;
	}
}

/* ==================================================== media + checklist =
   the design /.
   ======================================================================= */

.media-checklist {
	position: relative;
	overflow: hidden;
	background-color: var(--c-bg);
}

/*
 * The blueprint carries its own 0.1 opacity inside the SVG, so there is no
 * CSS opacity here — applying one again would multiply it to 0.01.
 */
.media-checklist__blueprint {
	position: absolute;
	top: -8px;
	left: 72.6389%;
	width: 35.2673%;
	aspect-ratio: 507.849 / 488;
	background-image: url("../icons/blueprint-procurement.svg");
	background-repeat: no-repeat;
	background-size: 100% 100%;
	pointer-events: none;
}

.media-checklist__inner {
	display: flex;
	align-items: center;
	gap: 48px;
	padding: var(--gap-2) var(--gutter) var(--section-py);
}

.media-checklist__media {
	flex: 1 0 0;
	min-width: 0;
	aspect-ratio: 616 / 587;
}


.media-checklist__play {
	position: absolute;
	bottom: 24px;
	left: 24px;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 48px;
	height: 48px;
	background-color: var(--white);
	border: 1px solid rgba(0, 0, 0, 0.01);
	border-radius: var(--radius-lg);
	transition: transform var(--transition);
}

.media-checklist__play svg {
	display: block;
	width: 24px;
	height: 24px;
}

.media-checklist__play:hover {
	transform: scale(1.08);
}

.media-checklist__copy {
	display: flex;
	flex: 1 0 0;
	flex-direction: column;
	gap: var(--gap-4);
	min-width: 0;
}

.media-checklist__body {
	color: var(--c-ink);
	font-size: var(--fs-body);
	font-weight: 300;
	line-height: var(--lh-body);
	opacity: 0.8;
}

.media-checklist__cta {
	align-self: flex-start;
}

@media (max-width: 1024px) {
	.media-checklist__blueprint {
		left: -4px;
		width: 507.849px;
	}

	.media-checklist__inner {
		flex-direction: column;
		align-items: stretch;
	}

	.media-checklist__media {
		flex: 0 0 auto;
		aspect-ratio: 342 / 280;
	}
}

/* ----------------------------------------------------------- checklist --
   Shared by the media band and the process panels: a 22px marker box with an
   8px red square at 7,7, then 4px to the text.
   ----------------------------------------------------------------------- */

.checklist {
	display: flex;
	flex-direction: column;
	gap: 8px;
	list-style: none;
	margin: 0;
	padding: 0;
}

.checklist__item {
	position: relative;
	padding-left: 26px;
	color: var(--c-ink);
	font-size: var(--fs-body);
	font-weight: 300;
	line-height: var(--lh-body);
	opacity: 0.8;
}

.checklist__item::before {
	content: "";
	position: absolute;
	top: 7px;
	left: 7px;
	width: 8px;
	height: 8px;
	background-color: var(--c-accent);
}

.checklist--dark .checklist__item {
	color: var(--description);
}

/* ========================================================= process tabs =
   the design / and the component.
   ======================================================================= */

/*
 * No overflow on the section itself: an ancestor with overflow:hidden becomes a
 * scroll container, and a sticky child cannot stick inside one. The clipping
 * the gradient columns need moves to __pin, which is the box that actually
 * sticks.
 */
.process {
	position: relative;
	background-color: var(--c-bg);
}

/*
 * The band's clipping box for the red gradient columns, which are taller than
 * the band on purpose — and the element that sticks while the band is pinned.
 */
.process__pin {
	position: relative;
	overflow: hidden;
}

/*
 * Set only once JavaScript has confirmed the screen is large enough and the
 * viewer has not asked for reduced motion; the section's extra height is set at
 * the same time, in pixels, from the band's own measured height.
 */
.process.is-pinned .process__pin {
	position: sticky;
	top: 0;
}

/*
 * Five 288px columns of red fading downwards, at three strengths. One element
 * carries all five as background layers: each is 20% wide (288 of 1440, and
 * 78 of 390 — the same fraction at both widths), and a percentage background
 * position of p places a layer of that width at 0.8 x p of the container, so
 * 0/25/50/75/100% lands them on 0/288/576/864/1152 exactly.
 */
.process__columns {
	position: absolute;
	top: 0;
	left: 0;
	width: 100%;
	height: 829px;
	background-image:
		linear-gradient(180deg, rgba(246, 40, 44, 0.25) 0%, rgba(246, 40, 44, 0) 100%),
		linear-gradient(180deg, rgba(246, 40, 44, 0.2) 0%, rgba(246, 40, 44, 0) 100%),
		linear-gradient(180deg, rgba(246, 40, 44, 0.15) 0%, rgba(246, 40, 44, 0) 100%),
		linear-gradient(180deg, rgba(246, 40, 44, 0.2) 0%, rgba(246, 40, 44, 0) 100%),
		linear-gradient(180deg, rgba(246, 40, 44, 0.25) 0%, rgba(246, 40, 44, 0) 100%);
	background-repeat: no-repeat;
	background-size: 20% 100%;
	background-position: 0% 0, 25% 0, 50% 0, 75% 0, 100% 0;
	pointer-events: none;
}

.process__inner {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: var(--gap-2);
	padding: var(--gap-1) var(--gutter) var(--section-py);
}

/* 1062 of the 1280 content column. */
.process__head {
	width: 82.9688%;
}

.process__body {
	display: flex;
	align-items: center;
	gap: var(--gap-2);
	width: 100%;
}

.process__nav {
	display: flex;
	flex: 0 0 auto;
	flex-direction: column;
	gap: var(--gap-5);
}

.process__dot {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 40px;
	height: 40px;
	padding: 0;
	background: transparent;
	color: var(--white);
	font-family: var(--font-body);
	font-size: var(--fs-small);
	font-weight: 500;
	line-height: var(--lh-body);
	border: 1px solid var(--white);
	border-radius: var(--radius-lg);
	opacity: 0.2;
	cursor: pointer;
	transition: opacity var(--transition);
}

.process__dot:hover {
	opacity: 0.6;
}

.process__dot[aria-selected="true"],
.process__dot[aria-selected="true"]:hover {
	opacity: 1;
}

.process__panels {
	flex: 1 0 0;
	min-width: 0;
}

.process__panel {
	display: flex;
	align-items: stretch;
	min-height: 424px;
	overflow: hidden;
	background-color: var(--white);
}

.process__panel[hidden] {
	display: none;
}

.process__copy {
	display: flex;
	flex: 1 0 0;
	flex-direction: column;
	gap: 24px;
	min-width: 0;
	/* The design: 48 left / 64 right / 48 block. */
	padding: var(--gap-2) var(--gap-1) var(--gap-2) var(--gap-2);
}

.process__number {
	color: var(--c-accent);
	font-size: var(--fs-small);
	font-weight: 500;
	line-height: var(--lh-body);
}

.process__title {
	color: var(--black);
	font-size: var(--fs-h3);
	line-height: var(--lh-tight);
	text-transform: uppercase;
}

.process__text {
	color: var(--description);
	font-size: var(--fs-body);
	font-weight: 300;
	line-height: var(--lh-body);
}

/* 487 of the 1192 the panel occupies at 1440. */
.process__media {
	flex: 0 0 40.8557%;
}


@media (max-width: 1024px) {
	.process__columns {
		height: 1606px;
	}

	.process__head {
		width: 100%;
	}

	/* The numbered discs move from a column at the left to a row underneath. */
	.process__body {
		flex-direction: column-reverse;
	}

	.process__nav {
		flex-direction: row;
		justify-content: center;
		gap: 16px;
	}

	.process__panel {
		flex-direction: column;
		min-height: 0;
	}

	.process__copy {
		gap: 16px;
		padding: var(--gap-4);
	}

	.process__media {
		flex: 0 0 auto;
		width: 100%;
		aspect-ratio: 487 / 424;
	}
}

/* =================================================================== FAQ =
   the design /.
   ======================================================================= */

.faq {
	position: relative;
	overflow: hidden;
	/* The design's own raised surface for this band; not --c-bg-alt. */
	background-color: #272629;
}

/*
 * Mirrored horizontally: the design stacks rotate(180deg) on scaleY(-1), which
 * composes to a plain horizontal flip. Its own SVG opacity is left alone.
 */
.faq__blueprint {
	position: absolute;
	top: -23px;
	right: -137px;
	width: 490px;
	height: 410px;
	background-image: url("../icons/blueprint-faq.svg");
	background-repeat: no-repeat;
	background-size: 100% 100%;
	transform: scaleX(-1);
	pointer-events: none;
}

.faq__inner {
	display: flex;
	align-items: flex-start;
	gap: 48px;
	padding: var(--section-py) var(--gutter);
}

/*
 * 411 of the 1280 content column, at a FIXED height.
 *
 * The design stretches this photograph to whatever the copy beside it happens to
 * be — 411x571 on a customer or location page, 411x593 on a
 * solution page, the difference being nothing but a longer set
 * of questions. Carried into CSS as `align-self: stretch` that made the
 * photograph resize every time a question was opened or closed, which reads as
 * the page lurching. It is pinned to the design's 411x571 instead.
 *
 * The BAND still takes its height from the copy, so nothing else moves: a
 * solution page is still 753 tall, it simply has a 571 photograph in it rather
 * than a 593 one. flex-start rather than stretch so the ratio is what decides.
 */
.faq__media {
	flex: 0 0 32.1094%;
	align-self: flex-start;
	aspect-ratio: 411 / 571;
}

.faq__copy {
	display: flex;
	flex: 1 0 0;
	flex-direction: column;
	justify-content: center;
	gap: 72px;
	min-width: 0;
	padding-block: var(--gap-2);
}

.faq__title {
	width: 100%;
	color: var(--c-ink);
	font-size: var(--fs-h2);
	line-height: var(--lh-tight);
	text-transform: uppercase;
}

.faq__list {
	display: flex;
	flex-direction: column;
	gap: 24px;
	width: 100%;
}

/*
 * The design draws a rule between rows with 24 either side. Gap supplies one
 * half, the row's own padding the other, so the rule sits centred in 48.
 *
 * It is a box-shadow rather than a border because the design's rule is a ZERO-height
 * node with its 1px stroke drawn outside the box — a real border would add its
 * 1px to the layout and push the list 3px long over four rows.
 */
.faq__item+.faq__item {
	padding-top: 24px;
	box-shadow: 0 -1px 0 0 var(--c-line);
}

.faq__question {
	display: flex;
	align-items: center;
	gap: 24px;
	color: var(--c-ink);
	font-family: var(--font-heading);
	font-size: var(--fs-h5);
	line-height: var(--lh-heading);
	text-transform: capitalize;
	list-style: none;
	cursor: pointer;
}

.faq__question::marker,
.faq__question::-webkit-details-marker {
	display: none;
	content: "";
}

.faq__question-text {
	flex: 1 1 auto;
	min-width: 0;
}

/* Same glyph pair as the primary menu: "+" closed, en dash open. */
.faq__indicator {
	flex: 0 0 auto;
	font-family: var(--font-heading);
	font-size: var(--fs-h4);
	line-height: var(--lh-tight);
}

.faq__indicator::before {
	content: "+";
}

.faq__item[open] .faq__indicator::before {
	content: "\2013";
}

.faq__answer {
	margin-top: 16px;
}

.faq__answer p {
	color: var(--c-ink);
	font-size: var(--fs-body);
	font-weight: 300;
	line-height: var(--lh-body);
	opacity: 0.8;
}

@media (max-width: 1024px) {
	.faq__inner {
		flex-direction: column;
		align-items: stretch;
	}

	/*
	 * 342x280 on mobile, and capped there: the ratio keeps the
	 * design's shape on a narrow screen while max-height stops a wider phone
	 * or a small tablet scaling the photograph past 280.
	 */
	.faq__media {
		flex: 0 0 auto;
		align-self: auto;
		aspect-ratio: 342 / 280;
		max-height: 280px;
	}

	.faq__copy {
		gap: var(--gap-2);
		padding-block: 0;
	}
}

/* ============================================= solutions, four across ===
   the design (desktop) / (mobile).

   The same card as the homepage carousel, laid out plainly. Above the
   breakpoint it is a four-column row; below it the markup is already a Swiper
   and becomes the peeking carousel the homepage uses.
   ======================================================================= */

.solutions-grid {
	background-color: var(--c-bg);
}

.solutions-grid__inner {
	position: relative;
	display: flex;
	width: 100%;
	max-width: calc(var(--container-max) + var(--gutter) * 2);
	flex-direction: column;
	align-items: center;
	/*
	 * The two frames name different gap variables — Gap 2 on desktop, Gap 3 on
	 * mobile — so this is 48 to 32 rather than either token's own pair.
	 */
	gap: clamp(32px, 3.3334vw, 48px);
	margin-inline: auto;
	padding: var(--section-py) var(--gutter);
	/*
	 * The carousel deliberately lets the next card peek past the gutter, and
	 * the slider itself must keep overflow visible for that. Something has to
	 * stop the peek reaching the document, or the page gains 970px of sideways
	 * scroll — the homepage wraps its own carousel for exactly this reason.
	 */
	overflow: hidden;
}

.solutions-grid__title {
	width: 100%;
	color: var(--c-ink);
	font-size: var(--fs-h2);
	line-height: var(--lh-tight);
	text-align: center;
	text-transform: uppercase;
}

/*
 * Swiper's own rule clips the slider, which would cut the blueprint lines that
 * bleed off each card's left edge. The card clips them itself (The design sets
 * overflow-clip on the component), so the slider does not need to.
 */
.solutions-grid__swiper {
	width: 100%;
	min-width: 0;
	overflow: visible;
}

/*
 * The trailing arrow IS wanted here — it is the homepage that goes without one.
 *
 * It takes NO width, which is the whole trick. The homepage reserves its width
 * at rest so revealing it causes no reflow, but 27px of reserved space is
 * enough to re-break a label: it put "Knockdown Rebuild" and "Subdivision &
 * Development" on to second lines they do not have in the design. A decorative
 * hover glyph should not decide where a title wraps, so it is given a zero-width
 * box and painted outside it, and moved with a transform — neither of which the
 * line breaker can see. Labels then break exactly as drawn and the band keeps
 * its 656.
 *
 * Below the grid the carousel is the touch layout, where there is no hover to
 * reveal an arrow at all, so it is dropped rather than left hanging.
 */
.solutions-grid .solution-card__arrow {
	width: 0;
	margin-left: 0;
	transform: translateX(-0.15em);
}

.solutions-grid .solution-card:hover .solution-card__arrow,
.solutions-grid .solution-card:focus-within .solution-card__arrow {
	transform: translateX(0.35em);
}

@media (max-width: 900px) {
	.solutions-grid .solution-card__arrow {
		display: none;
	}
}

/*
 * Above the carousel breakpoint Swiper has destroyed itself, so the wrapper is
 * an ordinary flex row again and the cards give up their fixed 316 to share
 * the 1280 four ways — 302 each at 1440, exactly the design's card.
 */
@media (min-width: 901px) {
	.solutions-grid__swiper .swiper-wrapper {
		display: flex;
		align-items: flex-start;
		gap: 24px;
	}

	.solutions-grid__swiper .solution-card {
		flex: 1 0 0;
		width: auto;
		min-width: 0;
		max-width: none;
	}
}

/* ================================================ solution detail ======
   the design, mobile.
   ======================================================================= */

/* ---- overview ---- */

.solution-overview {
	position: relative;
	overflow: hidden;
	background-color: var(--c-bg);
}

.solution-overview__blueprint {
	position: absolute;
	top: -8px;
	left: 72.6389%;
	width: 35.2673%;
	aspect-ratio: 507.849 / 488;
	background-image: url("../icons/blueprint-procurement.svg");
	background-repeat: no-repeat;
	background-size: 100% 100%;
	pointer-events: none;
}

.solution-overview__inner {
	position: relative;
	display: flex;
	align-items: flex-start;
	gap: 48px;
	width: 100%;
	max-width: calc(var(--container-max) + var(--gutter) * 2);
	margin-inline: auto;
	padding: var(--gap-1) var(--gutter) var(--section-py);
}

/*
 * 519 of the 1280 content column, and as tall as the copy beside it.
 *
 * The design stretches this photograph to the band's own height rather than giving
 * it a ratio: 519x631 on Subdivision & Development and 519x591 on
 * Custom Homes, where the shorter heading costs the copy column
 * 40px. A hard-coded `aspect-ratio: 519 / 631` held every solution at
 * Subdivision's height and pushed the Custom Homes band 40px past its design.
 *
 * align-self beats the container's flex-start, so the copy column sets the
 * cross size and the photograph follows it.
 */
.solution-overview__media {
	position: relative;
	flex: 0 0 40.5469%;
	align-self: stretch;
	overflow: hidden;

	/*
	 * The angled top-left corner. In the design this is not a photograph with a
	 * corner painted out — it is a VECTOR (`Rectangle 11` and its
	 * six siblings) whose top-left corner is clipped, image filled. So it is
	 * the SHAPE that is angled, and it belongs here rather than baked into
	 * each picture: baked, it went missing whenever a page took its
	 * photograph from elsewhere and its depth drifted with the box height.
	 *
	 * Depth is 22.4% of the box, measured off the design's own alpha mask —
	 * the edge is an exact line from (1036, 0) to (0, 245) in the 1038x1094
	 * export of, so 245/1094. Every one of the seven boxes is a
	 * different height, and the design's cut tracks the height rather than
	 * holding a fixed angle, which is
	 * why this is a percentage and not a pixel value.
	 */
	clip-path: polygon(0 22.4%, 100% 0, 100% 100%, 0 100%);
}

.solution-overview__media img {
	position: absolute;
	inset: 0;
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.solution-overview__copy {
	display: flex;
	flex: 1 0 0;
	flex-direction: column;
	gap: var(--gap-4);
	min-width: 0;
}

.solution-overview .section-head {
	gap: var(--gap-4);
}

.solution-overview .section-head__title,
.how-we-help .section-head__title,
.project-cards .section-head__title,
/* The two Resources bands are H2 [text-box-trim:trim-both] like the rest —
   untrimmed, the galleries heading measures 123 for two lines against the
   frame's 103. */
.galleries .section-head__title,
.property-cards .section-head__title,
.project-cards__title,
.more-solutions__title {
	text-box-trim: trim-both;
	text-box-edge: cap alphabetic;
}

.solution-overview__body,
.how-we-help__body {
	color: var(--c-ink);
	font-size: var(--fs-body);
	font-weight: 300;
	line-height: var(--lh-body);
	opacity: 0.8;
}

.solution-overview__points {
	display: flex;
	flex-direction: column;
	gap: 16px;
}

/* the design: the list is named, at the same size as the eyebrow. */
.solution-overview__points-heading {
	color: var(--c-ink);
	font-size: var(--fs-lead);
	font-weight: 300;
	line-height: var(--lh-body);
	letter-spacing: 0.01em;
}

.solution-overview__cta {
	align-self: flex-start;
}

@media (max-width: 1024px) {
	.solution-overview__inner {
		flex-direction: column;
		gap: 40px;
	}

	/*
	 * Mobile squares the photograph off but KEEPS the angled corner.
	 *
	 * This carried `clip-path: none` on the strength of a downscaled render of
	 * that looked square — the wedge is filled with the band colour,
	 * so at 0.67x it is easy to miss. Measured properly, by exporting each
	 * mobile `Rectangle 11` vector and scanning it, all three draw the same
	 * diagonal: solution, location and site acquisition
	 * each reach the left edge at 76 of 342 = 0.2222, which is the
	 * 22.4% the desktop clip already uses. So the clip simply carries over.
	 */
	.solution-overview__media {
		flex: 0 0 auto;
		width: 100%;
		aspect-ratio: 1 / 1;
	}

	.solution-overview__blueprint {
		left: -4px;
		width: 507.849px;
	}
}

/* ---- how we help ---- */

.how-we-help {
	position: relative;
	overflow: hidden;
	background-color: var(--c-bg);
}

/*
 * The gallery's treatment: a corner motif behind the head, not a drawing in the
 * middle of the band. It used to sit at 421 from the top and 22.5% from the
 * left, centred under the row — which was tolerable only while the cards were
 * translucent and it read as one texture with them. Once the cards became
 * opaque it was left as a wireframe smudge in the empty space beneath them.
 */
.how-we-help__blueprint {
	position: absolute;
	top: 0;
	right: -80px;
	width: 768.59px;
	height: 738.55px;
	background-image: url("../icons/blueprint-insights.svg");
	background-repeat: no-repeat;
	background-size: 100% 100%;
	pointer-events: none;
}

.how-we-help__inner,
.project-cards__inner,
.more-solutions__inner {
	position: relative;
	display: flex;
	flex-direction: column;
	width: 100%;
	max-width: calc(var(--container-max) + var(--gutter) * 2);
	margin-inline: auto;
}

/*
 * Opens at --section-py, matching the property gallery this band was asked to
 * be styled after. It used
 * to open at 48, which is why the site acquisition page carried an override to
 * push it back to 80 — that override is now the default and has been removed.
 */
.how-we-help__inner {
	gap: var(--gap-1);
	padding: var(--section-py) var(--gutter);
	/*
	 * NO overflow here. The row is meant to run past the content column and be
	 * cut by the WINDOW, which is what the section's own overflow does — the
	 * gallery this band is styled after leaves its inner visible for exactly
	 * that reason.
	 *
	 * Clipping on the inner instead cut the row at the column's right edge, so
	 * above 1440 the fourth card stopped at 1680 with a 240 strip of empty band
	 * beside it. At 1440 the column IS the window and the two are
	 * indistinguishable, which is how it went unnoticed.
	 */
}

/*
 * The supporting paragraph sits to the RIGHT of the heading and is bottom
 * aligned with it — 837 and 411 of the 1280 column, with the 32 between.
 */
.how-we-help__head {
	display: flex;
	align-items: flex-end;
	gap: var(--gap-4);
}

.how-we-help__head .section-head {
	flex: 0 0 65.3906%;
	gap: var(--gap-4);
	min-width: 0;
}

.how-we-help__body {
	flex: 1 0 0;
	min-width: 0;
}

/*
 * How We Help runs PAST the content column and off the right of the window:
 * lays four 410px cards on a 434 pitch inside a 1280 frame, so the
 * fourth starts at x=1302 and is cut by the screen edge. Overflow stays visible
 * and the SECTION clips, at the window rather than at the column.
 */
.how-we-help__swiper {
	width: 100%;
	min-width: 0;
	overflow: visible;
}

/*
 * Featured Projects and More Solutions do NOT do that. Both fit exactly three
 * 410.67 cards across the same 1280 column — 3 x 410.67 + 2 x 24 = 1280 — so
 * the row ends flush with the column and nothing is cut. They are still
 * carousels; the arrows page the rest in behind the clip.
 */
.project-cards__swiper,
.more-solutions__swiper {
	width: 100%;
	min-width: 0;
	overflow: hidden;
}

/* the design: 6% white with a 4px backdrop blur. */
/*
 * #272629 — the same ground the gallery tile is drawn on, and OPAQUE.
 *
 * This was white at 6% over a blur, which let the band's blueprint line-art
 * read straight through the card bodies: the wireframe ran across the titles
 * and the copy, and the cards stopped looking like cards. The drawing now
 * passes behind them and shows only in the gaps, which is what it does behind
 * the gallery's tiles.
 */
.help-card {
	display: flex;
	flex-direction: column;
	width: 410px;
	max-width: 84vw;
	/*
	 * 356 is the gallery tile's height, so the two rails end level and the
	 * arrows under them sit at the same place in the band. It is a MINIMUM, not
	 * a height: a card whose copy runs longer than the others still grows, and
	 * the row stays even because the slides stretch.
	 */
	min-height: 356px;
	background-color: #272629;
}

.help-card__media {
	position: relative;
	height: 200px;
	overflow: hidden;
}

.help-card__media img {
	position: absolute;
	inset: 0;
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.help-card__body {
	display: flex;
	flex-direction: column;
	gap: 16px;
	padding: 24px;
}

.help-card__title {
	color: var(--c-ink);
	font-size: var(--fs-h5);
	line-height: var(--lh-heading);
	text-transform: uppercase;
}

.help-card__text {
	color: var(--c-ink);
	font-size: var(--fs-body);
	font-weight: 300;
	line-height: var(--lh-body);
	opacity: 0.8;
}

/* ---- the rail-and-arrows control shared by both carousels ---- */

.slider-foot {
	display: flex;
	align-items: center;
	gap: 24px;
}

/*
 * Nothing to page through, nothing to draw. Swiper marks both arrows
 * swiper-button-lock when every slide already fits, and its own CSS hides
 * them — which left the rail behind as a 1256-wide bar filled to 100% and
 * unable to move. A full, immovable scrollbar is worse than no scrollbar.
 */
.slider-foot:has(.slider-nav__btn.swiper-button-lock) {
	display: none;
}

/* the design: a full-width track with a bright progress segment on it. */
.slider-rail {
	position: relative;
	flex: 1 0 0;
	height: 1px;
	min-width: 0;
	/* Belt and braces: whatever the script computes, the bright segment can
	   never paint outside the track and over the arrows. */
	overflow: hidden;
	/*
	 * 20% white, not --c-line's 10%. Sampled off both nav rows —
	 * at 1440 and at 390 — the track reads 71,70,73 on the band's
	 * #19181B, which is white at 0.200; --c-line renders 48,47,50. The token
	 * is right for the eight other places it is used, so this one is set
	 * locally rather than moving it.
	 */
	background-color: rgba(255, 255, 255, 0.2);
}

.slider-rail__progress {
	position: absolute;
	inset: 0 auto 0 0;
	width: 50%;
	background-color: var(--white);
	transition: width var(--transition), transform var(--transition);
}

/* ---- the project cards ---- */

.project-cards {
	position: relative;
	overflow: hidden;
	background-color: var(--c-bg);
}

.project-cards__blueprint,
.more-solutions__blueprint,
.property-cards__blueprint {
	position: absolute;
	top: 0;
	left: 52.0139%;
	width: 53.3740%;
	aspect-ratio: 768.585 / 738.546;
	background-image: url("../icons/blueprint-testimonials.svg");
	background-repeat: no-repeat;
	background-size: 100% 100%;
	/*
	 * This drawing is the one pair that does NOT carry its own 0.1 inside the
	 * file — blueprint-testimonials and blueprint-problem are full strength, and
	 * the sections using them apply the opacity. Without it the lines print
	 * bright white over the band instead of sitting behind it.
	 */
	opacity: 0.1;
	pointer-events: none;
}

.project-cards__inner {
	gap: var(--gap-1);
	padding: var(--section-py) var(--gutter);
	overflow: hidden;
}

/* 846 of the 1280 column, centred. */
.project-cards__head {
	width: 66.0938%;
	align-self: center;
}

.project-cards__title,
.more-solutions__title {
	width: 100%;
	color: var(--c-ink);
	font-size: var(--fs-h2);
	line-height: var(--lh-tight);
	text-transform: uppercase;
}

.project-card {
	position: relative;
	display: flex;
	flex-direction: column;
	justify-content: space-between;
	gap: 32px;
	width: 410px;
	max-width: 84vw;
	height: auto;
	padding: var(--gap-4);
	background-color: #272629;
}

.project-card__head {
	display: flex;
	flex-direction: column;
	gap: 24px;
}

/*
 * The design gives each badge its own box — 112x38 for REIQ, 109x38 for HIA, 48x38
 * for the square Master Builders mark — all at the same 38px height, carried in
 * as `--logo-w`.
 *
 * The treatment differs per mark too: only REIQ is a white silhouette in the
 * design, so the mask lives on a modifier and the default is the logo in its
 * own colours, cover-cropped to the box exactly as the design does.
 */
.project-card__badge {
	position: relative;
	display: block;
	width: var(--logo-w, 112px);
	height: 38px;
	overflow: hidden;
}

.project-card__badge img {
	position: absolute;
	inset: 0;
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.project-card__badge--mask {
	background-color: var(--white);
	-webkit-mask-image: var(--logo);
	mask-image: var(--logo);
	-webkit-mask-repeat: no-repeat;
	mask-repeat: no-repeat;
	-webkit-mask-position: left center;
	mask-position: left center;
	-webkit-mask-size: contain;
	mask-size: contain;
}

/*
 * The button is a real link now, so it has to sit above the full-card overlay
 * — otherwise the overlay swallows the press and the button is decorative
 * again, which is exactly what it used to be.
 */
.project-card__cta {
	position: relative;
	z-index: 2;
}

.project-card__title {
	color: var(--c-ink);
	font-size: var(--fs-h4);
	line-height: var(--lh-tight);
	text-transform: uppercase;
	text-box-trim: trim-both;
	text-box-edge: cap alphabetic;
}

.project-card__title a {
	color: inherit;
}

.project-card__quote {
	color: var(--c-ink);
	font-size: var(--fs-body);
	font-weight: 300;
	line-height: var(--lh-body);
}

.project-card__foot {
	display: flex;
	flex-direction: column;
	gap: 32px;
}

.project-card__media {
	position: relative;
	height: 200px;
	overflow: hidden;
}

.project-card__media img {
	position: absolute;
	inset: 0;
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.project-card__cta {
	align-self: flex-start;
}

/* The whole tile is the link; the button repeats it for the pointer. */
.project-card__hit {
	position: absolute;
	inset: 0;
	z-index: 1;
}

.project-card__title a,
.project-card__cta {
	position: relative;
	z-index: 2;
}

.project-card:hover .project-card__title {
	color: var(--c-accent);
}

/* ---- more solutions ---- */

.more-solutions {
	position: relative;
	overflow: hidden;
	background-color: var(--c-bg);
}

.more-solutions__inner {
	gap: var(--gap-1);
	padding: var(--section-py) var(--gutter);
	overflow: hidden;
}

/*
 * Above the carousel breakpoint every one of these rows is a plain grid: Swiper
 * has destroyed itself, so the wrapper is an ordinary flex row and the cards
 * give up their fixed width to share the 1280.
 */
@media (min-width: 901px) {

	/*
	 * Featured Projects and More Solutions hold exactly three cards, which at a
	 * 24px gap share the 1280 container as the design's 410 — so above the grid
	 * breakpoint they are a plain row and Swiper stays out of it.
	 *
	 * How We Help is NOT in this list. The design lays its four cards on
	 * a 410 + 24 pitch inside the same 1280 frame, which puts the fourth at
	 * x=1302 — clipped, with a rail and arrows drawn beneath it. Sharing the
	 * width equally instead squeezed all four to 302 and made the desktop
	 * arrows decorative, so that band stays a real carousel at every width.
	 */
	.more-solutions__swiper .swiper-wrapper {
		display: flex;
		align-items: stretch;
		gap: 24px;
	}

	.more-solutions__swiper .solution-card {
		flex: 1 0 0;
		width: auto;
		min-width: 0;
		max-width: none;
	}

	/*
	 * Featured Projects is a carousel at every width, not a static row. The design
	 * The design fits exactly three 410.67 cards across the 1280 frame and
	 * draws a rail and arrows beneath them — which only makes sense because
	 * there are more projects than fit. With seven seeded, a static row
	 * squeezed all seven in and the cards grew to 732 tall.
	 */
	.project-cards__swiper .project-card {
		width: auto;
		min-width: 0;
		max-width: none;
	}

	/*
	 * The design fixes the project card at 548 rather than letting it hug: the
	 * tallest content only comes to 513, and the remaining 35 is the gap
	 * justify-between opens between the quote and the photograph. Without it
	 * the row sits 64 short of the design.
	 */
	.project-card {
		min-height: 548px;
	}
}

@media (max-width: 900px) {
	.how-we-help__head {
		flex-direction: column;
		align-items: stretch;
		gap: var(--gap-4);
	}

	.how-we-help__head .section-head {
		flex: 0 0 auto;
	}

	.help-card,
	.project-card {
		width: 316px;
	}

	/* No arrow on the solution card in this band either — the design's default
	   variant, and its reserved width re-breaks the longest label. */
	.more-solutions__swiper .solution-card__arrow {
		display: none;
	}
}

/* ==================================================== projects listing ==
   the design, mobile.
   ======================================================================= */

/*
 * The listing banner is 480 tall, not the 648 a page uses ( against
 *) — everything else about it is the same band.
 */
.page-banner--compact {
	min-height: 480px;
}

@media screen and (min-width: 1600px) {
	.post-type-archive-bbqld_project .page-banner__image {
		object-position: 0 -200px;
	}
}

.project-archive {
	position: relative;
	overflow: hidden;
	background-color: var(--c-bg);
}

.project-archive__blueprint {
	position: absolute;
	top: -3px;
	left: -161px;
	width: 507.849px;
	height: 488px;
	background-image: url("../images/blueprint-testimonials.svg");
	background-repeat: no-repeat;
	background-size: contain;
	opacity: 0.1;
	pointer-events: none;
}

.project-archive__inner {
	position: relative;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: var(--gap-2);
	width: 100%;
	max-width: calc(var(--container-max) + var(--gutter) * 2);
	margin-inline: auto;
	padding: 0 var(--gutter) var(--section-py);
}

/* ---- the wide featured tile ---- */

.project-feature {
	display: flex;
	gap: 48px;
	align-items: stretch;
	width: 100%;
	padding: 48px;
	background-color: var(--c-bg-alt);
}

/*
 * The design fixes the copy column at 580. That is 580 of the tile's CONTENT box —
 * 1278 less its 48px padding either side, so 1182 — not of the tile's outer
 * width, which is what a naive 580/1278 gives and lands 43px short.
 */
.project-feature__copy {
	display: flex;
	flex: 0 0 49.0693%;
	flex-direction: column;
	justify-content: space-between;
	gap: 32px;
}

.project-feature__head {
	display: flex;
	flex-direction: column;
	gap: 24px;
}

.project-feature__title {
	color: var(--c-ink);
	font-size: var(--fs-h4);
	line-height: var(--lh-tight);
	text-transform: uppercase;
	text-box-trim: trim-both;
	text-box-edge: cap alphabetic;
}

.project-feature__title a {
	color: inherit;
	text-decoration: none;
	transition: color var(--transition);
}

.project-feature__title a:hover {
	color: var(--c-accent);
}

.project-feature__quote {
	color: var(--c-ink);
	font-size: var(--fs-body);
	font-weight: 300;
	line-height: var(--lh-body);
}

.project-feature__cta {
	align-self: flex-start;
}

/*
 * The photograph takes the rest of the row at a fixed 280 tall, and the image
 * is out of flow so a portrait upload cannot stretch the tile.
 */
.project-feature__media {
	position: relative;
	flex: 1 1 auto;
	min-width: 0;
	height: 280px;
	overflow: hidden;
}

.project-feature__media img {
	position: absolute;
	inset: 0;
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* ---- toolbar ---- */

.project-archive__toolbar {
	display: flex;
	gap: var(--gap-4);
	align-items: flex-end;
	width: 100%;
}

.project-archive__heading {
	flex: 1 1 auto;
	color: var(--c-ink);
	font-size: var(--fs-h4);
	line-height: var(--lh-tight);
	text-transform: uppercase;
	text-box-trim: trim-both;
	text-box-edge: cap alphabetic;
}

/*
 * The design draws the sort control as a 200px field with a 1px rule at 20% white
 * and a caret on the right. It is a real <select> so it works without
 * scripting; the native arrow is removed in favour of the design's caret.
 */
.project-sort {
	position: relative;
	flex: 0 0 200px;
	display: flex;
	align-items: center;
	padding: 8px 0 6px;
	border-bottom: 1px solid rgba(255, 255, 255, 0.2);
}

.project-sort__select {
	width: 100%;
	padding: 0 24px 0 0;
	background: transparent;
	color: var(--c-ink);
	font-family: var(--font-body);
	font-size: var(--fs-small);
	font-weight: 300;
	line-height: 20px;
	border: 0;
	border-radius: 0;
	cursor: pointer;
	appearance: none;
}

/* The panel is painted by the OS, so it needs a ground of its own. */
.project-sort__select option {
	color: var(--c-ink-dark);
	background-color: var(--white);
}

.project-sort__caret {
	position: absolute;
	right: 0;
	display: block;
	width: 20px;
	height: 20px;
	color: var(--c-ink);
	pointer-events: none;
}

.project-sort__caret svg {
	display: block;
	width: 20px;
	height: 20px;
}

/* ---- grid ---- */

.project-archive__grid {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: 24px;
	width: 100%;
}

/*
 * The grid card is the same component as Featured Projects, so it only needs
 * its width freeing from the carousel's fixed 410.
 */
.project-archive__grid .project-card {
	width: auto;
	max-width: none;
	min-height: 545px;
}

/* ---- pagination ---- */

.pagination {
	display: flex;
	gap: 16px;
	align-items: center;
	justify-content: center;
}

/*
 * layout.css gives the generic pagination a 48 top margin, which is right on
 * the blog where it follows a plain list. Here the listing column is a flex
 * stack that already opens --gap-2 between its children, so the two stacked
 * and the row sat 96 below the grid against the design's 48 ( at
 * y=1668 under a grid ending at 1620).
 */
.project-archive__inner .pagination {
	margin-top: 0;
}

.pagination .page-numbers {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 44px;
	height: 44px;
	color: var(--c-ink);
	font-family: var(--font-heading);
	font-size: var(--fs-body);
	line-height: var(--lh-tight);
	text-decoration: none;
	border: 1px solid var(--white);
	border-radius: 50%;
	opacity: 0.4;
	transition: opacity var(--transition), background-color var(--transition), color var(--transition);
}

.pagination .page-numbers:hover {
	opacity: 1;
}

/* The page you are on is solid white with dark text, and not dimmed. */
.pagination .page-numbers.current {
	color: var(--c-ink-dark);
	background-color: var(--white);
	border-color: rgba(0, 0, 0, 0.01);
	opacity: 1;
}

.pagination .page-numbers.dots {
	border-color: transparent;
}

@media (max-width: 900px) {
	.page-banner--compact {
		min-height: 480px;
	}

	/* Mobile stacks the tile: copy, button, then the photograph. */
	.project-feature {
		flex-direction: column;
		gap: 24px;
		padding: 24px;
	}

	.project-feature__copy {
		flex: 0 0 auto;
		gap: 24px;
	}

	.project-feature__media {
		width: 100%;
		height: 200px;
	}

	.project-archive__toolbar {
		flex-direction: column;
		align-items: stretch;
		gap: 24px;
	}

	.project-sort {
		flex: 0 0 auto;
	}

	.project-archive__grid {
		grid-template-columns: 1fr;
	}

	.project-archive__grid .project-card {
		width: auto;
		min-height: 0;
		/*
		 * 24, not the carousel card's 32, at both the head-to-photograph and
		 * the photograph-to-button joins. The four flat cards in —
		 * 5086, 5097, 5108, 5133 — all come to 507 that way; the two the design
		 * grouped into a sub-frame (5074, 5119) carry one 32 and come to 515,
		 * which is the same authoring slip the desktop frame has. The
		 * carousel's own mobile card really is 32, so this stays
		 * scoped to the listing rather than moving on the shared component.
		 *
		 * --gap-4, not --gap-5: --gap-5 bottoms out at 20 below 1200.
		 */
		gap: var(--gap-4);
	}

	.project-archive__grid .project-card__foot {
		gap: var(--gap-4);
	}
}

/* ======================================================= customers page ==
   the design, mobile. Every band is reused, so the
   only thing here is where this page's design differs from the one the band
   was built against.
   ======================================================================= */

@media (max-width: 900px) {

	/*
	 * The two designs disagree on the mobile solutions card: the Solutions page
	 * draws it 316 wide, this page draws it 302.
	 * Both are carousels with a 24px gap and the next card peeking, so the only
	 * difference is the card itself — scoped to this template rather than
	 * changed for both.
	 */
	.page-template-page-customers .solutions-grid .solution-card {
		width: 302px;
	}
}

/*
 * A customer page closes its opening band with a rule and the two partner
 * marquees: the copy ends at 611, the rule sits at
 * 659, the marquees run 707 to 899, and the band closes at 979.
 *
 * That means the copy column's own bottom padding has to come off — otherwise
 * the 80 lands between the copy and the rule instead of under the marquees,
 * which left the band 107 short of the design.
 */
.single-bbqld_customer .solution-overview__inner,
.single-bbqld_location .solution-overview__inner {
	padding-bottom: 0;
}

.solution-overview__marquees {
	display: flex;
	flex-direction: column;
	gap: 48px;
	padding-top: 48px;
	padding-bottom: var(--section-py);
}

.solution-overview__rule {
	width: 100%;
	height: 0;
	margin: 0;
	border: 0;
	border-top: 1px solid var(--c-line);
}

/* The rows are 80 tall with 32 between them, as under the testimonials. */
.solution-overview__marquees .logo-marquees {
	display: flex;
	flex-direction: column;
	gap: 32px;
}

/* ---- location detail: where this page differs from the bands it reuses ----
   the design /. -------------------------------------- */

/*
 * The same raised surface the customer pages open on. Measured, not guessed:
 * the wedge cut out of's top-left corner is painted flat #272629,
 * which is the band behind it.
 */
.single-bbqld_location .solution-overview {
	background-color: #272629;
}

.single-bbqld_location .page-banner__media::after {
	background-image: linear-gradient(180deg, rgba(25, 24, 27, 0) 0%, #272629 100%);
}

/*
 * The blog listing, and the archives and search that share its band, do the
 * same thing:'s scrim ends on #272629, which is the ground of the
 * band directly beneath it, so the photograph fades INTO that band with no
 * seam. Ending on #19181B instead — darker than the band below — left a dark
 * strip across the full width between the photograph and the featured post.
 */
/*
 * The consultation banner does the same: the band directly beneath it is
 * #272629, so ending the scrim on #19181B drew a dark line across the full
 * width between the photograph and the panel.
 */
/*
 * .category/.tag/.date/.author, NOT .archive. WordPress puts `archive` on the
 * body for EVERY post type archive, so this rule — written for the blog's own
 * taxonomy and date archives, which sit on a #272629 band — was also landing on
 * /property/ and /land/, whose band is #19181B. That left the scrim finishing
 * 14 levels lighter than the section under it and drew a hard horizontal seam
 * across the full width exactly at the banner's foot.
 *
 * Naming the four blog archive classes cannot catch a post type archive, so the
 * trap is removed rather than counter-patched for the two types that exist
 * today.
 */
.page-template-page-contact .page-banner__media::after,
.blog .page-banner__media::after,
.category .page-banner__media::after,
.tag .page-banner__media::after,
.date .page-banner__media::after,
.author .page-banner__media::after,
.search .page-banner__media::after {
	background-image: linear-gradient(180deg, rgba(25, 24, 27, 0) 0%, #272629 100%);
}

/*
 * MIRRORED. Every other page that draws the overview band puts the photograph
 * on the left; here the copy sits there and the photograph on the right.
 *
 * One `order` on the media does both breakpoints: in the desktop row it moves
 * to the right of the copy, and in the stacked mobile column it
 * falls BELOW the copy, which is where that frame draws it — the opposite of
 * the solution and customer pages, where the photograph is on top.
 */
.single-bbqld_location .solution-overview__media {
	order: 2;
}

/*
 * This band opens at 80, not the 64 every other page uses — the design puts
 * its inner frame at y=80 where the design puts it at 64. The 48 to the rule
 * and the 48 to the marquees below come from .solution-overview__marquees,
 * with the inner's own bottom padding zeroed just as on a customer page.
 */
.single-bbqld_location .solution-overview__inner {
	padding-top: var(--section-py);
}

/*
 * The design sets the copy 48 above the photograph on mobile, where the
 * stacked band otherwise uses 40. Scoped to this page rather than changed for
 * everyone — 40 is what the solution and customer mobile frames were measured
 * against, and those are a different stack (photograph on top).
 */
@media (max-width: 1024px) {
	.single-bbqld_location .solution-overview__inner {
		gap: 48px;
	}
}

/* ---- customer detail: where this page differs from the bands it reuses ---- */

/*
 * The opening band sits on the design's raised surface here, not
 * on the page ground a solution page uses.
 */
.single-bbqld_customer .solution-overview {
	background-color: #272629;
}

/* the design drops the trail to 60% on this page. */
.single-bbqld_customer .page-banner__crumbs ol {
	opacity: 0.6;
}

/*
 * A customer banner is one row — the H1 on the left, a 519px copy column on
 * the right, vertically centred — with the hairline beneath them both
 *. The 32px between it and the rule is the band's own gap.
 */
.page-banner__row {
	display: flex;
	gap: var(--gap-6);
	align-items: center;
	justify-content: space-between;
	width: 100%;
}

/*
 * The heading takes the room the 519 copy column leaves, and WRAPS into it.
 *
 * flex: 0 1 auto with the default min-width: auto cannot shrink below its own
 * content, so a long title stayed on one line and pushed the copy past the
 * container — "Subdivision & Development" measured 1036 beside a 519 column in
 * a 1280 row, putting the copy's right edge at 1651. The design gives the
 * heading flex 1 and a min-width it can shrink through, which is what lets it
 * break to a second line instead.
 */
.page-banner__row .page-banner__title {
	flex: 1 1 0;
	min-width: 0;
}

.page-banner__copy {
	display: flex;
	flex: 0 0 519px;
	flex-direction: column;
	gap: 8px;
	max-width: 519px;
}

.page-banner__lead {
	color: var(--c-ink);
	font-size: var(--fs-body);
	font-weight: 500;
	line-height: var(--lh-body);
}

.page-banner__copy .page-banner__blurb {
	max-width: none;
	margin-left: 0;
}

/* The banner's photograph fades into the design's raised surface here. */
.single-bbqld_customer .page-banner__media::after {
	background-image: linear-gradient(180deg, rgba(25, 24, 27, 0) 0%, #252427 100%);
}

.single-bbqld_customer .page-banner__media img {
	object-position: top center;
}

@media (max-width: 1024px) {
	.page-banner__row {
		flex-direction: column;
		align-items: flex-start;
		gap: 24px;
	}

	.page-banner__row .page-banner__title {
		white-space: normal;
	}

	.page-banner__copy {
		flex: 0 0 auto;
		max-width: none;
	}
}

/* ============================================================ about us ==
   Desktop 42401:2891 (1440x6426), mobile 42513:3707 (390x8356).

   Measured frames:
     hero      512 tall, py 48, crumb at 60% 8 above a centred row
     video     600 tall full bleed, 64px control centred      (mobile 300)
     story     745; inner 1280x585 at 80/80, copy 564, gap 24
     team     1030; copy 519, cards 697 (2 x 336.5), portrait 464, gap 64
               (mobile 1813: one card per row at 342, gap 16)

   The team band REPLACED "Meet Anthony" (42401:2919 / 43466:8057). That band
   was one man's portrait and a pull quote at 782 tall; it is now a copy column
   beside a row of portrait cards at 1030, and Is This You grew 835 -> 870 in
   the same revision.
   ======================================================================= */

/* ---- Container: the short hero ---- */

/*
 * A GRADIENT, not a picture. The Container is a flat #19181B carrying two
 * EMPTY `mix-blend-screen` layers at 20% — despite their
 * names they hold no video and no image, so all they do is lift the ground.
 *
 * BROWN, NOT THE DESIGN'S VIOLET, at the client's request (2026-09-17). The
 * frame ramped #1C1822 to #201A36, picking up a purple cast toward the foot.
 * There is no brown in the palette to reach for — it is --title #19181B,
 * --primary #E91E22 and white — so rather than invent one, each stop keeps its
 * saturation and lightness EXACTLY and only its hue is rotated, 253-260 degrees
 * round to 25. The ramp therefore has the depth and the shape the design drew,
 * warm instead of cool, and sits with the red accent rather than against it.
 * Relative luminance moves by at most 0.009, which is green carrying more
 * perceived weight than blue at the same HSL lightness, not a change of value.
 */
.about-hero {
	position: relative;
	display: flex;
	flex-direction: column;
	justify-content: flex-end;
	min-height: 512px;
	padding: 48px var(--gutter);
	overflow: hidden;
	background-color: #19181b;
	background-image: linear-gradient(180deg, #211c18 0%, #211c18 35%, #292019 55%, #36261a 100%);
	color: var(--white);
}

.about-hero__inner {
	position: relative;
	display: flex;
	flex-direction: column;
	gap: 8px;
	width: 100%;
	max-width: var(--container-max);
	margin-inline: auto;
}

/* — the trail sits at 60% here, where the 648 banner keeps it full. */
.about-hero__crumbs ol {
	opacity: 0.6;
}

.about-hero__row {
	display: flex;
	gap: var(--gap-5);
	align-items: center;
	justify-content: space-between;
	width: 100%;
}

.about-hero__title {
	flex: 1 0 0;
	min-width: 0;
	font-size: var(--fs-h1);
	font-weight: 400;
	line-height: 1.3;
	letter-spacing: -2px;
	text-transform: uppercase;
}

.about-hero__blurb {
	flex: 0 0 519px;
	max-width: 519px;
	font-size: var(--fs-small);
	font-weight: 300;
	line-height: var(--lh-body);
}

/* ---- the full-bleed video ---- */

.about-video {
	position: relative;
	height: 600px;
	overflow: hidden;
	background-color: var(--c-bg);
}

.about-video__video,
.about-video__image {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* — a 64px white disc, centred, holding a 32px glyph. */
.about-video__toggle {
	position: absolute;
	top: 50%;
	left: 50%;
	display: flex;
	width: 64px;
	height: 64px;
	align-items: center;
	justify-content: center;
	padding: 0;
	border: 1.333px solid rgba(0, 0, 0, 0.01);
	border-radius: 48px;
	background-color: var(--white);
	transform: translate(-50%, -50%);
	cursor: pointer;
}

.about-video__icon {
	display: flex;
	width: 32px;
	height: 32px;
	align-items: center;
	justify-content: center;
}

.about-video__icon svg {
	width: 32px;
	height: 32px;
}

.about-video__icon svg path {
	/* --c-accent, not --c-primary: the latter does not exist, and an invalid
	   var() made the path inherit `fill: none` from the <svg> and vanish. */
	fill: var(--c-accent);
}

/* One button, two states: the design draws it over a video already playing. */
.about-video__icon--play,
.about-video__toggle[aria-pressed="true"] .about-video__icon--pause {
	display: none;
}

.about-video__toggle[aria-pressed="true"] .about-video__icon--play {
	display: flex;
}

/* ---- Our Story ---- */

.about-story {
	position: relative;
	overflow: hidden;
	background-color: var(--c-bg);
}

.about-story__inner {
	display: flex;
	gap: var(--gap-5);
	align-items: center;
	width: 100%;
	max-width: calc(var(--container-max) + var(--gutter) * 2);
	margin-inline: auto;
	padding: var(--section-py) var(--gutter);
}

/* 564 of the 1280 content column, and 31 between its parts — not 32. */
.about-story__copy {
	display: flex;
	flex: 0 0 44.0625%;
	flex-direction: column;
	gap: 31px;
	align-items: flex-start;
	min-width: 0;
}

.about-story .section-head {
	gap: var(--gap-4);
}

.about-story .section-head__title {
	text-box-trim: trim-both;
	text-box-edge: cap alphabetic;
}

.about-story__body {
	color: var(--c-ink);
	font-size: var(--fs-body);
	font-weight: 300;
	line-height: var(--lh-body);
	opacity: 0.8;
}

/* The design draws two paragraphs 16 apart. */
.about-story__body p+p {
	margin-top: 16px;
}

.about-story__media {
	display: flex;
	flex: 1 0 0;
	gap: var(--gap-5);
	align-items: flex-start;
	min-width: 0;
}

/* The design drew these unequal — 512 and 400, the shorter one top-aligned so
   the pair finished ragged. The client asked for them matched (2026-09-17), so
   both take the taller of the two: it closes the gap under the right-hand
   photograph without shortening the block or disturbing the copy column beside
   it, which is what sets this band's height. */
.about-story__figure {
	position: relative;
	flex: 1 0 0;
	min-width: 0;
	height: 512px;
	overflow: hidden;
}

.about-story__figure img {
	position: absolute;
	inset: 0;
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* ---- Meet Anthony ---- */

/*
 * #272629, the raised surface — NOT the page ground Our Story sits on. Sampled
 * either side of the boundary in the design: the design is #19181B at y=1850
 * and the design is #272629 at y=1870.
 *
 * clip-path rather than overflow. The blueprint hangs 351 ABOVE this band
 * and the design draws it running continuously
 * across the boundary into Our Story — `overflow: hidden` chopped it dead
 * along the band's top edge, which is the seam the client pointed at.
 * inset() with a negative top opens the clip upward while still trimming the
 * 850px-wide drawing at the left and right edges, so nothing overflows the
 * page sideways.
 */
.about-team {
	position: relative;
	background-color: #272629;
	padding-block: var(--section-py);
}

/*
 * The clip, and it has to be its own element.
 *
 * The design hangs the blueprint 351 ABOVE this band and runs it continuously
 * across the boundary into Our Story — `overflow: hidden` on the band chopped
 * it dead along the top edge, which is the seam the client pointed at.
 * `clip-path` on the band was tried instead and clips the PAINT but not the
 * scroll width, so the 850px-wide drawing still widened the page.
 *
 * This wrapper spans the band's width exactly, so nothing overflows sideways,
 * and reaches 351 above its top, so the drawing crosses the boundary intact.
 */
.about-team__blueprint-clip {
	position: absolute;
	top: -351px;
	right: 0;
	left: 0;
	height: calc(100% + 351px);
	overflow: hidden;
	pointer-events: none;
}

/*
 * This band's OWN drawing, not the homepage's.
 *
 * It was pointed at blueprint-about.svg — the about band's Group, a different
 * drawing at 0.2/0.4 white. Fitting our render against the design's own export
 * put the best opacity multiplier at 0.022, which is what a complete shape
 * mismatch looks like: where we drew lines, the design has none. The exported
 * Group is `opacity="0.1"` filled #E8E9F5 (Background), against white at up to
 * 0.4 — hence both too bright and in the wrong places.
 *
 * 850.231 x 817 at x=865, y=-351 from the band's top.
 */
.about-team__blueprint {
	position: absolute;
	top: 0;
	left: 60.0694%;
	width: 59.0439%;
	aspect-ratio: 850.231 / 817;
	background-image: url("../icons/blueprint-anthony.svg");
	background-repeat: no-repeat;
	background-size: 100% 100%;
}

/*
 * 64 between the copy and the cards, stated rather than taken from --gap-1.
 * The design uses a literal 64 at BOTH breakpoints — it is the one gap on this
 * band that does not shrink on a phone — where --gap-1 clamps to 48 under 1080.
 */
.about-team__inner {
	position: relative;
	display: flex;
	gap: 64px;
	align-items: flex-start;
	width: 100%;
	max-width: calc(var(--container-max) + var(--gutter) * 2);
	margin-inline: auto;
	padding-inline: var(--gutter);
}

/*
 * The copy column: 519 in the frame, against Our Story's 564.
 *
 * align-items: flex-start for the BUTTON, which is the only child that should
 * not fill the column — stretched, it ran the full 519 and read as a banner
 * rather than a control. The heading and the blurb are unaffected: their text
 * is longer than the column, so fit-content still resolves to the full width.
 */
.about-team__head {
	display: flex;
	flex: 0 0 519px;
	flex-direction: column;
	gap: var(--gap-4);
	align-items: flex-start;
	min-width: 0;
	max-width: 519px;
}

.about-team .section-head {
	gap: var(--gap-4);
}

.about-team .section-head__title {
	text-box-trim: trim-both;
	text-box-edge: cap alphabetic;
}

.about-team__blurb {
	margin: 0;
	color: var(--c-ink);
	font-size: var(--fs-body);
	font-weight: 300;
	line-height: var(--lh-body);
	opacity: 0.8;
}

/*
 * Two per row that WRAP, where the design gives each card `flex: 1 0 0`.
 *
 * With the two people the frame draws, the two resolve to the same 336.5 the
 * design specifies — (1280 - 519 - 64 - 24) / 2. The difference only shows on
 * the third: flex would have squeezed all three to 216 under a 464-tall
 * photograph, a portrait twice as tall as it is wide, where the grid starts a
 * second row and every card keeps its designed width.
 */
.about-team__grid {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: var(--gap-5);
	flex: 1 1 0;
	min-width: 0;
	margin: 0;
	padding: 0;
	list-style: none;
}

/*
 * The design's backdrop-blur-[4px]. It does nothing behind the photograph,
 * which is opaque — it is there for the caption block, where the blueprint
 * drawing passes behind the band and would otherwise read through the type.
 */
.about-team__card {
	display: flex;
	flex-direction: column;
	min-width: 0;
	backdrop-filter: blur(4px);
}

/*
 * The portrait is 336.5 x 464 in the frame, which is exactly the 673 x 928 the
 * asset exports at. Held as a RATIO rather than a 464px height so the card
 * keeps the designed proportion at every width between the breakpoints instead
 * of squashing the crop as the column narrows.
 */
.about-team__portrait {
	position: relative;
	width: 100%;
	margin: 0;
	aspect-ratio: 673 / 928;
	overflow: hidden;
}

.about-team__portrait img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* 16 above and below the caption block, 8 between the two lines. */
.about-team__meta {
	display: flex;
	flex-direction: column;
	gap: 8px;
	padding-block: var(--gap-6);
}

.about-team__name {
	margin: 0;
	color: var(--c-ink);
	font-family: var(--font-heading);
	font-size: var(--fs-h5);
	font-weight: 400;
	line-height: 1.2;
	text-transform: uppercase;
}

.about-team__role {
	margin: 0;
	color: var(--c-ink);
	font-size: var(--fs-body);
	font-weight: 300;
	line-height: var(--lh-body);
	opacity: 0.8;
}

.about-team__marquees {
	position: relative;
	display: flex;
	flex-direction: column;
	gap: var(--gap-1);
	padding-top: var(--gap-1);
}

.about-team__rule {
	width: calc(100% - var(--gutter) * 2);
	height: 0;
	margin: 0 auto;
	border: 0;
	border-top: 1px solid var(--c-line);
}

.about-team__marquees .logo-marquees {
	display: flex;
	flex-direction: column;
	gap: var(--gap-4);
}

@media (max-width: 1024px) {

	/* The design stacks the hero row, 24 apart. */
	.about-hero__row {
		flex-direction: column;
		gap: var(--gap-5);
		align-items: flex-start;
	}

	.about-hero__title,
	.about-hero__blurb {
		flex: 0 0 auto;
		max-width: none;
		width: 100%;
	}

	/* — half the height on mobile. */
	.about-video {
		height: 300px;
	}

	/* 24 between the copy and the photographs, and 24 inside the copy
 — not the 20 --gap-5 clamps to at this width. */
	.about-story__inner {
		flex-direction: column;
		align-items: stretch;
		gap: 24px;
	}

	.about-story__copy {
		flex: 0 0 auto;
		gap: 24px;
	}

	/*
	 * — stacked, both 200 tall, 16 apart, and FULL WIDTH.
	 * align-items has to be restated: the desktop row's flex-start would
	 * shrink each figure to its content, and the photographs are out of flow,
	 * so there is no content to size against and both came out 0 wide.
	 */
	.about-story__media {
		flex-direction: column;
		align-items: stretch;
		gap: 16px;
	}

	/*
	 * flex, not height. Once the row becomes a column the desktop rule's
	 * `flex: 1 0 0` is a ZERO BASIS on the main axis, which beats `height` and
	 * collapsed both photographs to nothing.
	 */
	.about-story__figure {
		flex: 0 0 200px;
		height: 200px;
	}

	/*
	 * The copy stacks above the cards, still 64 apart — the design keeps that
	 * gap at full size on a phone where every other gap on the band shrinks,
	 * so the row simply turns without restating its gap.
	 */
	.about-team__inner {
		flex-direction: column;
	}

	.about-team__head {
		flex: 0 0 auto;
		max-width: none;
	}


	/*
	 * The mobile card is 342 x 464 where the desktop one is 336.5 x 464, so the
	 * ratio is restated rather than inherited — the desktop figure would have
	 * drawn the phone's portrait 8px taller than the frame.
	 */
	.about-team__portrait {
		aspect-ratio: 342 / 464;
	}

	/* The two marquee rows stay 32 apart here. */
	.about-team__marquees .logo-marquees {
		gap: 32px;
	}
}

@media (max-width: 500px) {

	/*
	 * ONE column, not two narrowed ones. The mobile frame draws a single
	 * 342-wide card per row: two would have put a 464-tall portrait in a 159
	 * column.
	 */
	.about-team__grid {
		grid-template-columns: minmax(0, 1fr);
		gap: var(--gap-6);
	}
}

/* ============================== site acquisition & opportunity ==========
   the design, mobile (390x8624).
   ======================================================================= */

/* ---- centred intro over the ragged photo row ---- */

.site-intro {
	position: relative;
	overflow: hidden;
	background-color: var(--c-bg);
}

.site-intro__inner {
	display: flex;
	flex-direction: column;
	gap: var(--gap-4);
	align-items: center;
	width: 100%;
	max-width: calc(var(--container-max) + var(--gutter) * 2);
	margin-inline: auto;
	padding: var(--section-py) var(--gutter);
}

/* 846 of the 1280 column, centred, and 31 between the two — not 32. */
.site-intro__copy {
	display: flex;
	flex-direction: column;
	gap: 31px;
	width: 66.0938%;
	max-width: 846px;
	text-align: center;
}

.site-intro__title {
	color: var(--c-ink);
	font-size: var(--fs-h2);
	line-height: var(--lh-tight);
	text-transform: uppercase;
	text-box-trim: trim-both;
	text-box-edge: cap alphabetic;
}

.site-intro__body {
	color: var(--c-ink);
	font-size: var(--fs-body);
	font-weight: 300;
	line-height: var(--lh-body);
	opacity: 0.8;
}

/*
 * NOT a grid. Two of the four carry fixed widths from the design and the other
 * two share the remainder, which is what makes them 253.5 each; and all four
 * are different heights, top-aligned, so the row is ragged along the bottom by
 * design.
 */
.site-intro__row {
	display: flex;
	gap: var(--gap-5);
	align-items: flex-start;
	width: 100%;
}

.site-intro__figure {
	position: relative;
	margin: 0;
	overflow: hidden;
}

.site-intro__figure img {
	position: absolute;
	inset: 0;
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.site-intro__figure--a,
.site-intro__figure--d {
	flex: 1 0 0;
	min-width: 0;
}

.site-intro__figure--b {
	flex: 0 0 26.4844%;
	/* 339 of 1280 */
}

.site-intro__figure--c {
	flex: 0 0 28.2813%;
	/* 362 of 1280 */
}

.site-intro__figure--a {
	height: 400px;
}

.site-intro__figure--b {
	height: 355px;
}

.site-intro__figure--c {
	height: 512px;
}

.site-intro__figure--d {
	height: 452px;
}

/*
 * What We Assess is the overview band MIRRORED, exactly as the
 * location pages draw it: copy on the left, the 519 photograph on the right,
 * and on mobile the photograph BELOW the copy rather than above it.
 */
.page-template-page-site-acquisition .solution-overview__media {
	order: 2;
}

/*
 * The raised surface, not the page ground. Read off the photograph rather than
 * guessed:'s cut corner is filled #272629, and a wedge is filled
 * with whatever sits behind it.
 */
.page-template-page-site-acquisition .solution-overview {
	background-color: #272629;
}

/*
 * The overview opens at 80 here where the solution pages open at 64 —
 * sits at y=80 in its band. Scoped, so the solution pages keep the spacing they
 * were signed off with. How We Help used to need the same push; it now opens at
 * 80 everywhere, to match the property gallery.
 */
.page-template-page-site-acquisition .solution-overview__inner {
	padding-top: var(--section-py);
}

@media (max-width: 1024px) {

	/* — the copy column goes full width and the row stacks. */
	.site-intro__copy {
		width: 100%;
		max-width: none;
		gap: 24px;
		text-align: left;
	}

	/*
	 * Four equal 342x200 bands, 24 apart. flex, not height: in a
	 * column the desktop `flex: 1 0 0` is a zero basis on the main axis and
	 * would beat `height`, and align-items has to be restated or the figures
	 * shrink to their out-of-flow content and come out zero wide.
	 */
	.site-intro__row {
		flex-direction: column;
		align-items: stretch;
		gap: var(--gap-5);
	}

	.site-intro__figure--a,
	.site-intro__figure--b,
	.site-intro__figure--c,
	.site-intro__figure--d {
		flex: 0 0 200px;
		height: 200px;
	}

	/* The design sets the copy 40 above the photograph here. */
	.page-template-page-site-acquisition .solution-overview__inner {
		gap: 40px;
	}
}

/* ============================================================ resources ==
   the design, mobile (390x4537).
   ======================================================================= */

/*
 * The banner is 480 here, not 648, and it carries no foot at all —
 * is the crumb, the H1 and the hairline and nothing after. The template does
 * that part on its own: page-banner.php only prints a foot when it has a blurb
 * or a button, and this page has neither.
 */
.page-template-page-resources .page-banner {
	min-height: 480px;
}

.page-template-page-resources .page-banner__media::after {
	background-image: linear-gradient(180deg, rgba(25, 24, 27, 0) 0%, #272629 100%);
}

/*
 * The head ROW both bands take here: eyebrow and heading on the left, the
 * button on the right of the same line, its baseline sitting with the last
 * line of the heading — both bands put it at y=119 against a 163-tall head,
 * so the button is bottom-aligned, not centred.
 */
.insights__head--row,
.project-cards__head--row,
.galleries__head--row,
.property-cards__head--row {
	display: flex;
	/* 32, not 24: the head is 1042 and the button starts at 1074. */
	gap: var(--gap-4);
	align-items: flex-end;
	justify-content: space-between;
	width: 100%;
	/* The centred homepage head is capped at 1062; this one spans the full
	   1280 content column, with the button ending on the right gutter. */
	max-width: none;
	text-align: left;
}

.insights__head--row .section-head,
.project-cards__head--row .section-head,
.galleries__head--row .section-head,
.property-cards__head--row .section-head {
	flex: 1 1 auto;
	min-width: 0;
	align-items: flex-start;
	text-align: left;
}

.insights__head-cta,
.project-cards__head-cta,
.galleries__head-cta,
.property-cards__head-cta {
	flex: 0 0 auto;
}

@media (max-width: 1024px) {

	/*
	 * The design stacks the row and drops the button beneath the heading, 24
	 * below it, left-aligned.
	 */
	.insights__head--row,
	.project-cards__head--row,
	.galleries__head--row,
	.property-cards__head--row {
		flex-direction: column;
		/* --gap-4, not --gap-5: the comment above says 24 and --gap-5 bottoms
		   out at 20 below 1200, which is where the button was landing. */
		gap: var(--gap-4);
		align-items: flex-start;
	}
}

/* ======================================== galleries (Resources) ========
   The design 1440x767. VERTICAL, gap 64, padding 80 top and bottom.
   ======================================================================= */

/*
 * This band has a ground of its own — it does not sit on the page's #19181B
 * the way Featured Properties beneath it does. A raw fill in the file, not a
 * token, and one step off the #272629 the property and gallery TILES are drawn
 * on: near enough to read as the same grey, far enough that it is written out
 * rather than folded into that literal.
 */
.galleries {
	position: relative;
	overflow: hidden;
	background-color: #272628;
}

/*
 * The same drawing, size and anchor the Blogs & Insights band above it carries
 * — 507.85 x 488 at x=-161, y=-7 — so it overhangs the band's left edge.
 */
.galleries__blueprint {
	position: absolute;
	top: -7px;
	left: -161px;
	width: 507.85px;
	height: 488px;
	background-image: url("../icons/blueprint-insights.svg");
	background-repeat: no-repeat;
	background-size: 100% 100%;
	pointer-events: none;
}

.galleries__inner {
	position: relative;
	display: flex;
	flex-direction: column;
	gap: 64px;
	align-items: flex-start;
	width: 100%;
	max-width: calc(var(--container-max) + var(--gutter) * 2);
	margin-inline: auto;
	padding: var(--section-py) var(--gutter);
}

/*
 * Five across, 20 apart, which fills the 1280 column exactly: 5 x 240 + 4 x 20.
 * The tracks are fractions rather than a fixed 240 so the row keeps filling the
 * column as it narrows, and the tile holds the design's 4:3 while it does.
 */
.galleries__grid {
	display: grid;
	grid-template-columns: repeat(5, minmax(0, 1fr));
	gap: 20px;
	width: 100%;
	margin: 0;
	padding: 0;
	list-style: none;
}

.galleries__tile {
	margin: 0;
}

/*
 * 16px, unlike the property and project tiles, which carry none. The radius is
 * on the picture as well as the box it is clipped by: a transform on a rounded
 * ancestor can leak square corners for a frame mid-animation, and the file
 * rounds both anyway.
 */
.galleries__tile-btn {
	position: relative;
	display: block;
	width: 100%;
	padding: 0;
	border: 0;
	background: none;
	overflow: hidden;
	aspect-ratio: 240 / 180;
	border-radius: 16px;
	cursor: pointer;
}

.galleries__tile-btn img {
	display: block;
	width: 100%;
	height: 100%;
	border-radius: 16px;
	object-fit: cover;
	transition: transform var(--transition-slow);
}

.galleries__tile-btn:hover img,
.galleries__tile-btn:focus-visible img {
	transform: scale(var(--card-zoom, 1.04));
}

/*
 * Not drawn for mobile. Five 240 tiles cannot survive a 342 column, and the
 * pictures carry no copy, so the wall steps down rather than becoming a
 * carousel: three across where the head row stacks, two on a phone. The 4:3
 * does the rest.
 */
@media (max-width: 1024px) {
	.galleries__grid {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}
}

@media (max-width: 600px) {
	.galleries__grid {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		gap: 16px;
	}
}

/* ============================== featured properties (Resources) ========
   The design 1440x845. VERTICAL, gap 64, padding 80 top and bottom, and NO
   slider control under the row — that belongs to Featured Projects.
   ======================================================================= */

.property-cards {
	position: relative;
	overflow: hidden;
}

.property-cards__inner {
	position: relative;
	display: flex;
	flex-direction: column;
	gap: 64px;
	align-items: flex-start;
	width: 100%;
	max-width: calc(var(--container-max) + var(--gutter) * 2);
	margin-inline: auto;
	padding: var(--section-py) var(--gutter);
}

/*
 * Above the carousel breakpoint Swiper has never been created, so the wrapper
 * is an ordinary grid — three 410s sharing the 1280 column 24 apart, which is
 * the row the design draws and the one the property archive already uses.
 */
.property-cards__swiper {
	width: 100%;
	min-width: 0;
	overflow: visible;
}

.property-cards__swiper .swiper-wrapper {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: 24px;
	width: 100%;
}

/* The slide is a plain box; the card inside it is the design's tile. */
.property-cards__slide {
	display: flex;
	height: auto;
}

.property-cards__slide .property-card {
	width: 100%;
}

/*
 * Not drawn for mobile. Three 458-tall cards stacked is a very long band, and
 * every other card row on this page is a peeking carousel by this width — so
 * this one is too, on the same 316 card the Insights cards take.
 */
@media (max-width: 1024px) {
	.property-cards__swiper .swiper-wrapper {
		display: flex;
		gap: 0;
	}

	.property-cards__slide {
		width: 316px;
		max-width: 82vw;
	}

	.property-cards__inner {
		/* The row runs to the screen edge so the next card peeks, exactly as
		   the Insights band does; the JS puts the gutter back at the end. */
		padding-inline-end: 0;
	}

	.property-cards__head--row {
		padding-inline-end: var(--gutter);
	}
}

/* ===================================================== project detail ==
   the design, mobile.
   ======================================================================= */

/*
 * All three new bands trim their headings. The design marks them
 * [text-box-trim:trim-both] with [text-box-edge:cap alphabetic], which is the
 * difference between the frame's 165 for three lines and the 184.8 three
 * untrimmed lines measure.
 */
.project-overview .section-head__title,
.project-case .section-head__title,
.project-feedback .section-head__title {
	text-box-trim: trim-both;
	text-box-edge: cap alphabetic;
}

/* ---- overview ---- */

.project-overview {
	position: relative;
	padding: var(--section-py) 0;
	background-color: var(--c-bg);
}

.project-overview__inner {
	display: flex;
	/* 24 between the copy and the pair, and 24 again between the photograph
	   and the panel: 564 | 24 | 376 | 24 | 292 fills the 1280 column. */
	gap: var(--gap-5);
	align-items: center;
	width: 100%;
	max-width: calc(var(--container-max) + var(--gutter) * 2);
	margin-inline: auto;
	padding-inline: var(--gutter);
}

.project-overview__copy {
	display: flex;
	flex: 0 0 564px;
	flex-direction: column;
	gap: var(--gap-4);
	min-width: 0;
}

.project-overview__body {
	color: var(--c-ink);
	font-size: var(--fs-body);
	font-weight: 300;
	line-height: var(--lh-body);
}

.project-overview__body p {
	margin: 0;
}

/*
 * 16, not --gap-5's 24. Measured off the frame rather than assumed: the body
 * in the design runs at a 22 line pitch and a 38 paragraph pitch, so the extra
 * between paragraphs is 16 — the same value the About story uses.
 */
.project-overview__body p+p {
	margin-top: 16px;
}

.project-overview__media {
	display: flex;
	flex: 1 0 0;
	gap: var(--gap-5);
	/* The panel is 224 against the photograph's 512, so it hangs from the top
	   of the pair rather than stretching. */
	align-items: flex-start;
	min-width: 0;
}

.project-overview__figure {
	position: relative;
	flex: 0 0 376px;
	aspect-ratio: 376 / 512;
	overflow: hidden;
}

.project-overview__figure img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/*
 * The partner's mark on white. The design draws the mark 180x61 inside a 292x224
 * panel, i.e. centred with 56 either side, so the panel is a centring box with
 * an explicit cap on the mark rather than a padded one.
 */
.project-overview__panel {
	display: flex;
	flex: 1 0 0;
	align-items: center;
	justify-content: center;
	min-width: 0;
	aspect-ratio: 292 / 224;
	background-color: var(--white);
}

.project-overview__panel img {
	width: auto;
	max-width: 61.6438%;
	/* 180 of 292 */
	height: auto;
	max-height: 27.2321%;
	/* 61 of 224 */
	object-fit: contain;
}

/* ---- Frames 147 / 148: challenge and solution ---- */

.project-case {
	position: relative;
	overflow: hidden;
	padding: var(--section-py) 0;
	background-color: var(--c-bg);
}

/*
 * The page alternates its grounds: overview #19181B, Challenge #272629,
 * Solution back to #19181B, Customer Feedback #272629. Sampled off the band
 * renders — the design reads 39,38,41 where the design reads 25,24,27.
 */
.project-case--challenge {
	background-color: #272629;
}

/*
 * the design at (1046,-8), 507.85x488 — the same drawing and the same 10%
 * inking as the Insights band, hung off the RIGHT of the band here.
 */
.project-case__blueprint {
	position: absolute;
	top: -8px;
	left: 1046px;
	width: 507.85px;
	height: 488px;
	background-image: url("../icons/blueprint-insights.svg");
	background-repeat: no-repeat;
	background-size: 100% 100%;
	pointer-events: none;
}

.project-case__inner {
	position: relative;
	display: flex;
	gap: var(--gap-2);
	align-items: stretch;
	width: 100%;
	max-width: calc(var(--container-max) + var(--gutter) * 2);
	margin-inline: auto;
	padding-inline: var(--gutter);
}

.project-case--flip .project-case__inner {
	flex-direction: row-reverse;
}

.project-case__copy {
	display: flex;
	flex: 1 0 0;
	flex-direction: column;
	gap: var(--gap-4);
	min-width: 0;
}

.project-case__body {
	color: var(--c-ink);
	font-size: var(--fs-body);
	font-weight: 300;
	line-height: var(--lh-body);
}

.project-case__body p {
	margin: 0;
}

/*
 * 16, not --gap-5's 24. Measured off the frame rather than assumed: the body
 * in the design runs at a 22 line pitch and a 38 paragraph pitch, so the extra
 * between paragraphs is 16 — the same value the About story uses.
 */
.project-case__body p+p {
	margin-top: 16px;
}

/*
 * 519 wide and as tall as the copy beside it — the design's Rectangle 11 is 427 on
 * the Challenge band and 489 on the Solution band, which is the copy's height
 * in each case, not two chosen numbers.
 */
.project-case__media {
	position: relative;
	flex: 0 0 519px;
	align-self: stretch;
	min-height: 0;
}

/*
 * Taken out of flow so the photograph cannot set the row's height. Left in
 * flow with `height: 100%`, the percentage resolves against an indefinite
 * height and falls back to the file's own aspect — which pushed a 427 band to
 * 641 and dragged the copy's box with it.
 *
 * The cut top-left corner is the same shape the Problem band uses, at the same
 * 519 width — the design's "Rectangle 11" in both.
 */
.project-case__media img {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	clip-path: polygon(0 22.43%, 100% 0, 100% 100%, 0 100%);
}

/* ---- customer feedback ---- */

/*
 * #272629, not the page's #19181B. Sampled off — the bare ground
 * inside the band reads 39,38,41 while the blueprint's overhang ABOVE it, on
 * the process band, reads 25,24,27. It is the card grey, run full width.
 */
.project-feedback {
	position: relative;
	overflow: hidden;
	padding: var(--section-py) 0;
	background-color: #272629;
}

/*
 * the design at (865,-351), 850.23x817. Its OWN export, not the
 * Insights one scaled up: the two share an aspect ratio and both carry the
 * group's 10%, which is what made reusing look safe, but the drawing inside is
 * a different crop and reads about three times denser on the band.
 */
.project-feedback__blueprint {
	position: absolute;
	top: -351px;
	left: 865px;
	width: 850.23px;
	height: 817px;
	background-image: url("../icons/blueprint-project-feedback.svg");
	background-repeat: no-repeat;
	background-size: 100% 100%;
	pointer-events: none;
}

.project-feedback__inner {
	position: relative;
	display: flex;
	gap: var(--gap-5);
	align-items: flex-start;
	width: 100%;
	max-width: calc(var(--container-max) + var(--gutter) * 2);
	margin-inline: auto;
	padding-inline: var(--gutter);
}

.project-feedback__head {
	flex: 0 0 411px;
	min-width: 0;
}

.project-feedback__figure {
	display: flex;
	flex: 1 0 0;
	gap: var(--gap-2);
	align-items: center;
	min-width: 0;
	margin: 0;
}

.project-feedback__panel {
	display: flex;
	flex: 0 0 302px;
	align-items: center;
	justify-content: center;
	align-self: stretch;
	min-height: 260px;
	background-color: var(--white);
}

.project-feedback__panel img {
	width: auto;
	max-width: 66.8874%;
	/* 202 of 302 */
	height: auto;
	max-height: 69px;
	object-fit: contain;
}

.project-feedback__quote-wrap {
	display: flex;
	flex: 1 0 0;
	flex-direction: column;
	gap: var(--gap-5);
	min-width: 0;
}

/* The design is DM Sans Light ITALIC at 80%, and the design is DM Sans Medium
   at full strength — the quote recedes and the name does not. */
.project-feedback__quote {
	margin: 0;
	color: var(--c-ink);
	font-size: var(--fs-body);
	font-style: italic;
	font-weight: 300;
	line-height: var(--lh-body);
	opacity: 0.8;
}

.project-feedback__author {
	color: var(--c-ink);
	font-size: var(--fs-body);
	font-weight: 500;
	line-height: var(--lh-body);
}

@media (max-width: 1024px) {

	.project-overview__inner,
	.project-case__inner,
	.project-case--flip .project-case__inner,
	.project-feedback__inner {
		flex-direction: column;
		align-items: stretch;
	}

	.project-overview__inner {
		gap: var(--gap-5);
	}

	.project-overview__copy,
	.project-case__copy,
	.project-feedback__head {
		flex: 0 0 auto;
	}

	.project-overview__media {
		flex: 0 0 auto;
		flex-direction: column;
		/*
		 * stretch, not the desktop rule's flex-start. Turned on its side that
		 * value stops being "hang the panel from the top" and becomes "shrink
		 * both to their content width" — which left the white panel 224 wide
		 * and, through its aspect-ratio, 131 tall against the frame's 342x200.
		 */
		align-items: stretch;
		gap: var(--gap-5);
	}

	/* 342x200 and 342x200 at 390 — both full width
	   and both shallower than the desktop pair. */
	.project-overview__figure {
		flex: 0 0 auto;
		aspect-ratio: 342 / 200;
	}

	.project-overview__panel {
		flex: 0 0 auto;
		aspect-ratio: 342 / 200;
	}

	.project-case__inner {
		gap: var(--gap-2);
	}

	/* Square at 390 — 342x342. */
	.project-case__media {
		flex: 0 0 auto;
		align-self: auto;
		aspect-ratio: 1 / 1;
	}

	.project-feedback__inner {
		gap: var(--gap-5);
	}

	.project-feedback__figure {
		flex: 0 0 auto;
		flex-direction: column;
		gap: var(--gap-2);
		align-items: stretch;
	}

	.project-feedback__panel {
		flex: 0 0 auto;
		align-self: auto;
	}

	.project-case__blueprint {
		left: 0;
	}

	.project-feedback__blueprint {
		left: 234px;
		width: 390px;
		height: 375px;
	}
}

/* ========================================================= the blog ==
   Listing the design, detail the design, plus the
   taxonomy archives and search, which are not drawn and are assembled from
   these same pieces.
   ======================================================================= */

/*
 * #272629, and the cards on it #19181B — the INVERSE of the projects listing,
 * which is a dark band carrying lighter tiles. Sampled off: the
 * band reads 39,38,41 and a card's interior reads 25,24,27, where
 * reads 25,24,27 for the band and 39,38,41 for its tiles.
 */
.post-archive {
	position: relative;
	overflow: hidden;
	background-color: #272629;
}

.post-archive__grid .post-card,
.post-feature {
	background-color: var(--c-bg);
}

.post-archive__blueprint {
	position: absolute;
	top: -7px;
	left: -161px;
	width: 507.85px;
	height: 488px;
	background-image: url("../icons/blueprint-insights.svg");
	background-repeat: no-repeat;
	background-size: 100% 100%;
	pointer-events: none;
}

.post-archive__inner {
	position: relative;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: var(--gap-2);
	width: 100%;
	max-width: calc(var(--container-max) + var(--gutter) * 2);
	margin-inline: auto;
	padding: 0 var(--gutter) var(--section-py);
}

.post-archive__inner .pagination {
	margin-top: 0;
}

/* ---- the wide featured post ---- */

.post-feature {
	display: flex;
	align-items: stretch;
	width: 100%;
}

/*
 * A 50% basis, not `flex: 1 0 0`. With a zero basis the free space is split
 * between the two CONTENT boxes and the copy's 48 of horizontal padding is
 * then added on top of its share — which is why the halves came out 616 and
 * 664 against the frame's even 640.
 */
.post-feature__media {
	position: relative;
	flex: 1 1 50%;
	min-width: 0;
	overflow: hidden;
}

.post-feature__media img {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: transform var(--transition-slow);
}

.post-feature:hover .post-feature__media img,
.post-feature:focus-within .post-feature__media img {
	transform: scale(var(--card-zoom, 1.04));
}

.post-feature__copy {
	display: flex;
	flex: 1 1 50%;
	flex-direction: column;
	gap: var(--gap-4);
	align-items: flex-start;
	min-width: 0;
	padding: var(--gap-2) var(--gap-5);
}

.post-feature__meta {
	display: flex;
	gap: var(--gap-6);
	align-items: center;
	margin: 0;
	color: var(--c-ink);
	font-size: var(--fs-small);
	font-weight: 300;
	line-height: var(--lh-body);
}

.post-feature__text {
	display: flex;
	flex-direction: column;
	/* 19, not a token: the design draws it, the same odd gap the post card's
	   own title/excerpt pair uses. */
	gap: 19px;
	width: 100%;
}

.post-feature__title {
	margin: 0;
	color: var(--c-ink);
	font-family: var(--font-heading);
	font-size: var(--fs-h4);
	font-weight: 400;
	line-height: var(--lh-tight);
	text-box-trim: trim-both;
	text-box-edge: cap alphabetic;
	text-transform: uppercase;
}

.post-feature__title a {
	color: inherit;
	text-decoration: none;
	transition: color var(--transition);
}

.post-feature__title a:hover {
	color: var(--c-accent);
}

.post-feature__excerpt {
	display: -webkit-box;
	margin: 0;
	overflow: hidden;
	color: var(--c-ink);
	font-size: var(--fs-small);
	font-weight: 300;
	line-height: var(--lh-body);
	opacity: 0.8;
	-webkit-box-orient: vertical;
	-webkit-line-clamp: 2;
}

.post-feature__rule {
	width: 100%;
	height: 1px;
	background-color: rgba(255, 255, 255, 0.2);
}

/* ---- the toolbar, shared with the projects listing ---- */

.post-archive__toolbar {
	display: flex;
	gap: var(--gap-4);
	align-items: flex-end;
	justify-content: space-between;
	width: 100%;
}

.post-archive__heading {
	flex: 1 0 0;
	min-width: 0;
	margin: 0;
	color: var(--c-ink);
	font-family: var(--font-heading);
	font-size: var(--fs-h4);
	font-weight: 400;
	line-height: var(--lh-tight);
	text-box-trim: trim-both;
	text-box-edge: cap alphabetic;
	text-transform: uppercase;
}

/* ---- the grid: three across, 24 apart, 40 between rows ---- */

.post-archive__grid {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	column-gap: var(--gap-5);
	row-gap: var(--gap-3);
	width: 100%;
}

.post-archive__grid .post-card {
	width: auto;
	max-width: none;
}

.post-archive__empty {
	width: 100%;
	color: var(--c-ink);
	font-size: var(--fs-body);
	font-weight: 300;
	line-height: var(--lh-body);
	opacity: 0.8;
}

/* ---- search (not drawn: built from the listing's own parts) ---- */

.search-panel {
	display: flex;
	flex-direction: column;
	gap: var(--gap-5);
	align-items: flex-start;
	width: 100%;
	padding: var(--gap-4);
	background-color: #272629;
}

.search-form {
	width: 100%;
}

.search-form__label {
	display: block;
	margin-bottom: 12px;
	color: var(--c-ink);
	font-size: var(--fs-small);
	font-weight: 500;
	line-height: var(--lh-body);
}

.search-form__row {
	display: flex;
	gap: var(--gap-6);
	align-items: stretch;
	width: 100%;
}

.search-form__input {
	flex: 1 0 0;
	min-width: 0;
	padding: 12px 16px;
	border: 0;
	background-color: transparent;
	box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.2);
	color: var(--c-ink);
	font-family: var(--font-body);
	font-size: var(--fs-small);
	font-weight: 300;
}

.search-form__input::placeholder {
	color: var(--c-ink);
	opacity: 0.5;
}

.search-form__input:focus {
	outline: 0;
	box-shadow: inset 0 0 0 1px var(--white);
}

.search-form__submit {
	flex: 0 0 auto;
}

.search-panel__home {
	display: inline-flex;
	gap: 8px;
	align-items: center;
	color: var(--c-ink);
	font-size: var(--fs-small);
	font-weight: 300;
	text-decoration: none;
	opacity: 0.8;
	transition: opacity var(--transition);
}

.search-panel__home:hover {
	opacity: 1;
}

.search-panel__home svg {
	width: 20px;
	height: 20px;
}

/* =============================================== the blog detail =======
: contents rail 248 | article 656 | consultation card 280,
   48 apart, on the 1280 column.
   ======================================================================= */

.post-detail {
	position: relative;
	/*
	 * clip-path, NOT overflow: hidden. `overflow` on ANY ancestor turns that
	 * ancestor into the sticky element's scroll container, and the two side
	 * columns then travelled with the page exactly as if sticky were
	 * unsupported. clip-path crops the blueprint without creating one.
	 */
	clip-path: inset(0);
	padding: var(--section-py) 0;
	/*
	 * WHITE, and everything in it inked dark. This band is the one light
	 * stretch on the site and I had it dark: the design sets the article's own
	 * text to #19181B and the design puts a DARK card with white text and a
	 * white button beside it, neither of which can sit on a dark ground. The
	 * page export reads 255,255,255 through the band and returns to 25,24,27
	 * at More Blogs.
	 */
	background-color: var(--white);
	color: var(--c-ink-dark);
}

/*
 * The blueprint is still drawn here, but the artwork is light ink
 * meant for a dark band. Inverted it becomes a near-black at the same 10% the
 * file carries, which is the barely-there mark the export shows — 253,253,253
 * against the band's 255.
 */
.post-detail .post-detail__blueprint {
	/*
	 * Inverted so the light artwork reads on white. Nothing else: measured on a
	 * strip left of the contents rail, where the band carries blueprint and no
	 * text, the inverted drawing's darkest line is 234 against's
	 * 232, and 15% of the strip is inked in both.
	 *
	 * It took two wrong readings to land on that. The first came off a
	 * 12x-downscaled page export, where thin lines average away to almost
	 * nothing; the second sampled a region that included the contents list, so
	 * the list's own 50%-opacity text was measured as blueprint and the drawing
	 * looked five times too strong. A strip with nothing else on it is the only
	 * honest place to read this.
	 */
	filter: invert(1);
}

.post-detail .post-body__lead,
.post-detail .post-body__prose,
.post-detail .post-body__prose h2,
.post-detail .post-toc__link,
.post-detail .post-share__label,
.post-detail .post-share__link {
	color: var(--c-ink-dark);
}

.post-detail .post-body__prose a {
	color: var(--c-ink-dark);
}

/* The rules and the contents rail are hairlines on white now, not on black. */
.post-detail .post-body__rule {
	background-color: rgba(25, 24, 27, 0.2);
}

.post-detail .post-toc__marker {
	background-color: var(--c-ink-dark);
}

/*
 * The checklist ticks are drawn for a dark band. On white the item text has to
 * follow the band, and the tick keeps the accent so it still reads as a mark
 * rather than disappearing.
 */
.post-detail .checklist__item {
	color: var(--c-ink-dark);
}

.post-detail__blueprint {
	position: absolute;
	top: -7px;
	left: -161px;
	width: 507.85px;
	height: 488px;
	background-image: url("../icons/blueprint-insights.svg");
	background-repeat: no-repeat;
	background-size: 100% 100%;
	pointer-events: none;
}

.post-detail__inner {
	position: relative;
	display: grid;
	/*
	 * Same as the default page: the ARTICLE flexes and the two side columns
	 * keep their widths, so the row never demands more than the band can give.
	 * 1440 still resolves to the frame's 656.
	 */
	grid-template-columns: 248px minmax(0, 1fr) 280px;
	gap: var(--gap-2);
	/*
	 * stretch, NOT start. The sticky wrappers travel inside their grid items,
	 * so those items have to span the row — with `start` they hugged their own
	 * content and there was no distance to travel, which reads exactly like
	 * sticky being unsupported.
	 */
	align-items: stretch;
	width: 100%;
	max-width: calc(var(--container-max) + var(--gutter) * 2);
	margin-inline: auto;
	padding-inline: var(--gutter);
}

/*
 * ---- the sticky pair -----------------------------------------------------
 *
 * Both side columns follow the article and then stop, and they stop where the
 * design says: at the top of "More Blogs".
 *
 * That release needs no scroll handler. `position: sticky` is bounded by its
 * containing block, and the containing block here is the grid ROW, which ends
 * with the article — which is where the band ends and More Blogs begins. So
 * the column travels while the article is beside it and is left behind at
 * exactly the right line, with no listener to get out of step during a fast
 * scroll or a resize.
 *
 * The grid items stretch to the row so each side column spans the article;
 * the wrapper inside is what sticks and what stops.
 */
.post-toc__sticky,
.post-cta__sticky {
	position: sticky;
	/* Clear of the sticky header (96) with the band's own 24 beneath it. */
	top: calc(var(--header-h, 96px) + var(--gap-5));
}

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

/*: pl 8, pr 16, py 16, gap 16, sitting 3.88 right of the rail. */
.post-toc__list {
	position: relative;
	display: flex;
	flex-direction: column;
	gap: var(--gap-6);
	margin: 0;
	padding: 16px 16px 16px 12px;
	list-style: none;
}

/* One line behind the whole list, not a border per item — a border per item
   would break the rail into pieces with the gaps showing through. */
/* 2px of #D7D7D7 — the design's Border token — not a 1px wash. */
.post-toc__rail {
	position: absolute;
	top: 0;
	bottom: 0;
	left: 0;
	width: 2px;
	background-color: var(--c-border);
}

/* The bright segment marking the reader's place. Moved by script, eased so it
   travels rather than jumping between entries. */
.post-toc__marker {
	position: absolute;
	top: 0;
	left: 0;
	width: 2px;
	height: 20px;
	background-color: var(--white);
	transition: transform var(--transition), height var(--transition);
}

.post-toc__item {
	margin: 0;
}

/*
 * DM Sans MEDIUM, and the entries a reader is not on sit at 50%.
 * They were Light at 60%, which read as a paragraph rather than a list of
 * places to go.
 */
.post-toc__link {
	display: block;
	color: var(--c-ink);
	font-size: var(--fs-small);
	font-weight: 500;
	line-height: var(--lh-body);
	text-decoration: none;
	opacity: 0.5;
	transition: opacity var(--transition), color var(--transition);
}

.post-toc__link:hover,
.post-toc__item--current .post-toc__link {
	opacity: 1;
}

/* ---- the article ---- */

.post-body {
	min-width: 0;
}

/* 48 under the lead — the design ends at 84 and the photograph starts at 132. */
.post-body__lead {
	margin: 0 0 var(--gap-2);
	color: var(--c-ink);
	font-size: var(--fs-h5);
	font-weight: 300;
	line-height: var(--lh-body);
}

.post-body__figure {
	margin: 0 0 var(--gap-2);
	overflow: hidden;
}

.post-body__figure img {
	display: block;
	width: 100%;
	height: 324px;
	object-fit: cover;
}

.post-body__prose {
	color: var(--c-ink);
	font-size: var(--fs-body);
	font-weight: 300;
	line-height: var(--lh-body);
}

/* 48 between sections, 16 under a heading. */
.post-body__prose h2 {
	margin: var(--gap-2) 0 var(--gap-6);
	color: var(--c-ink);
	font-family: var(--font-heading);
	font-size: var(--fs-h3);
	font-weight: 400;
	line-height: var(--lh-tight);
	text-box-trim: trim-both;
	text-box-edge: cap alphabetic;
	text-transform: uppercase;
	/* So an in-page jump does not land the heading under the sticky header. */
	scroll-margin-top: calc(var(--header-h, 96px) + var(--gap-4));
}

.post-body__prose h2:first-child {
	margin-top: 0;
}

/*
 * 16, not --gap-5's 24. The design sets the article's paragraphs `mb-[16px]`,
 * and the legal pages inherit the same prose — with 24 the privacy band ran 71
 * long against and the terms band 112 long against.
 */
.post-body__prose p {
	margin: 0 0 var(--gap-6);
}

.post-body__prose p:last-child {
	margin-bottom: 0;
}

.post-body__prose a {
	color: var(--c-ink);
	text-decoration: underline;
	text-decoration-thickness: 1px;
	text-underline-offset: 3px;
	transition: text-decoration-color var(--transition);
}

.post-body__prose a:hover {
	text-decoration-color: var(--c-accent);
}

/* ==========================================================================
   Editor content — the blocks an author can drop into a post or legal page.

   This prose is drawn on two grounds: white ink on the site's dark bands by
   default, dark ink on the blog detail and legal pages. So every rule, tint
   and wash below is mixed from currentColor rather than named, and follows
   the ink it sits beside on either ground. The one fixed colour is the brand
   red, kept to markers and the quote's rule — the same sparing use it has on
   the buttons.
   ========================================================================== */

.post-body__prose strong,
.post-body__prose b {
	font-weight: 500;
}

/* Sub-headings: one step down from the h2, same uppercase heading voice. */
.post-body__prose h3,
.post-body__prose h4 {
	margin: var(--gap-4) 0 var(--gap-7);
	font-family: var(--font-heading);
	font-weight: 400;
	line-height: var(--lh-heading);
	text-transform: uppercase;
	scroll-margin-top: calc(var(--header-h, 96px) + var(--gap-4));
}

.post-body__prose h3 {
	font-size: var(--fs-h4);
}

.post-body__prose h4 {
	font-size: var(--fs-h5);
}

/* ---- lists ---- */

.post-body__prose ul,
.post-body__prose ol {
	margin: 0 0 var(--gap-5);
	padding-left: 1.4em;
}

.post-body__prose li {
	margin-bottom: 8px;
	padding-left: 4px;
}

.post-body__prose li:last-child {
	margin-bottom: 0;
}

.post-body__prose ul {
	list-style: square;
}

.post-body__prose li::marker {
	color: var(--c-accent);
}

.post-body__prose ol li::marker {
	font-family: var(--font-heading);
	font-size: var(--fs-small);
	font-weight: 500;
	font-variant-numeric: tabular-nums;
}

.post-body__prose li > :is(ul, ol) {
	margin: 8px 0 0;
}

/* ---- tables ----
 * Editorial, not spreadsheet: no box, a firm rule top and bottom and hairlines
 * between rows. The first column is the row's label — set in the heading
 * face and given its own width — because that is how authors here use a
 * two-column table: a term, then what it means.
 */

.post-body__prose .wp-block-table {
	margin: var(--gap-4) 0;
	overflow-x: auto;
	-webkit-overflow-scrolling: touch;
}

.post-body__prose table {
	width: 100%;
	border-collapse: collapse;
	border-top: 1px solid currentColor;
	border-bottom: 1px solid currentColor;
	font-size: var(--fs-body);
	line-height: var(--lh-body);
}

.post-body__prose .wp-block-table :is(th, td) {
	padding: var(--gap-5) var(--gap-5) var(--gap-5) 0;
	text-align: left;
	vertical-align: top;
	border: 0;
	border-bottom: 1px solid color-mix(in srgb, currentColor 14%, transparent);
}

.post-body__prose .wp-block-table :is(th, td):last-child {
	padding-right: 0;
}

.post-body__prose .wp-block-table tr:last-child > :is(th, td) {
	border-bottom: 0;
}

.post-body__prose .wp-block-table td:first-child:not(:only-child) {
	width: 34%;
	/* 14px on a tight line beside 16px on a loose one: drop it onto the same first line. */
	padding-top: calc(var(--gap-5) + 3px);
	font-family: var(--font-heading);
	font-size: var(--fs-small);
	font-weight: 500;
	line-height: var(--lh-heading);
	letter-spacing: 0.02em;
	text-transform: uppercase;
}

/* A header row, when the author switches one on. */
.post-body__prose .wp-block-table thead th {
	padding-block: 12px;
	font-family: var(--font-heading);
	font-size: 12px;
	font-weight: 500;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	opacity: 0.6;
	border-bottom: 1px solid color-mix(in srgb, currentColor 30%, transparent);
}

.post-body__prose .wp-block-table tfoot td {
	font-weight: 500;
	border-top: 1px solid color-mix(in srgb, currentColor 30%, transparent);
}

/* The editor's "Stripes" style: a faint wash and cells padded off the edge. */
.post-body__prose .wp-block-table.is-style-stripes {
	border-bottom: 0;
}

.post-body__prose .wp-block-table.is-style-stripes tbody tr:nth-child(odd) {
	background-color: color-mix(in srgb, currentColor 4%, transparent);
}

.post-body__prose .wp-block-table.is-style-stripes :is(th, td) {
	padding-inline: var(--gap-6);
}

.post-body__prose :is(.wp-block-table, .wp-block-image, figure) figcaption {
	margin-top: 12px;
	font-size: 13px;
	line-height: var(--lh-body);
	text-align: left;
	opacity: 0.6;
}

/* ---- quotes ----
 * A brand-red rule and a lead-sized line on a faint wash: it should read as
 * the article's one standout sentence, which is how authors here use it.
 */

.post-body__prose blockquote,
.post-body__prose .wp-block-quote {
	position: relative;
	margin: var(--gap-4) 0;
	padding: var(--gap-4) var(--gap-4) var(--gap-4) calc(var(--gap-4) + 3px);
	background-color: color-mix(in srgb, currentColor 4%, transparent);
	border: 0;
	border-left: 3px solid var(--c-accent);
}

.post-body__prose blockquote p {
	margin-bottom: 12px;
	font-size: var(--fs-lead);
	font-weight: 300;
	line-height: var(--lh-body);
}

.post-body__prose blockquote p:last-of-type {
	margin-bottom: 0;
}

.post-body__prose blockquote cite,
.post-body__prose blockquote footer {
	display: block;
	margin-top: var(--gap-6);
	font-family: var(--font-heading);
	font-size: 12px;
	font-style: normal;
	font-weight: 500;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	opacity: 0.6;
}

/* The "Plain" quote style drops the wash and keeps just the rule. */
.post-body__prose .wp-block-quote.is-style-plain {
	padding-block: 0;
	background: none;
}

/* Pullquote: centred, heading face, ruled above and below rather than boxed. */
.post-body__prose .wp-block-pullquote {
	margin: var(--gap-2) 0;
	padding: var(--gap-3) 0;
	text-align: center;
	border-top: 1px solid currentColor;
	border-bottom: 1px solid currentColor;
}

.post-body__prose .wp-block-pullquote blockquote {
	margin: 0;
	padding: 0;
	background: none;
	border: 0;
}

.post-body__prose .wp-block-pullquote p {
	font-family: var(--font-heading);
	font-size: var(--fs-h4);
	line-height: var(--lh-heading);
	text-transform: uppercase;
}

/* ---- images, rules, code ---- */

.post-body__prose .wp-block-image,
.post-body__prose > figure:not(.wp-block-table) {
	margin: var(--gap-4) 0;
}

.post-body__prose img {
	display: block;
	max-width: 100%;
	height: auto;
}

.post-body__prose hr,
.post-body__prose .wp-block-separator {
	width: 100%;
	height: 1px;
	margin: var(--gap-2) 0;
	background-color: currentColor;
	border: 0;
	opacity: 0.2;
}

.post-body__prose :not(pre) > code {
	padding: 2px 6px;
	font-size: 0.875em;
	background-color: color-mix(in srgb, currentColor 8%, transparent);
	border-radius: 3px;
}

.post-body__prose pre {
	margin: var(--gap-4) 0;
	padding: var(--gap-5);
	overflow-x: auto;
	font-size: var(--fs-small);
	line-height: var(--lh-body);
	background-color: color-mix(in srgb, currentColor 6%, transparent);
	border-radius: 4px;
}

.post-body__prose mark {
	padding: 0 2px;
	background-color: color-mix(in srgb, var(--c-accent) 18%, transparent);
	color: inherit;
}

/*
 * Tables stack on a phone: two 150px columns of wrapped text are harder to
 * read than a label sitting over its description.
 */
@media (max-width: 600px) {

	.post-body__prose .wp-block-table:not(:has(thead)) :is(tr, td) {
		display: block;
		width: auto;
	}

	.post-body__prose .wp-block-table:not(:has(thead)) td {
		padding: 0;
		border: 0;
	}

	.post-body__prose .wp-block-table:not(:has(thead)) tr {
		padding: var(--gap-5) 0;
		border-bottom: 1px solid color-mix(in srgb, currentColor 14%, transparent);
	}

	.post-body__prose .wp-block-table:not(:has(thead)) tr:last-child {
		border-bottom: 0;
	}

	.post-body__prose .wp-block-table:not(:has(thead)) td:first-child:not(:only-child) {
		width: auto;
		margin-bottom: 8px;
	}
}

.post-body__rule {
	display: block;
	width: 100%;
	height: 1px;
	margin-top: var(--gap-2);
	background-color: rgba(255, 255, 255, 0.2);
}

/* ---- share ---- */

.post-share {
	display: flex;
	gap: var(--gap-6);
	align-items: center;
	margin-top: var(--gap-2);
}

.post-share__label {
	margin: 0;
	color: var(--c-ink);
	font-size: var(--fs-small);
	font-weight: 300;
	line-height: var(--lh-body);
}

.post-share__list {
	display: flex;
	gap: 8px;
	margin: 0;
	padding: 0;
	list-style: none;
}

.post-share__link {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 28px;
	height: 28px;
	color: var(--c-ink);
	transition: color var(--transition), transform var(--transition);
}

/*
 * The full 28, not a 20 inset in it. These are the design's own brand marks,
 * drawn as complete 28x28 badges with their own coloured grounds — insetting
 * them in a larger box left a ring of page around each badge and made the row
 * read as three small marks rather than the run the design draws.
 */
.post-share__link svg {
	width: 100%;
	height: 100%;
}

/*
 * No colour change on hover. The old rule set `color`, which worked when the
 * glyphs were currentColor silhouettes; these carry their own brand colours and
 * ignore it. The feedback is the lift, plus a small fade so it is felt on a
 * badge that cannot change hue.
 */
.post-share__link:hover {
	transform: scale(1.08);
	opacity: 0.85;
}

/* ---- the consultation card ---- */

/*
 * #19181B with white ink — a dark card standing out of the white
 * band, which is the other way round from every other card on the site.
 */
.post-cta__card {
	display: flex;
	flex-direction: column;
	gap: var(--gap-6);
	align-items: center;
	padding: var(--gap-5);
	background-color: var(--c-bg);
	text-align: center;
}

.post-cta__heading,
.post-cta__text {
	color: var(--c-ink);
}

.post-cta__copy {
	display: flex;
	flex-direction: column;
	gap: var(--gap-6);
	width: 100%;
}

.post-cta__heading {
	margin: 0;
	color: var(--c-ink);
	font-family: var(--font-heading);
	font-size: var(--fs-h5);
	font-weight: 400;
	line-height: var(--lh-tight);
	text-box-trim: trim-both;
	text-box-edge: cap alphabetic;
	text-transform: uppercase;
}

.post-cta__text {
	margin: 0;
	color: var(--c-ink);
	font-size: var(--fs-small);
	font-weight: 300;
	line-height: var(--lh-body);
	opacity: 0.8;
}

/* ---- More Blogs ---- */

.more-posts {
	position: relative;
	overflow: hidden;
	padding: var(--section-py) 0;
	background-color: var(--c-bg);
}

.more-posts__blueprint {
	position: absolute;
	top: -7px;
	left: -161px;
	width: 507.85px;
	height: 488px;
	background-image: url("../icons/blueprint-insights.svg");
	background-repeat: no-repeat;
	background-size: 100% 100%;
	pointer-events: none;
}

.more-posts__inner {
	position: relative;
	display: flex;
	flex-direction: column;
	gap: var(--gap-1);
	width: 100%;
	max-width: calc(var(--container-max) + var(--gutter) * 2);
	margin-inline: auto;
	padding-inline: var(--gutter);
}

.more-posts__title {
	margin: 0;
	color: var(--c-ink);
	font-family: var(--font-heading);
	font-size: var(--fs-h2);
	font-weight: 400;
	line-height: var(--lh-tight);
	text-box-trim: trim-both;
	text-box-edge: cap alphabetic;
	text-transform: uppercase;
}

.more-posts__grid {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: var(--gap-5);
}

.more-posts__grid .post-card {
	width: auto;
	max-width: none;
}

@media (max-width: 1024px) {

	.post-archive__grid,
	.more-posts__grid {
		grid-template-columns: 1fr;
		row-gap: var(--gap-5);
	}

	.post-archive__toolbar {
		flex-direction: column;
		align-items: stretch;
		gap: var(--gap-5);
	}

	/* The design stacks the featured post, photograph first. */
	.post-feature {
		flex-direction: column;
	}

	.post-feature__media {
		flex: 0 0 auto;
		aspect-ratio: 342 / 200;
	}

	.post-feature__copy {
		flex: 0 0 auto;
		padding: var(--gap-5);
	}

	/*
	 * The design stacks the detail: contents, article, then the card — and
	 * nothing sticks. There is no room beside the article to travel through,
	 * and a rail pinned over a phone screen costs more than it gives.
	 */
	.post-detail__inner {
		grid-template-columns: minmax(0, 1fr);
		gap: var(--gap-3);
	}

	.post-toc__sticky,
	.post-cta__sticky {
		position: static;
	}

	.post-body__figure img {
		height: 200px;
	}
}

/* ============================================================ 404 ==
   the design / Container.

   NOT .error404 — WordPress puts that exact class on <body> for a 404, so
   every rule here was landing on the body as well and giving the whole
   document the hero's height, padding and gradient.
   ================================================================== */

.error-hero {
	position: relative;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: flex-end;
	min-height: 800px;
	overflow: hidden;
	padding: 120px var(--gutter);
	background-color: var(--c-bg);
	/*
	 * The two layers The design names "7762075-hd_1920_1080_25fps" carry no fill —
	 * the same empty video placeholders the About hero had. What the frame
	 * actually renders is a violet wash over #19181B, strongest toward the
	 * lower left: sampled, the ground runs from 29,24,35 through 37,30,58 at
	 * the bottom-left corner.
	 */
	/*
	 * The frame's wash is a soft cloud, not a directional gradient — sampled
	 * across it the violet is everywhere (29,24,37 top-left, 37,26,39
	 * mid-RIGHT, 31,26,35 bottom-right) and merely deepest at the bottom-left
	 * (37,30,58). Two soft radials over a flat lift track it to a mean
	 * absolute luminance difference of about 2 across the corners and midpoints;
	 * a left-weighted version that looked more "correct" as a rule measured
	 * twice as far off. It is a decorative ground, and this is as close as is
	 * worth taking it.
	 */
	background-image:
		radial-gradient(120% 90% at 18% 88%, rgba(84, 62, 196, 0.2) 0%, rgba(84, 62, 196, 0) 62%),
		radial-gradient(90% 70% at 62% 18%, rgba(120, 80, 190, 0.1) 0%, rgba(120, 80, 190, 0) 65%),
		linear-gradient(rgba(88, 66, 180, 0.07), rgba(88, 66, 180, 0.07));
}

.error-hero__inner {
	display: flex;
	flex-direction: column;
	gap: var(--gap-5);
	align-items: center;
	width: 100%;
	max-width: var(--container-max);
}

/*
 * 300px in overlay blend, which is what keeps it a shape in the ground rather
 * than white type sitting on top of it.
 */
.error-hero__code {
	margin: 0;
	color: var(--white);
	font-family: var(--font-heading);
	font-size: 300px;
	font-weight: 700;
	line-height: 1;
	letter-spacing: -10px;
	text-align: center;
	text-box-trim: trim-both;
	text-box-edge: cap alphabetic;
	mix-blend-mode: overlay;
}

.error-hero__copy {
	display: flex;
	flex-direction: column;
	gap: var(--gap-6);
	width: 100%;
	text-align: center;
}

.error-hero__title {
	margin: 0;
	color: var(--c-ink);
	font-family: var(--font-heading);
	font-size: var(--fs-h1);
	font-weight: 400;
	line-height: 1.3;
	letter-spacing: -2px;
	text-transform: uppercase;
}

.error-hero__text {
	margin: 0;
	color: var(--c-ink);
	font-size: var(--fs-small);
	font-weight: 300;
	line-height: var(--lh-body);
}

@media (max-width: 1024px) {

	/* The design is 800 tall with the same 120 of bottom padding as desktop. */
	.error-hero {
		min-height: 800px;
		padding: 120px var(--gutter);
	}

	/*
	 * The design keeps the 800 container and the 120 bottom padding, so the
	 * only thing that changes is the scale of the numeral: its box is 357x134
	 * on a 342 column, i.e. it overhangs the gutter slightly by design. 134 of
	 * cap height is about 186px of Inter, which is 47.7% of a 390 viewport.
	 */
	.error-hero__code {
		font-size: clamp(140px, 50vw, 300px);
		letter-spacing: -0.033em;
	}
}

/* ===================================================== default page ==
   the design / — the shape every ordinary
   page takes.
   ======================================================================= */

/*
 * A 512 hero with no photograph, carrying the same violet wash the 404 does —
 * both are built on the empty "7762075" layers, and both render as a soft
 * cloud over #19181B.
 */
.page-hero {
	position: relative;
	display: flex;
	flex-direction: column;
	justify-content: flex-end;
	min-height: 512px;
	overflow: hidden;
	padding: 0 var(--gutter) 48px;
	background-color: var(--c-bg);
	background-image:
		radial-gradient(120% 90% at 18% 88%, rgba(84, 62, 196, 0.2) 0%, rgba(84, 62, 196, 0) 62%),
		radial-gradient(90% 70% at 62% 18%, rgba(120, 80, 190, 0.1) 0%, rgba(120, 80, 190, 0) 65%),
		linear-gradient(rgba(88, 66, 180, 0.07), rgba(88, 66, 180, 0.07));
}

.page-hero__inner {
	display: flex;
	flex-direction: column;
	/* 8 between the trail and the title. */
	gap: 8px;
	width: 100%;
	max-width: var(--container-max);
	margin-inline: auto;
}

.page-hero__head {
	display: flex;
	flex-direction: column;
	gap: var(--gap-6);
}

/*
 * NOT trimmed. The design gives the title a 94 box for one line at 72/1.3,
 * which is the full 93.6 line — the section headings elsewhere on the site are
 * trimmed, this one is not. Trimming it took the box to 52 and, because the
 * hero is bottom-aligned, pushed the whole block 42 down the hero: the trail
 * started at 348 against the frame's 306.
 */
.page-hero__title {
	margin: 0;
	color: var(--c-ink);
	font-family: var(--font-heading);
	font-size: var(--fs-h1);
	font-weight: 400;
	line-height: 1.3;
	letter-spacing: -2px;
	text-transform: uppercase;
}

.page-hero__meta {
	margin: 0;
	color: var(--c-ink);
	font-size: var(--fs-small);
	font-weight: 300;
	line-height: var(--lh-body);
	opacity: 0.8;
}

/* ---- the white body ---- */

.doc {
	padding: var(--section-py) 0;
	background-color: var(--white);
	color: var(--c-ink-dark);
}

.doc__inner {
	display: grid;
	/*
	 * The copy column FLEXES; only the card is fixed. Both columns were fixed,
	 * so the grid demanded 952 + 48 + 280 = 1280 whatever the viewport, and
	 * anywhere between the stacking breakpoint and 1440 the card hung out past
	 * the band's right edge. At 1440 the fraction still resolves to exactly the
	 * 952 the frame draws.
	 */
	grid-template-columns: minmax(0, 1fr) 280px;
	gap: var(--gap-2);
	align-items: stretch;
	width: 100%;
	max-width: calc(var(--container-max) + var(--gutter) * 2);
	margin-inline: auto;
	padding-inline: var(--gutter);
}

.doc__body {
	min-width: 0;
}

/*
 * The copy is inked dark, exactly as the blog detail's is — this band is the
 * other white stretch on the site.
 */
.doc .post-body__prose,
.doc .post-body__prose h2,
.doc .post-body__prose h3,
.doc .post-body__prose a,
.doc .checklist__item {
	color: var(--c-ink-dark);
}

.doc .post-body__prose h2:first-child {
	margin-top: 0;
}

/* Editors write ordinary pages with h2 AND h3; both are section headings here. */
.doc .post-body__prose h3 {
	margin: var(--gap-2) 0 var(--gap-6);
	font-family: var(--font-heading);
	font-size: var(--fs-h4);
	font-weight: 400;
	line-height: var(--lh-tight);
	text-box-trim: trim-both;
	text-box-edge: cap alphabetic;
	text-transform: uppercase;
}

.doc .post-body__prose ul,
.doc .post-body__prose ol {
	margin: 0 0 var(--gap-5);
	padding-left: 20px;
}

.doc .post-body__prose li {
	margin-bottom: 8px;
}

@media (max-width: 1024px) {
	.page-hero {
		min-height: 512px;
	}

	/*
	 * 40 between the copy and the card, matching the blog detail's own mobile
	 * stack — the two pages are the same
	 * layout and should not separate their blocks differently.
	 */
	.doc__inner {
		grid-template-columns: minmax(0, 1fr);
		gap: var(--gap-2);
	}
}

/* ================================================ book a consultation ==
   the design — the design and the map beneath it.
   ======================================================================= */

/*
 * Three grounds, not two. Sampled across the BAND is #272629, the
 * panel on it is #19181B and the details column inside that is #272629 again —
 * dark tile on light band, light column in the dark tile. I had the band and
 * the panel the same colour, which is why the panel's 20px corners could not
 * be seen at all: they were rounding one #19181B against another.
 */
.consult {
	padding: 0 var(--gutter) 48px;
	background-color: #272629;
}

/* One 1280 panel, 48 padded, holding both columns. */
.consult__panel {
	display: grid;
	grid-template-columns: minmax(0, 1fr) 400px;
	gap: var(--gap-2);
	align-items: start;
	width: 100%;
	max-width: var(--container-max);
	margin-inline: auto;
	padding: var(--gap-2);
	/*
	 * Both corners are rounded — walked down the frame's own top-left corner,
	 * the panel's ground first appears 20 in on its first row and reaches the
	 * edge by row 20, and the details column's 12 in reaching it by row 12.
	 * The design is rounded-[24px] and rounded-[16px]. Walking the
	 * render's corners gives the same pair: half coverage arrives at
	 * R - sqrt(R - 0.25) from the edge, which is 19 for the panel (R=24) and
	 * 12.5 for the details column (R=16). I had 20 and 12, read off the same
	 * corners with the arc's flattening near the tangent ignored.
	 */
	border-radius: 24px;
	/*
	 * #19181B, with the LIGHTER column inside it — the other way round from
	 * what I had. Sampled off the panel reads 25,24,27 at every
	 * corner while the details column reads 40,39,42 rising to 46,40,56 at its
	 * bottom-left, where the violet gathers.
	 */
	background-color: var(--c-bg);
}

.consult__form {
	display: flex;
	flex-direction: column;
	gap: var(--gap-4);
	min-width: 0;
}

.consult__head {
	display: flex;
	flex-direction: column;
	gap: var(--gap-7);
}

/* H3, not H4 —'s box is 23 tall, which is 32px trimmed to cap
   height; at 24px it measures 17.5 and the head block came out 53 against 59. */
.consult__title {
	margin: 0;
	color: var(--c-ink);
	font-family: var(--font-heading);
	font-size: var(--fs-h3);
	font-weight: 400;
	line-height: var(--lh-tight);
	text-box-trim: trim-both;
	text-box-edge: cap alphabetic;
	text-transform: uppercase;
}

.consult__blurb {
	margin: 0;
	color: var(--c-ink);
	font-size: var(--fs-small);
	font-weight: 300;
	line-height: var(--lh-body);
	opacity: 0.8;
}

/*
 * The details column carries the same violet wash the 404 and the default
 * page hero do — the design is another of the empty "7762075" layers.
 */
.consult__info {
	display: flex;
	flex-direction: column;
	justify-content: space-between;
	align-self: stretch;
	min-height: 459px;
	padding: var(--gap-3) var(--gap-5);
	border-radius: 16px;
	background-color: #272629;
	/*
	 * The same violet cloud the 404 and the page hero carry, but far weaker:
	 * this one sits on #272629 rather than #19181B, so the same alphas read
	 * much further. Mapped on a 6x8 grid across the whole field
	 * spans only 43..55 in blue over the tile's 41 — a flat +3 lift, rising
	 * to +9 along the foot and +14 in the bottom-left corner where it
	 * gathers. My previous fit ran it to 64 and put the peak too high and
	 * too far right.
	 */
	background-image:
		radial-gradient(120% 80% at 8% 100%, rgba(120, 80, 190, 0.055) 0%, rgba(120, 80, 190, 0) 55%),
		radial-gradient(90% 60% at 55% 45%, rgba(84, 62, 196, 0.03) 0%, rgba(84, 62, 196, 0) 70%),
		linear-gradient(180deg, rgba(84, 62, 196, 0) 30%, rgba(84, 62, 196, 0.035) 100%),
		linear-gradient(rgba(84, 62, 196, 0.012), rgba(84, 62, 196, 0.012));
}

/*
 * — the head and the contact rows are one block, 32 apart, and the
 * column's justify-between pushes the socials to the foot on their own. Held
 * as three siblings instead, the 86 of slack the design leaves above the rule
 * was split in two and the rows sat 32 low.
 */
.consult__info-top {
	display: flex;
	flex-direction: column;
	gap: var(--gap-4);
}

.consult__info-head {
	display: flex;
	flex-direction: column;
	gap: var(--gap-6);
}

/* H4 —'s box is 17 tall, which is 24px trimmed to cap height; at
   20 it measures 14.5 and the head block came out 70 against 73. */
.consult__info-title {
	margin: 0;
	color: var(--c-ink);
	font-family: var(--font-heading);
	font-size: var(--fs-h4);
	font-weight: 400;
	line-height: var(--lh-tight);
	text-box-trim: trim-both;
	text-box-edge: cap alphabetic;
	text-transform: uppercase;
}

/*
 * Full white: the design carries no opacity, where the form's blurb
 * is opacity-80. Same copy weight, two different strengths.
 */
.consult__info-blurb {
	margin: 0;
	color: var(--c-ink);
	font-size: var(--fs-small);
	font-weight: 300;
	line-height: var(--lh-body);
}

.consult__details {
	display: flex;
	flex-direction: column;
	gap: var(--gap-5);
	margin: 0;
	padding: 0;
	list-style: none;
}

/*
 * Paragraph 1/Medium at 88% — 16px at 500, not the 14px Light the
 * rest of the card uses. At 14 the address fitted on one line where the design
 * wraps it onto two, so the block measured 120 against 140 and every gap below
 * it inherited the 20.
 */
.consult__details li {
	display: flex;
	gap: 8px;
	align-items: flex-start;
	color: var(--c-ink);
	font-size: var(--fs-body);
	font-weight: 500;
	line-height: var(--lh-body);
}

/*
 * The 88% is on the PARAGRAPH, not the row: the icon frame beside
 * it carries none, so its strokes are pure white. Held on the row it dimmed
 * them to 228 where the design draws 255.
 */
.consult__details li>a,
.consult__details li>span {
	opacity: 0.88;
}

.consult__details svg {
	flex: 0 0 24px;
	width: 24px;
	height: 24px;
	color: var(--c-ink);
}

/*
 * The phone and pin icons ship with the accent baked in — correct on the
 * homepage's WHITE contact card, wrong on this dark panel, where
 * draws them neutral (sampled 95,92,96 and 188,187,188, with no red
 * dominance at all). They follow the text colour here.
 */
.consult__details svg [fill]:not([fill="none"]) {
	fill: currentColor;
}

.consult__details svg [stroke]:not([stroke="none"]) {
	stroke: currentColor;
}

.consult__details a {
	color: inherit;
	word-break: break-all;
	text-decoration: none;
	transition: color var(--transition);
}

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

/* A literal 24 in, not gap-5 — it does not shrink on mobile. */
.consult__socials {
	display: flex;
	flex-direction: column;
	gap: 24px;
	margin-top: 24px;
}

/* 10% white: the rule reads 64,61,68 over the card's 42,39,47, which is
   0.101 of the way to white. I had it at 20%. */
.consult__rule {
	width: 100%;
	height: 1px;
	background-color: rgba(255, 255, 255, 0.1);
}

.consult__socials-row {
	display: flex;
	gap: var(--gap-6);
	align-items: center;
}

.consult__socials-label {
	margin: 0;
	color: var(--c-ink);
	font-size: var(--fs-small);
	font-weight: 500;
	line-height: var(--lh-body);
}

.consult__socials-list {
	display: flex;
	gap: 8px;
	margin: 0;
	padding: 0;
	list-style: none;
}

.consult__socials-list li {
	display: flex;
}

.consult__socials-list a {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 24px;
	height: 24px;
	color: var(--c-ink);
	transition: color var(--transition), transform var(--transition);
}

.consult__socials-list svg {
	width: 24px;
	height: 24px;
}

.consult__socials-list a:hover {
	color: var(--c-accent);
	transform: scale(1.08);
}

/*
 * The fields sit on a 58 pitch here — 34 of control and 24 of gap
 * — where the homepage band's form uses 8, giving
 * it a 42 pitch. Same form component, two different rhythms, so the gap is set
 * on this page rather than moved on the shared rule.
 *
 * The button then needs its own 32, since the form's flex gap no longer
 * matches the 32 the design puts between the last field and it.
 */
.consult__form .bbqld-form form {
	gap: var(--gap-5);
}

/*
 * The form is inked for a DARK panel here. Everything in .bbqld-form is built
 * for the homepage's white contact card — #19181B text on a 10% BLACK rule
 * with a black placeholder — which on this panel meant invisible type on an
 * invisible underline. The design sets the placeholder white at 50% and
 * the rule at 10% white.
 */
.consult__form .bbqld-form {
	--form-focus: var(--white);
}

.consult__form .bbqld-form input,
.consult__form .bbqld-form textarea {
	color: var(--c-ink);
	border-bottom-color: rgba(255, 255, 255, 0.1);
}

.consult__form .bbqld-form input::placeholder,
.consult__form .bbqld-form textarea::placeholder {
	color: var(--c-ink);
	opacity: 0.5;
}

.consult__form .bbqld-form input:focus,
.consult__form .bbqld-form textarea:focus {
	border-bottom-color: var(--white);
}

/* The response and error text has to follow the same ground. */
.consult__form .bbqld-form .wpcf7-response-output {
	color: var(--c-ink);
}

.consult__form .bbqld-form .wpcf7-submit {
	margin-top: 8px;
}

/* ---- the map: full width, nothing over it ---- */

.consult-map {
	position: relative;
	height: 663px;
	overflow: hidden;
	background-color: var(--c-bg);
}

/*
 * The map fades into the bands above and below it rather than butting against
 * them. Read down the frame's own centre line the ground runs ~24 at the top,
 * opens to ~36 through the middle and closes to ~29 at the foot — the map at
 * full strength only in the middle half.
 */
/*
 * THREE gradients, not one —'s own fills, in the order it stacks
 * them: the left edge fading in from the gutter, the foot, and the head. I had
 * approximated this as a single vertical fade read off a downscaled render,
 * which got the top and bottom roughly right and missed the horizontal one
 * completely. It is the same stack the homepage's contact band carries.
 */
.consult-map::after {
	content: "";
	position: absolute;
	inset: 0;
	pointer-events: none;
	background-image:
		linear-gradient(90deg, var(--c-bg) 15%, rgba(25, 24, 27, 0) 40%),
		linear-gradient(180deg, rgba(25, 24, 27, 0) 60%, var(--c-bg) 100%),
		linear-gradient(180deg, var(--c-bg) 0%, rgba(25, 24, 27, 0) 40%);
}

/*
 * The map is not a plain cover fill: the design places it 130.14% tall at
 * top -14.93%, which is what lifts the pinned street into the band's middle
 * rather than centring the whole tile.
 */
.consult-map img {
	position: absolute;
	top: -14.93%;
	left: 0;
	display: block;
	width: 100%;
	height: 130.14%;
	max-width: none;
	object-fit: cover;
}

.consult-map__frame {
	display: block;
	width: 100%;
	height: 100%;
	border: 0;
}

@media (max-width: 1024px) {
	.consult__panel {
		grid-template-columns: minmax(0, 1fr);
		gap: var(--gap-3);
		padding: var(--gap-5);
	}

	.consult__info {
		min-height: 0;
		padding: var(--gap-5);
	}

	.consult-map {
		height: 360px;
	}
}

/* =============================================== testimonials listing ==
   Not drawn. Built from the listing banner, the toolbar line, the #272629
   card and the shared pagination, so it reads as part of the same set.
   ======================================================================= */

.tst-archive {
	position: relative;
	overflow: hidden;
	background-color: var(--c-bg);
}

.tst-archive__blueprint {
	position: absolute;
	top: -7px;
	left: -161px;
	width: 507.85px;
	height: 488px;
	background-image: url("../icons/blueprint-insights.svg");
	background-repeat: no-repeat;
	background-size: 100% 100%;
	pointer-events: none;
}

.tst-archive__inner {
	position: relative;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: var(--gap-2);
	width: 100%;
	max-width: calc(var(--container-max) + var(--gutter) * 2);
	margin-inline: auto;
	padding: var(--section-py) var(--gutter);
}

.tst-archive__inner .pagination {
	margin-top: 0;
}

.tst-archive__toolbar {
	width: 100%;
}

.tst-archive__heading {
	margin: 0;
	color: var(--c-ink);
	font-family: var(--font-heading);
	font-size: var(--fs-h4);
	font-weight: 400;
	line-height: var(--lh-tight);
	text-box-trim: trim-both;
	text-box-edge: cap alphabetic;
	text-transform: uppercase;
}

/* Two across: a testimonial is prose, and at 410 the quotes wrap to nine
   lines and stop being readable. */
.tst-archive__grid {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: var(--gap-5);
	width: 100%;
}

/* The cards stretch to the tallest in their row. `space-between` then spread
   the three children over that height, which floated a short testimonial's
   heading and quote into the middle of its card while a long one started at the
   top — the two columns never lined up. They stack from the top now and the
   foot is pushed down by its own auto margin instead, so the rule above the
   author still sits on the card's floor. */
.tst-card {
	display: flex;
	flex-direction: column;
	gap: var(--gap-4);
	justify-content: flex-start;
	margin: 0;
	padding: var(--gap-4);
	background-color: #272629;
}

.tst-card__mark {
	display: block;
	color: var(--c-accent);
}

.tst-card__mark svg {
	width: 32px;
	height: 32px;
}

.tst-card__copy {
	display: flex;
	flex-direction: column;
	gap: var(--gap-6);
}

.tst-card__project {
	margin: 0;
	color: var(--c-ink);
	font-size: var(--fs-small);
	font-weight: 500;
	line-height: var(--lh-body);
	opacity: 0.6;
}

.tst-card__title {
	margin: 0;
	color: var(--c-ink);
	font-family: var(--font-heading);
	font-size: var(--fs-h4);
	font-weight: 400;
	line-height: var(--lh-tight);
	text-box-trim: trim-both;
	text-box-edge: cap alphabetic;
	text-transform: uppercase;
}

.tst-card__quote {
	margin: 0;
	color: var(--c-ink);
	font-size: var(--fs-body);
	font-style: italic;
	font-weight: 300;
	line-height: var(--lh-body);
	opacity: 0.8;
}

/* The quote holds the editor's own paragraphs now, so their default margins
   are dropped and the space between them is set here instead. */
.tst-card__quote > * {
	margin: 0;
}

.tst-card__quote > * + * {
	margin-top: 0.85em;
}

.tst-card__foot {
	display: flex;
	gap: var(--gap-6);
	align-items: center;
	margin-top: auto;
	padding-top: var(--gap-5);
	box-shadow: inset 0 1px 0 0 rgba(255, 255, 255, 0.1);
}

.tst-card__avatar {
	flex: 0 0 48px;
	width: 48px;
	height: 48px;
	overflow: hidden;
	border-radius: 50%;
}

.tst-card__avatar img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.tst-card__author {
	color: var(--c-ink);
	font-size: var(--fs-small);
	font-weight: 500;
	line-height: var(--lh-body);
}

.tst-archive__empty {
	width: 100%;
	color: var(--c-ink);
	font-size: var(--fs-body);
	font-weight: 300;
	opacity: 0.8;
}

@media (max-width: 1024px) {
	.tst-archive__grid {
		grid-template-columns: minmax(0, 1fr);
	}
}

/* ======================================================== gallery page ==
   Not drawn in the design. Built from the pieces that are: the 480 listing banner,
   the toolbar line the projects and blog listings use, the same 3-up grid on
   the same 24 gutters, and the site's 20px tile radius and hover zoom.
   ======================================================================= */

.gallery {
	position: relative;
	overflow: hidden;
	background-color: var(--c-bg);
}

.gallery__blueprint {
	position: absolute;
	top: -7px;
	left: -161px;
	width: 507.85px;
	height: 488px;
	background-image: url("../icons/blueprint-insights.svg");
	background-repeat: no-repeat;
	background-size: 100% 100%;
	pointer-events: none;
}

.gallery__inner {
	position: relative;
	display: flex;
	flex-direction: column;
	gap: var(--gap-2);
	width: 100%;
	max-width: calc(var(--container-max) + var(--gutter) * 2);
	margin-inline: auto;
	/* The same 80 the testimonials listing leaves under its banner — the
	   projects listing starts flush only because a featured tile is first. */
	padding: var(--section-py) var(--gutter);
}

/* ---- the toolbar: the count on the left, the filter on the right ---- */

/*
 * Two rows, not two columns. Fifteen chips wrap to three lines at 1440, and
 * beside them the count was stranded at the bottom of a 148-tall box with the
 * whole top-left quarter empty. Stacked, the count reads as a title over the
 * filter it belongs to and the chips get the full width.
 */
.gallery__toolbar {
	display: flex;
	flex-direction: column;
	gap: var(--gap-5);
	width: 100%;
	padding-bottom: var(--gap-5);
	border-bottom: 1px solid var(--c-line);
}

.gallery__count {
	display: flex;
	gap: var(--gap-5);
	align-items: center;
}

.gallery__heading {
	margin: 0;
	color: var(--c-ink);
	font-family: var(--font-heading);
	font-size: var(--fs-h4);
	font-weight: 400;
	line-height: var(--lh-tight);
	text-box-trim: trim-both;
	text-box-edge: cap alphabetic;
	text-transform: uppercase;
}

.gallery__count-rule {
	flex: 1 1 auto;
	height: 1px;
	background-color: var(--c-line);
}

.gallery__tally {
	margin: 0;
	color: var(--c-ink);
	font-size: var(--fs-small);
	font-weight: 300;
	line-height: var(--lh-body);
	opacity: 0.6;
}

/*
 * Fourteen homes will not sit on one 1280 line, so the row wraps rather than
 * scrolling sideways — a horizontal scroller hides half the options behind an
 * affordance nobody looks for, and this list is the page's whole navigation.
 */
.gallery__filter {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
}

.gallery__chip {
	padding: 7px 16px;
	border: 1px solid var(--c-line);
	border-radius: 100px;
	background: transparent;
	color: var(--c-ink);
	font-family: var(--font-body);
	font-size: var(--fs-small);
	font-weight: 300;
	line-height: var(--lh-body);
	cursor: pointer;
	transition: border-color var(--transition), background-color var(--transition), color var(--transition);
}

.gallery__chip:hover {
	border-color: rgba(255, 255, 255, 0.4);
}

.gallery__chip.is-active {
	border-color: var(--c-accent);
	background-color: var(--c-accent);
	color: var(--white);
	font-weight: 500;
}

.gallery__intro {
	max-width: 736px;
	margin: 0;
	color: var(--c-ink);
	font-size: var(--fs-body);
	font-weight: 300;
	line-height: var(--lh-body);
	opacity: 0.8;
}

.gallery__empty {
	margin: 0;
	color: var(--c-ink);
	font-size: var(--fs-body);
	font-weight: 300;
	opacity: 0.7;
}

/* ---- one album ---- */

.gallery__albums {
	display: flex;
	flex-direction: column;
	gap: var(--gap-1);
}

.gallery-album {
	display: flex;
	flex-direction: column;
	gap: var(--gap-4);
}

/*
 * The UA's [hidden] rule is `display: none` at zero specificity, so the class
 * above outranks it and the filter hid nothing — the albums kept their layout,
 * their tiles kept their offsetParent, and 182 buttons stayed in the tab order
 * behind a filter that looked like it had worked.
 */
.gallery-album[hidden] {
	display: none;
}

/* Title, then a rule that takes the slack, then the count — the same
   head-with-a-hairline the row heads elsewhere on the site use. */
.gallery-album__head {
	display: flex;
	gap: var(--gap-5);
	align-items: center;
}

.gallery-album__title {
	flex: 0 0 auto;
	margin: 0;
	color: var(--c-ink);
	font-family: var(--font-heading);
	font-size: var(--fs-h4);
	font-weight: 400;
	line-height: var(--lh-tight);
	text-box-trim: trim-both;
	text-box-edge: cap alphabetic;
	text-transform: uppercase;
}

.gallery-album__rule {
	flex: 1 1 auto;
	height: 1px;
	background-color: var(--c-line);
}

.gallery-album__count {
	flex: 0 0 auto;
	margin: 0;
	color: var(--c-ink);
	font-size: var(--fs-small);
	font-weight: 300;
	line-height: var(--lh-body);
	opacity: 0.6;
}

/* The optional line under a gallery's heading. `.gallery-album` is a flex
   column on --gap-4, which is the right distance before the grid but too far
   under the heading this belongs to, so it is pulled back to hug it. */
.gallery-album__desc {
	max-width: 68ch;
	margin: calc(var(--gap-4) * -1 + 8px) 0 0;
	color: var(--c-ink);
	font-size: var(--fs-small);
	font-weight: 300;
	line-height: var(--lh-body);
	opacity: 0.6;
}

/* Five across, then four, then three — a contact sheet rather than a card
   listing. At 1440 that is a 236px tile; the lightbox is where a photograph is
   actually looked at. */
.gallery-album__grid {
	display: grid;
	grid-template-columns: repeat(5, minmax(0, 1fr));
	gap: 24px;
	margin: 0;
	padding: 0;
	list-style: none;
}

/* ---- one tile ---- */

.gallery-tile__btn {
	position: relative;
	display: block;
	width: 100%;
	padding: 0;
	overflow: hidden;
	border: 0;
	/* 12, not the 20 the site's full-width cards use — on a 236px tile a 20
	   corner eats most of the picture's edge. */
	border-radius: 12px;
	background-color: var(--c-bg-alt);
	cursor: pointer;
}

/*
 * 4:3, which is the shape the photographs were shot in. A floorplan is
 * portrait and gets cropped here — the lightbox shows it whole, uncropped,
 * which is where anyone actually reads one.
 */
.gallery-tile__media {
	display: block;
	aspect-ratio: 4 / 3;
	overflow: hidden;
}

.gallery-tile__media img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: transform var(--transition-slow);
}

.gallery-tile__btn:hover .gallery-tile__media img,
.gallery-tile__btn:focus-visible .gallery-tile__media img {
	transform: scale(var(--card-zoom, 1.04));
}

/*
 * The caption is not painted over the picture at rest. A gallery of 194
 * photographs with 194 labels burnt across them is unreadable; the label
 * arrives on hover, and the lightbox carries it permanently.
 */
.gallery-tile__overlay {
	position: absolute;
	right: 0;
	bottom: 0;
	left: 0;
	display: flex;
	gap: 8px;
	align-items: flex-end;
	justify-content: space-between;
	padding: 12px;
	background-image: linear-gradient(rgba(25, 24, 27, 0), rgba(25, 24, 27, 0.85));
	opacity: 0;
	transition: opacity var(--transition);
}

.gallery-tile__btn:hover .gallery-tile__overlay,
.gallery-tile__btn:focus-visible .gallery-tile__overlay {
	opacity: 1;
}

.gallery-tile__caption {
	color: var(--c-ink);
	font-size: var(--fs-small);
	font-weight: 500;
	line-height: var(--lh-body);
	text-align: left;
}

.gallery-tile__zoom {
	display: inline-flex;
	flex: 0 0 32px;
	align-items: center;
	justify-content: center;
	width: 32px;
	height: 32px;
	border-radius: 50%;
	background-color: var(--c-accent);
	color: var(--white);
}

.gallery-tile__zoom svg {
	width: 16px;
	height: 16px;
}

/* ---- the lightbox ---- */

html.has-lightbox {
	overflow: hidden;
}

.lightbox {
	width: 100vw;
	max-width: 100vw;
	height: 100dvh;
	max-height: 100dvh;
	padding: 0;
	border: 0;
	background: transparent;
	color: var(--c-ink);
	overscroll-behavior: contain;
}

/*
 * Nearly opaque. At 0.94 the header's white nav landed at 26 over a 13 ground
 * — faint, but legible enough to read as a page sitting behind a photograph
 * rather than a viewer.
 */
.lightbox::backdrop {
	background-color: rgba(12, 11, 13, 0.97);
}

.lightbox__shell {
	display: grid;
	grid-template-rows: auto minmax(0, 1fr);
	gap: var(--gap-5);
	width: 100%;
	height: 100%;
	padding: var(--gap-5) var(--gutter) var(--gap-3);
}

.lightbox__bar {
	display: flex;
	gap: var(--gap-4);
	align-items: center;
	justify-content: space-between;
}

.lightbox__album {
	margin: 0;
	color: var(--c-ink);
	font-family: var(--font-heading);
	font-size: var(--fs-h5);
	font-weight: 400;
	line-height: var(--lh-tight);
	text-transform: uppercase;
}

.lightbox__counter {
	margin: 0;
	color: var(--c-ink);
	font-size: var(--fs-small);
	font-weight: 300;
	font-variant-numeric: tabular-nums;
	line-height: var(--lh-body);
	opacity: 0.6;
}

.lightbox__close {
	display: inline-flex;
	flex: 0 0 44px;
	align-items: center;
	justify-content: center;
	width: 44px;
	height: 44px;
	padding: 0;
	border: 1px solid var(--c-line);
	border-radius: 50%;
	background: transparent;
	color: var(--c-ink);
	cursor: pointer;
	transition: border-color var(--transition), background-color var(--transition);
}

.lightbox__close:hover {
	border-color: var(--c-accent);
	background-color: var(--c-accent);
}

.lightbox__close svg {
	width: 20px;
	height: 20px;
}

/*
 * stretch, not center. Centring left the figure content-sized, so a PORTRAIT
 * picture had no definite height for its max-height: 100% to resolve against
 * and collapsed — a 1624x2400 floor plan rendered at 56x83 in a 1280 stage.
 * Landscape hid it, because max-width bound first and the height simply
 * followed. Stretching gives the figure the row's height and the image
 * something real to fit inside.
 */
.lightbox__stage {
	position: relative;
	display: grid;
	grid-template-columns: 56px minmax(0, 1fr) 56px;
	gap: var(--gap-5);
	align-items: stretch;
	min-height: 0;
}

/*
 * Pinned to the middle column. A hidden arrow is display:none and leaves the
 * grid altogether, so with nothing to page through the figure auto-placed into
 * the 56px arrow column and the picture came out 56 wide in a 1280 stage.
 * Naming the columns makes the layout independent of whether the arrows render.
 */
.lightbox__nav--prev {
	grid-column: 1;
}

.lightbox__figure {
	grid-column: 2;
	display: grid;
	grid-template-rows: minmax(0, 1fr) auto;
	gap: var(--gap-5);
	align-items: center;
	justify-items: center;
	min-height: 0;
	margin: 0;
}

.lightbox__nav--next {
	grid-column: 3;
}

/*
 * contain, and bounded by the row rather than by the picture: a 3000px-wide
 * photograph and a portrait floorplan both have to fit the same box without
 * either overflowing the dialog or forcing it to scroll.
 */
.lightbox__image {
	width: auto;
	max-width: 100%;
	height: auto;
	max-height: 100%;
	border-radius: 12px;
	object-fit: contain;
}

.lightbox__caption {
	margin: 0;
	color: var(--c-ink);
	font-size: var(--fs-body);
	font-weight: 300;
	line-height: var(--lh-body);
	text-align: center;
	opacity: 0.8;
}

.lightbox__nav {
	display: inline-flex;
	/*
	 * Centred on the picture. The stage is align-items: stretch — which it has
	 * to be, so a portrait has a definite height to fit into — and stretch
	 * falls back to START for an item that already has a height of its own, so
	 * both arrows had quietly parked at the top of an 868 stage.
	 */
	align-self: center;
	align-items: center;
	justify-content: center;
	width: 56px;
	height: 56px;
	padding: 0;
	border: 1px solid var(--c-line);
	border-radius: 50%;
	background-color: rgba(35, 35, 38, 0.7);
	color: var(--c-ink);
	cursor: pointer;
	transition: border-color var(--transition), background-color var(--transition);
}

.lightbox__nav:hover {
	border-color: var(--c-accent);
	background-color: var(--c-accent);
}

.lightbox__nav svg {
	width: 24px;
	height: 24px;
}

.lightbox__nav[hidden] {
	display: none;
}

@media (prefers-reduced-motion: reduce) {
	.gallery-tile__media img {
		transition: none;
	}
}

@media (max-width: 1024px) {
	.gallery-album__grid {
		grid-template-columns: repeat(4, minmax(0, 1fr));
		gap: 16px;
	}

	/*
	 * The arrows leave the row and sit ON the picture. At 56 a side they were
	 * eating 112 of a 390 screen, which left the photograph 250 wide.
	 */
	.lightbox__stage {
		grid-template-columns: minmax(0, 1fr);
	}

	/* One column here, and the arrows sit ON the picture. */
	.lightbox__figure,
	.lightbox__nav--prev,
	.lightbox__nav--next {
		grid-column: 1;
	}

	.lightbox__nav {
		position: absolute;
		top: 50%;
		z-index: 1;
		width: 44px;
		height: 44px;
		transform: translateY(-50%);
	}

	.lightbox__nav--prev {
		left: 0;
	}

	.lightbox__nav--next {
		right: 0;
	}

	.lightbox__nav svg {
		width: 20px;
		height: 20px;
	}
}

@media (max-width: 600px) {

	/*
	 * The one place the row becomes a scroller. Wrapping is right at 1440,
	 * where fifteen chips take two lines and every option is in view; at 390
	 * the same fifteen take SEVEN, which is 290px of filter before the first
	 * photograph. A snap scroller costs the discoverability of the options
	 * past the edge and buys back the whole of the fold.
	 */
	.gallery__filter {
		flex-wrap: nowrap;
		margin-inline: calc(var(--gutter) * -1);
		padding-inline: var(--gutter);
		overflow-x: auto;
		scroll-snap-type: x proximity;
		scrollbar-width: none;
		-webkit-overflow-scrolling: touch;
		/* The last chip fades out, so it reads as a row that continues. */
		mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 40px), transparent 100%);
	}

	.gallery__filter::-webkit-scrollbar {
		display: none;
	}

	.gallery__chip {
		flex: 0 0 auto;
		scroll-snap-align: start;
	}

	/*
	 * Three across at 390 is a 108px tile, so the gutter drops to 8 — at 16 the
	 * gaps were taking a third of the row away from the photographs.
	 */
	.gallery-album__grid {
		grid-template-columns: repeat(3, minmax(0, 1fr));
		gap: 8px;
	}

	.gallery-album__head {
		flex-wrap: wrap;
		gap: var(--gap-7);
	}

	.gallery-album__rule {
		order: 3;
		flex-basis: 100%;
	}

	.gallery-album__count {
		margin-left: auto;
	}

	/* The head wraps here and the rule takes a row of its own, so the
	   negative pull above would ride up into it. */
	.gallery-album__desc {
		margin-top: 0;
	}

	/* No room for a label on a 108px tile — the lightbox carries it. */
	.gallery-tile__caption {
		display: none;
	}

	.gallery-tile__overlay {
		justify-content: center;
		padding: 8px;
	}

	.gallery-tile__zoom {
		flex-basis: 24px;
		width: 24px;
		height: 24px;
	}

	.gallery-tile__zoom svg {
		width: 12px;
		height: 12px;
	}

	.lightbox__shell {
		padding: 16px var(--gutter) var(--gap-5);
	}
}

/* ==================================================== property listing ==
   the design (desktop) / (mobile).
   ======================================================================= */

.property-archive {
	position: relative;
	overflow: hidden;
	background-color: var(--c-bg);
}

.property-archive__blueprint {
	position: absolute;
	top: -7px;
	left: -161px;
	width: 507.85px;
	height: 488px;
	background-image: url("../icons/blueprint-insights.svg");
	background-repeat: no-repeat;
	background-size: 100% 100%;
	pointer-events: none;
}

/*
 * No top padding: the design starts its toolbar flush against the banner's
 * bottom edge, the way the projects listing does, because the banner's scrim
 * already lands on this band's ground.
 */
.property-archive__inner {
	position: relative;
	display: flex;
	flex-direction: column;
	gap: var(--gap-2);
	width: 100%;
	max-width: calc(var(--container-max) + var(--gutter) * 2);
	margin-inline: auto;
	padding: 0 var(--gutter) var(--section-py);
}

/* ---- the toolbar ---- */

.property-archive__toolbar {
	display: flex;
	flex-direction: column;
	gap: var(--gap-4);
	width: 100%;
}

.property-archive__heading {
	margin: 0;
	color: var(--c-ink);
	font-family: var(--font-heading);
	font-size: var(--fs-h4);
	font-weight: 400;
	line-height: var(--lh-tight);
	text-box-trim: trim-both;
	text-box-edge: cap alphabetic;
	text-transform: uppercase;
}

/*
 * Five 200px fields and a Search button that takes the slack. The fields are
 * the same underlined control the projects sort uses, so the two listings read
 * as one system.
 */
.property-filter {
	display: flex;
	gap: var(--gap-4);
	align-items: flex-end;
	width: 100%;
}

.property-filter__field {
	position: relative;
	flex: 0 0 200px;
	display: flex;
	align-items: center;
	margin: 0;
	/* 8 over and 6 under comes to 34 in the design because the 1px rule is drawn
	   INSIDE that 34; CSS adds the border outside the padding box. */
	padding: 8px 0 5px;
	border-bottom: 1px solid rgba(255, 255, 255, 0.2);
}

.property-filter__select {
	width: 100%;
	padding: 0 24px 0 0;
	border: 0;
	background: transparent;
	color: var(--c-ink);
	font-family: var(--font-body);
	font-size: var(--fs-small);
	font-weight: 300;
	line-height: var(--lh-body);
	appearance: none;
	cursor: pointer;
}

.property-filter__select option {
	background-color: var(--c-bg-alt);
	color: var(--c-ink);
}

.property-filter__caret {
	position: absolute;
	right: 0;
	display: inline-flex;
	pointer-events: none;
}

.property-filter__caret svg {
	width: 20px;
	height: 20px;
	color: var(--c-ink);
}

.property-filter__submit {
	flex: 1 1 auto;
	justify-content: center;
	min-width: 120px;
}

/* ---- the grid ---- */

.property-archive__grid {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: 24px;
	width: 100%;
}

/*
 * The empty state. Not drawn — the design has no no-results frame — so it is
 * the card's own #272629 tile at the grid's full width, with the mark, the
 * reason and the two ways out. A single unstyled sentence under a full toolbar
 * read as a page that had failed to load rather than a search that found
 * nothing.
 */
.property-empty {
	display: flex;
	flex-direction: column;
	gap: var(--gap-4);
	align-items: center;
	width: 100%;
	padding: var(--gap-1) var(--gap-2);
	background-color: #272629;
	text-align: center;
}

.property-empty__mark {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 56px;
	height: 56px;
	border: 1px solid var(--c-line);
	border-radius: 50%;
	color: var(--c-ink);
}

.property-empty__mark svg {
	width: 24px;
	height: 24px;
	opacity: 0.7;
}

.property-empty__copy {
	display: flex;
	flex-direction: column;
	gap: var(--gap-6);
	align-items: center;
	max-width: 560px;
}

.property-empty__title {
	margin: 0;
	color: var(--c-ink);
	font-family: var(--font-heading);
	font-size: var(--fs-h4);
	font-weight: 400;
	line-height: var(--lh-tight);
	text-box-trim: trim-both;
	text-box-edge: cap alphabetic;
	text-transform: uppercase;
}

.property-empty__text {
	margin: 0;
	color: var(--c-ink);
	font-size: var(--fs-body);
	font-weight: 300;
	line-height: var(--lh-body);
	opacity: 0.8;
}

.property-empty__text strong {
	font-weight: 500;
	opacity: 1;
}

.property-empty__actions {
	display: flex;
	flex-wrap: wrap;
	gap: var(--gap-6);
	justify-content: center;
}

@media (max-width: 600px) {
	.property-empty {
		padding: var(--gap-2) var(--gap-5);
	}

	.property-empty__actions {
		width: 100%;
		flex-direction: column;
	}

	.property-empty__actions .btn {
		justify-content: center;
	}
}

.property-archive__inner .pagination {
	margin-top: 0;
}

/* ---- one card ---- */

.property-card {
	position: relative;
	display: flex;
	flex-direction: column;
	justify-content: space-between;
	gap: var(--gap-4);
	min-height: 458px;
	/*
	 * A literal 24, not --gap-5. The token is clamp(20, ., 24) and bottoms out
	 * at 20 below 1200, but both designs inset the card by 24 — the padding
	 * does not shrink between the two frames. Same trap as the
	 * nav row, the mobile listing gaps and the mobile row-head.
	 */
	padding: 24px;
	background-color: #272629;
}

.property-card__body {
	display: flex;
	flex-direction: column;
	gap: var(--gap-6);
}

/* No radius: the design carries none, and neither does the tile around it. */
.property-card__media {
	overflow: hidden;
	height: 200px;
}

.property-card__media img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: transform var(--transition-slow);
}

.property-card:hover .property-card__media img,
.property-card:focus-within .property-card__media img {
	transform: scale(var(--card-zoom, 1.04));
}

.property-card__copy {
	display: flex;
	flex-direction: column;
	gap: var(--gap-6);
	align-items: flex-start;
}

/* A pill, not a flag: 10% white on the tile's own ground, 28 radius. */
.property-card__status {
	margin: 0;
	padding: 4px 12px;
	border-radius: 28px;
	background-color: rgba(255, 255, 255, 0.1);
	color: var(--c-ink);
	font-size: 12px;
	font-weight: 700;
	line-height: var(--lh-body);
	text-transform: uppercase;
}

.property-card__title {
	margin: 0;
	color: var(--c-ink);
	font-family: var(--font-heading);
	font-size: var(--fs-h4);
	font-weight: 400;
	line-height: var(--lh-tight);
	text-box-trim: trim-both;
	text-box-edge: cap alphabetic;
	text-transform: uppercase;
}

.property-card__title a {
	color: inherit;
	text-decoration: none;
}

/*
 * Two lines. -webkit-box defeats text-box-trim, which is why the title above
 * is a plain block and only the blurb is clamped.
 */
.property-card__blurb {
	display: -webkit-box;
	overflow: hidden;
	margin: 0;
	color: var(--c-ink);
	font-size: var(--fs-body);
	font-weight: 300;
	line-height: var(--lh-body);
	-webkit-box-orient: vertical;
	-webkit-line-clamp: 2;
}

.property-card__foot {
	display: flex;
}

/* The button is the click target, raised above the full-tile overlay. */
.property-card__cta {
	position: relative;
	z-index: 1;
}

.property-card__hit {
	position: absolute;
	inset: 0;
}

@media (max-width: 1024px) {
	.property-archive__grid {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}

	.property-filter {
		flex-wrap: wrap;
		gap: var(--gap-5);
	}

	.property-filter__field {
		flex: 1 1 200px;
	}

	.property-filter__submit {
		flex: 1 1 100%;
	}
}

@media (max-width: 600px) {
	.property-archive__grid {
		grid-template-columns: minmax(0, 1fr);
	}

	/* The design stacks the five fields full width on a 16 pitch. */
	.property-filter {
		flex-direction: column;
		align-items: stretch;
		gap: var(--gap-6);
	}

	.property-filter__field,
	.property-filter__submit {
		flex: 0 0 auto;
		width: 100%;
	}

	/*
	 * Only the height changes at 390 (the design is 448 against the desktop
	 * 458, because the H4 drops from 24 to 20). The gap is already --gap-4,
	 * which resolves to the frame's 24 here and 32 at 1440 on its own — the
	 * --gap-5 override that used to sit here forced it to 20.
	 */
	.property-card {
		min-height: 448px;
	}
}

/* ===================================================== property detail ==
   the design (desktop) / (mobile).
   ======================================================================= */

/*
 * The listing status over the banner. The same pill the card
 * draws, absolutely placed at 640/44 inside the head block so it sits on the
 * H1's own line clear of the address. Below 1100 there is no room for it there,
 * so it returns to the flow under the crumb.
 */
.page-banner__titlerow {
	display: flex;
	flex-wrap: wrap;
	gap: 16px;
	/* The pill tops with the H1's box, which is where the frame's 44 puts it. */
	align-items: flex-start;
	width: 100%;
}

.page-banner__titlerow .page-banner__title {
	flex: 0 1 auto;
}

.page-banner__status {
	flex: 0 0 auto;
	margin: 0;
	padding: 4px 12px;
	border-radius: 28px;
	background-color: rgba(255, 255, 255, 0.1);
	color: var(--c-ink);
	font-size: 12px;
	font-weight: 700;
	line-height: var(--lh-body);
	text-transform: uppercase;
	backdrop-filter: blur(2px);
}

/* A <button> in the foot row, not a link — it opens the plan in place. */
button.page-banner__cta {
	cursor: pointer;
}

/*
 * The overview and the support bands are #272629; the inclusions and the
 * galleries between them are #19181B. The frame alternates them, and the
 * banner's own scrim ends on #272629 because that is what it lands on. I had
 * all four on the page ground, which flattened the whole page to one tone and
 * left the scrim finishing 14 levels dark.
 */
.single-property .page-banner__media::after,
.single-land .page-banner__media::after {
	background-image: linear-gradient(180deg, rgba(25, 24, 27, 0) 0%, #272629 100%);
}

/*
 * The H2s on this page are TRIMMED. The design measures 103 over two lines,
 * which is 2 x 56 x 1.1 with the ascender gap and the descender taken off; the
 * untrimmed box is 123. The same 20 was showing up on the inclusions heading,
 * the support heading (165 against 185 over three lines) and the galleries
 * heading, and pushing everything under each of them down with it.
 */
.property-overview .section-head__title,
.property-inclusions .section-head__title,
.property-support .section-head__title,
.property-gallery .section-head__title {
	text-box-trim: trim-both;
	text-box-edge: cap alphabetic;
}

/* ---- the overview and its meta strip ---- */

.property-overview {
	position: relative;
	padding: var(--section-py) 0;
	background-color: #272629;
}

/* 564 | 24 | 376 | 24 | 292 fills the 1280 column, the same split the project
   overview uses — the frame is even named the same. */
.property-overview__inner {
	display: flex;
	gap: var(--gap-5);
	align-items: center;
	width: 100%;
	max-width: calc(var(--container-max) + var(--gutter) * 2);
	margin-inline: auto;
	padding-inline: var(--gutter);
}

.property-overview__copy {
	display: flex;
	flex: 0 0 564px;
	flex-direction: column;
	gap: var(--gap-4);
	align-items: flex-start;
	min-width: 0;
}

.property-overview__body {
	color: var(--c-ink);
	font-size: var(--fs-body);
	font-weight: 300;
	line-height: var(--lh-body);
}

.property-overview__body p {
	margin: 0;
}

.property-overview__body p+p {
	margin-top: 16px;
}

/* The design sets this one in caps, unlike every other button on the site. */
.property-overview__cta {
	text-transform: uppercase;
}

.property-overview__media {
	display: flex;
	flex: 1 0 0;
	gap: var(--gap-5);
	align-items: flex-start;
	min-width: 0;
}

.property-overview__figure {
	position: relative;
	flex: 0 0 376px;
	overflow: hidden;
	aspect-ratio: 376 / 512;
}

.property-overview__figure img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* A square, not the project panel's 292x224 — the design is 292x292 with the
   agent's name under it rather than a mark centred inside it. */
.property-overview__agent {
	display: flex;
	flex: 1 0 0;
	flex-direction: column;
	gap: var(--gap-6);
	min-width: 0;
	margin: 0;
}

.property-overview__agent img {
	display: block;
	width: 100%;
	aspect-ratio: 1;
	object-fit: cover;
}

/*
 * Italic, as the design draws it — and SYNTHESISED, because only the upright
 * DM Sans faces are bundled. Same cause and same remedy as the project quote
 * in item 43: shipping the italic woff2 fixes both.
 */
.property-overview__agent figcaption {
	color: var(--c-ink);
	font-size: var(--fs-body);
	font-style: italic;
	font-weight: 300;
	line-height: var(--lh-body);
	text-align: center;
}

.property-overview__stats {
	display: flex;
	flex-direction: column;
	gap: var(--gap-2);
	width: 100%;
	max-width: calc(var(--container-max) + var(--gutter) * 2);
	margin-inline: auto;
	padding-inline: var(--gutter);
	/* 48 either side of the hairline — 48 under the overview and 48 above the
	   stats — not the band's 80. */
	margin-top: var(--gap-2);
}

.property-overview__rule {
	height: 1px;
	background-color: var(--c-line);
}

.property-stats {
	display: grid;
	grid-template-columns: repeat(4, minmax(0, 1fr));
	gap: 8px;
	margin: 0;
}

/*
 * #343336, not #272629 — the cell sits on the #272629 band, so it is a raised
 * tile on it exactly as the card is on the page ground. Sampled 52,51,54.
 * 8 between the value and its label, not 16.
 */
.property-stats__cell {
	display: flex;
	flex-direction: column;
	gap: 8px;
	padding: var(--gap-5);
	background-color: #343336;
}

/* <dd> before <dt>, so the reading order is value-then-label as drawn; the
   margin the UA puts on a dd has to go with it. */
/*
 * 120%, not 110%. The design is 24 tall on one line and 48 on two, which is
 * 20 x 1.2; at --lh-tight the line box is 22 and the two-line cell came out
 * 4 short.
 */
.property-stats__value {
	margin: 0;
	color: var(--c-ink);
	font-family: var(--font-heading);
	font-size: var(--fs-h5);
	font-weight: 400;
	line-height: var(--lh-heading);
}

.property-stats__label {
	margin: 0;
	color: var(--c-ink);
	font-size: var(--fs-small);
	font-weight: 300;
	line-height: var(--lh-body);
	opacity: 0.6;
}

/* ---- inclusions ---- */

.property-inclusions {
	position: relative;
	overflow: hidden;
	padding: var(--section-py) 0;
	background-color: var(--c-bg);
}

.property-inclusions__blueprint {
	position: absolute;
	top: -8px;
	right: -161px;
	width: 507.85px;
	height: 488px;
	background-image: url("../icons/blueprint-insights.svg");
	background-repeat: no-repeat;
	background-size: 100% 100%;
	pointer-events: none;
}

.property-inclusions__inner {
	position: relative;
	display: flex;
	gap: var(--gap-2);
	align-items: flex-start;
	width: 100%;
	max-width: calc(var(--container-max) + var(--gutter) * 2);
	margin-inline: auto;
	padding-inline: var(--gutter);
}

/*
 * The top-left is CUT. "Rectangle 11" is a vector in both frames, not a plain
 * rectangle — the design export with a transparent wedge, and
 * reading their alpha gives the same shape in each: the top edge runs as a
 * diagonal from the top-right corner down to 22.4% of the height on the left
 * (141 of 629, and 114 of 509). A shared angle, so it is one value.
 */
.property-inclusions__figure,
.property-support__figure {
	clip-path: polygon(100% 0, 100% 100%, 0 100%, 0 22.4%);
}

.property-inclusions__figure {
	flex: 0 0 519px;
	overflow: hidden;
	aspect-ratio: 519 / 629;
}

.property-inclusions__figure img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.property-inclusions__copy {
	display: flex;
	flex: 1 0 0;
	flex-direction: column;
	gap: var(--gap-4);
	min-width: 0;
}

/*
 * The lead-in and the list come out of one editor, so these rules hang off the
 * elements it produces rather than off classes a template controls — the client
 * writes an ordinary paragraph and an ordinary bulleted list and gets the
 * design. The fallback for an unedited listing is assembled as the same <p> and
 * <ul>, so both paths land on exactly these rules.
 *
 * The copy column is a flex column, so the paragraph and the list carry no
 * margins of their own. The design ends at 319 and the design starts at 351,
 * so the space between them is 32 — --gap-4, not --gap-3, which resolves to 40
 * at 1440 and put the list eight low.
 */
.property-inclusions__body {
	display: flex;
	flex-direction: column;
	gap: var(--gap-4);
}

.property-inclusions__body> :first-child {
	margin-top: 0;
}

.property-inclusions__body> :last-child {
	margin-bottom: 0;
}

.property-inclusions__body p {
	margin: 0;
	color: var(--c-ink);
	font-size: var(--fs-body);
	font-weight: 300;
	line-height: var(--lh-body);
	/*
	 * The design measures 211 at its brightest over the band's 25,24,27 — the
	 * same 80% the list under it is set at, not full white. At 1 it read 255
	 * and sat forward of the heading it belongs under.
	 */
	opacity: 0.8;
}

/*
 * 332.5 | 48 | 332.5 fills the 713 column.
 *
 * Two columns from ONE list: authoring it as two lists would have a screen
 * reader announce two lists of nine and eight, where columns keep it a single
 * list of nineteen and let the split move with the viewport.
 *
 * display: block is not decoration. A flex container ignores `columns`
 * outright — that is how nineteen items once ran down one column at 592 tall
 * against the frame's 358, with computed style still reporting column-count: 2
 * because that is the specified value, not whether it took effect. Block layout
 * has no `gap`, so the 8 between items is a margin.
 */
.property-inclusions__body ul {
	display: block;
	columns: 2;
	column-gap: var(--gap-2);
	margin: 0;
	padding: 0;
	list-style: none;
}

.property-inclusions__body li {
	position: relative;
	margin-bottom: 8px;
	padding-left: 26px;
	color: var(--c-ink);
	font-size: var(--fs-body);
	font-weight: 300;
	line-height: var(--lh-body);
	opacity: 0.8;
	break-inside: avoid;
}

.property-inclusions__body li:last-child {
	margin-bottom: 0;
}

/* A 22px marker box with an 8px red square at 7,7, then 4px to the text. */
.property-inclusions__body li::before {
	content: "";
	position: absolute;
	top: 7px;
	left: 7px;
	width: 8px;
	height: 8px;
	background-color: var(--c-accent);
}

.property-inclusions__body a {
	color: inherit;
}

/* ---- the support band ---- */

.property-support {
	position: relative;
	padding: var(--section-py) 0;
	background-color: #272629;
}

/*
 * Top-aligned, not centred. The copy and the photograph are BOTH 509 and both
 * start at y=0 — the heading lines up with the top of the photograph. Centring
 * only looked right because the frame's copy happens to fill 509 exactly; with
 * a shorter paragraph it floated the whole column down 21.
 */
.property-support__inner {
	display: flex;
	gap: var(--gap-2);
	align-items: flex-start;
	width: 100%;
	max-width: calc(var(--container-max) + var(--gutter) * 2);
	margin-inline: auto;
	padding-inline: var(--gutter);
}

.property-support__copy {
	display: flex;
	flex: 1 0 0;
	flex-direction: column;
	gap: var(--gap-4);
	align-items: flex-start;
	min-width: 0;
}

.property-support__body {
	color: var(--c-ink);
	font-size: var(--fs-body);
	font-weight: 300;
	line-height: var(--lh-body);
}

.property-support__body p {
	margin: 0;
}

.property-support__body p+p {
	margin-top: 16px;
}

.property-support__figure {
	flex: 0 0 519px;
	overflow: hidden;
	aspect-ratio: 519 / 509;
}

.property-support__figure img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

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

.property-gallery {
	position: relative;
	overflow: hidden;
	padding: var(--section-py) 0;
	background-color: var(--c-bg);
}

.property-gallery__blueprint {
	position: absolute;
	top: 0;
	right: -80px;
	width: 768.59px;
	height: 738.55px;
	background-image: url("../icons/blueprint-insights.svg");
	background-repeat: no-repeat;
	background-size: 100% 100%;
	pointer-events: none;
}

.property-gallery__inner {
	position: relative;
	display: flex;
	flex-direction: column;
	gap: var(--gap-1);
	width: 100%;
	max-width: calc(var(--container-max) + var(--gutter) * 2);
	margin-inline: auto;
	padding-inline: var(--gutter);
}

/* The head on the left and the blurb set against its foot on the right. */
/* 837 | 32 | 411 fills the 1280 row. */
.property-gallery__head {
	display: flex;
	gap: var(--gap-4);
	align-items: flex-end;
}

.property-gallery__head .section-head {
	flex: 1 1 auto;
}

/* Paragraph 1, not 2: the design is 88 tall over four lines in 411, which is
   16 x 1.4. At 14 it came out 59. */
.property-gallery__blurb {
	flex: 0 0 411px;
	margin: 0;
	color: var(--c-ink);
	font-size: var(--fs-body);
	font-weight: 300;
	line-height: var(--lh-body);
	opacity: 0.8;
}

/*
 * The rail is allowed to run past the container's right edge, which is what
 * puts the fifth tile half in frame the way the design draws it.
 */
.property-gallery__rail {
	overflow: visible;
	width: 100%;
}

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

.property-gallery__slide {
	width: 410px;
	max-width: 82%;
	height: auto;
}

.property-gallery__tile {
	display: block;
	width: 100%;
	padding: 0;
	overflow: hidden;
	border: 0;
	background-color: #272629;
	cursor: pointer;
}

.property-gallery__tile img {
	display: block;
	width: 100%;
	aspect-ratio: 410 / 356;
	object-fit: cover;
	transition: transform var(--transition-slow);
}

.property-gallery__tile:hover img,
.property-gallery__tile:focus-visible img {
	transform: scale(var(--card-zoom, 1.04));
}

@media (max-width: 1024px) {

	.property-overview__inner,
	.property-inclusions__inner,
	.property-support__inner {
		flex-direction: column;
		align-items: stretch;
		gap: var(--gap-3);
	}

	.property-overview__copy,
	.property-inclusions__figure,
	.property-support__figure {
		flex: 0 0 auto;
	}

	/*
	 * The pair stacks here too. Left as a row, flex: 0 0 auto on
	 * the figure sized it from the photograph's intrinsic 3000px and pushed the
	 * document 2000px wide — a basis of auto on a flex item with an
	 * aspect-ratio takes the CONTENT's width, not the row's.
	 */
	.property-overview__media {
		flex-direction: column;
	}

	.property-overview__figure {
		flex: 0 0 auto;
		width: 100%;
		aspect-ratio: 16 / 10;
	}

	.property-overview__agent {
		flex: 0 0 auto;
		width: 100%;
	}

	.property-overview__agent img {
		aspect-ratio: 16 / 10;
	}

	.property-inclusions__figure,
	.property-support__figure {
		aspect-ratio: 16 / 10;
	}

	/* The photograph reads before the copy on a stacked inclusions band. */
	.property-inclusions__figure {
		order: -1;
	}

	.property-stats {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}

	.property-gallery__head {
		flex-direction: column;
		align-items: flex-start;
		gap: var(--gap-5);
	}

	.property-gallery__blurb {
		flex: 0 0 auto;
	}
}

@media (max-width: 600px) {
	.property-inclusions__body ul {
		columns: 1;
	}

	.property-stats {
		grid-template-columns: minmax(0, 1fr);
	}

}

/* ---- the lightbox's empty state ---- */

.lightbox__empty {
	grid-column: 2;
	display: flex;
	flex-direction: column;
	gap: var(--gap-4);
	align-items: center;
	justify-content: center;
	max-width: 460px;
	margin-inline: auto;
	text-align: center;
}

.lightbox__empty[hidden] {
	display: none;
}

.lightbox__empty-mark {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 56px;
	height: 56px;
	border: 1px solid var(--c-line);
	border-radius: 50%;
	color: var(--c-ink);
}

.lightbox__empty-mark svg {
	width: 24px;
	height: 24px;
	opacity: 0.7;
}

.lightbox__empty-title {
	margin: 0;
	color: var(--c-ink);
	font-family: var(--font-heading);
	font-size: var(--fs-h4);
	font-weight: 400;
	line-height: var(--lh-tight);
	text-box-trim: trim-both;
	text-box-edge: cap alphabetic;
	text-transform: uppercase;
}

.lightbox__empty-text {
	margin: 0;
	color: var(--c-ink);
	font-size: var(--fs-body);
	font-weight: 300;
	line-height: var(--lh-body);
	opacity: 0.8;
}

.lightbox__figure[hidden] {
	display: none;
}

@media (max-width: 1024px) {
	.lightbox__empty {
		grid-column: 1;
	}
}

/* Hidden plan triggers: they carry data, they are never seen. */
.page-banner__plan[hidden] {
	display: none;
}

/* ---- the map in the overview ---- */

.property-overview__figure--map {
	background-color: var(--c-bg);
}

.property-overview__map {
	display: block;
	width: 100%;
	height: 100%;
	border: 0;
}

/* ---- the Contact Agent dialog ---- */

.enquire {
	width: 100vw;
	max-width: 100vw;
	height: 100dvh;
	max-height: 100dvh;
	padding: 0;
	border: 0;
	background: transparent;
	color: var(--c-ink);
	overscroll-behavior: contain;
}

.enquire::backdrop {
	background-color: rgba(12, 11, 13, 0.9);
	backdrop-filter: blur(3px);
}

/*
 * Centred on the screen and scrollable within itself, so a long form on a short
 * screen scrolls the PANEL rather than the page behind it.
 */
.enquire__panel {
	position: relative;
	display: flex;
	flex-direction: column;
	gap: var(--gap-4);
	width: min(520px, calc(100vw - var(--gutter) * 2));
	max-height: calc(100dvh - var(--gap-2) * 2);
	margin: var(--gap-2) auto;
	padding: var(--gap-2);
	overflow-y: auto;
	border-radius: 16px;
	background-color: #272629;
	/* The same violet wash the consultation panel carries, at the same weight. */
	background-image:
		radial-gradient(120% 80% at 8% 100%, rgba(120, 80, 190, 0.055) 0%, rgba(120, 80, 190, 0) 55%),
		linear-gradient(180deg, rgba(84, 62, 196, 0) 30%, rgba(84, 62, 196, 0.035) 100%),
		linear-gradient(rgba(84, 62, 196, 0.012), rgba(84, 62, 196, 0.012));
}

.enquire__close {
	position: absolute;
	top: 16px;
	right: 16px;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 40px;
	height: 40px;
	padding: 0;
	border: 1px solid var(--c-line);
	border-radius: 50%;
	background: transparent;
	color: var(--c-ink);
	cursor: pointer;
	transition: border-color var(--transition), background-color var(--transition);
}

.enquire__close:hover {
	border-color: var(--c-accent);
	background-color: var(--c-accent);
}

.enquire__close svg {
	width: 18px;
	height: 18px;
}

.enquire__head {
	display: flex;
	flex-direction: column;
	gap: var(--gap-6);
	/* clear of the close button */
	padding-right: 48px;
}

.enquire__eyebrow {
	margin: 0;
	color: var(--c-ink);
	font-size: var(--fs-small);
	font-weight: 300;
	line-height: var(--lh-body);
	opacity: 0.6;
}

/* The listing is the heading: a form that does not say what it is about makes
   the sender wonder whether it knows. */
.enquire__title {
	margin: 0;
	color: var(--c-ink);
	font-family: var(--font-heading);
	font-size: var(--fs-h4);
	font-weight: 400;
	line-height: var(--lh-tight);
	text-box-trim: trim-both;
	text-box-edge: cap alphabetic;
	text-transform: uppercase;
}

.enquire__agent {
	display: flex;
	gap: 12px;
	align-items: center;
	padding-top: 4px;
}

.enquire__agent-photo {
	display: block;
	flex: 0 0 40px;
	width: 40px;
	height: 40px;
	overflow: hidden;
	border-radius: 50%;
}

.enquire__agent-photo img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.enquire__agent-name {
	color: var(--c-ink);
	font-size: var(--fs-small);
	font-weight: 300;
	line-height: var(--lh-body);
	opacity: 0.8;
}

/* The form is inked for this dark panel, exactly as the consultation one is. */
.enquire__form .bbqld-form form,
.enquire__form form {
	display: flex;
	flex-direction: column;
	gap: var(--gap-5);
}

.enquire__form input,
.enquire__form textarea {
	color: var(--c-ink);
	border-bottom-color: rgba(255, 255, 255, 0.1);
}

.enquire__form input::placeholder,
.enquire__form textarea::placeholder {
	color: var(--c-ink);
	opacity: 0.5;
}

.enquire__form input:focus,
.enquire__form textarea:focus {
	border-bottom-color: var(--white);
}

.enquire__form {
	--form-focus: var(--white);
}

.enquire__form .wpcf7-response-output,
.enquire__form .wpcf7-not-valid-tip {
	color: var(--c-ink);
}

.enquire__form .wpcf7-submit {
	margin-top: 8px;
}

/* A sent enquiry keeps the panel open on its confirmation. */
.enquire.is-sent .enquire__form .wpcf7-response-output {
	border-color: var(--c-accent);
}

@media (max-width: 600px) {
	.enquire__panel {
		width: calc(100vw - 32px);
		padding: var(--gap-5);
		margin: 16px auto;
		max-height: calc(100dvh - 32px);
	}
}

/* ================================ mobile carousel cutoff (sitewide) ===
   Every mobile carousel in the design runs its track to the VIEWPORT edge, so
   the next card is cut off there and reads as "there is more" — 26px of it at
   the 316 + 24 pitch these two bands share with Insights and Solutions.

   Featured Projects and More Solutions were still clipping at the container
   instead, which is 24px short, and 24 of the 26 went with it: what was left
   was a 2px sliver that read as a rendering seam rather than a card.

   The idiom is the one How It Works and Is This You already use — drop the
   inner's trailing padding and hand it back to the parts that are NOT the
   track, so the heading and the rail stay inside the gutter.
   ======================================================================= */

@media (max-width: 767px) {

	.project-cards__inner,
	.more-solutions__inner {
		padding-inline-end: 0;
	}

	.project-cards__head,
	.project-cards__foot,
	.more-solutions__title {
		padding-inline-end: var(--gutter);
		width: 100%;
	}
}


/* ========================================================= useful tools ==
   Two bands, one calculator each — the arrangement the old site uses. They
   answer different questions at different points in a build, and the duty one
   embeds a third-party widget whose height is not ours to set, so pairing them
   on one row would tie the height of a band we control to one we do not.

   Each band is a heading over a single card. Inside the card the controls and
   the results sit side by side on desktop and stack below 900.
   ======================================================================= */

.calc-band {
	background-color: var(--c-bg);
}

.calc-band__inner {
	display: flex;
	flex-direction: column;
	gap: var(--gap-2);
	max-width: var(--container-max);
	margin-inline: auto;
	padding: var(--section-py) var(--gutter);
}

/*
 * The duty band sits on the theme's raised ground so it reads as its own
 * section rather than the back half of the repayments one.
 *
 * #272629, which is what the FAQ band, the gallery tiles and the archives are
 * already drawn on — NOT --c-bg-alt. That token is the CARD surface, and the
 * repayments calculator's own card is drawn on it directly above; reusing it
 * here would have made this band the same colour as the card in the band
 * before it, which reads as a mistake rather than a division.
 *
 * It keeps its full top padding, unlike when the two ran together: a band with
 * its own ground has to start clear of the one above, or the colour change
 * lands hard against the previous band's content.
 */
.calc-band--duty {
	background-color: #272629;
}

.calc-band__intro {
	max-width: 720px;
	margin-top: 16px;
	color: var(--c-ink-muted);
	font-size: var(--fs-lead);
	font-weight: 300;
	line-height: var(--lh-body);
}

.calc {
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
	gap: var(--gap-3);
	padding: var(--gap-3);
	background-color: var(--c-bg-alt);
	border: 1px solid var(--c-line);
}

.calc__controls {
	display: flex;
	flex-direction: column;
	gap: var(--gap-5);
}

.calc__field {
	display: flex;
	flex-direction: column;
	gap: 8px;
	margin: 0;
}

.calc__label {
	color: var(--c-ink-muted);
	font-family: var(--font-body);
	font-size: var(--fs-small);
	font-weight: 300;
	line-height: 1.4;
}

/*
 * The rule under the field is the theme's form idiom carried onto the dark
 * ground: the contact card draws it at 10% BLACK, which is invisible here.
 */
.calc__input-wrap {
	display: flex;
	align-items: baseline;
	gap: 4px;
	padding-bottom: 8px;
	border-bottom: 1px solid var(--c-line-strong);
	transition: border-color var(--transition);
}

.calc__input-wrap:focus-within {
	border-bottom-color: var(--c-ink);
}

.calc__prefix,
.calc__suffix {
	flex: none;
	color: var(--c-ink-muted);
	font-family: var(--font-heading);
	font-size: var(--fs-h5);
	line-height: 1.2;
}

.calc__input {
	width: 100%;
	min-width: 0;
	padding: 0;
	background: transparent;
	color: var(--c-ink);
	font-family: var(--font-heading);
	font-size: var(--fs-h5);
	font-weight: 400;
	line-height: 1.2;
	border: 0;
	border-radius: 0;
	appearance: none;
}

/*
 * The ring goes on the WRAP, not the control. The control has no box of its own
 * — it sits flush inside the field and on top of the rule — so an outline drawn
 * on it was cropped against the field's own edge.
 *
 * `:has(:focus-visible)` rather than `:focus-within`, so the ring answers a
 * keyboard and not a mouse click. The rule turning to full ink above is the
 * affordance for both.
 */
.calc__input:focus {
	outline: none;
}

.calc__input-wrap:has(:focus-visible) {
	outline: 1px solid var(--c-ink);
	outline-offset: 4px;
}

/* The caret is drawn rather than left to the UA, which paints it black here. */
.calc__input-wrap--select {
	position: relative;
}

.calc__input-wrap--select::after {
	content: "";
	position: absolute;
	right: 2px;
	bottom: 14px;
	width: 8px;
	height: 8px;
	border-right: 1px solid var(--c-ink-muted);
	border-bottom: 1px solid var(--c-ink-muted);
	transform: rotate(45deg);
	pointer-events: none;
}

.calc__input-wrap--select .calc__input {
	padding-right: 24px;
	cursor: pointer;
}

/* The list itself is the UA's, and it paints on the system ground. */
.calc__input option {
	background-color: var(--c-bg-alt);
	color: var(--c-ink);
}

/*
 * The results are the second COLUMN on desktop, so the divide between them and
 * the controls is a left rule. It becomes a top rule once the card stacks.
 */
.calc__results {
	display: flex;
	flex-direction: column;
	gap: var(--gap-6);
	padding-left: var(--gap-3);
	border-left: 1px solid var(--c-line-strong);
}

.calc__results-title {
	margin: 0;
	color: var(--c-ink-muted);
	font-family: var(--font-body);
	font-size: var(--fs-small);
	font-weight: 300;
	line-height: 1.4;
}

.calc__headline {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: 8px;
	margin: 0;
}

.calc__headline-value {
	color: var(--c-ink);
	font-family: var(--font-heading);
	font-size: var(--fs-h2);
	font-weight: 500;
	line-height: var(--lh-tight);
	/*
	 * The figure changes on every keystroke, and proportional digits reflow the
	 * whole line as they do — the unit beside it visibly jitters. Tabular
	 * figures hold their advance so only the glyphs change.
	 */
	font-variant-numeric: tabular-nums;
}

.calc__headline-unit {
	color: var(--c-ink-muted);
	font-family: var(--font-body);
	font-size: var(--fs-body);
	font-weight: 300;
}

.calc__rows {
	display: flex;
	flex-direction: column;
	gap: 0;
	margin: 0;
}

.calc__row {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 16px;
	padding: 12px 0;
	border-top: 1px solid var(--c-line);
}

.calc__row dt {
	color: var(--c-ink-muted);
	font-family: var(--font-body);
	font-size: var(--fs-small);
	font-weight: 300;
	line-height: 1.4;
}

.calc__row dd {
	margin: 0;
	color: var(--c-ink);
	font-family: var(--font-heading);
	font-size: var(--fs-body);
	font-weight: 500;
	font-variant-numeric: tabular-nums;
	text-align: right;
	white-space: nowrap;
}

.calc__note {
	margin: 0;
	color: var(--c-accent);
	font-family: var(--font-body);
	font-size: var(--fs-small);
	font-weight: 300;
	line-height: var(--lh-body);
}

/* ---------------------------------------- the embedded duty calculator --- */

/*
 * The widget brings its own light stylesheet from its host, so rather than
 * fight it on the dark ground it is given the white card the contact form
 * already establishes. Anything it injects inherits a sane ground and its own
 * greys read as intended.
 */
.calc-band__panel {
	padding: var(--gap-3);
	background-color: var(--white, #fff);
	color: var(--c-ink-dark);
}

/*
 * The widget reveals ITSELF by removing `hidden` once it has cleared its host's
 * blocklist, so the panel would otherwise sit empty for four round trips with
 * nothing to say. These two are swapped by initDutyCalculator().
 */
.calc-band__loading,
.calc-band__fallback {
	margin: 0;
	color: rgba(0, 0, 0, 0.6);
	font-family: var(--font-body);
	font-size: var(--fs-small);
	font-weight: 300;
	line-height: var(--lh-body);
	text-align: center;
}

.calc-band__fallback a {
	color: var(--c-accent);
}

/*
 * The widget shows and hides its own parts with a `hidden` CLASS — it reveals
 * its container by removing it once the blocklist check passes, and hides its
 * error blocks by adding it. That is a Bootstrap utility, which the old site's
 * theme happened to load and this one does not, so every one of those calls
 * was a no-op: the container was never actually hidden, and an error state
 * would have stayed on screen after the widget tried to dismiss it.
 *
 * Defined here rather than globally. `.hidden` as a sitewide utility is exactly
 * the kind of name that collides later, and nothing else in the theme wants it
 * — the rest of the codebase uses the `hidden` ATTRIBUTE.
 */
.calc-band__panel .hidden {
	display: none;
}

/*
 * The widget's own markup, nudged only where it fights the theme. Kept to a
 * minimum on purpose: every selector here is a bet on a third party's DOM.
 */
.calc-band__panel #stamp-duty-calculator {
	max-width: 100%;
}

/*
 * The duplicate Calculate button, suppressed — carried over from the live site
 * verbatim, so this page shows what that one shows.
 *
 * The widget renders its Calculate control twice with an explanatory paragraph
 * after the first, and the live site has hidden that pair for years. It is
 * pinned to `:first-of-type`, which is a bet on the order of a third party's
 * DOM: if a future version of the widget reorders or renames anything here,
 * this silently stops matching and the duplicate returns. Nothing breaks — it
 * just looks wrong — so check it if the calculator ever grows a second button.
 */
.calc-band__panel #stamp-duty-calculator .stamp-calculate:first-of-type,
.calc-band__panel #stamp-duty-calculator .stamp-calculate:first-of-type+p {
	display: none;
}

.calc-band__panel img {
	display: inline;
}

.calc-band__disclaimer {
	max-width: 860px;
	margin: 0;
	color: var(--c-ink-muted);
	font-family: var(--font-body);
	font-size: 12px;
	font-weight: 300;
	line-height: var(--lh-body);
}

@media (max-width: 900px) {

	.calc {
		grid-template-columns: minmax(0, 1fr);
		padding: var(--gap-4);
	}

	/* Stacked, the divide is above the results rather than beside them. */
	.calc__results {
		padding-top: var(--gap-5);
		padding-left: 0;
		border-top: 1px solid var(--c-line-strong);
		border-left: 0;
	}

	.calc-band__panel {
		padding: var(--gap-4);
	}
}

/* =======================================================================
   Client Requirement Analysis — the unlisted pre-meeting questionnaire.

   Two bands and nothing else: the dark heading band the rest of the inner
   pages open on, then a white sheet carrying the form. It is deliberately
   plainer than any other page here — someone reaching it has already agreed
   to meet, so there is nothing left to sell them and twenty questions to get
   through.

   The form is NOT wrapped in .bbqld-form. That set of styles is built for the
   six-field card in the contact band: underlined controls, a placeholder
   standing in for the label and a textarea pinned to 60px. Every one of those
   is wrong for a questionnaire whose questions run a full sentence and whose
   answers run a paragraph, so the controls are drawn from scratch here.
   ======================================================================= */

.reqform-hero {
	/*
	 * The header OVERLAYS this band — is_page() takes the transparent bar, the
	 * same as every other inner page. The pages that open on a photograph
	 * absorb it in a 648px banner the content is bottom-aligned inside; this
	 * band is only as tall as its copy, so it has to clear the bar itself.
	 * Without the extra it did not: the H1's line box started 16px ABOVE the
	 * header's bottom edge.
	 */
	padding: calc(var(--header-height) + var(--section-py)) var(--gutter) var(--section-py);
	background-color: var(--c-bg);
	/* The same violet wash .page-hero carries, so the band belongs to the site
	   even without the photograph the other inner pages open on. */
	background-image:
		radial-gradient(120% 90% at 18% 88%, rgba(84, 62, 196, 0.2) 0%, rgba(84, 62, 196, 0) 62%),
		radial-gradient(90% 70% at 62% 18%, rgba(120, 80, 190, 0.1) 0%, rgba(120, 80, 190, 0) 65%),
		linear-gradient(rgba(88, 66, 180, 0.07), rgba(88, 66, 180, 0.07));
}

.reqform-hero__inner {
	display: flex;
	flex-direction: column;
	gap: var(--gap-4);
	width: 100%;
	max-width: var(--container-max);
	margin-inline: auto;
}

.reqform-hero__title {
	margin: 0;
	color: var(--c-ink);
	font-family: var(--font-heading);
	font-size: var(--fs-h1);
	font-weight: 400;
	line-height: 1.3;
	letter-spacing: -2px;
	text-transform: uppercase;
}

/*
 * Held to 720 rather than the full 1280. The blurb is two paragraphs of body
 * copy, and across the whole container a line ran past 150 characters — well
 * beyond the 60-to-80 a reader tracks back from without losing the line.
 */
.reqform-hero__blurb {
	max-width: 720px;
	color: var(--c-ink);
	font-size: var(--fs-lead);
	font-weight: 300;
	line-height: var(--lh-body);
	opacity: 0.8;
}

.reqform-hero__blurb p {
	margin: 0;
}

.reqform-hero__blurb p+p {
	margin-top: var(--gap-6);
}

/* ---- the white sheet ---- */

.reqform {
	padding: var(--section-py) var(--gutter);
	background-color: var(--white);
	color: var(--c-ink-dark);
}

/*
 * 840, not the container's 1280. A form is read down a single column, and the
 * fields would otherwise be drawn as 1280-wide boxes for answers that are
 * mostly a few words long.
 */
.reqform__inner {
	width: 100%;
	max-width: 840px;
	margin-inline: auto;
}

.reqform__notice {
	margin: 0;
	color: var(--c-accent);
	font-size: var(--fs-body);
}

.reqform form {
	display: flex;
	flex-direction: column;
	gap: var(--gap-1);
}

/*
 * The PDF's four headed blocks, kept as real fieldsets: the questions under
 * "Land" are only intelligible as a group, and a screen reader announces the
 * legend with each control inside it.
 */
.reqform__set {
	display: flex;
	flex-direction: column;
	gap: var(--gap-5);
	min-width: 0;
	margin: 0;
	padding: 0;
	border: 0;
}

/*
 * float rather than the UA's default legend placement, so the rule below it
 * runs the full width of the fieldset instead of breaking around the text.
 * The float is closed by the fieldset's own flex context.
 */
.reqform__legend {
	float: left;
	width: 100%;
	margin: 0 0 var(--gap-6);
	padding: 0 0 12px;
	color: var(--c-ink-dark);
	font-family: var(--font-heading);
	font-size: var(--fs-h4);
	font-weight: 400;
	line-height: 1.1;
	text-transform: uppercase;
	border-bottom: 1px solid rgba(0, 0, 0, 0.12);
}

/* The two clients, side by side as the sheet sets them out. */
.reqform__pair {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: var(--gap-2);
}

.reqform__party {
	display: flex;
	flex-direction: column;
	gap: var(--gap-5);
	min-width: 0;
}

.reqform__party-title {
	margin: 0;
	color: var(--c-ink-dark);
	font-family: var(--font-body);
	font-size: var(--fs-small);
	font-weight: 500;
	line-height: 20px;
	text-transform: uppercase;
	letter-spacing: 0.04em;
	opacity: 0.6;
}

.reqform__field {
	display: flex;
	flex-direction: column;
	gap: 8px;
	min-width: 0;
}

/*
 * Visible, unlike every other form on the site. Several of these questions are
 * a full sentence and two of them depend on the answer above — neither
 * survives being folded into a placeholder that disappears the moment someone
 * starts typing.
 */
.reqform__label {
	display: block;
	color: var(--c-ink-dark);
	font-family: var(--font-body);
	font-size: var(--fs-small);
	font-weight: 500;
	line-height: var(--lh-body);
}

.reqform__req {
	color: var(--c-accent);
	text-decoration: none;
	border: 0;
}

.reqform input[type="text"],
.reqform input[type="email"],
.reqform input[type="tel"],
.reqform textarea,
.reqform select {
	display: block;
	width: 100%;
	padding: 11px 13px;
	background-color: var(--white);
	color: var(--c-ink-dark);
	font-family: var(--font-body);
	/*
	 * 16px, where the rest of the site's controls are 14. Safari on iOS zooms
	 * the page in on any focused control under 16px and does not zoom back
	 * out, which on a twenty-question form means being left zoomed in for the
	 * whole of it.
	 */
	font-size: 16px;
	font-weight: 300;
	line-height: 20px;
	border: 1px solid rgba(0, 0, 0, 0.18);
	border-radius: 4px;
	transition: border-color var(--transition);
}

.reqform textarea {
	min-height: 96px;
	resize: vertical;
}

/*
 * The UA's own arrow is dropped for the theme's caret, because the native
 * control cannot be padded to match the text inputs beside it — a select
 * stayed 4px shorter than every field above it on WebKit.
 */
.reqform select {
	appearance: none;
	padding-right: 40px;
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%2319181B' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
	background-repeat: no-repeat;
	background-position: right 14px center;
	background-size: 12px 8px;
	cursor: pointer;
}

/* An unanswered select shows its blank option; grey it so it reads as a prompt. */
.reqform select:invalid,
.reqform select option[value=""] {
	color: rgba(0, 0, 0, 0.5);
}

.reqform input::placeholder,
.reqform textarea::placeholder {
	color: rgba(0, 0, 0, 0.5);
	opacity: 1;
}

.reqform :is(input, textarea, select):focus {
	border-color: var(--c-ink-dark);
	outline: none;
}

/*
 * The ring follows the ink, not the brand. Red on a focused field reads as the
 * rejection .wpcf7-not-valid-tip uses it for, which on this form would mean a
 * correctly filled answer looking refused the moment it was tabbed into.
 */
.reqform :is(input, textarea, select, button):focus-visible {
	outline: 1px solid var(--c-ink-dark);
	outline-offset: 2px;
}

/*
 * .btn--primary hovers to WHITE, which is the ground here — so on this band it
 * darkens instead, the same exception .btn--on-panel makes on the white nav
 * panels.
 */
.reqform .btn--primary:hover {
	background-color: var(--c-ink-dark);
	color: var(--white);
}

.reqform .wpcf7-submit {
	align-self: flex-start;
	cursor: pointer;
}

/* ---- Contact Form 7's own chrome ---- */

.reqform .wpcf7-form-control-wrap {
	display: block;
}

.reqform .wpcf7-not-valid-tip {
	display: block;
	margin-top: 6px;
	color: var(--c-accent);
	font-size: 12px;
	line-height: 1.4;
}

.reqform .wpcf7-not-valid {
	border-color: var(--c-accent);
}

.reqform .wpcf7-response-output {
	margin: var(--gap-6) 0 0;
	padding: 12px 16px;
	color: var(--c-ink-dark);
	font-size: 13px;
	line-height: 1.4;
	border: 1px solid rgba(25, 24, 27, 0.2);
	border-radius: 4px;
}

.reqform form.invalid .wpcf7-response-output,
.reqform form.unaccepted .wpcf7-response-output {
	border-color: var(--c-accent);
}

.reqform form.sent .wpcf7-response-output {
	border-color: #2E7D32;
}

/*
 * Taken out of the flex flow, for the reason the contact card's is: CF7 ships
 * the spinner as an inline-block that is merely hidden until a submission is
 * in flight, and flex blockifies it into a 24px item holding empty space open
 * under the button at all times.
 */
.reqform .wpcf7-spinner {
	position: absolute;
	margin-left: 8px;
}

/*
 * Tick-box groups (the land acquisition brief). A nested fieldset, so the
 * question is announced with each option; its legend borrows .reqform__label.
 */
.reqform__choice {
	min-width: 0;
	margin: 0;
	padding: 0;
	border: 0;
}

.reqform__choice > .reqform__label {
	margin-bottom: 12px;
	padding: 0;
}

/* Three across, as the PDF sets them out. */
.reqform .wpcf7-checkbox {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: 12px 24px;
}

.reqform .wpcf7-list-item {
	margin: 0;
}

.reqform .wpcf7-list-item label {
	display: flex;
	align-items: center;
	gap: 10px;
	color: var(--c-ink-dark);
	font-size: 16px;
	font-weight: 300;
	line-height: 20px;
	cursor: pointer;
}

.reqform input[type="checkbox"] {
	flex: none;
	width: 18px;
	height: 18px;
	margin: 0;
	accent-color: var(--c-ink-dark);
	cursor: pointer;
}

@media (max-width: 768px) {

	/* The two clients stack; side by side they were 150px columns on a phone. */
	.reqform__pair {
		grid-template-columns: minmax(0, 1fr);
		gap: var(--gap-1);
	}

	.reqform .wpcf7-checkbox {
		grid-template-columns: minmax(0, 1fr);
	}
}
