/*
Theme Name: PingNetwork
Theme URI: https://boomlive.in
Author: PingNetwork
Author URI: https://boomlive.in
Description: Custom block theme for PingNetwork. Design system ported from the PingNetwork Nuxt front-end — Figtree, brand blue/orange palette, and a fluid type scale. Built to run in Docker and deploy on Coolify.
Requires at least: 6.7
Tested up to: 7.0
Requires PHP: 8.0
Version: 0.1.0
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: pingnetwork
Tags: full-site-editing, block-patterns, block-styles, translation-ready, wide-blocks, accessibility-ready
*/

/* The design system lives in theme.json. Keep only progressive enhancements here. */

:where(pre) {
	overflow-x: auto;
}

h1, h2, h3, h4, h5, h6, blockquote, caption, figcaption, p {
	text-wrap: pretty;
}

/* ─── Header (ported from BlockSiteNav) ───────────────────────────────────
   Desktop: logo · inline nav · Subscribe + Join pill. Tablet/mobile (≤1199px):
   collapses to a left drawer toggled by the hamburger (assets/js/nav.js). */
:root {
	--pn-header-h: 100px;

	/* HERO HEIGHT — one token for every full-screen hero (.mh, .aip-hero).
	   Read it as: never shorter than 480px, never taller than 820px, and in
	   between just follow the window. The CEILING is the point: a plain
	   `100vh` hero turns into a huge empty band on a 4K screen or a zoomed-out
	   window, because the type stops growing (font sizes clamp out) while the
	   band keeps stretching. `svh` (small viewport height) keeps it steady while
	   a phone's browser bars slide away, instead of the band jumping mid-scroll.
	   It's a MIN-height, so a hero with more content than this still grows. */
	--pn-hero-h: clamp(480px, calc(100svh - var(--pn-header-h)), 820px);

	/* Pill CTAs. The font is one token everywhere; the two PADDING vars are
	   deliberately LEFT UNSET here, so on desktop each button falls back to its own
	   padding (a card CTA is narrower than a hero CTA). The queries below DEFINE
	   them for tablet/phone, which is what snaps every pill to one compact size.
	   Spec: _RESPONSIVE-SYSTEM.md §6. */
	--pn-pill-font: calc(var(--wp--preset--font-size--sm) + 1px); /* 17px */

	/* Hamburger icon as a mask — see .navbar-toggler::before for why not an <svg>. */
	--pn-burger: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6h16M4 12h16m-7 6h7'/%3E%3C/svg%3E");
}

/* The ONLY queries that redefine tokens. Order matters: 480 comes after 1024 so it
   wins on small phones. Spec: _RESPONSIVE-SYSTEM.md §2. */
@media (max-width: 1024px) {
	:root {
		--pn-pill-pad-y: 8px;
		--pn-pill-pad-x: 28px;
	}
}
@media (max-width: 768px) {
	:root {
		--pn-header-h: 68px;
	}
}
@media (max-width: 480px) {
	:root {
		--pn-pill-pad-y: 6px;
		--pn-pill-pad-x: 20px;
		--pn-pill-font: 15px;
	}
}
/* STICKY: the sticky must sit on the template-part wrapper, not on .site-header
   itself. A sticky element can only travel inside its own parent's box, and
   .site-header's parent <header class="wp-block-template-part"> is exactly one
   header tall — so it had nowhere to travel and never stuck. The wrapper's
   parent is .wp-site-blocks (full page height), which gives it the room. */
.wp-site-blocks > header.wp-block-template-part {
	position: sticky;
	top: 0;
	z-index: 1000;
}
/* Logged-in admins: sit below the fixed admin bar instead of under it. */
.admin-bar .wp-site-blocks > header.wp-block-template-part {
	top: var(--wp-admin--admin-bar--height, 32px);
}
@media screen and (max-width: 782px) {
	/* WP's admin bar stops being fixed here, so the header goes back to top: 0. */
	.admin-bar .wp-site-blocks > header.wp-block-template-part {
		top: 0;
	}
}
.site-header {
	background: var(--wp--preset--color--surface);
	border-bottom: 1px solid var(--wp--preset--color--border);
	height: var(--pn-header-h);
}
.nav-row {
	display: grid;
	grid-template-columns: 1fr auto 1fr;
	align-items: center;
	height: 100%;
	gap: var(--wp--preset--spacing--7);
}
.navbar-brand {
	grid-column: 1;
	justify-self: start;
	display: inline-flex;
	align-items: center;
	line-height: 0;
	flex-shrink: 0;
}
.site-logo-img {
	height: 48px;
	width: auto;
	max-width: none;
}
.navbar-collapse {
	grid-column: 2;
	display: flex;
	justify-content: center;
}
/* The menu is a core Navigation block with overlayMenu:"never", so it renders a
   plain <nav><ul class="wp-block-navigation__container"> — no core hamburger,
   no core modal. We style that list into the old .navbar-nav look, and our own
   drawer below takes over on tablet/mobile. Selectors carry an extra element or
   class so they beat core's own .wp-block-navigation rules whatever the
   stylesheet order ends up being. */
.site-header .wp-block-navigation {
	flex-grow: 0;
}
.site-header ul.wp-block-navigation__container {
	display: flex;
	align-items: center;
	gap: var(--wp--preset--spacing--6);
	list-style: none;
	padding: 0;
	margin: 0;
}
.site-header .wp-block-navigation-item {
	position: relative;
}
.nav-item-mobile-only {
	display: none;
}
.site-header .wp-block-navigation a.wp-block-navigation-item__content {
	color: var(--wp--preset--color--text);
	font-weight: 700;
	font-size: var(--wp--preset--font-size--sm);
	padding: var(--wp--preset--spacing--2) 0;
	text-decoration: none;
	display: inline-flex;
	align-items: center;
	transition: color 0.2s;
}
.site-header .wp-block-navigation a.wp-block-navigation-item__content:hover,
.site-header .wp-block-navigation a.wp-block-navigation-item__content:focus,
.site-header .wp-block-navigation-item.current-menu-item > a.wp-block-navigation-item__content,
.site-header .wp-block-navigation a.wp-block-navigation-item__content.is-active {
	color: var(--wp--preset--color--accent);
}
.header-actions {
	grid-column: 3;
	justify-self: end;
	display: flex;
	align-items: center;
	gap: var(--wp--preset--spacing--6);
	flex-shrink: 0;
}
.btn-signin {
	background: var(--wp--preset--color--accent);
	color: #fff;
	font-size: var(--pn-pill-font);
	border: none;
	cursor: pointer;
	padding: var(--pn-pill-pad-y, 11px) var(--pn-pill-pad-x, 28px);
	border-radius: 999px;
	white-space: nowrap;
	text-decoration: none;
	display: inline-flex;
	align-items: center;
	transition: background 0.2s;
}
.btn-signin:hover {
	background: #e0532f;
	color: #fff;
}
.navbar-toggler {
	background: none;
	border: none;
	color: var(--wp--preset--color--text);
	padding: 4px;
	min-width: 44px;
	min-height: 44px;
	align-items: center;
	justify-content: center;
	cursor: pointer;
	transition: color 0.2s;
	display: none;
}
.navbar-toggler:hover {
	color: var(--wp--preset--color--accent);
}
/* The hamburger is drawn in CSS, not as inline <svg>. It has to be: the header is
   a template part, and the moment it is saved in the Site Editor KSES strips <svg>
   from the stored copy (the same rule that forces curves through [pn_curve]) — which
   had already happened, leaving an EMPTY 44x44 button on every screen below 1199px.
   A mask survives that, because it lives in the stylesheet. */
.navbar-toggler::before {
	content: "";
	width: 24px;
	height: 24px;
	background: currentColor;
	-webkit-mask: var(--pn-burger) center / contain no-repeat;
	mask: var(--pn-burger) center / contain no-repeat;
}
.nav-backdrop {
	display: none;
}

/* Tablet + mobile: the left drawer */
@media (max-width: 1199px) {
	.navbar-toggler {
		display: inline-flex;
	}
	.btn-join-desktop {
		display: none;
	}
	.nav-item-mobile-only {
		display: block;
	}
	.nav-row {
		grid-template-columns: auto 1fr;
		gap: var(--wp--preset--spacing--4);
	}
	.header-actions {
		grid-column: 2;
		gap: var(--wp--preset--spacing--4);
	}
	.navbar-collapse {
		display: block;
		position: fixed;
		top: var(--pn-header-h);
		bottom: 0;
		left: 0;
		max-width: 85vw;
		background: var(--wp--preset--color--background);
		z-index: 999;
		border-right: 1px solid rgba(15, 45, 150, 0.1);
		box-shadow: 4px 0 24px rgba(15, 45, 150, 0.12);
		padding: var(--wp--preset--spacing--5);
		overflow-y: auto;
		transform: translateX(-100%);
		transition: transform 0.35s cubic-bezier(0.22, 0.61, 0.36, 1);
		pointer-events: none;
	}
	.site-header.nav-open .navbar-collapse {
		transform: none;
		pointer-events: auto;
	}
	.nav-backdrop {
		display: block;
		position: fixed;
		top: var(--pn-header-h);
		right: 0;
		bottom: 0;
		left: 0;
		background: rgba(10, 26, 92, 0.45);
		z-index: 998;
		opacity: 0;
		pointer-events: none;
		transition: opacity 0.35s cubic-bezier(0.22, 0.61, 0.36, 1);
	}
	.site-header.nav-open .nav-backdrop {
		opacity: 1;
		pointer-events: auto;
	}
	/* Core lays the <nav> out as a flex box, which shrinks the <ul> to the width
	   of its longest label. In the drawer we want the list to fill the panel so
	   each item's separator line runs edge to edge — so drop back to block. */
	.site-header .wp-block-navigation {
		display: block;
	}
	.site-header ul.wp-block-navigation__container {
		flex-direction: column;
		gap: 0;
		align-items: stretch;
	}
	.site-header .wp-block-navigation-item {
		border-bottom: 1px solid rgba(15, 45, 150, 0.08);
	}
	.site-header .wp-block-navigation a.wp-block-navigation-item__content {
		padding: var(--wp--preset--spacing--3) 0;
		width: 100%;
		text-align: left;
	}
	.nav-item-signin {
		border-bottom: none;
		margin-bottom: var(--wp--preset--spacing--2);
	}
	.nav-item-signin .btn-signin {
		display: inline-flex;
	}
}
@media (max-width: 768px) {
	.site-logo-img {
		height: 34px;
	}
}
/* Lock page scroll while the drawer is open. */
body:has(.site-header.nav-open) {
	overflow: hidden;
}

/* ─── Footer ──────────────────────────────────────────────────────────────
   Ported from the Nuxt BlockFooterColumns / BlockFooterBottom. The preset
   spacing vars mirror the design's --space-* scale 1:1. */

/* Footer background. Kept here rather than on the block so a page-level rule
   can override it without !important (a block colour renders as an inline
   style, which no stylesheet can beat). The `pn-page-<slug>` body class comes
   from pingnetwork_body_class() in functions.php. */
.site-footer {
	background-color: #4295f8;
}
.pn-page-about .site-footer,
.pn-page-ping-shield .site-footer {
	background-color: #052d96;
}

.site-footer .footer-cols {
	display: grid;
	grid-template-columns: 1.75fr 1.75fr minmax(190px, 1fr) auto;
	column-gap: var(--wp--preset--spacing--9);
	row-gap: var(--wp--preset--spacing--7);
	align-items: start;
}
.site-footer .footer-col {
	min-width: 0;
}
.site-footer .footer-logo {
	display: block;
	width: 137px;
	height: 62px;
	margin-bottom: var(--wp--preset--spacing--5);
}
.site-footer .footer-about {
	color: #fff;
	font-size: var(--wp--preset--font-size--sm);
	line-height: 1.55;
	margin: 0;
}
.site-footer .footer-heading {
	color: #fff;
	font-weight: 700;
	font-size: var(--wp--preset--font-size--md);
	line-height: 1.15;
	margin: 0 0 var(--wp--preset--spacing--4);
}
.site-footer .footer-contact-company,
.site-footer .footer-contact-address,
.site-footer .footer-cv-label {
	color: #fff;
	font-size: var(--wp--preset--font-size--sm);
	line-height: 1.55;
	margin: 0 0 var(--wp--preset--spacing--1);
}
.site-footer .footer-contact-address {
	margin-bottom: var(--wp--preset--spacing--3);
}
.site-footer .footer-contact-link {
	color: #fff;
	font-size: var(--wp--preset--font-size--sm);
	text-decoration: underline;
	display: inline-block;
	margin-bottom: var(--wp--preset--spacing--4);
	transition: color 0.2s;
}
.site-footer .footer-contact-link:hover {
	color: var(--wp--preset--color--accent);
}
/* Quick Links is a core Navigation block (className "footer-links", so the class
   lands on its <nav>). Core lays the list out as a flex ROW — force it back to a
   stacked column and restore the old link look. */
