/* Homepage-only section styles go here as each section is built. */

/* --- Intro (tagline + logo marquee) --- */

.intro {
	position: relative;
	z-index: 1;
	background: var(--color-white);
	/* Fluid instead of the flat 14.3rem/12rem this used to be — that read as
	   a huge, fixed block of dead space once the viewport got down to phone
	   width, since it never shrank with everything else. No breakpoint
	   needed, same approach as every other fixed section padding below. */
	padding-block: clamp(4rem, 14vw, 14.3rem) clamp(3rem, 10vw, 12rem);
}

.intro__tagline {
	/* Aligned with the site logo (both sit at the .container's left edge),
	   width just over half the design's 1440px reference. margin-inline:0
	   cancels out .container's margin-inline:auto, which otherwise centers
	   this narrower box instead of pinning it to the left edge. The 920px
	   cap only ever binds above ~1045px width (920 / 0.88) — capped at 88%
	   below that so there's still a deliberate gap on the right on any
	   narrower screen, phones included, instead of the text running the
	   full container width. */
	max-width: min(920px, 88%);
	margin-inline: 0;
}

.intro__eyebrow {
	/* Figma spec: font-size 1.6875rem/27px, font-weight 400, line-height
	   2.1875rem — a 1.296 ratio to the font-size, used unitless here for the
	   same reason as .intro__statement. Gap below is fluid too, same reason
	   as .intro's own padding above — a flat 12px read as cramped once
	   .intro__statement scaled up toward its own 3.125rem max via clamp(). */
	margin: 0 0 clamp(12px, 2.5vw, 28px);
	color: var(--color-ink);
	font-weight: 400;
	font-size: 1.6875rem;
	line-height: 1.296;
}

/* The 2.5vw term above stays near its 12px floor at every phone width,
   reading as cramped between the H1 and the statement below it — a
   bigger, separately-tuned gap here rather than just raising that floor
   for every viewport. */
@media (max-width: 900px) {
	.intro__eyebrow {
		margin-bottom: clamp(24px, 8vw, 40px);
	}
}

.intro__statement {
	/* Figma spec (at the 3.125rem/50px max size): font-weight 500, line-height
	   4.1875rem (a 1.34 ratio to the font-size), letter-spacing -0.0625rem
	   (a -0.02em ratio). Using unitless line-height and em letter-spacing
	   instead of fixed rem values keeps both ratios intact as font-size
	   scales down on smaller screens via clamp(), rather than the line-height
	   staying a fixed 67px (too loose once the text shrinks). */
	margin: 0;
	color: var(--color-ink);
	font-weight: 500;
	font-size: clamp(1.75rem, 4vw, 3.125rem);
	line-height: 1.34;
	letter-spacing: -0.02em;
}

/* Underline reveals on scroll-in, staggered per word/phrase (see the
   ".is-visible" toggle in home.js). display:inline-block so the ::after
   underline can be transformed independently of the text's own baseline,
   and so "capture demand" underlines as one continuous phrase while still
   leaving a natural gap before/after it (the comma and space around it sit
   outside the span, so their underlines never touch). */
.intro__highlight {
	position: relative;
	display: inline-block;
}

.intro__highlight::after {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	bottom: -0.05em;
	height: 1px;
	background: #b89c02;
	transform: scaleX(0);
	transform-origin: left;
	transition: transform 0.6s ease;
}

.intro__highlight:nth-of-type(1)::after {
	transition-delay: 0s;
}

.intro__highlight:nth-of-type(2)::after {
	transition-delay: 0.35s;
}

.intro__highlight:nth-of-type(3)::after {
	transition-delay: 0.7s;
}

.intro.is-visible .intro__highlight::after {
	transform: scaleX(1);
}

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

.logo-marquee {
	overflow: hidden;
	width: 100%;
	padding-block: 32px;
	margin-top: clamp(40px, 10vw, 96px);
}

.logo-marquee__track {
	display: flex;
	width: max-content;
	animation: logo-marquee-scroll 32s linear infinite;
}

.logo-marquee__set {
	display: flex;
	align-items: center;
	flex-shrink: 0;
	gap: 64px;
	padding-inline-end: 64px;
}

.logo-marquee__logo-wrap {
	/* Fixed height only — width stays shrink-to-fit so the visual GAP
	   between logo edges stays even (a fixed-width slot would leave a
	   narrow logo surrounded by empty padding inside its own box, making
	   gaps look inconsistent across the row). */
	display: flex;
	align-items: center;
	flex-shrink: 0;
	height: 56px;
}

.logo-marquee__logo {
	/* Height-bound sizing alone (e.g. a flat height:40px on the <img>)
	   gives every logo the same HEIGHT, but a square logo (Relish, Tap
	   Social — both 1:1) ends up with only a 40px-wide footprint next to
	   wide ones like STRAT7 (~5.4:1) rendering at 200px+, making the
	   square logos look noticeably smaller despite matching height.
	   Capping max-width too means a square logo can grow to fill the full
	   56px height (rather than being forced narrow to match), while a
	   wide logo is reined in by the width cap instead of ballooning out. */
	max-width: 130px;
	max-height: 100%;
	width: auto;
	height: auto;
	object-fit: contain;
}

@keyframes logo-marquee-scroll {
	from {
		transform: translateX(0);
	}
	to {
		/* Track holds exactly two identical sets back to back, so -50% is
		   precisely one set's width — the loop point is seamless. */
		transform: translateX(-50%);
	}
}

@media (prefers-reduced-motion: reduce) {
	.logo-marquee__track {
		animation: none;
	}
}

/* The loop itself is already seamless (two identical sets, -50% is exactly
   one set's width — see the keyframes comment above); the 64px gap just
   reads as unusually sparse/gappy on a narrow phone screen, where only
   2-3 logos fit in view at once instead of a whole row, so a large gap
   dominates the visible width in a way it never does on desktop. Tighter
   spacing here makes the row read as more continuous/"infinite" on mobile
   without touching the desktop spacing. */
@media (max-width: 900px) {
	.logo-marquee__set {
		gap: 36px;
		padding-inline-end: 36px;
	}
}

/* --- Video showcase --- */

.video-showcase {
	position: relative;
	z-index: 1;
	background: var(--color-white);
	/* Making it happen (v2) adds no top padding of its own — this bottom
	   padding is the ONLY thing controlling the gap to it below, so it
	   stays a single 8rem (fluid) total rather than stacking with a top
	   padding there too. */
	padding-block: 0 clamp(3rem, 10vw, 8rem);
}

