/* Fourways Group, Pass 1 clone of the GM Construction system.
   Structure: viz/fourways-concrete-ref (GM Construction teardown).
   Every color/type/shape token: design/brands/fourways-concrete.md (the kit).
   Reference hex values never ship. Zero box-shadows on the page. */

/* ---------- tokens (kit, provenance-commented) ---------- */
:root {
	--canvas: #171717;             /* measured: client civils-page dark, company-ref/tokens.json */
	--surface: #232323;            /* derived: canvas lifted one step, mirrors reference canvas-to-surface interval */
	--surface-light: #f4f4f4;      /* measured: client site canvas */
	--surface-light-card: #ffffff; /* measured: client surface */
	--ink: #fefefe;                /* reference-structure white; matches client hero h1 #ffffff */
	--ink-body: #3c3a47;           /* measured: client ink */
	--ink-muted: #a0a0a3;          /* derived: neutral, desaturated from client line #c9c9c9 */
	--line: #c9c9c9;               /* measured: client line */
	--accent: #821206;             /* measured: client deep brand red, chroma-proven S 0.912 */
	--accent-hover: #9a1a0c;       /* derived: accent lifted one hover step per reference interval */
	--accent-deep: #79201a;        /* measured: client heading red; large filled bands */
	--accent-gold: #af860a;        /* measured: client gold; RESERVED, off by default */
	--space-base: 40px;            /* reference structure: section pads 120/80/40 */
	--radius-chip: 2px;            /* reference structure: flat system, chips only */
	--radius-card: 16px;           /* operator amendment 2026-08-27 (Alex): rounded shape system for interactive surfaces; menu first, swept across cards and carousels in the facelift phases */
	--radius-media: 12px;          /* same amendment: media insets inside rounded cards */
	--radius-pill: 999px;          /* same amendment: round controls (close, dots, chips-as-pills) */
	--ease-reveal: cubic-bezier(0.5, 0, 0, 1); /* reference structure: ScrollReveal 4 default ease */
}

/* ---------- fonts (client's own face, OFL, self-hosted) ---------- */
@font-face {
	font-family: 'Poppins';
	src: url('../fonts/poppins-400.woff2') format('woff2');
	font-weight: 400;
	font-style: normal;
	font-display: swap;
}
@font-face {
	font-family: 'Poppins';
	src: url('../fonts/poppins-600.woff2') format('woff2');
	font-weight: 600;
	font-style: normal;
	font-display: swap;
}
@font-face {
	font-family: 'Poppins';
	src: url('../fonts/poppins-700.woff2') format('woff2');
	font-weight: 700;
	font-style: normal;
	font-display: swap;
}

/* ---------- base ---------- */
*, *::before, *::after { box-sizing: border-box; }
/* [hidden] must always win. Any author rule that sets `display` on an element
   (`.case-panel { display: grid }`) silently beats the UA's own
   `[hidden] { display: none }`, because author styles outrank the UA sheet
   whatever the specificity. JS that toggles `.hidden` then looks correct in
   the DOM while the element stays on screen. MEASURED 2026-08-28: all eight
   civils case studies had been rendering since the explorer shipped, with
   seven of them carrying the attribute; the probes read the attribute and
   reported a clean pass. This rule closes the whole class. */
[hidden] { display: none !important; }
html { font-size: 100%; }
body {
	margin: 0;
	padding: 0;
	background: var(--canvas);
	color: var(--ink-muted);
	font-family: 'Poppins', 'Helvetica Neue', Helvetica, Arial, sans-serif;
	font-weight: 400;
	font-size: 1rem;         /* kit: 16px floor for Zim mobile readability */
	line-height: 1.5;
	overflow-x: clip;        /* doctrine: clip, never hidden, on body */
	-webkit-font-smoothing: antialiased;
}
h1, h2, h3, p, ul { margin: 0; }
ul { padding: 0; list-style: none; }
a { text-decoration: none; color: inherit; }
img { max-width: 100%; display: block; }
button {
	font: inherit;
	color: inherit;
	background: none;
	border: none;
	padding: 0;
	cursor: pointer;
}
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ---------- type utilities (reference scale, kit face) ---------- */
.text-xs { font-size: 0.75rem; }
.text-sm { font-size: 0.875rem; }
.text-lg { font-size: 1.25rem; }
.text-2xl { font-size: 1.375rem; }
.text-3xl { font-size: 1.5rem; }
.text-5xl { font-size: 2.25rem; }
@media (min-width: 640px) {
	.text-2xl { font-size: 1.75rem; }
	.text-3xl { font-size: 2rem; }
	.text-5xl { font-size: 3.25rem; }
}
@media (min-width: 1024px) {
	.text-2xl { font-size: 2rem; }
	.text-3xl { font-size: 2.5rem; }
	.text-5xl { font-size: 4rem; }  /* kit: hero display 4rem desktop */
}
.text-bold { font-weight: 600; }
.text-uppercase { text-transform: uppercase; }
.tracking-wide { letter-spacing: 0.1em; }
.leading-tight { line-height: 1.25; }
.leading-tighter { line-height: 1.1; }
.text-white { color: var(--ink); }
.text-black { color: var(--canvas); }
.text-gray-lt { color: var(--line); }
.text-gray-md { color: var(--ink-muted); }

/* eyebrow voice: 14px 600 uppercase 0.1em with the 2rem accent dash (kit) */
.line-heading { display: inline-flex; align-items: center; }
.line-heading::before {
	content: '';
	width: 2rem;
	height: 2px;
	margin: 0 0.75rem 0 0;
	background: var(--accent);
}

/* ---------- layout ---------- */
.grid-container {
	max-width: 87.5rem;
	margin: 0 auto;
	padding-right: 0.75rem;
	padding-left: 0.75rem;
}
@media (min-width: 640px) {
	.grid-container { padding-right: 1.25rem; padding-left: 1.25rem; }
}
.show-for-medium { display: none; }
@media (min-width: 640px) {
	.show-for-medium { display: block; }
}

/* ---------- buttons (kit shape roles: radius 0, flat, scaleX accent wipe) ---------- */
.btn {
	position: relative;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	height: 3rem;
	padding: 0 2.5rem;
	font-weight: 600;
	font-size: 0.875rem;
	text-align: center;
	text-transform: uppercase;
	letter-spacing: 0.1em;
	border-radius: var(--radius-media); /* operator amendment 2026-08-27: rounded system */
	overflow: hidden;                   /* clips the ::before wipe to the rounded shape */
	transition: color 0.3s ease;
}
@media (min-width: 640px) {
	.btn { height: 3.5rem; }
}
.btn span { position: relative; z-index: 1; }
.btn::before {
	content: '';
	position: absolute;
	z-index: 0;
	top: 0;
	left: 0;
	bottom: 0;
	width: 100%;
	transform-origin: right;
	transform: scaleX(0);
	transition: transform 0.3s ease;
}
.btn:hover::before {
	transform-origin: left;
	transform: scaleX(1);
}
.btn.btn-stroke { border: 1px solid; }
.btn.btn-stroke.btn-white { color: var(--ink); border-color: var(--ink); }
.btn.btn-stroke.btn-white::before { background: var(--accent); } /* kit: wipe fill = accent */
.btn.btn-stroke.btn-white:hover { color: var(--ink); border-color: var(--accent); }
.btn.btn-stroke.btn-black { color: var(--canvas); border-color: var(--canvas); }
.btn.btn-stroke.btn-black::before { background: var(--accent); } /* kit: wipe fill = accent */
.btn.btn-stroke.btn-black:hover { color: var(--ink); border-color: var(--accent); }
.btn.btn-primary { color: var(--ink); background: var(--accent); }
.btn.btn-primary:hover { background: var(--accent-hover); }

/* ---------- reveal system (reference: 40px rise, 600ms, 100ms stagger) ---------- */
html.js .fade-up {
	opacity: 0;
	transform: translateY(40px);
	transition: opacity 0.6s var(--ease-reveal), transform 0.6s var(--ease-reveal);
	transition-delay: var(--reveal-delay, 0s);
}
html.js .fade-up.is-revealed { opacity: 1; transform: none; }
html.js .line-heading.fade-up { display: inline-flex; } /* keep dash layout while hidden */

/* ---------- header (fixed overlay bar, shrink on scroll) ---------- */
.site-header {
	position: fixed;
	z-index: 100;
	top: 0;
	left: 0;
	width: 100%;
	padding: 0 5vw;
	display: grid;
	grid-template-rows: 4.5rem;     /* 72px at 375, reference structure */
	transition: grid-template-rows 0.6s ease;
}
@media (min-width: 640px) { .site-header { grid-template-rows: 8rem; } }
@media (min-width: 1024px) { .site-header { grid-template-rows: 10rem; } } /* 160px desktop */
.site-header::after {
	content: '';
	position: absolute;
	top: 0; right: 0; bottom: 0; left: 0;
	background: var(--surface-light-card);
	transform: translateY(-100%);
	transition: transform 0.6s ease;
}
.header-inner {
	position: relative;
	z-index: 1;
	display: flex;
	align-items: center;
	justify-content: space-between;
	height: 100%;                   /* fills the animated header grid track */
}
.header-inner .logo { display: inline-block; }
.header-inner .logo img { width: auto; height: 2.5rem; }
@media (min-width: 640px) { .header-inner .logo img { height: 3.5rem; } }
.header-inner .logo .logo-on-light { display: none; }

.menu-trigger {
	display: inline-flex;
	flex-direction: column;
	align-items: flex-end;
	justify-content: center;
	width: 2rem;
	height: 2rem;
}
.menu-trigger .burger-top,
.menu-trigger .burger-middle,
.menu-trigger .burger-bottom {
	display: block;
	height: 2px;
	background-color: var(--ink);
	transition: background-color 0.3s ease;
}
.menu-trigger .burger-top, .menu-trigger .burger-bottom { width: 1.75rem; }
.menu-trigger .burger-middle { width: 1.25rem; margin: 0.25rem 0; }

.header-nav { display: none; }
@media (min-width: 1024px) {
	.menu-trigger { display: none; }
	.header-nav { display: block; }
}
.header-nav ul {
	display: flex;
	font-weight: 600;
	font-size: 0.875rem;
	text-transform: uppercase;
	letter-spacing: 0.1em;
}
.header-nav ul li { position: relative; margin: 0 1.25rem; }
.header-nav ul li:last-child { margin-right: 0; }
.header-nav ul li a {
	display: inline-flex;
	align-items: center;
	height: 2.25rem;
	opacity: 0.75;
	color: var(--ink);
	transition: color 0.6s ease, opacity 0.3s ease;
}
/* Active / hover marker. The reference stylesheet's rule (a 2px x 3rem vertical
   tick at bottom:100% of the link) has NEVER rendered on the live reference,
   because the reference serves an EMPTY header nav; it is unverified CSS, not
   faithful CSS, and it must be eye-checked here. Eye check at 1280: shortened to
   1rem it still floats 12px clear of the glyph tops, reading as a stray red mark
   detached from its label. Re-expressed as the 2px accent rule the rest of the
   system already uses for this job (the eyebrow's 2rem x 2px dash, the drawer's
   active dash), seated directly under the label. One marker idiom site-wide. */
.header-nav ul li a::before {
	content: '';
	position: absolute;
	top: 100%;
	right: 0;
	left: 0;
	height: 2px;
	background: var(--ink);
	transform-origin: right;
	transform: scaleX(0);
	transition: transform 0.3s ease;
}
.header-nav ul li a:hover { opacity: 1; }
.header-nav ul li a:hover::before { transform-origin: left; transform: scaleX(1); }

/* shrunk state: white bar, dark chrome (reference behavior contract) */
.site-header.header-shrunk::after { transform: translateY(0); }
/* The reference scopes its shrunk track to its own breakpoints and carries NO shrunk
   rule below 40em, so below 640 its header holds at 4.5rem through the whole scroll.
   Driven on the reference mirror at 375, 414 and 639: rest 72px, scrolled 72px, delta 0.
   Ported without the query this rule fired at every width and grew ours 72 to 80, which
   is the opposite of what the state name says. The white bar still slides in below 640,
   which is what the reference does (its ::after rule carries no media query either). */
