/* =========================================================
   Polish pass — site-wide fit + finish.
   Loaded last so it can override module-level rules where needed.
   Aligned with Mona_Polish_Prompt.md (April 2026).
   ========================================================= */

/* ---------- Font rendering ---------- */
body {
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
	text-rendering: optimizeLegibility;
}

/* ---------- Text-wrap (modern, progressive enhancement) ---------- */
/* Headings get balance — avoids orphan words on the last line of a long heading.
   Body text gets pretty — better paragraph rag, no widows. Both are no-ops in
   browsers that don't support them. */
h1, h2, h3, h4 { text-wrap: balance; }
p, li         { text-wrap: pretty; }

/* ---------- Form inputs (iOS auto-zoom prevention + touch targets) ---------- */
/* Any input/select/textarea on the site — never below 16px on mobile.
   iOS Safari auto-zooms the viewport when a form input below 16px gets focus,
   which causes a jarring layout shift. Belt-and-braces: explicit 16px floor. */
input[type="text"],
input[type="email"],
input[type="tel"],
input[type="url"],
input[type="number"],
input[type="password"],
input[type="search"],
input[type="date"],
select,
textarea {
	font-size: max(1rem, 16px);
}

/* Mobile only — bump min-height on inputs so they're easy to tap. */
@media (max-width: 767px) {
	input[type="text"],
	input[type="email"],
	input[type="tel"],
	input[type="url"],
	input[type="number"],
	input[type="password"],
	input[type="search"],
	input[type="date"],
	select {
		min-height: 48px;
	}
	textarea { min-height: 140px; }
}

/* ---------- Filter bar — horizontal scroll on mobile ---------- */
/* Both .pf-filter (portfolio archive) and .fw-filter (homepage) inherit this
   so neither wraps to a second row on small screens. */
@media (max-width: 767px) {
	.pf-filter,
	.fw-filter {
		flex-wrap: nowrap;
		overflow-x: auto;
		-webkit-overflow-scrolling: touch;
		scrollbar-width: none;
		scroll-snap-type: x proximity;
		padding-inline: var(--gutter);
		margin-inline: calc(var(--gutter) * -1);
	}
	.pf-filter::-webkit-scrollbar,
	.fw-filter::-webkit-scrollbar {
		display: none;
	}
	.pf-filter button,
	.fw-filter button {
		flex-shrink: 0;
		scroll-snap-align: start;
	}
}

/* ---------- Hero — svh on mobile prevents content hiding under browser chrome ---------- */
/* `100vh` includes the visible URL bar AND the chrome that slides up while
   scrolling. `100svh` is just the visible safe area. Use it on mobile only;
   desktop browsers don't have the same chrome behaviour. */
@media (max-width: 767px) {
	.home-hero        { min-height: 90svh; }
	.ab-hero          { min-height: auto; } /* about hero already content-driven */
	.subbrand-hero    { min-height: 80svh; }
}

/* ---------- Touch targets (WCAG 2.2 AAA spec is 44×44; we hit it where it matters) ---------- */
/* Only icon-only buttons get the explicit 36px floor. Text-based nav links
   (.np-menutrig, .lang button) are already correctly sized via the
   inline-flex layout in components.css — adding min-height to them throws
   baseline alignment off because they're peers of plain <a> links. */
.np-burger,
.welsh-hint-close,
.reel-lightbox-close,
.hamburger,
button.icon-btn {
	min-height: 36px;
	min-width: 36px;
}

/* ---------- Custom scrollbar (desktop only) ---------- */
/* Thin, accent-coloured on hover. Mobile uses native scroll feel. */
@media (min-width: 768px) {
	* {
		scrollbar-width: thin;
		scrollbar-color: var(--muted-2) transparent;
	}
	::-webkit-scrollbar       { width: 8px; height: 8px; }
	::-webkit-scrollbar-track { background: transparent; }
	::-webkit-scrollbar-thumb {
		background: var(--muted-2);
		border-radius: 4px;
		border: 2px solid transparent;
		background-clip: padding-box;
	}
	::-webkit-scrollbar-thumb:hover { background: var(--accent); background-clip: padding-box; }
}

/* ---------- Light mode card refinement ---------- */
/* In light mode, hairline borders read as a bit weak. Add a subtle shadow on
   key cards so they have presence on the warm off-white background. */
body:not(.dark) .seas-card {
	box-shadow: 0 1px 3px rgba(0, 0, 0, .04), 0 1px 2px rgba(0, 0, 0, .03);
}
body:not(.dark) .seas-card:hover {
	box-shadow: 0 6px 18px -6px rgba(0, 0, 0, .12), 0 2px 6px -2px rgba(0, 0, 0, .08);
}

/* ---------- Image safety ---------- */
/* Stop accidental overflows site-wide. Most modules already do this; the
   global rule is a backstop. */
img, video {
	max-width: 100%;
	height: auto;
	display: block;
}

/* Lazy images get a placeholder colour so layout doesn't shift before load. */
img[loading="lazy"] {
	background: rgba(20, 22, 22, .04);
}
body.dark img[loading="lazy"] {
	background: rgba(245, 245, 244, .04);
}

/* ---------- No horizontal scroll site-wide ---------- */
html, body {
	overflow-x: hidden;
}

/* ---------- Scroll progress bar ----------
 * Pure-CSS scroll-driven animation. Renders a 2px teal line at the top of
 * the viewport that fills left→right as the user scrolls. Zero JS, runs
 * entirely off the main thread. Applies only on pages where body has
 * .has-progress-bar (set in functions.php for portfolio singles, about,
 * faq — long-form content where the reader benefits from progress feedback).
 *
 * Browser support: Chrome 115+, Firefox 134+, Safari 17.5+ (with -webkit-).
 * Falls back to no progress bar in unsupported browsers (no broken state). */
.has-progress-bar::before {
	content: "";
	position: fixed;
	top: 0;
	left: 0;
	right: 0;
	height: 2px;
	background: var(--accent);
	transform-origin: left center;
	transform: scaleX(0);
	z-index: 1000;
	pointer-events: none;
	animation: mona-scroll-progress linear;
	animation-timeline: scroll(root);
}
@keyframes mona-scroll-progress {
	to { transform: scaleX(1); }
}

/* ---------- Cinematic page transitions ----------
 * Native cross-document View Transitions API (Chrome 126+, Safari 18.2+).
 *
 * Two layers stack:
 *   1. The default root transition — outgoing page drifts UP + fades, the
 *      incoming page rises FROM BELOW with a clip-mask reveal + slight
 *      scale-down. Reads as a deliberate "stage lift", not a snap.
 *   2. Named transitions (vt-{slug}) — portfolio card thumbnail morphs
 *      directly into the project-page hero. Browser snapshots both
 *      elements with that name, FLIP-animates between them. The headline
 *      effect: card flies into hero on click.
 *
 * The card sets its name via inline style (one per slug, generated PHP-side).
 * The matching destination hero on single-portfolio.php has the same name.
 *
 * Total duration is ~0.7s — long enough to feel deliberate and editorial,
 * short enough to never feel slow.
 */
@view-transition {
	navigation: auto;
}

/* Outgoing page — fades + drifts up + slight scale-down (camera pulls back). */
::view-transition-old(root) {
	animation: mona-page-out .38s cubic-bezier(.65, 0, .35, 1) forwards;
}
@keyframes mona-page-out {
	from { opacity: 1; transform: translateY(0)    scale(1); }
	to   { opacity: 0; transform: translateY(-32px) scale(.97); }
}

