/* ==========================================================================
   mikeui.co design system
   --------------------------------------------------------------------------
   Traced from the mikeui.co Figma handoff (frame 17426:160 About,
   17439:862 Projects). The desktop design is specified proportionally against
   a 1512px frame, so display type and bleed positions are expressed in vw of
   that frame; gutters and gaps stay in px, exactly as the source does.

   Layout is flow based (grid/flex) rather than absolutely positioned like the
   prototype, so ACF-edited copy can grow without bursting a section.

   Breakpoint: below 768px the mobile layout takes over (single column,
   16px gutters, 430px max content width, 44px minimum hit targets).
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */

:root {
	/* Surfaces */
	--c-dark: #121212;
	/* The live site has no #191917 anywhere: every dark surface is #121212.
	   The name is kept so the scrim literals still read sensibly. */
	--c-near-black: #121212;
	--c-footer: #131313;
	--c-watermark: #1c1c1c;
	--c-light: #f8f8f8;
	--c-white: #fff;
	--c-card: #e3e5e8;
	--c-video-frame: #d9d9d9;

	/* Text */
	--c-muted: #7c7c7c;
	--c-muted-light: #9ea1ae;

	/* Lines */
	--c-border-dark: #2b2b2b;
	--c-divider-dark: rgba(255, 255, 255, 0.12);
	--c-divider-light: #dedede;

	/* Accent */
	--c-star: #d69900;

	/* Families. Sora is display only: short headings, few words. Inter carries
	   all body and paragraph text. Overpass Mono is for eyebrows, labels and
	   supporting text. (Was DM Mono per docs/LIVE-BASELINE.md, but that is the
	   old Elementor site and the theme never loads it: see functions.php.) */
	--f-display: "Sora", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
	--f-body: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Arial, sans-serif;
	--f-mono: "Overpass Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

	/* Display scale: mobile floor, then the live site's exact vw of the 1512
	   frame, with a cap so ultra-wide stays sane. */
	--fs-d1: clamp(2.75rem, 8vw, 10rem); /* 44 -> 121 @1512 */
	--fs-d2: clamp(2.375rem, 6vw, 7.5rem); /* 38 -> 90.7 */
	--fs-d3: clamp(2.125rem, 5vw, 6.5rem); /* 34 -> 75.6 */
	--fs-d4: clamp(2.125rem, 4.76vw, 6rem); /* 34 -> 72 footer */
	--fs-d5: clamp(1.5rem, 2.12vw, 2.75rem); /* 24 -> 32 CTA line */
	--fs-statement: clamp(1.25rem, 2.12vw, 2.75rem); /* 20 -> 32 */

	/* Body scale */
	--fs-body: 1rem;
	--fs-body-sm: 0.9375rem;
	--fs-quote: clamp(1.125rem, 1.32vw, 1.5rem);
	--fs-card-title: clamp(1.25rem, 1.59vw, 1.75rem);
	--fs-mono: 0.75rem;

	/* Display metrics */
	--ls-display: -0.08em;
	--lh-display: 1.1;

	/* Body metrics, measured off the live site */
	--ls-body: -0.02em;
	--lh-body: 1.4;

	/* Rhythm */
	--gutter: 16px;
	--gap: 20px;
	--section-y: clamp(72px, 7.94vw, 120px);

	/* Motion */
	--ease-out: cubic-bezier(0.16, 1, 0.3, 1);
}

@media (min-width: 768px) {
	:root {
		--gutter: 20px;
	}
}

/* --------------------------------------------------------------------------
   1b. Generated handoff pages (.dc-page)
   --------------------------------------------------------------------------
   The four designed pages are generated verbatim from design/handoff/*.dc.html
   and are fully self-styled inline. These rules only provide what the
   prototype runtime used to: responsive branch switching, hidden overlays,
   and protection from this stylesheet's own element resets. */

.dc-desktop { display: block; }
.dc-mobile { display: none; }

@media (max-width: 767px) {
	.dc-desktop { display: none; }
	.dc-mobile { display: block; }
}

/* Overlays are closed via the hidden attribute; inline display styles on the
   generated markup must not beat it. */
[data-compose][hidden],
[data-mobile-menu][hidden] {
	display: none !important;
}

/* The prototypes ran without this sheet's element resets and body type
   tokens; neutralise both inside generated markup so nothing shifts against
   the handoff. Verified: without the type guard the inherited -0.02em body
   tracking shrinks every unstyled text run by 1-4px. */
.dc-page {
	letter-spacing: normal;
	line-height: normal;
}

/* The prototypes were authored against UA default content-box; elements that
   need border-box declare it inline. This sheet's global border-box reset
   otherwise shrinks any bare height+padding combo (verified: the Project hero
   header row measured 48px instead of 68px). */
.dc-page *,
.dc-page *::before,
.dc-page *::after {
	box-sizing: revert;
}

.dc-page img,
.dc-page svg,
.dc-page video {
	display: revert;
	max-width: revert;
	height: revert;
}

@media (prefers-reduced-motion: reduce) {
	.dc-page [data-marquee] {
		animation: none !important;
	}
}

/* --------------------------------------------------------------------------
   2. Reset and base
   -------------------------------------------------------------------------- */

*,
*::before,
*::after {
	box-sizing: border-box;
}

html {
	-webkit-text-size-adjust: 100%;
	scroll-behavior: smooth;
}

body {
	margin: 0;
	/* The live site's body is white; dark is applied per band. */
	background: var(--c-white);
	color: var(--c-dark);
	font-family: var(--f-body);
	font-size: var(--fs-body);
	line-height: var(--lh-body);
	letter-spacing: var(--ls-body);
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
	overflow-x: hidden;
}

body.is-locked {
	overflow: hidden;
}

/* Interactive states for the one shared compose modal
   (template-parts/compose.php). These are the handoff's style-focus /
   style-hover / style-active attributes: the converter turns those into
   generated dcs-N classes, but the modal now renders on blog pages too, where
   no generated stylesheet exists, so they live here under stable names. */
