/*
Theme Name: AAC Partners
Theme URI:
Author: Publitrust
Author URI:
Description: Tema a blocchi per AAC Partners — Investment & Development Management.
Requires at least: 6.7
Tested up to: 7.0
Requires PHP: 8.2
Version: 0.8.30
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: aac-partners
Tags: block-theme, full-site-editing
*/

/*
 * Only what theme.json cannot express lives here: sticky positioning, pseudo-element
 * decoration, scroll-driven state, and list resets. Colours, type and spacing all
 * resolve to presets — no raw brand values below.
 */

:root {
	--aac--header-height: 5.75rem;
	--aac--header-height-condensed: 4.125rem;
	--aac--logo-height: 3.75rem;
	--aac--logo-height-condensed: 2.625rem;
	--aac--footer-logo-height: 4.25rem;
	/* Veil over the hero photograph. A tint of the surface neutral rather than a
	   brand colour, so it stays a component value instead of a palette entry. */
	--aac--hero-veil: rgba(244, 247, 250, 0.3);
	--aac--ease: cubic-bezier(0.22, 0.61, 0.36, 1);

	/*
	 * Asset-class colours. Not brand colours and not a palette entry — they encode
	 * a category, and the same five drive the projects map's markers and legend.
	 */
	/* Tint behind the projects map. A shade darker than the `surface-alt` preset
	   so the grey dot grid reads against it; not a palette entry because it
	   backs exactly one section. */
	--aac--surface-map: #e7eef7;

	--aac--cat-office: #2f6fb0;
	--aac--cat-logistics: #0b2f6b;
	--aac--cat-hospitality: #4a9b3f;
	--aac--cat-residential: #cf2e77;
	--aac--cat-pbsa: #e6821e;
}

/*
 * Phone step for the section rhythm. The reference drops `--vsp` from
 * clamp(64px,9vw,120px) to clamp(40px,9vw,58px) below 760px, and the two curves
 * are discontinuous — 58px just under the breakpoint against 68.4px just over —
 * so no single clamp() can express both and theme.json cannot hold a query.
 *
 * Redefining the preset is the same move the reference makes on `--vsp`, and it
 * is safe because `spacing|70` is the section-padding token: every use of it in
 * this theme is a section's top/bottom padding, never a gap or a margin.
 */
@media (max-width: 760px) {
	:root {
		--wp--preset--spacing--70: clamp(2.5rem, 9vw, 3.625rem);
	}
}

/*
 * Phone step for the base text size, mirroring the reference's
 * `@media (max-width:480px){ body{font-size:16px} }`. theme.json sets the body
 * size from the `medium` preset and cannot hold a query, so it is stepped here.
 *
 * On `body` rather than on the preset: the reference lowers only the inherited
 * size, so anything given an explicit size keeps it. Redefining
 * `--wp--preset--font-size--medium` would also shrink every block that asked for
 * that size on purpose.
 */
@media (max-width: 480px) {
	body {
		font-size: 1rem;
	}
}

/*
 * Text rendering, not typography — theme.json has no key for either of these.
 *
 * Without them macOS falls back to subpixel antialiasing, which thickens every
 * glyph: side by side against the reference each weight reads a step heavier
 * even though font-family, weight and size are identical. The reference sets
 * both on `body`, so the theme matches it there.
 */
body {
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
	text-rendering: optimizeLegibility;
}

/*
 * The page is a stack of full-bleed bands that meet edge to edge. The root
 * block gap would open a strip of page background at every seam — under the
 * header and above the footer — so it is cleared on the two template-level
 * siblings. Gaps inside the content are untouched.
 */
.wp-site-blocks > main,
.wp-site-blocks > footer {
	margin-block-start: 0;
}

/* ============================================================
   HEADER
   The .site-header class is applied to the template-part wrapper in each
   template, not inside parts/header.html: position:sticky needs the outermost
   element, otherwise its containing block is exactly its own height and it
   never sticks.
   ============================================================ */

.site-header {
	position: sticky;
	top: 0;
	z-index: 100;
	background-color: color-mix(in srgb, var(--wp--preset--color--base) 72%, transparent);
	backdrop-filter: saturate(160%) blur(16px);
	-webkit-backdrop-filter: saturate(160%) blur(16px);
	border-bottom: 1px solid color-mix(in srgb, var(--wp--preset--color--navy) 7%, transparent);
}

/* `backdrop-filter` makes this element the containing block for every descendant
   that is `position: fixed`, and the mobile navigation overlay is one. Left on,
   the overlay resolves against the header instead of the viewport and opens as a
   92px strip with the menu spilling out of it rather than as a full-screen sheet.
   The blur has nothing to do while a full-screen menu covers the page, so it is
   dropped for as long as the menu is open — core puts `has-modal-open` on the
   `<html>` element for exactly that window. */
.has-modal-open .site-header {
	backdrop-filter: none;
	-webkit-backdrop-filter: none;
}

.site-header .header-inner {
	min-height: var(--aac--header-height);
}

.site-header .wp-block-site-logo img {
	height: var(--aac--logo-height);
	width: auto;
	max-width: none;
}

/* Condense on scroll. Scroll-driven animations degrade to the un-condensed
   header where unsupported, which is purely cosmetic. */
@supports (animation-timeline: scroll()) {
	@media (prefers-reduced-motion: no-preference) {
		.site-header,
		.site-header .header-inner,
		.site-header .wp-block-site-logo img {
			/* Progress-based timelines need `auto`; a time-based duration leaves
			   the animation's currentTime null and nothing ever applies. */
			animation-duration: auto;
			animation-fill-mode: both;
			animation-timing-function: linear;
			animation-timeline: scroll(root block);
			animation-range: 0 120px;
		}

		.site-header {
			animation-name: aac-header-settle;
		}

		.site-header .header-inner {
			animation-name: aac-header-condense;
		}

		.site-header .wp-block-site-logo img {
			animation-name: aac-logo-condense;
		}
	}
}

@keyframes aac-header-settle {
	to {
		background-color: color-mix(in srgb, var(--wp--preset--color--base) 90%, transparent);
		border-bottom-color: transparent;
		box-shadow: 0 10px 30px -20px color-mix(in srgb, var(--wp--preset--color--navy) 40%, transparent);
	}
}

@keyframes aac-header-condense {
	to {
		min-height: var(--aac--header-height-condensed);
	}
}

@keyframes aac-logo-condense {
	to {
		height: var(--aac--logo-height-condensed);
	}
}

/* ---------- Header navigation ---------- */

.site-header .wp-block-navigation-item__content {
	position: relative;
	display: inline-block;
	padding-block: 0.5rem;
	/* Colour is set on the nav container in theme.json, not here: core ships
	   `.wp-block-navigation-item__content.wp-block-navigation-item__content
	   {color:inherit}` — a doubled class the item can only inherit past. */
	text-decoration: none;
	transition: opacity 0.2s var(--aac--ease);
}

.site-header .wp-block-navigation-item__content::after {
	content: "";
	position: absolute;
	inset-inline-start: 0;
	bottom: 0;
	width: 0;
	height: 2px;
	background-color: currentColor;
	transition: width 0.28s var(--aac--ease);
}

.site-header .wp-block-navigation-item__content:hover {
	opacity: 0.62;
}

.site-header .wp-block-navigation-item__content:hover::after,
.site-header .current-menu-item .wp-block-navigation-item__content::after {
	width: 100%;
}

.site-header .wp-block-navigation-item__content:focus-visible {
	outline: 2px solid var(--wp--preset--color--navy-ink);
	outline-offset: 4px;
	opacity: 1;
}

.site-header .wp-block-navigation__responsive-container-open,
.site-header .wp-block-navigation__responsive-container-close {
	color: var(--wp--preset--color--navy-ink);
}

/* ============================================================
   MOBILE NAVIGATION OVERLAY
   Core opens a full-screen sheet with the items hard against the right edge.
   With five links that sheet is almost entirely empty, so below the mobile line
   it becomes a panel that drops from the top and sizes to its content.
   ============================================================ */

/* Home is a mobile-only entry. The reference header carries four links and lets
   the logo be the way back, which works while the logo is full size; in the
   overlay there is no logo on screen, so the link earns its place there. */
@media (min-width: 782px) {
	.site-header .wp-block-home-link {
		display: none;
	}
}

@media (max-width: 781px) {
	/* Starts at the very top rather than under the header so the close button
	   lands where the hamburger was, instead of costing a row of its own. */
	.site-header .wp-block-navigation__responsive-container.is-menu-open {
		/* Core drives the overlay's alignment through these two properties rather
		   than through `align-items` directly, so setting them is what makes the
		   rows fill the panel — fighting the declaration instead only escalates a
		   specificity war with core's own stylesheet. Full-width rows are what let
		   the dividers run the whole panel and the whole row stay tappable. */
		--navigation-layout-justification-setting: stretch;
		--navigation-layout-align: stretch;

		inset: 0 0 auto 0;
		height: auto;
		padding: 0;
		background-color: var(--wp--preset--color--base);
		border-block-end: 1px solid var(--wp--preset--color--line);
		box-shadow: 0 24px 48px -32px color-mix(in srgb, var(--wp--preset--color--navy) 55%, transparent);
	}

	/*
	 * Every rule below repeats `.wp-block-navigation__responsive-container` next to
	 * `.is-menu-open` on purpose. Core's overlay styles are written as
	 * `.wp-block-navigation__responsive-container.is-menu-open:where(…) .target`,
	 * which scores the same three classes a shorter selector here would, and core's
	 * stylesheet loads after the theme's — so a tie goes to core and the rule
	 * silently does nothing. The extra class breaks the tie.
	 */

	/* Clears the close-button row above the first link. */
	.site-header .wp-block-navigation__responsive-container.is-menu-open
		.wp-block-navigation__responsive-container-content {
		width: 100%;
		padding: var(--aac--header-height) 0 0;
	}

	.site-header .wp-block-navigation__responsive-container.is-menu-open
		.wp-block-navigation__container {
		align-items: stretch;
		gap: 0;
	}

	/* Hairline rules between rows, the same divider the contact blocks use. */
	.site-header .wp-block-navigation__responsive-container.is-menu-open
		.wp-block-navigation-item + .wp-block-navigation-item {
		border-block-start: 1px solid var(--wp--preset--color--line);
	}

	/* The inset sits on the link rather than the row, so the whole width of the
	   row stays tappable while the label still keeps the site's gutter. */
	.site-header .wp-block-navigation__responsive-container.is-menu-open
		.wp-block-navigation-item__content {
		display: block;
		padding-block: 1.0625rem;
		padding-inline: var(--wp--style--root--padding-left);
	}

	/* The sliding underline is a horizontal-nav gesture; stacked, the hairlines
	   already separate the rows and it only adds noise. */
	.site-header .wp-block-navigation__responsive-container.is-menu-open
		.wp-block-navigation-item__content::after {
		display: none;
	}

	.site-header .wp-block-navigation__responsive-container.is-menu-open
		.current-menu-item .wp-block-navigation-item__content {
		color: var(--wp--preset--color--navy);
	}

	/* Centred on the header's own height so it replaces the hamburger in place. */
	.site-header .wp-block-navigation__responsive-container-close {
		top: calc((var(--aac--header-height) - 1.5rem) / 2);
		right: var(--wp--style--root--padding-right);
	}
}

/* A fragment link scrolls its target to the very top of the viewport, which the
   sticky header then covers. Every anchored section gets cleared by the header's
   condensed height — by the time a link like #andrea-carlo-sala has scrolled,
   the header has already condensed. */
.wp-site-blocks section[id] {
	scroll-margin-block-start: calc(var(--aac--header-height-condensed) + 0.5rem);
}

/* ============================================================
   FOOTER
   ============================================================ */

/*
 * Footer body copy sits between preset steps in the reference (14.5px / 12.5px),
 * so these blocks carry no font-size preset — the preset class would win on
 * `!important` — and the exact value is set here instead.
 */

.site-footer .footer-logo {
	margin: 0;
}

.site-footer .footer-logo img {
	height: var(--aac--footer-logo-height);
	width: auto;
	max-width: 100%;
	display: block;
}

/* The footer column headings are `h4`s in the reference, not the section
   eyebrow: tighter tracking, a smaller gap beneath, and heading leading rather
   than the eyebrow's flat line-height of 1. */
.site-footer .is-style-eyebrow {
	line-height: 1.16;
	letter-spacing: 0.16em;
	margin-block-end: 1.25rem;
}

.site-footer .footer-brand__desc {
	margin-block-start: 1.375rem;
	max-width: 34ch;
	font-size: 0.90625rem;
	line-height: 1.7;
	color: color-mix(in srgb, var(--wp--preset--color--base) 60%, transparent);
}

.site-footer .footer-col__links {
	list-style: none;
	padding-inline-start: 0;
	display: grid;
	gap: 0.75rem;
	font-size: 0.90625rem;
}