.site-footer .footer-links ul.wp-block-navigation__container {
	display: block;
	list-style: none;
	padding: 0;
	margin: 0;
}
.site-footer .footer-links .wp-block-navigation-item {
	display: block;
	margin-bottom: var(--wp--preset--spacing--2);
}
.site-footer .footer-links a.wp-block-navigation-item__content {
	color: #fff;
	font-size: var(--wp--preset--font-size--sm);
	line-height: 1.55;
	text-decoration: none;
	transition: color 0.2s;
}
.site-footer .footer-links a.wp-block-navigation-item__content:hover,
.site-footer .footer-links a.wp-block-navigation-item__content:focus {
	color: var(--wp--preset--color--accent);
}
.site-footer .footer-social-row {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--wp--preset--spacing--4);
	margin-top: var(--wp--preset--spacing--7);
}
.site-footer .social-icon {
	color: #fff;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	transition: color 0.2s;
}
.site-footer .social-icon:hover {
	color: var(--wp--preset--color--accent);
}
.site-footer .icon-social {
	width: 18px;
	height: 18px;
	display: block;
}
.site-footer .footer-col-pmark {
	align-self: center;
	display: flex;
	justify-content: flex-end;
}
.site-footer .footer-pmark {
	width: 188px;
	height: auto;
}
@media (max-width: 1024px) {
	.site-footer .footer-cols {
		grid-template-columns: 1fr 1fr;
	}
	.site-footer .footer-col-brand {
		grid-column: 1 / -1;
	}
	.site-footer .footer-col-pmark {
		display: none;
	}
}
@media (max-width: 768px) {
	.site-footer .footer-cols {
		grid-template-columns: 1fr;
	}
	.site-footer .footer-col {
		max-width: 420px;
	}
}

/* ─── Home hero (marketing-hero) ──────────────────────────────────────────
   Sky-blue band. The decorative white curve is JS-driven in the Nuxt theme,
   so it's deferred here (static v1); the band is sized to its content. */
.mh {
	position: relative;
	overflow: hidden;
	display: flex;
	min-height: var(--pn-hero-h);
	/* SITE-WIDE FIRST-SECTION SPACING. Every page's first band starts its content
	   the same distance below the header, and that distance is this one value.
	   The block writes its own padding inline, so this has to be !important to
	   win — nothing else on the site can beat an inline style. */
	padding-block: var(--wp--preset--spacing--section) !important;
}
.mh > .mh-inner {
	position: relative;
	z-index: 1;
	width: 100%;
	/* WP's blockGap would add 24px here (the inner is the curve's sibling), which
	   pushed the heading past the padding and broke the shared spacing above. */
	margin-block-start: 0;
}
@media (max-width: 1024px) {
	.mh {
		min-height: 60svh;
	}
}
.mh-heading {
	max-width: 760px;
	color: #fff;
}
.mh-subtext {
	max-width: 600px;
	color: #fff;
}
.mh-ctas .wp-block-button__link {
	padding: var(--pn-pill-pad-y, 11px) var(--pn-pill-pad-x, 52px);
	/* Without this these fell back to the core button size (16px) and were the
	   only CTAs on the site a pixel smaller than the rest. */
	font-size: var(--pn-pill-font);
}
.mh-cta--ghost .wp-block-button__link {
	background-color: #4295f8;
	border: 2px solid var(--wp--preset--color--brand-blue-light);
	color: #fff;
}
.mh-cta--ghost .wp-block-button__link:hover {
	background-color: #fff;
	color: #4295f8;
}

/* ─── Shared section container (the design's .container-custom) ───────────── */
.pn-container {
	width: min(100% - (var(--wp--custom--gutter) * 2), var(--wp--custom--container));
	margin-inline: auto;
}

/* Full-bleed sections butt flush against the header/footer — no page-background
   strip between the top-level template blocks. Sections carry their own padding. */
.wp-site-blocks > main,
.wp-site-blocks > .wp-block-template-part {
	margin-block-start: 0;
}

/* NO WHITE STRIPS BETWEEN SECTIONS — site-wide, every page.
   WP's blockGap puts a 24px margin between sibling blocks, which let the cream
   page background show as a strip between full-bleed bands. Every band is an
   `alignfull` group carrying its own padding, so zero the gap for all of them
   wherever they live (page content, template, or nested band wrapper).
   `.alignfull` is 0,1,0 and beats WP's `:where()`-only gap rule (0,0,0). */
.wp-block-post-content > .alignfull,
main.wp-block-group > .alignfull,
.wp-site-blocks > .alignfull,
.alignfull > .alignfull {
	margin-block: 0;
}
/* The section classes too, for bands that aren't `alignfull` (e.g. a plain
   wrapper) or that sit inside another layout. */
.mh,
.sc,
.ai,
.bls,
.impact,
.wp-sec,
.sg,
.fq,
.about-band,
.sh,
.hw,
.sm,
.sc-band,
.ss,
.si,
.shcta,
.kh,
.cs,
.kc {
	margin-block: 0;
}

/* ─── Home: Services Cards ────────────────────────────────────────────────
   Ported from BlockServicesCards. Light-blue band, navy cards, orange pills. */
.sc {
	background: var(--wp--preset--color--brand-blue-light);
	padding: var(--wp--preset--spacing--section) 0;
}
.sc-title {
	color: var(--wp--preset--color--text);
	text-align: center;
	font-size: var(--wp--preset--font-size--xl);
	font-weight: 600;
	line-height: 1.15;
	margin: 0 0 var(--wp--preset--spacing--8);
}
/* A SCROLL TRACK, not a grid: there are more services than fit on a screen, so
   the row runs off to the right and the reader swipes, scrolls or uses the dots.
   `--sc-per-view` is the only number to tune — the trailing .1 is the sliver of
   the next card that shows there is more to come. */
.sc-grid {
	--card-lift: 4px;
	--sc-per-view: 3.1;
	--sc-gap: var(--wp--preset--spacing--6);
	display: flex;
	gap: var(--sc-gap);
	overflow-x: auto;
	scroll-snap-type: x mandatory;
	/* Keeps a swipe that runs past the last card from scrolling the page/history. */
	overscroll-behavior-x: contain;
	list-style: none;
	/* The hover lift moves a card 4px UP, and `overflow-x` makes the other axis
	   scrollable too — without this room the lift would be clipped. */
	margin: calc(var(--card-lift) * -1) 0 0;
	padding: var(--card-lift) 0 0;
	/* The dots are the control; the native bar would just sit under the cards. */
	scrollbar-width: none;
	-ms-overflow-style: none;
}
.sc-grid::-webkit-scrollbar {
	display: none;
}
.sc-card {
	/* n cards + the gaps between them fill the track exactly. */
	/* 3 whole cards + the 3 gaps between them + the 0.1 sliver of the next one
	   fill the track exactly. The gap count is floor(per-view), which is always
	   per-view minus the trailing .1. */
	flex: 0 0 calc((100% - (var(--sc-per-view) - 0.1) * var(--sc-gap)) / var(--sc-per-view));
	scroll-snap-align: start;
	position: relative;
	display: flex;
	flex-direction: column;
	gap: var(--wp--preset--spacing--6);
	background: var(--wp--preset--color--text);
	border-radius: 18px;
	padding: var(--wp--preset--spacing--6);
	transition: transform 0.35s cubic-bezier(0.22, 0.61, 0.36, 1);
}
/* Whole-card link: the real link is the card TITLE (so it reads as a link to a
   screen reader and shows a real URL), and this pseudo-element stretches its hit
   area over the entire card. A card with no linked title simply isn't clickable. */
.sc-card-title a {
	color: inherit;
	text-decoration: none;
}
.sc-card-title a::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 1;
	border-radius: inherit;
}
.sc-card-title {
	color: #fff;
	font-size: var(--wp--preset--font-size--lg);
	font-weight: 600;
	margin: 0 0 var(--wp--preset--spacing--4);
}
.sc-card-desc {
	color: #fff;
	font-size: var(--wp--preset--font-size--body);
	line-height: 1.55;
	margin: 0;
}
/* The cards have NO "Know more" button — the whole card is the link now. Any
   .sc-card-cta still sitting in a page's saved content is leftover and stays
   hidden; delete it in the editor whenever it suits. */
.sc-card .sc-card-cta {
	/* Two classes deep on purpose: WP prints its own `.wp-block-buttons-is-layout-flex
	   { display: flex }` inline in the head, AFTER this file, so a single class ties
	   on specificity and loses on order. */
	display: none;
}
/* Dots — built by services-carousel.js, one per card. Only a window of five is
   ever on show (Instagram-style): the rail slides under a fixed-width mask and
   the dots at the window's edges shrink, so ten cards don't mean ten dots. */
.sc-dots {
	--sc-dot: 8px;
	--sc-dot-gap: 6px;
	--sc-dot-window: 5;
	display: flex;
	justify-content: center;
	margin-top: var(--wp--preset--spacing--6);
}
.sc-dots[hidden] {
	display: none; /* `display: flex` would otherwise beat the hidden attribute. */
}
.sc-dots-window {
	overflow: hidden;
	width: calc(
		var(--sc-dot-window) * var(--sc-dot) +
		(var(--sc-dot-window) - 1) * var(--sc-dot-gap)
	);
}
.sc-dots-rail {
	display: flex;
	gap: var(--sc-dot-gap);
	transition: transform 0.3s ease;
}
.sc-dot {
	position: relative;
	flex: 0 0 var(--sc-dot);
	height: var(--sc-dot);
	padding: 0;
	border: 0;
	border-radius: 50%;
	background: rgba(15, 45, 150, 0.35);
	cursor: pointer;
	transform: scale(var(--sc-dot-scale, 1));
	transition: transform 0.3s ease, background 0.3s ease;
}
/* An 8px target is too small to hit — this grows the clickable area without
   changing the layout the rail's maths depends on. */
.sc-dot::before {
	content: "";
	position: absolute;
	inset: -8px;
}
.sc-dot[aria-current="true"] {
	background: var(--wp--preset--color--text);
}
@media (prefers-reduced-motion: reduce) {
	.sc-dots-rail,
	.sc-dot {
		transition: none;
	}
}
@media (max-width: 900px) {
	.sc-grid {
		--sc-per-view: 2.1;
	}
}
@media (max-width: 600px) {
	.sc-grid {
		--sc-per-view: 1.1;
	}
}

/* ─── Home: About Intro ───────────────────────────────────────────────────
   Ported from BlockAboutIntro. White band, left copy + right stat/contact.
   The decorative intro-lines curve is JS in the Nuxt theme — deferred here. */
.ai {
	position: relative;
	overflow: hidden;
	background: #fff;
	padding: var(--wp--preset--spacing--section) 0;
}
.ai-inner {
	display: grid;
	grid-template-columns: 1.5fr 1fr;
	gap: var(--wp--preset--spacing--9);
	align-items: stretch;
	min-height: 520px;
}
.ai-left {
	display: flex;
	flex-direction: column;
	justify-content: center;
}
.ai-heading {
	color: var(--wp--preset--color--text);
	font-size: var(--wp--preset--font-size--xl);
	font-weight: 700;
	line-height: 1.15;
	margin: 0 0 var(--wp--preset--spacing--5);
}
.ai-body {
	color: var(--wp--preset--color--text);
	font-size: calc(var(--wp--preset--font-size--lg) - 2px);
	font-weight: 400;
	line-height: 1.55;
	max-width: 700px;
	margin: 0 0 var(--wp--preset--spacing--6);
}
.ai-underline {
	text-decoration: underline;
	text-underline-offset: 3px;
	text-decoration-thickness: 2px;
}
.ai-cta {
	align-self: flex-start;
}
.ai-cta .wp-block-button__link {
	padding: var(--pn-pill-pad-y, 11px) var(--pn-pill-pad-x, 52px);
	font-size: var(--pn-pill-font);
}
.ai-cta .wp-block-button__link:hover {
	background: #e0532f;
}
.ai-right {
	display: flex;
	flex-direction: column;
	justify-content: space-between;
	align-items: flex-end;
	text-align: left;
}
.ai-stat {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	line-height: 1;
}
.ai-stat-value {
	color: var(--wp--preset--color--accent);
	font-size: calc(var(--wp--preset--font-size--display) + 16px);
	font-weight: 700;
	line-height: 1;
	margin: 0 0 0 -0.045em;
}
.ai-stat-label {
	color: var(--wp--preset--color--text);
	font-size: calc(var(--wp--preset--font-size--lg) - 2px);
	font-weight: 500;
	line-height: 1.3;
	max-width: 200px;
	margin: var(--wp--preset--spacing--2) 0 0;
}
.ai-contact {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: var(--wp--preset--spacing--2);
}
.ai-contact p {
	margin: 0;
}
.ai-contact a {
	color: var(--wp--preset--color--text);
	font-size: var(--wp--preset--font-size--body);
	text-decoration: underline;
	transition: color 0.2s;
}
.ai-contact a:hover {
	color: var(--wp--preset--color--accent);
}
@media (max-width: 768px) {
	.ai-inner {
		grid-template-columns: 1fr;
		gap: var(--wp--preset--spacing--7);
		min-height: 0;
	}
	.ai-right {
		align-items: flex-start;
		gap: var(--wp--preset--spacing--6);
	}
	.ai-stat-label {
		max-width: none;
	}
}