.mk-cmp-field:focus {
	box-shadow: inset 0 0 0 1px #121212 !important;
}

.mk-cmp-close:hover {
	opacity: 0.7 !important;
}

/* The blog-family templates are dark end to end, but body is white for the
   four designed pages. <main id="main"> is emitted only by chrome-header.php,
   so it is an exact hook for those templates: paint it dark and no seam
   between two dark blocks can flash white again. */
#main {
	background: var(--c-dark);
}

/* Menu icon: two right-aligned bars (26px + 17px, 7px apart) that rotate into
   an X. The opener in the header and the closer in the overlay carry identical
   markup and sit at the same viewport spot, so swapping between them is
   invisible and the morph reads as one continuous icon.

   Transforms only: the bar width/height/background are inline styles from the
   handoff and must not be fought with !important. The short bar is scaled to
   the long bar's length and shifted left so both bars share a centre, or the
   X comes out lopsided. Numbers derive from the bar geometry above:
   translateY 4.25 = (7 + 1.5) / 2, scaleX 1.5294 = 26 / 17, translateX -4.5 =
   -(26 - 17) / 2. */
[data-burger] [data-bar] {
	transition: transform 300ms cubic-bezier(0.65, 0, 0.35, 1);
	will-change: transform;
}

[data-mobile-menu].is-open [data-burger] [data-bar="1"] {
	transform: translateY(4.25px) rotate(45deg);
}

[data-mobile-menu].is-open [data-burger] [data-bar="2"] {
	transform: translate(-4.5px, -4.25px) rotate(-45deg) scaleX(1.5294);
}

/* The panel fades with the icon rather than vanishing under it. main.js keeps
   the overlay mounted for data-exit-ms after .is-open is dropped so this and
   the reverse icon morph both get to run. */
[data-mobile-menu] {
	transition: opacity 300ms cubic-bezier(0.65, 0, 0.35, 1);
}

[data-mobile-menu]:not(.is-open) {
	opacity: 0;
}

@media (prefers-reduced-motion: reduce) {
	[data-burger] [data-bar],
	[data-mobile-menu] {
		transition: none;
	}
}

img,
video,
svg {
	display: block;
	max-width: 100%;
}

img,
video {
	height: auto;
}

a {
	color: inherit;
	text-decoration: none;
	transition: opacity 250ms var(--ease-out);
}

a:hover {
	opacity: 0.7;
}

button {
	font: inherit;
	color: inherit;
	background: none;
	border: 0;
	padding: 0;
	cursor: pointer;
}

h1,
h2,
h3,
h4,
p,
figure,
blockquote,
dd {
	margin: 0;
}

ul,
ol {
	margin: 0;
	padding: 0;
	list-style: none;
}

::selection {
	background: var(--c-near-black);
	color: var(--c-white);
}

:focus-visible {
	outline: 2px solid currentColor;
	outline-offset: 3px;
}

.u-sr {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

.skip-link {
	position: fixed;
	top: -100px;
	left: var(--gutter);
	z-index: 200;
	padding: 12px 20px;
	background: var(--c-white);
	color: var(--c-dark);
	font-family: var(--f-mono);
	font-weight: 500;
	font-size: var(--fs-mono);
	letter-spacing: 0.03em;
	text-transform: uppercase;
}

.skip-link:focus {
	top: 12px;
}

/* --------------------------------------------------------------------------
   3. Typography primitives
   -------------------------------------------------------------------------- */

.t-display {
	font-family: var(--f-display);
	font-weight: 400;
	line-height: var(--lh-display);
	letter-spacing: var(--ls-display);
}

.t-d1 { font-size: var(--fs-d1); }
.t-d2 { font-size: var(--fs-d2); }
.t-d3 { font-size: var(--fs-d3); }
.t-d4 { font-size: var(--fs-d4); }
.t-d5 { font-size: var(--fs-d5); }

.t-label {
	font-family: var(--f-mono);
	font-weight: 500;
	font-size: var(--fs-mono);
	line-height: 1.2;
	letter-spacing: 0.03em;
	text-transform: uppercase;
}

.t-body {
	font-size: var(--fs-body);
	line-height: var(--lh-body);
	letter-spacing: var(--ls-body);
}

.t-body-sm {
	font-size: var(--fs-body-sm);
	line-height: 1.5;
	letter-spacing: var(--ls-body);
}

.t-muted { color: var(--c-muted); }
.t-muted-light { color: var(--c-muted-light); }

/* --------------------------------------------------------------------------
   4. Layout primitives
   -------------------------------------------------------------------------- */

.shell {
	width: 100%;
	padding-inline: var(--gutter);
}

@media (max-width: 767px) {
	.shell > * {
		max-width: 430px;
		margin-inline: auto;
	}
}

.section {
	position: relative;
	padding-block: var(--section-y);
	/* Contain descendant margins. Without a BFC, the first child's top margin
	   collapses up and out of the section and moves the section box itself
	   down: .entry__content's clamp(40px, 3.97vw, 60px) escaped through
	   .entry and .shell and opened a 57px gap above every .section--flush-top,
	   which showed the page background instead of the section's own. */
	display: flow-root;
}

.section--dark {
	background: var(--c-dark);
	color: var(--c-white);
}

.section--near-black {
	background: var(--c-near-black);
	color: var(--c-white);
}

.section--light {
	background: var(--c-light);
	color: var(--c-dark);
}

.section--white {
	background: var(--c-white);
	color: var(--c-dark);
}

.section--flush-top { padding-top: 0; }
.section--flush-bottom { padding-bottom: 0; }
.section--clip { overflow: hidden; }

.divider {
	height: 1px;
	border: 0;
	margin: 0;
	background: var(--c-divider-dark);
}

.section--light .divider,
.section--white .divider {
	background: var(--c-divider-light);
}

/* --------------------------------------------------------------------------
   5. Buttons
   -------------------------------------------------------------------------- */

.btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 10px;
	font-family: var(--f-mono);
	font-weight: 500;
	font-size: var(--fs-mono);
	line-height: 1.2;
	letter-spacing: 0.03em;
	text-transform: uppercase;
	/* Live button measures 171x42 with this exact asymmetric padding. */
	padding: 14px 24px 12px;
	min-height: 42px;
	background: var(--c-white);
	color: var(--c-dark);
	transition: background-color 250ms var(--ease-out), color 250ms var(--ease-out);
}