.site-footer .footer-col__address {
	font-size: 0.90625rem;
	line-height: 1.8;
	color: color-mix(in srgb, var(--wp--preset--color--base) 72%, transparent);
}

/* Links in list and standalone contexts drop the underline; the inline links in
   the bottom bar keep theirs, so they are not distinguished by colour alone. */
.site-footer .footer-col__links a,
.site-footer .footer-col__address a {
	color: color-mix(in srgb, var(--wp--preset--color--base) 72%, transparent);
	text-decoration: none;
}

.site-footer .footer-col__links a:hover,
.site-footer .footer-col__address a:hover {
	color: var(--wp--preset--color--base);
	text-decoration: underline;
}

.site-footer .footer-bottom {
	border-block-start: 1px solid color-mix(in srgb, var(--wp--preset--color--base) 12%, transparent);
	font-size: 0.78125rem;
	color: color-mix(in srgb, var(--wp--preset--color--base) 50%, transparent);
}

.site-footer .footer-bottom a {
	color: inherit;
	text-decoration: underline;
}

.site-footer .footer-bottom a:hover {
	color: var(--wp--preset--color--base);
}

.site-footer a:focus-visible {
	outline: 2px solid var(--wp--preset--color--sky);
	outline-offset: 3px;
}

/* ============================================================
   PAGE HERO
   Dark banner at the top of every interior page. The base gradient is the
   `hero-navy` preset applied through the block's gradient support; only the
   decoration and the measure constraints live here.
   ============================================================ */

.page-hero {
	position: relative;
	overflow: hidden;
}

/* Two stacked washes — a sky bloom off the top-right corner and a vertical
   hairline rhythm. Background supports take a single image, so this cannot be
   expressed on the block itself. */
.page-hero::before {
	content: "";
	position: absolute;
	inset: 0;
	pointer-events: none;
	background-image:
		radial-gradient(
			110% 90% at 88% 0%,
			color-mix(in srgb, var(--wp--preset--color--sky) 26%, transparent),
			transparent 58%
		),
		repeating-linear-gradient(
			90deg,
			color-mix(in srgb, var(--wp--preset--color--base) 3%, transparent) 0 1px,
			transparent 1px 5.5rem
		);
}

.page-hero > * {
	position: relative;
}

/* The reference spaces the three lines with 26px and 24px bottom margins, which a
   single blockGap cannot express — so the group sets blockGap to 0 and the margins
   live here, as with `.sec-head`. Both are fixed in the reference, so `rem` rather
   than `em`: the title's own font size swings 38→72px. */
.page-hero__breadcrumb {
	margin-bottom: 1.625rem;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: color-mix(in srgb, var(--wp--preset--color--base) 50%, transparent);
}

/* The reference spaces the trail with `display:flex; gap:10px`. Here the gap is
   carried by the separator's own margins instead, so the rule stays inert for a
   breadcrumb written without a `.sep` — flex would silently re-space those too. */
.page-hero__breadcrumb .sep {
	margin-inline: 0.625rem;
	opacity: 0.5;
}

/* No resting underline — the trail's position and separators carry the
   affordance — but hover and focus both get one, so the state change is never
   colour alone. */
.page-hero__breadcrumb a {
	color: color-mix(in srgb, var(--wp--preset--color--base) 70%, transparent);
	text-decoration: none;
}

.page-hero__breadcrumb a:hover {
	color: var(--wp--preset--color--base);
	text-decoration: underline;
	text-underline-offset: 0.25em;
}

.page-hero__breadcrumb a:focus-visible {
	color: var(--wp--preset--color--base);
	text-decoration: underline;
	outline: 2px solid var(--wp--preset--color--sky);
	outline-offset: 4px;
}

/* 38→72px in the reference, which overshoots the xxx-large step (36→66px). The
   blocks carry no `fontSize` attribute so the preset class cannot win here on
   `!important`. */
/* Doubled up so the bottom margin survives being the last child, which core's
   `:root :where(.is-layout-flow) > :last-child` would otherwise zero. The
   policy heroes have no lede under the title, and the reference keeps the 24px
   inside the padded band there. */
.page-hero .page-hero__title {
	margin-bottom: 1.5rem;
	max-width: 15ch;
	font-size: clamp(2.375rem, 6vw, 4.5rem);
	line-height: 1.06;
}

.page-hero__lede {
	max-width: 56ch;
	line-height: 1.6;
	color: color-mix(in srgb, var(--wp--preset--color--base) 82%, transparent);
}

/* ============================================================
   SECTION HEAD
   Eyebrow, title and standfirst opening a section. Both sizes fall between
   preset steps, so these blocks carry no font-size preset — the preset class
   would win on `!important` — and the exact values are set here.

   The blocks that use this component set blockGap to 0: the reference spaces
   them with the elements' own bottom margins, which collapse against the
   following block instead of stacking with a layout gap.
   ============================================================ */

/* The reference keeps section heads flush with the container's leading edge and
   centres only `.center-head`, a separate component. Capping the head element
   itself cannot reproduce that: core's constrained layout stamps
   `margin-inline: auto !important` on every child, which no selector outranks,
   and zeroing the margins would pull the head off the wide column onto the root
   padding edge. So the head keeps its full column width and the reference's
   measure is applied to its children, which sit in a flow layout core leaves
   alone. */
.wp-block-group.sec-head {
	margin-block-end: clamp(2.25rem, 5vw, 3.625rem);
}

.sec-head__title {
	max-width: 40rem;
	margin-block-end: 1.125rem;
	font-size: clamp(1.375rem, 2.6vw, 2rem);
	line-height: 1.14;
}

.sec-head__text {
	max-width: 40rem;
	margin: 0;
}

/* ============================================================
   APPROACH
   Three principles under a section head, each opened by a navy rule.
   ============================================================ */

/* The reference runs this head at the service-heading size rather than the
   smaller section-head default. */
.approach .sec-head__title {
	font-size: clamp(1.6875rem, 3.4vw, 2.5rem);
	color: var(--wp--preset--color--navy);
}

/* Doubled class: the grid layout's own container rule carries a single class,
   so gap and columns have to outweigh it. */
.wp-block-group.approach__grid {
	gap: 1.75rem;
	margin-block-start: clamp(1.875rem, 4vw, 3rem);
}

.approach__item {
	padding-block-start: 1.375rem;
	border-block-start: 2px solid var(--wp--preset--color--navy);
}

/* Transcribed from a `<b>` in the reference, so it keeps that weight and the
   body line-height rather than the heading defaults — but it is marked up as a
   heading, because that is what it is. */
.approach__title {
	margin-block-end: 0.75rem;
	font-size: 1.25rem;
	font-weight: 700;
	line-height: 1.65;
	letter-spacing: normal;
	color: var(--wp--preset--color--navy);
}

.approach__text {
	margin: 0;
	font-size: 0.9375rem;
	line-height: 1.6;
}

/* Grid layout has no built-in stacking point — core's 782px only applies to
   Columns — and the collapsed state changes the rules as well as the count, so
   it needs a query either way.

   Stacked, every principle keeps its own navy rule rather than the reference's
   hairline-between-items list, and the rule runs three quarters of the width. A
   deliberate departure: the reference gives the navy rule to the first item only
   and separates the rest with `1px var(--line)`.

   It is a pseudo-element and not `border-block-start` because a border always
   spans the full box and there is nothing to shorten it with. */
@media (max-width: 960px) {
	.wp-block-group.approach__grid {
		grid-template-columns: 1fr;
		gap: 0;
	}

	.approach__item {
		position: relative;
		padding-block: 1.375rem;
		border-block-start: 0;
	}

	.approach__item::before {
		content: "";
		position: absolute;
		inset-block-start: 0;
		inset-inline-start: 0;
		width: 75%;
		height: 2px;
		background-color: var(--wp--preset--color--navy);
	}
}

/* ============================================================
   SERVICE DETAIL
   Numbered service row: copy on one side, photograph on the other, closed by a
   hairline. Three of these stack on the Expertise page, all with the image on
   the same side — the reference carries an alternation rule but it resolves to
   a no-op, so the rendered page does not alternate.
   ============================================================ */

.svc-detail {
	border-block-end: 1px solid var(--wp--preset--color--line);
}

/* Doubled class: the grid layout's own container rule carries a single class,
   so gap and columns have to outweigh it. */
.wp-block-group.svc-detail__grid {
	gap: clamp(2.5rem, 6vw, 5.25rem);
	align-items: center;
}

.svc-detail__no {
	margin-block-end: 1.125rem;
	font-size: 0.9375rem;
	font-weight: 700;
	letter-spacing: 0.1em;
	color: var(--wp--preset--color--sky);
}

.svc-detail__title {
	margin-block-end: 1.375rem;
	font-size: clamp(1.6875rem, 3.4vw, 2.5rem);
	line-height: 1.14;
	color: var(--wp--preset--color--navy);
}

.svc-detail__text {
	margin-block-end: 1.75rem;
	font-size: 1.03125rem;
}

.svc-detail__label {
	margin-block-end: 1rem;
	font-weight: 700;
	letter-spacing: 0.16em;
	text-transform: uppercase;
}

.svc-list {
	display: grid;
	gap: 0.75rem;
	margin: 0;
	padding-inline-start: 0;
	list-style: none;
	font-size: 0.96875rem;
	line-height: 1.5;
}

.svc-list li {
	position: relative;
	padding-inline-start: 1.625rem;
}

/* An open ring rather than a filled dot: the list markup already carries the
   list semantics, so the marker is free to be brand detail. */
.svc-list li::before {
	content: "";
	position: absolute;
	inset-block-start: 0.4375rem;
	inset-inline-start: 0;
	width: 0.5625rem;
	height: 0.5625rem;
	border: 1.5px solid var(--wp--preset--color--sky);
	border-radius: 50%;
}

/* Element + class: core's `.wp-block-image img { height: auto }` matches on one
   class, and the image has to fill the fixed ratio instead. */
figure.svc-detail__media {
	position: relative;
	margin: 0;
	aspect-ratio: 4 / 3;
	overflow: hidden;
	border-radius: 2px;
}

figure.svc-detail__media img {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* Tonal weighting toward the bottom of the frame — no text sits over it. */
figure.svc-detail__media::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 1;
	background: linear-gradient(
		200deg,
		transparent 40%,
		color-mix(in srgb, var(--wp--preset--color--navy-night) 34%, transparent) 100%
	);
}

/* Same stacking point as the approach grid, and well before the copy column
   would get too narrow to read. The photograph goes wide once it is on its own
   row, so it does not eat a screen height. */
@media (max-width: 960px) {
	.wp-block-group.svc-detail__grid {
		grid-template-columns: 1fr;
		gap: 2.25rem;
	}

	figure.svc-detail__media {
		aspect-ratio: 16 / 9;
	}
}

/* ============================================================
   CONTACT BAND
   Photograph under a navy scrim, centred call to action. Closes most pages of
   the site; only the heading changes between them.
   ============================================================ */

.imgband {
	position: relative;
	overflow: hidden;
	/* The photograph is a block background from the Media Library. This fill keeps
	   the white copy legible if the attachment is missing, since the ::before
	   overlay below is only partly opaque. */
	background-color: var(--wp--preset--color--navy-night);
	/* Deeper than any step on the spacing scale, and the same clamp on every
	   page, so it is set here rather than added as a one-use preset. */
	padding-block: clamp(5.25rem, 11vw, 9.375rem);
	text-align: center;
}

/* Two classes to clear the `max-width: contentSize` core's constrained layout
   puts on a plain child — the photograph has to fill the band, not sit in the
   text column. Margins are core's `!important` ones but harmless here: `inset`
   governs an absolutely positioned box. */
.imgband .imgband__bg {
	position: absolute;
	inset: 0;
	z-index: 0;
	max-width: none;
	margin: 0;
}

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

/* The wash sits on the photograph rather than the band, so it darkens the image
   without touching the navy fill underneath. */
.imgband__bg::after {
	content: "";
	position: absolute;
	inset: 0;
	background: linear-gradient(
		180deg,
		color-mix(in srgb, var(--wp--preset--color--navy-night) 72%, transparent),
		color-mix(in srgb, var(--wp--preset--color--navy-night) 82%, transparent)
	);
}

.imgband > * {
	position: relative;
}

.imgband__title {
	max-width: 18ch;
	margin-inline: auto;
	margin-block-end: 1.375rem;
	font-size: clamp(1.875rem, 4.6vw, 3.625rem);
	line-height: 1.08;
}

.imgband__text {
	max-width: 52ch;
	margin-inline: auto;
	margin-block-end: 2.5rem;
	color: color-mix(in srgb, var(--wp--preset--color--base) 82%, transparent);
}

/* Dark instance of the arrow button: swapping the colours the component names
   is the whole change. */