/* Incoming page — rises from below, reveals via clip-mask wipe (top→bottom),
 * scale settles from 1.04 → 1. Slight overlap timing creates the cross-fade. */
::view-transition-new(root) {
	animation: mona-page-in .68s cubic-bezier(.16, 1, .3, 1) forwards;
}
@keyframes mona-page-in {
	from {
		opacity: 0;
		transform: translateY(48px) scale(1.04);
		clip-path: inset(0 0 100% 0);
	}
	60% {
		opacity: 1;
	}
	to {
		opacity: 1;
		transform: translateY(0) scale(1);
		clip-path: inset(0 0 0% 0);
	}
}

/* Named morphs — portfolio cards. The wildcard targets every vt-* group
   the browser pairs up, so we don't need a rule per slug. Tuned with a
   slightly slower curve than root since the morph is the "wow moment". */
::view-transition-group(*) {
	animation-duration: .65s;
	animation-timing-function: cubic-bezier(.65, 0, .35, 1);
}
::view-transition-image-pair(*) {
	isolation: isolate; /* prevent backdrop-filter bleed during morph */
}

/* (Removed: teal/blue gradient sweep on portfolio cards. Felt too
 *  "hover effect" — the cinematic Ken Burns + slideshow + lift now
 *  carry the hover state on their own.) */

/* ---------- Client / broadcast logo marquee ----------
 * Continuous horizontal scroll of client + broadcast logos, hover-paused
 * for legibility. Logos are recolored to a single tone so they harmonize
 * (full-colour brand logos in a strip look chaotic). The track contains
 * two identical rows side-by-side so when row #1 scrolls off the left,
 * row #2 is already in view — the loop is seamless.
 * --------------------------------------------------------------- */
/* Marquee section — full-width edge-fade. Logos themselves have
 * transparent backgrounds (Imagick-stripped) and are tinted by CSS
 * filter to match the theme. Hover reveals original colour. */
.client-marq {
	margin: 9rem 0 6rem;
	padding: 4rem 0 3.5rem;
	overflow: hidden;
	position: relative;
	/* Full viewport width so the fade reaches the actual screen edges. */
	width: 100vw;
	margin-left: calc(50% - 50vw);
	margin-right: calc(50% - 50vw);
	/* Wide soft fade — 22% on each side. Logos are gradually revealed
	 * (and dissolved) over a fifth of the screen, which feels editorial
	 * rather than abrupt. */
	-webkit-mask-image: linear-gradient(to right,
		transparent 0%,
		rgba(0,0,0,.4) 8%,
		rgba(0,0,0,.85) 18%,
		#000 22%,
		#000 78%,
		rgba(0,0,0,.85) 82%,
		rgba(0,0,0,.4) 92%,
		transparent 100%
	);
	        mask-image: linear-gradient(to right,
		transparent 0%,
		rgba(0,0,0,.4) 8%,
		rgba(0,0,0,.85) 18%,
		#000 22%,
		#000 78%,
		rgba(0,0,0,.85) 82%,
		rgba(0,0,0,.4) 92%,
		transparent 100%
	);
}
.client-marq-eyebrow {
	display: flex;
	justify-content: center;
	margin-bottom: 2rem;
}
.client-marq-eyebrow span {
	font-family: var(--font-mono);
	font-size: .72rem;
	letter-spacing: .14em;
	text-transform: uppercase;
	color: var(--muted);
	padding: 0 var(--gutter);
}
.client-marq-track {
	display: flex;
	width: max-content;
	animation: mona-client-marq-scroll 60s linear infinite;
	will-change: transform;
}
.client-marq-row {
	display: flex;
	align-items: center;
	gap: clamp(2.5rem, 5vw, 4.5rem);
	padding-right: clamp(2.5rem, 5vw, 4.5rem);
	flex-shrink: 0;
}
/* ---------- Follow-the-work section ----------
 * Sits between testimonial and footer CTA. Editorial layout: handle
 * as the hero, single line of context underneath, social icons as a
 * row of equally-sized links. No embed, no bloat — just clean
 * outbound links with proper rel="external" for SEO + privacy.
 *
 * Matches the typographic rhythm of the rest of the homepage —
 * Outfit display, Fraunces italic accent, generous whitespace.
 * --------------------------------------------------------------- */
.follow-work {
	max-width: 900px;
	margin: 6rem auto;
	padding: 0 var(--gutter);
	text-align: center;
	color: var(--ink);
}
.follow-work-handle {
	font-family: var(--font-display);
	font-weight: 500;
	font-size: clamp(2.4rem, 5.5vw, 4.5rem);
	letter-spacing: -0.04em;
	line-height: 1;
	margin: 0 0 1.4rem;
	color: var(--ink);
}
.follow-work-handle .italic {
	font-family: var(--font-accent-serif);
	font-style: italic;
	font-weight: 300;
	color: var(--accent-deep);
}
.follow-work-line {
	font-size: clamp(1rem, 1.6vw, 1.2rem);
	color: var(--muted);
	max-width: 50ch;
	margin: 0 auto 2.5rem;
	line-height: 1.55;
}
.follow-work-icons {
	display: flex;
	justify-content: center;
}

/* The shared mona_social_icons() output uses .mona-socials. We
 * override it specifically when it's inside this section to make
 * the icons larger, more prominent, with subtle hover treatment. */
.follow-work .mona-socials.follow-work-socials {
	list-style: none;
	display: flex;
	gap: 1.6rem;
	padding: 0;
	margin: 0;
}
.follow-work .mona-socials.follow-work-socials a {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 56px;
	height: 56px;
	border-radius: 50%;
	border: 1px solid var(--hairline);
	background: transparent;
	color: var(--muted);
	transition: color .3s ease, border-color .3s ease, background .3s ease, transform .3s ease;
}
.follow-work .mona-socials.follow-work-socials a:hover,
.follow-work .mona-socials.follow-work-socials a:focus-visible {
	color: var(--accent);
	border-color: var(--accent);
	background: var(--accent-soft);
	transform: translateY(-2px);
}

@media (max-width: 640px) {
	.follow-work {
		margin: 4rem auto;
	}
	.follow-work .mona-socials.follow-work-socials {
		gap: 1rem;
	}
	.follow-work .mona-socials.follow-work-socials a {
		width: 48px;
		height: 48px;
	}
}

/* ---------- Logo item ----------
 * One img per item. BG already stripped (Imagick or GD), so the PNG
 * has a transparent background. CSS filter handles the theme tint:
 *   light mode: dark-grey silhouette
 *   dark mode:  light-grey silhouette
 *   on hover:   removes the filter to reveal original brand colour
 *
 * Sizing: each item is a fixed-width slot (the marquee LANE) and the
 * logo inside is height-normalised — every logo's actual rendered
 * height is the same regardless of aspect ratio, so wordmarks and
 * icon-only marks share visual weight. Square icons sit inside the
 * lane with breathing room; wide wordmarks fill it horizontally.
 * Pattern from Stripe / Linear / Vercel customer strips.
 * ---------------------------------------------------------------- */