.btn:hover {
	opacity: 1;
	background: var(--c-card);
}

.btn--lg { padding: 24px 30px; }

.btn--dark {
	background: var(--c-near-black);
	color: var(--c-white);
}

.btn--dark:hover { background: var(--c-dark); }

/* Plain text + icon variant used by the header email action. */
/* The header CTA on every designed page. port-handoff.py normalises About and
   Projects to this same bordered button, so the blog chrome uses it too.
   Values verbatim from the handoff: Overpass Mono 600 at 12px, 0.08em, 14/24
   padding, a 1px white rule, inverting on hover. */
.btn--outline {
	padding: 14px 24px;
	min-height: 0;
	background: none;
	border: 1px solid var(--c-white);
	color: var(--c-white);
	font-family: var(--f-mono);
	font-weight: 600;
	/* Scales with the designed pages' header CTA; see .site-nav a above. */
	font-size: clamp(12px, 0.794vw, 16.2px);
	line-height: 1.2;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	transition: background-color 250ms ease, color 250ms ease;
}

.btn--outline:hover {
	background: var(--c-white);
	color: var(--c-dark);
}

.btn--bare {
	background: none;
	color: inherit;
	padding: 0;
	min-height: 0;
	font-family: var(--f-body);
	font-weight: 400;
	font-size: var(--fs-body);
	line-height: var(--lh-body);
	letter-spacing: var(--ls-body);
	text-transform: none;
}

.btn--bare:hover {
	background: none;
	opacity: 0.7;
}

.btn__icon {
	width: 16px;
	height: 16px;
	flex: none;
	stroke: currentColor;
	fill: none;
}

/* --------------------------------------------------------------------------
   6. Header and navigation
   -------------------------------------------------------------------------- */

/* An 80px band in normal flow with its own dark background, matching the live
   site. It is not an overlay, so the heroes below it need no top clearance. */
/* This must match the header the handoff bakes into the four designed pages,
   or the chrome visibly changes when you cross from /about/ to /blog/.
   Canonical values come from the GENERATED templates, not the handoff source:
   port-handoff.py's normalise_header rewrites the row to
   "position: absolute; left/right 20px; top: 28px; height: 48px" on all four
   pages. Reading 20px off the handoff put this header 8px high, which is why
   the chrome jumped when crossing between /blog/ and /about/. Mobile is
   14px/16px with a 34x23 logo. */
.site-header {
	position: relative;
	z-index: 40;
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 20px;
	box-sizing: content-box;
	height: 48px;
	padding: 28px 20px 0;
	background: var(--c-dark);
	color: var(--c-white);
}

@media (max-width: 767px) {
	.site-header {
		height: 44px;
		padding: 14px 16px 0;
	}

	.site-header__logo {
		width: 34px;
		height: 23px;
	}
}

.site-header__logo {
	display: block;
	width: 40px;
	height: 27px;
	flex: none;
}

.site-header__logo svg {
	width: 100%;
	height: 100%;
	fill: currentColor;
}

.site-nav {
	display: flex;
	align-items: center;
	gap: 24px;
}

/* Inter 16px/400, fading on hover: same as the designed pages' nav links.
   The clamp mirrors port-handoff.py's fluid_desktop_type, clamp(px, px/15.12
   vw, px*1.35): identical at and below 1512 and growing in step above it.
   Without it this header stayed put while the designed pages' grew, so the
   chrome visibly jumped crossing from /blog/ to /about/ on a wide screen. */
.site-nav a {
	font-family: var(--f-body);
	font-size: clamp(16px, 1.058vw, 21.6px);
	font-weight: 400;
	line-height: 1.5;
	letter-spacing: normal;
	color: var(--c-white);
	transition: opacity 200ms ease;
}

.site-nav a:hover { opacity: 0.7; }

.site-nav a[aria-current="page"] { opacity: 0.6; }

.nav-toggle {
	display: none;
	width: 44px;
	height: 44px;
	margin-right: -10px;
	align-items: center;
	justify-content: flex-end;
}

/* Bar geometry for the blog-family chrome. The generated pages carry the same
   numbers as inline styles from the handoff, so these are a no-op there. */
[data-burger] {
	flex-direction: column;
	align-items: flex-end;
	justify-content: center;
	gap: 7px;
	padding: 0;
	background: none;
	border: none;
	cursor: pointer;
	color: inherit;
}

[data-burger] [data-bar] {
	display: block;
	height: 1.5px;
	background: currentColor;
}

[data-burger] [data-bar="1"] {
	width: 26px;
}

[data-burger] [data-bar="2"] {
	width: 17px;
}

@media (max-width: 767px) {
	.site-nav { display: none; }
	.nav-toggle { display: flex; }
}

.mobile-menu {
	position: fixed;
	inset: 0;
	z-index: 90;
	display: flex;
	flex-direction: column;
	padding: 20px var(--gutter) 40px;
	background: var(--c-dark);
	color: var(--c-white);
	opacity: 0;
	pointer-events: none;
	transition: opacity 300ms var(--ease-out);
}

.mobile-menu.is-open {
	opacity: 1;
	pointer-events: auto;
}

/* The closed state is the [hidden] attribute, not visibility. The class sets
   display:flex, which would otherwise beat the UA [hidden] rule and leave the
   overlay in the layout. Keeping visibility out of the transition also means
   focus() works the instant the overlay opens. */
.mobile-menu[hidden] {
	display: none;
}

.mobile-menu__top {
	display: flex;
	align-items: center;
	justify-content: space-between;
	min-height: 48px;
}

.mobile-menu__close {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 44px;
	height: 44px;
	margin-right: -10px;
}