.imgband .is-style-arrow .wp-block-button__link {
	--aac--arrow-ink: var(--wp--preset--color--base);
	--aac--arrow-void: var(--wp--preset--color--navy);
	--aac--arrow-ring-line: color-mix(in srgb, var(--wp--preset--color--base) 60%, transparent);
}

/* ============================================================
   BLOCK STYLES
   ============================================================ */

.is-style-eyebrow {
	margin-block: 0 1.75rem;
	font-weight: 600;
	line-height: 1;
	letter-spacing: 0.2em;
	text-transform: uppercase;
	color: var(--wp--preset--color--signal);
}

/* ---------- Button: arrow ----------
   Strips the solid fill back to a label plus an outlined ring holding an arrow.
   The two colours are named once as custom properties, so a dark-section
   instance only has to swap them rather than restate the whole treatment.

   The arrow is a masked shape on a second pseudo-element rather than a "→"
   character: generated text can reach the accessibility tree, and the label
   already says where the link goes. It cannot share the ring's element — a
   mask clips the border along with the background. */

.is-style-arrow .wp-block-button__link {
	--aac--arrow-ink: var(--wp--preset--color--navy);
	--aac--arrow-void: var(--wp--preset--color--base);
	/* Its own property because the dark instance holds the ring back to 60%
	   rather than matching the label. */
	--aac--arrow-ring-line: var(--aac--arrow-ink);
	--aac--arrow-ring: 3.375rem;
	--aac--arrow-glyph: 1.125rem;

	position: relative;
	display: inline-flex;
	align-items: center;
	gap: 1rem;
	padding: 0;
	border: 0;
	background: none;
	/* 12.5px in the reference — between the x-small and small preset steps, so
	   it is set here rather than snapped to either. The button element's
	   line-height of 1 is for the solid variant; this one keeps body leading. */
	font-size: 0.78125rem;
	line-height: 1.65;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--aac--arrow-ink);
}

.is-style-arrow .wp-block-button__link::after {
	content: "";
	/* The reference's ring is 54px including its border, under a global
	   border-box reset WordPress does not ship. Without this the ring — and so
	   the whole button — comes out 2px taller everywhere it appears. */
	box-sizing: border-box;
	flex: 0 0 auto;
	width: var(--aac--arrow-ring);
	height: var(--aac--arrow-ring);
	border: 1px solid var(--aac--arrow-ring-line);
	border-radius: 50%;
	transition: background-color 0.3s var(--aac--ease);
}

.is-style-arrow .wp-block-button__link::before {
	content: "";
	position: absolute;
	z-index: 1;
	inset-block-start: 50%;
	inset-inline-end: calc((var(--aac--arrow-ring) - var(--aac--arrow-glyph)) / 2);
	width: var(--aac--arrow-glyph);
	height: var(--aac--arrow-glyph);
	transform: translateY(-50%);
	background-color: var(--aac--arrow-ink);
	transition: background-color 0.3s var(--aac--ease);
	mask: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 12h16M13 6l6 6-6 6" fill="none" stroke="black" stroke-width="1.5"/></svg>') no-repeat center / contain;
	-webkit-mask: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 12h16M13 6l6 6-6 6" fill="none" stroke="black" stroke-width="1.5"/></svg>') no-repeat center / contain;
}

/* The ring fills and the arrow inverts; the label is left alone, so the change
   is a shape inversion rather than a colour shift on text. */
.is-style-arrow .wp-block-button__link:hover {
	background: none;
	color: var(--aac--arrow-ink);
}

.is-style-arrow .wp-block-button__link:hover::after {
	background-color: var(--aac--arrow-ink);
}

.is-style-arrow .wp-block-button__link:hover::before {
	background-color: var(--aac--arrow-void);
}

.is-style-arrow .wp-block-button__link:focus-visible {
	outline: 2px solid var(--aac--arrow-ink);
	outline-offset: 6px;
}

/* ============================================================
   HOME HERO — L-shape
   Text column and brand lockup on the left, full-height photograph on the
   right; white rules trace the inner corner of the L. Column widths come from
   the block, so only the parts the block cannot express live here.
   ============================================================ */

.hero-l {
	--hero-l-split: 54%;
	--hero-l-rule: max(3px, 0.285vw);
	position: relative;
	isolation: isolate;
	overflow: hidden;
	min-height: calc(100svh - var(--aac--header-height));
	container-type: inline-size;
}

/* Vertical rule on the column split. Absolute positioning keeps it out of the
   columns flex flow, so it is not treated as a fourth column. */
.hero-l::before {
	content: "";
	position: absolute;
	z-index: 5;
	inset-block: 0;
	inset-inline-start: var(--hero-l-split);
	width: var(--hero-l-rule);
	transform: translateX(-50%);
	background-color: var(--wp--preset--color--base);
	pointer-events: none;
}

.hero-l > .wp-block-column {
	display: flex;
	flex-direction: column;
	justify-content: center;
}

/* Both sizes are the reference's own hero-L overrides, not the base hero scale,
   and neither lands on a preset step — so these blocks carry no `fontSize`. */
.hero-l__title {
	font-size: clamp(2rem, 4vw, 3.5rem);
	line-height: 1.05;
	letter-spacing: -0.015em;
	margin-block-end: 1.25rem;
}

.hero-l__lede {
	font-size: clamp(1.0625rem, 1.5vw, 1.25rem);
	line-height: 1.6;
	margin-block-end: 1.75rem;
}

/* The hero bleeds full width, so the copy has to find the container edge on its
   own: whichever is further in, the root gutter or the wide container's left
   edge. That is the same line the header logo sits on.

   `100vw` counts the scrollbar and the container does not, so this lands ~7px
   further in than the header logo. That gap is in the reference too — its hero
   copy and panel lockup both sit on this line while the header sits on the
   container's — and it is reproduced rather than corrected. */
.hero-l__text {
	padding-block: clamp(1.5rem, 4.4vh, 3.75rem);
	padding-inline: max(
			var(--wp--style--root--padding-left),
			calc((100vw - var(--wp--style--global--wide-size)) / 2)
		)
		var(--wp--preset--spacing--40);
}

.hero-l__panel,
.hero-l__photo {
	position: relative;
	margin-block: 0;
}

/* The photograph is sized by the layout, never by its own dimensions — taking it
   out of flow is what stops its intrinsic height from becoming the flex base and
   pushing the hero past one screen. */
.hero-l__photo img {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* The foot of the L: a navy panel carrying the brand backdrop, with the white
   lockup centred on it. It takes whatever height the copy leaves. */
/* Alignment comes from the block's own flex layout, not from here, so it stays
   visible and editable in the editor. */
.hero-l__panel {
	flex: 1 1 0;
	min-height: clamp(12.5rem, 28vh, 21.25rem);
	/* No `overflow: hidden` here on purpose: the horizontal rule below is this
	   element's ::before and has to run on past the panel's right edge, across
	   the photograph, to close the corner of the L. The backdrop below is inset
	   to this box and cannot spill either, so nothing needs clipping. */
	/* The photograph is an image block from the Media Library, laid in behind the
	   lockup by `.hero-l__panel-bg` — no media is served from the theme. This
	   colour is the fill it sits on, and the fallback if it goes missing. */
	background-color: var(--wp--preset--color--navy-panel);
	/* Left padding puts the lockup on the same gutter as the copy above it, so
	   the two stay aligned at every width. */
	padding-block: 1.5rem;
	padding-inline: max(
			var(--wp--style--root--padding-left),
			calc((100vw - var(--wp--style--global--wide-size)) / 2)
		)
		1.5rem;
}

/* Out of flow, so the panel's flex layout still sees only the lockup. */
.hero-l__panel-bg {
	position: absolute;
	inset: 0;
	z-index: 0;
	margin: 0;
	max-width: none;
}

.hero-l__panel-bg img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.hero-l__lockup {
	position: relative;
	z-index: 3;
	margin: 0;
	max-width: min(64%, 28.75rem);
}

.hero-l__lockup img {
	width: 100%;
	height: auto;
	display: block;
}

/* Horizontal rule along the top edge of the panel, running on across the
   photograph to close the corner. */
.hero-l__panel::before {
	content: "";
	position: absolute;
	z-index: 5;
	inset-block-start: 0;
	inset-inline-start: 0;
	width: 100cqw;
	height: var(--hero-l-rule);
	background-color: var(--wp--preset--color--base);
	pointer-events: none;
}

.hero-l__photo {
	flex: 1 1 auto;
	overflow: hidden;
}

/* The photograph is a backdrop, not a subject: desaturated here and veiled
   below, so the heading holds contrast against it. The lockup is brand artwork
   and is left untouched.

   The building's peak sits about 44% from the left of the source frame; the
   zoom and shift re-centre it in a column narrower than the photograph. */
.hero-l__photo img {
	filter: saturate(0.38) brightness(1.1) contrast(0.85);
	transform: scale(1.16) translate(6.9%, 7%);
}

.hero-l__photo::after {
	content: "";
	position: absolute;
	inset: 0;
	background-color: var(--aac--hero-veil);
	pointer-events: none;
}

/* 781px is where core stacks the Columns block. Below it the L no longer
   exists, so the rules that trace it are removed rather than left floating. */
@media (max-width: 781px) {
	.hero-l {
		min-height: 0;
	}

	.hero-l::before,
	.hero-l__panel::before {
		display: none;
	}

	/* Leads with the photograph on small screens, as the reference does. The
	   image is not focusable, so visual order and tab order stay in step. */
	.hero-l__media {
		order: -1;
	}

	.hero-l__panel,
	.hero-l__photo {
		height: 52vw;
		min-height: 0;
		flex: 0 0 auto;
	}

	/* The peak sits about 44% from the left of the source frame, and the frame is
	   far taller than this band: under `cover` the width fits exactly, so the crop
	   is vertical only and `object-position` has no horizontal play to give. The
	   small scale creates that play — 7% spare on each side — and the shift then
	   brings the peak onto the centre line. Vertical framing is left alone; the
	   desktop rule's downward nudge would push the peak out of a band this shallow. */
	.hero-l__photo img {
		transform: scale(1.14) translateX(5.2%);
	}

	/* On desktop the panel's left padding puts the lockup on the copy's gutter.
	   Stacked there is no copy beside it to align to, so it centres on the panel
	   instead. Doubled with the block class to outrank the flex layout rule core
	   prints for the group's own container class. */
	.wp-block-group.hero-l__panel {
		justify-content: center;
		padding-inline: 1.5rem;
	}

	.hero-l__lockup {
		max-width: min(72%, 17.5rem);
	}
}

/* ============================================================
   HOME — CONVICTION / THREE PILLARS
   Section intro over three alternating image / text rows.

   Every type size in this section falls between preset steps in the reference
   (34px / 16.5px / 23px), so these blocks carry no `fontSize` attribute — a
   preset class would win on `!important` — and the exact values are set here.
   ============================================================ */

.conviction__lead {
	margin-block: 0 1.5rem;
	font-size: clamp(1.4375rem, 2.6vw, 2.125rem);
	font-weight: 400;
	line-height: 1.28;
}

/* The highlighted clause is a colour + weight shift, not stress emphasis, so it
   is core's inline-colour format rather than an <em>. */
.conviction__lead mark {
	font-weight: 500;
}

.conviction__text {
	margin-block: 0;
	max-width: 44ch;
	font-size: 1.03125rem;
	line-height: 1.7;
}

.conv-rows {
	margin-block-start: clamp(2.75rem, 5.5vw, 4.5rem);
}

.conv-rows > .conv-row + .conv-row {
	margin-block-start: clamp(2.25rem, 5vw, 4.5rem);
}

/* Doubled-up selector so it outranks the grid rules core prints for the block's
   own container class. */
.conv-row.conv-row {
	grid-template-columns: repeat(2, minmax(0, 1fr));
	align-items: center;
	column-gap: clamp(2rem, 5vw, 4.5rem);
}

/*
 * No fill behind these frames. Each one IS the image block — `media_image()`
 * emits nothing at all when an attachment is missing, so the figure would not
 * exist to show a fallback. All a fill can do is show: the frames size to a
 * fractional height, and the photograph leaves a sliver of whatever is painted
 * behind it uncovered along the edges, drawn as a hairline around the picture.
 */
.conv-row__media {
	aspect-ratio: 4 / 3;
	overflow: hidden;
	border-radius: 2px;
}

.conv-row__media img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: transform 0.8s var(--aac--ease);
}

.conv-row:hover .conv-row__media img {
	transform: scale(1.04);
}

.conv-row__title {
	position: relative;
	margin-block: 0 1.125rem;
	padding-block-start: 1.375rem;
	font-size: clamp(1.4375rem, 2.8vw, 2.125rem);
}

/* Short rule above each pillar title; it lengthens on row hover. Decorative
   only — the title carries the meaning either way. */
