/**
 * motion.css — Tobi Portfolio
 * ---------------------------------------------------------------------------
 * Layout, motion and micro-interactions for the redesign (spec 3–10).
 *
 * Rules of the system:
 *   1. Transform and opacity only — nothing here animates size/position props
 *      on scroll (hover glows are the one deliberate exception, and they are
 *      cheap and isolated).
 *   2. Progressive enhancement — entrance states are hidden only under
 *      `html.js`; the reduced-motion sweep at the bottom restores everything
 *      that matters.
 *   3. Breakpoint: 820px. Parallax drops to 40%, cursor/tilt/magnet off.
 */

/* ---------------------------------------------------------------- tokens */

:root {
	--ease-out: cubic-bezier(0.2, 0.7, 0.2, 1);
	--dur-fast: 0.25s;
	--dur-med: 0.35s;
	--dur-slow: 0.9s;
	--color-bg: var(--wp--preset--color--bg);
	--color-text: var(--wp--preset--color--text);
	--color-muted: var(--wp--preset--color--muted);
	--color-line: var(--wp--preset--color--line);
	--color-accent: var(--wp--preset--color--accent);
	--color-on-accent: var(--wp--preset--color--on-accent);

	/* Placeholder art behind project imagery, in spec order 01→04. */
	--card-bg: #e9eef8;
}