.video-showcase__frame {
	/* Explicit width:100% so this reliably spans the full .container — same
	   left/right edges as the logo, tagline, and marquee above it. */
	position: relative;
	width: 100%;
	aspect-ratio: 16 / 9;
	overflow: hidden;
	background: var(--color-ink);
}

.video-showcase__video {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.video-showcase__audio-toggle {
	position: absolute;
	right: 24px;
	bottom: 24px;
	width: clamp(48px, 6vw, 70px);
	height: clamp(48px, 6vw, 70px);
	padding: 0;
	transition: transform 0.2s ease;
}

.video-showcase__audio-toggle:hover {
	transform: scale(1.08);
}

@media (prefers-reduced-motion: reduce) {
	.video-showcase__audio-toggle {
		transition: none;
	}
}

.video-showcase__audio-toggle-bg,
.video-showcase__audio-toggle-icon {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
}

.video-showcase__audio-toggle-icon {
	/* Speaker icon sits inset within the circle, not edge-to-edge — matches
	   the source asset's own proportions (30.4 x 29.3 within a 70 x 70 circle). */
	width: 43%;
	height: 42%;
	inset: auto;
	top: 50%;
	left: 50%;
	transform: translate(-50%, -50%);
}

.video-showcase__audio-toggle[aria-pressed="true"] {
	opacity: 0.6;
}

/* --- Making it happen --- */

.making-it-happen {
	position: relative;
	z-index: 1;
	background: var(--color-white);
	padding-block: 96px;
}

.making-it-happen__grid {
	display: grid;
	grid-template-columns: 1fr;
	gap: 64px;
}

@media (min-width: 900px) {
	.making-it-happen__grid {
		grid-template-columns: 1fr 1fr;
		gap: 80px;
	}
}

.making-it-happen__heading {
	margin: 0;
	font-family: var(--font-body);
	font-weight: 500;
	font-size: clamp(2.5rem, 5vw, 4.375rem);
	line-height: 1.07;
	letter-spacing: -0.01em;
	color: var(--color-ink);
}

.making-it-happen__reveal {
	/* Fixed-height clipped "window" — matches the Figma source's own
	   overflow-clip approach for this reveal. --row-height drives both this
	   and the track's per-item translate step, so they can never drift out
	   of sync. */
	--row-height: 8rem;
	height: var(--row-height);
	overflow: hidden;
	margin-top: 56px;
}

.making-it-happen__reveal-track {
	/* Default: translated fully below the window, i.e. nothing visible —
	   matches the "nothing on" default state. */
	transform: translateY(var(--row-height));
	transition: transform 0.4s ease;
}

.making-it-happen[data-active="strategy"] .making-it-happen__reveal-track {
	transform: translateY(0);
}

.making-it-happen[data-active="content-creative"] .making-it-happen__reveal-track {
	transform: translateY(calc(var(--row-height) * -1));
}

.making-it-happen[data-active="activation"] .making-it-happen__reveal-track {
	transform: translateY(calc(var(--row-height) * -2));
}

.making-it-happen__reveal-text {
	height: var(--row-height);
	margin: 0;
	overflow: hidden;
	font-size: 20px;
	line-height: 32px;
	color: var(--color-ink);
}

@media (prefers-reduced-motion: reduce) {
	.making-it-happen__reveal-track {
		transition: none;
	}
}

.making-it-happen__nav {
	display: flex;
	flex-direction: column;
}

.making-it-happen__link {
	padding-block: 2.5rem;
	font-family: var(--font-body);
	font-weight: 500;
	font-size: clamp(1.75rem, 3vw, 3.125rem);
	line-height: 1;
	color: var(--color-ink);
	transition: color 0.3s ease;
}

.making-it-happen__divider {
	height: 1px;
	background: var(--color-ink);
}

.making-it-happen[data-active] .making-it-happen__link {
	color: rgba(27, 27, 27, 0.15);
}

.making-it-happen[data-active="strategy"] .making-it-happen__link[data-target="strategy"],
.making-it-happen[data-active="content-creative"] .making-it-happen__link[data-target="content-creative"],
.making-it-happen[data-active="activation"] .making-it-happen__link[data-target="activation"] {
	color: #ff9500;
}

/* --- Specialties --- */

.specialties {
	/* No overflow:hidden here — it's not needed to contain the bg image
	   (inset:0 on an absolutely-positioned element already keeps it within
	   this box), and critically, overflow other than visible on ANY
	   ancestor breaks position:sticky on descendants. That was exactly
	   why the sticky heading wasn't sticking.

	   --section-padding is shared with .specialties__sticky's top offset,
	   so once the heading pins, it sits at the same distance from the
	   viewport top as it started at within the section's own padding —
	   not two independent numbers that happen to look similar. */
	position: relative;
	background: var(--color-ink);
	--section-padding: clamp(4rem, 14vw, 10.3rem);
}

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

.specialties__overlay {
	/* Figma's own composited render is visibly darker/more muted than the
	   raw source photo — approximated here since the exact figure wasn't
	   extractable (rotated image fills break Figma's plain CSS export). */
	position: absolute;
	inset: 0;
	z-index: 0;
	background: rgba(0, 0, 0, 0.3);
	pointer-events: none;
}

.specialties__grid {
	position: relative;
	z-index: 1;
	display: grid;
	grid-template-columns: 1fr;
	gap: 48px;
	padding-block: var(--section-padding);
}

@media (min-width: 900px) {
	.specialties__grid {
		/* align-items:stretch (grid default) is what makes the sticky pin
		   work: .specialties__intro stretches to match .specialties__list's
		   full height, giving .specialties__sticky room to stay pinned for
		   the whole scroll length instead of releasing almost immediately. */
		grid-template-columns: 1fr 1fr;
		/* Matches .making-it-happen__grid's desktop column gap above it. */
		gap: 80px;
	}
}

.specialties__sticky {
	position: sticky;
	top: var(--section-padding);
}

.specialties__heading {
	margin: 0 0 32px;
	color: var(--color-white);
	font-family: var(--font-body);
	font-weight: 500;
	font-size: clamp(2.5rem, 5vw, 4.375rem);
	line-height: 1.07;
	letter-spacing: -0.01em;
}

/* The global .btn hover (background: var(--color-ink)) is meant for
   light-background sections — on this dark section it would hover to a
   black fill that barely reads against the already-dark background. */
.specialties__cta:hover,
.specialties__cta:focus-visible {
	background: var(--color-white);
	color: var(--color-ink);
}

.specialties__group {
	margin-bottom: 32px;
}

.specialties__group:last-child {
	margin-bottom: 0;
}

.specialties__group-heading {
	margin: 0 0 1.44rem;
	color: var(--color-white);
	font-family: var(--font-body);
	font-weight: 400;
	font-size: clamp(1.5rem, 3vw, 1.8rem);
	line-height: 1.25;
}

.specialties__group-divider {
	height: 1px;
	background: var(--color-white);
	margin-bottom: 24px;
}

.specialties__item {
	margin: 0 0 2rem;
	color: var(--color-white);
	font-family: var(--font-body);
	font-weight: 300;
	font-size: clamp(1.5rem, 3vw, 1.9rem);
	line-height: 1.25;
}

/* Dimmed-until-hover only where hovering is actually possible — a touch
   device has no equivalent gesture, so it would otherwise leave every item
   permanently stuck at 60% opacity. Matches the same (hover: hover) gate
   site.js already uses for the primary-menu category triggers. */
@media (hover: hover) {
	.specialties__item {
		opacity: 0.6;
		transition: opacity 0.3s ease, transform 0.3s ease;
	}

	.specialties__item:hover {
		opacity: 1;
		transform: translateX(20px);
	}
}

@media (hover: hover) and (prefers-reduced-motion: reduce) {
	.specialties__item {
		transition: none;
	}
}

@media (max-width: 900px) {
	/* .specialties__intro and .specialties__list are already a single
	   stacked column at this width (see .specialties__grid below) — sticky
	   has nothing left to pin against once they're not two side-by-side
	   columns of different heights, so it's just disabled outright here
	   rather than pinning the heading/CTA oddly over the list beneath it. */
	.specialties__sticky {
		position: static;
	}

	/* Figma's mobile layout wants the CTA AFTER the full list, not grouped
	   with the heading — but the button is nested two levels deep
	   (.specialties__intro > .specialties__sticky > .specialties__cta), and
	   flex/grid `order` only reorders DIRECT children of the same
	   container. display:contents on both wrapper levels removes their own
	   boxes from layout entirely while leaving their children (the heading
	   and the button) to participate directly in .specialties__grid's own
	   flex context instead — at which point `order` can freely interleave
	   them with .specialties__list without any markup duplication or JS. */
	.specialties__grid {
		display: flex;
		flex-direction: column;
		align-items: flex-start;
	}

	.specialties__intro,
	.specialties__sticky {
		display: contents;
	}

	/* Global mobile h2 baseline (2.3rem) — see base.css. */
	.specialties__heading {
		order: 1;
		font-size: clamp(1.875rem, 10vw, 2.3rem);
	}

	.specialties__list {
		order: 2;
	}

	.specialties__cta {
		order: 3;
		margin-top: 8px;
	}
}

/* --- Recent projects --- */

.recent-projects {
	position: relative;
	background: var(--color-offwhite);
	/* Without this, the last card (still visibly offwhite-backed) sits
	   flush against Closing Statement's white background the moment it
	   unsticks — same "big gap" used between Intro/Video Showcase. Kept on
	   the section itself, outside .recent-projects__body, so it stays
	   outside the sticky heading's containing block — see that comment.
	   Fluid like every other fixed section padding in this file. */
	padding-bottom: clamp(4rem, 10vw, 12rem);
}

.recent-projects__body {
	/* The sticky heading below is contained by .recent-projects__heading-zone,
	   not the section — so it stops sticking exactly when the stack ends,
	   not part-way through the section's own padding-bottom gap above.
	   Without that, the heading stayed pinned through that entire gap too,
	   only letting go right at Closing Statement's boundary — "coming down"
	   messily over content it had no business still hovering over.

	   padding-top is set inline (see $stack_top, template-parts/home/
	   recent-projects.php) rather than hardcoded here — .heading-zone is
	   position:absolute (removed from flow) so this padding has to account
	   for the space the heading used to occupy in normal flow by itself,
	   or the stack (and every card timing calc tied to it) would shift up
	   by the heading's height. Keeping it in PHP, next to $heading_top/
	   $heading_height, means it can't quietly drift out of sync with them
	   the way a hand-copied number here already once did. */
	position: relative;
}

.recent-projects__heading-zone {
	/* A dedicated containing block for the heading, sized so it releases at
	   the exact same scroll position the last card does (see PHP), instead
	   of lingering afterward. position:absolute means this doesn't add to
	   .recent-projects__body's own layout height; the real
	   .recent-projects__stack alongside it still does.

	   top MUST match .recent-projects__heading's own sticky "top" (96px,
	   moved down from an original 32px so the heading reads as vertically
	   centred in the gap above the first card once everything's locked,
	   rather than hugging the very top — see PHP's own $heading_top
	   comment) — that's what makes the heading engage sticky with zero
	   visual jump, since its normal-flow starting position and its lock
	   point are then the same number. Using a DIFFERENT top here than on
	   .recent-projects__heading itself (tried once, to try to match where
	   .recent-projects__stack starts) fixed the release timing but broke
	   that: the heading's pre-lock position no longer matched its lock
	   point, so it visibly drifted into place instead of catching cleanly.
	   The height calc (see PHP's $heading_zone_height) accounts for the
	   gap between this and .recent-projects__body's own padding-top
	   instead, so both timings stay correct without moving this element's
	   starting position.

	   top is min()'d against a vh term now too, for the same reason as
	   .recent-projects__heading's own font-size below: the first card's
	   own lock point (top:24vh) moves up on a short viewport, but a flat
	   96px didn't, and confirmed live (a wide-but-short "small laptop"
	   window, where the heading's font-size is also at its widest) that
	   let the locked heading sit right on top of the card underneath it.
	   12vh crosses 96px at 800px of viewport height, so nothing changes
	   above that, same as every other vh-blended value on this site. */
	position: absolute;
	top: min(96px, 12vh);
	left: 0;
	right: 0;
}

.recent-projects__heading {
	/* Pinned the whole time the card stack scrolls beneath it — same
	   "sticky label over long scrolling content" idea as .specialties, and
	   matches the Figma source (its heading is sticky too, not just a
	   one-off title above the stack). top:96px (see .recent-projects__
	   heading-zone's own comment on why it must match that element's top)
	   sits it roughly halfway down the gap between the header and the
	   first card's own lock point (top:24vh, .recent-projects__card),
	   comfortably clear of the fixed header either way. */
	position: sticky;
	top: min(96px, 12vh);
	z-index: 2;
	margin: 0;
	text-align: center;
	font-family: var(--font-body);
	font-weight: 500;
	/* min()'d against a vh term, same crossover math as this element's
	   own top above: confirmed live this needed to shrink too, not just
	   move up — on a wide-but-short viewport the width-driven 5vw term
	   sits close to its own 3.75rem ceiling at exactly the moment the
	   short height leaves the least room to clear the card with. 7.5vh
	   crosses 3.75rem (60px) at the same 800px of viewport height the
	   top term does, so both ease in together. */
	font-size: min(clamp(2rem, 5vw, 3.75rem), 7.5vh);
	color: var(--color-ink);
}

.recent-projects__stack {
	/* Height set inline (see PHP) — it includes the first card's lead-in
	   buffer, which a plain var(--count) * var(--dwell) here wouldn't. */
	position: relative;
}

.recent-projects__wrapper {
	position: absolute;
	left: 0;
	right: 0;
	bottom: 0;
	padding-inline: var(--gutter);
}

.recent-projects__card {
	/* Sized by aspect-ratio, not by stretching to container width — a
	   width-driven card (full container width, height along for the ride)
	   turned into a long, thin strip on short viewports (laptops especially,
	   where vh is limited relative to width). Instead the WIDTH is capped by
	   whichever is smaller: 90% of viewport width, the usual container max,
	   or a height budget (68vh) converted to a matching width via the ratio
	   — so on a short screen, the height constraint wins and the whole card
	   (width included) scales down together, keeping its proportions.

	   Anchored by its TOP edge (top:24vh, no centering transform) rather
	   than centered — centering made the top and bottom gaps shrink/grow
	   together, but the top spacing needed to stay fixed while only the
	   bottom changed. 24vh (nudged up from 19vh) gives the locked-in
	   position a bit more clearance from the pinned heading above it — 19vh
	   read fine mid-scroll but felt too tight once actually stuck.
	   card-shape ratio is 1190/568 — the real image content (once the blank
	   space above it is cropped out, see the PHP comment) plus the info bar. */
	position: sticky;
	top: 24vh;
	width: min(90vw, var(--container-width), calc(68vh * 2.0951));
	aspect-ratio: 1190 / 568;
	margin-inline: auto;
	display: flex;
	flex-direction: column;
	background: var(--color-white);
	overflow: hidden;
	/* Ties the info bar's text/logo/padding to the card's own rendered
	   width, so they scale down together with it (a smaller card on a short
	   laptop screen doesn't end up with oversized, cramped-looking text). */
	container-type: inline-size;
	container-name: rp-card;
}

.recent-projects__media {
	flex: 1 1 auto;
	min-height: 0;
	background: var(--color-offwhite);
}

.recent-projects__media img,
.recent-projects__media video {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}

.recent-projects__info {
	flex-shrink: 0;
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: clamp(8px, 4cqw, 24px);
	padding: clamp(10px, 4cqw, 24px) clamp(14px, 5cqw, 30px);
	background: var(--color-white);
}

.recent-projects__logo {
	/* height clamp scaled up ~20% (from 20-40px to 24-48px) — this only
	   actually grows the near-square logos (Relish, Tap Social), which are
	   height-bound since their computed width never comes close to
	   max-width below. The wide ones (STRAT7, Microsoft, IBM, leafletdrop)
	   are already capped by max-width instead, so their rendered size is
	   governed by that constraint, not this one, and stays unaffected. */
	height: clamp(24px, 8cqw, 48px);
	width: auto;
	max-width: clamp(90px, 27cqw, 160px);
	object-fit: contain;
	flex-shrink: 0;
}

.recent-projects__cta {
	display: flex;
	align-items: center;
	gap: clamp(8px, 3cqw, 24px);
}

.recent-projects__description {
	margin: 0;
	max-width: clamp(180px, 57cqw, 340px);
	text-align: right;
	font-size: clamp(12px, 3.2cqw, 19px);
	line-height: 1.6;
	color: var(--color-ink);
}

.recent-projects__arrow {
	flex-shrink: 0;
	width: clamp(24px, 7.8cqw, 46px);
	height: clamp(24px, 7.8cqw, 46px);
	/* Source icon points down (same asset as the hero scroll indicator) —
	   rotated to point right, matching a "view case study" link here. */
	transform: rotate(-90deg);
}

.recent-projects__arrow img {
	width: 100%;
	height: 100%;
	display: block;
}

@media (max-width: 900px) {
	/* The whole sticky-stack/pile-up effect above is tuned against desktop
	   vh behaviour (see the PHP file's own top comment) — mobile browsers
	   resize their real visible viewport as the address bar/toolbar shows
	   and hides while scrolling, which this effect has no way to account
	   for, so instead of trying to make vh-driven sticky math hold up
	   against a moving target, it's switched off here in favour of a plain
	   stacked list — closer to how Figma's own mobile frame shows this
	   section anyway (no pile-up there either, just cards in a column).
	   Every height/position below with "!important" is overriding a value
	   PHP set as an inline style for the desktop effect — CSS has no way to
	   know at render time which breakpoint the visitor is on, so the
	   inline styles are always there; !important is the only way an
	   ordinary stylesheet rule can still win against that at this width. */
	.recent-projects {
		/* Desktop's offwhite section background is what the cards' own
		   media/info sit directly against with no gap of their own — fine
		   there, since nothing is meant to show through between them. Once
		   cards have real margins around them again (.recent-projects__wrapper
		   below), that same offwhite showed through the gaps too, reading
		   as one continuous grey block with no visible framing at all —
		   Figma's mobile frame has true white around each card, with grey
		   confined to just the logo/text/arrow panel at its bottom. */
		background: var(--color-white);
	}

	.recent-projects__body {
		/* !important: this is a plain external-stylesheet rule fighting an
		   inline style (the desktop $stack_top value, template-parts/home/
		   recent-projects.php) that has no !important of its own — normally
		   losing specificity would decide that, but an inline style always
		   outranks an ordinary external rule regardless, !important or not.
		   Without this, mobile was silently stuck at the desktop 169px
		   value instead of this clamp() — confirmed live, and exactly why
		   every other property in this same media query already needed
		   the same !important (see this block's own top comment). */
		padding-top: clamp(32px, 8vw, 56px) !important;
	}

	.recent-projects__heading-zone {
		position: static;
		height: auto !important;
	}

	.recent-projects__heading {
		position: static;
		/* Was relying on .recent-projects__stack's own top margin/gap for
		   clearance, which made sense while the heading was sticky/absolute
		   — now that it's a plain static element again, it needs its own
		   bottom space before the first card. */
		margin-bottom: clamp(32px, 8vw, 48px);
		/* Global mobile h2 baseline (2.3rem) — see base.css. */
		font-size: clamp(1.875rem, 10vw, 2.3rem);
	}

	.recent-projects__stack {
		height: auto !important;
	}

	.recent-projects__wrapper {
		position: static;
		height: auto !important;
		/* Figma's actual mobile frame (node 5029:37646): each card sits in
		   its own inset, margined panel with a real gap to the next one —
		   not the full-bleed continuous-strip treatment this used to have. */
		padding-inline: 11px;
		margin-bottom: 15px;
	}

	.recent-projects__lead-in {
		display: none;
	}

	.recent-projects__card {
		position: static;
		width: 100%;
		/* The 1190/568 desktop ratio is tuned to show a wide LANDSCAPE slice
		   of each image — at full mobile width that same ratio crops down
		   to a very short strip, making the (already full-bleed, so
		   individually larger) image read as small/thumbnail-ish rather
		   than the full-bleed hero-ish treatment Figma's mobile frame
		   actually shows. aspect-ratio moves to .recent-projects__media
		   instead (below), sized for a taller, more considered crop. */
		aspect-ratio: auto;
		/* Rounded + clipped as one unit (photo top corners + panel bottom
		   corners together) — matches Figma's own subtle rounding on the
		   photo layer, so each card reads as a distinct panel rather than
		   a flat strip. */
		border-radius: 4px;
		overflow: hidden;
	}

	.recent-projects__media {
		aspect-ratio: 5 / 4;
	}

	/* Logo / description / arrow stack as three separate full-width rows
	   (Figma: one flex-col with an 18px gap between every item), not the
	   single "everything on one row" layout used elsewhere — .info and
	   .cta both switch to column here so the description+arrow pairing
	   (a desktop-only sub-grouping in the markup) reads as two more
	   stacked rows instead of a nested row-within-a-row. */
	.recent-projects__info {
		flex-direction: column;
		align-items: flex-start;
		gap: 18px;
		padding: 32px 19px 25px;
		background: var(--color-offwhite);
	}

	.recent-projects__logo {
		height: 28px;
		max-width: 84px;
	}

	.recent-projects__cta {
		flex-direction: column;
		align-items: flex-start;
		gap: 18px;
	}

	.recent-projects__description {
		max-width: none;
		text-align: left;
		font-size: 1.1875rem;
		line-height: 1.53;
	}

	.recent-projects__arrow {
		width: 44px;
		height: 44px;
	}
}

/* --- Hero --- */

.hero {
	position: relative;
	height: 100vh;
	min-height: 100vh;
	/* 100svh (the viewport height with mobile browser toolbars accounted for
	   as SHOWN) redeclared right after 100vh — browsers that don't know
	   "svh" just ignore that second declaration and keep the 100vh above;
	   ones that do use it instead. Plain 100vh on mobile Safari/Chrome is
	   sized against the LARGEST possible viewport (toolbars hidden), so the
	   page loads taller than what's actually visible and visibly jumps/
	   resizes as the toolbar shows and hides while scrolling — svh doesn't. */
	height: 100svh;
	min-height: 100svh;
	display: flex;
	align-items: center;
	justify-content: center;
}

/* Fixed to the viewport (not clipped to .hero) so that once you scroll past
   this section, the next section's solid background scrolls up over it —
   the video stays pinned in place the whole time rather than moving with
   the page. Negative z-index keeps it behind every normal-flow section. */
.hero__video {
	position: fixed;
	inset: 0;
	width: 100vw;
	height: 100vh;
	height: 100svh;
	object-fit: cover;
	z-index: -1;
}

.hero__overlay {
	position: fixed;
	inset: 0;
	z-index: -1;
	background: linear-gradient(248deg, rgba(0, 0, 0, 0.5) 14.75%, rgba(0, 0, 0, 0.7) 100.53%);
	pointer-events: none;
}

@media (max-width: 900px) {
	.hero {
		/* --hero-vh (home.js) is window.innerHeight measured ONCE on load —
		   svh alone still visibly resized the hero a moment after load on
		   real mobile browsers as they settled on a final toolbar state
		   (not reproducible in desktop device emulation, but confirmed by
		   eye on-device); a value fixed at load time can never do that
		   again. Falls back to 100svh until the JS has run (a near-instant
		   window, and still the more mobile-safe of the two static units if
		   it's ever the one left standing, e.g. JS disabled). */
		height: var(--hero-vh, 100svh);
		min-height: var(--hero-vh, 100svh);
		/* Switches the video/overlay off position:fixed here: that "pinned
		   background, page scrolls over it" trick is defined relative to
		   the viewport itself, which reintroduces the same jump regardless
		   of how stable the height value above is. Absolute (scrolls away
		   normally with the section instead of staying pinned) sidesteps
		   that entirely. */
		overflow: hidden;
	}

	.hero__video,
	.hero__overlay {
		position: absolute;
		height: 100%;
	}
}

.hero__content {
	/* Only the headline is in normal flow here (the scroll button is
	   position:absolute below), so this box's height — and therefore what
	   .hero centers — is exactly the headline's height. The icon hangs off
	   the bottom edge without affecting that centering at all. */
	position: relative;
	z-index: 1;
}

.hero__headline {
	margin: 0;
	padding-inline: var(--gutter);
	text-align: center;
	font-family: var(--font-display);
	font-weight: 800;
	font-size: clamp(2.75rem, 9vw, 7.9rem);
	line-height: 0.95;
	letter-spacing: 0.02em;
}

.hero__headline-line {
	display: block;
	color: var(--color-white);
}

.hero__headline-line--outline {
	/* Both CSS text-stroke and an SVG-filter-built outline still showed (or
	   nearly hid) a seam on this font's "E" — its crossbar is a separate
	   overlapping contour in the glyph outline. Using the pre-built outline
	   SVG exported straight from the design sidesteps font rendering
	   entirely. The actual word lives as visually-hidden real text
	   (.screen-reader-text) for SEO/accessibility; the image is decorative
	   (empty alt). */
	display: block;
}

.hero__headline-outline-img {
	display: inline-block;
	height: 0.75em;
	width: auto;
}

.hero__scroll {
	position: absolute;
	top: 100%;
	left: 50%;
	transform: translateX(-50%);
	margin-top: 20px;
	display: block;
	width: clamp(2.75rem, 6vw, 4.25rem);
}

.hero__scroll img {
	width: 100%;
	height: auto;
	display: block;
}

@media (max-width: 900px) {
	/* Figma's mobile headline takes up most of the screen's width — the
	   desktop-tuned clamp() above only reaches ~44px (its own floor) at a
	   390px viewport (9vw = 35px, below the 2.75rem floor), noticeably
	   smaller than that. Placed AFTER the base .hero__headline rule (not
	   grouped with the other mobile hero tweaks above, which sit earlier in
	   the file) so it actually wins the cascade — same specificity, so
	   whichever rule is LAST wins regardless of the media condition; a
	   min-width/max-width query doesn't add specificity of its own. Sized
	   from a real measurement (SETTLE's rendered width against the
	   viewport), not a guess: ~19vw lands "SETTLE" at roughly 85% of the
	   gutter-to-gutter width at a 390px viewport, tapering via the same
	   vw slope up to 462px before its ceiling caps it — chosen so it hands
	   off reasonably smoothly to the desktop clamp's own value just above
	   this query's 900px boundary, rather than jumping. */
	.hero__headline {
		font-size: clamp(3.5rem, 19vw, 5.5rem);
	}

	.hero__scroll {
		width: 68px;
	}
}

/* --- Hero intro animation ---
   On load, only the headline shows (bigger than its resting size) — no
   logo, no menu toggle, no scroll arrow. home.js adds .hero-intro-played
   to <body> a beat later, which is what these rules actually transition
   toward; everything below this comment is deliberately the PRE-animation
   state and applies by default (not gated behind a class JS adds first),
   so there's no flash of the settled state before JS has run — the
   settled state is the one that has to wait for a class, not the other
   way round. Scoped to body.home so none of this touches these same
   header elements on every other page. */
body.home .site-header__logo {
	opacity: 0;
	transform: translateX(-24px);
	transition: opacity 0.7s ease 0.2s, transform 0.7s ease 0.2s;
}

body.home .site-header__menu-toggle {
	opacity: 0;
	transform: translateX(24px);
	transition: opacity 0.7s ease 0.2s, transform 0.7s ease 0.2s;
}

body.home.hero-intro-played .site-header__logo,
body.home.hero-intro-played .site-header__menu-toggle {
	opacity: 1;
	transform: translateX(0);
}

body.home .hero__headline {
	transform: scale(1.12);
	transition: transform 0.7s ease;
}

body.home.hero-intro-played .hero__headline {
	transform: scale(1);
}

/* .hero__scroll's resting transform is itself translateX(-50%) (its own
   horizontal centering, see the base rule above) — both states here
   combine that same X offset with the intro's own Y move so centering
   never breaks mid-transition. */
body.home .hero__scroll {
	opacity: 0;
	transform: translate(-50%, 14px);
	transition: opacity 0.7s ease 0.1s, transform 0.7s ease 0.1s;
}

body.home.hero-intro-played .hero__scroll {
	opacity: 1;
	transform: translate(-50%, 0);
}

@media (prefers-reduced-motion: reduce) {
	body.home .site-header__logo,
	body.home .site-header__menu-toggle,
	body.home .hero__headline,
	body.home .hero__scroll {
		transition: none;
	}
}

/* --- Closing statement (pull-quote + testimonial carousel) --- */
.closing-statement {
	background: var(--color-white);
	padding-block: clamp(64px, 8vw, 120px);
}

.closing-statement__head {
	display: flex;
	flex-wrap: wrap;
	align-items: flex-end;
	justify-content: space-between;
	gap: 40px;
	margin-bottom: clamp(27px, 4vw, 53px);
}

.closing-statement__quote-wrap {
	/* max-width is the ONLY thing controlling where this text wraps —
	   font-size below scales off the viewport (like every other heading
	   in this file), not off this box's own width, so the two are fully
	   decoupled. Tighten/loosen this value to move the wrap points. */
	max-width: 710px;
	width: 100%;
}

.closing-statement__quote {
	margin: 0;
	font-family: var(--font-body);
	font-weight: 500;
	font-size: clamp(1.5rem, 3.3vw, 2.5rem);
	line-height: 1.325;
	letter-spacing: -0.02em;
	color: var(--color-ink);
}

.closing-statement__quote em {
	display: block;
	font-style: italic;
}

.closing-statement__nav {
	display: flex;
	gap: 16px;
	flex-shrink: 0;
}

.closing-statement__arrow {
	/* arrow-icon.svg already IS a full circle+arrow button (borrowed from
	   Recent Projects) — no extra circle/border wrapper needed here, that
	   was doubling up and showing as a circle-within-a-circle. */
	width: clamp(48px, 4.7vw, 68px);
	height: clamp(48px, 4.7vw, 68px);
	background: none;
	border: none;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 0;
	cursor: pointer;
}

.closing-statement__arrow img {
	width: 100%;
	height: 100%;
	display: block;
}

.closing-statement__arrow--prev img {
	transform: rotate(90deg);
}

.closing-statement__arrow--next img {
	transform: rotate(-90deg);
}

/* Matching the img rotations above so the filled hover state (.arrow-circle
   in base.css) points the same direction as the outline icon. */
.closing-statement__arrow--prev::after {
	transform: rotate(90deg);
}

.closing-statement__arrow--next::after {
	transform: rotate(-90deg);
}

.closing-statement__arrow:disabled {
	opacity: 0.3;
	cursor: default;
}

.closing-statement__viewport {
	width: 100%;
	overflow: hidden;
}

.closing-statement__track {
	position: relative;
	list-style: none;
	margin: 0;
	padding: 0;

	/* Card size scales with the viewport instead of revealing more cards as
	   it widens — there are only 4 real testimonials, so showing more slots
	   at once would eventually put a repeated one on screen simultaneously.
	   Keeping ~3.8 slots visible at any width (matching the Figma "one card
	   peeks off the edge" cue) means only the cards themselves grow. */
	--card-w: clamp(220px, 25vw, 380px);
	--gap: calc(var(--card-w) * 0.049);
	--pitch: calc(var(--card-w) + var(--gap));
	/* Twice the inter-card gap, not the site's usual container gutter — the
	   track itself runs full-bleed (it overflows past .container on
	   purpose, see the "peek" cue), so its own left margin is sized
	   relative to its own rhythm rather than the site-wide gutter. Applied
	   directly on the card's `left` below, not as padding here — padding on
	   a positioned ancestor doesn't offset absolutely-positioned children,
	   which align to its border edge regardless of padding. */
	--edge-gap: calc(var(--gap) * 2);
	/* Figma's own offset between the two staggered rows is a fixed 2rem,
	   not proportional to card size. */
	--stagger: 2rem;
	--card-h: calc(var(--card-w) * 1.1162);
	height: calc(var(--card-h) + var(--stagger));
}

.closing-statement__card {
	position: absolute;
	top: 0;
	left: var(--edge-gap);
	width: var(--card-w);
	height: var(--card-h);
	overflow: hidden;
	container-type: inline-size;
	container-name: cs-card;

	/* --slot and --parity are set per-card by home.js and recalculated on
	   every Prev/Next click — the up/down stagger belongs to the slot a
	   card currently occupies, not to the card itself, so both axes
	   transition together as cards move between slots. parity 0 = flush top
	   ("up"), parity 1 = shifted down by the full --stagger amount. */
	transform: translate3d(calc(var(--slot, 0) * var(--pitch)), calc(var(--parity, 0) * var(--stagger)), 0);
	transition: transform 0.55s cubic-bezier(0.65, 0, 0.35, 1);
}

.closing-statement__figure {
	position: relative;
	width: 100%;
	height: 100%;
	margin: 0;
	box-sizing: border-box;
	display: flex;
	flex-direction: column;
	justify-content: space-between;
	padding: clamp(14px, 7.7cqw, 28px);
	background: var(--color-offwhite);
}

.closing-statement__card--photo .closing-statement__figure {
	color: var(--color-white);
}

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

.closing-statement__card--photo .closing-statement__figure::after {
	content: '';
	position: absolute;
	inset: 0;
	background: linear-gradient(180deg, rgba(0, 0, 0, 0.1) 0%, rgba(0, 0, 0, 0.45) 100%);
	z-index: 1;
}

.closing-statement__mark,
.closing-statement__quote-text,
.closing-statement__attribution {
	position: relative;
	z-index: 2;
}

.closing-statement__mark {
	display: block;
	width: clamp(24px, 11.6cqw, 43px);
	height: auto;
}

.closing-statement__quote-text {
	margin: 0;
	font-family: var(--font-body);
	font-weight: 400;
	font-size: clamp(13px, 5.35cqw, 19.64px);
	line-height: 1.454;
}

.closing-statement__attribution {
	margin: 0;
	font-style: normal;
	font-family: var(--font-body);
	font-weight: 300;
	font-size: clamp(11px, 4.4cqw, 16px);
	line-height: 1.45;
}

@media (max-width: 900px) {
	/* .closing-statement__head still carries the .container class (the
	   source of its left/right gutter) — display:contents below means its
	   children (quote-wrap, hidden; nav) need that gutter re-applied
	   directly instead of inheriting it. Same technique as .specialties__cta
	   above. */
	.closing-statement {
		display: flex;
		flex-direction: column;
	}

	.closing-statement__head {
		display: contents;
	}

	/* Dropped entirely on mobile (not just visually de-emphasised) — this
	   section becomes just the carousel + its nav arrows, no heading. */
	.closing-statement__quote-wrap {
		display: none;
	}

	.closing-statement__viewport {
		order: 2;
	}

	.closing-statement__nav {
		order: 3;
		justify-content: center;
		padding-inline: var(--gutter);
		margin-top: clamp(24px, 6vw, 40px);
	}

	.closing-statement__track {
		/* One card fills most of the viewport with the next one peeking in
		   on the right — matches the "swipe through one at a time" pattern
		   this becomes on mobile, vs desktop's ~3.8-cards-visible strip. */
		--card-w: 84vw;
	}
}

/* --- Making it happen v2 (Figma nodes 4424:16517, 4424:16848,
   4424:16764/16806/16835) — parallel to .making-it-happen above, not a
   replacement. See making-it-happen-v2.php's own top comment for how to
   revert to the original hover-reveal version. */

.making-it-happen-v2 {
	background: var(--color-white);
	/* No top padding here — .video-showcase's own bottom padding is the
	   only thing controlling the gap above (8rem total), see its comment. */
	padding-bottom: clamp(64px, 8vw, 120px);
}

.making-it-happen-v2__intro {
	max-width: 40.8125rem;
	margin-inline: auto;
	text-align: center;
}

.making-it-happen-v2__heading {
	margin: 0 0 24px;
	font-family: var(--font-body);
	font-weight: 500;
	font-size: clamp(2.25rem, 4vw, 3.75rem);
	line-height: 1.25;
	color: var(--color-ink);
}

/* Global mobile h2 baseline (2.3rem) — see base.css. */
@media (max-width: 900px) {
	.making-it-happen-v2__heading {
		font-size: clamp(1.875rem, 10vw, 2.3rem);
	}
}

.making-it-happen-v2__intro-copy {
	margin: 0;
	font-family: var(--font-body);
	font-weight: 300;
	font-size: 1.25rem;
	line-height: 2rem;
	color: var(--color-ink);
}

.making-it-happen-v2__grid {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: 20px;
	max-width: 75.625rem;
	margin: clamp(40px, 5vw, 64px) auto 0;
}

.making-it-happen-v2__card {
	position: relative;
	display: flex;
	flex-direction: column;
	justify-content: space-between;
	aspect-ratio: 390 / 385;
	/* Fluid, not the flat 40px this used to be — at "in-between" widths
	   just past the 900px mobile breakpoint, 3 fixed-width-content columns
	   in a narrowing grid were squeezing the card well below its 390px
	   design width while the padding/font-sizes below stayed full size,
	   so the body copy overflowed past the bottom of the (aspect-ratio-
	   locked, overflow:hidden) card and got clipped. */
	padding: clamp(20px, 4vw, 40px);
	background: var(--color-offwhite, #fafafa);
	overflow: hidden;
	/* No native outline (the icon/text colour change already signals
	   hover/focus) — the browser's default outline box also clips
	   awkwardly against overflow:hidden here. */
	outline: none;
}

/* Fluid padding/font-sizes alone weren't quite enough to stop the longest
   card's copy overflowing across this whole range — 1210px is exactly
   where .making-it-happen-v2__grid's own max-width caps out, so above it
   the column width (and the aspect-ratio box below) never gets any
   narrower than its 390px design width anyway. Dropping the fixed aspect-
   ratio here instead lets each card's height follow its own content, and
   the grid's default stretch makes all 3 cards match the tallest one —
   so nothing needs to be guessed as a min-height. */
@media (min-width: 901px) and (max-width: 1210px) {
	.making-it-happen-v2__card {
		aspect-ratio: auto;
	}
}

/* Photo + gradient fade in on hover/focus — absolutely positioned behind
   the icon/title/text, which get position:relative below to stay on top. */
.making-it-happen-v2__card-bg {
	position: absolute;
	inset: 0;
	background-size: cover;
	background-position: center;
	opacity: 0;
	transition: opacity 0.4s ease;
}

/* Figma's own stops (0 until 43%, ramping to 0.9 by 99%) leave the title —
   which sits right around that 43% mark — on almost-undarkened photo, so
   this darkens earlier/more throughout rather than matching those exactly. */
.making-it-happen-v2__card-bg::after {
	content: '';
	position: absolute;
	inset: 0;
	background: linear-gradient(180deg, rgba(27, 27, 27, 0.15) 0%, rgba(27, 27, 27, 0.45) 40%, rgba(27, 27, 27, 0.88) 70%, rgba(27, 27, 27, 1) 100%);
}

/* Hover/focus-triggered reveal is desktop-only (mouse/trackpad, or a
   keyboard on such a device) — on a touch device there's no :hover, but
   :focus-visible can still land on this link after a tap in some mobile
   browsers, and the mobile layout below hides the photo/gradient
   entirely, so without this gate the title/text-color rules further down
   would turn the text white against the card's own plain background with
   nothing behind it to make that legible. */
@media (hover: hover) {
	.making-it-happen-v2__card:hover .making-it-happen-v2__card-bg,
	.making-it-happen-v2__card:focus-visible .making-it-happen-v2__card-bg {
		opacity: 1;
	}
}

.making-it-happen-v2__card-top {
	position: relative;
	display: flex;
	justify-content: flex-end;
}

/* Stroke is white — invisible against the card's own off-white
   background by design, and stays exactly as-is on hover; it's the new
   dark photo behind it (☝ __card-bg) that makes it visible, not a
   change to the icon itself. */
.making-it-happen-v2__card-icon-wrap {
	position: relative;
	display: block;
	width: 3.251rem;
	height: 3.251rem;
}

.making-it-happen-v2__card-icon {
	position: relative;
	display: block;
	width: 100%;
	height: 100%;
}

/* Same outline-crossfades-to-filled treatment as .arrow-circle (base.css)
   — a solid-filled version layered on top, faded in only when the pointer
   is directly over the icon itself, not just anywhere on the card. */
.making-it-happen-v2__card-icon-wrap::after {
	content: '';
	position: absolute;
	inset: 0;
	background-image: url('../images/making-it-happen/card-icon-filled.svg');
	background-repeat: no-repeat;
	background-size: contain;
	opacity: 0;
	transition: opacity 0.25s ease;
}

@media (hover: hover) {
	.making-it-happen-v2__card-icon-wrap:hover::after {
		opacity: 1;
	}
}

.making-it-happen-v2__card-body {
	position: relative;
	display: flex;
	flex-direction: column;
	gap: 15px;
}

.making-it-happen-v2__card-title {
	margin: 0;
	font-family: var(--font-body);
	font-weight: 500;
	/* Fluid (same reasoning as .making-it-happen-v2__card's own padding
	   above) — the ratio to font-size (50/30) is kept as a unitless
	   line-height instead of the flat 50px this used to be, so it scales
	   down with the font-size instead of going disproportionately loose
	   at the smaller end of the clamp. */
	font-size: clamp(1.3rem, 2.2vw, 1.875rem);
	line-height: 1.667;
	color: var(--color-ink);
	transition: color 0.4s ease;
}

/* Global mobile h3 baseline (1.7rem) — see base.css. */
@media (max-width: 900px) {
	.making-it-happen-v2__card-title {
		font-size: 1.7rem;
	}
}

@media (hover: hover) {
	.making-it-happen-v2__card:hover .making-it-happen-v2__card-title,
	.making-it-happen-v2__card:focus-visible .making-it-happen-v2__card-title {
		color: var(--color-white);
	}
}

.making-it-happen-v2__card-text {
	margin: 0;
	font-family: var(--font-body);
	font-weight: 300;
	/* Same fluid treatment as the title above (ratio to font-size, 30/20,
	   kept as unitless line-height). */
	font-size: clamp(0.95rem, 1.6vw, 1.25rem);
	line-height: 1.5;
	color: var(--color-ink);
	transition: color 0.4s ease;
}

@media (hover: hover) {
	.making-it-happen-v2__card:hover .making-it-happen-v2__card-text,
	.making-it-happen-v2__card:focus-visible .making-it-happen-v2__card-text {
		color: var(--color-white);
	}
}

/* Hidden on desktop — see making-it-happen-v2.php's own comment. Sized/
   rotated exactly like .recent-projects__arrow, the same component used the
   same way there. */
.making-it-happen-v2__mobile-arrow {
	display: none;
	flex-shrink: 0;
	width: 52px;
	height: 52px;
	margin-top: 24px;
	transform: rotate(-90deg);
}

.making-it-happen-v2__mobile-arrow img {
	width: 100%;
	height: 100%;
	display: block;
}

@media (max-width: 900px) {
	.making-it-happen-v2__intro {
		max-width: none;
		margin-inline: 0;
		text-align: left;
	}

	.making-it-happen-v2__grid {
		grid-template-columns: 1fr;
		gap: 0;
	}

	/* The hover-reveal photo card doesn't have a touch equivalent (see
	   making-it-happen-v2.php's comment) — mobile drops the card look
	   entirely in favour of a plain divided list (heading, copy, arrow),
	   matching the Figma mobile frame, rather than leaving a "dead" card
	   that can never show its own reveal state. */
	.making-it-happen-v2__card {
		aspect-ratio: auto;
		flex-direction: column;
		align-items: flex-start;
		padding: 40px 0;
		background: none;
		border-top: 1px solid var(--color-ink);
	}

	.making-it-happen-v2__card:first-child {
		padding-top: 0;
		border-top: none;
	}

	.making-it-happen-v2__card:last-child {
		padding-bottom: 0;
	}

	.making-it-happen-v2__card-bg,
	.making-it-happen-v2__card-top {
		display: none;
	}

	.making-it-happen-v2__mobile-arrow {
		display: flex;
	}
}