.conv-row__title::before {
	content: "";
	position: absolute;
	inset-block-start: 0;
	inset-inline-start: 0;
	width: 2.125rem;
	height: 2px;
	background-color: var(--wp--preset--color--sky);
	transition: width 0.4s var(--aac--ease);
}

.conv-row:hover .conv-row__title::before {
	width: 3.25rem;
}

.conv-row__body p {
	margin-block: 0;
	max-width: 44ch;
	font-size: clamp(0.9375rem, 1.5vw, 1.03125rem);
	line-height: 1.7;
}

/*
 * A Grid layout rather than Columns: the reference stacks these rows at 820px
 * and Columns only knows core's fixed 782px point — and opting out of that with
 * `isStackedOnMobile: false` buys a `flex-wrap: nowrap !important` that can only
 * be beaten with another `!important`.
 *
 * Media comes first in the markup, so on wide screens the even rows swap sides
 * to alternate. Once stacked the order is reversed instead: every row leads with
 * its title and copy, and the photograph follows.
 */
@media (min-width: 821px) {
	.conv-row:nth-child(even) > .conv-row__media {
		order: 2;
	}
}

@media (max-width: 820px) {
	.conv-row.conv-row {
		grid-template-columns: minmax(0, 1fr);
		row-gap: 1.5rem;
	}

	/* Text before image on every stacked row. Ordering the body rather than the
	   media keeps it independent of the odd/even swap above, which no longer
	   applies at this width. */
	.conv-row__body {
		order: -1;
	}

	.conv-row__media {
		aspect-ratio: 16 / 10;
	}
}

/* ============================================================
   ABOUT — BODY
   Eyebrow, heading and a stretching photograph on the left; three paragraphs
   on the right, the first of them a lede.

   The reference type sizes here (38px / 21px / 16.5px) all fall between preset
   steps, so these blocks carry no `fontSize` attribute — a preset class would
   win on `!important` — and the exact values are set below.
   ============================================================ */

.about-body__grid {
	column-gap: clamp(2.5rem, 7vw, 5.625rem);
}

/* A flex context so the photograph can claim the leftover height; a block
   layout has no way to hand a child `flex: 1 1 0`. */
.about-body__left {
	display: flex;
	flex-direction: column;
}

.about-body__title {
	margin-block: 0;
	font-size: clamp(1.625rem, 3.2vw, 2.375rem);
}

/* `min-height: 0` is what lets the figure actually shrink: a flex item's
   automatic minimum size is its content, which here is a 1700px-wide image. */
.about-body__media {
	position: relative;
	flex: 1 1 0;
	min-height: 0;
	margin-block: clamp(1.75rem, 3.4vw, 2.75rem) 0;
	overflow: hidden;
	border-radius: 2px;
}

.about-body__media img {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	filter: grayscale(1) contrast(1.02);
}

.about-body__text p {
	margin-block: 0 1.375rem;
	font-size: 1.03125rem;
	line-height: 1.7;
}

/* Two classes, so this beats `.about-body__text p` on specificity rather than
   on source order. */
.about-body__text .about-body__lede {
	font-size: clamp(1.125rem, 2vw, 1.3125rem);
	line-height: 1.55;
}

.about-body__text strong {
	font-weight: 600;
	color: var(--wp--preset--color--contrast);
}

/* The reference stacks this grid at 900px; core stacks the Columns block at
   782px and that point is not configurable, so the stacked rules key off core's
   breakpoint instead. */
/* Stacked, the photograph closes the section instead of interrupting the
   heading and the copy it belongs to — a deliberate departure from the
   reference, which leaves it above the text.

   `display: contents` on the left column is what makes it possible: the image
   lives inside that column so that it can stretch under the title on desktop,
   and a nested item cannot be ordered past its parent's sibling. Dropping the
   column's own box lifts its three children into the grid's flow, where `order`
   can reach the image. */
@media (max-width: 781px) {
	.about-body__grid {
		display: flex;
		flex-direction: column;
		/* Core leaves the Columns block wrapping for its own stacking; in a
		   column direction that would let the stack break into a second column
		   the moment anything constrains its height. */
		flex-wrap: nowrap;
		row-gap: 1.75rem;
	}

	.about-body__left {
		display: contents;
	}

	.about-body__text {
		order: 1;
		padding-block-start: 0;
	}

	/* `width: 100%` rather than leaving it to `align-items: stretch`: a stretched
	   cross size is resolved after the main size, so `aspect-ratio` has no width
	   to work from and the figure collapses to the zero height of its absolutely
	   positioned image. An explicit width is definite, and the ratio resolves. */
	.about-body__media {
		order: 2;
		flex: none;
		width: 100%;
		aspect-ratio: 3 / 4;
		margin-block-start: 1.5rem;
	}
}

/* ============================================================
   KEY FIGURES
   Shared by the home band (four figures on tint) and the navy band used by both
   About and Projects (three figures). The two differ only in palette and in how
   they stack, so everything else is defined once here.

   Both reference sizes are off the preset scale (68px / 12.5px), so these
   blocks carry no `fontSize` attribute and the values are set below.
   ============================================================ */

.figure {
	position: relative;
	padding: 0.5rem clamp(1rem, 2vw, 2rem);
	text-align: center;
}

/* Hairline between figures, inset top and bottom so it reads as a divider
   rather than a full-height column rule. There is no gutter — the breathing
   room is the figure's own horizontal padding. */
.figure:not(:last-child)::after {
	content: "";
	position: absolute;
	inset-block: 12%;
	inset-inline-end: 0;
	width: 1px;
	background-color: var(--wp--preset--color--line);
}

/* Flex rather than inline text so the unit hangs from the top of the numeral
   instead of riding its baseline. As flex items `sup`'s own `vertical-align`
   no longer applies, which is what the reference relies on too. */
.figure__num {
	display: flex;
	align-items: flex-start;
	justify-content: center;
	margin-block: 0;
	font-size: clamp(2.375rem, 4.6vw, 4.25rem);
	font-weight: 400;
	line-height: 1;
	letter-spacing: 0.01em;
}

/* Tabular figures keep the numerals on a common width, so a band does not
   shift if these values are ever edited. */
.figure__num,
.figure__num .val {
	font-variant-numeric: tabular-nums;
}

.figure__num sup {
	margin-inline-start: 0.05em;
	font-size: 0.42em;
	font-weight: 700;
	color: var(--wp--preset--color--sky);
}

.figure__lbl {
	margin-block: 1.125rem 0;
	font-size: 0.78125rem;
	font-weight: 500;
	line-height: 1.4;
	letter-spacing: 0.1em;
	text-transform: uppercase;
}

/* ---------- Navy variant (About, Projects) ---------- */

.figures--navy .figure:not(:last-child)::after {
	background-color: color-mix(in srgb, var(--wp--preset--color--base) 20%, transparent);
}

.figures--navy .figure__lbl {
	color: color-mix(in srgb, var(--wp--preset--color--base) 75%, transparent);
}

/*
 * The navy band is a Columns block, so it stacks at core's fixed 782px rather
 * than the reference's 760px, and the hairlines go once it does.
 *
 * Deliberate deviation, confirmed: between 461px and 820px the reference puts
 * the three figures on two columns, orphaning "40+" on a row of its own. That is
 * an accident in its CSS — `.figures__grid--3` asks for one column under 760px
 * but `.figures__grid` is declared later at equal specificity inside the 820px
 * query and wins. We follow the reference's stated intent ("stacks to 1 on
 * phones"), not its rendering, so no figure is ever left orphaned. Reproducing
 * it would mean trading Columns for a Grid to get a second stacking point.
 */
@media (max-width: 781px) {
	.figures--navy .figures__grid {
		row-gap: 2.5rem;
	}

	.figures--navy .figure::after {
		display: none;
	}
}

/* ---------- Home band: 3 → 1 ---------- */

/*
 * A Grid layout rather than Columns, because this band needs two stacking steps
 * and Columns only knows one. The selector is doubled up so it outranks the grid
 * rules core prints for the block's own container class, which land at the same
 * specificity and whose print order relative to this file is not something to
 * rely on. `:not(.figures--navy)` keeps these breakpoints off the navy band.
 */
.figures:not(.figures--navy) .figures__grid {
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: 0;
}

/* Straight to one column, skipping a two-up step: with three figures that step
   would leave the third alone on a row, the same orphan the navy band avoids. */
@media (max-width: 820px) {
	.figures:not(.figures--navy) .figures__grid {
		grid-template-columns: minmax(0, 1fr);
		gap: 2.5rem;
	}

	.figures:not(.figures--navy) .figure::after {
		display: none;
	}
}

/* ============================================================
   ABOUT — SIX FOUNDING PRINCIPLES
   Section head over a six-cell grid.

   The hairlines between cells are the grid showing through: a 1px gap over a
   `line` background, closed on the outside by a 1px border. One rule instead
   of per-cell borders that would double up where cells meet.

   No colour here comes from a block attribute. Every one of them is swapped on
   hover and preset classes carry `!important`, which would pin the resting
   colour and kill the hover.
   ============================================================ */

/* Doubled class: the grid layout's own container rule carries a single class,
   so gap and columns have to outweigh it. */
.wp-block-group.principles__grid {
	gap: 1px;
	background-color: var(--wp--preset--color--line);
	border: 1px solid var(--wp--preset--color--line);
}

.principle {
	padding: 2.375rem 2.125rem;
	background-color: var(--wp--preset--color--base);
	transition: background-color 0.3s var(--aac--ease);
}

.principle__no {
	margin-block: 0 1.125rem;
	font-weight: 700;
	letter-spacing: 0.1em;
	color: var(--wp--preset--color--sky);
	transition: color 0.3s var(--aac--ease);
}

.principle__title {
	margin-block: 0 0.875rem;
	font-size: 1.375rem;
	font-weight: 700;
	color: var(--wp--preset--color--navy);
	transition: color 0.3s var(--aac--ease);
}

.principle__text {
	margin: 0;
	font-size: 0.9375rem;
	line-height: 1.6;
	color: var(--wp--preset--color--muted);
	transition: color 0.3s var(--aac--ease);
}

/* Decorative only: the cell is not a link and carries no state, so nothing is
   conveyed by the hover that the resting card does not already say. */
.principle:hover {
	background-color: var(--wp--preset--color--navy);
}

.principle:hover .principle__no,
.principle:hover .principle__title {
	color: var(--wp--preset--color--base);
}

.principle:hover .principle__text {
	color: color-mix(in srgb, var(--wp--preset--color--base) 80%, transparent);
}

/* Grid layout has no built-in stacking point — core's 782px only applies to
   Columns — so the reference's own two breakpoints are reproduced here. A
   `minimumColumnWidth` grid cannot stand in for them: it measures the
   container, and the reference's 960px / 760px are viewport widths. */
@media (max-width: 960px) {
	.wp-block-group.principles__grid {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (max-width: 760px) {
	.wp-block-group.principles__grid {
		grid-template-columns: 1fr;
	}
}

/* ============================================================
   REVEAL ON ENTRY
   The reference fades each section element up 24px over 0.7s the first time an
   IntersectionObserver sees it, and never replays it. `assets/js/reveal.js`
   drives it with the same threshold and margins.

   The hidden state hangs off a class the script adds to the document element, so
   without scripts — or with reduced motion — nothing is ever hidden.
   ============================================================ */

.aac-reveal-on .aac-reveal {
	opacity: 0;
	transform: translateY(24px);
	transition:
		opacity 0.7s var(--aac--ease),
		transform 0.7s var(--aac--ease);
}

.aac-reveal-on .aac-reveal.is-in {
	opacity: 1;
	transform: none;
}

/* ============================================================
   ABOUT — THE TEAM
   Section head, then one full-width profile per partner: portrait over key
   figures on the left, name / role / biography on the right.

   Reference sizes here (32px name, 13px role, 18px and 16px body, 26px and
   11px figures) are all off the preset scale, so these blocks carry no
   `fontSize` attribute and the values are set below.
   ============================================================ */

.member-full {
	padding-block: clamp(1.875rem, 3.6vw, 3.25rem);
	border-block-end: 1px solid var(--wp--preset--color--line);
}

/* Doubled class: the grid layout's own container rule carries a single class,
   so the asymmetric tracks and the gap have to outweigh it. */
.wp-block-group.member-full__grid {
	grid-template-columns: 0.85fr 1.15fr;
	gap: clamp(2.5rem, 6vw, 5rem);
	align-items: start;
}

/* 4:5 frame around a square source, so the crop is anchored high on the
   sitter's head rather than centred on the chest. */
.member-full__photo {
	position: relative;
	margin: 0;
	aspect-ratio: 4 / 5;
	overflow: hidden;
	border-radius: 2px;
}

.member-full__photo img {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: center 12%;
}

.wp-block-group.member-full__stats {
	gap: 1.25rem;
	margin-block-start: 1.625rem;
	padding-block-start: 1.5rem;
	border-block-start: 1px solid var(--wp--preset--color--line);
}

.member-full__stat-num {
	margin-block: 0 0.5rem;
	font-size: 1.625rem;
	font-weight: 700;
	line-height: 1;
	color: var(--wp--preset--color--navy);
}

.member-full__stat-lbl {
	margin: 0;
	font-size: 0.6875rem;
	line-height: 1.3;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--wp--preset--color--muted);
}

/* Marked up as a heading because that is what it is, but the reference styles
   it as a plain div — so it keeps the body line-height rather than the tighter
   heading one. Weight and tracking already match the heading defaults. */
.member-full__name {
	margin-block: 0 0.5rem;
	font-size: clamp(1.5rem, 2.8vw, 2rem);
	line-height: 1.65;
	color: var(--wp--preset--color--navy);
}

.member-full__role {
	margin-block: 0 1.5rem;
	font-size: 0.8125rem;
	font-weight: 600;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--wp--preset--color--signal);
}