.mobile-menu__list {
	display: flex;
	flex-direction: column;
	gap: 8px;
	margin-top: 48px;
}

.mobile-menu__list a {
	display: flex;
	align-items: center;
	min-height: 44px;
	font-family: var(--f-display);
	font-weight: 400;
	font-size: 2rem;
	letter-spacing: var(--ls-display);
}

.mobile-menu__cta { margin-top: auto; }

/* --------------------------------------------------------------------------
   7. Home hero
   -------------------------------------------------------------------------- */

/* The header band takes the first 80px, so the hero fills the rest of the
   viewport. Content is bottom-anchored: the live H1 ends 90px above the fold. */
.hero-home {
	position: relative;
	display: flex;
	flex-direction: column;
	justify-content: flex-end;
	min-height: calc(100svh - 80px);
	padding-block: 40px 90px;
	background: var(--c-dark);
	color: var(--c-white);
	overflow: hidden;
}

@media (max-width: 767px) {
	.hero-home {
		min-height: calc(100svh - 64px);
		padding-block: 32px 56px;
	}
}

.hero-home__titles span {
	display: block;
	font-family: var(--f-display);
	font-weight: 400;
	font-size: var(--fs-d1);
	line-height: var(--lh-display);
	letter-spacing: var(--ls-display);
}

.hero-home__intro {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: 24px;
}

/* Live layout: the H1 is a 477 column at the left, the intro a 497 column at
   the right, both bottom-anchored. The portrait is not in the hero at all: it
   is a 477x862 rectangle in the middle column that starts at the hero's bottom
   edge and runs down into the section below. */
@media (min-width: 768px) {
	.hero-home__inner {
		display: grid;
		grid-template-columns: 31.55vw 1fr 32.87vw;
		gap: var(--gap);
		align-items: end;
	}

	.hero-home__intro {
		grid-column: 3;
		margin-bottom: 52px;
	}

	.hero-home__titles {
		grid-column: 1;
	}
}

.hero-portrait {
	position: relative;
	z-index: 1;
	display: block;
	width: 31.55vw;
	aspect-ratio: 477 / 862;
	object-fit: cover;
	margin-inline: auto;
	margin-top: -20px;
}

@media (max-width: 767px) {
	.hero-portrait {
		width: 100%;
		max-width: 430px;
		aspect-ratio: 4 / 5;
		margin-top: 0;
	}
}

/* --------------------------------------------------------------------------
   8. Bridge heading and marquees
   -------------------------------------------------------------------------- */

.bridge {
	padding-block: var(--section-y) 0;
	background: var(--c-white);
	color: var(--c-dark);
	overflow: hidden;
}

.bridge__heading {
	font-family: var(--f-display);
	font-weight: 400;
	font-size: var(--fs-d2);
	line-height: var(--lh-display);
	letter-spacing: var(--ls-display);
	text-align: center;
	text-wrap: balance;
}

/* GSAP scrubs --gap-close from 16px down to 0 as the section scrolls.
   The resting value is 0, so with no JS the words sit at their normal gap. */
.bridge__gap-word { margin-left: var(--gap-close, 0px); }

.marquees {
	display: flex;
	flex-direction: column;
	gap: var(--gap);
	margin-top: clamp(40px, 5.29vw, 80px);
}

.marquee {
	display: flex;
	width: 100%;
	overflow: hidden;
}

.marquee__track {
	display: flex;
	gap: var(--gap);
	flex: none;
	padding-right: var(--gap);
}

.marquee__track img {
	width: clamp(220px, 23.81vw, 420px);
	aspect-ratio: 1296 / 762;
	object-fit: cover;
	flex: none;
}

/* --------------------------------------------------------------------------
   9. Statement and video demo
   -------------------------------------------------------------------------- */

/* White band with dark text on the live site, and the paragraphs are set at
   32px Inter 500, not body size. */
.statement {
	position: relative;
	background: var(--c-white);
	color: var(--c-dark);
	overflow: hidden;
}

.statement__render {
	position: absolute;
	left: -18.3vw;
	top: 18.7vw;
	width: 46.2vw;
	transform: rotate(-24.7deg);
	transform-origin: 0 0;
	pointer-events: none;
	z-index: 0;
}

.statement__inner {
	position: relative;
	z-index: 1;
	display: grid;
	gap: clamp(32px, 3.97vw, 60px);
}

.statement__copy {
	display: grid;
	gap: 24px;
}

.statement__copy p {
	font-family: var(--f-body);
	font-weight: 500;
	font-size: var(--fs-statement);
	line-height: 1.3;
	letter-spacing: -0.03em;
}

@media (min-width: 768px) {
	.statement__inner {
		grid-template-columns: 1fr 1fr;
		align-items: start;
	}

	.statement__copy { justify-self: end; }
}

.video-card {
	background: var(--c-video-frame);
	padding: 19px;
}

.video-card__shell { position: relative; }

.video-card video,
.video-card__poster {
	width: 100%;
	aspect-ratio: 16 / 9;
	object-fit: cover;
	background: var(--c-dark);
}

/* Click to play: the multi-megabyte source is only fetched on interaction. */
.video-card__play {
	position: absolute;
	inset: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 10px;
	color: var(--c-white);
	background: rgba(18, 18, 18, 0.35);
	font-family: var(--f-mono);
	font-weight: 600;
	font-size: var(--fs-mono);
	letter-spacing: 0.08em;
	text-transform: uppercase;
	transition: background-color 250ms var(--ease-out);
}

.video-card__play svg {
	width: 14px;
	height: 14px;
	fill: currentColor;
}

.video-card__play:hover { background: rgba(18, 18, 18, 0.15); }

.video-card__shell.is-playing .video-card__play { display: none; }

.video-card__caption {
	margin-top: 12px;
	color: var(--c-dark);
}

/* --------------------------------------------------------------------------
   10. Services
   -------------------------------------------------------------------------- */

.services__grid {
	display: grid;
	gap: clamp(40px, 3.97vw, 60px);
	margin-top: clamp(40px, 3.97vw, 60px);
}