@media (min-width: 640px) { .site-header.header-shrunk { grid-template-rows: 5rem; } }
@media (min-width: 1024px) { .site-header.header-shrunk { grid-template-rows: 6rem; } } /* 96px */
.site-header.header-shrunk .logo .logo-on-dark { display: none; }
.site-header.header-shrunk .logo .logo-on-light { display: block; }
.site-header.header-shrunk .menu-trigger .burger-top,
.site-header.header-shrunk .menu-trigger .burger-middle,
.site-header.header-shrunk .menu-trigger .burger-bottom { background-color: var(--canvas); }
.site-header.header-shrunk .header-nav ul li a { color: var(--canvas); }
.site-header.header-shrunk .header-nav ul li a::before { background: var(--canvas); }

/* ---------- mobile menu drawer ---------- */
/* Drawer redesigned 2026-08-27 (operator critique 7, IEC anatomy in the Fourways
   skin): the page blurs behind a floating dark card, links stagger in with the
   accent-underline idiom, promo card at the foot. Kit shadow law holds: the lift
   is border + backdrop blur, zero box-shadows. JS contract unchanged
   (#menu/.menu-mask/.menu-trigger/.menu-close, is-open, inert). */
.menu {
	position: fixed;
	z-index: 250;
	top: 5.5rem;
	right: 1rem;
	left: 1rem;
	display: flex;
	flex-direction: column;
	max-width: 24rem;
	max-height: calc(100vh - 6.5rem);
	max-height: calc(100svh - 6.5rem);
	margin-left: auto;
	padding: 1.25rem 1.5rem 1.5rem;
	overflow: auto;
	background: var(--surface);
	border: 1px solid rgba(254, 254, 254, 0.08);
	border-radius: var(--radius-card);
	opacity: 0;
	transform: translateY(-0.5rem) scale(0.98);
	transition: transform 0.35s cubic-bezier(0.22, 1, 0.36, 1), opacity 0.25s ease, visibility 0s linear 0.35s;
	visibility: hidden;
}
.menu.is-open {
	opacity: 1;
	transform: none;
	visibility: visible;
	transition: transform 0.35s cubic-bezier(0.22, 1, 0.36, 1), opacity 0.25s ease;
}
.menu-head {
	display: flex;
	align-items: center;
	justify-content: space-between;
}
.menu-eyebrow {
	font-size: 0.75rem;
	font-weight: 600;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--ink-muted);
}
.menu-close {
	position: relative;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 2.25rem;
	height: 2.25rem;
	border: 1px solid rgba(254, 254, 254, 0.16);
	border-radius: var(--radius-pill);
	transition: border-color 0.2s ease, transform 0.2s ease;
}
.menu-close:hover { border-color: rgba(254, 254, 254, 0.4); transform: rotate(90deg); }
.menu-close .x-a, .menu-close .x-b {
	position: absolute;
	width: 0.875rem;
	height: 2px;
	background: var(--ink);
}
.menu-close .x-a { transform: rotate(45deg); }
.menu-close .x-b { transform: rotate(-45deg); }
.menu-nav { padding: 1rem 0 1.25rem; }
.menu-nav ul li + li { margin-top: 0.25rem; }
.menu-nav a {
	position: relative;
	display: inline-block;
	padding: 0.375rem 0;
	font-size: 1.375rem;
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.06em;
	color: var(--ink);
}
.menu-nav a::after {
	content: '';
	position: absolute;
	left: 0;
	bottom: 0.125rem;
	width: 100%;
	height: 2px;
	background: var(--accent);
	transform: scaleX(0);
	transform-origin: left;
	transition: transform 0.3s var(--ease-reveal);
}
.menu-nav a:hover::after, .menu-nav a:focus-visible::after { transform: scaleX(1); }
.menu-nav li { opacity: 0; transform: translateY(0.5rem); }
.menu.is-open .menu-nav li {
	opacity: 1;
	transform: none;
	transition: opacity 0.4s ease, transform 0.4s var(--ease-reveal);
}
.menu.is-open .menu-nav li:nth-child(1) { transition-delay: 0.05s; }
.menu.is-open .menu-nav li:nth-child(2) { transition-delay: 0.1s; }
.menu.is-open .menu-nav li:nth-child(3) { transition-delay: 0.15s; }
.menu.is-open .menu-nav li:nth-child(4) { transition-delay: 0.2s; }
.menu.is-open .menu-nav li:nth-child(5) { transition-delay: 0.25s; }
.menu.is-open .menu-nav li:nth-child(6) { transition-delay: 0.3s; }
.menu.is-open .menu-nav li:nth-child(7) { transition-delay: 0.35s; }
.menu-foot {
	margin-top: auto;
	padding-top: 1rem;
	border-top: 1px solid rgba(254, 254, 254, 0.1);
}
.menu-contact {
	display: flex;
	flex-wrap: wrap;
	gap: 0.25rem 1.25rem;
	margin-bottom: 1rem;
}
.menu-contact a {
	font-size: 0.875rem;
	font-weight: 600;
	color: var(--ink-muted);
	transition: color 0.2s ease;
}
.menu-contact a:hover, .menu-contact a:focus-visible { color: var(--ink); }
.menu-promo {
	position: relative;
	display: flex;
	align-items: center;
	gap: 1rem;
	padding: 0.75rem;
	border: 1px solid rgba(254, 254, 254, 0.1);
	border-radius: var(--radius-media);
	overflow: hidden;
	transition: border-color 0.25s ease;
}
.menu-promo:hover, .menu-promo:focus-visible { border-color: rgba(254, 254, 254, 0.28); }
.menu-promo-media {
	flex: 0 0 4.5rem;
	height: 4.5rem;
	border-radius: calc(var(--radius-media) - 4px);
	background: var(--canvas) center / cover no-repeat;
}
/* the promo photo loads on first open only; a closed drawer costs zero image
   bytes (it was fetching 39KB eagerly on every route) */
.menu.is-open .menu-promo-media {
	background-image: url('../assets/menu-promo.jpg');
}
.menu.is-open .menu-promo-media {
	background-image: image-set(url('../assets/menu-promo.avif') type('image/avif'), url('../assets/menu-promo.jpg') type('image/jpeg'));
}
.menu-promo-text {
	display: flex;
	flex-direction: column;
	gap: 0.125rem;
}
.menu-promo-title {
	display: inline-flex;
	align-items: center;
	font-size: 1rem;
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.08em;
	color: var(--ink);
}
.menu-promo-arrow {
	position: relative;
	width: 1rem;
	height: 2px;
	margin-left: 0.5rem;
	background: var(--accent);
	transition: transform 0.25s ease;
}
.menu-promo-arrow::after {
	content: '';
	position: absolute;
	top: 50%;
	right: -1px;
	width: 0.4rem;
	height: 0.4rem;
	border-top: 2px solid var(--accent);
	border-right: 2px solid var(--accent);
	transform: translateY(-50%) rotate(45deg);
}
.menu-promo:hover .menu-promo-arrow { transform: translateX(4px); }
.menu-promo-line { font-size: 0.8125rem; color: var(--ink-muted); }
.menu-mask {
	position: fixed;
	z-index: 200;
	top: 0; right: 0; bottom: 0; left: 0;
	background: rgba(23, 23, 23, 0.55); /* kit canvas over half, reference mask interval */
	-webkit-backdrop-filter: blur(8px);
	backdrop-filter: blur(8px);
	opacity: 0;
	transition: opacity 0.4s ease;
}
.menu-mask.is-open { opacity: 1; }

/* ---------- hero (full-viewport dark slideshow, left copy, bottom-anchored) ---------- */
.home-hero {
	position: relative;
	display: flex;
	align-items: flex-end; /* mobile art direction 2026-08-27: type pinned low, picture above */
	min-height: 100vh;
	min-height: 100svh; /* phones: first-paint viewport, no URL-bar overshoot */
	padding: 0 5vw;
	background: var(--canvas);
}
@media (min-width: 640px) {
	.home-hero { align-items: center; min-height: 100vh; }
}
@media (min-width: 1024px) {
	.home-hero { align-items: flex-end; }
}
.home-hero-inner {
	position: relative;
	z-index: 1;
	width: 100%;
	padding: 7rem 0 5rem 0;
}
@media (min-width: 1024px) {
	.home-hero-inner { padding: 10rem 0 7.5rem 0; }
}
.home-hero-content { width: 100%; max-width: 45rem; }
.home-hero-content h2 { font-weight: 700; } /* kit: 700 reserved for hero display */
.line-heading + .text-5xl { margin-top: 1.5rem; }

.home-hero-play {
	display: inline-flex;
	align-items: center;
	margin-top: 1.5rem;
}
.home-hero-play .icon {
	position: relative;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 2rem;
	height: 2rem;
	border-radius: 50%; /* kit: circles for play buttons only */
	background: var(--accent);
}
@media (min-width: 640px) { .home-hero-play .icon { width: 3rem; height: 3rem; } }
@media (min-width: 1024px) { .home-hero-play .icon { width: 4rem; height: 4rem; } }
.home-hero-play .icon::before {
	content: '';
	position: absolute;
	inset: 0;
	z-index: 0;
	border-radius: 50%;
	background: var(--accent);
	transform: scale(1);
	transition: transform 0.3s ease;
}
.home-hero-play:hover .icon::before { transform: scale(1.2); }
.home-hero-play .icon::after {
	content: '';
	position: relative;
	z-index: 1;
	width: 0;
	height: 0;
	margin-left: 2px;
	border-style: solid;
	border-width: 6px 0 6px 10px;
	border-color: transparent transparent transparent var(--ink);
}
@media (min-width: 1024px) {
	.home-hero-play .icon::after { border-width: 8px 0 8px 13px; }
}
.home-hero-play .text {
	margin-left: 0.75rem;
	font-weight: 600;
	font-size: 0.875rem;
	text-transform: uppercase;
	letter-spacing: 0.1em;
	color: var(--ink);
}
@media (min-width: 1024px) { .home-hero-play .text { margin-left: 1.5rem; } }

.home-hero-slides {
	position: absolute;
	z-index: 0;
	top: 0; right: 0; bottom: 0; left: 0;
	overflow: hidden;
}
/* catalog: 104 fx-slider skin=fourways-dark (COMPONENT-GAPS 1, lessons.json) */
.home-hero-slides .slide {
	position: absolute;
	inset: 0;
	opacity: 0;
	background-position: center center;
	background-repeat: no-repeat;
	background-size: cover;
}
.home-hero-slides .slide.is-active { opacity: 0.3; } /* reference: slides dimmed to 0.3 over canvas */
/* LCP gate (2026-08-27): under JS the active slide waits at 0 until its file has
   decoded (main.js adds .hero-ready), so the headline is the largest first paint
   on throttled mobile CPUs; the slide then fades in on the slider's own timing
   language. No-JS never sees these rules and paints the slide statically. */
html.js .home-hero[data-hero]:not(.hero-ready) .home-hero-slides .slide.is-active { opacity: 0; }
html.js .home-hero[data-hero].hero-ready .home-hero-slides .slide.is-active { transition: opacity 0.6s ease; }
/* Mobile art direction (operator critique 2026-08-27): portrait crops carry the
   scene, image lifted to 0.45, bottom scrim keeps the type on solid ground.
   Scrim paints after the slides at equal z, under the dots/progress (z2). */