/* The heading carries the pair's bottom margin now that it shares a row with
   the icon — left on the heading it would offset the flex centring. */
.wp-block-group.member-full__head {
	margin-block: 0 0.5rem;
}

.member-full__head .member-full__name {
	margin-block: 0;
}

.wp-block-social-links.member-full__social {
	margin-block: 0;
}

/* Core paints the logo LinkedIn blue — the one colour on this page that belongs
   to no preset. The colour has to be set on the `li`, not on the list: core's
   own `…__anchor { color: currentColor }` runs at 0,4,1 and would beat anything
   reasonable set on the anchor, so the anchor is left to inherit instead. */
.member-full__social .wp-social-link.wp-social-link-linkedin {
	color: var(--wp--preset--color--navy);
}

.member-full__social .wp-social-link.wp-social-link-linkedin:hover {
	color: var(--wp--preset--color--sky);
}

/* Logos-only means to draw the glyph larger, but its own rule scores lower than
   core's generic `.wp-block-social-links .wp-social-link svg` and never lands.
   Restated one class higher: 1.5em of the block's 16px is a 24px glyph. */
.member-full__social .wp-social-link a svg {
	width: 1.5em;
	height: 1.5em;
}

/* Logos-only zeroes the anchor padding, leaving a target the size of the glyph.
   This brings it to 36px, clear of the 24px minimum of WCAG 2.2 SC 2.5.8. */
.member-full__social .wp-social-link a {
	padding: 0.375rem;
	border-radius: 999px;
}

.member-full__social .wp-social-link a:focus-visible {
	outline: 2px solid var(--wp--preset--color--navy);
	outline-offset: 3px;
}

.member-full__bio p {
	margin-block: 0 1.125rem;
	font-size: 1rem;
	line-height: 1.7;
	color: var(--wp--preset--color--muted);
}

/* Two classes, so this beats `.member-full__bio p` on specificity rather than
   on source order. */
.member-full__bio .member-full__lede {
	font-size: 1.125rem;
	line-height: 1.6;
	color: var(--wp--preset--color--contrast);
}

/* The reference collapses the profile at 960px, which is why this grid is not
   a Columns block — core stacks those at a fixed 782px. Capping the aside keeps
   the portrait from spanning the full measure once stacked. */
@media (max-width: 960px) {
	.wp-block-group.member-full__grid {
		grid-template-columns: 1fr;
		gap: 2rem;
	}

	.member-full__aside {
		max-width: 26.25rem;
	}
}

/* Same cap the home page puts on its two portraits at this width, so a partner
   photographed on About is not twice the size of the same face on the home
   page. Left at the column width it also reads as a full-bleed banner rather
   than a portrait. */
@media (max-width: 600px) {
	.member-full__photo {
		max-width: 15.625rem;
		margin-inline: auto;
	}

	/* Once the portrait is centred and no longer reaches the column edges, the
	   figures under it read as its caption — flush left they would hang off to
	   one side of it. */
	.wp-block-group.member-full__stats {
		text-align: center;
	}
}

@media (max-width: 480px) {
	.wp-block-group.member-full__stats {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}

	/* Three figures in two columns leave the last one alone on its row, hanging
	   under the first column. `:nth-child(odd)` is what scopes this to that
	   case — an even count fills both columns and needs no help. */
	.wp-block-group.member-full__stats > :last-child:nth-child(odd) {
		grid-column: 1 / -1;
		justify-self: center;
	}
}

/* ============================================================
   HOME — SERVICES BAND
   Full-bleed dark band: photograph one side, the three specialisations the
   other. Sizes here (38px / 21px / 15px) are off the preset scale, so these
   blocks carry no `fontSize` attribute and the values are set below.
   ============================================================ */

/* Grid, not Columns — the reference splits this band at 900px and Columns only
   knows core's fixed 782px point. Doubled-up selector so it outranks the grid
   rules core prints for the block's own container class. */
.band.band--dark {
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 0;
	min-height: min(80vh, 760px);
	overflow: hidden;
}

.band__media {
	position: relative;
	overflow: hidden;
}

.band__media figure {
	margin: 0;
	height: 100%;
}

/* Out of flow so the photograph fills its half of the grid regardless of its
   own proportions, exactly as it does in the hero. */
.band__media img {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.band__body {
	display: flex;
	flex-direction: column;
	justify-content: center;
	padding: clamp(3rem, 7vw, 6.875rem) clamp(1.75rem, 5vw, 5.25rem);
}

.band__title {
	margin-block: 0 1.625rem;
	font-size: clamp(1.5rem, 3.1vw, 2.375rem);
	line-height: 1.08;
}

.svc-band-list {
	margin-block-start: 0.5rem;
	/* The numbers are drawn from this counter, so they are always the row's real
	   position — nothing to renumber when a row is added or moved. */
	counter-reset: aac-svc;
}

/*
 * Rows are separated by rules rather than gaps, so each carries a top border and
 * the last one closes the stack with a bottom border.
 *
 * The arrow disc is drawn from this element's two pseudo-elements: the ring on
 * ::before, the glyph on ::after. Drawing it rather than marking it up keeps it
 * out of the accessibility tree — the row's link text already says where it goes.
 */
.svc-band-item {
	--aac--go-size: 2.375rem;

	/* Explicit because the `min-height` below is authored against it and
	   WordPress ships no universal border-box reset: under content-box the rule
	   lands outside the box and every row grows by its own border. */
	box-sizing: border-box;
	position: relative;
	counter-increment: aac-svc;
	width: 100%;
	border-block-start: 1px solid color-mix(in srgb, var(--wp--preset--color--base) 16%, transparent);
}

.svc-band-item:last-child {
	border-block-end: 1px solid color-mix(in srgb, var(--wp--preset--color--base) 16%, transparent);
}

/*
 * The row is one button, so the anchor is stretched to fill it rather than a
 * heading having its hit area faked with a pseudo-element. Everything the button
 * element brings — its fill, border and radius — is unset here; the two classes
 * out-specify the `elements.button` styles theme.json emits.
 *
 * `min-height` keeps the reference's row rhythm against the out-of-flow disc,
 * and `padding-inline-end` reserves the disc's width.
 */
.svc-band-item .wp-block-button__link {
	display: flex;
	align-items: center;
	gap: 1.375rem;
	width: 100%;
	/* The row's own border sits outside this box and adds the reference's extra
	   pixel, so it is not counted here as it was when the rule lived on the row. */
	min-height: calc(var(--aac--go-size) + 2.75rem);
	padding-block: 1.375rem;
	padding-inline: 0 calc(var(--aac--go-size) + 1.375rem);
	border: 0;
	border-radius: 0;
	background: none;
	color: inherit;
	font-size: clamp(1.0625rem, 1.8vw, 1.3125rem);
	font-weight: 500;
	letter-spacing: normal;
	line-height: 1.3;
	text-align: start;
	text-decoration: none;
}

.svc-band-item .wp-block-button__link::before {
	content: counter(aac-svc, decimal-leading-zero);
	flex: 0 0 auto;
	color: var(--wp--preset--color--sky);
	font-size: 0.9375rem;
	font-weight: 700;
}

.svc-band-item .wp-block-button__link:hover,
.svc-band-item .wp-block-button__link:focus {
	background: none;
	color: inherit;
}

.svc-band-item .wp-block-button__link:focus-visible {
	outline: 2px solid var(--wp--preset--color--sky);
	outline-offset: 4px;
}

.svc-band-item::before,
.svc-band-item::after {
	content: "";
	position: absolute;
	inset-block-start: 50%;
	pointer-events: none;
	transform: translateY(-50%);
}

.svc-band-item::before {
	inset-inline-end: 0;
	width: var(--aac--go-size);
	height: var(--aac--go-size);
	border: 1px solid color-mix(in srgb, var(--wp--preset--color--base) 40%, transparent);
	border-radius: 50%;
	transition: background-color 0.3s var(--aac--ease);
}

.svc-band-item::after {
	inset-inline-end: calc((var(--aac--go-size) - 0.875rem) / 2);
	width: 0.875rem;
	height: 0.875rem;
	background-color: var(--wp--preset--color--base);
	transition: background-color 0.3s var(--aac--ease);
	mask: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 12h16M13 6l6 6-6 6" fill="none" stroke="black" stroke-width="1.5"/></svg>') no-repeat center / contain;
	-webkit-mask: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 12h16M13 6l6 6-6 6" fill="none" stroke="black" stroke-width="1.5"/></svg>') no-repeat center / contain;
}

.svc-band-item:hover::before,
.svc-band-item:focus-within::before {
	background-color: var(--wp--preset--color--base);
}

.svc-band-item:hover::after,
.svc-band-item:focus-within::after {
	background-color: var(--wp--preset--color--navy);
}


@media (max-width: 900px) {
	.band.band--dark {
		grid-template-columns: minmax(0, 1fr);
		min-height: 0;
	}

	/* Photograph on top once stacked, as in the reference. */
	.band__media {
		order: -1;
		min-height: 52vw;
	}
}

/* ============================================================
   HOME — LEADERSHIP
   Centred intro over the two founding partners.

   The reference sizes here (52px / 22px / 12px) are off the preset scale, so
   these blocks carry no `fontSize` attribute and the values are set below.
   ============================================================ */

.leadership__intro {
	max-width: 42.5rem;
	margin-inline: auto;
	margin-block-end: clamp(2.5rem, 5vw, 3.75rem);
}

.leadership__title {
	margin-block: 0 1.125rem;
	font-size: clamp(1.75rem, 4.4vw, 3.25rem);
	line-height: 1.12;
}

.leadership__lede {
	max-width: 52ch;
	margin-block: 0;
	margin-inline: auto;
}

/*
 * Fixed 400px tracks rather than the fluid ones core's Grid layout emits: the
 * pair is meant to sit centred in the container at its natural size, not stretch
 * to fill it. Doubled-up selector so it outranks the layout rules core prints
 * for the block's own container class.
 */
.leadership .leadership__grid {
	grid-template-columns: repeat(2, 25rem);
	justify-content: center;
	gap: clamp(4rem, 9vw, 8.75rem);
}

.leader__fig {
	position: relative;
	margin: 0;
	aspect-ratio: 4 / 5;
	max-width: 25rem;
	margin-inline: auto;
	overflow: hidden;
	border-radius: 2px;
}

/* `center 10%` keeps the sitter's head in frame when a square portrait is
   cropped to a 4:5 box. */
.leader__fig img {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: center 10%;
}

.leader__name {
	margin-block: 1.25rem 0.25rem;
	font-size: 1.375rem;
	font-weight: 700;
}

.leader__role {
	margin-block: 0;
	font-size: 0.75rem;
	font-weight: 600;
	letter-spacing: 0.1em;
	text-transform: uppercase;
}

.leadership__cta {
	margin-block-start: clamp(2.25rem, 5vw, 3.25rem);
}

/* The pair stays side by side all the way down. Below 900px the fixed 25rem
   tracks would overflow, so the columns go fluid and the gap closes with them. */
@media (max-width: 900px) {
	.leadership .leadership__grid {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		gap: clamp(1rem, 4vw, 3.5rem);
	}
}

/* At two-up on a phone each column is roughly 140px, so the name set for a
   25rem portrait is far too large and breaks across three lines. */
@media (max-width: 600px) {
	.leader__name {
		margin-block-start: 0.875rem;
		font-size: 1.0625rem;
	}

	.leader__role {
		font-size: 0.6875rem;
		letter-spacing: 0.08em;
	}
}

/* ============================================================
   ASSET CLASSES
   Five cards on one row: title, portrait image, one-line description. Each is
   keyed to its category colour through a modifier class.

   Shared by the home page and Projects, which differ only above the row: home
   runs a bare eyebrow and title, Projects a `.sec-head` widened to 760px plus a
   standfirst naming the sectors.

   Reference sizes here (32px / 22px / 13.5px) are off the preset scale, so
   these blocks carry no `fontSize` attribute and the values are set below.
   ============================================================ */

.asset-classes__head {
	margin-block-end: clamp(1.75rem, 3.5vw, 2.75rem);
}

/* The reference widens this one section head past the 640px default. */
.asset-classes .sec-head__title,
.asset-classes .sec-head__text {
	max-width: 47.5rem;
}

.asset-classes__intro {
	margin-block: 0 clamp(1.375rem, 3vw, 2.125rem);
}

.asset-classes__intro p {
	max-width: 48ch;
	margin-block: 0;
}

.asset-classes__title {
	margin-block: 0;
	font-size: clamp(1.375rem, 2.6vw, 2rem);
	line-height: 1.18;
}

/* Doubled-up selector so it outranks the grid rules core prints for the block's
   own container class. */
.asset-classes .asset-row {
	grid-template-columns: repeat(5, minmax(0, 1fr));
	align-items: start;
	gap: clamp(1rem, 1.6vw, 1.625rem);
}

.asset3 {
	--aac--cat: var(--wp--preset--color--sky);
}

/* Paired selectors so the asset-class colour has one definition: `.asset3--*`
   for the cards on this row, `.has-cat-*` for anything keyed to a term slug —
   the case-study badges today, the map markers next. */
.asset3--office,
.has-cat-office {
	--aac--cat: var(--aac--cat-office);
}

.asset3--logistics,
.has-cat-logistics {
	--aac--cat: var(--aac--cat-logistics);
}

.asset3--hospitality,
.has-cat-hospitality {
	--aac--cat: var(--aac--cat-hospitality);
}

.asset3--residential,
.has-cat-residential {
	--aac--cat: var(--aac--cat-residential);
}

.asset3--pbsa,
.has-cat-pbsa {
	--aac--cat: var(--aac--cat-pbsa);
}

/* `box-sizing` is explicit because the reference sets it globally and the
   `min-height` below is authored against it: WordPress ships no universal
   border-box reset, so under content-box the 18px rule padding lands outside the
   min-height and every title box grows 18px, pushing the photos down. */
.asset3__title {
	box-sizing: border-box;
	position: relative;
	margin-block: 0 1rem;
	padding-block-start: 1.125rem;
	font-size: clamp(1.125rem, 1.8vw, 1.375rem);
	font-weight: 500;
	color: var(--wp--preset--color--navy);
	transition: color 0.3s var(--aac--ease);
}

/* Holds two lines' worth of height so the images below stay on a common line
   whether a title wraps or not. Dropped once the row is a single column. */
.asset-row .asset3__title {
	min-height: calc(1.125rem + 2.5em);
}

.asset3__title::before {
	content: "";
	position: absolute;
	inset-block-start: 0;
	inset-inline-start: 0;
	width: 1.625rem;
	height: 2px;
	background-color: var(--aac--cat);
	transition: width 0.4s var(--aac--ease);
}

.asset3:hover .asset3__title {
	color: var(--aac--cat);
}

.asset3:hover .asset3__title::before {
	width: 50%;
}

.asset3__fig {
	margin: 0;
	aspect-ratio: 4 / 5;
	overflow: hidden;
	border-radius: 2px;
}

.asset3__fig img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: transform 0.7s var(--aac--ease);
}