.client-marq-item {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex-shrink: 0;
	/* Fixed lane — every logo gets the same horizontal slot */
	width:  clamp(140px, 14vw, 200px);
	height: clamp(48px, 5vw, 64px);
}
.client-marq-item img {
	/* Height-normalise — every logo's rendered height is the SAME */
	height: 100%;
	width: auto;
	max-width: 100%;
	object-fit: contain;
	opacity: .85;
	filter: brightness(0) invert(.42);
	transition: opacity .35s ease, filter .35s ease, transform .35s ease;
}
body.dark .client-marq-item img {
	filter: brightness(0) invert(.92);
}
.client-marq-item:hover img {
	filter: none;
	opacity: 1;
	transform: scale(1.04);
}
.client-marq-wordmark {
	font-family: var(--font-display);
	font-weight: 600;
	font-size: clamp(1rem, 1.5vw, 1.25rem);
	letter-spacing: -0.02em;
	color: var(--muted);
	white-space: nowrap;
	padding: 0 .25em;
}

/* Pause on hover so users can read individual entries */
.client-marq:hover .client-marq-track {
	animation-play-state: paused;
}

@keyframes mona-client-marq-scroll {
	from { transform: translateX(0); }
	to   { transform: translateX(-50%); } /* exactly one row's width */
}

/* Reduced motion — stop the scroll, let content sit static */
@media (prefers-reduced-motion: reduce) {
	.client-marq-track {
		animation: none !important;
		flex-wrap: wrap;
		justify-content: center;
		row-gap: 1.5rem;
	}
	.client-marq-row + .client-marq-row {
		display: none; /* dedup the doubled row */
	}
}

@media (max-width: 720px) {
	.client-marq {
		margin: 4rem auto;
		padding: 2rem 0;
	}
	.client-marq-track {
		animation-duration: 40s;
	}
}

/* Reduced motion: keep the view-transition group calm. */
@media (prefers-reduced-motion: reduce) {
	::view-transition-group(*) { animation-duration: 0s; }
}

/* (Scroll-driven reveals removed — the JS-driven IntersectionObserver
 * path in scroll-reveal.js handles all .reveal animations and works
 * reliably across browsers. The animation-timeline: view() experiment
 * was caused a conflict with the existing .reveal { opacity: 0 } base
 * style and is reverted.) */

/* ---------- Magnetic CTA polish ----------
 * Visual feedback for the magnetic-hover JS. The element itself moves via
 * GSAP-free vanilla JS (see assets/js/magnetic.js). This rule just makes
 * sure the transition is GPU-friendly and respects reduced motion. */
[data-magnetic] {
	will-change: transform;
	transition: background .25s var(--ease), color .25s var(--ease), border-color .25s var(--ease);
}

/* ---------- Subtle link hover refinement ----------
 * Body-text links get a micro-thick underline that slides in on hover from
 * left to right. Replaces the heavy default underline with something that
 * feels editorial. Doesn't override existing `.link-arrow` styling — it
 * only targets paragraph-level links inside .ab-bio, .ab-block, .single-body,
 * .single-reel-caption, and similar prose containers. */
.ab-bio a:not(.btn):not(.link-arrow),
.ab-block a:not(.btn):not(.link-arrow),
.single-body a:not(.btn):not(.link-arrow),
.faq-list a:not(.btn):not(.link-arrow) {
	background-image: linear-gradient(currentColor, currentColor);
	background-position: 0 100%;
	background-repeat: no-repeat;
	background-size: 0 1px;
	transition: background-size .35s var(--ease), color .25s var(--ease);
	text-decoration: none;
	padding-bottom: 1px;
}
.ab-bio a:not(.btn):not(.link-arrow):hover,
.ab-block a:not(.btn):not(.link-arrow):hover,
.single-body a:not(.btn):not(.link-arrow):hover,
.faq-list a:not(.btn):not(.link-arrow):hover {
	background-size: 100% 1px;
	color: var(--accent-deep);
}

/* ---------- Marquee polish ----------
 * Pause the credibility marquee on hover so users can read individual
 * service words. The animation itself lives in home.css. */
.marq:hover .marq-row {
	animation-play-state: paused;
}

/* ---------- Film grain (dark mode global) ----------
 * Fine SVG noise overlay on the dark canvas. References real film grain —
 * directly relevant for a video production studio. Makes flat dark
 * backgrounds feel tactile and expensive without ever competing with
 * content. Pure data-URI SVG, zero network cost, zero JS.
 *
 * Global rules:
 *   - opacity: .035 — felt, not seen
 *   - pointer-events: none / aria-hidden via parent
 *   - animation steps the texture position 10× per second to simulate
 *     actual film grain motion. Tiny CPU cost (transform-only).
 *   - Disabled in light mode (only reads on dark backgrounds).
 *   - Killed by prefers-reduced-motion. */
body.dark::after {
	content: "";
	position: fixed;
	inset: 0;
	pointer-events: none;
	z-index: 900;
	opacity: .035;
	background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
	background-repeat: repeat;
	background-size: 256px 256px;
	mix-blend-mode: overlay;
	animation: mona-grain-shift .55s steps(1) infinite;
}
@keyframes mona-grain-shift {
	0%   { transform: translate(0, 0); }
	10%  { transform: translate(-2%, -3%); }
	20%  { transform: translate(3%, 1%); }
	30%  { transform: translate(-1%, 4%); }
	40%  { transform: translate(4%, -2%); }
	50%  { transform: translate(-3%, 3%); }
	60%  { transform: translate(2%, -4%); }
	70%  { transform: translate(-4%, 1%); }
	80%  { transform: translate(1%, 3%); }
	90%  { transform: translate(-2%, -1%); }
	100% { transform: translate(3%, -3%); }
}

/* ---------- Atmospheric orb (hero depth) ----------
 * Soft, off-canvas-feeling teal glow that sits behind the hero content
 * on the homepage and sub-brand pages. Pulses very slowly (8s breathe).
 * Adds a sense of light source / depth to the otherwise flat dark hero.
 *
 * Positioned in the upper-right quadrant for the homepage; sub-brands
 * shift it to suit the spread of content per page. */
.home-hero { position: relative; isolation: isolate; }
.home-hero::before {
	content: "";
	position: absolute;
	width: 70vmax;
	height: 70vmax;
	border-radius: 50%;
	background: radial-gradient(
		circle,
		rgba(27, 191, 186, .08) 0%,
		rgba(27, 191, 186, .025) 40%,
		transparent 70%
	);
	top: -25%;
	right: -25%;
	z-index: -1;
	pointer-events: none;
	animation: mona-orb-breathe 8s ease-in-out infinite alternate;
}
.home-hero > * { position: relative; z-index: 1; }

/* Sub-brand heroes — same orb but tinted to brand. Position varies. */
.sb-hero { position: relative; isolation: isolate; }
body.sb-stori .sb-hero::before,
body.sb-hafn .sb-hero::before,
body.sb-core .sb-hero::before,
body.sb-boost .sb-hero::before {
	content: "";
	position: absolute;
	width: 60vmax;
	height: 60vmax;
	border-radius: 50%;
	z-index: -1;
	pointer-events: none;
	animation: mona-orb-breathe 9s ease-in-out infinite alternate;
}
body.sb-stori .sb-hero::before { background: radial-gradient(circle, rgba(201, 160, 74, .07) 0%, transparent 70%); top: -15%; right: -10%; }
body.sb-hafn .sb-hero::before  { background: radial-gradient(circle, rgba(201, 168, 76, .06) 0%, transparent 70%); top: auto; bottom: -20%; left: -15%; }
body.sb-core .sb-hero::before  { background: radial-gradient(circle, rgba(232, 90, 42, .08) 0%, transparent 70%); top: auto; bottom: -10%; left: -10%; }
body.sb-boost .sb-hero::before { background: radial-gradient(circle, rgba(124, 58, 237, .09) 0%, transparent 70%); top: -10%; right: -15%; }