@media (max-width: 639px) {
	.home-hero-slides .slide.is-active { opacity: 0.45; }
	.home-hero-slides::after {
		content: '';
		position: absolute;
		inset: 0;
		z-index: 1;
		background: linear-gradient(to top, rgba(23, 23, 23, 0.82) 0%, rgba(23, 23, 23, 0.2) 44%, rgba(23, 23, 23, 0) 62%);
	}
	.home-hero-inner { padding-bottom: 5.5rem; }
}
.home-hero-slides .slide.is-enter-down,
.home-hero-slides .slide.is-enter-up { z-index: 1; }
.home-hero-slides .slide.is-exit-down,
.home-hero-slides .slide.is-exit-up { z-index: 0; }
.home-hero-slides .slide.is-enter-down { animation: hero-slide-enter-down 0.64s cubic-bezier(0.86, 0, 0.07, 1) forwards; }
.home-hero-slides .slide.is-enter-up { animation: hero-slide-enter-up 0.64s cubic-bezier(0.86, 0, 0.07, 1) forwards; }
.home-hero-slides .slide.is-exit-down { animation: hero-slide-exit-down 0.64s cubic-bezier(0.86, 0, 0.07, 1) forwards; }
.home-hero-slides .slide.is-exit-up { animation: hero-slide-exit-up 0.64s cubic-bezier(0.86, 0, 0.07, 1) forwards; }
@keyframes hero-slide-enter-down {
	from { clip-path: inset(100% 0 0 0); opacity: 0.3; }
	to { clip-path: inset(0 0 0 0); opacity: 0.3; }
}
@keyframes hero-slide-enter-up {
	from { clip-path: inset(0 0 100% 0); opacity: 0.3; }
	to { clip-path: inset(0 0 0 0); opacity: 0.3; }
}
/* repair pass 2, defect 3: exit holds 0.3, clipped by the complement of the entering wipe */
@keyframes hero-slide-exit-down {
	from { transform: translateY(0); clip-path: inset(0 0 0 0); opacity: 0.3; }
	to { transform: translateY(-5%); clip-path: inset(5% 0 95% 0); opacity: 0.3; }
}
@keyframes hero-slide-exit-up {
	from { transform: translateY(0); clip-path: inset(0 0 0 0); opacity: 0.3; }
	to { transform: translateY(5%); clip-path: inset(95% 0 5% 0); opacity: 0.3; }
}
/* catalog: 104 fx-slider, progress rule; track alpha 0.302 = source txtColor+4D */
.hero-progress {
	position: absolute;
	z-index: 2;
	top: 50%;
	right: 0;
	width: 3rem;
	height: 1px;
	margin-top: 44px;
	background: rgba(254, 254, 254, 0.302);
}
.hero-progress-fill {
	display: block;
	width: 25%;
	height: 100%;
	margin-left: auto;
	background: var(--ink);
	transition: width 0.3s cubic-bezier(0.65, 0, 0.35, 1);
}
.hero-dots {
	position: absolute;
	z-index: 2;
	top: 50%;
	right: 0;
	display: flex;
	flex-direction: column;
	width: 3rem;
	transform: translateY(-50%);
	overflow: hidden;
}
.hero-dots button {
	display: block;
	width: 3rem;
	height: 2px;
	margin: 0.5rem 0;
	background: var(--ink);
	opacity: 0.5;
	transform-origin: right;
	transform: scaleX(0.5);
	transition: all 0.3s ease;
}
.hero-dots button.is-active { opacity: 1; transform: scaleX(1); }

/* ---------- about (raised panel split: copy left, image right) ---------- */
/* catalog: 340 background-pattern skin=fourways-dark, "diagonal" tile verbatim at size
   40, stroke 1, --ink, opacity 0.07 (COMPONENT-GAPS 5) */
.home-about {
	display: flex;
	flex-direction: column;
	align-items: center;
	padding: 2.5rem 5vw;
	background-color: var(--surface);
	background-image: url("data:image/svg+xml;utf8,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20width%3D'40'%20height%3D'40'%20viewBox%3D'0%200%2040%2040'%20fill%3D'none'%3E%3Cline%20x1%3D'0'%20y1%3D'40'%20x2%3D'40'%20y2%3D'0'%20stroke%3D'%23fefefe'%20stroke-width%3D'1'%20stroke-opacity%3D'0.07'%20stroke-linecap%3D'square'%2F%3E%3Cline%20x1%3D'-40'%20y1%3D'40'%20x2%3D'0'%20y2%3D'0'%20stroke%3D'%23fefefe'%20stroke-width%3D'1'%20stroke-opacity%3D'0.07'%20stroke-linecap%3D'square'%2F%3E%3Cline%20x1%3D'40'%20y1%3D'40'%20x2%3D'80'%20y2%3D'0'%20stroke%3D'%23fefefe'%20stroke-width%3D'1'%20stroke-opacity%3D'0.07'%20stroke-linecap%3D'square'%2F%3E%3C%2Fsvg%3E");
	background-position: center bottom; /* reference: same anchor as its monogram */
	background-repeat: repeat;
}
@media (min-width: 640px) { .home-about { padding: 5rem 5vw; } }
@media (min-width: 1024px) {
	.home-about { flex-direction: row-reverse; padding: 7.5rem 0; }
}
.home-about .image {
	width: 100%;
	height: 50vw;
	max-height: 70vh;
	margin: 0 0 2.5rem 0;
	background-color: var(--canvas);
	background-position: center center;
	background-repeat: no-repeat;
	background-size: cover;
}
@media (min-width: 640px) { .home-about .image { margin: 0 0 3.75rem 0; } }
@media (min-width: 1024px) {
	.home-about .image { width: 40%; margin: 0; }
}
.home-about .text {
	display: flex;
	justify-content: center;
	width: 100%;
}
@media (min-width: 1024px) { .home-about .text { width: 60%; } }
.home-about .text .inner { width: 100%; max-width: 35rem; }
@media (min-width: 1024px) { .home-about .text .inner { max-width: 30rem; } }
.line-heading + .text-3xl { margin-top: 1rem; }
.about-body { margin-top: 1rem; }
.home-about .btn { margin-top: 1.5rem; }

/* ---------- services band (four hover panels) ---------- */
/* Services band re-expressed 2026-08-27 (operator: homepage joins the facelift
   language). The reference's idle-flat hover-reveal band (recorded Pass 2 as
   reference-faithful, upgrade proposal COMPONENT-GAPS 13) is superseded on
   operator direction: the four division photographs now carry the band as
   rounded cards, always visible, gradient-grounded type, arrow idiom, hover
   lift. The old interleaved .home-services-image reveal layers are gone from
   markup and main.js. */