/* ─── Home: Brand Logo Strip ──────────────────────────────────────────────
   Ported from BlockBrandLogoStrip. Navy band, white-chip marquee (pure CSS;
   pauses on hover; static wrap under prefers-reduced-motion). Logos are text
   placeholders until real logo media is uploaded. */
.bls {
	background: var(--wp--preset--color--brand-blue);
	padding: var(--wp--preset--spacing--section) 0;
	overflow: hidden;
}
.bls-title {
	color: #fff;
	text-align: center;
	font-size: var(--wp--preset--font-size--xl);
	font-weight: 600;
	line-height: 1.3;
	margin: 0 0 var(--wp--preset--spacing--7);
}
/* Two editable logo galleries. Without JS (or under reduced motion) each is a
   centered, wrapped row of white logo chips. brands.js upgrades each into a
   seamless marquee: it moves the images into a .bls-track, repeats + duplicates
   them, and scrolls the track. Row 2 runs the other way; both pause on hover. */
.bls-gallery {
	justify-content: center;
	--wp--style--unstable-gallery-gap: var(--wp--preset--spacing--6);
	gap: var(--wp--preset--spacing--6);
}
.bls-gallery--row2 {
	margin-top: var(--wp--preset--spacing--6);
}
/* Marquee mode: the track is the flex row; the full-width gallery clips it. */
.bls-gallery.bls-ready {
	display: block;
	overflow: hidden;
	gap: 0;
}
.bls-track {
	display: flex;
	flex-wrap: nowrap;
	width: max-content;
	align-items: center;
	gap: var(--wp--preset--spacing--7);
	animation: bls-scroll var(--bls-duration, 40s) linear infinite;
}
.bls-track--reverse {
	animation-direction: reverse;
}
.bls-gallery.bls-ready:hover .bls-track {
	animation-play-state: paused;
}
@keyframes bls-scroll {
	from { transform: translateX(0); }
	to { transform: translateX(calc(-1 * var(--bls-shift, 50%))); }
}
@media (prefers-reduced-motion: reduce) {
	.bls-track { animation: none; }
}
/* WP guards its gallery column-width rule with a :not(#id) specificity hack, so
   plain classes can't beat `width: calc(33%…)` — !important is the clean way to
   make each chip only as wide as its logo instead of a third of the row. */
.bls--white .bls-gallery.has-nested-images .wp-block-image {
	width: auto !important;
	max-width: none !important;
	flex: 0 0 auto !important;
	margin: 0;
	background: #fff;
	border-radius: 12px;
	padding: var(--wp--preset--spacing--3) var(--wp--preset--spacing--5);
	display: flex;
	align-items: center;
}
/* WP sets the gallery img height/max-width with a :not(#id) specificity hack too,
   so pin the logo size with !important — ~40px tall, capped width, never cropped. */
.bls-gallery .wp-block-image img {
	height: 40px !important;
	width: auto !important;
	max-width: 160px !important;
	object-fit: contain;
}
@media (max-width: 768px) {
	.bls-gallery {
		--wp--style--unstable-gallery-gap: var(--wp--preset--spacing--4);
		gap: var(--wp--preset--spacing--4);
	}
	.bls-gallery--row2 {
		margin-top: var(--wp--preset--spacing--4);
	}
	.bls-track {
		gap: var(--wp--preset--spacing--5);
	}
	.bls-gallery .wp-block-image img {
		height: 30px;
	}
}

/* ─── Home: Studio Gallery ────────────────────────────────────────────────
   Ported from BlockStudioGallery. Light-blue band; two small boxes bottom-left
   + one tall box right. Navy placeholders until studio photos are uploaded. */
.sg {
	background: var(--wp--preset--color--brand-blue-light);
	padding: var(--wp--preset--spacing--section) 0;
}
.sg-grid {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: var(--wp--preset--spacing--5);
	align-items: stretch;
}
.sg-left {
	display: flex;
	flex-direction: column;
}
.sg-title {
	color: var(--wp--preset--color--text);
	text-align: left;
	font-size: var(--wp--preset--font-size--xl);
	font-weight: 700;
	line-height: 1.15;
	margin: 0 0 var(--wp--preset--spacing--5);
}
.sg-small-row {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: var(--wp--preset--spacing--5);
	margin-top: auto;
}
.sg-small {
	aspect-ratio: 185 / 220;
}
.sg-big {
	aspect-ratio: 380 / 440;
}
.sg-item {
	position: relative;
	border-radius: 20px;
	overflow: hidden;
	margin: 0;
	background: var(--wp--preset--color--text); /* navy placeholder until a photo is set */
}
/* The photo fills the FIXED box and covers it (cropping to fit) — it never
   resizes the box. position:absolute takes it out of flow so its natural size
   can't push the box or the grid row; the !important sizes beat WP's core/image
   img rules (height:auto / max-width:100%) that would otherwise let it grow. */
.sg-item img {
	position: absolute;
	inset: 0;
	width: 100% !important;
	height: 100% !important;
	max-width: none !important;
	object-fit: cover;
	display: block;
	transition: transform 0.35s cubic-bezier(0.22, 0.61, 0.36, 1);
}
.sg-item:hover img {
	transform: scale(1.04);
}
@media (max-width: 768px) {
	.sg-grid {
		grid-template-columns: 1fr;
		gap: var(--wp--preset--spacing--4);
	}
	.sg-small-row {
		gap: var(--wp--preset--spacing--4);
		margin-top: var(--wp--preset--spacing--4);
	}
	.sg-big {
		aspect-ratio: 16 / 11;
	}
}

/* ─── Home: Impact Stats ──────────────────────────────────────────────────
   Orange band, video placeholder + three big stats. (Mockup section 5.) */
.impact {
	background: var(--wp--preset--color--accent);
	padding: var(--wp--preset--spacing--section) 0;
}
.impact-video {
	width: 100%;
	aspect-ratio: 5 / 2;
	background: #4295f8;
	border-radius: 32px;
	overflow: hidden;
	margin: 0 0 var(--wp--preset--spacing--8);
}
.impact-video video {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}
.impact-grid {
	list-style: none;
	display: flex;
	justify-content: center;
	flex-wrap: wrap;
	gap: var(--wp--preset--spacing--12);
}
.impact-value {
	color: var(--wp--preset--color--text);
	font-size: calc(var(--wp--preset--font-size--display) + 16px);
	font-weight: 700;
	line-height: 1;
	margin: 0;
}
.impact-label {
	color: #fff;
	font-size: calc(var(--wp--preset--font-size--lg) - 2px);
	line-height: 1.3;
	max-width: 210px;
	margin: var(--wp--preset--spacing--3) 0 0;
}
@media (max-width: 768px) {
	.impact-video {
		aspect-ratio: 3 / 2;
		border-radius: 20px;
	}
	.impact-grid {
		display: grid;
		grid-template-columns: 1fr;
		gap: var(--wp--preset--spacing--6);
	}
	.impact-label {
		max-width: none;
	}
}

/* ─── Home: Work Preview ──────────────────────────────────────────────────
   White band, "Our Brand Work" + 3 teaser cards. (Mockup section 6.) */