@keyframes mona-orb-breathe {
	from { transform: scale(1);    opacity: .85; }
	to   { transform: scale(1.12); opacity: 1; }
}

/* Light mode — orb gets even subtler, just a hint of warmth */
body:not(.dark) .home-hero::before {
	background: radial-gradient(circle, rgba(27, 191, 186, .05) 0%, transparent 70%);
}

/* ---------- Corner viewfinder marks (key sections) ----------
 * Small bracket marks (┌ in the top-left) that suggest a camera viewfinder
 * frame. Applied to specific section types where the framing reference
 * makes sense — service cards, sub-brand intro blocks, the studio bio.
 * Pure CSS via ::before pseudo with a border-only treatment.
 *
 * Apply by adding `.has-viewfinder` to the target element. */
.has-viewfinder {
	position: relative;
}
.has-viewfinder::before,
.has-viewfinder::after {
	content: "";
	position: absolute;
	width: 18px;
	height: 18px;
	border: 1px solid var(--accent);
	opacity: .35;
	pointer-events: none;
}
.has-viewfinder::before {
	top: clamp(.75rem, 2vw, 1.25rem);
	left: clamp(.75rem, 2vw, 1.25rem);
	border-right: 0;
	border-bottom: 0;
}
.has-viewfinder::after {
	bottom: clamp(.75rem, 2vw, 1.25rem);
	right: clamp(.75rem, 2vw, 1.25rem);
	border-left: 0;
	border-top: 0;
}

/* ---------- Chat widget (floating, bottom-right) ----------
 * Opens to a small bilingual panel with quick-reply prompts that
 * pre-fill a WhatsApp message body or email subject. Async by design —
 * no live chat staffing required. Hidden on /contact/.
 *
 * Brand fit: not a garish WhatsApp green button. Uses Mona's teal accent
 * with neutral icons. Pill trigger matches the editorial tone.
 */
.mona-chat {
	position: fixed;
	bottom: clamp(1rem, 2.5vw, 1.5rem);
	right: clamp(1rem, 2.5vw, 1.5rem);
	z-index: 9000;
	font-family: var(--font-sans);
}

/* Trigger button */
.mona-chat-trigger {
	display: inline-flex;
	align-items: center;
	gap: .55rem;
	padding: .85rem 1.2rem .85rem 1rem;
	background: var(--ink);
	color: var(--bg);
	border: 0;
	border-radius: 999px;
	cursor: pointer;
	font-family: var(--font-sans);
	font-size: .9rem;
	font-weight: 500;
	letter-spacing: -0.005em;
	text-transform: lowercase;
	box-shadow: 0 6px 18px -6px rgba(0, 0, 0, .25), 0 2px 6px -2px rgba(0, 0, 0, .15);
	transition: transform .35s var(--ease), box-shadow .35s var(--ease), background .25s var(--ease);
	position: relative;
}
.mona-chat-trigger:hover {
	transform: translateY(-2px);
	box-shadow: 0 12px 28px -8px rgba(0, 0, 0, .3), 0 4px 10px -2px rgba(0, 0, 0, .2);
	background: var(--accent);
}
.mona-chat-trigger:focus-visible {
	outline: 2px solid var(--accent);
	outline-offset: 3px;
}
.mona-chat-icon {
	width: 18px;
	height: 18px;
	stroke: currentColor;
}
.mona-chat-close-icon {
	width: 18px;
	height: 18px;
	display: none;
}
.mona-chat[data-state="open"] .mona-chat-icon { display: none; }
.mona-chat[data-state="open"] .mona-chat-close-icon { display: block; }
.mona-chat[data-state="open"] .mona-chat-trigger-text { display: none; }
.mona-chat[data-state="open"] .mona-chat-trigger { padding: .85rem; }

/* Subtle pulse on first session if user hasn't engaged yet */
.mona-chat.mona-chat-pulse .mona-chat-trigger::after {
	content: "";
	position: absolute;
	inset: 0;
	border-radius: 999px;
	box-shadow: 0 0 0 0 rgba(27, 191, 186, .5);
	animation: mona-chat-pulse 1.6s ease-out infinite;
	pointer-events: none;
}
@keyframes mona-chat-pulse {
	0%   { box-shadow: 0 0 0 0    rgba(27, 191, 186, .55); }
	70%  { box-shadow: 0 0 0 14px rgba(27, 191, 186, 0); }
	100% { box-shadow: 0 0 0 0    rgba(27, 191, 186, 0); }
}

/* Panel */
.mona-chat-panel {
	position: absolute;
	bottom: calc(100% + .8rem);
	right: 0;
	width: clamp(280px, 90vw, 340px);
	background: var(--bg);
	border: 1px solid var(--hairline);
	border-radius: 18px;
	padding: 1.25rem;
	box-shadow: 0 24px 48px -12px rgba(0, 0, 0, .25), 0 8px 16px -8px rgba(0, 0, 0, .15);
	transform-origin: bottom right;
	animation: mona-chat-in .32s cubic-bezier(.16, 1, .3, 1) forwards;
}
body.dark .mona-chat-panel {
	background: var(--bg-alt);
	border-color: rgba(245, 245, 244, .1);
	box-shadow: 0 24px 48px -12px rgba(0, 0, 0, .55), 0 8px 16px -8px rgba(0, 0, 0, .35);
}
@keyframes mona-chat-in {
	from { opacity: 0; transform: translateY(8px) scale(.96); }
	to   { opacity: 1; transform: translateY(0) scale(1); }
}

.mona-chat-head {
	display: flex;
	align-items: center;
	gap: .75rem;
	padding-bottom: 1rem;
	border-bottom: 1px solid var(--hairline);
	margin-bottom: 1rem;
}
.mona-chat-avatar {
	width: 36px;
	height: 36px;
	border-radius: 50%;
	background: var(--ink);
	color: var(--bg);
	display: grid;
	place-items: center;
	flex-shrink: 0;
	position: relative;
	font-family: var(--font-display);
	font-weight: 500;
	font-size: 1rem;
}
.mona-chat-avatar::before {
	content: "D";
	font-family: var(--font-display);
}
.mona-chat-dot {
	position: absolute;
	bottom: 0;
	right: 0;
	width: 10px;
	height: 10px;
	border-radius: 50%;
	background: #2ECC71;
	border: 2px solid var(--bg);
	box-shadow: 0 0 0 0 rgba(46, 204, 113, .55);
	animation: mona-chat-online 2.4s ease-out infinite;
}
body.dark .mona-chat-dot { border-color: var(--bg-alt); }
@keyframes mona-chat-online {
	0%   { box-shadow: 0 0 0 0    rgba(46, 204, 113, .55); }
	70%  { box-shadow: 0 0 0 6px  rgba(46, 204, 113, 0); }
	100% { box-shadow: 0 0 0 0    rgba(46, 204, 113, 0); }
}
.mona-chat-meta {
	display: flex;
	flex-direction: column;
	gap: .15em;
	min-width: 0;
}
.mona-chat-name {
	font-family: var(--font-display);
	font-weight: 500;
	font-size: .95rem;
	color: var(--ink);
	letter-spacing: -0.01em;
	text-transform: lowercase;
}
.mona-chat-status {
	font-family: var(--font-mono);
	font-size: .65rem;
	letter-spacing: .04em;
	color: var(--muted);
	text-transform: lowercase;
}

.mona-chat-greeting p {
	font-size: .95rem;
	line-height: 1.5;
	color: var(--ink);
	margin: 0 0 1rem;
}