.asset3:hover .asset3__fig img {
	transform: scale(1.05);
}

/* 5 → 3, then a swipeable row below the mobile line. */
@media (max-width: 1080px) {
	.asset-classes .asset-row {
		grid-template-columns: repeat(3, minmax(0, 1fr));
		row-gap: clamp(1.75rem, 4vw, 2.5rem);
	}
}

/*
 * On a phone the five cards scroll sideways instead of stacking: stacked they
 * turn an overview into a very long scroll. The card sits at 74% so the next one
 * always peeks in — that peek is the affordance saying the row moves, and it is
 * why the title keeps its two-line `min-height` here, so the two visible cards
 * still line their photographs up.
 *
 * Native scrolling does the work. The arrows added by `assets/js/asset-slider.js`
 * are an enhancement on top of the swipe, not a replacement for it.
 */
@media (max-width: 781px) {
	.asset-classes .asset-row {
		display: flex;
		grid-template-columns: none;
		gap: 1rem;
		overflow-x: auto;
		overscroll-behavior-inline: contain;
		scroll-snap-type: x mandatory;
		scrollbar-width: none;
	}

	.asset-classes .asset-row::-webkit-scrollbar {
		display: none;
	}

	.asset-row > .asset3 {
		flex: 0 0 74%;
		scroll-snap-align: start;
	}
}

/* Kept out of the block above so a visitor who asks for less motion still gets
   the snap, just without the animated glide. */
@media (max-width: 781px) and (prefers-reduced-motion: no-preference) {
	.asset-classes .asset-row {
		scroll-behavior: smooth;
	}
}

/* Injected by the script, so it exists only where the script runs — without JS
   the row is still swipeable and nothing is missing. */
.asset-nav {
	display: none;
}

@media (max-width: 781px) {
	.asset-nav {
		display: flex;
		justify-content: flex-end;
		gap: 0.875rem;
		margin-block-start: 1.5rem;
	}

	/* Same ring-and-glyph component as the arrow buttons, at a smaller ring. */
	.asset-nav__btn {
		--aac--arrow-ink: var(--wp--preset--color--navy);
		--aac--arrow-void: var(--wp--preset--color--base);
		--aac--arrow-ring: 2.875rem;
		--aac--arrow-glyph: 1.125rem;

		box-sizing: border-box;
		display: inline-flex;
		align-items: center;
		justify-content: center;
		width: var(--aac--arrow-ring);
		height: var(--aac--arrow-ring);
		padding: 0;
		border: 1px solid var(--aac--arrow-ink);
		border-radius: 50%;
		background: none;
		cursor: pointer;
		transition: background-color 0.3s var(--aac--ease), opacity 0.3s var(--aac--ease);
	}

	.asset-nav__btn::before {
		content: "";
		width: var(--aac--arrow-glyph);
		height: var(--aac--arrow-glyph);
		background-color: var(--aac--arrow-ink);
		transition: background-color 0.3s var(--aac--ease);
		mask: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 12h16M13 6l6 6-6 6" fill="none" stroke="black" stroke-width="1.5"/></svg>') no-repeat center / contain;
		-webkit-mask: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 12h16M13 6l6 6-6 6" fill="none" stroke="black" stroke-width="1.5"/></svg>') no-repeat center / contain;
	}

	.asset-nav__btn--prev::before {
		transform: scaleX(-1);
	}

	.asset-nav__btn:hover:not(:disabled) {
		background-color: var(--aac--arrow-ink);
	}

	.asset-nav__btn:hover:not(:disabled)::before {
		background-color: var(--aac--arrow-void);
	}

	.asset-nav__btn:disabled {
		opacity: 0.3;
		cursor: default;
	}

	.asset-nav__btn:focus-visible {
		outline: 2px solid var(--aac--arrow-ink);
		outline-offset: 3px;
	}

	.asset-row:focus-visible {
		outline: 2px solid var(--wp--preset--color--navy);
		outline-offset: 4px;
	}
}

/* ============================================================
   CONTACT — DETAILS AND FORM
   Two columns: office details on the left, the Fluent Forms enquiry form on
   the right, with a map band beneath.

   Fluent Forms ships its own public stylesheet and renders its own markup, so
   the theme cannot express this through supports. The plugin CSS is kept — it
   carries the validation, error and success states, which would all have to be
   rebuilt if it were dequeued — and only the visual surface is repainted below,
   from presets. Every selector is scoped under `.contact-form` so no other
   form on the site inherits it.
   ============================================================ */

/* The reference type size (24→34px) falls between preset steps, so the block
   carries no `fontSize` and the value is set here. */
.contact-info__title {
	margin-block-end: 1.5rem;
	font-size: clamp(1.5rem, 3vw, 2.125rem);
}

.contact-block {
	border-block-start: 1px solid var(--wp--preset--color--line);
	padding-block: 1.375rem;
}

/* The reference labels these `h4`; here they are `h3` so the section's heading
   order runs h2 → h3 without a skipped level. The eyebrow style already carries
   the tracking and case — only the colour and the gap below differ. */
.contact-block .is-style-eyebrow {
	margin-block-end: 0.625rem;
	color: var(--wp--preset--color--signal);
}

.contact-block p {
	font-size: 1rem;
	line-height: 1.7;
	color: var(--wp--preset--color--contrast);
}

/* No resting underline; hover and focus both add one, so the state change is
   never carried by colour alone. */
.contact-block a {
	color: var(--wp--preset--color--navy);
	text-decoration: none;
	border-block-end: 1px solid transparent;
}

.contact-block a:hover {
	border-block-end-color: var(--wp--preset--color--navy);
}

.contact-block a:focus-visible {
	outline: 2px solid var(--wp--preset--color--navy);
	outline-offset: 3px;
}

/* ---------- Form panel ---------- */

.contact-form {
	align-self: start;
	background-color: var(--wp--preset--color--surface);
	border: 1px solid var(--wp--preset--color--line);
	border-radius: 2px;
	padding: clamp(1.75rem, 4vw, 2.75rem);
}

.contact-form .ff-el-group {
	margin-block-end: 1.25rem;
}

.contact-form .ff-el-input--label label {
	display: block;
	margin-block-end: 0.5rem;
	font-size: 0.75rem;
	font-weight: 600;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--wp--preset--color--contrast);
}

.contact-form .ff-el-form-control {
	width: 100%;
	padding: 0.875rem 1rem;
	font-family: inherit;
	font-size: 0.9375rem;
	color: var(--wp--preset--color--contrast);
	background-color: var(--wp--preset--color--base);
	border: 1px solid var(--wp--preset--color--line);
	border-radius: 2px;
	transition:
		border-color 0.2s var(--aac--ease),
		box-shadow 0.2s var(--aac--ease);
}

.contact-form .ff-el-form-control:focus {
	outline: none;
	border-color: var(--wp--preset--color--navy);
	box-shadow: 0 0 0 3px color-mix(in srgb, var(--wp--preset--color--navy) 10%, transparent);
}

.contact-form textarea.ff-el-form-control {
	resize: vertical;
	min-height: 8.125rem;
}

/* The plugin lays each two-column row out as flex cells with an inline
   `flex-basis:50%` and no gap. The gap is added here rather than as padding on
   the cells, so the row still meets the panel's edges. */
.contact-form .ff-t-container.ff-column-container {
	display: flex;
	gap: 1.25rem;
}

.contact-form .ff-t-cell {
	min-width: 0;
}

/* ---------- Form submit ---------- */

/* Fluent Forms renders a bare `<button>`, not a core Button block, so the
   button element styles in theme.json never reach it. They are restated here
   from the same presets — keep the two in step. */
.contact-form .ff-btn-submit {
	width: 100%;
	margin-block-start: 0.375rem;
	padding: 0.9375rem 1.875rem;
	font-family: inherit;
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
	letter-spacing: 0.04em;
	line-height: 1;
	color: var(--wp--preset--color--base);
	background-color: var(--wp--preset--color--navy);
	border: 1px solid var(--wp--preset--color--navy);
	border-radius: 2px;
	cursor: pointer;
	transition:
		background-color 0.2s var(--aac--ease),
		border-color 0.2s var(--aac--ease);
}

.contact-form .ff-btn-submit:hover {
	background-color: var(--wp--preset--color--navy-deep);
	border-color: var(--wp--preset--color--navy-deep);
}

.contact-form .ff-btn-submit:focus-visible {
	outline: 2px solid var(--wp--preset--color--navy-ink);
	outline-offset: 3px;
}

/* ---------- Validation states ---------- */

.contact-form .ff-el-is-error .ff-el-form-control {
	border-color: var(--wp--preset--color--signal);
}

.contact-form .error.text-danger {
	margin-block-start: 0.375rem;
	font-size: 0.8125rem;
	color: var(--wp--preset--color--signal);
}

.contact-form .ff-message-success {
	padding: 1.25rem;
	background-color: var(--wp--preset--color--base);
	border: 1px solid var(--wp--preset--color--line);
	border-radius: 2px;
	color: var(--wp--preset--color--contrast);
}

/* ---------- Map band ---------- */

.map-placeholder {
	position: relative;
	overflow: hidden;
	margin-block-start: clamp(1.875rem, 4vw, 3rem);
	aspect-ratio: 21 / 6;
	border-radius: 2px;
	background-image: linear-gradient(
		150deg,
		var(--wp--preset--color--navy) 0%,
		var(--wp--preset--color--navy-night) 100%
	);
	display: flex;
	align-items: center;
	justify-content: center;
}