.service__title {
	font-family: var(--f-display);
	font-weight: 400;
	font-size: var(--fs-d3);
	line-height: var(--lh-display);
	letter-spacing: var(--ls-display);
}

.service__label { margin-top: 8px; }

.service__body {
	margin-top: 20px;
	max-width: 46ch;
}

.service__media {
	margin-top: 24px;
	width: 100%;
	aspect-ratio: 1;
	object-fit: cover;
}

@media (min-width: 768px) {
	.services__grid { grid-template-columns: 1fr 1fr; }

	.services__grid > :last-child { text-align: right; }

	.services__grid > :last-child .service__body { margin-left: auto; }
}

/* "The best of both worlds": a render sits between the two columns. */
.duo {
	position: relative;
	text-align: center;
}

.duo__render {
	position: relative;
	z-index: 0;
	width: clamp(220px, 46.3vw, 700px);
	margin-inline: auto;
}

.duo__cols {
	position: relative;
	z-index: 1;
	display: grid;
	gap: 32px;
}

.duo__notes {
	display: grid;
	gap: 24px;
	margin-top: clamp(32px, 3.97vw, 60px);
}

.duo__notes p { max-width: 353px; }

@media (min-width: 768px) {
	.duo__cols {
		grid-template-columns: 1fr 1fr;
		align-items: start;
		margin-top: clamp(-160px, -13vw, -60px);
	}

	/* Home: both columns centred over the photo. */
	.duo--center .duo__cols { text-align: center; }

	/* About: columns pushed to the outer edges of the render. */
	.duo--split .duo__cols { text-align: left; }
	.duo--split .duo__cols > :last-child { text-align: right; }

	.duo__notes { grid-template-columns: 1fr 1fr; }

	.duo__notes > :first-child { text-align: right; }

	.duo__notes > :first-child p { margin-left: auto; }

	.duo__notes > :last-child { justify-self: end; }
}

/* --------------------------------------------------------------------------
   11. Website project cards
   -------------------------------------------------------------------------- */

.work__grid {
	display: grid;
	gap: var(--gap);
	margin-top: clamp(40px, 3.97vw, 60px);
}

@media (min-width: 768px) {
	.work__grid { grid-template-columns: 1fr 1fr; }
}

.project-card {
	position: relative;
	display: flex;
	flex-direction: column;
	justify-content: space-between;
	gap: 24px;
	aspect-ratio: 726 / 550;
	min-height: 320px;
	padding: 19px;
	overflow: hidden;
	color: var(--c-white);
	transition: transform 500ms var(--ease-out);
}

.project-card:hover {
	opacity: 1;
	transform: scale(1.01);
}

.project-card:active { transform: scale(0.99); }

.project-card__media {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	z-index: 0;
}

/* Two scrims, top and bottom, so title and body stay legible over any shot. */
.project-card::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 1;
	background:
		linear-gradient(180deg, rgba(25, 25, 23, 0.5) 0%, rgba(25, 25, 23, 0) 21.63%),
		linear-gradient(180deg, rgba(25, 25, 23, 0) 68.75%, rgba(25, 25, 23, 0.4) 100%);
	pointer-events: none;
}

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

.project-card__title {
	font-weight: 500;
	font-size: var(--fs-card-title);
	line-height: 1.4;
	letter-spacing: -0.013em;
}

.project-card__body {
	font-weight: 500;
	max-width: 477px;
	line-height: 1.5;
}

@media (min-width: 768px) {
	.project-card { padding-right: 104px; }
}

/* --------------------------------------------------------------------------
   12. UI/UX list cards
   -------------------------------------------------------------------------- */

.uiux__grid {
	display: grid;
	gap: var(--gap);
	margin-top: var(--gap);
}

@media (min-width: 768px) {
	.uiux__grid { grid-template-columns: 1fr 1fr; }
}

.uiux-card {
	display: flex;
	align-items: flex-start;
	justify-content: space-between;
	gap: 20px;
	padding: 24px;
	border: 1px solid var(--c-border-dark);
	color: var(--c-white);
	transition: background-color 300ms var(--ease-out);
}

.uiux-card:hover {
	opacity: 1;
	background: rgba(255, 255, 255, 0.05);
}

.uiux-card__title {
	font-weight: 500;
	font-size: var(--fs-card-title);
	line-height: 1.4;
	letter-spacing: -0.013em;
}

.uiux-card__tags {
	display: flex;
	flex-wrap: wrap;
	gap: 12px;
	margin-top: 10px;
	color: var(--c-muted-light);
}

.uiux-card__arrow {
	flex: none;
	width: 16px;
	height: 16px;
	stroke: currentColor;
	fill: none;
}

/* Final card is the resume download, inverted. */
.uiux-card--invert {
	background: var(--c-white);
	color: var(--c-dark);
	border-color: var(--c-white);
}

.uiux-card--invert:hover { background: var(--c-card); }

.uiux-card--invert .uiux-card__tags { color: var(--c-muted); }

/* --------------------------------------------------------------------------
   13. CTA block
   -------------------------------------------------------------------------- */

.cta {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 20px;
	text-align: center;
	margin-top: clamp(56px, 5.95vw, 90px);
}

.cta__line {
	font-family: var(--f-display);
	font-weight: 400;
	font-size: var(--fs-d5);
	line-height: var(--lh-display);
	letter-spacing: var(--ls-display);
	max-width: 780px;
	text-wrap: balance;
}

/* --------------------------------------------------------------------------
   14. Testimonials
   -------------------------------------------------------------------------- */

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

.testimonials__render {
	position: absolute;
	left: -19.18vw;
	top: -0.99vw;
	width: 56.28vw;
	pointer-events: none;
	z-index: 0;
}

.testimonials__grid,
.testimonials__head {
	position: relative;
	z-index: 1;
}

.testimonials__grid {
	display: grid;
	gap: var(--gap);
	margin-top: clamp(40px, 5.95vw, 90px);
}