.mona-chat-prompts {
	display: flex;
	flex-wrap: wrap;
	gap: .4rem;
	margin-bottom: 1rem;
}
.mona-chat-prompts button {
	background: transparent;
	border: 1px solid var(--hairline);
	border-radius: 999px;
	padding: .45em .8em;
	color: var(--ink);
	font-family: var(--font-sans);
	font-size: .8rem;
	font-weight: 400;
	letter-spacing: -0.005em;
	cursor: pointer;
	transition: background .2s var(--ease), border-color .2s var(--ease), color .2s var(--ease);
	text-transform: lowercase;
}
.mona-chat-prompts button:hover,
.mona-chat-prompts button:focus-visible {
	background: var(--ink);
	color: var(--bg);
	border-color: var(--ink);
	outline: none;
}
.mona-chat-prompts button.is-on {
	background: var(--accent);
	color: var(--ink);
	border-color: var(--accent);
}
body.dark .mona-chat-prompts button.is-on {
	color: #0C0D0D;
}

.mona-chat-actions {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: .55rem;
	padding-top: .25rem;
}
.mona-chat-cta {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: .45em;
	padding: .8em .6em;
	border-radius: 12px;
	font-family: var(--font-sans);
	font-size: .88rem;
	font-weight: 500;
	letter-spacing: -0.005em;
	text-decoration: none;
	transition: background .25s var(--ease), color .25s var(--ease), transform .25s var(--ease);
	min-height: 44px;
}
.mona-chat-cta svg { width: 18px; height: 18px; }
.mona-chat-cta--wa {
	background: #25D366;
	color: #fff;
}
.mona-chat-cta--wa:hover {
	background: #128C7E;
	transform: translateY(-1px);
}
.mona-chat-cta--email {
	background: var(--ink);
	color: var(--bg);
}
.mona-chat-cta--email:hover {
	background: var(--accent);
	color: var(--ink);
	transform: translateY(-1px);
}

.mona-chat-foot {
	font-family: var(--font-mono);
	font-size: .62rem;
	letter-spacing: .08em;
	color: var(--muted-2);
	text-align: center;
	margin: 1rem 0 0;
	text-transform: lowercase;
}

/* Mobile — full-width-ish panel, bottom drawer feel */
@media (max-width: 480px) {
	.mona-chat { right: 1rem; bottom: 1rem; }
	.mona-chat-panel {
		width: calc(100vw - 2rem);
		right: 0;
	}
	.mona-chat-trigger-text { display: none; }
	.mona-chat-trigger { padding: .85rem; }
}

/* ---------- Typing indicator (popup, before greeting on first open) ---------- */
.mona-chat-typing {
	display: none;
	align-items: center;
	gap: 4px;
	padding: 0 0 .75rem;
	margin-bottom: .25rem;
}
.mona-chat-typing span {
	width: 6px;
	height: 6px;
	border-radius: 50%;
	background: var(--muted-2);
	animation: mona-chat-typing-bounce 1s ease-in-out infinite;
}
.mona-chat-typing span:nth-child(2) { animation-delay: .15s; }
.mona-chat-typing span:nth-child(3) { animation-delay: .3s; }
@keyframes mona-chat-typing-bounce {
	0%, 60%, 100% { opacity: .35; transform: translateY(0); }
	30%           { opacity: 1;   transform: translateY(-4px); }
}
.mona-chat.is-typing .mona-chat-typing { display: inline-flex; }
.mona-chat.is-typing .mona-chat-greeting,
.mona-chat.is-typing .mona-chat-prompts,
.mona-chat.is-typing .mona-chat-actions,
.mona-chat.is-typing .mona-chat-foot {
	opacity: 0;
	pointer-events: none;
}
.mona-chat.is-greeted .mona-chat-greeting,
.mona-chat.is-greeted .mona-chat-prompts,
.mona-chat.is-greeted .mona-chat-actions,
.mona-chat.is-greeted .mona-chat-foot {
	animation: mona-chat-fade-in .35s var(--ease) forwards;
}
.mona-chat.is-greeted .mona-chat-prompts { animation-delay: .08s; }
.mona-chat.is-greeted .mona-chat-actions { animation-delay: .16s; }
.mona-chat.is-greeted .mona-chat-foot    { animation-delay: .24s; }
@keyframes mona-chat-fade-in {
	from { opacity: 0; transform: translateY(4px); }
	to   { opacity: 1; transform: translateY(0); }
}

/* Context prompt highlight — the auto-injected "about [project]" pill
 * gets a subtle accent so users see it's pre-selected. */
.mona-chat-prompts .is-context {
	background: rgba(27, 191, 186, .12);
	border-color: rgba(27, 191, 186, .35);
	color: var(--accent-deep);
}

/* Keyboard hint in the foot — `c` styled as a key cap */
.mona-chat-foot kbd {
	display: inline-block;
	padding: 0 .35em;
	background: rgba(20, 22, 22, .06);
	border: 1px solid var(--hairline);
	border-radius: 4px;
	font-family: var(--font-mono);
	font-size: .9em;
	line-height: 1.4;
	color: var(--ink);
}
body.dark .mona-chat-foot kbd {
	background: rgba(245, 245, 244, .08);
	border-color: rgba(245, 245, 244, .15);
}

/* ---------- Inline chat panel on /contact/ ----------
 * Same component, no popup chrome. Sits inside .ct-left below the
 * contact-block, gives users a real chat-style alternative to the form. */
.ct-chat {
	margin-top: clamp(2rem, 5vw, 3rem);
	max-width: 480px;
}
.ct-chat-tabs {
	position: relative;
	display: flex;
	align-items: center;
	margin-bottom: 1.25rem;
}
.ct-chat-divider {
	flex: 1;
	height: 1px;
	background: var(--hairline);
}
.ct-chat-or {
	margin-left: 1rem;
	font-family: var(--font-mono);
	font-size: .68rem;
	letter-spacing: .12em;
	text-transform: uppercase;
	color: var(--muted);
	white-space: nowrap;
	padding-right: .5rem;
	background: var(--bg);
}
.mona-chat-panel--inline {
	position: static;
	width: 100%;
	max-width: 100%;
	background: rgba(20, 22, 22, .03);
	border: 1px solid var(--hairline);
	border-radius: 14px;
	padding: 1.5rem;
	box-shadow: none;
	animation: none;
}
body.dark .mona-chat-panel--inline {
	background: rgba(245, 245, 244, .03);
	border-color: rgba(245, 245, 244, .08);
}

/* Hide the typing indicator on the inline version (always shows greeting). */
.mona-chat-panel--inline .mona-chat-typing { display: none !important; }

@media (prefers-reduced-motion: reduce) {
	.mona-chat-pulse .mona-chat-trigger::after,
	.mona-chat-dot { animation: none; }
	.mona-chat-panel { animation: none; }
}

/* ---------- Footer colophon link ----------
 * Lighthouse flagged the previous .35 alpha (≈ #5e5e5e on #0c0d0d
 * dark footer) as 3.0 contrast — fails WCAG AA (4.5:1 needed for
 * normal text). Bumped to .8 alpha = ≈ #c4c4c4, contrast 11.5:1. */
.foot-credits-link {
	color: rgba(245, 245, 244, .8) !important;
	font-family: var(--font-mono);
	font-size: .68rem;
	letter-spacing: .08em;
	text-transform: lowercase;
	transition: color .25s var(--ease);
}
.foot-credits-link:hover {
	color: var(--accent) !important;
}