.home-services {
	display: grid;
	grid-template-columns: 1fr;
	gap: 1rem;
	padding: calc(var(--space-base) * 1.5) 5vw;
	background: var(--canvas);
}
@media (min-width: 640px) { .home-services { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1280px) { .home-services { grid-template-columns: repeat(4, 1fr); } }
.home-services .service-panel {
	position: relative;
	display: block;
	aspect-ratio: 3 / 4;
	color: var(--ink);
	text-transform: uppercase;
	border: 1px solid rgba(254, 254, 254, 0.09);
	border-radius: var(--radius-card);
	overflow: hidden;
	transition: border-color 0.25s ease, transform 0.25s var(--ease-reveal);
}
@media (min-width: 640px) and (max-width: 1279px) {
	.home-services .service-panel { aspect-ratio: 4 / 3; }
}
.home-services .service-panel:hover,
.home-services .service-panel:focus-visible {
	border-color: rgba(254, 254, 254, 0.32);
	transform: translateY(-3px);
}
.home-services .service-panel .image {
	position: absolute;
	z-index: 0;
	top: 0; right: 0; bottom: 0; left: 0;
	opacity: 0.6;
	background-position: center center;
	background-repeat: no-repeat;
	background-size: cover;
	transition: transform 0.5s var(--ease-reveal), opacity 0.3s ease;
}
.home-services .service-panel:hover .image { transform: scale(1.05); opacity: 0.75; }
.home-services .service-panel::after {
	content: '';
	position: absolute;
	inset: 0;
	background: linear-gradient(to top, rgba(23, 23, 23, 0.85), rgba(23, 23, 23, 0.05) 55%);
}
.home-services .service-panel .inner {
	position: absolute;
	inset: 0;
	z-index: 1;
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	justify-content: flex-end;
	gap: 0.625rem;
	padding: 1.5rem;
	text-align: left;
}
.home-services .service-panel .inner h2 {
	font-weight: 700;
	font-size: 1.25rem;
	letter-spacing: 0.04em;
}
@media (min-width: 640px) { .home-services .service-panel .inner h2 { font-size: 1.375rem; } }
/* the arrow idiom stands in for the old hover-only button; the whole panel is the link */
.home-services .service-panel .inner .btn { display: none; }
.home-services .service-panel .inner::after {
	content: '';
	position: relative;
	width: 1.25rem;
	height: 2px;
	background: var(--accent);
	transition: width 0.25s ease;
}
.home-services .service-panel:hover .inner::after { width: 2.25rem; }

/* ---------- projects (single light band, 3-up carousel) ---------- */
.content { padding: 2.5rem 5vw; }
@media (min-width: 640px) { .content { padding: 5rem 5vw; } }
@media (min-width: 1024px) { .content { padding: 7.5rem 5vw; } }
.bg-gray-ltr { background-color: var(--surface-light); }
.bg-gray-ltr .line-heading { color: var(--canvas); }

.home-projects-header {
	display: flex;
	align-items: center;
	justify-content: space-between;
	margin-bottom: 1rem;
}
.view-all { transition: color 0.3s ease; }
.view-all:hover { color: var(--canvas); }

.related-projects { position: relative; }
/* touch-action pan-y: the browser keeps vertical panning, the track keeps the
   horizontal gesture. Without it the browser claims a horizontal swipe and fires
   pointercancel, so the carousel could not be swiped on any touch device at any
   width (measured 375, 768, 1280: translateX never left 0). */
.carousel-viewport { overflow: hidden; margin: 0 -0.75rem; touch-action: pan-y; }
@media (min-width: 640px) { .carousel-viewport { margin: 0 -1.25rem; } }
.card-list {
	display: flex;
	transition: transform 0.3s ease; /* reference: slick speed 300ms, discrete steps */
	touch-action: pan-y;
}
/* catalog: 088 dragable-carousel skin=fourways-light, release snap only; is-dragging is
   declared last so a finger put down mid-snap wins on equal specificity */
.card-list.is-snapping { transition: transform 0.6s cubic-bezier(0.25, 1, 0.25, 1); }
.card-list.is-dragging { transition: none; }
.card-list .card-cell {
	flex: 0 0 100%;
	max-width: 100%;
	padding: 0.75rem;
}
@media (min-width: 640px) {
	.card-list .card-cell { flex-basis: 50%; max-width: 50%; padding: 1.25rem; }
}
@media (min-width: 1024px) {
	.card-list .card-cell { flex-basis: 33.3333%; max-width: 33.3333%; }
}
.card-surface {
	display: flex;
	flex-direction: column;
	height: 100%;
	overflow: hidden;
	border-radius: 0;               /* kit: card radius 0, no border, filled, no shadow */
	background: var(--surface-light-card);
}
.card-surface .image {
	position: relative;
	z-index: 1;
	padding-top: 80%;
	background: var(--canvas);
}
.card-surface .image .inner {
	position: absolute;
	inset: 0;
	opacity: 1;
	background-position: center center;
	background-repeat: no-repeat;
	background-size: cover;
	transition: opacity 0.3s ease;
}
.card-surface .text {
	position: relative;
	z-index: 2;
	flex: 1;
	padding: 2rem 1rem 1rem 1rem;
	text-align: center;
	background: var(--surface-light-card);
	transform: translateY(0);
	transition: transform 0.3s ease;
}
@media (min-width: 640px) { .card-surface .text { padding: 2rem; } }
.category-list {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	margin-top: 1rem;
}
.chip {
	margin: 0.125rem;
	padding: 0.25rem 0.625rem;
	font-size: 0.75rem;
	color: var(--ink-muted);
	border-radius: var(--radius-pill); /* operator amendment 2026-08-27: chips read as pills */
	border: 1px solid var(--line);
	background: transparent;
}
.card-surface .text .bottom { padding: 2rem 0 0 0; }
/* The reference hides the card CTA below the fold of the card and slides the text
   panel up on hover (probed on the mirror: .text position relative + transform
   0.3s, .bottom absolute at top:100%). Reproduced, but gated on (hover: hover):
   the un-gated rule fired from 640px up, so on a TOUCH tablet the "View project"
   button was parked outside the card with no way to reveal it. Pointer devices
   keep the reference behaviour; touch keeps the button in flow, as it already is
   below 640. */
@media (min-width: 640px) and (hover: hover) {
	.card-surface .text .bottom {
		position: absolute;
		top: calc(100% + 2px);
		right: 0;
		left: 0;
		padding: 0 2rem 2rem 2rem;
	}
	.card-surface .text .bottom .btn { width: 100%; }
	.card-surface:hover .image .inner { opacity: 0.5; }
	.card-surface:hover .text { transform: translateY(-5.5rem); }
}

.carousel-dots {
	position: absolute;
	top: 100%;
	left: 0;
	display: flex;
	justify-content: center;
	width: 100%;
	margin-top: 1rem;
}
/* WCAG 2.2 AA 2.5.8: the painted dot stays the reference's 4px, but the control itself
   must be at least 24x24. The dot moves to a centred ::before so the hit area can grow
   without the mark growing. .carousel-dots is absolutely positioned, so the taller box
   costs no document height. */
.carousel-dots button {
	position: relative;
	width: 1.5rem;
	height: 1.5rem;
	margin: 0;
	border-radius: 50%; /* kit: circles for slider dots only */
	background: none;
}
.carousel-dots button::before {
	content: '';
	position: absolute;
	top: 50%;
	left: 50%;
	width: 0.25rem;
	height: 0.25rem;
	margin: -0.125rem 0 0 -0.125rem;
	border-radius: 50%;
	opacity: 0.25;
	background: var(--canvas);
	transition: opacity 0.3s ease;
}
.carousel-dots button.is-active::before { opacity: 1; }

/* ---------- contact cta band (full-bleed photo, scrim, centered) ---------- */
.contact-cta {
	position: relative;
	padding: 2.5rem 5vw;
	background-color: var(--surface);
	background-position: center center;
	background-repeat: no-repeat;
	background-size: cover;
}
@media (min-width: 640px) { .contact-cta { padding: 5rem 5vw; } }
@media (min-width: 1024px) { .contact-cta { padding: 7.5rem 5vw; } }
.contact-cta::after {
	content: '';
	position: absolute;
	z-index: 0;
	top: 0; right: 0; bottom: 0; left: 0;
	opacity: 0.5;
	background: var(--canvas); /* reference scrim: canvas at 0.5 over the photo */
}
.contact-cta .cta-cell { text-align: center; }
.contact-cta .inner { position: relative; z-index: 1; }
.contact-cta h2 { margin-bottom: 0.5rem; }
.contact-cta .btn { margin-top: 2rem; }

/* ---------- footer ---------- */
.site-footer {
	padding: 2.5rem 5vw;
	background: var(--canvas);
}
@media (min-width: 640px) { .site-footer { padding: 5rem 5vw 2.5rem 5vw; } }
@media (min-width: 1024px) { .site-footer { padding: 7.5rem 5vw 2.5rem 5vw; } }
.footer-main { text-align: center; }
@media (min-width: 640px) {
	.footer-main {
		display: flex;
		align-items: flex-start;
		justify-content: space-between;
		text-align: left;
	}
}
.footer-logo-cell .logo { margin: 0 auto 2rem auto; height: 3.5rem; width: auto; opacity: 0.85; }
@media (min-width: 1024px) { .footer-logo-cell .logo { margin: 0 0 3rem 0; } }
.footer-nav { display: none; }
@media (min-width: 640px) {
	/* no bottom margin: the nav is the tallest item in an align-items:flex-start
	   row, so 2rem under it was dead space stacked on top of .footer-bottom's own
	   5rem padding-top and the footer's 2.5rem bottom padding. It pushed the
	   desktop footer to 472px against the reference's 403px, outside section-diff's
	   +/-15% band (max 462). Removed: 440px, in band, and the footer stops
	   bottoming out below its own content. */
	.footer-nav.show-for-medium { display: flex; flex-direction: row; margin: 0 2rem; }
}
.footer-nav ul {
	width: 11rem;
	padding: 0 1.25rem;
	font-weight: 600;
	font-size: 0.875rem;
	text-transform: uppercase;
	letter-spacing: 0.1em;
	border-left: 1px solid rgba(254, 254, 254, 0.1);
}
.footer-nav ul li { margin-bottom: 0.5rem; }
.footer-nav ul li:last-child { margin-bottom: 0; }
.footer-nav ul li a { color: var(--ink); transition: opacity 0.3s ease; }
.footer-nav ul li a:hover { opacity: 0.5; }
.footer-nav ul.secondary { width: 8rem; }
.footer-nav ul.secondary li a { color: var(--ink-muted); }
.footer-nav ul.footer-contact {
	width: 20rem;
	font-weight: 400;
	font-size: 0.875rem;
	text-transform: none;
	letter-spacing: 0;
	color: var(--ink-muted);
}
.footer-nav ul.footer-contact li { margin-bottom: 0.25rem; }
.footer-nav ul.footer-contact a { color: var(--ink-muted); }
.footer-nav ul.footer-contact a:hover { color: var(--ink); }
/* Below 640 the reference drops its whole footer nav. Faithful, except that it
   also strands the two legal routes this site actually ships: nothing anywhere
   else links to Terms or Privacy, and the drawer carries only the main nav, so on
   a phone (the majority viewport in this client's market) they were unreachable.
   Only the legal column comes back, centred under the logo. CSS only: the shell
   markup is untouched, so the shared-shell hash is unaffected. */
@media (max-width: 39.9375em) {
	.footer-nav.show-for-medium { display: flex; justify-content: center; margin: 0 0 2rem 0; }
	.footer-nav ul:not(.secondary) { display: none; }
	.footer-nav ul.secondary {
		display: flex;
		gap: 1.5rem;
		width: auto;
		padding: 0;
		border-left: none;
	}
	.footer-nav ul.secondary li { margin-bottom: 0; }
}
.footer-bottom { padding-top: 2.5rem; }
@media (min-width: 1024px) { .footer-bottom { padding-top: 5rem; } }
.footer-bottom .copyright {
	display: flex;
	flex-direction: column;
	align-items: center;
	font-size: 0.875rem;
	color: var(--ink-muted);
	text-align: center;
}
@media (min-width: 640px) {
	.footer-bottom .copyright { flex-direction: row; justify-content: center; }
	.footer-bottom .copyright li::after { content: '\00B7'; margin: 0 0.5rem; }
	.footer-bottom .copyright li:last-child::after { display: none; }
}

/* ---------- video modal (venobox-equivalent, local video) ----------
   catalog: 164 popup-button skin=fourways-dark, "zoom" at its 0.3s default */
.video-modal {
	position: fixed;
	z-index: 300;
	inset: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 5vw;
	background: rgba(23, 23, 23, 0.75); /* kit canvas at reference overlay interval */
	animation: popup-overlay-in 0.3s ease forwards;
}
.video-modal video {
	width: min(60rem, 100%);
	max-height: 80vh;
	background: #000000; /* video letterbox bed, media chrome */
	outline: none;
	animation: popup-zoom-in 0.3s cubic-bezier(0.25, 1, 0.5, 1) forwards;
}
@keyframes popup-overlay-in {
	from { opacity: 0; }
	to { opacity: 1; }
}
@keyframes popup-zoom-in {
	from { opacity: 0; transform: scale(0.8); }
	to { opacity: 1; transform: scale(1); }
}
.video-modal .video-close {
	position: absolute;
	top: 1.5rem;
	right: 5vw;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 2.5rem;
	height: 2.5rem;
}
.video-modal .video-close .x-a,
.video-modal .video-close .x-b {
	position: absolute;
	width: 1.75rem;
	height: 2px;
	background: var(--ink);
}
.video-modal .video-close .x-a { transform: rotate(45deg); }
.video-modal .video-close .x-b { transform: rotate(-45deg); }

/* =========================================================================
   INNER PAGES. Extensions only, same tokens, same flat system, no forks.
   Every value below is the kit's; no new colors, no radii, no shadows.
   ========================================================================= */

/* ---------- active route marker ----------
   Driven by a class on <body> plus data-nav on the shell's li, never by a class
   written into the shell itself: header, drawer nav and footer must hash
   byte-identically on every route (allpages shared-shell gate). Source order
   puts these after the header rules, so they win the shrunk-header tie. */
body.nav-home .header-nav li[data-nav="home"] a,
body.nav-quarry .header-nav li[data-nav="quarry"] a,
body.nav-ready-mix .header-nav li[data-nav="ready-mix"] a,
body.nav-civils .header-nav li[data-nav="civils"] a,
body.nav-projects .header-nav li[data-nav="projects"] a,
body.nav-about .header-nav li[data-nav="about"] a,
body.nav-contact .header-nav li[data-nav="contact"] a { opacity: 1; }

body.nav-home .header-nav li[data-nav="home"] a::before,
body.nav-quarry .header-nav li[data-nav="quarry"] a::before,
body.nav-ready-mix .header-nav li[data-nav="ready-mix"] a::before,
body.nav-civils .header-nav li[data-nav="civils"] a::before,
body.nav-projects .header-nav li[data-nav="projects"] a::before,
body.nav-about .header-nav li[data-nav="about"] a::before,
body.nav-contact .header-nav li[data-nav="contact"] a::before {
	background: var(--accent);
	transform-origin: left;
	transform: scaleX(1);
}

/* drawer active page (redesign 2026-08-27): the persistent accent underline,
   one marker idiom with the drawer's own hover language */
body.nav-home .menu-nav li[data-nav="home"] a::after,
body.nav-quarry .menu-nav li[data-nav="quarry"] a::after,
body.nav-ready-mix .menu-nav li[data-nav="ready-mix"] a::after,
body.nav-civils .menu-nav li[data-nav="civils"] a::after,
body.nav-projects .menu-nav li[data-nav="projects"] a::after,
body.nav-about .menu-nav li[data-nav="about"] a::after,
body.nav-contact .menu-nav li[data-nav="contact"] a::after { transform: scaleX(1); }

/* ---------- band variants (the .content pad scale already exists) ---------- */
.bg-surface { background-color: var(--surface); }
.bg-canvas { background-color: var(--canvas); }
.bg-gray-ltr { color: var(--ink-body); }        /* light band needs the light-band ink */
.bg-gray-ltr .text-gray-lt { color: var(--ink-body); }

/* ---------- page hero (the home hero shell, shorter, one static image) ---------- */
.page-hero {
	position: relative;
	display: flex;
	align-items: flex-end;
	min-height: 60vh;
	padding: 0 5vw;
	background: var(--canvas);
}
@media (min-width: 1024px) { .page-hero { min-height: 70vh; } }
.page-hero .page-hero-inner {
	position: relative;
	z-index: 1;
	width: 100%;
	padding: 8rem 0 3rem 0;
}
@media (min-width: 1024px) { .page-hero .page-hero-inner { padding: 12rem 0 5rem 0; } }
.page-hero-content { width: 100%; max-width: 52rem; }
.page-hero-content h1 { font-weight: 700; } /* kit: 700 reserved for display */
.page-hero .page-hero-image {
	position: absolute;
	z-index: 0;
	top: 0; right: 0; bottom: 0; left: 0;
	opacity: 0.3;                    /* same dim as the home hero slides */
	background-position: center center;
	background-repeat: no-repeat;
	background-size: cover;
}
.page-hero-lede { margin-top: 1.5rem; max-width: 44rem; }
.page-hero .btn { margin-top: 2rem; }

/* ---------- section head + prose ---------- */
.section-head { max-width: 52rem; margin-bottom: 2rem; }
@media (min-width: 1024px) { .section-head { margin-bottom: 3rem; } }
.section-head .lede { margin-top: 1rem; }
.line-heading + .text-2xl { margin-top: 1rem; }
.line-heading + .text-lg { margin-top: 1rem; }
.prose { max-width: 48rem; }
.prose p { margin-bottom: 1rem; }
.prose p:last-child { margin-bottom: 0; }
.prose .ticks li { position: relative; margin-bottom: 0.5rem; padding-left: 1.75rem; }
.prose .ticks li::before {
	content: '';
	position: absolute;
	top: 0.7em;
	left: 0;
	width: 0.75rem;
	height: 2px;
	background: var(--accent);
}
.stack-lg { margin-top: 2.5rem; }
@media (min-width: 1024px) { .stack-lg { margin-top: 4rem; } }

/* ---------- blurb grid (who we serve, services, competencies, markets) ---------- */
.blurb-grid { display: grid; grid-template-columns: 1fr; gap: 2rem; }
@media (min-width: 640px) { .blurb-grid { grid-template-columns: repeat(2, 1fr); gap: 2.5rem; } }
@media (min-width: 1024px) {
	.blurb-grid.cols-3 { grid-template-columns: repeat(3, 1fr); }
	.blurb-grid.cols-4 { grid-template-columns: repeat(4, 1fr); }
}
/* the head is a class, not a level: a band that follows the h1 directly needs an
   h2 here, a band under a section head needs an h3, and the look must not move */
.blurb .blurb-head,
.legal-block .blurb-head {
	font-weight: 600;
	font-size: 1.125rem;
	text-transform: uppercase;
	letter-spacing: 0.05em;
	color: var(--ink);
}
.blurb .blurb-head::after,
.legal-block .blurb-head::after {
	content: '';
	display: block;
	width: 2rem;
	height: 2px;
	margin-top: 0.75rem;
	background: var(--accent);       /* the eyebrow dash, moved under the head */
}
.blurb p { margin-top: 0.75rem; }
.blurb .image {
	width: 100%;
	height: 12rem;
	margin-bottom: 1.25rem;
	background-color: var(--canvas);
	background-position: center center;
	background-repeat: no-repeat;
	background-size: cover;
}
.blurb-grid.on-light .blurb .blurb-head { color: var(--canvas); }
.blurb-grid.on-light .blurb p { color: var(--ink-body); }

/* ---------- static card grid (projects; reuses .card-surface verbatim) ---------- */
/* two up, not three: the client has exactly four projects, and a 3-up grid
   strands the fourth card alone on its own row */
.card-grid { display: grid; grid-template-columns: 1fr; gap: 1.5rem; }
@media (min-width: 640px) { .card-grid { grid-template-columns: repeat(2, 1fr); gap: 2.5rem; } }
@media (min-width: 1024px) { .card-grid { gap: 2.5rem 3rem; } }

/* ---------- product cards (white-bed studio shots, contained not cropped) ---------- */
.product-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1rem; }
@media (min-width: 640px) { .product-grid { grid-template-columns: repeat(3, 1fr); gap: 1.5rem; } }
@media (min-width: 1024px) { .product-grid { grid-template-columns: repeat(3, 1fr); gap: 2rem; } }
.product-card {
	display: flex;
	flex-direction: column;
	height: 100%;
	border-radius: 0;
	background: var(--surface-light-card);
}
.product-card .image { position: relative; padding-top: 66%; background: var(--surface-light-card); }
.product-card .image .inner {
	position: absolute;
	inset: 0;
	background-position: center center;
	background-repeat: no-repeat;
	background-size: contain;        /* studio cut-outs on white; never crop them */
}
.product-card .text {
	flex: 1;
	padding: 1rem;
	text-align: center;
	border-top: 1px solid var(--line);
}
.product-card h3 {
	font-weight: 600;
	font-size: 1rem;
	text-transform: uppercase;
	letter-spacing: 0.05em;
	color: var(--canvas);
}
.product-card .category-list { margin-top: 0.75rem; }