.map-placeholder::before {
	content: "";
	position: absolute;
	inset: 0;
	background-image:
		repeating-linear-gradient(
			90deg,
			color-mix(in srgb, var(--wp--preset--color--base) 4%, transparent) 0 1px,
			transparent 1px 4.375rem
		),
		repeating-linear-gradient(
			0deg,
			color-mix(in srgb, var(--wp--preset--color--base) 4%, transparent) 0 1px,
			transparent 1px 4.375rem
		);
}

.map-placeholder__label {
	position: relative;
	margin: 0;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	color: color-mix(in srgb, var(--wp--preset--color--base) 50%, transparent);
}

/* The reference stacks this grid at 960px; core stacks the Columns block at
   782px and that point is not configurable, so the stacked rules key off core's
   breakpoint instead — as with `.about-body__grid`. */
@media (max-width: 781px) {
	.contact-grid {
		row-gap: 2.25rem;
	}

	/* The band is a 21:6 letterbox on desktop, which collapses to a sliver once
	   it is only a phone wide. */
	.map-placeholder {
		aspect-ratio: 16 / 9;
	}
}

@media (max-width: 480px) {
	.contact-form .ff-t-container.ff-column-container {
		flex-direction: column;
		gap: 0;
	}
}

/* ============================================================
   CASE STUDIES
   Cards on a dark navy band, one per `aac_case_study` post. The whole card is
   a single link, so everything inside it is inert markup — the hover and focus
   states belong to the anchor.

   The card sizes (23px / 13px / 11px / 10.5px) are the reference's own and sit
   off the preset scale, so they are set here rather than as `fontSize`
   attributes; only the title lands on a preset (`large`) and uses its variable.
   ============================================================ */

.cs-grid {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: 1.5rem;
}

/* The card is one big anchor, so the underline core gives content links has to
   come off: the CTA row and the hover lift are the affordance, and the focus
   ring below keeps that visible to the keyboard. */
.cs-card {
	display: flex;
	flex-direction: column;
	overflow: hidden;
	color: inherit;
	text-decoration: none;
	border: 1px solid var(--wp--preset--color--line);
	border-radius: 2px;
	background-color: var(--wp--preset--color--base);
	transition:
		transform 0.3s var(--aac--ease),
		box-shadow 0.3s var(--aac--ease);
}

.cs-card:hover {
	transform: translateY(-5px);
	box-shadow: 0 18px 44px color-mix(in srgb, var(--wp--preset--color--navy) 12%, transparent);
}

.cs-card:focus-visible {
	outline: 2px solid var(--wp--preset--color--navy);
	outline-offset: 3px;
}

/* Gradient rather than a flat panel: it is what shows through while the image
   loads, and behind a card that has no featured image yet. */
.cs-card__media {
	position: relative;
	display: flex;
	align-items: center;
	justify-content: center;
	overflow: hidden;
	aspect-ratio: 16 / 9;
	background-image: linear-gradient(
		150deg,
		var(--wp--preset--color--navy) 0%,
		var(--wp--preset--color--navy-night) 100%
	);
}

.cs-card__media::before {
	content: "";
	position: absolute;
	inset: 0;
	background-image: radial-gradient(
		80% 90% at 80% 10%,
		color-mix(in srgb, var(--wp--preset--color--sky) 34%, transparent),
		transparent 60%
	);
}

.cs-card__media img {
	position: absolute;
	inset: 0;
	z-index: 1;
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: transform 0.7s var(--aac--ease);
}

.cs-card:hover .cs-card__media img {
	transform: scale(1.05);
}

/* Colour comes from the asset-class term through `.has-cat-*`, the same custom
   property the asset-class row uses. */
.cs-card__cat {
	position: absolute;
	z-index: 2;
	inset-block-start: 0.875rem;
	inset-inline-start: 0.875rem;
	padding: 0.3125rem 0.75rem;
	border-radius: 999px;
	background-color: var(--aac--cat, var(--wp--preset--color--signal));
	box-shadow: 0 4px 14px color-mix(in srgb, var(--wp--preset--color--navy-night) 28%, transparent);
	font-size: 0.65625rem;
	font-weight: 600;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--wp--preset--color--base);
}

.cs-card__body {
	display: flex;
	flex: 1;
	flex-direction: column;
	padding: 1.875rem 1.875rem 2rem;
}

.cs-card__meta {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem 0.875rem;
	margin-block-end: 1rem;
}

.cs-tag {
	font-size: 0.6875rem;
	font-weight: 600;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--wp--preset--color--signal);
}

.cs-tag.size {
	color: var(--wp--preset--color--navy);
}

.cs-tag.status {
	color: var(--wp--preset--color--sky);
}

/* 1.4375rem is the `large` step, but written out rather than taken from the
   preset variable: fluid typography is on, so the preset resolves to a clamp()
   and the title would shrink on phones. The reference holds it at 23px. */
.cs-card h3 {
	margin-block: 0 0.375rem;
	font-size: 1.4375rem;
	font-weight: 700;
	line-height: 1.16;
	letter-spacing: -0.01em;
	color: var(--wp--preset--color--navy);
}

/* 15px and 22px rather than the 13px and 16px `.cs-card__type` asks for in the
   reference: its own `.cs-card__body p` rule is more specific and comes later,
   so those are the values that actually render there. */
.cs-card__type {
	margin-block: 0 1.375rem;
	font-size: 0.9375rem;
	line-height: 1.6;
	color: var(--wp--preset--color--muted);
}

/* `margin-top:auto` pins the row to the bottom, so cards of unequal text still
   line their rules up. */
.cs-card__cta {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 0.5em;
	margin-block-start: auto;
	padding-block-start: 1.125rem;
	border-block-start: 1px solid var(--wp--preset--color--line);
	font-size: 0.8125rem;
	font-weight: 600;
	letter-spacing: 0.03em;
	color: var(--wp--preset--color--navy);
}

.cs-card__cta .arrow {
	color: var(--wp--preset--color--sky);
}

.cs-section .sec-head__title {
	color: var(--wp--preset--color--base);
}

.cs-section .sec-head__text {
	color: color-mix(in srgb, var(--wp--preset--color--base) 72%, transparent);
}

.rr-note {
	max-width: 70ch;
	margin-block-end: 0;
	font-size: 0.8125rem;
	line-height: 1.6;
	color: var(--wp--preset--color--muted);
}

/* The top margin is carried by the compound selector, not by `.rr-note` alone:
   core zeroes a flow container's first child through
   `:root :where(.is-layout-flow) > :first-child`, which outranks a lone class. */
.cs-section .rr-note {
	margin-block-start: 2rem;
	color: color-mix(in srgb, var(--wp--preset--color--base) 55%, transparent);
}

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

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

/* ============================================================
   CASE STUDY DETAIL
   Gallery over a two-column body: the write-up beside a sticky fact list.
   ============================================================ */

.pd__gallery {
	position: relative;
	margin-block-end: clamp(2.375rem, 5vw, 4rem);
}

.pd__frame {
	position: relative;
	width: 100%;
	aspect-ratio: 16 / 9;
	overflow: hidden;
	border-radius: 2px;
	background-color: var(--wp--preset--color--navy-night);
}

.pd__frame img {
	position: absolute;
	inset: 0;
	z-index: 1;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.pd__frame img.is-anim {
	animation: aac-gallery-fade 0.5s var(--aac--ease);
}

@keyframes aac-gallery-fade {
	from {
		opacity: 0;
		transform: scale(1.05);
	}

	to {
		opacity: 1;
		transform: none;
	}
}

@media (prefers-reduced-motion: reduce) {
	.pd__frame img.is-anim {
		animation: none;
	}
}

/* The arrows sit outside the frame, in the page's side margins. */
.pd__nav {
	position: absolute;
	inset-block-start: 50%;
	z-index: 4;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 3rem;
	height: 3rem;
	transform: translateY(-50%);
	border: 1px solid var(--wp--preset--color--line);
	border-radius: 50%;
	background-color: var(--wp--preset--color--base);
	font-size: 1.125rem;
	color: var(--wp--preset--color--navy);
	cursor: pointer;
	transition:
		background-color 0.2s var(--aac--ease),
		color 0.2s var(--aac--ease),
		border-color 0.2s var(--aac--ease);
}

.pd__nav--prev {
	inset-inline-end: calc(100% + clamp(0.875rem, 2vw, 2.25rem));
}

.pd__nav--next {
	inset-inline-start: calc(100% + clamp(0.875rem, 2vw, 2.25rem));
}

.pd__nav:hover {
	border-color: var(--wp--preset--color--navy);
	background-color: var(--wp--preset--color--navy);
	color: var(--wp--preset--color--base);
}

.pd__nav:focus-visible {
	outline: 2px solid var(--wp--preset--color--navy);
	outline-offset: 3px;
}

.pd__nav .arrow {
	color: inherit;
}

/* Below this there is no room beside the frame, so the arrows move onto it. */
@media (max-width: 1280px) {
	.pd__nav--prev {
		inset-inline: 0.875rem auto;
	}

	.pd__nav--next {
		inset-inline: auto 0.875rem;
	}

	.pd__nav {
		background-color: color-mix(in srgb, var(--wp--preset--color--base) 92%, transparent);
		box-shadow: 0 6px 18px color-mix(in srgb, var(--wp--preset--color--navy-night) 18%, transparent);
	}
}

@media (max-width: 640px) {
	.pd__nav {
		width: 2.5rem;
		height: 2.5rem;
		font-size: 1rem;
		box-shadow: 0 4px 14px color-mix(in srgb, var(--wp--preset--color--navy-night) 28%, transparent);
	}

	.pd__nav--prev {
		inset-inline: 0.625rem auto;
	}

	.pd__nav--next {
		inset-inline: auto 0.625rem;
	}
}

.modal__dots {
	position: absolute;
	inset-block-end: 0.875rem;
	inset-inline: 0;
	z-index: 2;
	display: flex;
	gap: 0.4375rem;
	justify-content: center;
}

.modal__dot {
	width: 0.4375rem;
	height: 0.4375rem;
	border-radius: 50%;
	background-color: color-mix(in srgb, var(--wp--preset--color--base) 50%, transparent);
}

.modal__dot.is-active {
	background-color: var(--wp--preset--color--base);
}

/* Three items, not two: the "All projects" link is a sibling of the columns so
   that it can fall below the fact list once the grid stacks. On two columns it
   takes the second row of the first column, which puts it back under the body —
   hence the near-zero row gap, the link carrying its own 6px as in the
   reference. */
.pd__cols {
	display: grid;
	grid-template-columns: 1.55fr 0.9fr;
	column-gap: clamp(2.5rem, 6vw, 5rem);
	row-gap: 0;
	align-items: start;
}

/* `justify-self` because a grid item is stretched and blockified: left to fill
   the track, the link's underline would run the whole column instead of sitting
   under its own label. */
.pd__cols > .ul-link {
	grid-column: 1;
	justify-self: start;
	margin-block-start: 0.375rem;
}

.pd__body .is-style-eyebrow {
	margin-block-end: 1.25rem;
}

.pd__text p {
	margin-block: 0 1.25rem;
	font-size: 1.03125rem;
	line-height: 1.7;
	color: var(--wp--preset--color--muted);
}

/* The opening paragraph runs as a standfirst.

   Scoped to `.pd__text`, not to `.pd__body`: the eyebrow is also a paragraph,
   and in the reference this rule lands on it and blows it up to 21px — an
   accident of specificity there, since every other eyebrow on the site is 12px.
   The wrapper keeps the rule on the write-up where it belongs. */
.pd__text > p:first-of-type {
	font-size: clamp(1.125rem, 2vw, 1.3125rem);
	line-height: 1.55;
	color: var(--wp--preset--color--contrast);
}

.pd__cat {
	display: inline-block;
	margin-block-end: 0.875rem;
	padding: 0.25rem 0.75rem;
	border-radius: 999px;
	background-color: var(--aac--cat, var(--wp--preset--color--signal));
	font-size: 0.6875rem;
	font-weight: 600;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--wp--preset--color--base);
}

.pd__aside {
	position: sticky;
	inset-block-start: 6.25rem;
}

.pd__facts {
	margin: 0;
	border-block-start: 1px solid var(--wp--preset--color--line);
}

.pd__fact {
	display: flex;
	justify-content: space-between;
	gap: 1.25rem;
	padding-block: 0.9375rem;
	border-block-end: 1px solid var(--wp--preset--color--line);
}

.pd__fact dt {
	flex: none;
	font-size: 0.75rem;
	font-weight: 600;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--wp--preset--color--signal);
}

.pd__fact dd {
	margin: 0;
	font-size: 0.9375rem;
	font-weight: 600;
	text-align: end;
	color: var(--wp--preset--color--navy);
}

.ul-link {
	display: inline-flex;
	align-items: center;
	gap: 0.6em;
	padding-block-end: 0.375rem;
	border-block-end: 1px solid var(--wp--preset--color--navy);
	font-size: 0.8125rem;
	font-weight: 600;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--wp--preset--color--navy);
	text-decoration: none;
	transition: gap 0.25s var(--aac--ease);
}