/* ---------- Anglesey fog (404 page) ----------
 * Subtle moving fog effect behind the 404 hero. Two layered radial
 * gradients drift in opposite directions — gives the "lost in the fog"
 * idiom a literal visual cue without being heavy-handed. Pure CSS. */
.sec-404 {
	position: relative;
	isolation: isolate;
	overflow: hidden;
}
.sec-404::before,
.sec-404::after {
	content: "";
	position: absolute;
	inset: -10%;
	z-index: -1;
	pointer-events: none;
	background: radial-gradient(
		ellipse 60% 40% at 30% 30%,
		rgba(245, 245, 244, .04) 0%,
		transparent 65%
	);
	animation: mona-fog-drift-a 22s ease-in-out infinite alternate;
}
.sec-404::after {
	background: radial-gradient(
		ellipse 50% 35% at 70% 70%,
		rgba(27, 191, 186, .035) 0%,
		transparent 70%
	);
	animation: mona-fog-drift-b 28s ease-in-out infinite alternate-reverse;
}
@keyframes mona-fog-drift-a {
	from { transform: translate(0, 0)      scale(1); }
	to   { transform: translate(8%, -4%)   scale(1.08); }
}
@keyframes mona-fog-drift-b {
	from { transform: translate(0, 0)      scale(1.05); }
	to   { transform: translate(-6%, 5%)   scale(.95); }
}
body:not(.dark) .sec-404::before {
	background: radial-gradient(ellipse 60% 40% at 30% 30%, rgba(20, 22, 22, .045) 0%, transparent 65%);
}
@media (prefers-reduced-motion: reduce) {
	.sec-404::before,
	.sec-404::after { animation: none; }
}

/* ---------- Portfolio card hover: cinematic stack ----------
 * Cards with no loop-video used to sit still on hover. This block adds
 * a layered hover animation that's properly cinematic without being
 * distracting. Five effects layered:
 *
 *   1. Varied Ken Burns — every 4th card pans in a different direction
 *      (top-left, top-right, bottom-right, bottom-left) so a grid of
 *      cards looks alive instead of synchronised.
 *   2. Parallax — title + meta UI pop forward slightly faster than the
 *      image zooms, creating depth.
 *   3. Crossfade slideshow — if there are 2-3 frames, they cross-dissolve
 *      with a tiny scale on each frame so the transitions feel filmed,
 *      not flipbook.
 *   4. Teal gradient sweep — a soft accent gradient wipes diagonally
 *      across the card on hover-in, then settles.
 *   5. Title rise — the card title slides up by a few pixels and gains
 *      a subtle text-shadow accent.
 *
 * Animations only run on hover/focus, so cards are calm at rest.
 * Vertical covers (.is-vertical-cover) get object-position: top to keep
 * heads/subjects visible — the full filter logic is in portfolio-card.php.
 * --------------------------------------------------------------- */
.seas-cover-stack {
	position: absolute;
	inset: 0;
	overflow: hidden;
	transform-origin: center center;
	will-change: transform;
}
.seas-cover-stack .cover-frame {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: center 38%; /* slightly above centre — favours subject heads when cropping */
	opacity: 0;
	transform: scale(1);
	transition: opacity 1s cubic-bezier(.4, 0, .2, 1), transform 1.6s cubic-bezier(.16, 1, .3, 1);
	will-change: opacity, transform;
}
.seas-cover-stack .cover-frame.is-frame-0 {
	opacity: 1;
}

/* Vertical cover safeguard — when the featured image is portrait,
 * crop to the top of the frame so heads/shoulders stay visible
 * instead of zooming into torsos. */
.seas-cover-stack.is-vertical-cover .cover-frame {
	object-position: center 18%;
}

/* ---------- 1. Varied Ken Burns per card position ---------- */
.seas-card:hover .seas-cover-stack,
.seas-card:focus-within .seas-cover-stack {
	animation: mona-kb-tl 9s ease-in-out infinite alternate;
}
.seas-card:nth-child(4n+2):hover .seas-cover-stack,
.seas-card:nth-child(4n+2):focus-within .seas-cover-stack {
	animation-name: mona-kb-tr;
}
.seas-card:nth-child(4n+3):hover .seas-cover-stack,
.seas-card:nth-child(4n+3):focus-within .seas-cover-stack {
	animation-name: mona-kb-br;
}
.seas-card:nth-child(4n):hover .seas-cover-stack,
.seas-card:nth-child(4n):focus-within .seas-cover-stack {
	animation-name: mona-kb-bl;
}
@keyframes mona-kb-tl {
	from { transform: scale(1)     translate(0, 0); }
	to   { transform: scale(1.11)  translate(-2.5%, -1.8%); }
}
@keyframes mona-kb-tr {
	from { transform: scale(1)     translate(0, 0); }
	to   { transform: scale(1.11)  translate(2.5%, -1.8%); }
}
@keyframes mona-kb-br {
	from { transform: scale(1)     translate(0, 0); }
	to   { transform: scale(1.11)  translate(2.5%, 1.8%); }
}
@keyframes mona-kb-bl {
	from { transform: scale(1)     translate(0, 0); }
	to   { transform: scale(1.11)  translate(-2.5%, 1.8%); }
}

/* ---------- 2. Parallax — title/meta float forward ---------- */
.seas-card .seas-inner {
	transition: transform .6s cubic-bezier(.16, 1, .3, 1);
}
.seas-card:hover .seas-inner,
.seas-card:focus-within .seas-inner {
	transform: translateZ(0) scale(1.02);
}

/* ---------- 3. Slideshow with per-frame scale ---------- */
.seas-card:hover .seas-cover-stack[data-frames="2"] .cover-frame,
.seas-card:focus-within .seas-cover-stack[data-frames="2"] .cover-frame {
	animation: mona-frame-cycle-2 6s ease-in-out infinite;
}
.seas-card:hover .seas-cover-stack[data-frames="2"] .is-frame-1,
.seas-card:focus-within .seas-cover-stack[data-frames="2"] .is-frame-1 {
	animation-delay: -3s;
}
@keyframes mona-frame-cycle-2 {
	0%, 30%  { opacity: 1; }
	50%, 80% { opacity: 0; }
	100%     { opacity: 1; }
}

.seas-card:hover .seas-cover-stack[data-frames="3"] .cover-frame,
.seas-card:focus-within .seas-cover-stack[data-frames="3"] .cover-frame {
	animation: mona-frame-cycle-3 8s ease-in-out infinite;
}
.seas-card:hover .seas-cover-stack[data-frames="3"] .is-frame-1,
.seas-card:focus-within .seas-cover-stack[data-frames="3"] .is-frame-1 {
	animation-delay: -2.66s;
}
.seas-card:hover .seas-cover-stack[data-frames="3"] .is-frame-2,
.seas-card:focus-within .seas-cover-stack[data-frames="3"] .is-frame-2 {
	animation-delay: -5.33s;
}
@keyframes mona-frame-cycle-3 {
	0%, 20%   { opacity: 1; }
	33%, 87%  { opacity: 0; }
	100%      { opacity: 1; }
}

/* ---------- 4. (Diagonal teal sweep removed — felt too "hover effect", didn't match the editorial feel) ---------- */

/* ---------- 5. Title rise + arrow energy ---------- */
.seas-card .seas-top {
	transition: transform .55s cubic-bezier(.16, 1, .3, 1), letter-spacing .55s ease;
}
.seas-card:hover .seas-top,
.seas-card:focus-within .seas-top {
	transform: translateY(-3px);
	letter-spacing: -0.005em;
}
.seas-card .seas-bot {
	transition: opacity .5s ease, transform .55s cubic-bezier(.16, 1, .3, 1);
}
.seas-card:hover .seas-bot,
.seas-card:focus-within .seas-bot {
	transform: translateY(-2px);
}