.wp-sec {
	background: #fff;
	padding: var(--wp--preset--spacing--section) 0;
}
.wp-head {
	display: flex;
	justify-content: space-between;
	align-items: center;
	gap: var(--wp--preset--spacing--6);
	margin: 0 0 var(--wp--preset--spacing--4);
}
.wp-kicker {
	color: var(--wp--preset--color--text);
	font-size: calc(var(--wp--preset--font-size--xl) - 4px);
	font-weight: 700;
	line-height: 1.15;
	margin: 0;
}
.wp-more-link {
	display: inline-flex;
	align-items: center;
	gap: var(--wp--preset--spacing--2);
	white-space: nowrap;
	color: var(--wp--preset--color--text);
	font-size: var(--wp--preset--font-size--body);
	font-weight: 700;
	text-decoration: none;
	border-bottom: 2px solid currentColor;
	padding-bottom: 2px;
}
.wp-more-link:hover {
	color: var(--wp--preset--color--accent);
}
.wp-more-wrap {
	margin: 0;
}
.wp-subtitle {
	color: var(--wp--preset--color--text);
	font-size: var(--wp--preset--font-size--body);
	line-height: 1.55;
	max-width: 560px;
	margin: 0 0 var(--wp--preset--spacing--8);
}
.wp-grid {
	list-style: none;
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: var(--wp--preset--spacing--7);
}
.wp-card {
	display: flex;
	flex-direction: column;
}
.wp-thumb {
	width: 100%;
	aspect-ratio: 16 / 9;
	border-radius: 20px;
	overflow: hidden;
}
.wp-ph {
	width: 100%;
	height: 100%;
}
.wp-card-title {
	color: var(--wp--preset--color--text);
	font-size: min(var(--wp--preset--font-size--lg), 1.4rem);
	font-weight: 700;
	line-height: 1.3;
	margin: var(--wp--preset--spacing--4) 0 0;
}
@media (max-width: 900px) {
	.wp-grid {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}
@media (max-width: 768px) {
	.wp-head {
		flex-direction: column;
		align-items: flex-start;
		gap: var(--wp--preset--spacing--3);
	}
	.wp-grid {
		grid-template-columns: 1fr;
		gap: var(--wp--preset--spacing--6);
	}
}

/* ─── Home: FAQ ───────────────────────────────────────────────────────────
   White band, native <details> accordion. (Mockup section 8.) */
.fq {
	background: #fff;
	padding: var(--wp--preset--spacing--section) 0;
}
.fq-inner {
	max-width: 800px;
}
.fq-title {
	color: var(--wp--preset--color--text);
	font-size: var(--wp--preset--font-size--xl);
	font-weight: 700;
	text-align: center;
	margin: 0 0 var(--wp--preset--spacing--7);
}
.fq-list {
	counter-reset: fq;
	border-top: 1px solid rgba(15, 45, 150, 0.1);
}
.fq-item {
	border-bottom: 1px solid rgba(15, 45, 150, 0.1);
	margin: 0;
}
.fq-item > summary {
	list-style: none;
	cursor: pointer;
	display: flex;
	gap: var(--wp--preset--spacing--3);
	padding: var(--wp--preset--spacing--4) 0;
	/* flex-start, never center: a question that wraps to 2-3 lines would otherwise
	   drift the number and the +/- circle down to the middle of the block. */
	align-items: flex-start;
	color: var(--wp--preset--color--text);
	font-size: var(--wp--preset--font-size--body);
	font-weight: 500;
	line-height: 1.3;
}
.fq-item > summary::-webkit-details-marker {
	display: none;
}
.fq-item > summary::marker {
	content: '';
}
.fq-item > summary::before {
	counter-increment: fq;
	content: counter(fq, decimal-leading-zero);
	font-weight: 700;
	flex-shrink: 0;
}
.fq-item > summary::after {
	content: '';
	margin-left: auto;
	flex-shrink: 0;
	width: 28px;
	height: 28px;
	border: 1.5px solid var(--wp--preset--color--text);
	border-radius: 50%;
	background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath d='M6 0v12M0 6h12' stroke='%230f2d96' stroke-width='1.5'/%3E%3C/svg%3E") center no-repeat;
}
.fq-item[open] > summary::after {
	background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='2' viewBox='0 0 12 2'%3E%3Cpath d='M0 1h12' stroke='%230f2d96' stroke-width='1.5'/%3E%3C/svg%3E") center no-repeat;
}
.fq-a {
	color: var(--wp--preset--color--text);
	font-size: var(--wp--preset--font-size--body);
	line-height: 1.55;
	margin: 0 0 var(--wp--preset--spacing--5);
	max-width: 680px;
}

/* ─── Decorative curves (shared "swoosh" system) ──────────────────────────
   ONE weight everywhere: 130 units at the 1440px design width. non-scaling-stroke
   keeps that weight constant on screen no matter how big/tall the section is, so
   a curve is never fatter on one band and thinner on another. Below 1440 the
   weight scales down with the viewport (min(130px, 9.028vw)); at/above 1440 it
   caps — the curve gets LONGER, never thicker. Resting state is FULLY DRAWN, so
   no-JS / reduced-motion / a missed observer still show the complete curve.
   Curves are decorative: aria-hidden, no pointer events, behind the content. */
:root {
	--pn-draw-dur: 1.4s;
	--pn-draw-ease: cubic-bezier(0.22, 0.61, 0.36, 1);
}
.has-curve {
	position: relative;
	overflow: hidden;
}
.ai .ai-inner {
	position: relative;
	z-index: 1;
}
/* Ported from the reference ThemeCurve: the SVG FILLS its section and scales its
   own drawing with `preserveAspectRatio="xMidYMid slice"`. The stroke width is a
   USER-UNIT value on each path (130), so it thickens with the section exactly
   like the reference — no non-scaling-stroke, no vw cap. */
.curve {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	display: block;
	pointer-events: none;
	z-index: 0;
	/* WP's blockGap gives every child after the first a 24px top margin, and it
	   shifts an absolutely positioned box too. The mobile <svg> is the second
	   child, so its art started 24px below the band's top edge and the curves
	   stopped short of it (desktop, being first, was unaffected). */
	margin-block: 0;
}
/* Desktop / mobile art, swapped at the reference's 1024px breakpoint. */
.curve--mobile { display: none; }
@media (max-width: 1024px) {
	.curve--desktop { display: none; }
	.curve--mobile { display: block; }
}
/* Fill the whole section, never the constrained content column. Defeats the WP
   constrained-layout child cap (.section > * { max-width: contentSize }). */
.has-curve > .curve { max-width: none; }
/* Top-anchored ribbon (About page team-ribbon): full width from the top, height
   from the viewBox ratio. The lower part runs off behind the content below and
   is clipped by the wrapper's overflow — never anchored by height, so it stays
   put however tall the band grows. */
.curve--x-top {
	inset: 0 0 auto 0;
	height: auto;
}
.curve path {
	fill: none;
	stroke-linecap: round;
	stroke-linejoin: round;
}
/* Live text riding a curve. `central` puts the baseline through the middle of the
   stroke, so the words sit centred on the band rather than along its edge. */
.curve-text {
	font-family: inherit;
	font-weight: 700;
	/* Tight-ish: the phrase has to fit the band's height at this size. */
	letter-spacing: 0.02em;
	dominant-baseline: central;
}
.curve--sky path { stroke: #92deff; }
.curve--orange path { stroke: #ff6a4d; }
.curve--blue path { stroke: #4295f8; }

/* Draw-in — only when motion is allowed. Paired strokes draw one after another.
   The hidden start and the draw animation are declared TOGETHER: above-fold
   curves get them on load (pure CSS); below-fold curves get them only when JS
   adds .pn-draw on scroll-in. A curve is therefore hidden ONLY while actively
   drawing — no JS, a missed observer, an old browser, or reduced-motion all
   leave it fully drawn (the resting state). */
@media (prefers-reduced-motion: no-preference) {
	/* `opacity: 0` matters as much as the dash offset: `stroke-linecap: round`
	   still paints a round CAP DOT for a zero-length dash, so an undrawn stroke
	   left a fat orange blob wherever its end point landed on screen. The dot is
	   only cropped away when the end point sits outside the viewBox, which is why
	   just one stroke ever showed it. The keyframes below restore opacity, and the
	   animation only applies during its active phase — so a stroke waiting out its
	   stagger delay stays completely invisible. */
	.curve[data-trigger="paint"] path,
	.curve.pn-draw path {
		stroke-dasharray: 1;
		stroke-dashoffset: 1;
		opacity: 0;
		animation: pn-draw var(--pn-draw-dur) var(--pn-draw-ease) forwards;
	}
	.curve[data-trigger="paint"] path:nth-of-type(2),
	.curve.pn-draw path:nth-of-type(2) { animation-delay: var(--pn-draw-dur); }
	.curve[data-trigger="paint"] path:nth-of-type(3),
	.curve.pn-draw path:nth-of-type(3) { animation-delay: calc(var(--pn-draw-dur) * 2); }

	/* Wipe reveal (left→right) — the team-ribbon. The paths draw statically and a
	   clip-path uncovers them from the left, instead of the pen-style dash draw
	   above. Declared after the dash rules (equal specificity) so it wins. */
	.curve--wipe[data-trigger="paint"] path,
	.curve--wipe.pn-draw path {
		stroke-dasharray: none;
		stroke-dashoffset: 0;
		opacity: 1; /* the clip does the hiding here, so undo the dash-draw's opacity: 0 */
		animation: none;
	}
	.curve--wipe[data-trigger="paint"],
	.curve--wipe.pn-draw {
		animation: pn-wipe-lr var(--pn-draw-dur) var(--pn-draw-ease) forwards;
	}

	/* HELD UNDRAWN until its turn. A `view` curve otherwise sits fully drawn (the
	   resting state) while it waits, so it was visible BEFORE it drew — and a later
	   stroke, still waiting out its stagger delay, read as "already on the page".
	   JS adds this only to curves BELOW the fold, so no-JS / a missed observer /
	   reduced motion still leave an on-screen curve complete. Declared last so it
	   outranks the equal-specificity draw rules above. */
	.curve.pn-hold path {
		stroke-dasharray: 1;
		stroke-dashoffset: 1;
		opacity: 0; /* also kills the round-cap dot — see the note above. */
		animation: none;
	}
	.curve--wipe.pn-hold {
		clip-path: inset(0 100% 0 0);
		animation: none;
	}
}
@keyframes pn-draw {
	/* opacity is 1 throughout: the base style keeps a waiting stroke invisible
	   (see the cap-dot note above), and the animation is what reveals it. */
	from { stroke-dashoffset: 1; opacity: 1; }
	to { stroke-dashoffset: 0; opacity: 1; }
}
@keyframes pn-wipe-lr {
	from { clip-path: inset(0 100% 0 0); }
	to { clip-path: inset(0 0 0 0); }
}

/* Reveal-on-scroll. The `.pn-reveal` hidden state is added by JS ONLY to elements
   that are below the fold at load — so it never flashes, and with JS off (or
   reduced-motion, where anim.js bails) nothing is ever hidden. */
.pn-reveal {
	opacity: 0;
	transform: translateY(24px);
	will-change: opacity, transform;
}
/* Transition lives on the revealed state only, so priming to hidden is instant
   (no off-screen fade-out) and only the reveal itself animates. */
.pn-reveal.pn-in {
	opacity: 1;
	transform: none;
	transition: opacity 0.7s ease, transform 0.7s cubic-bezier(0.22, 0.61, 0.36, 1);
}
@media (prefers-reduced-motion: reduce) {
	.pn-reveal { opacity: 1 !important; transform: none !important; transition: none !important; }
}

/* Count-up: keep digits from jittering as the number grows while ticking. */
.impact-value,
.ai-stat-value {
	font-variant-numeric: tabular-nums;
	font-feature-settings: "tnum" 1;
}

/* ─── About page ──────────────────────────────────────────────────────────
   Hero + team grid share ONE blue band (.about-band) so the orange team-ribbon
   runs continuously behind both. .ah / .tg stay transparent and sit above it. */
.about-band {
	background: #4295f8;
}
/* Clear space above the ribbon: the tall shape already carries a built-in top
   gap (~180px on desktop), so this small push lands the first stroke ~250px
   down. Scales down on small screens. */
.about-band .curve {
	top: clamp(30px, 6vw, 75px);
}
.ah,
.tg {
	position: relative;
	z-index: 1;
	background: transparent;
}
.ah {
	padding: var(--wp--preset--spacing--section) 0 var(--wp--preset--spacing--7);
}
.ah-heading {
	color: #fff;
	/* Same size as the home hero's h1 — both are a page's opening title. */
	font-size: var(--wp--preset--font-size--xxl);
	font-weight: 600;
	line-height: 1.15;
	max-width: 820px;
	margin: 0 0 var(--wp--preset--spacing--5);
}
.ah-subtext {
	color: #fff;
	font-size: var(--wp--preset--font-size--lead);
	font-weight: 400;
	line-height: 1.55;
	max-width: 640px;
	margin: 0;
}

/* Team grid */
.tg {
	padding: var(--wp--preset--spacing--5) 0 var(--wp--preset--spacing--section);
}
.tg-title {
	color: var(--wp--preset--color--text);
	font-size: var(--wp--preset--font-size--xl);
	font-weight: 700;
	margin: 0 0 var(--wp--preset--spacing--7);
}
.tg-grid {
	list-style: none;
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: var(--wp--preset--spacing--8) var(--wp--preset--spacing--7);
	margin: 0;
	padding: 0;
}
.tg-card {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	transition: transform 0.25s cubic-bezier(0.22, 0.61, 0.36, 1);
}
.tg-card:hover {
	transform: translateY(-4px);
}
.tg-photo {
	width: 100%;
	aspect-ratio: 5 / 4;
	background: #92deff;
	border-radius: 20px;
	overflow: hidden;
	margin-bottom: var(--wp--preset--spacing--4);
}
.tg-photo-img,
.tg-photo-ph {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}
.tg-name {
	color: var(--wp--preset--color--text);
	font-size: var(--wp--preset--font-size--md);
	font-weight: 700;
	line-height: 1.2;
	margin: 0 0 var(--wp--preset--spacing--1);
}
.tg-role {
	color: var(--wp--preset--color--text);
	font-size: var(--wp--preset--font-size--sm);
	font-weight: 400;
	margin: 0 0 var(--wp--preset--spacing--4);
}
.tg-plus {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 34px;
	height: 34px;
	padding: 0;
	margin-top: auto;
	border: 2px solid var(--wp--preset--color--text);
	border-radius: 50%;
	background: transparent;
	color: var(--wp--preset--color--text);
	cursor: pointer;
	transition: background 0.2s, color 0.2s, transform 0.2s;
}
.tg-plus:hover,
.tg-plus:focus-visible {
	background: var(--wp--preset--color--text);
	color: #fff;
	transform: rotate(90deg);
}
.tg-plus-svg { width: 18px; height: 18px; display: block; }
.tg-more { display: flex; justify-content: center; margin-top: var(--wp--preset--spacing--8); }
.tg-more-btn {
	background: var(--wp--preset--color--text);
	color: #fff;
	border: none;
	border-radius: 999px;
	font-size: var(--pn-pill-font);
	font-weight: 600;
	padding: var(--pn-pill-pad-y, 11px) var(--pn-pill-pad-x, 52px);
	cursor: pointer;
	transition: background 0.2s;
}
.tg-more-btn:hover:not(:disabled) { background: var(--wp--preset--color--accent); }
.tg-more-btn:disabled { opacity: 0.6; cursor: default; }
.tg-empty { color: #fff; }

/* ─── Team bio popup ──────────────────────────────────────────────────── */
.tg-modal {
	position: fixed;
	inset: 0;
	z-index: 2000;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: var(--wp--preset--spacing--5);
}
.tg-modal[hidden] { display: none; }
.tg-modal-backdrop {
	position: absolute;
	inset: 0;
	background: rgba(15, 45, 150, 0.55);
	backdrop-filter: blur(6px);
	-webkit-backdrop-filter: blur(6px);
}
.tg-modal-dialog {
	position: relative;
	width: min(720px, 100%);
	max-height: min(86vh, 760px);
	overflow: hidden;
	display: flex;
	flex-direction: column;
	background: var(--wp--preset--color--text);
	color: #fff;
	border-radius: 28px;
	padding: var(--wp--preset--spacing--8);
	box-shadow: 0 30px 80px rgba(10, 26, 92, 0.5);
}
.tg-modal-close {
	position: absolute;
	top: var(--wp--preset--spacing--5);
	right: var(--wp--preset--spacing--5);
	width: 42px;
	height: 42px;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	border: none;
	border-radius: 50%;
	background: #fff;
	color: var(--wp--preset--color--text);
	cursor: pointer;
	transition: transform 0.2s;
}
.tg-modal-close:hover {
	background: var(--wp--preset--color--accent);
	color: #fff;
	transform: rotate(90deg);
}
.tg-modal-close svg { width: 20px; height: 20px; }
.tg-modal-head {
	flex: 0 0 auto;
	display: flex;
	align-items: center;
	gap: var(--wp--preset--spacing--5);
	margin-bottom: var(--wp--preset--spacing--6);
	padding-right: 48px;
}
.tg-modal-photo {
	flex: 0 0 auto;
	width: 108px;
	height: 108px;
	border-radius: 14px;
	overflow: hidden;
	background: #92deff;
}
.tg-modal-photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.tg-modal-name {
	color: #fff;
	font-size: var(--wp--preset--font-size--lg);
	font-weight: 700;
	line-height: 1.15;
	margin: 0 0 var(--wp--preset--spacing--2);
}
.tg-modal-role {
	color: #92deff;
	font-size: var(--wp--preset--font-size--sm);
	font-weight: 500;
	margin: 0;
}
.tg-modal-role[hidden] { display: none; }
.tg-modal-bio {
	/* `min-height: 0` is what actually makes this scroll. As a column flex item it
	   defaults to `min-height: auto`, so a long bio refuses to shrink, grows past
	   the dialog, and gets clipped by the dialog's `overflow: hidden` instead of
	   showing a scrollbar. `flex: 1 1 auto` lets it take the leftover height. */
	flex: 1 1 auto;
	min-height: 0;
	overflow-y: auto;
	overscroll-behavior: contain;
	padding-right: var(--wp--preset--spacing--3);
	color: #fff;
	line-height: 1.6;
	overflow-wrap: break-word;
	scrollbar-width: thin;
	scrollbar-color: rgba(255, 255, 255, 0.45) transparent;
}
.tg-modal-bio::-webkit-scrollbar {
	width: 6px;
}
.tg-modal-bio::-webkit-scrollbar-track {
	background: transparent;
}
.tg-modal-bio::-webkit-scrollbar-thumb {
	background: rgba(255, 255, 255, 0.45);
	border-radius: 3px;
}
.tg-modal-bio p { margin: 0 0 1em; color: #fff; }
.tg-modal-bio :is(h2, h3, h4) { color: #fff; margin: 1.2em 0 0.4em; }
.tg-modal-bio a { color: #92deff; }
body.tg-modal-open { overflow: hidden; }

@media (max-width: 1024px) {
	.tg-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 768px) {
	.tg-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--wp--preset--spacing--6) var(--wp--preset--spacing--4); }
	.tg-modal-dialog { padding: var(--wp--preset--spacing--6); border-radius: 20px; }
	/* Stacked: photo on top, then name, then designation. As a row the heading was
	   squeezed into the sliver beside the photo, so both wrapped and the last line
	   of the designation got clipped. Full width each, no clipping. The close
	   button sits top-right and the photo top-left, so the 48px reserve is moot. */
	.tg-modal-head {
		flex-direction: column;
		align-items: flex-start;
		gap: var(--wp--preset--spacing--4);
		padding-right: 0;
	}
	.tg-modal-photo { width: 108px; height: 108px; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   PING SHIELD PAGE — ported from page-mocks/ping-shield.html (tokens map 1:1).
   ═══════════════════════════════════════════════════════════════════════════ */

/* 1 · Shield hero */
.sh { background: #ffffff; padding: var(--wp--preset--spacing--section) 0 0; }
.sh-main { display: grid; grid-template-columns: 1.4fr 1fr; gap: var(--wp--preset--spacing--8); align-items: center; }
/* Height = one line of .sh-heading (xxl clamp x its 1.15 line-height), width
   derived from the SVG's own 762.83:151.56 ratio — so the wordmark tracks the
   title on every screen. aspect-ratio keeps it undistorted if max-width bites. */
.sh-logo { height: calc(var(--wp--preset--font-size--xxl) * 1.15); width: auto; aspect-ratio: 762.83 / 151.56; max-width: 100%; display: block; margin: 0 0 var(--wp--preset--spacing--5); }
.sh-heading { color: #0f2d96; font-size: var(--wp--preset--font-size--xxl); font-weight: 700; line-height: 1.15; max-width: 620px; margin: 0 0 var(--wp--preset--spacing--5); }
.sh-subtext { color: #0f2d96; font-size: var(--wp--preset--font-size--lead); line-height: 1.55; max-width: 480px; margin: 0 0 var(--wp--preset--spacing--6); }
.sh-ctas { display: flex; flex-wrap: wrap; gap: var(--wp--preset--spacing--4); }
.sh-cta { display: inline-flex; align-items: center; border-radius: 999px; padding: var(--pn-pill-pad-y, 11px) var(--pn-pill-pad-x, 32px); font-weight: 600; font-size: var(--pn-pill-font); text-decoration: none; transition: background .2s, color .2s; }
.sh-cta-primary { background: #ff6a4d; color: #fff; padding-inline: var(--pn-pill-pad-x, 36px); }
.sh-cta-primary:hover { background: #e0532f; }
.sh-cta-blue { background: #92deff; color: #fff; }
.sh-cta-blue:hover { background: #7fd3fa; }
.sh-right { position: relative; min-height: 420px; }
.sh-emblem { position: absolute; top: 50%; right: 4%; transform: translateY(-50%); width: 200px; height: auto; }
.sh-stat { position: absolute; display: flex; flex-direction: column; margin: 0; }
.sh-stat-value { color: #ff6a4d; font-size: var(--wp--preset--font-size--lg); font-weight: 700; line-height: 1; }
.sh-stat-label { color: #0f2d96; font-size: var(--wp--preset--font-size--sm); font-weight: 500; margin-top: var(--wp--preset--spacing--1); }
.sh-stat--0 { top: 0; right: 6%; text-align: right; align-items: flex-end; }
.sh-stat--1 { top: 38%; left: 0; text-align: left; align-items: flex-start; }
.sh-stat--2 { bottom: 4%; right: 12%; text-align: right; align-items: flex-end; }
.sh-badges-band { background: #0f2d96; margin-top: var(--wp--preset--spacing--7); padding: var(--wp--preset--spacing--9) 0; }
/* Centered trio: each badge centers its icon + text, and the text is capped and
   balanced so the three read as even blocks rather than ragged columns. */
/* `margin-block: 0`, NOT `margin: 0` — this <ul> also carries .pn-container, and a
   blanket margin reset would kill its `margin-inline: auto` and shove the whole
   group to the left edge instead of centring it in the band. */
.sh-badges { list-style: none; display: grid; grid-template-columns: repeat(3, 1fr); justify-items: center; align-items: start; gap: var(--wp--preset--spacing--6); margin-block: 0; padding: 0; }
.sh-badge { display: flex; flex-direction: column; align-items: center; justify-content: flex-start; text-align: center; gap: var(--wp--preset--spacing--4); color: #ffffff; font-size: var(--wp--preset--font-size--xl); font-weight: 700; line-height: 1.3; margin: 0; }
.sh-badge > span { display: block; max-width: 22ch; margin-inline: auto; text-align: center; text-wrap: balance; }
.sh-check { width: 40px; height: 40px; flex-shrink: 0; }

/* 2 · How it works */
.hw { position: relative; overflow: hidden; background: linear-gradient(to right, #ffffff 0 50%, #92deff 50% 100%); }
.hw-curve { position: absolute; top: 0; right: 0; width: 50%; height: 100%; z-index: 0; pointer-events: none; }
.hw-curve .curve { opacity: 0.9; }
.hw-inner { position: relative; z-index: 1; display: grid; grid-template-columns: 1fr 1fr; min-height: 540px; }
.hw-left { display: flex; flex-direction: column; justify-content: center; padding: var(--wp--preset--spacing--9) var(--wp--preset--spacing--8) var(--wp--preset--spacing--9) 0; }
.hw-kicker { color: #0f2d96; font-size: calc(var(--wp--preset--font-size--xl) - 4px); font-weight: 700; margin: 0 0 var(--wp--preset--spacing--5); }
.hw-heading { color: #0f2d96; font-size: var(--wp--preset--font-size--xl); font-weight: 700; line-height: 1.15; margin: 0 0 var(--wp--preset--spacing--5); max-width: 480px; }
.hw-body { color: #0f2d96; font-size: var(--wp--preset--font-size--body); line-height: 1.55; margin: 0 0 var(--wp--preset--spacing--6); max-width: 460px; }
/* Circle-plus: a real SVG icon (assets/img/plus-circle.svg) rather than CSS bars,
   so the strokes stay crisp and perfectly centred at any size. */
.hw-plus, .sc-plus { display: block; width: 44px; height: 44px; flex: 0 0 auto; }
.hw-right { display: flex; flex-direction: column; justify-content: space-around; align-items: center; gap: var(--wp--preset--spacing--7); padding: var(--wp--preset--spacing--9) var(--wp--preset--spacing--5) var(--wp--preset--spacing--9) var(--wp--preset--spacing--9); }
.hw-item { display: flex; flex-direction: column; align-items: center; text-align: center; }
.hw-num { color: #0f2d96; font-size: calc(var(--wp--preset--font-size--display) + 16px); font-weight: 700; line-height: 1; }
.hw-item-title { color: #0f2d96; font-size: calc(var(--wp--preset--font-size--lg) - 2px); font-weight: 700; line-height: 1.3; margin-top: var(--wp--preset--spacing--4); }

/* 3 & 4 · Model panels */
.sm { background: #92deff; padding: var(--wp--preset--spacing--6) 0; }
/* Both Model cards use the same light blue (Model 02 matched to Model 01). */
.sm-card { border-radius: 28px; padding: var(--wp--preset--spacing--8) var(--wp--preset--spacing--9); display: grid; grid-template-columns: 1.5fr 1fr; gap: var(--wp--preset--spacing--9); align-items: center; background: #4295f8; }
.sm-number { color: #0f2d96; font-size: calc(var(--wp--preset--font-size--xl) - 4px); font-weight: 700; margin: 0 0 var(--wp--preset--spacing--4); }
.sm-title { color: #ffffff; font-size: var(--wp--preset--font-size--xl); font-weight: 700; line-height: 1.15; margin: 0 0 var(--wp--preset--spacing--4); }
.sm-desc { color: #fff; font-size: var(--wp--preset--font-size--body); line-height: 1.55; margin: 0 0 var(--wp--preset--spacing--4); }
.sm-hl { color: #0f2d96; font-weight: 700; }
.sm-cta { display: inline-flex; align-items: center; background: #ff6a4d; color: #fff; border-radius: 999px; padding: var(--pn-pill-pad-y, 11px) var(--pn-pill-pad-x, 36px); font-weight: 600; font-size: var(--pn-pill-font); text-decoration: none; transition: background .2s; margin-top: var(--wp--preset--spacing--4); }
.sm-cta:hover { background: #e0532f; }
.sm-bullets { display: flex; flex-direction: column; gap: var(--wp--preset--spacing--5); }
.sm-check { width: 40px; height: 40px; margin-bottom: var(--wp--preset--spacing--1); }
.sm-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--wp--preset--spacing--5); }
.sm-list li { color: #ffffff; font-size: var(--wp--preset--font-size--lg); font-weight: 700; line-height: 1.3; }

/* 5 · Cost of piracy */
.sc-band { background: linear-gradient(to right, #ffffff 0 50%, #0f2d96 50% 100%); }
.sc-inner { display: grid; grid-template-columns: 1fr 1fr; min-height: 520px; }
.sc-left { display: flex; flex-direction: column; justify-content: center; padding: var(--wp--preset--spacing--9) var(--wp--preset--spacing--9) var(--wp--preset--spacing--9) 0; }
.sc-eyebrow { color: #0f2d96; font-size: calc(var(--wp--preset--font-size--xl) - 4px); font-weight: 700; margin: 0 0 var(--wp--preset--spacing--5); }
.sc-heading { color: #0f2d96; font-size: var(--wp--preset--font-size--xl); font-weight: 700; line-height: 1.15; margin: 0 0 var(--wp--preset--spacing--5); max-width: 440px; }
.sc-body { color: #0f2d96; font-size: var(--wp--preset--font-size--body); line-height: 1.55; margin: 0 0 var(--wp--preset--spacing--6); max-width: 430px; }
.sc-right { display: flex; flex-direction: column; padding: var(--wp--preset--spacing--6) var(--wp--preset--spacing--4) var(--wp--preset--spacing--4); }
.sc-chart-title { color: #ffffff; font-size: var(--wp--preset--font-size--xl); font-weight: 700; line-height: 1.3; margin: 0 0 var(--wp--preset--spacing--7); }
.sc-bars { flex: 1; min-height: 300px; display: flex; align-items: stretch; gap: var(--wp--preset--spacing--4); padding: 0; }
.sc-bar-col { flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: center; justify-content: flex-end; container-type: inline-size; }
.sc-bar-label { color: #ffffff; font-size: var(--wp--preset--font-size--sm); font-weight: 500; text-align: center; line-height: 1.3; margin-bottom: var(--wp--preset--spacing--3); max-width: 100px; }
.sc-bar { position: relative; width: 100%; background: #92deff; border-radius: 42cqw 42cqw 0 0; }
/* Heights are a share of the column MINUS the label row (3.75rem), exactly as the
   design mock — otherwise the label's space skews the ratios (75% read as 85%). */
.sc-bar--h100 { height: calc((100% - 3.75rem) * 100 / 100); }
.sc-bar--h75 { height: calc((100% - 3.75rem) * 75 / 100); }
.sc-bar--h45 { height: calc((100% - 3.75rem) * 45 / 100); }
.sc-bar--h30 { height: calc((100% - 3.75rem) * 30 / 100); }
/* Bars grow up from the bottom when the chart scrolls in. JS collapses them to 0
   (`pn-bars-prime`, instant — no transition in that state) only while they're
   off-screen, then swaps in `pn-bars-in`, which supplies the transition, so the
   growth is the only thing that animates. No JS / reduced motion → full height. */
.sc-bars.pn-bars-prime .sc-bar { height: 0; }
.sc-bars.pn-bars-in .sc-bar { transition: height 0.9s cubic-bezier(0.22, 0.61, 0.36, 1); }
.sc-bars.pn-bars-in .sc-bar-col:nth-child(2) .sc-bar { transition-delay: 0.12s; }
.sc-bars.pn-bars-in .sc-bar-col:nth-child(3) .sc-bar { transition-delay: 0.24s; }
.sc-bars.pn-bars-in .sc-bar-col:nth-child(4) .sc-bar { transition-delay: 0.36s; }
/* anim.js bails under reduced motion, so the prime class is never added there;
   this only makes sure nothing animates if the preference flips mid-session. */
@media (prefers-reduced-motion: reduce) {
	.sc-bars .sc-bar { transition: none !important; }
}
.sc-bar-pct { position: absolute; top: calc(var(--wp--preset--spacing--2) + 20px); left: 0; right: 0; text-align: center; color: #ff6a4d; font-weight: 700; line-height: 1; padding: 0 0.5rem; font-size: 39cqw; }

/* 6 · Stats */
.ss { background: #92deff; padding: var(--wp--preset--spacing--section) 0; }
.ss-eyebrow { color: #0f2d96; font-size: calc(var(--wp--preset--font-size--xl) - 4px); font-weight: 700; margin: 0 0 var(--wp--preset--spacing--2); }
.ss-title { color: #0f2d96; font-size: var(--wp--preset--font-size--xl); font-weight: 700; line-height: 1.15; max-width: 600px; margin: 0 0 var(--wp--preset--spacing--4); }
.ss-subtitle { color: #0f2d96; font-size: var(--wp--preset--font-size--body); line-height: 1.55; max-width: 560px; margin: 0 0 var(--wp--preset--spacing--8); }
.ss-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--wp--preset--spacing--7); }
.ss-row { display: grid; grid-template-columns: minmax(0, 55fr) minmax(0, 45fr); gap: var(--wp--preset--spacing--6); align-items: center; margin: 0; }
.ss-value { color: #0f2d96; font-size: calc(var(--wp--preset--font-size--display) + 16px); font-weight: 700; line-height: 1; font-variant-numeric: tabular-nums; }
.ss-desc { color: #0f2d96; font-size: calc(var(--wp--preset--font-size--lg) - 2px); font-weight: 500; line-height: 1.55; }
.ss-row--accent .ss-value, .ss-row--accent .ss-desc { color: #ff6a4d; }

/* 7 · Insights */
.si-head { background: #ffffff; padding: var(--wp--preset--spacing--9) 0 var(--wp--preset--spacing--8); }
.si-title { color: #0f2d96; font-size: var(--wp--preset--font-size--xl); font-weight: 700; line-height: 1.15; max-width: 620px; margin: 0 0 var(--wp--preset--spacing--5); }
.si-explore { display: inline-flex; align-items: center; background: #92deff; color: #ffffff; border-radius: 999px; padding: var(--pn-pill-pad-y, 11px) var(--pn-pill-pad-x, 32px); font-size: var(--pn-pill-font); font-weight: 600; text-decoration: none; transition: background .2s; }
.si-explore:hover { background: #7fd3fa; }
.si-band { position: relative; background: #0f2d96; padding: var(--wp--preset--spacing--9) 0 var(--wp--preset--spacing--10); }
.si-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--wp--preset--spacing--8); }
.si-thumb { width: 100%; aspect-ratio: 16 / 9; border-radius: 20px; overflow: hidden; margin: 0; }
.si-photo, .si-ph { width: 100%; height: 100%; display: block; object-fit: cover; }
.si-card-title { color: #ffffff; font-size: var(--wp--preset--font-size--lg); font-weight: 700; line-height: 1.3; margin: var(--wp--preset--spacing--5) 0 0; }
.si-dot { position: absolute; right: 40px; bottom: 40px; width: 34px; height: 34px; border-radius: 50%; background: #ff6a4d; }

/* ═══════════════════════════════════════════════════════════════════════════
   KNOWLEDGE PAGE — ported from page-mocks/knowledge.html.
   ═══════════════════════════════════════════════════════════════════════════ */

/* 1 · Knowledge hero — sky LEFT half, white RIGHT half, one big swoosh laid
   across both: it bleeds off the right edge, and its left arm runs into the sky
   half where it blends into the background instead of stopping mid-air. */
.kh {
	position: relative;
	overflow: hidden;
	background: linear-gradient(to right, #92deff 0 50%, #ffffff 50% 100%);
	padding: var(--wp--preset--spacing--section) 0;
}
/* margin-block-start: WP's blockGap adds 24px here (the inner follows the curve
   <svg>), which pushed the heading past the band's padding and broke the shared
   header-to-title spacing. */
.kh-inner { position: relative; z-index: 1; margin-block-start: 0; }
/* 90% of the sky half, left aligned. The container is centred and narrower than
   the page, so its left half ≈ 49.4% of the container — 45% is ~90% of that, and
   the remaining tenth is the breathing gap before the white half. */
.kh-left {
	position: relative;
	z-index: 1;
	width: 45%;
	text-align: left;
}
.kh-heading { color: #0f2d96; font-size: var(--wp--preset--font-size--xxl); font-weight: 700; line-height: 1.15; margin: 0 0 var(--wp--preset--spacing--5); }
.kh-body { color: #0f2d96; font-size: var(--wp--preset--font-size--body); line-height: 1.55; margin: 0 0 var(--wp--preset--spacing--6); }
/* Same metrics as the homepage pills (theme.json button + .ai-cta): 11px/52px,
   17px, 600 — so every button on the site is identical. */
.kh-cta {
	display: inline-flex;
	align-items: center;
	background: #ff6a4d;
	color: #fff;
	font-weight: 600;
	font-size: var(--pn-pill-font);
	padding: var(--pn-pill-pad-y, 11px) var(--pn-pill-pad-x, 52px);
	border-radius: 999px;
	text-decoration: none;
	transition: background 0.2s;
}
.kh-cta:hover { background: #e0532f; }
/* The curve layer spans the whole band (not just the right column) — that is what
   lets the horizontal sweep reach the sky half. Wider than half the page, anchored
   right and pushed past the edge, so it bleeds right and is cropped top/bottom. */
.kh .curve {
	inset: auto -4% auto auto;
	top: 50%;
	width: 62%;
	height: auto;
	max-width: none;
	transform: translateY(-50%);
	overflow: visible;
}
@media (max-width: 768px) {
	/* Stacked: the white right half (and the swoosh it carried) is dropped, so the
	   band is plain sky with the normal section rhythm on both edges — that gives
	   the CTA room underneath instead of butting it against the artwork strip. */
	.kh {
		background: #92deff;
		padding: var(--wp--preset--spacing--section) 0;
	}
	.kh-left { width: 100%; padding-right: 0; }
	.kh .curve { display: none; }
}

/* 2 · Explore our collection — white band, centred heading + search */
.cs { background: #ffffff; padding: var(--wp--preset--spacing--section) 0; }
.cs-inner { text-align: center; }
.cs-title { color: #0f2d96; font-size: var(--wp--preset--font-size--xl); font-weight: 700; margin: 0 0 var(--wp--preset--spacing--6); }
/* core/search, restyled: underlined field + sky pill button. WP's own rules are
   `:where()`-wrapped, so plain classes are enough to override them. */
.cs .wp-block-search { max-width: 560px; margin-inline: auto; }
/* Column, so the pill sits BELOW the field and centred (per the design). */
.cs .wp-block-search__inside-wrapper {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: var(--wp--preset--spacing--5);
	border: none;
	padding: 0;
}
/* The magnifier is a background image on the input itself — keeps it inside the
   underlined field without adding an element the block editor doesn't know about. */
.cs .wp-block-search__input {
	width: 100%;
	max-width: 440px;
	min-width: 0;
	border: none;
	border-bottom: 2px solid #0f2d96;
	border-radius: 0;
	background-color: transparent;
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230f2d96' stroke-width='2'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='M20 20l-3.5-3.5' stroke-linecap='round'/%3E%3C/svg%3E");
	background-repeat: no-repeat;
	background-position: left center;
	background-size: 22px 22px;
	outline: none;
	font-family: inherit;
	font-size: var(--wp--preset--font-size--body);
	color: #0f2d96;
	padding: var(--wp--preset--spacing--2) 0 var(--wp--preset--spacing--2) 34px;
}
/* Keep the native clear (×) that a search input provides, tinted to the brand. */
.cs .wp-block-search__input::-webkit-search-cancel-button {
	-webkit-appearance: none;
	appearance: none;
	width: 14px;
	height: 14px;
	cursor: pointer;
	background-color: #1c64f2;
	-webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='3' stroke-linecap='round'%3E%3Cpath d='M6 6l12 12M18 6L6 18'/%3E%3C/svg%3E") center / contain no-repeat;
	mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='3' stroke-linecap='round'%3E%3Cpath d='M6 6l12 12M18 6L6 18'/%3E%3C/svg%3E") center / contain no-repeat;
}
.cs .wp-block-search__input::placeholder { color: rgba(15, 45, 150, 0.5); }
.cs .wp-block-search__input:focus { border-bottom-color: #ff6a4d; }
/* Same pill metrics as the homepage buttons. */
.cs .wp-block-search__button {
	flex: 0 0 auto;
	background: #92deff;
	color: #ffffff;
	border: none;
	border-radius: 999px;
	padding: var(--pn-pill-pad-y, 11px) var(--pn-pill-pad-x, 52px);
	margin: 0;
	font-family: inherit;
	font-size: var(--pn-pill-font);
	font-weight: 600;
	cursor: pointer;
	transition: background 0.2s;
}
.cs .wp-block-search__button:hover { background: #7fd3fa; }

/* 3 · Knowledge cards — post cards (thumbnail + title, no play button).
   Short top gap: continues the white area from the search band above. */
.kc { background: #ffffff; padding: var(--wp--preset--spacing--5) 0 var(--wp--preset--spacing--section); }
.kc-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--wp--preset--spacing--7); }
.kc-card { display: flex; flex-direction: column; }
.kc-thumb { position: relative; width: 100%; aspect-ratio: 16 / 9; border-radius: 20px; overflow: hidden; margin: 0; }
.kc-ph { width: 100%; height: 100%; display: block; }
.kc-title { color: #0f2d96; font-size: var(--wp--preset--font-size--md); font-weight: 700; line-height: 1.3; margin: var(--wp--preset--spacing--4) 0 0; }
@media (max-width: 768px) {
	/* Two-up at every width — only the gutter tightens. */
	.kc-grid { gap: var(--wp--preset--spacing--6) var(--wp--preset--spacing--5); }
}

/* 9 · Final CTA */
.shcta { background: #4295f8; padding: var(--wp--preset--spacing--section) 0; }
.shcta-inner { text-align: center; }
.shcta-heading { color: #ffffff; font-size: var(--wp--preset--font-size--xxl); font-weight: 700; line-height: 1.15; margin: 0 0 var(--wp--preset--spacing--4); }
.shcta-subtext { color: #ffffff; font-size: var(--wp--preset--font-size--lead); line-height: 1.55; max-width: 620px; margin: 0 auto var(--wp--preset--spacing--6); }
.shcta-btn { display: inline-flex; align-items: center; background: #ff6a4d; color: #fff; border-radius: 999px; padding: var(--pn-pill-pad-y, 11px) var(--pn-pill-pad-x, 52px); font-weight: 600; font-size: var(--pn-pill-font); text-decoration: none; transition: background .2s; }
.shcta-btn:hover { background: #e0532f; }

@media (max-width: 768px) {
	.sh-main { grid-template-columns: 1fr; gap: var(--wp--preset--spacing--5); }
	.sh-right { min-height: 360px; }
	.sh-emblem { width: 150px; }
	/* Stacked one per row, so the check reads inline with its label instead of
	   sitting on top of it. justify-items: start keeps the left edges lined up. */
	.sh-badges { grid-template-columns: 1fr; gap: var(--wp--preset--spacing--5); justify-items: start; }
	.sh-badge { flex-direction: row; align-items: center; text-align: left; }
	.sh-badge > span { max-width: none; margin-inline: 0; text-align: left; }
	.hw { background: #92deff; }
	.hw-curve { display: none; }
	.hw-inner { grid-template-columns: 1fr; min-height: 0; }
	.hw-left { padding: var(--wp--preset--spacing--8) 0; }
	.hw-right { padding: var(--wp--preset--spacing--7) 0; }
	.sm-card { grid-template-columns: 1fr; gap: var(--wp--preset--spacing--7); padding: var(--wp--preset--spacing--7) var(--wp--preset--spacing--6); }
	/* The band goes solid navy here, but the left column's text is navy too (it
	   sits on the white half on desktop) — it vanished. White it on this width. */
	.sc-band { background: #0f2d96; }
	.sc-inner { grid-template-columns: 1fr; min-height: 0; }
	.sc-left { padding: var(--wp--preset--spacing--8) 0; color: #ffffff; }
	.sc-left .sc-eyebrow,
	.sc-left .sc-heading,
	.sc-left .sc-body { color: #ffffff; }
	.sc-right { padding: var(--wp--preset--spacing--7) 0; }
	.ss-row { grid-template-columns: 1fr; gap: var(--wp--preset--spacing--2); }
	.si-grid { grid-template-columns: 1fr; gap: var(--wp--preset--spacing--6); }
	.si-dot { right: 20px; bottom: 20px; width: 26px; height: 26px; }
}

/* ─── Contact — "Ping Us!" ────────────────────────────────────────────────
   Ported from the Nuxt contact page. Sky band with ONE blue swoosh anchored to
   the top (see the 'contact-lines' shape in inc/curves.php), the form on the
   left and the Reach Out sidebar on the right. Design's --space-* scale maps
   1:1 onto the theme's spacing presets. */
.ping-contact {
	background: #92deff;
	padding: var(--wp--preset--spacing--section) 0;
}
/* The curve hangs off the bottom of the band; .has-curve clips it. Its own
   .curve--x-top rule pins it to the top so the dip runs off behind the form
   instead of being squashed as the band grows with the form's height. */
.ping-contact-inner {
	position: relative;
	z-index: 1;
}
/* The curve <svg> is the band's first child, so WP's flow-layout blockGap would
   push the content 24px down past the band's own padding. Kill it here so the
   heading sits exactly on the padding, as in the design. */
.ping-contact > .ping-contact-inner {
	margin-block-start: 0;
}
.ping-contact .ping-contact-heading {
	color: var(--wp--preset--color--text);
	font-size: var(--wp--preset--font-size--xxl);
	font-weight: 600;
	line-height: var(--wp--custom--line-height--tight);
	margin: 0 0 var(--wp--preset--spacing--4);
}
.ping-contact .ping-contact-lede {
	color: var(--wp--preset--color--text);
	font-size: var(--wp--preset--font-size--lead);
	line-height: var(--wp--custom--line-height--body);
	max-width: 620px;
	margin: 0 0 var(--wp--preset--spacing--7);
}
.ping-contact-cols {
	display: flex;
	gap: var(--wp--preset--spacing--9);
	align-items: flex-start;
}

/* Form (left) */
.ping-form {
	display: flex;
	flex-direction: column;
	gap: var(--wp--preset--spacing--5);
	max-width: 720px;
	flex: 1 1 0;
	min-width: 0;
}
.ping-field input,
.ping-field textarea {
	width: 100%;
	/* WordPress has no global border-box reset (the design mock does), so without
	   this the padding is ADDED to the 100% width and every field overflows the
	   form column by 64px. */
	box-sizing: border-box;
	background: var(--wp--preset--color--surface);
	border: none;
	border-radius: 20px;
	padding: var(--wp--preset--spacing--5) var(--wp--preset--spacing--6);
	font-size: var(--wp--preset--font-size--body);
	font-weight: 400;
	color: var(--wp--preset--color--text);
	font-family: inherit;
	outline: none;
	box-shadow: 0 2px 8px rgba(15, 45, 150, 0.06);
	transition: box-shadow 0.2s ease;
}
.ping-field input::placeholder,
.ping-field textarea::placeholder {
	color: var(--wp--preset--color--text);
	opacity: 0.85;
}
.ping-field textarea {
	resize: vertical;
	min-height: 150px;
	display: block;
}
.ping-field input:focus,
.ping-field textarea:focus {
	box-shadow: 0 0 0 3px rgba(242, 111, 76, 0.45);
}
.ping-form-actions {
	display: flex;
	justify-content: flex-end;
}
.ping-submit {
	background: var(--wp--preset--color--accent);
	color: #fff;
	border: none;
	border-radius: 999px;
	padding: var(--pn-pill-pad-y, 11px) var(--pn-pill-pad-x, 52px);
	font-size: var(--pn-pill-font);
	font-weight: 500;
	cursor: pointer;
	font-family: inherit;
	transition: background 0.2s;
}
.ping-submit:hover {
	background: #e0532f;
}
/* The honeypot. Off-screen rather than display:none — a bot that reads styles
   skips hidden inputs, but this one still looks fillable to it. */
.ping-field-trap {
	position: absolute;
	left: -9999px;
	width: 1px;
	height: 1px;
	overflow: hidden;
}
/* Post-submit notice, above the first field. */
.ping-form-notice {
	margin: 0;
	padding: var(--wp--preset--spacing--4) var(--wp--preset--spacing--5);
	border-radius: 12px;
	font-size: var(--wp--preset--font-size--sm);
	font-weight: 600;
	line-height: var(--wp--custom--line-height--body);
}
.ping-form-notice--ok {
	background: var(--wp--preset--color--surface);
	color: var(--wp--preset--color--text);
	border-left: 4px solid #2f9e5f;
}
.ping-form-notice--bad {
	background: var(--wp--preset--color--surface);
	color: var(--wp--preset--color--text);
	border-left: 4px solid var(--wp--preset--color--accent);
}

/* Reach Out (right) */
.ping-reachout {
	flex: 0 0 320px;
}
.ping-reachout .ping-reachout-title {
	color: var(--wp--preset--color--text);
	font-size: var(--wp--preset--font-size--lg);
	font-weight: 600;
	line-height: var(--wp--custom--line-height--tight);
	margin: 0 0 var(--wp--preset--spacing--6);
}
.ping-reachout-item {
	display: flex;
	align-items: flex-start;
	gap: var(--wp--preset--spacing--4);
	margin-bottom: var(--wp--preset--spacing--5);
}
.ping-reachout-icon {
	color: var(--wp--preset--color--accent);
	width: 26px;
	height: 26px;
	flex-shrink: 0;
	margin-top: 2px;
}
.ping-reachout-label {
	color: var(--wp--preset--color--text);
	font-weight: 600;
	font-size: var(--wp--preset--font-size--body);
	margin: 0 0 2px;
}
.ping-reachout-value {
	color: var(--wp--preset--color--text);
	font-size: var(--wp--preset--font-size--body);
	text-decoration: none;
	margin: 0;
}
a.ping-reachout-value:hover {
	text-decoration: underline;
}
.ping-reachout-socials {
	display: flex;
	flex-wrap: wrap;
	gap: var(--wp--preset--spacing--3);
	margin-top: var(--wp--preset--spacing--6);
}
.ping-social {
	width: 42px;
	height: 42px;
	border-radius: 999px;
	background: var(--wp--preset--color--brand-blue);
	color: #fff;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	transition: background 0.2s;
}
.ping-social:hover {
	background: var(--wp--preset--color--accent);
}
.ping-social svg {
	width: 20px;
	height: 20px;
	display: block;
}

@media (max-width: 900px) {
	.ping-contact-cols {
		flex-direction: column;
	}
	.ping-form {
		width: 100%;
		max-width: none;
	}
	.ping-reachout {
		flex-basis: auto;
		width: 100%;
		max-width: 620px;
	}
}
@media (max-width: 768px) {
	.ping-field input,
	.ping-field textarea {
		padding: 10px 20px;
	}
}

/* ─── AI & Intelligence page ──────────────────────────────────────────────
   Three bands: blue hero + count-up stat, white "what we handle" + navy card,
   navy "How we work" step line. Everything is real blocks, so the decorative
   bits (step numbers, orange ticks, card icon) are drawn in CSS — an editor can
   add or remove a list item and the numbering/marks follow on their own. */

/* The two icon shapes, kept as masks so they take their colour from CSS and no
   <svg> ever has to live in post content. */
:root {
	--aip-tick: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 12.5 9.5 18 20 6'/%3E%3C/svg%3E");
	--aip-pulse: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2 12h4l3-9 4 18 3-9h6'/%3E%3C/svg%3E");
}

/* 1 — Hero */
.aip-hero {
	display: flex;
	/* Same height token as the home hero — see --pn-hero-h. */
	min-height: var(--pn-hero-h);
	/* Site-wide first-section spacing — same value as .mh and every other page. */
	padding: var(--wp--preset--spacing--section) 0;
}
/* Without this the inner stretches to the band's full height and its grid's
   `align-items: center` re-centres the heading, undoing the shared top spacing. */
.aip-hero > .aip-hero-inner {
	align-self: flex-start;
}
.aip-hero-inner {
	position: relative;
	z-index: 1;
	display: grid;
	grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr);
	gap: var(--wp--preset--spacing--9);
	align-items: center;
}
.aip-hero > .aip-hero-inner {
	margin-block-start: 0;
}
.aip-hero .aip-hero-heading {
	color: #fff;
	font-size: var(--wp--preset--font-size--xxl);
	font-weight: 700;
	line-height: var(--wp--custom--line-height--tight);
	margin: 0 0 var(--wp--preset--spacing--5);
	max-width: 12em;
}
.aip-hero .aip-hero-lede {
	color: #fff;
	font-size: var(--wp--preset--font-size--lead);
	line-height: var(--wp--custom--line-height--body);
	margin: 0;
	max-width: 34em;
}
.aip-hero-stat {
	align-self: center;
}
/* Same type as the home page's stat (.ai-stat-value / .ai-stat-label), so the
   two stats read as one component across the site. */
.aip-hero .aip-stat-value {
	color: var(--wp--preset--color--accent);
	font-size: calc(var(--wp--preset--font-size--display) + 16px);
	font-weight: 700;
	line-height: 1;
	margin: 0 0 var(--wp--preset--spacing--2);
	/* Keeps the digits from jittering while the count-up runs. */
	font-variant-numeric: tabular-nums;
}
.aip-hero .aip-stat-label {
	color: var(--wp--preset--color--text);
	font-size: calc(var(--wp--preset--font-size--lg) - 2px);
	font-weight: 500;
	line-height: 1.3;
	margin: 0;
}

/* 2 — What we handle */
.aip-handle {
	background: var(--wp--preset--color--surface);
	padding: var(--wp--preset--spacing--12) 0;
}
.aip-handle-inner {
	position: relative;
	z-index: 1;
	display: grid;
	grid-template-columns: minmax(0, 0.92fr) minmax(0, 1.08fr);
	gap: var(--wp--preset--spacing--9);
	align-items: start;
}
.aip-handle > .aip-handle-inner {
	margin-block-start: 0;
}
/* Same type as the hero's lede above it — one paragraph style down the page. */
.aip-handle .aip-handle-lede {
	color: var(--wp--preset--color--text);
	font-size: var(--wp--preset--font-size--lead);
	font-weight: 400;
	line-height: var(--wp--custom--line-height--body);
	margin: 0 0 var(--wp--preset--spacing--6);
}
.aip-handle .aip-handle-heading {
	color: var(--wp--preset--color--text);
	font-size: var(--wp--preset--font-size--xl);
	font-weight: 700;
	line-height: var(--wp--custom--line-height--tight);
	margin: 0 0 var(--wp--preset--spacing--5);
}
/* Pill tags. A real list block, so tags are added/removed like normal text. */
.aip-handle .aip-tags {
	display: flex;
	flex-wrap: wrap;
	gap: var(--wp--preset--spacing--3);
	list-style: none;
	padding: 0;
	margin: 0 0 var(--wp--preset--spacing--6);
}
.aip-handle .aip-tags li {
	background: var(--wp--preset--color--accent);
	color: #fff;
	/* The site-wide pill size, so these chips read at the same scale as buttons. */
	font-size: var(--pn-pill-font);
	font-weight: 600;
	line-height: 1;
	padding: 8px 14px;
	border-radius: 999px;
	white-space: nowrap;
}
/* Tick list. The check mark is a CSS mask, never typed into the content, so it
   stays the accent colour and every new list item gets one automatically. */
.aip-handle .aip-checks {
	list-style: none;
	padding: 0;
	margin: 0;
}
.aip-handle .aip-checks li {
	position: relative;
	padding-left: 32px;
	margin-bottom: var(--wp--preset--spacing--5);
	color: var(--wp--preset--color--text);
	/* Same body type as the home page's section subtitles (.wp-subtitle). */
	font-size: var(--wp--preset--font-size--body);
	font-weight: 400;
	line-height: var(--wp--custom--line-height--body);
}
.aip-handle .aip-checks li::before {
	content: "";
	position: absolute;
	left: 0;
	top: 3px;
	width: 16px;
	height: 16px;
	background: var(--wp--preset--color--accent);
	-webkit-mask: var(--aip-tick) center / contain no-repeat;
	mask: var(--aip-tick) center / contain no-repeat;
}

/* Representative-work card: navy panel inside a sky frame. */
.aip-card-frame {
	/* No panel of its own — the curve behind the card is the only backdrop. */
	background: none;
	padding: 0;
}
.aip-card {
	position: relative;
	background: var(--wp--preset--color--brand-blue);
	border-radius: 24px;
	padding: var(--wp--preset--spacing--8) var(--wp--preset--spacing--8) var(--wp--preset--spacing--9);
}
/* Pulse icon, top-right — a CSS mask rather than inline SVG, so the card's text
   stays plain editable blocks (KSES would strip an <svg> from post content). */
.aip-card::after {
	content: "";
	position: absolute;
	top: var(--wp--preset--spacing--8);
	right: var(--wp--preset--spacing--8);
	width: 30px;
	height: 30px;
	background: #4295f8;
	-webkit-mask: var(--aip-pulse) center / contain no-repeat;
	mask: var(--aip-pulse) center / contain no-repeat;
}
/* Same type as the hero's lede, like the band's own lede — see .aip-handle-lede. */
.aip-card .aip-card-eyebrow {
	color: #fff;
	font-size: var(--wp--preset--font-size--lead);
	font-weight: 400;
	line-height: var(--wp--custom--line-height--body);
	margin: 0 0 var(--wp--preset--spacing--7);
	padding-right: 48px;
}
.aip-card .aip-card-heading {
	color: #fff;
	font-size: var(--wp--preset--font-size--xl);
	font-weight: 700;
	line-height: var(--wp--custom--line-height--tight);
	margin: 0 0 var(--wp--preset--spacing--5);
}
.aip-card .aip-card-body {
	color: #fff;
	/* Same body type as the tick list opposite it (.wp-subtitle on the home page). */
	font-size: var(--wp--preset--font-size--body);
	line-height: var(--wp--custom--line-height--body);
	margin: 0;
}

/* 3 — How we work */
.aip-how {
	padding: var(--wp--preset--spacing--10) 0 var(--wp--preset--spacing--12);
	/* The step rail bleeds 50vw past each edge (below) so it runs off both sides.
	   Without this clip that bleed widens the whole document and the page scrolls
	   sideways. */
	overflow: hidden;
}
/* Same type as "What we handle:" in the band above (.aip-handle-heading) — a
   section title, not the small uppercase eyebrow it used to be. White, because
   this band is navy; the centring is this section's own layout. */
.aip-how .aip-how-title {
	color: #fff;
	font-size: var(--wp--preset--font-size--xl);
	font-weight: 700;
	line-height: var(--wp--custom--line-height--tight);
	text-align: center;
	margin: 0 0 var(--wp--preset--spacing--10);
}
/* The step line. Numbers come from a CSS counter, so adding or deleting a step
   in the editor renumbers the rest with no markup to touch. */
.aip-how .aip-steps {
	position: relative;
	display: flex;
	justify-content: space-between;
	align-items: flex-start;
	list-style: none;
	counter-reset: aip-step;
	padding: 0;
	margin: 0;
}
/* The rail sits behind the dots and runs off both edges of the container. */
.aip-how .aip-steps::before {
	content: "";
	position: absolute;
	left: -50vw;
	right: -50vw;
	top: 31px;
	height: 2px;
	transform-origin: left center;
	background: #ff3b1f;
	box-shadow: 0 0 12px rgba(255, 106, 77, 0.9);
	z-index: 0;
}
.aip-how .aip-steps li {
	position: relative;
	z-index: 1;
	counter-increment: aip-step;
	flex: 1 1 0;
	min-width: 0;
	text-align: center;
	color: #fff;
	font-size: var(--wp--preset--font-size--xs);
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.14em;
	margin: 0;
	padding-top: 84px;
}
.aip-how .aip-steps li::before {
	content: counter(aip-step, decimal-leading-zero);
	position: absolute;
	top: 0;
	left: 50%;
	transform: translateX(-50%);
	width: 63px;
	height: 63px;
	border-radius: 999px;
	background: var(--wp--preset--color--accent);
	box-shadow: 0 0 18px rgba(255, 106, 77, 0.85);
	color: #fff;
	font-size: var(--pn-pill-font);
	font-weight: 700;
	letter-spacing: 0.04em;
	display: flex;
	align-items: center;
	justify-content: center;
}

/* While the line is animating, anim.js drives the number through --aip-num and
   then removes it, handing the digits back to the CSS counter — so adding or
   deleting a step in the editor still renumbers the rest. If a browser can't
   parse var() here the whole declaration is dropped and the plain counter rule
   above still applies, so the number can never come out blank. */
.aip-how .aip-steps.pn-steps-prime li::before,
.aip-how .aip-steps.pn-steps-in li::before {
	content: var(--aip-num, counter(aip-step, decimal-leading-zero));
}

/* Step line, animated on scroll-in. Same shape as the piracy bar chart: anim.js
   adds `pn-steps-prime` (collapsed, no transition, so nothing is seen moving into
   place) only while the section is below the fold, then swaps in `pn-steps-in`,
   which supplies BOTH the end state and the transition — so the reveal is the
   only thing that animates. No JS / reduced motion → neither class is ever added
   and the section renders finished.

   The beat: the rail draws left-to-right over 0.9s while each dot pops in behind
   it on a stagger, so the line reads as if it were creating the dots. */
.aip-how .aip-steps.pn-steps-prime::before { transform: scaleX(0); }
.aip-how .aip-steps.pn-steps-prime li { opacity: 0; transform: translateY(12px); }
.aip-how .aip-steps.pn-steps-prime li::before { transform: translateX(-50%) scale(0); }

.aip-how .aip-steps.pn-steps-in::before {
	transform: scaleX(1);
	transition: transform 1.3s cubic-bezier(0.22, 0.61, 0.36, 1);
}
.aip-how .aip-steps.pn-steps-in li {
	opacity: 1;
	transform: translateY(0);
	transition: opacity 0.6s ease, transform 0.6s cubic-bezier(0.22, 0.61, 0.36, 1);
}
/* The back-out curve overshoots slightly, so each dot springs rather than grows. */
.aip-how .aip-steps.pn-steps-in li::before {
	transform: translateX(-50%) scale(1);
	transition: transform 0.7s cubic-bezier(0.34, 1.56, 0.64, 1);
}
/* Stagger: dot n lands roughly where the drawing rail has reached. The label
   follows its own dot by 120ms. Covers up to 8 steps, so adding one in the
   editor still animates. Steps of 190ms, matching the slower rail. */
.aip-how .aip-steps.pn-steps-in li:nth-child(1)::before { transition-delay: 0.15s; }
.aip-how .aip-steps.pn-steps-in li:nth-child(2)::before { transition-delay: 0.34s; }
.aip-how .aip-steps.pn-steps-in li:nth-child(3)::before { transition-delay: 0.53s; }
.aip-how .aip-steps.pn-steps-in li:nth-child(4)::before { transition-delay: 0.72s; }
.aip-how .aip-steps.pn-steps-in li:nth-child(5)::before { transition-delay: 0.91s; }
.aip-how .aip-steps.pn-steps-in li:nth-child(6)::before { transition-delay: 1.10s; }
.aip-how .aip-steps.pn-steps-in li:nth-child(7)::before { transition-delay: 1.29s; }
.aip-how .aip-steps.pn-steps-in li:nth-child(8)::before { transition-delay: 1.48s; }
.aip-how .aip-steps.pn-steps-in li:nth-child(1) { transition-delay: 0.31s; }
.aip-how .aip-steps.pn-steps-in li:nth-child(2) { transition-delay: 0.50s; }
.aip-how .aip-steps.pn-steps-in li:nth-child(3) { transition-delay: 0.69s; }
.aip-how .aip-steps.pn-steps-in li:nth-child(4) { transition-delay: 0.88s; }
.aip-how .aip-steps.pn-steps-in li:nth-child(5) { transition-delay: 1.07s; }
.aip-how .aip-steps.pn-steps-in li:nth-child(6) { transition-delay: 1.26s; }
.aip-how .aip-steps.pn-steps-in li:nth-child(7) { transition-delay: 1.45s; }
.aip-how .aip-steps.pn-steps-in li:nth-child(8) { transition-delay: 1.64s; }
/* The pulse — a bright blob that runs the length of the rail once the dots have
   landed, like a signal travelling through the line. Shares the rail's span and
   z-index, so it passes BEHIND the dots. It is a moving background rather than a
   moving element because the rail's -50vw bleed makes its true width unknowable
   in CSS; background-position percentages sweep the full span whatever it is. */
.aip-how .aip-steps::after {
	content: "";
	position: absolute;
	left: -50vw;
	right: -50vw;
	top: 28px;
	height: 8px;
	z-index: 0;
	opacity: 0;
	pointer-events: none;
	border-radius: 999px;
	background-image: linear-gradient(90deg, rgba(255, 106, 77, 0) 0%, rgba(255, 224, 210, 0.95) 50%, rgba(255, 106, 77, 0) 100%);
	background-repeat: no-repeat;
	background-size: 22% 100%;
	background-position: -25% 50%;
}
/* 1.5s in: the last of five dots has just settled. */
.aip-how .aip-steps.pn-steps-in::after {
	animation: aip-pulse 1.15s cubic-bezier(0.4, 0, 0.6, 1) 1.5s 1 both;
}
@keyframes aip-pulse {
	0% { opacity: 0; background-position: -25% 50%; }
	15% { opacity: 1; }
	85% { opacity: 1; }
	100% { opacity: 0; background-position: 125% 50%; }
}
@keyframes aip-pulse-vertical {
	0% { opacity: 0; background-position: 50% -25%; }
	15% { opacity: 1; }
	85% { opacity: 1; }
	100% { opacity: 0; background-position: 50% 125%; }
}

/* anim.js bails under reduced motion so the classes are never added; this only
   covers the preference flipping mid-session. */
@media (prefers-reduced-motion: reduce) {
	.aip-how .aip-steps::before,
	.aip-how .aip-steps::after,
	.aip-how .aip-steps li,
	.aip-how .aip-steps li::before {
		transition: none !important;
		animation: none !important;
		transform: none !important;
	}
	.aip-how .aip-steps::before,
	.aip-how .aip-steps li,
	.aip-how .aip-steps li::before { opacity: 1 !important; }
	.aip-how .aip-steps::after { opacity: 0 !important; }
}

/* Mirror the home hero's tablet/mobile height rule (.mh at 1024px). */
@media (max-width: 1024px) {
	.aip-hero {
		min-height: 60svh;
	}
}
@media (max-width: 900px) {
	.aip-hero-inner,
	.aip-handle-inner {
		grid-template-columns: 1fr;
		gap: var(--wp--preset--spacing--8);
	}
	.aip-hero .aip-hero-heading {
		max-width: none;
	}
	/* Stack the steps: the rail turns vertical and runs down the dots' centre. */
	.aip-how .aip-steps {
		flex-direction: column;
		align-items: stretch;
		gap: var(--wp--preset--spacing--6);
	}
	.aip-how .aip-steps::before {
		left: 31px;
		right: auto;
		top: 0;
		bottom: 0;
		width: 2px;
		height: auto;
	}
	.aip-how .aip-steps li {
		text-align: left;
		padding: 8px 0 8px 84px;
		min-height: 63px;
	}
	.aip-how .aip-steps li::before {
		top: 0;
		left: 0;
		transform: none;
	}
	/* Stacked: the rail is vertical, so it draws downward, and the dots have no
	   translateX(-50%) to compose with. */
	.aip-how .aip-steps::before { transform-origin: center top; }
	.aip-how .aip-steps.pn-steps-prime::before { transform: scaleY(0); }
	.aip-how .aip-steps.pn-steps-in::before { transform: scaleY(1); }
	.aip-how .aip-steps.pn-steps-prime li::before { transform: scale(0); }
	.aip-how .aip-steps.pn-steps-in li::before { transform: scale(1); }
	/* The pulse travels down the rail instead of across it. */
	.aip-how .aip-steps::after {
		left: 28px;
		right: auto;
		top: 0;
		bottom: 0;
		width: 8px;
		height: auto;
		background-image: linear-gradient(180deg, rgba(255, 106, 77, 0) 0%, rgba(255, 224, 210, 0.95) 50%, rgba(255, 106, 77, 0) 100%);
		background-size: 100% 22%;
		background-position: 50% -25%;
	}
	.aip-how .aip-steps.pn-steps-in::after { animation-name: aip-pulse-vertical; }
}
@media (max-width: 768px) {
	/* Join the fluid band rhythm on phones (spec §5): the tall desktop padding
	   gives way to --section, which shrinks 80px -> 48px with the screen. */
	.aip-hero,
	.aip-handle,
	.aip-how {
		padding: var(--wp--preset--spacing--section) 0;
	}
	.aip-card-frame {
		border-radius: 26px;
		padding: 14px;
	}
	.aip-card {
		padding: var(--wp--preset--spacing--7) var(--wp--preset--spacing--6) var(--wp--preset--spacing--8);
	}
}