/* ---------- client logo wall (marks ship unlabelled) ---------- */
.logo-wall {
	display: grid;
	grid-template-columns: repeat(2, 1fr);
	gap: 1px;
	border: 1px solid var(--line);
	background: var(--line);
}
@media (min-width: 640px) { .logo-wall { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 1024px) { .logo-wall { grid-template-columns: repeat(6, 1fr); } }
.logo-wall .logo-cell {
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 1.25rem;
	background: var(--surface-light-card);
}
.logo-wall img { width: 100%; height: auto; }

/* ---------- team ---------- */
.team-grid { display: grid; grid-template-columns: 1fr; gap: 1.5rem; }
@media (min-width: 640px) { .team-grid { grid-template-columns: repeat(2, 1fr); gap: 2rem; } }
@media (min-width: 1024px) { .team-grid { grid-template-columns: repeat(3, 1fr); } }
/* Seven people do not divide into two or three columns: the plain grid left the
   seventh card alone on a row with two thirds of it empty at 1024 and one half
   empty at 640. The client's own first-listed person is the Managing Director, so
   the lead card takes the whole first row and the remaining six fill exact rows.
   No orphan at either breakpoint, and the grid stops being six identical cards. */
.team-card.is-lead { grid-column: 1 / -1; }
@media (min-width: 1024px) {
	.team-card.is-lead { display: grid; grid-template-columns: 1fr 2fr; gap: 0 2.5rem; align-items: start; }
	.team-card.is-lead p:last-child { margin-top: 0; grid-column: 2; grid-row: 1 / span 2; }
	.team-card.is-lead h3 { grid-column: 1; }
	.team-card.is-lead .role { grid-column: 1; }
}
.team-card { height: 100%; padding: 2rem; background: var(--surface-light-card); }
.team-card h3 {
	font-weight: 600;
	font-size: 1.125rem;
	text-transform: uppercase;
	letter-spacing: 0.05em;
	color: var(--canvas);
}
.team-card .role {
	margin-top: 0.5rem;
	font-weight: 600;
	font-size: 0.875rem;
	text-transform: uppercase;
	letter-spacing: 0.1em;
	color: var(--accent);            /* accent as ink only on the light card */
}
.team-card p { margin-top: 1rem; color: var(--ink-body); }

/* ---------- generic split band (the .home-about composition, reusable) ----------
   The band is full-bleed (it carries its own background) so it cannot take the
   .grid-container box, but its CONTENT edge must land on the same column as every
   .content band above and below it, or two stacked bands start at different left
   edges. Measured before this rule: .split content began at 64px while every
   sibling section began at 84px, a visible 20px step on quarry, quarry-products
   and ready-mix. The inline padding below reproduces .content's 5vw plus
   .grid-container's own padding and its 87.5rem centering, so the edges agree at
   every viewport rather than only below 1528px. */
.split {
	display: flex;
	flex-direction: column;
	align-items: center;
	padding: 2.5rem 5vw;
	padding-right: calc(5vw + 0.75rem + max(0px, (100% - 10vw - 87.5rem) / 2));
	padding-left: calc(5vw + 0.75rem + max(0px, (100% - 10vw - 87.5rem) / 2));
}
@media (min-width: 640px) {
	.split {
		padding-top: 5rem;
		padding-bottom: 5rem;
		padding-right: calc(5vw + 1.25rem + max(0px, (100% - 10vw - 87.5rem) / 2));
		padding-left: calc(5vw + 1.25rem + max(0px, (100% - 10vw - 87.5rem) / 2));
	}
}
@media (min-width: 1024px) {
	.split {
		flex-direction: row-reverse;
		align-items: center;
		padding-top: 7.5rem;
		padding-bottom: 7.5rem;
	}
}
.split .image {
	width: 100%;
	height: 50vw;
	max-height: 70vh;
	margin: 0 0 2.5rem 0;
	background-color: var(--canvas);
	background-position: center center;
	background-repeat: no-repeat;
	background-size: cover;
}
@media (min-width: 1024px) { .split .image { width: 42%; height: 32rem; margin: 0; } }
/* left-aligned, NOT centred like .home-about's panel. The home band is flush to
   the viewport and centring its 30rem block inside the 60% column is what puts
   the reference's copy at x=144; this band is padded to the site's content column
   instead, so centring the inner block inside the column pushed the copy off that
   column by half the slack (measured: +28px at 1440, +58px at 1920, +22px at 768)
   and only agreed at exactly 1280. Left-aligning holds the edge at every width. */
.split .text { display: flex; justify-content: flex-start; width: 100%; }
@media (min-width: 1024px) { .split .text { width: 58%; padding-right: 4rem; } }
.split .text .inner { width: 100%; max-width: 38rem; }
.split .btn { margin-top: 2rem; }

/* ---------- civils showcases (long-form case bands) ---------- */
.showcase { margin-top: 2.5rem; padding-top: 2.5rem; border-top: 1px solid rgba(254, 254, 254, 0.1); }
@media (min-width: 1024px) { .showcase { margin-top: 4rem; padding-top: 4rem; } }
.showcase:first-child { margin-top: 0; padding-top: 0; border-top: none; }
.showcase-block { margin-top: 1.5rem; }
.showcase-block h4 {
	margin-bottom: 0.5rem;
	font-weight: 600;
	font-size: 0.875rem;
	text-transform: uppercase;
	letter-spacing: 0.1em;
	color: var(--ink);
}
.showcase-block p { margin-bottom: 0.75rem; }
.showcase-block p:last-child { margin-bottom: 0; }

/* ---------- contact ---------- */
.contact-grid { display: grid; grid-template-columns: 1fr; gap: 2.5rem; }
@media (min-width: 1024px) { .contact-grid { grid-template-columns: 1fr 1fr; gap: 4rem; } }
.contact-block { margin-bottom: 2rem; }
.contact-block:last-child { margin-bottom: 0; }
.contact-block h2 {
	margin-bottom: 0.75rem;
	font-weight: 600;
	font-size: 0.875rem;
	text-transform: uppercase;
	letter-spacing: 0.1em;
	color: var(--ink);
}
.contact-block li { margin-bottom: 0.375rem; }
/* every actionable line in a contact block (tel, mailto, the map link) rendered
   pixel-identical to the static address line, so nothing said which lines do
   something; the hover colour change is not reachable on touch. A hairline
   underline in the text's own colour carries the affordance without adding one. */
.contact-block a {
	text-decoration: underline;
	text-decoration-thickness: 1px;
	text-underline-offset: 0.25em;
	text-decoration-color: rgba(160, 160, 163, 0.45); /* --ink-muted at the hairline alpha */
	transition: color 0.3s ease, text-decoration-color 0.3s ease;
}
.contact-block a:hover { color: var(--ink); text-decoration-color: var(--ink); }

.form-field { margin-bottom: 1.25rem; }
.form-field label {
	display: block;
	margin-bottom: 0.5rem;
	font-weight: 600;
	font-size: 0.875rem;
	text-transform: uppercase;
	letter-spacing: 0.1em;
	color: var(--ink);
}
.form-field input,
.form-field textarea {
	width: 100%;
	padding: 0.875rem 1rem;
	font: inherit;
	font-size: 1rem;
	color: var(--ink-body);
	border: 1px solid var(--line);
	border-radius: 0;                /* kit: input radius 0, filled, no shadow */
	background: var(--surface-light-card);
}
.form-field textarea { min-height: 9rem; resize: vertical; }
.form-note { margin-top: 1rem; font-size: 0.875rem; color: var(--ink-muted); }
.form-note a { color: var(--ink); text-decoration: underline; }

/* ---------- project detail ---------- */
.detail-media {
	width: 100%;
	max-width: 34rem;
	height: 0;
	padding-top: min(34rem, 100%);   /* the client's thumbnails are square */
	background-color: var(--canvas);
	background-position: center center;
	background-repeat: no-repeat;
	background-size: cover;
}
.detail-meta {
	margin-top: 1.5rem;
	font-size: 0.875rem;
	text-transform: uppercase;
	letter-spacing: 0.1em;
	color: var(--ink-muted);
}
.pager {
	display: flex;
	flex-wrap: wrap;
	justify-content: space-between;
	gap: 1rem;
	margin-top: 3rem;
	padding-top: 2rem;
	border-top: 1px solid rgba(254, 254, 254, 0.1);
}
.pager a {
	font-weight: 600;
	font-size: 0.875rem;
	text-transform: uppercase;
	letter-spacing: 0.1em;
	color: var(--ink);
	opacity: 0.75;
	transition: opacity 0.3s ease;
}
.pager a:hover { opacity: 1; }

/* ---------- reduced motion: reveals visible, slideshow static, no page motion ---------- */
@media (prefers-reduced-motion: reduce) {
	html.js .fade-up {
		opacity: 1 !important;
		transform: none !important;
		transition: none !important;
	}
	.home-hero-slides .slide { animation: none !important; transition: none !important; }
	.hero-progress-fill { transition: none; }
	.card-list, .card-list.is-snapping { transition: none; }
	.video-modal, .video-modal video { animation: none !important; }
	.menu { transition: none; }
	.menu-nav li, .menu.is-open .menu-nav li { transition: none; }
	.menu-close, .menu-close:hover { transition: none; transform: none; }
	.menu-promo-arrow, .menu-promo:hover .menu-promo-arrow { transition: none; transform: none; }
	.project-row, .project-row:hover, .project-row:focus-visible { transition: none; transform: none; }
	.project-row .thumb, .project-row:hover .thumb { transition: none; transform: none; }
	.row-arrow, .project-row:hover .row-arrow { transition: none; transform: none; }
	html.js .case-panel.is-entering { animation: none; }
	.value-cards .blurb, .value-cards .blurb:hover { transition: none; transform: none; }
	.team-card, .team-card:hover { transition: none; transform: none; }
	.home-services .service-panel, .home-services .service-panel:hover { transition: none; transform: none; }
	.home-services .service-panel .image, .home-services .service-panel:hover .image { transition: none; transform: none; }
	.fold-icon::before, .fold-icon::after { transition: none; }
	.site-header::after, .site-header { transition: none; }
	.btn::before { transition: none; }
}

/* ================================================================
   Projects page redesign 2026-08-27 (operator critiques 4+5).
   Editorial rows: typographic presentation with small sharp media (project
   sources are 400px; rendered small they stay honest), index numerals, pill
   chips, the arrow idiom from the drawer promo. Radius amendment applied.
   ================================================================ */
.project-rows {
	display: flex;
	flex-direction: column;
	gap: 1rem;
}
.project-row {
	position: relative;
	display: flex;
	align-items: center;
	gap: 1.25rem;
	padding: 1.25rem;
	background: var(--surface-light-card);
	border: 1px solid rgba(23, 23, 23, 0.08);
	border-radius: var(--radius-card);
	overflow: hidden;
	transition: border-color 0.25s ease, transform 0.25s var(--ease-reveal);
}
.project-row:hover, .project-row:focus-visible {
	border-color: rgba(23, 23, 23, 0.3);
	transform: translateY(-2px);
}
.project-row .num {
	flex: 0 0 auto;
	font-size: 0.8125rem;
	font-weight: 600;
	letter-spacing: 0.12em;
	color: var(--ink-muted-on-light);
}
.project-row .thumb {
	flex: 0 0 5rem;
	height: 5rem;
	border-radius: var(--radius-media);
	background-position: center center;
	background-repeat: no-repeat;
	background-size: cover;
	transition: transform 0.35s var(--ease-reveal);
}
.project-row:hover .thumb { transform: scale(1.05); }
.row-text {
	display: flex;
	flex-direction: column;
	gap: 0.375rem;
	min-width: 0;
}
.row-title {
	font-size: 1.0625rem;
	font-weight: 700;
	line-height: 1.3;
	text-transform: uppercase;
	color: var(--canvas);
}
/* chips sit on the white row card here: the on-light ink token (the Pass 3
   contrast fix), not the dark-band muted ink */
.project-row .chip { color: var(--ink-muted-on-light); }
.row-arrow {
	position: relative;
	flex: 0 0 auto;
	width: 1.25rem;
	height: 2px;
	margin-left: auto;
	background: var(--accent);
	transition: transform 0.25s ease;
}
.row-arrow::after {
	content: '';
	position: absolute;
	top: 50%;
	right: -1px;
	width: 0.45rem;
	height: 0.45rem;
	border-top: 2px solid var(--accent);
	border-right: 2px solid var(--accent);
	transform: translateY(-50%) rotate(45deg);
}
.project-row:hover .row-arrow { transform: translateX(6px); }
@media (min-width: 640px) {
	.project-row { gap: 1.75rem; padding: 1.5rem 1.75rem; }
	.project-row .thumb { flex-basis: 7rem; height: 7rem; }
	.row-title { font-size: 1.25rem; }
}
@media (min-width: 1024px) {
	.row-title { font-size: 1.375rem; }
}

/* ================================================================
   Radius amendment sweep 2026-08-27 (operator directive): every card-class
   surface joins the rounded system. Full-bleed bands and split-band media stay
   square (they are architecture, not cards).
   ================================================================ */
.card-surface { border-radius: var(--radius-card); overflow: hidden; }
.card .image .inner { border-radius: 0; } /* inside an overflow-clipped card the media keeps its own corners */
.product-card { border-radius: var(--radius-card); overflow: hidden; }
.contact-block { border-radius: var(--radius-card); }

/* ================================================================
   Fold cards 2026-08-27 (operator: quarry and ready-mix read all-at-once).
   Native details/summary in the rounded card language: headers that hide
   their prose. Closed by default (phones get headers only); main.js opens
   them all at desktop init. Both band skins. No-JS: the browser's own
   details behavior, fully accessible.
   ================================================================ */
.fold-cards { align-items: start; }
.fold-cards .fold {
	border-radius: var(--radius-card);
	border: 1px solid rgba(23, 23, 23, 0.1);
	background: var(--surface-light-card);
	overflow: hidden;
	transition: border-color 0.25s ease;
}
.fold-cards .fold:hover { border-color: rgba(23, 23, 23, 0.3); }
.bg-canvas .fold-cards .fold, .bg-surface .fold-cards .fold {
	background: rgba(254, 254, 254, 0.04);
	border-color: rgba(254, 254, 254, 0.09);
}
.bg-canvas .fold-cards .fold:hover, .bg-surface .fold-cards .fold:hover { border-color: rgba(254, 254, 254, 0.24); }
.fold-cards summary {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 1rem;
	padding: 1.25rem 1.5rem;
	cursor: pointer;
	list-style: none;
}
.fold-cards summary::-webkit-details-marker { display: none; }
.fold-cards summary .blurb-head { margin: 0; }
.fold-icon {
	position: relative;
	flex: 0 0 auto;
	width: 1.75rem;
	height: 1.75rem;
	border: 1px solid rgba(23, 23, 23, 0.2);
	border-radius: var(--radius-pill);
}
.bg-canvas .fold-icon, .bg-surface .fold-icon { border-color: rgba(254, 254, 254, 0.2); }
.fold-icon::before, .fold-icon::after {
	content: '';
	position: absolute;
	top: 50%;
	left: 50%;
	width: 0.75rem;
	height: 2px;
	background: var(--accent);
	transform: translate(-50%, -50%);
	transition: transform 0.25s var(--ease-reveal);
}
.fold-icon::after { transform: translate(-50%, -50%) rotate(90deg); }
.fold[open] .fold-icon::after { transform: translate(-50%, -50%) rotate(0deg); }
.fold-body { padding: 0 1.5rem 1.5rem; }
.fold-body > p:first-child { margin-top: 0; }

/* ================================================================
   About regroup 2026-08-27 (operator critique 6): the four value blurbs become
   numbered rounded cards, mission and vision become a statement panel pair
   (accent-deep + white), team cards gain monogram identity and the rounded
   surface language. All client words verbatim; presentation only.
   ================================================================ */
.value-cards { counter-reset: value-card; gap: 1rem; }
.value-cards .blurb {
	counter-increment: value-card;
	position: relative;
	padding: 1.75rem 1.5rem 1.5rem;
	background: rgba(254, 254, 254, 0.04);
	border: 1px solid rgba(254, 254, 254, 0.09);
	border-radius: var(--radius-card);
	overflow: hidden;
	transition: border-color 0.25s ease, background-color 0.25s ease, transform 0.25s var(--ease-reveal);
}
.value-cards .blurb:hover {
	background: rgba(254, 254, 254, 0.06);
	border-color: rgba(254, 254, 254, 0.22);
	transform: translateY(-3px);
}
.value-cards .blurb::after {
	content: counter(value-card, decimal-leading-zero);
	position: absolute;
	top: 0.875rem;
	right: 1.125rem;
	font-size: 2.5rem;
	font-weight: 700;
	line-height: 1;
	color: rgba(254, 254, 254, 0.07);
}
.mv-panels { gap: 1rem; }
.mv-panels .blurb {
	padding: 2.25rem 2rem;
	background: var(--surface-light-card);
	border: 1px solid rgba(23, 23, 23, 0.08);
	border-radius: var(--radius-card);
}
.mv-panels .blurb p { font-size: 1.0625rem; line-height: 1.65; }
.blurb-grid.on-light.mv-panels .blurb:first-child { background: var(--accent-deep); border-color: var(--accent-deep); }
.blurb-grid.on-light.mv-panels .blurb:first-child .blurb-head,
.blurb-grid.on-light.mv-panels .blurb:first-child p { color: var(--ink); }
.team-card {
	border: 1px solid rgba(23, 23, 23, 0.08);
	border-radius: var(--radius-card);
	transition: transform 0.25s var(--ease-reveal), border-color 0.25s ease;
}
.team-card:hover { transform: translateY(-3px); border-color: rgba(23, 23, 23, 0.3); }
.team-card[data-initials]::before {
	content: attr(data-initials);
	display: flex;
	align-items: center;
	justify-content: center;
	width: 3.25rem;
	height: 3.25rem;
	margin-bottom: 1.25rem;
	font-weight: 700;
	font-size: 1rem;
	letter-spacing: 0.05em;
	color: var(--accent);
	background: transparent;
	border: 2px solid var(--accent);
	border-radius: var(--radius-pill);
}
@media (min-width: 1024px) {
	.team-card.is-lead[data-initials]::before { grid-column: 1; }
}

/* ================================================================
   Civils case-study explorer 2026-08-27 (operator critique 3). The 8 client
   case studies, verbatim, one on stage at a time behind pill tabs; the 44
   paragraphs stop being a wall. No-JS stacks all 8 panels and hides the tabs.
   Media are the client's own case slides, inner-cropped past their baked
   title plates (source-capped 742px, recorded).
   ================================================================ */
.case-tabs {
	/* sticky switcher (operator ruling 2026-08-27): the pills hold the top of
	   the screen while a long case is read; selection swaps in place, the
	   viewport never moves. Solid canvas ground so content scrolls under it. */
	position: sticky;
	top: 4.5rem;
	z-index: 5;
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	padding: 0.75rem 0;
	margin-bottom: 1.5rem;
	background: var(--canvas);
}
@media (min-width: 1024px) {
	.case-tabs { top: 6.5rem; } /* shrunk desktop header is 96px; pills clear it */
}
@media (max-width: 639px) {
	.case-tabs {
		flex-wrap: nowrap;
		overflow-x: auto;
		scroll-snap-type: x proximity;
		-webkit-overflow-scrolling: touch;
		scrollbar-width: none; /* the clipped pill edge is the affordance, not a track */
	}
	.case-tabs::-webkit-scrollbar { display: none; }
	.case-tabs button { flex: 0 0 auto; scroll-snap-align: start; }
}
.case-tabs button {
	padding: 0.625rem 1.125rem;
	font-size: 0.8125rem;
	font-weight: 600;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	white-space: nowrap;
	color: var(--ink-muted);
	background: rgba(254, 254, 254, 0.04);
	border: 1px solid rgba(254, 254, 254, 0.12);
	border-radius: var(--radius-pill);
	transition: color 0.2s ease, border-color 0.2s ease, background-color 0.2s ease;
}
.case-tabs button:hover { color: var(--ink); border-color: rgba(254, 254, 254, 0.3); }
.case-tabs button[aria-expanded="true"] {
	color: var(--ink);
	background: var(--accent);
	border-color: var(--accent);
}
.case-panel { display: grid; gap: 1.5rem; }
@media (min-width: 1024px) {
	.case-panel.has-media { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); align-items: start; }
	.case-media { position: sticky; top: 7rem; }
}
.case-media {
	aspect-ratio: 735 / 436;
	border-radius: var(--radius-card);
	background-position: center center;
	background-repeat: no-repeat;
	background-size: cover;
}
html.js .case-panel.is-entering { animation: case-in 0.4s var(--ease-reveal); }
@keyframes case-in {
	from { opacity: 0; transform: translateY(0.75rem); }
}
.case-hint {
	padding: 0.5rem 0 1rem;
	font-size: 0.9375rem;
	color: var(--ink-muted);
}
html:not(.js) .case-tabs { display: none; }
html:not(.js) .case-hint { display: none; }
html:not(.js) .case-panel + .case-panel { margin-top: 3.5rem; }
.bg-case-ngwarati-boxcut { background-image: url('../assets/case-ngwarati-boxcut.jpg'); }
.bg-case-ngwarati-boxcut { background-image: image-set(url('../assets/case-ngwarati-boxcut.avif') type('image/avif'), url('../assets/case-ngwarati-boxcut.jpg') type('image/jpeg')); }
.bg-case-bimha-3mtpa { background-image: url('../assets/case-bimha-3mtpa.jpg'); }
.bg-case-bimha-3mtpa { background-image: image-set(url('../assets/case-bimha-3mtpa.avif') type('image/avif'), url('../assets/case-bimha-3mtpa.jpg') type('image/jpeg')); }
.bg-case-bimha-crusher { background-image: url('../assets/case-bimha-crusher.jpg'); }
.bg-case-bimha-crusher { background-image: image-set(url('../assets/case-bimha-crusher.avif') type('image/avif'), url('../assets/case-bimha-crusher.jpg') type('image/jpeg')); }
.bg-case-shotcrete { background-image: url('../assets/case-shotcrete.jpg'); }
.bg-case-shotcrete { background-image: image-set(url('../assets/case-shotcrete.avif') type('image/avif'), url('../assets/case-shotcrete.jpg') type('image/jpeg')); }
.bg-case-mimosa-tsf { background-image: url('../assets/case-mimosa-tsf.jpg'); }
.bg-case-mimosa-tsf { background-image: image-set(url('../assets/case-mimosa-tsf.avif') type('image/avif'), url('../assets/case-mimosa-tsf.jpg') type('image/jpeg')); }
.bg-case-murowa { background-image: url('../assets/case-murowa.jpg'); }
.bg-case-murowa { background-image: image-set(url('../assets/case-murowa.avif') type('image/avif'), url('../assets/case-murowa.jpg') type('image/jpeg')); }