/* ---------- 6. Card lift — subtle shadow + 1° rotation ---------- */
.seas-card {
	transition: transform .55s cubic-bezier(.16, 1, .3, 1), box-shadow .5s ease;
}
.seas-card:hover,
.seas-card:focus-within {
	transform: translateY(-4px);
	box-shadow:
		0 18px 38px -14px rgba(20, 22, 22, .35),
		0 6px 14px -6px rgba(20, 22, 22, .25);
}
body.dark .seas-card:hover,
body.dark .seas-card:focus-within {
	box-shadow:
		0 22px 42px -14px rgba(0, 0, 0, .65),
		0 8px 18px -6px rgba(0, 0, 0, .45);
}

/* Reduced motion — strip every animation, leave only a subtle lift. */
@media (prefers-reduced-motion: reduce) {
	.seas-card:hover .seas-cover-stack,
	.seas-card:focus-within .seas-cover-stack,
	.seas-card:hover .seas-cover-stack[data-frames] .cover-frame,
	.seas-card:focus-within .seas-cover-stack[data-frames] .cover-frame,
	.seas-card .seas-cover-stack::after {
		animation: none !important;
		opacity: revert;
	}
	.seas-card .cover-frame.is-frame-0 { opacity: 1; }
	.seas-card .cover-frame:not(.is-frame-0) { opacity: 0; }
	.seas-card:hover,
	.seas-card:focus-within {
		transform: none;
	}
}

/* ---------- Language switch curtain ----------
 * Full-screen overlay shown during a / ↔ /cy/ navigation. The browser
 * actually navigates underneath while this sits on top; the slide-up
 * + slide-out animation makes a normal page reload feel deliberate.
 *
 * Sequence:
 *   1. User clicks lang button → curtain slides UP from below (.is-leaving)
 *   2. After ~420ms, JS navigates → curtain disappears with the old page
 *   3. New page paints with curtain already covering (.is-incoming) —
 *      synchronous head script prevents any flash
 *   4. After a brief hold, curtain slides UP off the top (.is-exiting)
 *   5. New page is revealed
 *
 * Total ≈ 1100ms with a 200ms hold in the middle.
 * --------------------------------------------- */
.lang-curtain {
	position: fixed;
	inset: 0;
	z-index: 10001; /* above splash (9999) and lightbox (10000) */
	background: var(--ink); /* near-black in both modes — confident, not noisy */
	color: var(--bg);
	display: none;
	align-items: center;
	justify-content: center;
	pointer-events: none;
	overflow: hidden;
	will-change: transform;
}
.lang-curtain.is-active {
	display: flex;
}

/* Going OUT — slides up from below to cover the screen. */
.lang-curtain.is-leaving {
	animation: lang-curtain-up 0.42s cubic-bezier(0.7, 0, 0.2, 1) forwards;
}

/* Incoming — paints already covering (no animation), then slides up off top. */
.lang-curtain.is-incoming {
	transform: translateY(0);
}
.lang-curtain.is-exiting {
	animation: lang-curtain-off 0.6s cubic-bezier(0.7, 0, 0.2, 1) forwards;
}

@keyframes lang-curtain-up {
	from { transform: translateY(100%); }
	to   { transform: translateY(0);    }
}
@keyframes lang-curtain-off {
	from { transform: translateY(0);     }
	to   { transform: translateY(-101%); }
}

.lang-curtain-inner {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 1.25rem;
	text-align: center;
	padding: 0 var(--gutter);
}
.lang-curtain-eyebrow {
	font-family: var(--font-mono);
	font-size: 0.78rem;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	color: var(--accent);
	opacity: 0;
	animation: lang-curtain-eyebrow 0.5s 0.18s ease-out forwards;
}
.lang-curtain-label {
	font-family: var(--font-accent-serif);
	font-style: italic;
	font-weight: 300;
	font-size: clamp(3.5rem, 12vw, 9rem);
	letter-spacing: -0.04em;
	line-height: 1;
	color: var(--bg);
	opacity: 0;
	transform: translateY(0.5em);
	animation: lang-curtain-label 0.55s 0.1s cubic-bezier(0.2, 0.8, 0.2, 1) forwards;
}
.lang-curtain-rule {
	display: block;
	width: 0;
	height: 1px;
	background: var(--accent);
	animation: lang-curtain-rule 0.55s 0.32s cubic-bezier(0.7, 0, 0.2, 1) forwards;
}
.lang-curtain.is-exiting .lang-curtain-eyebrow,
.lang-curtain.is-exiting .lang-curtain-label,
.lang-curtain.is-exiting .lang-curtain-rule {
	/* During exit, freeze the contents — let the curtain itself slide. */
	animation-play-state: paused;
}

@keyframes lang-curtain-eyebrow {
	to { opacity: 1; }
}
@keyframes lang-curtain-label {
	to { opacity: 1; transform: translateY(0); }
}
@keyframes lang-curtain-rule {
	to { width: 80px; }
}

/* Reduced motion: still show, but no sliding — instant cover + instant clear. */
@media (prefers-reduced-motion: reduce) {
	.lang-curtain.is-leaving { animation: none; transform: translateY(0); }
	.lang-curtain.is-exiting { animation: none; display: none !important; }
	.lang-curtain-eyebrow,
	.lang-curtain-label,
	.lang-curtain-rule { animation: none; opacity: 1; transform: none; width: 80px; }
}

/* ---------- Public sector landing page ----------
 * All colours use theme tokens (--ink, --muted, --hairline, --accent).
 * Dark mode flips them automatically via dark-mode.css overrides.
 * ----------------------------------------------- */
.ps-credentials {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
	gap: 1.5rem;
	max-width: 1200px;
	margin: 4rem auto 6rem;
	padding: 0 var(--gutter);
	color: var(--ink);
}
.ps-cred {
	border: 1px solid var(--hairline);
	background: var(--bg);
	padding: 2rem 1.5rem;
	border-radius: 14px;
	text-align: center;
	transition: transform 0.4s ease, border-color 0.3s ease, background 0.3s ease;
}
.ps-cred:hover {
	transform: translateY(-4px);
	border-color: var(--accent);
	background: var(--bg-alt);
}
.ps-cred-num {
	font-size: clamp(1.6rem, 3vw, 2.4rem);
	font-weight: 700;
	letter-spacing: -0.02em;
	color: var(--accent);
	margin-bottom: 0.5rem;
}
.ps-cred-label {
	font-size: 0.86rem;
	letter-spacing: 0.02em;
	line-height: 1.4;
	color: var(--muted);
	text-transform: lowercase;
}

.ps-services {
	max-width: 1200px;
	margin: 6rem auto;
	padding: 0 var(--gutter);
	color: var(--ink);
}
.ps-services h2 {
	font-size: clamp(2.4rem, 5vw, 4rem);
	margin-bottom: 3rem;
	color: var(--ink);
}
.ps-grid {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
	gap: 2.5rem;
}
.ps-grid > div {
	border-top: 1px solid var(--hairline);
	padding-top: 1.5rem;
}
.ps-grid h3 {
	font-size: 1.3rem;
	margin-bottom: 1rem;
	letter-spacing: -0.01em;
	color: var(--ink);
}
.ps-grid p {
	font-size: 0.98rem;
	line-height: 1.6;
	color: var(--muted);
}