/* Desktop reproduces the two offset rows: row 1 in columns 2-3, row 2 in 1-2. */
@media (min-width: 768px) {
	/* Live site puts this heading at x=776 with a 735 measure, which is the
	   right half of the frame rather than a right-aligned two-column span. */
	.testimonials__head {
		width: 48.6vw;
		margin-left: 51.32vw;
	}

	.testimonials__grid { grid-template-columns: repeat(3, 1fr); }

	.testimonials__grid > :nth-child(1) { grid-column: 2; }
	.testimonials__grid > :nth-child(2) { grid-column: 3; }
	.testimonials__grid > :nth-child(3) { grid-column: 1; }
	.testimonials__grid > :nth-child(4) { grid-column: 2; }
}

@media (max-width: 767px) {
	.testimonials__render {
		position: relative;
		left: -80px;
		top: 0;
		width: 300px;
		margin-block: -30px -50px;
	}
}

.tcard {
	display: flex;
	flex-direction: column;
	gap: 20px;
	padding: 24px;
	background: var(--c-card);
	color: var(--c-dark);
	/* The design fixes the card at 477x414. A min-height rather than a fixed
	   one keeps that proportion while letting a long quote grow the card. */
	min-height: clamp(300px, 27.38vw, 460px);
}

.tcard__top {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 12px;
}

.tcard__stars {
	display: flex;
	gap: 2px;
	color: var(--c-star);
}

.tcard__stars svg {
	width: 14px;
	height: 14px;
	fill: currentColor;
}

.tcard__quote {
	font-weight: 500;
	font-size: var(--fs-quote);
	line-height: 1.3;
	letter-spacing: -0.03em;
	flex: 1;
}

.tcard__person {
	display: flex;
	align-items: center;
	gap: 16px;
}

.tcard__avatar {
	width: 72px;
	height: 72px;
	flex: none;
	border-radius: 50%;
	object-fit: cover;
}

.tcard__name {
	font-weight: 500;
	font-size: var(--fs-quote);
	line-height: 1.3;
}

.tcard__role { margin-top: 4px; }

/* --------------------------------------------------------------------------
   15. About hero
   -------------------------------------------------------------------------- */

/* Top padding excludes the 80px header band, which is now in normal flow. */
.hero-about {
	position: relative;
	background: var(--c-dark);
	color: var(--c-white);
	overflow: hidden;
	padding-top: clamp(100px, 23.15vw, 350px);
}

.hero-about__render {
	position: absolute;
	left: 38.4vw;
	top: -17.9vw;
	width: 46.23vw;
	transform: rotate(21.4deg);
	transform-origin: top left;
	pointer-events: none;
	z-index: 0;
}

@media (max-width: 767px) {
	.hero-about__render {
		left: 30%;
		top: -120px;
		width: 320px;
	}
}

.hero-about__head {
	position: relative;
	z-index: 1;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 24px;
	text-align: center;
}

.hero-about__head h1 { max-width: 18ch; }
.hero-about__head p { max-width: 377px; }

.hero-about__divider { margin-top: clamp(56px, 5.95vw, 90px); }

/* Justified statement with the APPROACH label off to the right. */
.approach {
	position: relative;
	z-index: 1;
	display: grid;
	gap: 24px;
	margin-top: clamp(40px, 3.97vw, 60px);
}

.approach__statement {
	font-family: var(--f-body);
	font-weight: 500;
	font-size: var(--fs-statement);
	line-height: 1.35;
	letter-spacing: -0.015em;
	max-width: 726px;
	text-align: justify;
	text-indent: 3em;
	hyphens: auto;
}

@media (min-width: 768px) {
	.approach {
		grid-template-columns: 1fr auto;
		align-items: start;
	}

	.approach__label { justify-self: end; }
}

.process {
	position: relative;
	z-index: 1;
	display: grid;
	gap: clamp(40px, 3.97vw, 60px);
	margin-top: clamp(56px, 5.95vw, 90px);
	align-items: end;
}

.process__steps {
	display: grid;
	gap: 33px;
	max-width: 478px;
}

.process__step h3 { margin-bottom: 10px; }

.process__portrait {
	width: 100%;
	aspect-ratio: 746 / 884;
	object-fit: cover;
	background: var(--c-video-frame);
}

@media (min-width: 768px) {
	.process {
		grid-template-columns: 1fr 49.34vw;
		gap: var(--gap);
		padding-left: clamp(0px, 9.52vw, 144px);
	}

	/* The portrait sits flush with the hero's bottom edge. Dropping the hero's
	   bottom padding does that exactly; a negative margin on the grid item
	   shifts it unpredictably against align-items:end. */
	.hero-about { padding-bottom: 0; }
}

/* --------------------------------------------------------------------------
   16. Simple page hero (Projects, single project, blog)
   -------------------------------------------------------------------------- */

.hero-page {
	position: relative;
	background: var(--c-dark);
	color: var(--c-white);
	overflow: hidden;
	padding-top: clamp(100px, 23.15vw, 350px);
	padding-bottom: var(--section-y);
	text-align: center;
}

.hero-page__render {
	position: absolute;
	left: 24.67vw;
	top: -26.39vw;
	width: 50.66vw;
	pointer-events: none;
	z-index: 0;
}

@media (max-width: 767px) {
	.hero-page__render {
		left: 15%;
		top: -160px;
		width: 300px;
	}
}

.hero-page > .shell {
	position: relative;
	z-index: 1;
}

.hero-page--compact { padding-top: clamp(60px, 9.26vw, 140px); }

/* --------------------------------------------------------------------------
   17. Single project
   -------------------------------------------------------------------------- */

.hero-page--project { text-align: left; }

.project-hero__back {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	margin-bottom: 32px;
}

.project-hero__back svg {
	width: 12px;
	height: 12px;
	stroke: currentColor;
	fill: none;
}

.project-chips {
	display: flex;
	flex-wrap: wrap;
	gap: 10px;
	margin-top: 24px;
}

.project-chip {
	border: 1px solid var(--c-border-dark);
	padding: 8px 14px;
}

.project-meta {
	display: grid;
	gap: 24px;
	margin-top: clamp(40px, 3.97vw, 60px);
}