/* ================================================================
   Clients marquee, catalog 091 Dragable Ticker, skin fourways-dark
   (operator critique 4, 2026-08-27). Auto-drift 100px/s easing to 25 on
   hover, drag scrubs with a velocity fling, duplicate set fills the loop.
   WCAG 2.2.2: the pause control stops the drift. Reduced motion: no drift,
   native horizontal scroll. No-JS: no clones exist, the track wraps as the
   old logo grid.
   ================================================================ */
.logo-marquee {
	position: relative;
	overflow: hidden;
	touch-action: pan-y; /* the browser keeps vertical scroll; horizontal is ours (P5 lesson) */
	-webkit-mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent);
	mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent);
}
.logo-track {
	display: flex;
	gap: 1rem;
	width: max-content;
	will-change: transform;
}
.logo-marquee .logo-cell {
	flex: 0 0 auto;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 11rem;
	height: 5.5rem;
	padding: 1rem 1.5rem;
	background: rgba(254, 254, 254, 0.04);
	border: 1px solid rgba(254, 254, 254, 0.09);
	border-radius: var(--radius-media);
	transition: border-color 0.25s ease, background-color 0.25s ease;
}
.logo-marquee .logo-cell:hover {
	background: rgba(254, 254, 254, 0.07);
	border-color: rgba(254, 254, 254, 0.22);
}
.logo-marquee .logo-cell img {
	max-width: 100%;
	max-height: 100%;
	width: auto;
	height: auto;
}
/* pause control removed 2026-08-27 on operator direction; hover and touch now
   PAUSE the drift (eased), reduced-motion serves a static strip. Recorded as
   the WCAG 2.2.2 mechanism exception in the build record. */