.ps-why {
	max-width: 1000px;
	margin: 6rem auto;
	padding: 0 var(--gutter);
	color: var(--ink);
}
.ps-why h2 {
	font-size: clamp(2.4rem, 5vw, 4rem);
	margin-bottom: 3rem;
	color: var(--ink);
}
.ps-why-list {
	list-style: none;
	padding: 0;
	display: grid;
	gap: 2rem;
}
.ps-why-list li {
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
	gap: 2rem;
	padding-bottom: 2rem;
	border-bottom: 1px solid var(--hairline);
}
.ps-why-list li:last-child {
	border-bottom: 0;
}
.ps-why-list strong {
	font-size: 1.1rem;
	letter-spacing: -0.01em;
	font-weight: 600;
	display: block;
	color: var(--ink);
}
.ps-why-list span {
	font-size: 0.98rem;
	line-height: 1.65;
	color: var(--muted);
}
@media (max-width: 720px) {
	.ps-why-list li { grid-template-columns: 1fr; gap: 0.75rem; }
}

/* ---------- Service-area pages ---------- */
.sa-hero {
	max-width: 1200px;
	margin: 4rem auto 5rem;
	padding: 0 var(--gutter);
	color: var(--ink);
}
.sa-hero h1 {
	font-size: clamp(3rem, 7vw, 5.5rem);
	letter-spacing: -0.03em;
	line-height: 1.02;
	color: var(--ink);
}
.sa-hero-media {
	margin: 2rem 0 3rem;
	border-radius: 14px;
	overflow: hidden;
	aspect-ratio: 16 / 9;
	background: var(--surface);
}
.sa-hero-media img,
.sa-hero-media video {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}
.sa-meta {
	display: flex;
	gap: 1.5rem;
	flex-wrap: wrap;
	font-size: 0.86rem;
	letter-spacing: 0.04em;
	text-transform: uppercase;
	color: var(--muted);
	margin: 1.5rem 0 2.5rem;
}
.sa-intro {
	max-width: 65ch;
	font-size: 1.15rem;
	line-height: 1.65;
	color: var(--ink);
}
.sa-intro p {
	color: var(--ink-2);
}
.sa-intro p + p {
	margin-top: 1rem;
}

.sa-list {
	max-width: 1200px;
	margin: 6rem auto;
	padding: 0 var(--gutter);
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
	gap: 2rem;
}
.sa-list a {
	display: block;
	border: 1px solid var(--hairline);
	background: var(--bg);
	padding: 2rem;
	border-radius: 14px;
	text-decoration: none;
	color: var(--ink);
	transition: transform 0.4s ease, border-color 0.3s ease, background 0.3s ease;
}
.sa-list a:hover {
	transform: translateY(-4px);
	border-color: var(--accent);
	background: var(--bg-alt);
}
.sa-list h3 {
	font-size: 1.6rem;
	letter-spacing: -0.01em;
	margin-bottom: 0.5rem;
	color: var(--ink);
}
.sa-list p {
	font-size: 0.95rem;
	line-height: 1.55;
	color: var(--muted);
}
.sa-list .sa-arrow {
	display: inline-block;
	margin-top: 1rem;
	color: var(--accent);
	font-size: 1.2rem;
}

/* ---------- Featured-work block reused on landing pages ---------- */
.lp-related {
	max-width: 1300px;
	margin: 6rem auto;
	padding: 0 var(--gutter);
	color: var(--ink);
}
.lp-related-head {
	display: flex;
	justify-content: space-between;
	align-items: baseline;
	margin-bottom: 2rem;
	gap: 1rem;
	flex-wrap: wrap;
}
.lp-related-head h2 {
	font-size: clamp(2rem, 4vw, 3rem);
	letter-spacing: -0.02em;
	color: var(--ink);
	margin: 0;
}
.lp-related-head .link-arrow {
	color: var(--accent);
}
.lp-related-grid {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
	gap: 1.5rem;
}
.lp-related-grid .seas-card {
	min-height: 320px;
}

/* ---------- Reduced motion respect ---------- */
@media (prefers-reduced-motion: reduce) {
	*,
	*::before,
	*::after {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
		scroll-behavior: auto !important;
	}
	/* Pure CSS animations also disabled */
	.has-progress-bar::before { animation: none; transform: scaleX(0); }
	::view-transition-old(root),
	::view-transition-new(root) { animation: none; }
	.marq-row { animation: none !important; }
	[data-magnetic] { transform: none !important; }
	body.dark::after { animation: none; } /* film grain — keep static texture */
	.home-hero::before,
	.sb-hero::before { animation: none !important; }
}

/* ---------- Breadcrumb buffer for the fixed nav ----------
 *
 * Originally inline in header.php as an emergency hotfix. Moved here
 * so it cache-busts properly with the rest of the stylesheet and the
 * <head> ships fewer inline bytes.
 *
 * Tightened from the original clamp(7.5rem, 10vw, 9rem) which left
 * a ~70px void between the nav and the breadcrumb on every page. The
 * new value clears the ~64-72px fixed nav with about 16-24px of
 * breathing room below it, then the breadcrumb sits.
 *
 * Background is scoped to non-sub-brand pages so the cream var(--bg)
 * doesn't paint a strip on dark Core / Boost canvases. The body.sb
 * rule in components.css handles the transparent variant. */
.mona-breadcrumbs-wrap {
	padding-top: clamp(5rem, 7vw, 6rem) !important;
	padding-bottom: 0.9rem !important;
	position: relative !important;
	z-index: 10 !important;
}
body:not(.sb) .mona-breadcrumbs-wrap {
	background: var(--bg) !important;
}
.mona-breadcrumbs-wrap + .ab-hero,
.mona-breadcrumbs-wrap + .svc-head,
.mona-breadcrumbs-wrap + .pf-head,
.mona-breadcrumbs-wrap + .ct-wrap {
	padding-top: 2.25rem !important;
}
.mona-breadcrumbs-wrap + .single-project .single-hero,
.mona-breadcrumbs-wrap + .single-hero {
	margin-top: 2rem !important;
}
@media (max-width: 768px) {
	.mona-breadcrumbs-wrap {
		padding-top: 4.75rem !important;
	}
}

/* ---------- Policy / formal-document pages — lowercase headings ----------
   Audit fix #8 (2026-05-07): /carbon-reduction-plan/, /privacy/ and similar
   long-form policy pages were Title Case in their post_content while the rest
   of the marketing pages run lowercase per brand voice. Forcing lowercase via
   text-transform keeps the visible UI consistent without requiring a content
   edit on every paragraph in the database. Proper nouns inside the post body
   that should stay capitalised get a `<span class="cap-keep">` wrapper.
   Page IDs targeted explicitly to avoid blanket-lowercasing every page.        */
body.page-id-497 .post-content h1,
body.page-id-497 .post-content h2,
body.page-id-497 .post-content h3,
body.page-id-497 .entry-content h1,
body.page-id-497 .entry-content h2,
body.page-id-497 .entry-content h3,
body.page-id-497 article h1,
body.page-id-497 article h2,
body.page-id-497 article h3 {
	text-transform: lowercase;
}
body.page-id-497 .post-content h1 .cap-keep,
body.page-id-497 .post-content h2 .cap-keep,
body.page-id-497 .post-content h3 .cap-keep,
body.page-id-497 .entry-content h1 .cap-keep,
body.page-id-497 .entry-content h2 .cap-keep,
body.page-id-497 .entry-content h3 .cap-keep {
	text-transform: none;
}