@media (min-width: 480px) {
	.project-meta { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

.project-meta dt {
	color: var(--c-muted-light);
	margin-bottom: 8px;
}

.project-meta dd { font-weight: 500; }

.project-figure {
	width: 100%;
	aspect-ratio: 16 / 9;
	object-fit: cover;
	background: var(--c-near-black);
}

.project-overview {
	display: grid;
	gap: 32px;
	max-width: 900px;
}

.project-overview__lead {
	font-family: var(--f-body);
	font-weight: 400;
	font-size: var(--fs-statement);
	line-height: 1.35;
	letter-spacing: -0.015em;
}

.project-figures {
	display: grid;
	gap: var(--gap);
	margin-top: var(--section-y);
}

.project-next {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 24px;
	padding-block: clamp(40px, 3.97vw, 60px);
	background: var(--c-dark);
	color: var(--c-white);
}

.project-next__title {
	font-family: var(--f-display);
	font-weight: 400;
	font-size: clamp(1.75rem, 3.5vw, 3.5rem);
	line-height: var(--lh-display);
	letter-spacing: var(--ls-display);
	margin-top: 12px;
}

.project-next__arrow {
	flex: none;
	width: 28px;
	height: 28px;
	stroke: currentColor;
	fill: none;
}

/* --------------------------------------------------------------------------
   18. Blog
   -------------------------------------------------------------------------- */

.post-list {
	display: grid;
	gap: var(--gap);
	margin-top: clamp(40px, 3.97vw, 60px);
}

@media (min-width: 768px) {
	.post-list { grid-template-columns: 1fr 1fr; }
}

.post-card {
	display: flex;
	flex-direction: column;
	border: 1px solid var(--c-border-dark);
	transition: background-color 300ms var(--ease-out), border-color 300ms var(--ease-out);
}

.post-card:hover {
	opacity: 1;
	background: rgba(255, 255, 255, 0.05);
	border-color: var(--c-divider-dark);
}

/* Cover art sits flush to the card edge; only the text block is padded. */
.post-card__media {
	overflow: hidden;
	background: var(--c-watermark);
}

.post-card__img {
	display: block;
	width: 100%;
	aspect-ratio: 16 / 9;
	object-fit: cover;
	transition: transform 600ms var(--ease-out);
}

.post-card:hover .post-card__img { transform: scale(1.03); }

.post-card__body {
	display: flex;
	flex-direction: column;
	gap: 12px;
	padding: 28px;
}

.post-card__title {
	font-family: var(--f-display);
	font-weight: 400;
	font-size: clamp(1.375rem, 1.85vw, 1.75rem);
	line-height: var(--lh-display);
	letter-spacing: -0.04em;
	text-wrap: balance;
}

.post-card__excerpt { color: var(--c-muted-light); }

/* Reading affordance. Marked aria-hidden in the markup: the whole card is one
   link, so a second "Read" announcement would be noise. */
.post-card__more {
	margin-top: auto;
	padding-top: 8px;
	color: var(--c-muted-light);
	transition: color 250ms var(--ease-out);
}

.post-card__more::after {
	content: " \2192";
	display: inline-block;
	transition: transform 250ms var(--ease-out);
}

.post-card:hover .post-card__more { color: var(--c-white); }
.post-card:hover .post-card__more::after { transform: translateX(4px); }

/* The newest post leads the index: full width, art beside the text on
   desktop, and a larger title. Page 2 onward has no lead (see home.php). */
@media (min-width: 768px) {
	.post-card--lead {
		grid-column: 1 / -1;
		flex-direction: row;
		align-items: stretch;
	}

	.post-card--lead .post-card__media { flex: 1 1 55%; }

	.post-card--lead .post-card__img {
		height: 100%;
		aspect-ratio: auto;
		min-height: 340px;
	}

	.post-card--lead .post-card__body {
		flex: 1 1 45%;
		justify-content: center;
		padding: clamp(32px, 3.2vw, 52px);
	}

	.post-card--lead .post-card__title { font-size: clamp(1.75rem, 2.6vw, 2.5rem); }
}

.entry {
	max-width: 720px;
	margin-inline: auto;
}

/* The article head gets more room than the body. 720px is the right measure
   for reading 17px prose (about 78 characters) but far too tight for a
   headline, which was wrapping long titles into six lines. */
.hero-page .entry {
	max-width: 900px;
}

/* Post titles are not hero words. t-d2 tops out at 120px, which suits "Blog"
   or "Selected Work" and buries a 65-character article title; this scale tops
   out at 52px, so even a long one sits in two or three lines. */
.entry__title {
	font-size: clamp(1.875rem, 3.4vw, 3.25rem);
	line-height: 1.12;
	letter-spacing: -0.04em;
	text-wrap: balance;
}

/* An eyebrow above a display heading needs its own gap: the heading carries no
   top margin and its 1.12 line-height pulls the first line up into the label. */
.entry__eyebrow {
	margin-bottom: 16px;
}

.entry__meta {
	color: var(--c-muted-light);
	margin-top: 20px;
}

/* Cover art breaks out past the 720px measure so the article opens on an
   image wider than its own text, the usual editorial move. Clamped to the
   shell so it never causes a horizontal scroll. */
.entry__cover {
	margin: 0;
	overflow: hidden;
	background: var(--c-watermark);
}

.entry__cover-img {
	display: block;
	width: 100%;
	aspect-ratio: 16 / 9;
	object-fit: cover;
}

@media (min-width: 768px) {
	.entry__cover {
		width: min(1100px, calc(100vw - (var(--gutter) * 2)));
		margin-inline: calc(50% - min(550px, (100vw - (var(--gutter) * 2)) / 2));
	}
}

.entry__content {
	margin-top: clamp(40px, 3.97vw, 60px);
	line-height: 1.7;
	font-size: 1.0625rem;
}

.entry__content > * + * { margin-top: 1.25em; }

/* Lead paragraph. Sets the article's voice before the reader commits, and
   gives the wall of body copy somewhere to start. */
.entry__content > p:first-child {
	font-size: clamp(1.1875rem, 1.6vw, 1.4375rem);
	line-height: 1.5;
	letter-spacing: -0.015em;
	color: var(--c-white);
}

.entry__content h2,
.entry__content h3 {
	font-family: var(--f-display);
	font-weight: 400;
	letter-spacing: -0.04em;
	line-height: 1.2;
	margin-top: 1.8em;
}

.entry__content h2 { font-size: clamp(1.5rem, 2.4vw, 2.25rem); }
.entry__content h3 { font-size: clamp(1.25rem, 1.85vw, 1.625rem); }

.entry__content a {
	text-decoration: underline;
	text-underline-offset: 3px;
}

.entry__content img { width: 100%; }

.entry__content blockquote {
	border-left: 1px solid var(--c-divider-dark);
	padding-left: 24px;
	font-family: var(--f-body);
	font-size: var(--fs-statement);
	letter-spacing: -0.015em;
	line-height: 1.35;
}

.entry__content ul,
.entry__content ol {
	padding-left: 1.4em;
	list-style: disc;
}

.entry__content ol { list-style: decimal; }
.entry__content li + li { margin-top: 0.5em; }

.pagination {
	display: flex;
	gap: 20px;
	justify-content: center;
	margin-top: var(--section-y);
}

/* Post content tables (pricing tiers etc.) */
.entry__content table {
	width: 100%;
	border-collapse: collapse;
	font-size: var(--fs-body-sm);
	line-height: 1.5;
}

.entry__content th,
.entry__content td {
	border: 1px solid var(--c-border-dark);
	padding: 12px 14px;
	text-align: left;
	vertical-align: top;
}

.entry__content th {
	font-family: var(--f-mono);
	font-weight: 600;
	font-size: var(--fs-mono);
	letter-spacing: 0.03em;
	text-transform: uppercase;
	color: var(--c-muted-light);
}

.crumbs {
	margin-bottom: 20px;
}

.crumbs a:hover {
	opacity: 0.7;
}

/* End-of-post CTA */
.entry__cta {
	display: flex;
	flex-direction: column;
	gap: 16px;
	margin-top: clamp(40px, 3.97vw, 60px);
	padding-top: clamp(28px, 2.6vw, 40px);
	border-top: 1px solid var(--c-divider-dark);
}

.entry__cta-row {
	display: flex;
	align-items: center;
	gap: 20px;
	flex-wrap: wrap;
}

.entry__cta-link {
	text-decoration: underline;
	text-underline-offset: 3px;
	color: var(--c-muted-light);
}

/* Older / newer post navigation */
.post-nav {
	display: grid;
	gap: var(--gap);
	margin-top: clamp(40px, 3.97vw, 60px);
}

@media (min-width: 600px) {
	.post-nav {
		grid-template-columns: 1fr 1fr;
	}

	.post-nav__item--next {
		text-align: right;
	}
}

.post-nav__item {
	display: flex;
	flex-direction: column;
	gap: 8px;
	padding: 20px;
	border: 1px solid var(--c-border-dark);
	transition: background-color 300ms var(--ease-out);
}

.post-nav__item:hover {
	opacity: 1;
	background: rgba(255, 255, 255, 0.05);
}

.post-nav__title {
	font-weight: 500;
	line-height: 1.4;
}

/* --------------------------------------------------------------------------
   19. Footer
   -------------------------------------------------------------------------- */

.site-footer {
	position: relative;
	background: var(--c-footer);
	color: var(--c-white);
	overflow: hidden;
	padding-block: clamp(56px, 5.88vw, 89px) clamp(32px, 2.5vw, 38px);
}

.site-footer__watermark {
	position: absolute;
	left: 28.17vw;
	top: 11.57vw;
	width: 55.56vw;
	color: var(--c-watermark);
	pointer-events: none;
	z-index: 0;
}

.site-footer__watermark svg {
	width: 100%;
	height: auto;
	fill: currentColor;
}

.site-footer > .shell {
	position: relative;
	z-index: 1;
}

.site-footer__top {
	display: grid;
	gap: 32px;
	align-items: start;
}

.site-footer__photo {
	width: 191px;
	aspect-ratio: 191 / 146;
	object-fit: cover;
	margin-top: 24px;
}

@media (min-width: 768px) {
	.site-footer__top { grid-template-columns: 1fr auto; }
	.site-footer__cta { justify-self: end; }
}

.site-footer__nav {
	display: flex;
	flex-wrap: wrap;
	gap: 24px;
	justify-content: space-between;
	margin-top: clamp(56px, 6.7vw, 101px);
	padding-top: 24px;
	border-top: 1px solid var(--c-divider-dark);
}

.site-footer__nav ul {
	display: flex;
	flex-wrap: wrap;
	gap: 24px;
}

.site-footer__bottom {
	display: flex;
	flex-wrap: wrap;
	gap: 12px 24px;
	justify-content: space-between;
	align-items: baseline;
	margin-top: clamp(32px, 3.44vw, 52px);
}

.site-footer__clock {
	font-size: 0.875rem;
	font-variant-numeric: tabular-nums;
}

/* The handoff calls for 44px minimum hit targets on mobile. Text links are
   only ~20px tall, so give them a taller box without changing the type. */
@media (max-width: 767px) {
	.btn {
		min-height: 44px;
	}

	.site-footer__nav a,
	.site-footer__nav button,
	.site-nav a,
	.site-nav button {
		display: inline-flex;
		align-items: center;
		min-height: 44px;
	}

	.site-footer__nav ul {
		gap: 0 24px;
	}

	.site-header__logo {
		display: flex;
		align-items: center;
		height: 44px;
	}

	.site-header__logo svg {
		height: 27px;
	}

	.skip-link {
		padding: 15px 20px;
	}
}

/* --------------------------------------------------------------------------
   20. Reduced motion
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
	html { scroll-behavior: auto; }

	*,
	*::before,
	*::after {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
	}

	.marquee__track { transform: none !important; }
}