.logo-marquee[data-static] {
	overflow-x: auto;
	-webkit-mask-image: none;
	mask-image: none;
}
html:not(.js) .logo-track { flex-wrap: wrap; justify-content: center; width: auto; }

/* ================================================================
   PASS 3, delivery layer; recut 2026-08-27 (operator critique: quality sweep).
   Each rule declares a plain url() first (the fallback any browser without
   image-set keeps) and then image-set() with explicit type(), which browsers
   resolve by declared MIME support: AVIF where available, the JPEG otherwise.
   The ladder is now sized to DEVICE pixels, not CSS pixels: the mobile-first
   base serves the phone-2x cut, (min-resolution: 2.5dppx) lifts phones to the
   3x cut, tablets get 4:3 art-directed cuts, >=1024 gets landscape 1920, and
   >=1024 at >=1.5dppx gets the -hi tier (2000..2560, source-capped). The home
   hero carries portrait art-directed crops below 640; the short .page-hero
   bands use the 4:3 cuts there instead (same photographs, different geometry).
   Panels + CTA re-sourced from the client's own high-res photos 2026-08-27
   (old sources: 500x300 card renders and an 848x480 video, both dead ends).
   ================================================================ */
.bg-about-operations { background-image: url('../assets/about-operations.jpg'); }
.bg-about-operations { background-image: image-set(url('../assets/about-operations-1366.avif') type('image/avif'), url('../assets/about-operations.jpg') type('image/jpeg')); }
.bg-cta-aerial { background-image: url('../assets/cta-aerial.jpg'); }
.bg-cta-aerial { background-image: image-set(url('../assets/cta-aerial-m750.avif') type('image/avif'), url('../assets/cta-aerial.jpg') type('image/jpeg')); }
.bg-hero-slide-aerial { background-image: url('../assets/hero-slide-aerial.jpg'); }
.bg-hero-slide-aerial { background-image: image-set(url('../assets/hero-slide-aerial-m750.avif') type('image/avif'), url('../assets/hero-slide-aerial.jpg') type('image/jpeg')); }
.bg-hero-slide-concrete { background-image: url('../assets/hero-slide-concrete.jpg'); }
.bg-hero-slide-concrete { background-image: image-set(url('../assets/hero-slide-concrete-m750.avif') type('image/avif'), url('../assets/hero-slide-concrete.jpg') type('image/jpeg')); }
.bg-hero-slide-quarry { background-image: url('../assets/hero-slide-quarry.jpg'); }
.bg-hero-slide-quarry { background-image: image-set(url('../assets/hero-slide-quarry-m750.avif') type('image/avif'), url('../assets/hero-slide-quarry.jpg') type('image/jpeg')); }
.bg-hero-slide-quarry-face { background-image: url('../assets/hero-slide-quarry-face.jpg'); }
.bg-hero-slide-quarry-face { background-image: image-set(url('../assets/hero-slide-quarry-face-m750.avif') type('image/avif'), url('../assets/hero-slide-quarry-face.jpg') type('image/jpeg')); }
.bg-panel-civils { background-image: url('../assets/panel-civils.jpg'); }
.bg-panel-civils { background-image: image-set(url('../assets/panel-civils-m750.avif') type('image/avif'), url('../assets/panel-civils.jpg') type('image/jpeg')); }
.bg-panel-concrete { background-image: url('../assets/panel-concrete.jpg'); }
.bg-panel-concrete { background-image: image-set(url('../assets/panel-concrete-m750.avif') type('image/avif'), url('../assets/panel-concrete.jpg') type('image/jpeg')); }
.bg-panel-products { background-image: url('../assets/panel-products.jpg'); }
.bg-panel-products { background-image: image-set(url('../assets/panel-products-m750.avif') type('image/avif'), url('../assets/panel-products.jpg') type('image/jpeg')); }
.bg-panel-quarry { background-image: url('../assets/panel-quarry.jpg'); }
.bg-panel-quarry { background-image: image-set(url('../assets/panel-quarry-m750.avif') type('image/avif'), url('../assets/panel-quarry.jpg') type('image/jpeg')); }
.bg-product-stone-01 { background-image: url('../assets/product-stone-01.jpg'); }
.bg-product-stone-01 { background-image: image-set(url('../assets/product-stone-01.avif') type('image/avif'), url('../assets/product-stone-01.jpg') type('image/jpeg')); }
.bg-product-stone-02 { background-image: url('../assets/product-stone-02.jpg'); }
.bg-product-stone-02 { background-image: image-set(url('../assets/product-stone-02.avif') type('image/avif'), url('../assets/product-stone-02.jpg') type('image/jpeg')); }
.bg-product-stone-03 { background-image: url('../assets/product-stone-03.jpg'); }
.bg-product-stone-03 { background-image: image-set(url('../assets/product-stone-03.avif') type('image/avif'), url('../assets/product-stone-03.jpg') type('image/jpeg')); }
.bg-product-stone-04 { background-image: url('../assets/product-stone-04.jpg'); }
.bg-product-stone-04 { background-image: image-set(url('../assets/product-stone-04.avif') type('image/avif'), url('../assets/product-stone-04.jpg') type('image/jpeg')); }
.bg-product-stone-05 { background-image: url('../assets/product-stone-05.jpg'); }
.bg-product-stone-05 { background-image: image-set(url('../assets/product-stone-05.avif') type('image/avif'), url('../assets/product-stone-05.jpg') type('image/jpeg')); }
.bg-product-stone-06 { background-image: url('../assets/product-stone-06.jpg'); }
.bg-product-stone-06 { background-image: image-set(url('../assets/product-stone-06.avif') type('image/avif'), url('../assets/product-stone-06.jpg') type('image/jpeg')); }
.bg-project-cbd-road { background-image: url('../assets/project-cbd-road.jpg'); }
.bg-project-cbd-road { background-image: image-set(url('../assets/project-cbd-road.avif') type('image/avif'), url('../assets/project-cbd-road.jpg') type('image/jpeg')); }
.bg-project-housing-borrowdale { background-image: url('../assets/project-housing-borrowdale.jpg'); }
.bg-project-housing-borrowdale { background-image: image-set(url('../assets/project-housing-borrowdale.avif') type('image/avif'), url('../assets/project-housing-borrowdale.jpg') type('image/jpeg')); }
.bg-project-mazowe-bridge { background-image: url('../assets/project-mazowe-bridge.jpg'); }
.bg-project-mazowe-bridge { background-image: image-set(url('../assets/project-mazowe-bridge.avif') type('image/avif'), url('../assets/project-mazowe-bridge.jpg') type('image/jpeg')); }
.bg-project-shopping-mall { background-image: url('../assets/project-shopping-mall.jpg'); }
.bg-project-shopping-mall { background-image: image-set(url('../assets/project-shopping-mall.avif') type('image/avif'), url('../assets/project-shopping-mall.jpg') type('image/jpeg')); }
/* short page-hero bands: 4:3 cuts below 1024 (the portrait cuts would over-crop
   a 375x487 band; these bands share photographs with the home hero, not geometry).
   Low-density phones get the 768 cut (the t1536 was 3MP into a 400px viewport and
   its decode pushed projects.html LCP to 4.2s); 2.5dppx+ phones and tablets keep
   the 1536 cut. */
@media (max-width: 1023px) {
	.page-hero-image.bg-hero-slide-aerial { background-image: image-set(url('../assets/hero-slide-aerial-t1536.avif') type('image/avif'), url('../assets/hero-slide-aerial.jpg') type('image/jpeg')); }
	.page-hero-image.bg-hero-slide-concrete { background-image: image-set(url('../assets/hero-slide-concrete-t1536.avif') type('image/avif'), url('../assets/hero-slide-concrete.jpg') type('image/jpeg')); }
	.page-hero-image.bg-hero-slide-quarry { background-image: image-set(url('../assets/hero-slide-quarry-t1536.avif') type('image/avif'), url('../assets/hero-slide-quarry.jpg') type('image/jpeg')); }
	.page-hero-image.bg-hero-slide-quarry-face { background-image: image-set(url('../assets/hero-slide-quarry-face-t1536.avif') type('image/avif'), url('../assets/hero-slide-quarry-face.jpg') type('image/jpeg')); }
	.page-hero-image.bg-cta-aerial { background-image: image-set(url('../assets/cta-aerial-t1536.avif') type('image/avif'), url('../assets/cta-aerial.jpg') type('image/jpeg')); }
}
@media (max-width: 639px) and (max-resolution: 2.49dppx) {
	.page-hero-image.bg-about-operations { background-image: image-set(url('../assets/about-operations-b640.avif') type('image/avif'), url('../assets/about-operations.jpg') type('image/jpeg')); }
	.page-hero-image.bg-hero-slide-aerial { background-image: image-set(url('../assets/hero-slide-aerial-b640.avif') type('image/avif'), url('../assets/hero-slide-aerial.jpg') type('image/jpeg')); }
	.page-hero-image.bg-hero-slide-concrete { background-image: image-set(url('../assets/hero-slide-concrete-b640.avif') type('image/avif'), url('../assets/hero-slide-concrete.jpg') type('image/jpeg')); }
	.page-hero-image.bg-hero-slide-quarry { background-image: image-set(url('../assets/hero-slide-quarry-b640.avif') type('image/avif'), url('../assets/hero-slide-quarry.jpg') type('image/jpeg')); }
	.page-hero-image.bg-hero-slide-quarry-face { background-image: image-set(url('../assets/hero-slide-quarry-face-b640.avif') type('image/avif'), url('../assets/hero-slide-quarry-face.jpg') type('image/jpeg')); }
	.page-hero-image.bg-cta-aerial { background-image: image-set(url('../assets/cta-aerial-b640.avif') type('image/avif'), url('../assets/cta-aerial.jpg') type('image/jpeg')); }
}
/* phones at 3x density: lift the home-hero portrait and full-bleed cards to the 3x cut
   (.page-hero-image rules above out-rank these by specificity and keep the 4:3 cut) */