.card-bg-blue { --card-bg: #e9eef8; }
.card-bg-peach { --card-bg: #f6ddd0; }
.card-bg-teal { --card-bg: #d7ece9; }
.card-bg-lilac { --card-bg: #e4dcf6; }

/* --------------------------------------------------------------- helpers */

/* Visually hidden but screen-reader reachable. */
.visually-hidden {
	position: absolute !important;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	border: 0;
	clip-path: inset(100%);
	clip: rect(0 0 0 0);
	overflow: hidden;
	white-space: nowrap;
}

/* Hidden until focused (marquee pause control, spec 10). */
.visually-hidden-focusable:not(:focus):not(:focus-within) {
	position: absolute !important;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	border: 0;
	clip-path: inset(100%);
	clip: rect(0 0 0 0);
	overflow: hidden;
	white-space: nowrap;
}

.visually-hidden-focusable:focus {
	position: fixed;
	inset: auto 16px 16px auto;
	z-index: 210;
	padding: 12px 18px;
	border-radius: 999px;
	background: var(--color-accent);
	color: var(--color-on-accent);
	font-size: 15px;
	font-weight: 600;
}

/* ------------------------------------------------------- entrance states */

/* Hidden initial states exist only when JS is running (spec 5). */
.js [data-reveal] { opacity: 0; }

.js [data-reveal="clip"] {
	clip-path: inset(0 0 100% 0);
	opacity: 1;
}

/* Word/line split masks (created by motion.js). */
.split-word {
	display: inline-block;
	overflow: hidden;
}

.js .split-word > .split-word__inner {
	display: inline-block;
	transform: translateY(110%);
	will-change: transform;
}

.js [data-split] .split-word > .split-word__inner {
	transform: translateY(110%);
}

/* -------------------------------------------------------- scroll progress */

.scroll-progress {
	position: fixed;
	inset: 0 0 auto 0;
	height: 2px;
	background: var(--color-accent);
	transform: scaleX(0);
	transform-origin: left;
	z-index: 100;
	pointer-events: none;
}

/* ---------------------------------------------------------------- header */

.site-header {
	position: sticky;
	top: 0;
	z-index: 90;
	transition: transform var(--dur-med) var(--ease-out);
}

.site-header.is-hidden { transform: translateY(-100%); }

/* ≥80px scrolled: translucent bg + blur + bottom hairline (motion.js toggles). */
.site-header.is-stuck {
	background: color-mix(in srgb, var(--color-bg) 85%, transparent);
	backdrop-filter: blur(12px);
	-webkit-backdrop-filter: blur(12px);
	border-bottom: 1px solid var(--color-line);
}

.site-header__inner {
	box-sizing: content-box;
	max-width: 1280px;
	margin: 0 auto;
	align-items: center;
	padding-top: 36px;
	padding-bottom: 36px;
	padding-left: clamp(20px, 3vw, 40px);
	padding-right: clamp(20px, 3vw, 40px);
}

.site-header__brand {
	align-items: center;
	gap: 20px;
}

.site-header__name {
	font-family: var(--wp--preset--font-family--display);
	font-weight: 700;
	font-size: 22px;
	color: var(--color-text);
	text-decoration: none;
}

/* Status line with the pulsing accent dot (spec 4.1/7). */
.site-status {
	position: relative;
	padding-left: 18px;
	color: var(--color-muted);
	font-size: 13px;
	white-space: nowrap;
}

.status-dot::before {
	content: "";
	position: absolute;
	top: 50%;
	left: 0;
	width: 8px;
	height: 8px;
	margin-top: -4px;
	border-radius: 50%;
	background: var(--color-accent);
	animation: pulse 1.8s infinite;
}

@keyframes pulse {
	0%   { box-shadow: 0 0 0 0 rgba(245, 181, 68, 0.6); }
	100% { box-shadow: 0 0 0 10px rgba(245, 181, 68, 0); }
}

/* Nav links: accent underline scales in from the left (spec 7). */
.site-nav .wp-block-navigation-item__content,
.site-nav .wp-block-navigation-link a {
	color: var(--color-text);
	font-size: 14px;
	text-decoration: none;
}

.site-nav .wp-block-navigation-item {
	position: relative;
	padding: 6px 0;
}

.site-nav .wp-block-navigation-item::after {
	content: "";
	position: absolute;
	inset: auto 0 0 0;
	height: 1px;
	background: var(--color-accent);
	transform: scaleX(0);
	transform-origin: left;
	transition: transform 0.35s var(--ease-out);
}

.site-nav .wp-block-navigation-item:hover::after,
.site-nav .wp-block-navigation-item:focus-within::after,
.site-nav .wp-block-navigation-item.is-active::after {
	transform: scaleX(1);
}

.site-nav { gap: 32px; }

.site-header__actions {
	align-items: center;
	gap: 24px;
}

/* Menu overlay (≤820px): toggled by motion.js. */
.menu-toggle {
	display: none;
	place-items: center;
	width: 44px;
	height: 44px;
	padding: 0;
	border: 1px solid var(--color-line);
	border-radius: 999px;
	background: transparent;
	color: var(--color-text);
}

.menu-toggle__lines,
.menu-toggle__lines::before,
.menu-toggle__lines::after {
	display: block;
	width: 18px;
	height: 2px;
	background: currentColor;
	transition: transform var(--dur-fast) var(--ease-out), opacity var(--dur-fast) var(--ease-out);
}

.menu-toggle__lines {
	position: relative;
	transition: none;
}

.menu-toggle__lines::before,
.menu-toggle__lines::after {
	content: "";
	position: absolute;
	inset: 0;
}

.menu-toggle__lines::before { transform: translateY(-5px); }
.menu-toggle__lines::after { transform: translateY(5px); }

.menu-toggle[aria-expanded="true"] .menu-toggle__lines { background: transparent; }
.menu-toggle[aria-expanded="true"] .menu-toggle__lines::before { transform: rotate(45deg); }
.menu-toggle[aria-expanded="true"] .menu-toggle__lines::after { transform: rotate(-45deg); }

.menu-overlay {
	position: fixed;
	inset: 0;
	z-index: 80;
	display: flex;
	flex-direction: column;
	justify-content: center;
	gap: 32px;
	padding: 40% clamp(20px, 3vw, 40px) 48px;
	background: var(--color-bg);
	opacity: 0;
	transform: translateY(-8px);
	transition: opacity var(--dur-med) var(--ease-out), transform var(--dur-med) var(--ease-out);
	pointer-events: none;
}

.menu-overlay.is-open {
	opacity: 1;
	transform: none;
	pointer-events: auto;
}

.menu-overlay__list {
	margin: 0;
	padding: 0;
	list-style: none;
}

.menu-overlay__list a {
	display: block;
	padding: 10px 0;
	font-family: var(--wp--preset--font-family--display);
	font-size: 40px;
	color: var(--color-text);
	text-decoration: none;
}

.menu-overlay__cta {
	width: fit-content;
	margin: 8px 0 0;
}

/* When the overlay is open the header stays visible above it. */
body.menu-open .site-header,
body.menu-open .site-header.is-hidden {
	transform: none;
}

/* ------------------------------------------------------------------ hero */

.hero {
	position: relative;
	padding-top: 72px;
	padding-bottom: 96px;
}

/* The decor layer bleeds to the viewport edges and overhangs the section's
   bottom — the glow fades out inside the clipped box, so nothing it holds
   can cause page scroll or a visible gradient seam, while the hero's real
   content (chips, ring) is never cut. */
.hero__decor {
	position: absolute;
	inset-block: 0 -480px;
	left: calc(50% - 50vw);
	right: calc(50% - 50vw);
	overflow: clip;
	pointer-events: none;
	z-index: 0;
}

.hero__blob {
	position: absolute;
	left: 0;
	right: 0;
	filter: blur(70px);
}

/* One wide glow band low in the hero — sized so its fade ends inside the
   clipped box on every edge (no seams at the viewport sides or bottom). */
.hero__blob--one {
	top: auto;
	bottom: 0;
	height: min(90vh, 760px);
	transform: translateY(62%);
	background: radial-gradient(50% 44% at 50% 30%, rgba(245, 181, 68, 0.16), rgba(245, 181, 68, 0) 76%);
}

/* A fainter one up top, sized to fade out inside the clip box too. */
.hero__blob--two {
	top: -80px;
	bottom: auto;
	height: 520px;
	transform: none;
	background: radial-gradient(40% 40% at 72% 70%, rgba(245, 181, 68, 0.1), rgba(245, 181, 68, 0) 76%);
}

/* Twinkling sparks + small orbit dots (decor, aria-hidden in the pattern). */
.hero__spark {
	position: absolute;
	z-index: 1;
	color: var(--color-accent);
}

.hero__spark--one { top: 21%; left: 55%; }
.hero__spark--two { top: 70%; right: 1%; }

.hero__dot {
	position: absolute;
	z-index: 1;
	width: 10px;
	height: 10px;
	border-radius: 50%;
}

.hero__dot--mint { top: 36%; left: 52%; background: #39d98a; }
.hero__dot--pink { top: 84%; right: 5%; background: #e07a9b; }

.hero__inner {
	position: relative;
	z-index: 1;
	display: grid;
	grid-template-columns: minmax(0, 1.14fr) minmax(0, 0.86fr);
	gap: 48px 64px;
	align-items: center;
	padding-bottom: 8px;
}

.hero__copy { position: relative; z-index: 1; }

/* Greeting: handwritten accent line (Caveat, self-hosted via theme.json). */
.hero__greeting {
	font-family: var(--wp--preset--font-family--hand);
	font-weight: 600;
	font-size: clamp(34px, 3.4vw, 48px);
	line-height: 1.25;
	color: var(--color-accent);
	margin: 0 0 6px;
}

.hero__title {
	max-width: 720px;
	margin: 0;
	font-size: clamp(42px, 5.3vw, 78px);
}

/* The italic, accented word in the headline. */
.accent-italic,
.contact__awesome,
.hero__title em,
.contact__title em {
	font-style: italic;
	color: var(--color-accent);
}

/* Split reveal gives styled words their own class — same look, no italics
   in the story hero. */
.hero__title .split-word__inner.hero__accent {
	font-style: normal;
	color: var(--color-accent);
}

.hero__lede {
	max-width: 680px;
	margin: 20px 0 0;
	color: var(--color-muted);
	font-size: 18px;
	line-height: 1.6;
}

.muted { color: var(--color-muted); }

.hero__cta {
	margin: 36px 0 0;
	gap: 16px;
	flex-wrap: nowrap;
}

/* ------- portrait column ------- */

.hero__media {
	position: relative;
	z-index: 1;
	justify-self: end;
	width: 100%;
	max-width: min(100%, 540px);
	margin: -40px 0 20px -20px;
	overflow: visible;
}

/* The img wrapper carries the clip reveal (an inset() clip-path clips *all*
   of an element's children — chips and ring must stay outside it). The
   border-radius lives here so the rounded corners survive the reveal. */
.hero__clip {
	display: block;
	border-radius: 28px;
	overflow: hidden;
}

/* Dotted orbit ring behind the photo. It sits centered on the media box as
   a square (aspect-ratio 1) so the rotation tooltip in motion.js never
   changes its axis-aligned footprint — only a circle can spin without
   widening the page. */
/* Width is capped so the centered ring box can never cross the viewport
   edge (its rotated bounding box would otherwise widen the page a
   fraction on some frames). */
.hero__ring-pos {
	position: absolute;
	top: 50%;
	left: 50%;
	width: min(135%, 656px, 100vw - 60px);
	aspect-ratio: 1;
	transform: translate(-50%, -50%);
	pointer-events: none;
	/* The rotation in motion.js makes the ring's border-box swing wider
	   than the box itself; a circle paints exactly inside the box, so the
	   clip only discards the invisible corners (keeps the page width fixed). */
	overflow: clip;
}

.hero__ring {
	position: absolute;
	inset: 0;
	z-index: -1;
	border: 2px dotted rgba(245, 181, 68, 0.38);
	border-radius: 50%;
	will-change: transform;
}

.hero__portrait {
	display: block;
	width: 100%;
	height: auto;
	filter: grayscale(1) contrast(1.05);
}

/* Floating status chips. Popped in and idle-floated by motion.js; hidden
   only while JS motion is managing them (reduced motion shows them at
   once, and dropping `js` restores them too). */
html.js:not(.reduced) .hero__chip { opacity: 0; }
.hero__chip {
	position: absolute;
	z-index: 2;
	display: inline-flex;
	align-items: center;
	gap: 9px;
	padding: 12px 18px;
	border-radius: 999px;
	background: rgba(24, 23, 22, 0.94);
	color: var(--color-text);
	font-size: 15px;
	font-weight: 500;
	line-height: 1.2;
	white-space: nowrap;
	box-shadow: 0 12px 32px rgba(0, 0, 0, 0.35);
}

.hero__chip--ai svg { color: var(--color-accent); flex: none; }

.hero__chip--ai { top: 42%; left: -88px; }
.hero__chip--role {
	bottom: 48px;
	left: -36px;
	background: #d674a0;
	color: #ffffff;
	font-size: 16px;
}

/* --------------------------------------------------------------- marquee */

.marquee {
	position: relative;
	display: flex;
	align-items: center;
	flex-direction: column;
	gap: 0;
	overflow: clip;
	padding-block: 36px;

	/* Bleed edge-to-edge out of the root padding (constrained main). */
	margin-left: calc(var(--wp--style--root--padding-left, 40px) * -1);
	margin-right: calc(var(--wp--style--root--padding-right, 40px) * -1);
}

/* The band's lines are the draw-in subjects (scaleX 0 → 1, spec 6.4). */
.marquee::before,
.marquee::after {
	content: "";
	position: absolute;
	inset-inline: 0;
	height: 1px;
	background: var(--color-line);
	transform: scaleX(0);
	transform-origin: left;
	transition: transform 0.8s var(--ease-out);
}

.marquee::before { top: -1px; }
.marquee::after { bottom: -1px; }

.marquee.is-drawn::before,
.marquee.is-drawn::after { transform: scaleX(1); }

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

.marquee__track {
	display: flex;
	align-items: baseline;
	gap: 56px;
	margin: 0;
	padding: 0;
	list-style: none;
	width: max-content;
	/* Never shrink: both tracks must stay exactly one content-width wide or
	   the loop seam drifts and the copies overlap. */
	flex: none;
}

.marquee__track li {
	flex: 0 0 auto;
	font-family: var(--wp--preset--font-family--display);
	font-size: 30px;
	color: var(--color-text);
}

.marquee__track li.marquee__sep {
	color: var(--color-accent);
	font-size: 20px;
}

/* Image logos land here when the owner swaps text for images (spec 4.3). */
.marquee__track img {
	height: 32px;
	width: auto;
	opacity: 0.7;
	transition: opacity var(--dur-fast) var(--ease-out);
}

.marquee__track img:hover { opacity: 1; }

/* Pause control appears for keyboard users (proves WSAG pause, spec 10). */
.marquee__pause { cursor: pointer; }

/* ---------------------------------------------------------- selected work */

.work { padding-top: 140px; }

.work__head {
	align-items: flex-end;
	gap: 24px 48px;
	margin-bottom: 24px;
}

.work__title { max-width: 820px; margin: 0; }

.work__cue {
	color: var(--color-muted);
	font-size: 13px;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	text-decoration: none;
	white-space: nowrap;
	animation: cue-float 2.4s ease-in-out infinite alternate;
	transition: opacity 0.5s var(--ease-out);
}

@keyframes cue-float {
	from { transform: translateY(-4px); }
	to   { transform: translateY(6px); }
}

.work__cue.is-spent { opacity: 0; pointer-events: none; }

.work__query { margin-top: 24px; }

.work__list {
	margin: 0;
	padding: 0;
	list-style: none;
	counter-reset: project;
}

/* Numbering lives on the list itself so it works even without JS. */
.work__list > li {
	counter-increment: project;
}

/* The row's top border draws in from the left on entrance (spec 6.5). */
.project-row__grid {
	position: relative;
	display: grid;
	grid-template-columns: 1.25fr 1fr;
	gap: 72px;
	align-items: center;
	padding-block: 80px;
}

.project-row__grid::before {
	content: "";
	position: absolute;
	inset: 0 auto auto 0;
	width: 100%;
	height: 1px;
	background: var(--color-line);
	transform: scaleX(0);
	transform-origin: left;
	transition: transform 0.9s var(--ease-out);
}

.project-row.is-drawn .project-row__grid::before { transform: scaleX(1); }

/* Even rows flip (spec 4.4). */
.work__list > li:nth-child(even) .project-row__grid {
	direction: rtl;
}

.work__list > li:nth-child(even) .project-visual,
.work__list > li:nth-child(even) .project-row__text {
	direction: ltr;
}

/* Visual side: a 16/11 frame whose background is the editable placeholder. */
.project-visual {
	position: relative;
	grid-column: 1;
	border-radius: 20px;
	overflow: hidden;
	background: var(--card-bg);
	will-change: transform;
	contain: layout paint;
}

.project-visual__frame {
	margin: 0;
}

.project-visual__frame img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	aspect-ratio: 16 / 11;

	/* `scale` (not transform): motion.js drives a parallax transform on the
	   same element; keeping the zoom on the CSS `scale` property lets both
	   coexist. */
	scale: 1.2;
	transition: scale 0.6s var(--ease-out);
}

.project-row:hover .project-visual__frame img,
.project-visual:focus-within .project-visual__frame img {
	scale: 1.28;
}

/* Row hover: the visual scales a touch and leans (spec 7). */
.project-visual { transition: scale 0.6s var(--ease-out), rotate 0.6s var(--ease-out); }

.project-row:hover .project-visual {
	scale: 1.025;
	rotate: -0.5deg;
}

/* Number layer: Playfair 96px, drifts against the scroll (spec 6.5). */
.project-row__number {
	position: absolute;
	top: 16px;
	left: 20px;
	font-family: var(--wp--preset--font-family--display);
	font-size: 96px;
	line-height: 1;
	color: var(--color-text);
	mix-blend-mode: difference;
	z-index: 1;
}

.project-row__number::before {
	content: counter(project, decimal-leading-zero);
}

.project-row__label {
	position: absolute;
	bottom: 16px;
	left: 20px;
	z-index: 1;
	padding: 6px 12px;
	border-radius: 999px;
	background: rgba(14, 14, 14, 0.55);
	color: var(--color-text);
	font-size: 12px;
	letter-spacing: 0.14em;
	text-transform: uppercase;
}

/* Project term tags as pills. */
.project-tags {
	display: flex;
	flex-wrap: wrap;
	gap: 10px;
	margin: 0 0 18px;
}

.project-tags a {
	display: inline-block;
	padding: 6px 14px;
	border: 1px solid var(--color-line);
	border-radius: 999px;
	color: var(--color-muted);
	font-size: 13px;
	text-decoration: none;
}

/* Text side. */
.project-row__text {
	grid-column: 2;
	min-width: 0;
}

.project-row__title {
	margin: 0 0 18px;
	font-size: var(--wp--preset--font-size--project-title);
	line-height: 1.1;
}

/* Title underline sweeps in on row hover (spec 7). */
.project-row__title a {
	color: var(--color-text);
	text-decoration: none;
	background-image: linear-gradient(currentColor, currentColor);
	background-repeat: no-repeat;
	background-position: 0 100%;
	background-size: 0% 1px;
	transition: background-size 0.3s var(--ease-out);
}

.project-row:hover .project-row__title a,
.project-row:focus-within .project-row__title a {
	background-size: 100% 1px;
}

.project-row__excerpt {
	margin: 0 0 22px;
	color: var(--color-muted);
	font-size: var(--wp--preset--font-size--body-s);
	line-height: 1.6;
}

.project-row__link {
	display: inline-block;
	color: var(--color-text);
	font-weight: 600;
	font-size: 15px;
	text-decoration: underline;
	text-decoration-color: var(--color-line);
	text-underline-offset: 4px;
	transition: color 0.3s var(--ease-out);
}

/* "Full project" gap grows and turns accent on hover (spec 7). */
.project-row__link::after {
	content: " ↗";
	display: inline-block;
	margin-left: 10px;
	transition: margin-left 0.3s var(--ease-out);
}

.project-row:hover .project-row__link,
.project-row__link:hover,
.project-row__link:focus-visible {
	color: var(--color-accent);
	text-decoration-color: var(--color-accent);
}

.project-row:hover .project-row__link::after {
	margin-left: 18px;
}

/* ----------------------------------------------------------------- work cards */
/*
 * Card mosaic (mock, Oct 2026). Scoped to `.work` — the /work archive still
 * renders the legacy rows above. All four cards share one loop; the mosaic
 * split is pure CSS, the per-card theming is the `card-bg-*` post_class
 * that inc/post-types.php derives from the project's `card_bg` meta.
 *
 * Light card tokens (bg, title colour, strip height) ride CSS custom
 * properties so each variant only overrides three things.
 */

.work .work__query { margin-top: 28px; }

.work .work__list {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 20px;
}

/* Mosaic: card 1 full width, cards 2+3 share a row, card 4 full width. */
.work .work__list > li:first-child,
.work .work__list > li:nth-child(4) {
	grid-column: 1 / -1;
}

.work .work-card {
	position: relative;
	display: flex;
	flex-direction: column;
	box-sizing: border-box;
	padding: 28px 28px 0;
	border-radius: 24px;
	overflow: clip;
	background: var(--work-card-bg, #ffffff);
	--work-card-bg: #ffffff;
	--work-card-title: #141414;
	--work-card-media-h: clamp(320px, 30vw, 430px);
	transition: translate 0.5s var(--ease-out);
}

/* Hover lift (translate property — GSAP's tilt owns transform|rotate/scale). */
.work .work-card:hover { translate: 0 -4px; }

/*
 * Per-card theming, keyed on the card element itself so the tokens are local
 * (an inherited value would lose to the defaults above). The `card-bg-*`
 * class lives on the surrounding <li> (post_class).
 */
.work .card-bg-blue .work-card {
	--work-card-bg: #ffffff;
	--work-card-title: #2454e6;
	--work-card-media-h: clamp(230px, 21vw, 300px);
}

.work .card-bg-peach .work-card {
	--work-card-bg: #f6ddd0;
	--work-card-title: #17614b;
}

.work .card-bg-teal .work-card {
	--work-card-bg: #ffffff;
	--work-card-title: #0d8a7d;
}

.work .card-bg-lilac .work-card {
	--work-card-bg: #ffffff;
	--work-card-title: #5c2ed6;
}

/* Head row: type pills left, circular arrow right. */
.work .work-card__head {
	display: flex;
	align-items: flex-start;
	justify-content: space-between;
	gap: 16px;
}

.work .work-card .project-tags {
	margin: 0;
	gap: 8px;
	/* Pills wrap rather than push the arrow off the card (narrow viewports). */
	min-width: 0;
}

.work .work-card .project-tags a {
	border-color: rgba(20, 20, 20, 0.22);
	color: rgba(20, 20, 20, 0.62);
	font-size: 11px;
	letter-spacing: 0.08em;
	text-transform: uppercase;
}

/* Circular arrow. The link's visible label ("View case study") is collapsed
   with font-size 0 — it stays in the accessibility tree, and the ↗ is drawn
   by the ::before. The read-more block also carries the post's title in a
   visually hidden span, so screen readers announce the full target. */
.work .work-card__arrow {
	display: inline-grid;
	place-items: center;
	flex-shrink: 0;
	width: 44px;
	height: 44px;
	border-radius: 50%;
	background: #141414;
	color: #f4f1ea;
	font-size: 0;
	text-decoration: none;
	transition: background 0.3s var(--ease-out), scale 0.3s var(--ease-out);
}

.work .work-card__arrow::before {
	content: "↗";
	font-size: 17px;
}

.work .work-card__arrow:hover,
.work .work-card__arrow:focus-visible {
	background: var(--color-accent);
	color: var(--color-on-accent);
	scale: 1.08;
}

/* The lilac card's arrow sits bottom-left, clear of the right-anchored
   imagery (mock card 04). Back in flow (after the tags) on mobile. */
.work .card-bg-lilac .work-card__arrow {
	position: absolute;
	bottom: 24px;
	left: 24px;
}

.work .work-card__title {
	margin: 18px 0 0;
	font-size: clamp(26px, 2.4vw, 34px);
	line-height: 1.12;
}

.work .work-card__title a {
	color: var(--work-card-title);
	text-decoration: none;
	background-image: linear-gradient(currentColor, currentColor);
	background-repeat: no-repeat;
	background-position: 0 100%;
	background-size: 0% 1px;
	transition: background-size 0.3s var(--ease-out);
}

.work .project-row:hover .work-card__title a,
.work .work-card:focus-within .work-card__title a {
	background-size: 100% 1px;
}

.work .work-card__excerpt {
	margin: 12px 0 26px;
	color: rgba(20, 20, 20, 0.72);
	font-size: var(--wp--preset--font-size--body-s);
	line-height: 1.6;
	max-width: 62ch;
}

/* Imagery: full bleed to the card's inline edges and bottom; the frame's
   crop and zoom behave like the legacy visual (parallax rides transform). */
.work .work-card__media {
	position: relative;
	margin: auto -28px 0;
}

.work .work-card__media img {
	display: block;
	width: 100%;
	height: auto;
	object-fit: cover;
	scale: 1.2;
	transition: scale 0.6s var(--ease-out);
}

/* Only the wide freight illustration crops to a fixed strip; the other three
   artworks render at their natural ratio so nothing of the composition is lost. */
.work .card-bg-blue .work-card__media img {
	height: var(--work-card-media-h);
}

.work .project-row:hover .work-card__media img,
.work .work-card__media:focus-within img {
	scale: 1.28;
}

.work .card-bg-lilac .work-card {
	/* Matched to the artwork's own backdrop tint (sampled: #f8f6f9 top,
	   #f5f5f5 left, with a lavender wash) so the seam melts away. */
	--work-card-bg: #f6f5f8;
	--work-card-title: #5c2ed6;
}

/* The money-manager artwork sits right, clear of the bottom-left arrow,
   bleeding off the card's right edge. */
.work .card-bg-lilac .work-card__media {
	margin-inline: 0 -28px;
	width: min(64%, 660px);
	margin-left: auto;
}

/* Melt the artwork's top and left edges into the tinted card background. */
.work .card-bg-lilac .work-card__media::before,
.work .card-bg-lilac .work-card__media::after {
	content: "";
	position: absolute;
	z-index: 1; /* above the image, below the tilt glare */
	pointer-events: none;
}

.work .card-bg-lilac .work-card__media::before {
	inset: 0 auto 0 0;
	width: clamp(60px, 14%, 150px);
	background: linear-gradient(90deg, var(--work-card-bg), transparent);
}

.work .card-bg-lilac .work-card__media::after {
	inset: 0 0 auto 0;
	height: clamp(28px, 10%, 80px);
	background: linear-gradient(180deg, var(--work-card-bg), transparent);
}

/* ----------------------------------------------------------------- stats */

.stats { padding-top: 120px; }

.stats__grid {
	display: grid !important;
	grid-template-columns: repeat(4, 1fr);
	gap: 20px;
}

/* Neutralise core/columns flex behavior; the grid owns the layout. */
.stats__grid > .wp-block-column {
	flex-basis: auto !important;
	margin: 0 !important;
}

.stat-card {
	box-sizing: border-box;
	padding: 32px;
	border: 1px solid var(--color-line);
	border-radius: 20px;
	background: transparent;

	/* Hover lift on the `translate` property: the staircase parallax owns
	   `transform`, so they never conflict (motion.js). */
	transition: translate 0.35s var(--ease-out), background-color 0.35s var(--ease-out);
}

.stat-card:hover {
	translate: 0 -8px;
	background: var(--wp--preset--color--surface-hover);
}

.stat-card__number {
	margin: 0 0 6px;
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--stat-number);
	line-height: 1;
	transition: color 0.35s var(--ease-out);
}

.stat-card:hover .stat-card__number { color: var(--color-accent); }

.stat-card__label {
	margin: 0;
	font-size: 14px;
	line-height: 1.5;
}

/* ------------------------------------------------------------ experience */

.experience { padding-top: 140px; }

.experience__head {
	max-width: 640px;
	margin-bottom: 56px;
}

.experience__title { margin: 0; }

.experience__list {
	margin: 0;
	padding: 0;
	list-style: none;
}

.experience-row {
	display: grid;
	grid-template-columns: 140px 1.4fr 1fr 40px;
	gap: 24px;
	align-items: center;
	padding-block: 28px;
	padding-left: 0;
	background: transparent;
	text-decoration: none;
	position: relative;
	transition: padding-left var(--dur-med) var(--ease-out), background-color var(--dur-med) var(--ease-out);
}

/* The row's top border draws left-to-right on entry (spec 6.7). */
.experience-row::before {
	content: "";
	position: absolute;
	inset: 0 auto auto 0;
	width: 100%;
	height: 1px;
	background: var(--color-line);
	transform: scaleX(0);
	transform-origin: left;
	transition: transform 0.7s var(--ease-out);
}

.experience-row.is-drawn::before { transform: scaleX(1); }

.experience__list li:last-child .experience-row {
	border-bottom: 1px solid var(--color-line);
}

.experience-row:hover {
	padding-left: 20px;
	background: var(--wp--preset--color--row-hover);
}

.experience-row__duration {
	margin: 0;
	font-size: var(--wp--preset--font-size--eyebrow);
	letter-spacing: 0.14em;
	text-transform: uppercase;
}

.experience-row__role {
	margin: 0 0 4px;
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--role-title);
	line-height: 1.2;
	color: var(--color-text);
}

.experience-row__where,
.experience-row__sector {
	margin: 0;
	font-size: 15px;
}

.experience-row__arrow {
	justify-self: end;
	color: var(--color-muted);
	font-size: 22px;
	transition: transform var(--dur-med) var(--ease-out), color var(--dur-med) var(--ease-out);
}

.experience-row:hover .experience-row__arrow {
	transform: translate(4px, -4px);
	color: var(--color-accent);
}

.experience__more {
	margin-top: 48px;
}

/* --------------------------------------------------------------- contact */

.contact {
	position: relative;
	padding-top: 160px;
	text-align: center;
}

/* Full-bleed glow, same recipe as the hero bands: the box spans the whole
   viewport width and the gradient reaches alpha 0 inside every edge, so it
   never shows a seam and never widens the page. It keeps riding the slow
   parallax (±25px ≪ the fade margins). */
.contact__glow {
	position: absolute;
	top: 60px;
	bottom: 0;
	left: calc(50% - 50vw);
	right: calc(50% - 50vw);
	background: radial-gradient(60% 40% at 50% 42%, rgba(245, 181, 68, 0.12), rgba(245, 181, 68, 0) 78%);
	pointer-events: none;
	z-index: 0;
}

.contact__eyebrow,
.contact__lede,
.contact__title,
.contact__cta,
.contact-form,
.contact__social {
	position: relative;
	z-index: 1;
}

.contact__eyebrow {
	font-size: var(--wp--preset--font-size--eyebrow);
	letter-spacing: 0.14em;
	text-transform: uppercase;
	margin-bottom: 20px;
}

.contact__title {
	font-size: var(--wp--preset--font-size--contact-title);
	line-height: 1.05;
	max-width: 900px;
	margin: 0 auto 24px;
}

.contact__lede {
	max-width: 560px;
	margin: 0 auto 32px !important;
	color: var(--color-muted);
	font-size: 18px;
	line-height: 1.6;
}

.contact__cta {
	justify-content: center;
	gap: 16px;
	margin-bottom: 72px;
}

.contact-form {
	display: grid;
	gap: 18px;
	max-width: 620px;
	margin: 24px auto 0;
	text-align: left;
}

.contact-form__heading {
	margin: 48px auto 8px;
	font-size: 24px;
}

.field { position: relative; }

.field input,
.field textarea {
	width: 100%;
	box-sizing: border-box;
	padding: 22px 18px 10px;
	border: 1px solid var(--color-line);
	border-radius: 14px;
	background: rgba(255, 255, 255, 0.03);
	color: var(--color-text);
	font-family: var(--wp--preset--font-family--sans);
	font-size: 15px;
	line-height: 1.5;
	outline: none;
	transition: border-color var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
}

.field textarea {
	resize: vertical;
	min-height: 140px;
}

.field label {
	position: absolute;
	top: 18px;
	left: 18px;
	padding: 0 6px;
	color: var(--color-muted);
	font-size: 15px;
	pointer-events: none;
	transition: transform var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out), background-color var(--dur-fast) var(--ease-out);
}

/* Floating labels (spec 7): the placeholder is empty space, so the label
   floats up as soon as the field is filled or focused. */
.field input:focus + label,
.field textarea:focus + label,
.field input:not(:placeholder-shown) + label,
.field textarea:not(:placeholder-shown) + label {
	transform: translateY(-14px) scale(0.82);
	color: var(--color-text);
	background: var(--color-bg);
}

.field input:focus,
.field textarea:focus {
	border-color: var(--color-accent);
	box-shadow: 0 0 0 3px rgba(245, 181, 68, 0.18);
}

/* Honeypot fields: out of sight, out of the tab order. */
.field--hp {
	position: absolute !important;
	width: 1px;
	height: 1px;
	margin: -1px;
	overflow: hidden;
	clip-path: inset(100%);
	clip: rect(0 0 0 0);
	white-space: nowrap;
}

.contact-form__submit {
	justify-self: start;
	padding: 14px 26px;
	border: 0;
	border-radius: 999px;
	background: var(--color-accent);
	color: var(--color-on-accent);
	font-family: var(--wp--preset--font-family--sans);
	font-size: 15px;
	font-weight: 600;
	cursor: pointer;
	transition: transform var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
}

.contact-form__submit:hover {
	transform: translateY(-3px);
	box-shadow: 0 6px 24px rgba(245, 181, 68, 0.25);
}

.contact-form__submit:active { transform: scale(0.97); }

.contact-form__notice {
	max-width: 620px;
	margin: 16px auto 0;
	padding: 14px 20px;
	border: 1px solid var(--color-line);
	border-radius: 14px;
	background: rgba(255, 255, 255, 0.03);
	color: var(--color-text);
	font-size: 15px;
	text-align: left;
}

.contact-form__notice--error {
	border-color: rgba(230, 90, 70, 0.6);
	color: #ffb3a7;
}

.contact-form__check {
	display: inline-block;
	margin-right: 8px;
	color: var(--color-accent);
}

/* Animated checkmark on the success notice (spec 7). */
[data-success] .contact-form__check {
	animation: check-in 0.45s var(--ease-out) both;
}

@keyframes check-in {
	from { transform: scale(0.2); opacity: 0; }
	to   { transform: scale(1); opacity: 1; }
}

/* Social circular buttons (spec 4.7 / 7). */
.contact__social {
	justify-content: center !important;
	gap: 14px !important;
	margin-top: 48px;
}

.contact__social li { margin: 0 !important; }

.contact__social a {
	width: 48px;
	height: 48px;
	display: flex;
	align-items: center;
	justify-content: center;
	border: 1px solid var(--color-line);
	border-radius: 50%;
	background: transparent;
	color: var(--color-text);
	transition: background-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);
}

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

.contact__social a:hover,
.contact__social a:focus-visible {
	background: var(--color-accent);
	border-color: var(--color-accent);
	color: var(--color-on-accent);
	transform: translateY(-4px) rotate(8deg);
}

/* Accent shimmer sweep over "awesome" (added by motion.js once revealed). */
.shimmer {
	background: linear-gradient(90deg, currentColor 40%, #fff 50%, currentColor 60%) 200% 0 / 200% 100% text;
	-webkit-text-fill-color: transparent;
	animation: sheen 1.6s var(--ease-out) forwards;
}

@keyframes sheen {
	to { background-position: -100% 0; }
}

/* ------------------------------------------------------------- footer */

.site-footer {
	margin-top: 80px;
	border-top: 1px solid var(--color-line);
	padding: 48px clamp(20px, 3vw, 40px);
}

.site-footer__inner {
	box-sizing: content-box;
	max-width: 1280px;
	margin: 0 auto;
}

.site-footer__copy {
	font-size: 14px;
	color: var(--color-muted);
}

.site-footer__copy p { margin: 0; }

.site-footer__links {
	gap: 20px;
	align-items: center;
}

.site-footer__link {
	margin: 0;
	font-size: 14px;
}

/* Underline grows from the left on footer nav + text links (spec 7). */
.site-footer__link a,
.hero__lede a,
.experience-row__where a {
	color: var(--color-text);
	text-decoration: none;
}

.site-footer__link a {
	background-image: linear-gradient(currentColor, currentColor);
	background-repeat: no-repeat;
	background-position: 0 100%;
	background-size: 0% 1px;
	transition: background-size 0.3s var(--ease-out), color 0.3s var(--ease-out);
}

.site-footer__link a:hover,
.site-footer__link a:focus-visible {
	background-size: 100% 1px;
}

/* --------------------------------------------------------------- buttons */

/* Shared micro-interactions: lift, arrow slide, glow, magnetic (motion.js). */
.wp-block-button__link {
	display: inline-flex;
	align-items: center;
	gap: 6px;
}

.wp-block-button:hover .wp-block-button__link,
.wp-block-button:focus-within .wp-block-button__link {
	transform: translateY(-3px);
}

.wp-block-button:active .wp-block-button__link,
.wp-block-button__link:active {
	transform: scale(0.97) !important;
}

.wp-block-button__link {
	transition: transform var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out), background-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}

.btn-arrow {
	display: inline-block;
	transition: transform var(--dur-fast) var(--ease-out);
}

.wp-block-button:hover .btn-arrow {
	transform: translate(3px, -3px);
}

/* Primary gets the soft accent glow; secondary border turns accent. */
.wp-block-button:not(.is-style-secondary) .wp-block-button__link:hover,
.wp-block-button:not(.is-style-secondary) .wp-block-button__link:focus-visible {
	box-shadow: 0 8px 28px rgba(245, 181, 68, 0.28);
}

.wp-block-button.is-style-secondary .wp-block-button__link:hover,
.wp-block-button.is-style-secondary .wp-block-button__link:focus-visible {
	border-color: var(--color-accent);
	color: var(--color-accent);
}

/* --------------------------------------------------------- custom cursor */

/* The "View" cursor is an 88px accent circle created by motion.js; it only
   ever rides along on desktops with a fine pointer (motion.css hidden under
   reduced motion; motion.js adds it). It never replaces focus indicators. */
.cursor-view {
	position: fixed;
	top: 0;
	left: 0;
	z-index: 150;
	display: grid;
	place-items: center;
	width: 88px;
	height: 88px;
	border-radius: 50%;
	background: var(--color-accent);
	color: var(--color-on-accent);
	font-size: 14px;
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.04em;
	pointer-events: none;
	translate: -50% -50%;
	opacity: 0;
	transition: opacity 0.25s var(--ease-out);
}

.cursor-view.is-visible { opacity: 1; }

/* Under fine pointers, hide the native cursor over the visuals only. */
@media (pointer: fine) {
	html.js .project-visual,
	html.js .work .work-card__media { cursor: none; }
}

/* ------------------------------------------------- project visual helpers */

/* Tilt glare highlight (motion.js drives --glare-x/--glare-y). */
.project-visual__glare {
	position: absolute;
	inset: 0;
	z-index: 2;
	background: radial-gradient(
		400px circle at var(--glare-x, 50%) var(--glare-y, 50%),
		rgba(255, 255, 255, 0.25),
		transparent 45%
	);
	opacity: 0;
	transition: opacity 0.5s var(--ease-out);
	pointer-events: none;
}

.project-row:hover .project-visual__glare { opacity: 1; }

/* ------------------------------------------------------ back to top */

.back-to-top {
	position: fixed;
	right: 22px;
	bottom: 22px;
	z-index: 95;
	display: grid;
	place-items: center;
	width: 48px;
	height: 48px;
	border: 0;
	border-radius: 50%;
	background: var(--color-accent);
	color: var(--color-on-accent);
	font-size: 18px;
	cursor: pointer;
	opacity: 0;
	scale: 0.8;
	transition: opacity var(--dur-med) var(--ease-out), scale var(--dur-med) var(--ease-out);
}

.back-to-top.is-visible {
	opacity: 1;
	scale: 1;
}

/* --------------------------------------------------------- page transition */

.js .is-online a[data-leaving] { /* reserved hook — see motion.js */ }

/* --------------------------------------------------------- responsive ≤820px */

@media (max-width: 820px) {
	/* Parallax JS scales distances by 0.4; layout below. */
	.hero {
		padding-top: 56px;
	}

	/* Decor spots are desktop-only — on mobile they land on the copy. */
	.hero__spark,
	.hero__dot { display: none; }

	.hero__inner {
		grid-template-columns: 1fr;
		gap: 40px;
	}

	.hero__media {
		justify-self: center;
		max-width: min(100%, 420px);
	}

	.hero__ring { width: 125%; }

	.hero__chip { padding: 10px 14px; font-size: 14px; }
	.hero__chip--ai { top: 40%; left: -10px; }
	.hero__chip--role { bottom: 20px; left: -10px; font-size: 15px; }

	.hero { padding-bottom: 64px; }

	.site-header__inner { padding-top: 20px; padding-bottom: 20px; }

	/* The inline nav and the status line give way to the overlay menu. */
	.js .site-nav,
	.js .site-status { display: none; }

	.menu-toggle {
		display: grid;
	}

	/* With JS disabled the real nav stays available (progressive enhancement). */
	html:not(.js) .menu-toggle { display: none; }

	.project-row__grid {
		grid-template-columns: 1fr;
		gap: 28px;
		padding-block: 48px;
	}

	.work__list > li:nth-child(even) .project-row__grid { direction: ltr; }

	.project-row__text { grid-column: 1; }

	.project-row__number { font-size: 64px; }

	/* Cards stack in one column; imagery strips shrink to portrait-friendly
	   heights and the lilac arrow returns to the head row. */
	.work .work__list {
		grid-template-columns: 1fr;
		gap: 24px;
	}

	.work .work-card {
		padding: 22px 22px 0;
		border-radius: 20px;
		--work-card-media-h: clamp(200px, 56vw, 300px);
	}

	.work .card-bg-blue { --work-card-media-h: clamp(170px, 44vw, 240px); }

	.work .card-bg-lilac .work-card__arrow {
		position: static;
		/* head is space-between; the arrow already follows the tags. */
		margin-left: auto;
	}

	.work .card-bg-lilac .work-card__media {
		width: 100%;
		margin-inline: -22px;
	}

	.work .work-card__media {
		margin-inline: -22px;
	}

	.work .work-card__title { font-size: 26px; }

	.stats__grid { grid-template-columns: repeat(2, 1fr); }

	.experience-row {
		grid-template-columns: 1fr 40px;
		gap: 8px 16px;
		/* Re-flow: duration + arrow share line 1, the title block spans
		   below so it never lands in the narrow 40px arrow column. */
		grid-template-rows: auto auto;
		align-items: start;
	}

	.experience-row__duration {
		grid-row: 1;
		grid-column: 1;
		align-self: center;
	}

	.experience-row__arrow {
		grid-row: 1;
		grid-column: 2;
		justify-self: end;
		font-size: 18px;
	}

	.experience-row__main {
		grid-row: 2;
		grid-column: 1 / -1;
		margin-block-start: 4px;
	}

	.experience-row__where { grid-column: 1; }

	.experience-row__sector { display: none; }

	.contact { padding-top: 120px; }
}

/* --------------------------------------------------------- reduced motion */

@media (prefers-reduced-motion: reduce) {
	/*
	 * The compact sweep: near-zero durations kill every loop and transition.
	 * Hover color changes still work (they are not timed by the sweep, they
	 * just happen instantly).
	 */
	*, *::before, *::after {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
	}

	/* Restore everything an entrance was hiding. */
	.js [data-reveal] {
		opacity: 1 !important;
		transform: none !important;
		clip-path: none !important;
	}

	.js [data-split] .split-word > .split-word__inner { transform: none !important; }

	/* The scroll progress bar and the blob/hero copy drift are scroll effects:
	     disable them entirely. */
	.scroll-progress { display: none; }

	/* The marquee holds still (a static band of names is fine). */
	.marquee::before, .marquee::after { transform: none; }

	.header-hold,
	.site-header.is-hidden { transform: none !important; }

	.project-visual,
	.project-visual__frame img,
	.work .work-card__media,
	.work .work-card__media img,
	.stat-card,
	.experience-row,
	.marquee,
	.hero__blob,
	.hero__inner { transition: none !important; transform: none !important; animation: none !important; }

	.back-to-top { transition: none; }
}

/* Custom cursor never runs without a fine pointer. */
@media (pointer: coarse), (hover: none) {
	.cursor-view { display: none; }
	.js .project-visual,
	.js .work .work-card__media { cursor: auto; }
}