.ul-link:hover {
	gap: 1em;
}

@media (max-width: 820px) {
	.pd__cols {
		grid-template-columns: minmax(0, 1fr);
		gap: 2.125rem;
	}

	.pd__aside {
		position: static;
	}

	/* Stacked, the row gap is the whole spacing — the 6px that tucks the link
	   under the copy on two columns would only skew it. */
	.pd__cols > .ul-link {
		margin-block-start: 0;
	}
}

/* ============================================================
   HOME — PROJECTS MAP
   ============================================================ */
.pmap {
	/* The band's own top and bottom padding, and the distance the stacked map
	   bleeds past its foot. The pattern sets the padding to `var(--aac--pmap-foot)`
	   rather than repeating the clamp, so this declaration is the only place the
	   value exists. */
	--aac--pmap-foot: clamp(2.5rem, 5.5vw, 5rem);

	position: relative;
	overflow: hidden;
	background-color: var(--aac--surface-map);
	min-height: clamp(37.5rem, 54vw, 50rem);
}

/*
 * The text column is stacked over the map, but its box spans the whole section
 * — so it has to let the pointer through, or the markers that fall behind it
 * could never be hovered. Its own links take events back.
 */
.pmap__inner {
	position: relative;
	z-index: 2;
	pointer-events: none;
}

.pmap__inner a {
	pointer-events: auto;
}

.pmap__text {
	max-width: 28.75rem;
}

/* Off the preset scale in the reference, and a preset class would win on
   specificity with its `!important`, so the size is set here and the block
   carries no `fontSize`. */
.pmap__title {
	font-size: clamp(1.5rem, 3.2vw, 2.5rem);
	line-height: 1.14;
}

.pmap__note {
	max-width: 46ch;
	margin-top: 1rem;
}

.pmap__legend {
	display: grid;
	gap: 0.8125rem;
	margin: 1.75rem 0 0;
	padding: 0;
	list-style: none;
}

.pmap__legend li {
	display: flex;
	align-items: center;
	gap: 0.75rem;
	font-size: 0.9375rem;
	font-weight: 500;
	color: var(--wp--preset--color--contrast);
}

/* The swatch is generated rather than marked up: `core/list-item` sets
   `className: false`, so a class per item would break block validation. That
   makes position the only thing left to key the colour to — hence `nth-child`,
   matching the order `asset_classes()` returns. */
.pmap__legend li::before {
	content: "";
	flex: 0 0 auto;
	width: 0.8125rem;
	height: 0.8125rem;
	border-radius: 50%;
	background-color: var(--aac--cat, var(--aac--cat-office));
}

.pmap__legend li:nth-child(1) {
	--aac--cat: var(--aac--cat-office);
}

.pmap__legend li:nth-child(2) {
	--aac--cat: var(--aac--cat-logistics);
}

.pmap__legend li:nth-child(3) {
	--aac--cat: var(--aac--cat-hospitality);
}

.pmap__legend li:nth-child(4) {
	--aac--cat: var(--aac--cat-residential);
}

.pmap__legend li:nth-child(5) {
	--aac--cat: var(--aac--cat-pbsa);
}

/* Absolute in the right half rather than glued to the edge: the north of the
   country stays in view and the deep south bleeds past the bottom, which is what
   the section's `overflow: hidden` is for. */
/* Two classes to clear the specificity of core's `.alignfull` rules. The bleed
   those give this wrapper is wanted only once the map stacks, so on desktop the
   margins go back to zero — an absolutely positioned box with `left` and `width`
   set would otherwise be dragged sideways by them. */
.pmap .pmap__map {
	position: absolute;
	z-index: 1;
	top: clamp(1rem, 2vw, 2.5rem);
	left: 47%;
	width: min(51vw, 46.25rem);
	margin-inline: 0;
	pointer-events: none;
}

.pmap__art {
	margin: 0;
}

/* The ratio is here rather than on the `<img>`: width and height attributes stop
   the image block round-tripping, and without a reserved box the section would
   jump the moment the artwork loads. It is the artwork's own viewBox. */
.pmap__art img {
	display: block;
	width: 100%;
	height: auto;
	aspect-ratio: 720 / 758;
}

/* The markers overlay the artwork rather than sitting inside it, sharing its
   `viewBox` so the two scale as one. Events pass straight through to the page
   except on the markers themselves, which take them back. */
.pmap__svg {
	position: absolute;
	inset: 0;
	overflow: visible;
	pointer-events: none;
}

/* The fallback colour sits on the group, not on the marker: on the marker it
   would share specificity with the `.has-cat-*` class beside it and, being later
   in this file, win — painting every marker office blue. */
.pmap__dots {
	--aac--cat: var(--aac--cat-office);
}

.pmap__dot {
	cursor: default;
	pointer-events: auto;
}

.pmap__dot:focus {
	outline: none;
}

/* The last circle is the coloured marker; the two before it are the halo and
   the enlarged hit area. The white keyline the reference reserves for markers
   that carry a card applies to all of them, since all of them do. */
.pmap__dot > circle:last-of-type {
	fill: var(--aac--cat);
	stroke: var(--wp--preset--color--base);
	stroke-width: 1.6;
	transform-box: fill-box;
	transform-origin: center;
	transition: transform 0.18s ease;
}

.pmap__dot:hover > circle:last-of-type,
.pmap__dot:focus-visible > circle:last-of-type {
	transform: scale(1.4);
}

.pmap__halo {
	fill: var(--wp--preset--color--base);
	opacity: 0;
	transition: opacity 0.18s;
}

.pmap__dot:hover .pmap__halo,
.pmap__dot:focus-visible .pmap__halo {
	opacity: 1;
}

.pmap__tip {
	position: absolute;
	z-index: 6;
	width: max-content;
	max-width: 15.625rem;
	padding: 0.6875rem 0.875rem;
	transform: translate(-50%, -100%);
	border-radius: 0.6875rem;
	background-color: var(--wp--preset--color--navy-night);
	box-shadow: 0 0.875rem 2rem color-mix(in srgb, var(--wp--preset--color--navy-night) 34%, transparent);
	color: var(--wp--preset--color--base);
	font-size: 0.78125rem;
	line-height: 1.4;
	text-align: start;
	cursor: pointer;
	opacity: 0;
	visibility: hidden;
	pointer-events: none;
	transition: opacity 0.15s, visibility 0.15s;
}

.pmap__tip.show {
	opacity: 1;
	visibility: visible;
	pointer-events: auto;
}

.pmap__tip b {
	display: block;
	margin-block-end: 0.125rem;
	font-size: 0.875rem;
	letter-spacing: 0.01em;
	color: var(--wp--preset--color--base);
}

.pmap__tip-at {
	display: block;
	color: color-mix(in srgb, var(--wp--preset--color--base) 72%, transparent);
}

/* Between the city and the activity, and keyed to the marker's own category
   colour so the card and the dot read as the same thing. */
.pmap__tip-class {
	display: block;
	margin-block-end: 0.1875rem;
	font-size: 0.6875rem;
	font-weight: 600;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--wp--preset--color--sky);
}

.pmap__tip::after {
	content: "";
	position: absolute;
	top: 100%;
	left: 50%;
	transform: translateX(-50%);
	border: 0.4375rem solid transparent;
	border-block-start-color: var(--wp--preset--color--navy-night);
}

/* Tablet and below: stop the bleed and stack the map under the text. */
@media (max-width: 1180px) {
	.pmap {
		min-height: 0;
	}

	.pmap__text {
		max-width: none;
	}

	/*
	 * The wrapper keeps the section's side gutter, so the artwork stays inset from
	 * both edges, and gives up the section's bottom padding instead: the dot grid
	 * runs into the foot of the band. `.pmap` is `overflow: hidden`, so whatever
	 * passes the boundary is clipped there rather than spilling into the section
	 * below.
	 *
	 * `relative` rather than `static` so the hover card stays anchored to the map
	 * here too; left static it would resolve against the section instead and land
	 * in the wrong place.
	 */
	.pmap .pmap__map {
		position: relative;
		left: auto;
		width: auto;
		margin-block: clamp(1.5rem, 4vw, 2.5rem) calc(var(--aac--pmap-foot) * -1);
		margin-inline: 0;
		pointer-events: auto;
	}

	/* The artwork and the marker overlay are capped and centred together — the
	   overlay is positioned against the full-bleed wrapper, so left to fill it
	   the markers would drift off the cities the moment the map narrows. */
	.pmap__art,
	.pmap__svg {
		max-width: 32.5rem;
		margin-inline: auto;
	}
}

/* A tighter cap on a phone. Artwork and marker overlay are capped together —
   sizing them apart would slide the markers off their cities. */
@media (max-width: 600px) {
	.pmap__art,
	.pmap__svg {
		max-width: 23.75rem;
	}
}

/* No hover card on touch. The card is driven by `mouseenter`/`focus`, and a tap
   fires `focus`, so on a phone it appears over the map with no way to dismiss it.
   Hiding it in CSS rather than in `pmap.js` keeps the behaviour correct when the
   viewport is resized across the breakpoint. Each marker is a link, so tapping
   one still opens its case study. */
@media (max-width: 781px) {
	.pmap__tip {
		display: none;
	}
}

/* ============================================================
   LEGAL
   Prose column for the policy pages. The rules reach the markup an external
   privacy service injects — iubenda, Cookiebot — as well as anything typed
   into the page, so they are element selectors inside `.legal` rather than
   block classes.
   ============================================================ */

.wp-block-post-content.legal {
	max-width: 47.5rem;
	margin-inline: 0;
}

.legal h2 {
	margin-block: 2.75rem 1rem;
	font-size: clamp(1.375rem, 2.4vw, 1.875rem);
	line-height: 1.2;
	color: var(--wp--preset--color--navy);
}

.legal > :first-child {
	margin-block-start: 0;
}

.legal h3 {
	margin-block: 2rem 0.75rem;
	font-size: clamp(1.125rem, 2vw, 1.375rem);
	line-height: 1.25;
	color: var(--wp--preset--color--contrast);
}

.legal p {
	margin-block: 0 1.125rem;
	color: var(--wp--preset--color--muted);
}

.legal ul {
	margin-block: 0 1.125rem;
	padding-inline-start: 1.375rem;
	list-style: disc;
	color: var(--wp--preset--color--muted);
}

.legal li {
	margin-block-end: 0.5rem;
}

.legal a {
	color: var(--wp--preset--color--navy);
	text-decoration: underline;
	text-underline-offset: 2px;
}

.legal a:hover {
	color: var(--wp--preset--color--signal);
}

/* Where the privacy service's own snippet goes. Until something is pasted in,
   the slot says so rather than collapsing to nothing. */
.legal-embed {
	margin-block: 0.5rem;
}

.legal-embed:empty::before {
	content: "Custom code del servizio privacy — da inserire qui.";
	display: block;
	padding: 1.75rem 1.5rem;
	border: 1px dashed var(--wp--preset--color--line);
	border-radius: 2px;
	background-color: var(--wp--preset--color--surface);
	font-size: 0.875rem;
	text-align: center;
	color: var(--wp--preset--color--muted);
}

.legal__updated {
	margin-block-start: 2.75rem;
	padding-block-start: 1.25rem;
	border-block-start: 1px solid var(--wp--preset--color--line);
	font-size: 0.8125rem;
	color: var(--wp--preset--color--muted);
}

/* ============================================================
   404
   ============================================================ */

.err {
	display: flex;
	align-items: center;
	min-height: calc(100vh - var(--aac--header-height));
	min-height: calc(100svh - var(--aac--header-height));
	text-align: center;
}

/* Doubled up with the block's class: the group is `alignwide`, so core's
   `<container> > .alignwide` rule sets the width and a lone class cannot
   outrank it. */
.wp-block-group.err__inner {
	/* A flex item would otherwise shrink to its content rather than filling the
	   column up to the cap. */
	width: 100%;
	max-width: 40rem;
	margin-inline: auto;
}

/* Muted digits with a sky nought, which is how the reference renders — its own
   `.err__code` asks for navy but the later `.err p` rule outranks it. Kept as
   rendered: unlike the accident on the case-study eyebrow, this one reads as
   the intended treatment. */
.err__code {
	margin-block: 0 2rem;
	font-size: clamp(5.5rem, 18vw, 11.25rem);
	font-weight: 700;
	line-height: 1;
	letter-spacing: -0.03em;
	color: var(--wp--preset--color--muted);
}

.err__title {
	margin-block: 0.5rem 1rem;
	font-size: clamp(1.5rem, 3.4vw, 2.375rem);
	color: var(--wp--preset--color--contrast);
}

.err__text {
	max-width: 44ch;
	margin-block: 0 2rem;
	margin-inline: auto;
	color: var(--wp--preset--color--muted);
}