@media (max-width: 639px) and (min-resolution: 2.5dppx) {
	.bg-hero-slide-aerial { background-image: image-set(url('../assets/hero-slide-aerial-m1125.avif') type('image/avif'), url('../assets/hero-slide-aerial.jpg') type('image/jpeg')); }
	.bg-hero-slide-concrete { background-image: image-set(url('../assets/hero-slide-concrete-m1125.avif') type('image/avif'), url('../assets/hero-slide-concrete.jpg') type('image/jpeg')); }
	.bg-hero-slide-quarry { background-image: image-set(url('../assets/hero-slide-quarry-m1125.avif') type('image/avif'), url('../assets/hero-slide-quarry.jpg') type('image/jpeg')); }
	.bg-hero-slide-quarry-face { background-image: image-set(url('../assets/hero-slide-quarry-face-m1125.avif') type('image/avif'), url('../assets/hero-slide-quarry-face.jpg') type('image/jpeg')); }
	.bg-cta-aerial { background-image: image-set(url('../assets/cta-aerial-m1125.avif') type('image/avif'), url('../assets/cta-aerial.jpg') type('image/jpeg')); }
	.bg-panel-civils { background-image: image-set(url('../assets/panel-civils-m1125.avif') type('image/avif'), url('../assets/panel-civils.jpg') type('image/jpeg')); }
	.bg-panel-concrete { background-image: image-set(url('../assets/panel-concrete-m1125.avif') type('image/avif'), url('../assets/panel-concrete.jpg') type('image/jpeg')); }
	.bg-panel-products { background-image: image-set(url('../assets/panel-products-m1125.avif') type('image/avif'), url('../assets/panel-products.jpg') type('image/jpeg')); }
	.bg-panel-quarry { background-image: image-set(url('../assets/panel-quarry-m1125.avif') type('image/avif'), url('../assets/panel-quarry.jpg') type('image/jpeg')); }
}
@media (min-width: 640px) and (max-width: 1023px) {
	.bg-hero-slide-aerial { background-image: image-set(url('../assets/hero-slide-aerial-t1536.avif') type('image/avif'), url('../assets/hero-slide-aerial.jpg') type('image/jpeg')); }
	.bg-hero-slide-concrete { background-image: image-set(url('../assets/hero-slide-concrete-t1536.avif') type('image/avif'), url('../assets/hero-slide-concrete.jpg') type('image/jpeg')); }
	.bg-hero-slide-quarry { background-image: image-set(url('../assets/hero-slide-quarry-t1536.avif') type('image/avif'), url('../assets/hero-slide-quarry.jpg') type('image/jpeg')); }
	.bg-hero-slide-quarry-face { background-image: image-set(url('../assets/hero-slide-quarry-face-t1536.avif') type('image/avif'), url('../assets/hero-slide-quarry-face.jpg') type('image/jpeg')); }
	.bg-cta-aerial { background-image: image-set(url('../assets/cta-aerial-t1536.avif') type('image/avif'), url('../assets/cta-aerial.jpg') type('image/jpeg')); }
	.bg-panel-civils { background-image: image-set(url('../assets/panel-civils-1536.avif') type('image/avif'), url('../assets/panel-civils.jpg') type('image/jpeg')); }
	.bg-panel-concrete { background-image: image-set(url('../assets/panel-concrete-1536.avif') type('image/avif'), url('../assets/panel-concrete.jpg') type('image/jpeg')); }
	.bg-panel-products { background-image: image-set(url('../assets/panel-products-1536.avif') type('image/avif'), url('../assets/panel-products.jpg') type('image/jpeg')); }
	.bg-panel-quarry { background-image: image-set(url('../assets/panel-quarry-1536.avif') type('image/avif'), url('../assets/panel-quarry.jpg') type('image/jpeg')); }
}
@media (min-width: 1024px) {
	.bg-hero-slide-aerial { background-image: image-set(url('../assets/hero-slide-aerial-1920.avif') type('image/avif'), url('../assets/hero-slide-aerial.jpg') type('image/jpeg')); }
	.bg-hero-slide-concrete { background-image: image-set(url('../assets/hero-slide-concrete-1920.avif') type('image/avif'), url('../assets/hero-slide-concrete.jpg') type('image/jpeg')); }
	.bg-hero-slide-quarry { background-image: image-set(url('../assets/hero-slide-quarry-1920.avif') type('image/avif'), url('../assets/hero-slide-quarry.jpg') type('image/jpeg')); }
	.bg-hero-slide-quarry-face { background-image: image-set(url('../assets/hero-slide-quarry-face-1920.avif') type('image/avif'), url('../assets/hero-slide-quarry-face.jpg') type('image/jpeg')); }
	.bg-cta-aerial { background-image: image-set(url('../assets/cta-aerial-1920.avif') type('image/avif'), url('../assets/cta-aerial.jpg') type('image/jpeg')); }
	.bg-panel-civils { background-image: image-set(url('../assets/panel-civils-1920.avif') type('image/avif'), url('../assets/panel-civils.jpg') type('image/jpeg')); }
	.bg-panel-concrete { background-image: image-set(url('../assets/panel-concrete-1920.avif') type('image/avif'), url('../assets/panel-concrete.jpg') type('image/jpeg')); }
	.bg-panel-products { background-image: image-set(url('../assets/panel-products-1920.avif') type('image/avif'), url('../assets/panel-products.jpg') type('image/jpeg')); }
	.bg-panel-quarry { background-image: image-set(url('../assets/panel-quarry-1920.avif') type('image/avif'), url('../assets/panel-quarry.jpg') type('image/jpeg')); }
}
/* retina laptops and hi-dpi desktops: the -hi tier, source-capped (2560/2000/2126/2560) */
@media (min-width: 1024px) and (min-resolution: 1.5dppx) {
	.bg-hero-slide-aerial { background-image: image-set(url('../assets/hero-slide-aerial-hi.avif') type('image/avif'), url('../assets/hero-slide-aerial.jpg') type('image/jpeg')); }
	.bg-hero-slide-concrete { background-image: image-set(url('../assets/hero-slide-concrete-hi.avif') type('image/avif'), url('../assets/hero-slide-concrete.jpg') type('image/jpeg')); }
	.bg-hero-slide-quarry { background-image: image-set(url('../assets/hero-slide-quarry-hi.avif') type('image/avif'), url('../assets/hero-slide-quarry.jpg') type('image/jpeg')); }
	.bg-hero-slide-quarry-face { background-image: image-set(url('../assets/hero-slide-quarry-face-hi.avif') type('image/avif'), url('../assets/hero-slide-quarry-face.jpg') type('image/jpeg')); }
}

/* Horizontal overflow at the mid widths, found by the pass-3 matrix and PRE-EXISTING
   (identical before this pass): from 640px the footer becomes a flex row of
   logo + 4-column nav + CTA, and the nav alone needs about 800px, so between roughly
   640 and 1090 the row ran to 1077px and the document scrolled sideways by 309px at
   768. Earlier passes only probed 375, 1280 and 1440, where it happens to fit, so it
   was never seen. Both rows may wrap here. Scoped to 640..1279 deliberately: 1280 and
   1440 never overflowed and must keep the 440px footer that section-diff bands against
   the reference, so those widths are untouched. */
@media (min-width: 640px) and (max-width: 1279px) {
	.footer-main { flex-wrap: wrap; row-gap: 2.5rem; }
	.footer-nav.show-for-medium { flex-wrap: wrap; row-gap: 1.5rem; }
}

/* WCAG 2.2 AA contrast, measured with axe-core. --ink-muted (#a0a0a3) is correct on the
   dark canvas (6.87:1) but fails on the light surfaces: 2.37:1 for .view-all on
   --surface-light and 2.61:1 for .chip on white, against a 4.5:1 bar for text this size.
   The token stays as the kit defines it; light-surface muted text gets its own value,
   same neutral hue, dark enough to pass on both light beds (5.08:1 on white,
   4.62:1 on --surface-light). This is the one intentional colour change in pass 3. */
:root { --ink-muted-on-light: #6e6e71; }
.chip,
.bg-gray-ltr .text-gray-md,
.on-light .text-gray-md,
.card-surface .text-gray-md,
.product-card .text-gray-md { color: var(--ink-muted-on-light); }

/* Skip link: first in tab order, off-screen until focused. */
.skip-link {
	position: absolute;
	z-index: 100;
	top: 0;
	left: 0;
	padding: 0.75rem 1.25rem;
	font-weight: 600;
	font-size: 0.875rem;
	text-transform: uppercase;
	letter-spacing: 0.1em;
	color: var(--ink);
	background: var(--accent);
	transform: translateY(-150%);
	transition: transform 0.2s ease;
}
.skip-link:focus { transform: translateY(0); }
main:focus { outline: none; }

/* Focus visibility: never rely on the UA ring alone over the dark canvas. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible,
[tabindex]:focus-visible {
	outline: 3px solid var(--accent);
	outline-offset: 2px;
}
/* 2.4.11: a focused target must not sit under the sticky header. */
:target,
main, section, [id] { scroll-margin-top: 11rem; }

/* No-JS navigation. The drawer is the only nav below 1024px and it can only be opened
   by script, so with JS off a phone had no way to leave the page at all. Without the
   js class the burger is dropped and the real nav is shown inline, wrapping as needed. */
html:not(.js) .menu-trigger { display: none; }
html:not(.js) .header-nav { display: block; }
html:not(.js) .header-nav ul { flex-wrap: wrap; justify-content: flex-end; row-gap: 0.25rem; }
@media (max-width: 1023px) {
	html:not(.js) .header-nav ul li { margin: 0 0 0 1.25rem; }
	html:not(.js) .header-nav ul li a { font-size: 0.75rem; }
}
/* The drawer markup ships the inert attribute, which removes its links from both the
   tab order and the accessibility tree while it is closed; JS toggles only that one
   attribute. It is also visibility:hidden until open (see .menu above). aria-hidden was
   dropped: on a container full of focusable links it is the hidden-focusable error, and
   inert expresses the same intent correctly. */

@media (prefers-reduced-motion: reduce) {
	.skip-link { transition: none; }
}

/* ---------- legal routes (terms, privacy): long-form text column ----------
   Spacing only, and every value is one the system already uses: the .blurb-head
   voice carries each section head (same 2rem accent dash under the label, added
   to that rule's selector list rather than restated), .prose carries the body at
   its own 48rem measure, and the link affordance is the hairline underline the
   contact block already ships, because a mailto inside a paragraph otherwise
   renders identical to the text around it. The rule above the closing note is
   the footer nav's own hairline. No new token, no radius, no shadow. */
.legal-block { margin-top: 2.5rem; }
@media (min-width: 1024px) { .legal-block { margin-top: 4rem; } }
.legal-block .blurb-head { margin-bottom: 1.5rem; }
.legal-block .prose a {
	text-decoration: underline;
	text-decoration-thickness: 1px;
	text-underline-offset: 0.25em;
	text-decoration-color: rgba(160, 160, 163, 0.45); /* --ink-muted at the hairline alpha */
	transition: color 0.3s ease, text-decoration-color 0.3s ease;
}
.legal-block .prose a:hover { color: var(--ink); text-decoration-color: var(--ink); }
.legal-note {
	max-width: 48rem;
	margin-top: 2.5rem;
	padding-top: 2.5rem;
	border-top: 1px solid rgba(160, 160, 163, 0.25);
}
@media (min-width: 1024px) { .legal-note { margin-top: 4rem; padding-top: 4rem; } }
