@charset "UTF-8";
/* ==========================================================================
   NaxerTech — Design System
   One stylesheet, no build step, no dependencies.

   TWO ART DIRECTIONS, one codebase. Every surface token is declared twice:

     A — "Control Room"   :root[data-theme="dark"]
         Deep OLED-navy, radial mesh glows, glass surfaces on hairline
         borders, live-signal accents. The signature look.

     B — "Daylight"       :root (default) / :root[data-theme="light"]
         Silver-grey canvas, heavy grotesk display type, floating
         components on soft diffused shadows.

   Components never hard-code a colour — they consume semantic tokens only,
   so both directions get identical structure and equal polish.

   1.  Tokens
   2.  Reset & base
   3.  Layout primitives
   4.  Typography
   5.  Buttons & links
   6.  Header / navigation
   7.  Footer
   8.  Hero
   9.  Cards & content blocks
   10. Sections (metrics, marquee, tabs, steps, accordion, testimonials, pricing)
   11. Forms
   12. Blog
   13. Utilities & motion
   ========================================================================== */

/* Registered so gradients and glows animate on the compositor instead of
   being reparsed as strings every frame. */
@property --spot-x {
	syntax: "<length-percentage>";
	inherits: true;
	initial-value: 50%;
}
@property --spot-y {
	syntax: "<length-percentage>";
	inherits: true;
	initial-value: 0%;
}
@property --spot-o {
	syntax: "<number>";
	inherits: true;
	initial-value: 0;
}
/* The hero panel's travelling bezel highlight. Registered so the conic
   gradient's start angle interpolates instead of snapping; where @property is
   missing the ring simply holds still. Rotating the element itself is not an
   option — it would take the border mask with it. */
@property --sim-edge {
	syntax: "<angle>";
	inherits: false;
	initial-value: 0deg;
}

/* ==========================================================================
   1. TOKENS
   ========================================================================== */

:root {
	/* ---------------------------------------------------------- brand ramp */
	/* The logo red held at source; large surfaces use the slightly
	   desaturated --brand so it sits with the neutrals instead of vibrating. */
	--brand-pure: #e8232a;
	--brand: #e33a41;
	--brand-400: #f4676d;
	--brand-600: #c9262d;
	--brand-700: #a51d23;

	/* Signal colours. One accent (red); these are status, not decoration. */
	--live: #12b981;
	--amber: #f0a52b;
	--sky: #3f9bf2;
	--violet: #7b6bf0;
	--cyan: #17b8cf;

	/* Contact details read as links, not as brand marks. Split per theme — no
	   single blue clears 4.5:1 against both a white card and a near-black one
	   (--sky itself only manages 2.9:1 on white). */
	--link-blue: #1668c4;

	/* ------------------------------------------------------------- radii */
	--r-xs: 8px;
	--r-sm: 12px;
	--r-md: 16px;
	--r-lg: 22px;
	--r-xl: 30px;
	--r-2xl: 38px;
	--r-pill: 999px;
	/* Concentric inner radius for the double-bezel shells. */
	--r-inner: calc(var(--r-xl) - 7px);

	/* ------------------------------------------------------------ spacing */
	--s-1: 4px;
	--s-2: 8px;
	--s-3: 12px;
	--s-4: 16px;
	--s-5: 24px;
	--s-6: 32px;
	--s-7: 48px;
	--s-8: 64px;
	--s-9: 96px;
	--s-10: 128px;
	--s-11: 176px;

	/* ------------------------------------------------------------- layout */
	/* Wide enough that the full-bleed product surfaces (the fleet dashboard
	   in particular) run at their native size instead of being squeezed into
	   a column narrower than they were designed for. */
	--container: 1320px;
	--container-wide: 1480px;
	--container-narrow: 820px;
	--gutter: clamp(20px, 5vw, 44px);
	/* Deliberately heavy — the design is meant to breathe. */
	--section-y: clamp(80px, 11vw, 168px);
	--section-y-tight: clamp(56px, 7vw, 104px);
	--header-h: 76px;

	/* --------------------------------------------------------------- type */
	--font-display: "Space Grotesk", "Segoe UI", system-ui, -apple-system, sans-serif;
	--font-body: "Manrope", "Segoe UI", system-ui, -apple-system, sans-serif;
	--font-mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;

	/* Fluid scale. Tight tracking at the large end, open at the small.
	   The whole ramp sits roughly one step above where it started — the page
	   was reading undersized at desktop widths, and every component consumes
	   these tokens rather than hard-coded sizes, so the site scales as one. */
	/* Capped at 4.5rem: the hero headline shares its row with the product shot,
	   so anything larger shreds into ragged three-word lines. */
	--fs-display: clamp(2.75rem, 1.4rem + 4.1vw, 4.5rem);
	--fs-h1: clamp(2.5rem, 1.45rem + 4.2vw, 4.5rem);
	--fs-h2: clamp(2.125rem, 1.45rem + 2.7vw, 3.5rem);
	--fs-h3: clamp(1.5rem, 1.22rem + 1.2vw, 2.125rem);
	--fs-h4: clamp(1.1875rem, 1.1rem + 0.45vw, 1.4375rem);
	--fs-lead: clamp(1.1875rem, 1.09rem + 0.55vw, 1.5rem);
	--fs-body: 1.0625rem;
	--fs-sm: 1rem;
	--fs-xs: 0.875rem;
	--fs-2xs: 0.75rem;

	/* ------------------------------------------------------------- motion */
	/* No linear and no ease-in-out anywhere in this file. */
	--ease: cubic-bezier(0.32, 0.72, 0, 1);
	--ease-out: cubic-bezier(0.16, 1, 0.3, 1);
	--ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
	--t-fast: 0.18s;
	--t: 0.34s;
	--t-slow: 0.62s;
	--t-slower: 0.9s;

	/* ------------------------------------------------------------ z-scale */
	/* Systemic layers only — nothing in this file invents a z-index. */
	--z-base: 1;
	--z-raised: 10;
	--z-sticky: 100;
	/* The drawer sits BELOW the header on purpose: the header carries the
	   burger that closes it, so covering the header would trap the user. */
	--z-drawer: 150;
	--z-header: 200;
	--z-overlay: 400;
	--z-toast: 500;
	--z-grain: 600;
}

/* ==========================================================================
   B — "Daylight"  (default, and the explicit light selection)
   Silver-grey structural canvas, soft highly-diffused ambient shadows.
   ========================================================================== */

:root,
:root[data-theme="light"] {
	color-scheme: light;

	--canvas: #f2f4f8;
	--bg: #f2f4f8;
	--bg-alt: #e9edf3;
	--bg-sunken: #e2e7ee;
	--surface: #ffffff;
	--surface-2: #f7f9fc;
	--surface-3: #eef2f7;
	/* Glass over a light canvas is milky white, not a dark tint. */
	--glass: rgba(255, 255, 255, 0.72);
	--glass-strong: rgba(255, 255, 255, 0.88);

	--hairline: rgba(16, 30, 51, 0.08);
	--hairline-strong: rgba(16, 30, 51, 0.15);
	--border: var(--hairline);
	--border-strong: var(--hairline-strong);
	/* The inset top highlight that makes a surface read as physical. */
	--bevel: inset 0 1px 0 rgba(255, 255, 255, 0.9);
	--bevel-ring: 0 0 0 1px rgba(16, 30, 51, 0.06);
	--shell-bg: rgba(16, 30, 51, 0.035);

	--text: #101d31;
	--text-strong: #060d18;
	--text-muted: #55677f;
	--text-faint: #8496ab;
	--text-on-brand: #ffffff;

	/* Shadows carry the canvas hue — never neutral black. */
	--shadow-xs: 0 1px 2px rgba(23, 43, 77, 0.06);
	--shadow-sm: 0 2px 6px -1px rgba(23, 43, 77, 0.08), 0 1px 2px rgba(23, 43, 77, 0.05);
	--shadow: 0 12px 28px -10px rgba(23, 43, 77, 0.16), 0 3px 8px -3px rgba(23, 43, 77, 0.08);
	--shadow-lg: 0 34px 68px -28px rgba(23, 43, 77, 0.26), 0 10px 24px -12px rgba(23, 43, 77, 0.12);
	--shadow-xl: 0 60px 120px -40px rgba(23, 43, 77, 0.34), 0 18px 44px -20px rgba(23, 43, 77, 0.16);
	--shadow-brand: 0 18px 40px -16px rgba(227, 58, 65, 0.42);

	--brand-soft: rgba(227, 58, 65, 0.09);
	--brand-ring: rgba(227, 58, 65, 0.24);
	--live-soft: rgba(18, 185, 129, 0.12);
	--amber-soft: rgba(240, 165, 43, 0.14);
	--sky-soft: rgba(63, 155, 242, 0.12);

	/* Regions that stay dark in both directions (footer, feature bands). */
	--on-dark: #e9eff8;
	--on-dark-muted: #93a5bd;
	--on-dark-border: rgba(255, 255, 255, 0.11);
	--on-dark-surface: rgba(255, 255, 255, 0.05);
	--band-dark: #0a1424;

	/* Ambient mesh behind the page — soft, cool, barely there. */
	--mesh-1: radial-gradient(58% 44% at 14% 4%, rgba(63, 155, 242, 0.14), transparent 62%);
	--mesh-2: radial-gradient(48% 40% at 88% 0%, rgba(227, 58, 65, 0.1), transparent 60%);
	--mesh-3: radial-gradient(64% 50% at 50% 108%, rgba(123, 107, 240, 0.09), transparent 66%);
	--grain-opacity: 0.022;
	--grain-blend: multiply;
	--grid-line: rgba(16, 30, 51, 0.055);
	--spot-tint: rgba(16, 30, 51, 0.05);

	/* Hero / page-hero. These are what actually make the two directions read
	   as different products rather than one theme with a light-mode toggle:
	   in Daylight the hero is part of the silver canvas, in Control Room it is
	   the deep navy plate. Everything in the hero consumes these, never
	   --on-dark-* directly. */
	--hero-bg: linear-gradient(180deg, #eef1f6 0%, #f6f8fb 62%, var(--canvas) 100%);
	--hero-ink: var(--text-strong);
	--hero-ink-muted: var(--text-muted);
	--hero-line: var(--hairline);
	--hero-surface: rgba(255, 255, 255, 0.66);
	--hero-surface-hover: rgba(255, 255, 255, 0.86);
	--hero-surface-ring: rgba(16, 30, 51, 0.09);
	--hero-glow: radial-gradient(54% 58% at 14% 4%, rgba(63, 155, 242, 0.2), transparent 62%),
		radial-gradient(46% 52% at 88% 0%, rgba(227, 58, 65, 0.16), transparent 60%),
		radial-gradient(58% 48% at 54% 104%, rgba(123, 107, 240, 0.14), transparent 66%);
	--hero-chip-bg: rgba(255, 255, 255, 0.82);
	--hero-chip-ink: var(--text-strong);
	--hero-chip-muted: var(--text-muted);
	--hero-chip-ring: rgba(16, 30, 51, 0.1);
}

/* ==========================================================================
   A — "Control Room"  :root[data-theme="dark"]
   Deep OLED navy, radial mesh glows, glass on hairlines.
   ========================================================================== */

:root[data-theme="dark"] {
	color-scheme: dark;

	--canvas: #050b14;
	--bg: #050b14;
	--bg-alt: #070f1c;
	--bg-sunken: #030710;
	--surface: #0a1322;
	--surface-2: #0e1a2c;
	--surface-3: #132339;
	--glass: rgba(255, 255, 255, 0.035);
	--glass-strong: rgba(255, 255, 255, 0.062);

	--hairline: rgba(255, 255, 255, 0.09);
	--hairline-strong: rgba(255, 255, 255, 0.18);
	--border: var(--hairline);
	--border-strong: var(--hairline-strong);
	--bevel: inset 0 1px 0 rgba(255, 255, 255, 0.12);
	--bevel-ring: 0 0 0 1px rgba(255, 255, 255, 0.06);
	--shell-bg: rgba(255, 255, 255, 0.028);

	--text: #e7eef8;
	--text-strong: #ffffff;
	--text-muted: #9aabc2;
	--text-faint: #6c7f99;
	--text-on-brand: #ffffff;

	/* On near-black a shadow does little — depth comes from bevel and glow.
	   These stay for layering under genuinely floating elements. */
	--shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.5);
	--shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.55);
	--shadow: 0 16px 34px -14px rgba(0, 0, 0, 0.75);
	--shadow-lg: 0 38px 76px -30px rgba(0, 0, 0, 0.85);
	--shadow-xl: 0 64px 130px -44px rgba(0, 0, 0, 0.92);
	--shadow-brand: 0 20px 52px -18px rgba(227, 58, 65, 0.5);

	--brand-soft: rgba(227, 58, 65, 0.15);
	--brand-ring: rgba(227, 58, 65, 0.36);
	--live-soft: rgba(18, 185, 129, 0.15);
	--amber-soft: rgba(240, 165, 43, 0.16);
	--sky-soft: rgba(63, 155, 242, 0.15);

	--link-blue: #6fb2ff;

	--on-dark: #e7eef8;
	--on-dark-muted: #9aabc2;
	--on-dark-border: rgba(255, 255, 255, 0.1);
	--on-dark-surface: rgba(255, 255, 255, 0.04);
	--band-dark: #030710;

	/* The glow field — larger and warmer than the light direction. */
	--mesh-1: radial-gradient(62% 46% at 12% 0%, rgba(63, 155, 242, 0.2), transparent 64%);
	--mesh-2: radial-gradient(54% 44% at 90% 2%, rgba(227, 58, 65, 0.19), transparent 62%);
	--mesh-3: radial-gradient(70% 54% at 50% 106%, rgba(123, 107, 240, 0.16), transparent 68%);
	--grain-opacity: 0.055;
	--grain-blend: overlay;
	--grid-line: rgba(255, 255, 255, 0.045);
	--spot-tint: rgba(255, 255, 255, 0.07);

	/* Hero / page-hero — the deep navy plate. */
	--hero-bg: var(--band-dark);
	--hero-ink: #ffffff;
	--hero-ink-muted: var(--on-dark-muted);
	--hero-line: var(--on-dark-border);
	--hero-surface: var(--on-dark-surface);
	--hero-surface-hover: rgba(255, 255, 255, 0.1);
	--hero-surface-ring: rgba(255, 255, 255, 0.11);
	--hero-glow: radial-gradient(52% 56% at 16% 6%, rgba(63, 155, 242, 0.24), transparent 62%),
		radial-gradient(48% 52% at 86% 0%, rgba(227, 58, 65, 0.24), transparent 60%),
		radial-gradient(60% 50% at 50% 104%, rgba(123, 107, 240, 0.2), transparent 68%);
	--hero-chip-bg: rgba(3, 7, 16, 0.78);
	--hero-chip-ink: #ffffff;
	--hero-chip-muted: var(--on-dark-muted);
	--hero-chip-ring: rgba(255, 255, 255, 0.12);
}

/* Follow the OS on first visit. The inline <head> snippet applies any saved
   choice before first paint, so switching never flashes. */
@media (prefers-color-scheme: dark) {
	:root:not([data-theme]) {
		color-scheme: dark;
	}
}

/* ==========================================================================
   2. RESET & BASE
   ========================================================================== */

*,
*::before,
*::after {
	box-sizing: border-box;
}

* {
	margin: 0;
}

html {
	-webkit-text-size-adjust: 100%;
	scroll-behavior: smooth;
	/* Anchors clear the sticky header instead of hiding beneath it. */
	scroll-padding-top: calc(var(--header-h) + 28px);
}

body {
	min-height: 100dvh;
	background: var(--canvas);
	color: var(--text);
	font-family: var(--font-body);
	font-size: var(--fs-body);
	line-height: 1.65;
	font-weight: 450;
	letter-spacing: -0.005em;
	font-synthesis-weight: none;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
	overflow-x: clip;
	transition: background-color var(--t-slow) var(--ease), color var(--t-slow) var(--ease);
}

/* The ambient field. Fixed, so it never repaints while the page scrolls. */
body::before {
	content: "";
	position: fixed;
	inset: 0;
	z-index: -1;
	pointer-events: none;
	background-color: var(--canvas);
	background-image: var(--mesh-1), var(--mesh-2), var(--mesh-3);
	transition: background-color var(--t-slow) var(--ease);
}

/* Film grain. Fixed and pointer-events:none — it must never ride a
   scrolling container or the GPU repaints continuously. */
body::after {
	content: "";
	position: fixed;
	inset: 0;
	z-index: var(--z-grain);
	pointer-events: none;
	opacity: var(--grain-opacity);
	mix-blend-mode: var(--grain-blend);
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
	transition: opacity var(--t-slow) var(--ease);
}

img,
picture,
svg,
video,
canvas {
	display: block;
	max-width: 100%;
}

img,
video {
	height: auto;
}

/* Ultra-light precise line icons, never chunky strokes.
   `fill` is deliberately NOT reset here: a blanket `fill: none` beats the
   inline fill="currentColor" on the ~160 solid icons (socials, WhatsApp) and
   blanks them out. Stroke icons already carry their own fill="none". */
svg {
	stroke-width: 1.5;
}

input,
button,
textarea,
select {
	font: inherit;
	color: inherit;
}

button {
	background: none;
	border: 0;
	cursor: pointer;
}

ul,
ol {
	padding: 0;
	list-style: none;
}

a {
	color: inherit;
	text-decoration: none;
}

hr {
	border: 0;
	border-top: 1px solid var(--hairline);
}

table {
	border-collapse: collapse;
	width: 100%;
}

::selection {
	background: var(--brand);
	color: #fff;
}

:focus-visible {
	outline: 2px solid var(--brand);
	outline-offset: 3px;
	border-radius: var(--r-xs);
}

:focus:not(:focus-visible) {
	outline: none;
}

.skip-link {
	position: fixed;
	top: var(--s-3);
	left: var(--s-3);
	z-index: var(--z-toast);
	padding: var(--s-3) var(--s-5);
	border-radius: var(--r-pill);
	background: var(--brand);
	color: #fff;
	font-weight: 700;
	font-size: var(--fs-sm);
	box-shadow: var(--shadow-lg);
	transform: translateY(-180%);
	transition: transform var(--t) var(--ease-spring);
}

.skip-link:focus-visible {
	transform: translateY(0);
}

/* ==========================================================================
   3. LAYOUT PRIMITIVES
   ========================================================================== */

.container {
	width: 100%;
	max-width: calc(var(--container) + var(--gutter) * 2);
	margin-inline: auto;
	padding-inline: var(--gutter);
}

.container--wide {
	max-width: calc(var(--container-wide) + var(--gutter) * 2);
}

.container--narrow {
	max-width: calc(var(--container-narrow) + var(--gutter) * 2);
}

.section {
	position: relative;
	/* Optically asymmetric — the eye reads a slightly heavier base as balanced. */
	padding-block: var(--section-y) calc(var(--section-y) * 1.08);
}

.section--tight {
	padding-block: var(--section-y-tight);
}

.section--flush-top {
	padding-top: 0;
}

.section--flush-bottom {
	padding-bottom: 0;
}

/* A tonal step, never a jump to a different colour family. */
.section--alt {
	background: color-mix(in oklab, var(--bg-alt) 88%, transparent);
}

.section--sunken {
	background: var(--bg-sunken);
}

/* A genuinely dark band. In the light direction this is a deliberate
   full-bleed feature with its own glow field, not a copy-paste accident. */
.section--dark {
	background: var(--band-dark);
	color: var(--on-dark);
	isolation: isolate;
	overflow: clip;
}

.section--dark::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	background: radial-gradient(58% 60% at 20% 0%, rgba(63, 155, 242, 0.16), transparent 64%),
		radial-gradient(52% 54% at 84% 6%, rgba(227, 58, 65, 0.16), transparent 60%);
}

.section--dark h1,
.section--dark h2,
.section--dark h3,
.section--dark h4,
.section--dark .h2,
.section--dark .h3 {
	color: #fff;
}

.section--dark .text-muted,
.section--dark .lead {
	color: var(--on-dark-muted);
}

.grid {
	display: grid;
	gap: var(--s-5);
}

/* The track minimums are tuned so that inside the 1320px container these
   settle on exactly 2, 3 and 4 columns. Too low a minimum and auto-fit adds
   an extra column, which strands orphan cards on the last row. */
.grid-2 {
	display: grid;
	gap: var(--s-5);
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 480px), 1fr));
}

.grid-3 {
	display: grid;
	gap: var(--s-5);
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 360px), 1fr));
}

.grid-4 {
	display: grid;
	gap: var(--s-4);
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr));
}

/* Asymmetric editorial split — text column narrower than the media column. */
.split {
	display: grid;
	gap: clamp(var(--s-6), 5vw, var(--s-9));
	align-items: center;
	grid-template-columns: 1fr;
}

@media (min-width: 900px) {
	.split {
		grid-template-columns: minmax(0, 0.92fr) minmax(0, 1.08fr);
	}
	.split--reverse > :first-child {
		order: 2;
	}
	.split--even {
		grid-template-columns: 1fr 1fr;
	}
}

.split--top {
	align-items: start;
}

.stack {
	display: flex;
	flex-direction: column;
	gap: var(--s-4);
}

/* The asymmetric bento. Collapses to one column below 900px, where every
   span override resets — overlapping spans break touch targets on mobile. */
.bento {
	display: grid;
	gap: var(--s-4);
	grid-template-columns: 1fr;
}

@media (min-width: 900px) {
	.bento {
		grid-template-columns: repeat(12, minmax(0, 1fr));
		gap: var(--s-5);
	}
	.bento__item--wide {
		grid-column: span 7;
	}
	.bento__item--narrow {
		grid-column: span 5;
	}
	.bento__item--half {
		grid-column: span 6;
	}
	.bento__item--third {
		grid-column: span 4;
	}
	.bento__item--two-thirds {
		grid-column: span 8;
	}
	.bento__item--full {
		grid-column: span 12;
	}
	.bento__item--tall {
		grid-row: span 2;
	}
}

.section-head {
	/* Widened with the type ramp — at 62ch the larger h2 was breaking into
	   four-line stacks in a container that has room to spare. */
	max-width: 74ch;
	margin-bottom: clamp(var(--s-6), 4vw, var(--s-8));
}

.section-head--center {
	margin-inline: auto;
	text-align: center;
}

.section-head > * + * {
	margin-top: var(--s-4);
}

/* The supporting line under a section heading is a lead whether or not the
   markup remembered to say so — at body size it read as a caption hung off a
   56px headline. The eyebrow is excluded; it sets its own size. */
.section-head p:not(.eyebrow) {
	color: var(--text-muted);
	font-size: var(--fs-lead);
	line-height: 1.6;
	letter-spacing: -0.012em;
}

.section-head--center p:not(.eyebrow) {
	max-width: 68ch;
	margin-inline: auto;
}

/* ==========================================================================
   4. TYPOGRAPHY
   ========================================================================== */

h1,
h2,
h3,
h4,
h5,
h6,
.h1,
.h2,
.h3,
.h4 {
	font-family: var(--font-display);
	color: var(--text-strong);
	font-weight: 600;
	line-height: 1.06;
	/* Negative tracking scaled to size — large type needs more of it. */
	letter-spacing: -0.035em;
	text-wrap: balance;
}

h1,
.h1 {
	font-size: var(--fs-h1);
	letter-spacing: -0.042em;
}

.display {
	font-family: var(--font-display);
	font-size: var(--fs-display);
	font-weight: 600;
	line-height: 0.98;
	letter-spacing: -0.048em;
	color: var(--text-strong);
	text-wrap: balance;
}

h2,
.h2 {
	font-size: var(--fs-h2);
	letter-spacing: -0.038em;
}

h3,
.h3 {
	font-size: var(--fs-h3);
	line-height: 1.18;
	letter-spacing: -0.028em;
}

h4,
.h4 {
	font-size: var(--fs-h4);
	line-height: 1.32;
	letter-spacing: -0.018em;
	font-weight: 600;
}

h5,
h6 {
	font-size: var(--fs-sm);
	line-height: 1.4;
	letter-spacing: -0.01em;
}

p {
	text-wrap: pretty;
}

/* Body copy never runs wider than a comfortable measure. */
.lead {
	font-size: var(--fs-lead);
	line-height: 1.6;
	color: var(--text-muted);
	font-weight: 450;
	max-width: 62ch;
	letter-spacing: -0.012em;
}

.section-head--center .lead,
.center .lead {
	margin-inline: auto;
}

.text-muted {
	color: var(--text-muted);
}

.text-faint {
	color: var(--text-faint);
}

.text-brand {
	color: var(--brand);
}

/* Gradient highlight inside a headline. */
.hl {
	background: linear-gradient(96deg, var(--brand) 0%, var(--brand-400) 46%, var(--amber) 100%);
	-webkit-background-clip: text;
	background-clip: text;
	color: transparent;
	/* Descenders clip without a little breathing room. */
	padding-inline-end: 0.06em;
}

/* Microscopic pill that precedes a major heading. */
.eyebrow {
	display: inline-flex;
	align-items: center;
	gap: var(--s-2);
	padding: 6px 13px 6px 11px;
	border-radius: var(--r-pill);
	background: var(--glass);
	box-shadow: var(--bevel-ring), var(--bevel);
	backdrop-filter: blur(12px);
	-webkit-backdrop-filter: blur(12px);
	color: var(--text-muted);
	font-family: var(--font-mono);
	font-size: var(--fs-2xs);
	font-weight: 500;
	line-height: 1;
	text-transform: uppercase;
	letter-spacing: 0.18em;
	white-space: nowrap;
}

.eyebrow--plain {
	padding: 0;
	background: none;
	box-shadow: none;
	backdrop-filter: none;
	-webkit-backdrop-filter: none;
	color: var(--brand);
}

.eyebrow__dot {
	width: 5px;
	height: 5px;
	border-radius: 50%;
	background: var(--brand);
	box-shadow: 0 0 0 3px var(--brand-soft);
	flex: none;
}

.section--dark .eyebrow {
	color: var(--on-dark-muted);
	background: var(--on-dark-surface);
	box-shadow: 0 0 0 1px var(--on-dark-border), inset 0 1px 0 rgba(255, 255, 255, 0.1);
}

/* Data and figures use tabular lining figures so columns line up. */
/* NB: .plan__price is deliberately absent — despite the name it carries a
   tagline ("Track & recover"), not a figure. This site quotes rather than
   publishes prices. */
.num,
.metric__value,
.spec-table td,
.ring__pct,
.stat__value {
	font-family: var(--font-mono);
	font-variant-numeric: tabular-nums lining-nums;
	font-feature-settings: "tnum" 1, "lnum" 1;
}

/* Long-form article body. */
.prose {
	max-width: 68ch;
	font-size: 1.0625rem;
	line-height: 1.78;
	color: var(--text-muted);
}

.prose > * + * {
	margin-top: 1.25em;
}

.prose h2 {
	margin-top: 2.2em;
	font-size: clamp(1.5rem, 1.2rem + 1.4vw, 2.125rem);
}

.prose h3 {
	margin-top: 1.9em;
	font-size: clamp(1.25rem, 1.1rem + 0.7vw, 1.5rem);
}

.prose h2 + *,
.prose h3 + * {
	margin-top: 0.7em;
}

.prose strong {
	color: var(--text-strong);
	font-weight: 650;
}

.prose a {
	color: var(--brand);
	text-decoration: underline;
	text-underline-offset: 0.22em;
	text-decoration-thickness: 1px;
	text-decoration-color: var(--brand-ring);
	transition: text-decoration-color var(--t) var(--ease);
}

.prose a:hover {
	text-decoration-color: var(--brand);
}

.prose ul,
.prose ol {
	padding-left: 1.3em;
	list-style: disc;
}

.prose ol {
	list-style: decimal;
}

.prose li + li {
	margin-top: 0.5em;
}

.prose li::marker {
	color: var(--brand);
}

.prose blockquote {
	position: relative;
	margin-block: 2em;
	padding: var(--s-5) var(--s-6);
	border-radius: var(--r-lg);
	background: var(--glass);
	box-shadow: var(--bevel-ring);
	font-size: 1.15em;
	line-height: 1.6;
	color: var(--text);
}

.prose blockquote::before {
	content: "";
	position: absolute;
	inset-block: var(--s-4);
	left: 0;
	width: 3px;
	border-radius: var(--r-pill);
	background: linear-gradient(180deg, var(--brand), transparent);
}

.prose figure {
	margin-block: 2em;
}

.prose img {
	border-radius: var(--r-lg);
	box-shadow: var(--shadow);
}

.prose figcaption {
	margin-top: var(--s-3);
	font-size: var(--fs-xs);
	color: var(--text-faint);
}

.prose code {
	font-family: var(--font-mono);
	font-size: 0.88em;
	padding: 0.15em 0.42em;
	border-radius: var(--r-xs);
	background: var(--surface-3);
	color: var(--text-strong);
}

/* ==========================================================================
   5. BUTTONS & LINKS
   ========================================================================== */

.btn {
	--btn-pad-x: 28px;
	--btn-pad-y: 15px;
	position: relative;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 12px;
	padding: var(--btn-pad-y) var(--btn-pad-x);
	border-radius: var(--r-pill);
	font-family: var(--font-body);
	font-size: var(--fs-sm);
	font-weight: 650;
	line-height: 1.2;
	letter-spacing: -0.012em;
	white-space: nowrap;
	cursor: pointer;
	isolation: isolate;
	-webkit-tap-highlight-color: transparent;
	transition: transform var(--t) var(--ease-spring), box-shadow var(--t) var(--ease),
		background-color var(--t) var(--ease), color var(--t) var(--ease), opacity var(--t) var(--ease);
}

/* Physical press. Applies to every variant. */
.btn:active {
	transform: scale(0.975);
	transition-duration: var(--t-fast);
}

.btn[disabled],
.btn[aria-disabled="true"] {
	opacity: 0.45;
	pointer-events: none;
}

/* The trailing icon never sits naked beside the label — it lives in its own
   circular well, flush with the inner padding of the button. */
.btn__icon {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex: none;
	width: 29px;
	height: 29px;
	margin-right: -12px;
	margin-left: 2px;
	border-radius: 50%;
	background: rgba(255, 255, 255, 0.16);
	transition: transform var(--t) var(--ease-spring), background-color var(--t) var(--ease);
}

.btn__icon svg {
	width: 15px;
	height: 15px;
	stroke-width: 1.9;
}

/* Internal kinetic tension: the well travels diagonally, the button does not. */
.btn:hover .btn__icon {
	transform: translate(3px, -1px) scale(1.06);
	background: rgba(255, 255, 255, 0.28);
}

.btn--lg {
	--btn-pad-x: 36px;
	--btn-pad-y: 20px;
	font-size: 1.125rem;
}

.btn--lg .btn__icon {
	width: 33px;
	height: 33px;
	margin-right: -16px;
}

.btn--lg .btn__icon svg {
	width: 17px;
	height: 17px;
}

.btn--lg .btn__icon {
	width: 30px;
	height: 30px;
	margin-right: -14px;
}

.btn--sm {
	--btn-pad-x: 18px;
	--btn-pad-y: 10px;
	/* Pinned like .nav__link — these sit inside the header island. */
	font-size: 0.8125rem;
}

.btn--sm .btn__icon {
	width: 21px;
	height: 21px;
	margin-right: -8px;
}

.btn--sm .btn__icon svg {
	width: 12px;
	height: 12px;
}

.btn--block {
	display: flex;
	width: 100%;
}

/* --------------------------------------------------------------- primary */
.btn--primary {
	background: linear-gradient(180deg, var(--brand-400) -10%, var(--brand) 48%, var(--brand-600) 100%);
	color: #fff;
	box-shadow: var(--shadow-brand), inset 0 1px 0 rgba(255, 255, 255, 0.28),
		inset 0 -1px 0 rgba(0, 0, 0, 0.16), 0 0 0 1px var(--brand-600);
}

.btn--primary:hover {
	transform: translateY(-2px);
	box-shadow: 0 26px 54px -18px rgba(227, 58, 65, 0.6), inset 0 1px 0 rgba(255, 255, 255, 0.34),
		inset 0 -1px 0 rgba(0, 0, 0, 0.16), 0 0 0 1px var(--brand-600);
}

.btn--primary:active {
	transform: translateY(0) scale(0.975);
}

/* ----------------------------------------------------------------- glass */
/* The default secondary. Reads correctly on both art directions. */
.btn--outline,
.btn--ghost-light {
	background: var(--glass);
	color: var(--text-strong);
	box-shadow: var(--bevel-ring), var(--bevel);
	backdrop-filter: blur(14px);
	-webkit-backdrop-filter: blur(14px);
}

.btn--outline:hover,
.btn--ghost-light:hover {
	transform: translateY(-2px);
	background: var(--glass-strong);
	box-shadow: 0 0 0 1px var(--hairline-strong), var(--bevel), var(--shadow);
}

.btn--outline .btn__icon,
.btn--ghost-light .btn__icon {
	background: var(--shell-bg);
}

.btn--outline:hover .btn__icon,
.btn--ghost-light:hover .btn__icon {
	background: var(--brand-soft);
}

/* On an always-dark region the glass button needs the on-dark tokens. */
.section--dark .btn--outline,
.section--dark .btn--ghost-light {
	color: var(--on-dark);
	background: var(--on-dark-surface);
	box-shadow: 0 0 0 1px var(--on-dark-border), inset 0 1px 0 rgba(255, 255, 255, 0.1);
}

.section--dark .btn--outline:hover,
.section--dark .btn--ghost-light:hover {
	background: rgba(255, 255, 255, 0.1);
	box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.22), inset 0 1px 0 rgba(255, 255, 255, 0.14);
}

/* The hero follows the art direction, so its glass button does too. */
.hero .btn--ghost-light,
.hero .btn--outline,
.page-hero .btn--ghost-light,
.page-hero .btn--outline {
	color: var(--hero-ink);
	background: var(--hero-surface);
	box-shadow: 0 0 0 1px var(--hero-surface-ring), inset 0 1px 0 rgba(255, 255, 255, 0.16);
}

.hero .btn--ghost-light:hover,
.hero .btn--outline:hover,
.page-hero .btn--ghost-light:hover,
.page-hero .btn--outline:hover {
	background: var(--hero-surface-hover);
	box-shadow: 0 0 0 1px var(--hero-surface-ring), inset 0 1px 0 rgba(255, 255, 255, 0.22),
		var(--shadow);
}

/* ------------------------------------------------------------------ dark */
.btn--dark {
	background: var(--band-dark);
	color: #fff;
	box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.1), inset 0 1px 0 rgba(255, 255, 255, 0.14),
		var(--shadow);
}

.btn--dark:hover {
	transform: translateY(-2px);
	box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.16), inset 0 1px 0 rgba(255, 255, 255, 0.18),
		var(--shadow-lg);
}

/* -------------------------------------------------------------- tertiary */
/* Reduces visual noise where a third filled button would shout. */
.btn--quiet {
	padding-inline: 6px;
	background: none;
	color: var(--text-muted);
	box-shadow: none;
	font-weight: 600;
}

.btn--quiet:hover {
	color: var(--text-strong);
}

.btn--whatsapp {
	background: linear-gradient(180deg, #34d072 0%, #1da851 100%);
	color: #fff;
	box-shadow: 0 16px 34px -14px rgba(29, 168, 81, 0.5), inset 0 1px 0 rgba(255, 255, 255, 0.28);
}

.btn--whatsapp:hover {
	transform: translateY(-2px);
	box-shadow: 0 24px 48px -16px rgba(29, 168, 81, 0.62), inset 0 1px 0 rgba(255, 255, 255, 0.32);
}

.btn-row {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--s-3);
}

.section-head--center .btn-row,
.center .btn-row {
	justify-content: center;
}

/* ------------------------------------------------------------ text links */
.link-arrow {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	color: var(--brand);
	font-weight: 650;
	font-size: var(--fs-sm);
	letter-spacing: -0.012em;
	transition: gap var(--t) var(--ease), color var(--t) var(--ease);
}

.link-arrow svg {
	width: 15px;
	height: 15px;
	stroke-width: 2;
	transition: transform var(--t) var(--ease-spring);
}

.link-arrow:hover {
	gap: 12px;
}

.link-arrow:hover svg {
	transform: translateX(2px);
}

/* Underline that draws from one side instead of appearing all at once. */
.link-underline {
	position: relative;
	color: var(--text);
	font-weight: 600;
}

.link-underline::after {
	content: "";
	position: absolute;
	left: 0;
	bottom: -3px;
	width: 100%;
	height: 1px;
	background: currentColor;
	transform: scaleX(0);
	transform-origin: right;
	transition: transform var(--t) var(--ease);
}

.link-underline:hover::after {
	transform: scaleX(1);
	transform-origin: left;
}

/* ----------------------------------------------------------- icon button */
.icon-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 40px;
	height: 40px;
	border-radius: 50%;
	color: var(--text-muted);
	background: var(--glass);
	box-shadow: var(--bevel-ring), var(--bevel);
	backdrop-filter: blur(14px);
	-webkit-backdrop-filter: blur(14px);
	transition: transform var(--t) var(--ease-spring), color var(--t) var(--ease),
		background-color var(--t) var(--ease), box-shadow var(--t) var(--ease);
}

.icon-btn svg {
	width: 17px;
	height: 17px;
	stroke-width: 1.7;
}

.icon-btn:hover {
	color: var(--text-strong);
	background: var(--glass-strong);
	transform: translateY(-1px);
}

.icon-btn:active {
	transform: scale(0.94);
}

/* ==========================================================================
   6. HEADER / NAVIGATION
   ========================================================================== */

/* --------------------------------------------------------------- topbar */
.topbar {
	position: relative;
	z-index: var(--z-raised);
	background: var(--band-dark);
	color: var(--on-dark-muted);
	font-size: var(--fs-sm);
	border-bottom: 1px solid rgba(255, 255, 255, 0.06);
}

.topbar__inner {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--s-5);
	min-height: 44px;
	padding-block: 9px;
}

.topbar__contacts {
	display: flex;
	align-items: center;
	gap: var(--s-5);
	flex-wrap: wrap;
}

.topbar__right {
	display: flex;
	align-items: center;
	gap: var(--s-5);
	flex: none;
}

.topbar__item {
	display: inline-flex;
	align-items: center;
	gap: 7px;
	white-space: nowrap;
	letter-spacing: -0.005em;
}

.topbar__item svg {
	width: 15px;
	height: 15px;
	color: var(--brand-400);
	stroke-width: 1.8;
	flex: none;
}

.topbar__item b {
	color: var(--on-dark);
	font-weight: 650;
	font-family: var(--font-mono);
	font-size: var(--fs-2xs);
	letter-spacing: 0.06em;
}

.topbar a {
	color: var(--on-dark-muted);
	transition: color var(--t) var(--ease);
}

.topbar a:hover {
	color: #fff;
}

@media (max-width: 1023px) {
	.topbar__contacts .topbar__item:not(:first-child) {
		display: none;
	}
}

@media (max-width: 600px) {
	.topbar__right {
		display: none;
	}
	.topbar__inner {
		justify-content: center;
	}
}

/* ------------------------------------------------ the floating island nav */
/* Detached from the top edge and contracting as the page scrolls. */
.site-header {
	position: sticky;
	top: 0;
	z-index: var(--z-header);
	padding-top: 16px;
	padding-bottom: 8px;
	transition: padding-top var(--t-slow) var(--ease);
}

.site-header > .container {
	max-width: calc(var(--container-wide) + var(--gutter) * 2);
}

.nav {
	position: relative;
	display: flex;
	align-items: center;
	gap: var(--s-4);
	height: 68px;
	padding-inline: 18px;
	border-radius: var(--r-pill);
	background: var(--glass);
	box-shadow: var(--bevel-ring), var(--bevel);
	/* backdrop-filter only on this sticky element, never on scrolling content. */
	backdrop-filter: blur(20px) saturate(180%);
	-webkit-backdrop-filter: blur(20px) saturate(180%);
	transition: background-color var(--t-slow) var(--ease), box-shadow var(--t-slow) var(--ease),
		height var(--t-slow) var(--ease);
}

/* Once stuck the island tightens and gains a real shadow. */
.site-header.is-stuck {
	padding-top: 8px;
}

.site-header.is-stuck .nav {
	height: 62px;
	background: var(--glass-strong);
	box-shadow: 0 0 0 1px var(--hairline), var(--bevel), var(--shadow-lg);
}

.brand {
	display: inline-flex;
	align-items: center;
	gap: 11px;
	flex: none;
	padding-right: var(--s-2);
	transition: opacity var(--t) var(--ease);
}

.brand img {
	width: auto;
	height: 36px;
	object-fit: contain;
}

.brand:hover {
	opacity: 0.78;
}

.brand__tag {
	display: none;
	padding-left: 11px;
	border-left: 1px solid var(--hairline);
	color: var(--text-faint);
	font-size: 11px;
	font-weight: 600;
	line-height: 1.25;
	letter-spacing: 0.02em;
	text-transform: uppercase;
}

@media (min-width: 1240px) {
	.brand__tag {
		display: block;
	}
}

/* -------------------------------------------------------------- menu bar */
.nav__menu {
	display: none;
	align-items: center;
	gap: 2px;
	margin-inline: auto;
}

@media (min-width: 1080px) {
	.nav__menu {
		display: flex;
	}
}

.nav__item {
	position: relative;
}

.nav__link {
	position: relative;
	display: inline-flex;
	align-items: center;
	gap: 5px;
	padding: 9px 13px;
	border-radius: var(--r-pill);
	color: var(--text-muted);
	/* Deliberately NOT --fs-sm: six top-level items plus the brand and the
	   action buttons only just fit the island at the 1080px breakpoint, so the
	   nav keeps its own size while the page type scales up around it. */
	font-size: 0.9375rem;
	font-weight: 600;
	letter-spacing: -0.014em;
	white-space: nowrap;
	transition: color var(--t) var(--ease), background-color var(--t) var(--ease);
}

.nav__link:hover,
.nav__item:hover > .nav__link,
.nav__item:focus-within > .nav__link {
	color: var(--text-strong);
	background: var(--shell-bg);
}

/* Current page gets a signal dot, not just a colour change. */
.nav__link[aria-current="page"] {
	color: var(--text-strong);
}

.nav__link[aria-current="page"]::after {
	content: "";
	position: absolute;
	left: 50%;
	bottom: 1px;
	width: 5px;
	height: 5px;
	border-radius: 50%;
	background: var(--brand);
	transform: translateX(-50%);
	box-shadow: 0 0 0 3px var(--brand-soft);
}

.nav__caret {
	display: inline-flex;
	transition: transform var(--t) var(--ease);
}

.nav__caret svg {
	width: 12px;
	height: 12px;
	stroke-width: 2;
}

.nav__item:hover > .nav__link .nav__caret,
.nav__item:focus-within > .nav__link .nav__caret {
	transform: rotate(180deg);
}

/* -------------------------------------------------------------- dropdown */
.nav__dropdown {
	position: absolute;
	top: calc(100% + 14px);
	left: 50%;
	z-index: var(--z-header);
	display: grid;
	gap: 2px;
	width: max-content;
	min-width: 268px;
	padding: 8px;
	border-radius: var(--r-lg);
	/* --glass-strong alone is not a surface in the dark theme: it is
	   rgba(255,255,255,0.062), a sheen meant to sit ON something. Used as the
	   only fill it left the panel effectively transparent, and page text read
	   straight through the menu as blurred smudges. The sheen now rides on a
	   real surface, so the panel is opaque in both directions. */
	background: linear-gradient(var(--glass-strong), var(--glass-strong)),
		color-mix(in oklab, var(--surface-2) 94%, transparent);
	box-shadow: var(--bevel-ring), var(--bevel), var(--shadow-xl);
	backdrop-filter: blur(24px) saturate(180%);
	-webkit-backdrop-filter: blur(24px) saturate(180%);
	opacity: 0;
	visibility: hidden;
	transform: translate(-50%, -10px) scale(0.97);
	transform-origin: top center;
	transition: opacity var(--t) var(--ease), transform var(--t) var(--ease-spring),
		visibility var(--t) var(--ease);
}

/* An invisible bridge so the pointer can cross the gap without closing. */
.nav__dropdown::before {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	top: -16px;
	height: 16px;
}

.nav__dropdown--wide {
	grid-template-columns: repeat(2, minmax(0, 1fr));
	min-width: 540px;
}

.nav__item:hover > .nav__dropdown,
.nav__item:focus-within > .nav__dropdown {
	opacity: 1;
	visibility: visible;
	transform: translate(-50%, 0) scale(1);
}

.nav__dropdown a {
	display: block;
	padding: 11px 13px;
	border-radius: var(--r-sm);
	transition: background-color var(--t) var(--ease), transform var(--t) var(--ease);
}

.nav__dropdown a:hover {
	background: var(--shell-bg);
	transform: translateX(2px);
}

.nav__dropdown span {
	display: block;
	color: var(--text-strong);
	font-size: var(--fs-sm);
	font-weight: 650;
	letter-spacing: -0.016em;
}

.nav__dropdown small {
	display: block;
	margin-top: 2px;
	color: var(--text-faint);
	font-size: var(--fs-xs);
	line-height: 1.45;
}

.nav__dropdown a:hover span {
	color: var(--brand);
}

/* --------------------------------------------------------------- actions */
.nav__actions {
	display: none;
	align-items: center;
	gap: var(--s-2);
	flex: none;
	margin-left: auto;
}

@media (min-width: 1080px) {
	.nav__actions {
		display: flex;
		margin-left: 0;
	}
}

.theme-toggle .icon-sun {
	display: none;
}

.theme-toggle .icon-moon {
	display: block;
}

:root[data-theme="dark"] .theme-toggle .icon-sun {
	display: block;
}

:root[data-theme="dark"] .theme-toggle .icon-moon {
	display: none;
}

/* ----------------------------------------------------------- burger morph */
/* Three bars that rotate and translate into a true X, not a swap. */
.burger {
	display: inline-flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 5px;
	width: 44px;
	height: 44px;
	margin-left: auto;
	border-radius: 50%;
	background: var(--shell-bg);
	box-shadow: var(--bevel-ring);
	flex: none;
	transition: background-color var(--t) var(--ease), transform var(--t) var(--ease-spring);
}

.burger:active {
	transform: scale(0.92);
}

@media (min-width: 1080px) {
	.burger {
		display: none;
	}
}

.burger span {
	display: block;
	width: 17px;
	height: 1.5px;
	border-radius: 2px;
	background: var(--text-strong);
	transition: transform var(--t-slow) var(--ease), opacity var(--t-fast) var(--ease);
}

.burger[aria-expanded="true"] span:nth-child(1) {
	transform: translateY(6.5px) rotate(45deg);
}

.burger[aria-expanded="true"] span:nth-child(2) {
	opacity: 0;
	transform: scaleX(0.2);
}

.burger[aria-expanded="true"] span:nth-child(3) {
	transform: translateY(-6.5px) rotate(-45deg);
}

/* ------------------------------------------------------- mobile drawer */
/* A screen-filling glass overlay, not a dropdown strip. */
.mobile-nav {
	position: fixed;
	inset: 0;
	z-index: var(--z-drawer);
	overflow-y: auto;
	overscroll-behavior: contain;
	padding-top: calc(var(--header-h) + 34px);
	padding-bottom: var(--s-8);
	background: color-mix(in oklab, var(--canvas) 82%, transparent);
	backdrop-filter: blur(28px) saturate(160%);
	-webkit-backdrop-filter: blur(28px) saturate(160%);
	opacity: 0;
	visibility: hidden;
	transition: opacity var(--t-slow) var(--ease), visibility var(--t-slow) var(--ease);
}

.mobile-nav.is-open {
	opacity: 1;
	visibility: visible;
}

@media (min-width: 1080px) {
	.mobile-nav {
		display: none;
	}
}

body.nav-open {
	overflow: hidden;
}

/* Each row rises out of an invisible box, staggered by --i set from the JS. */
.mobile-nav__group {
	border-bottom: 1px solid var(--hairline);
	opacity: 0;
	transform: translateY(28px);
	transition: opacity var(--t-slow) var(--ease-out), transform var(--t-slow) var(--ease-out);
	transition-delay: calc(var(--i, 0) * 45ms);
}

.mobile-nav.is-open .mobile-nav__group {
	opacity: 1;
	transform: translateY(0);
}

.mobile-nav__group > a,
.mobile-nav__toggle {
	display: flex;
	align-items: center;
	justify-content: space-between;
	width: 100%;
	padding: 18px 4px;
	color: var(--text-strong);
	font-family: var(--font-display);
	font-size: 1.375rem;
	font-weight: 600;
	letter-spacing: -0.03em;
	text-align: left;
	transition: color var(--t) var(--ease);
}

.mobile-nav__group > a:hover,
.mobile-nav__toggle:hover {
	color: var(--brand);
}

.mobile-nav__toggle svg {
	width: 18px;
	height: 18px;
	color: var(--text-faint);
	stroke-width: 1.8;
	transition: transform var(--t-slow) var(--ease);
}

.mobile-nav__toggle[aria-expanded="true"] svg {
	transform: rotate(180deg);
	color: var(--brand);
}

/* grid-template-rows 0fr -> 1fr animates open height without a magic number. */
.mobile-nav__panel {
	display: grid;
	grid-template-rows: 0fr;
	transition: grid-template-rows var(--t-slow) var(--ease);
}

.mobile-nav__toggle[aria-expanded="true"] + .mobile-nav__panel {
	grid-template-rows: 1fr;
}

.mobile-nav__panel > div {
	overflow: hidden;
}

.mobile-nav__panel a {
	display: block;
	padding: 11px 4px 11px 18px;
	border-left: 1px solid var(--hairline);
	color: var(--text-muted);
	font-size: 1rem;
	font-weight: 550;
	transition: color var(--t) var(--ease), border-color var(--t) var(--ease);
}

.mobile-nav__panel a:last-child {
	margin-bottom: var(--s-4);
}

.mobile-nav__panel a:hover {
	color: var(--brand);
	border-color: var(--brand);
}

.mobile-nav__actions {
	display: grid;
	gap: var(--s-3);
	margin-top: var(--s-7);
	opacity: 0;
	transform: translateY(28px);
	transition: opacity var(--t-slow) var(--ease-out), transform var(--t-slow) var(--ease-out);
	transition-delay: 280ms;
}

.mobile-nav.is-open .mobile-nav__actions {
	opacity: 1;
	transform: translateY(0);
}

/* ==========================================================================
   7. FOOTER

   One footer for the whole site: link columns, office cards, watermark and a
   bottom bar. Every class is namespaced .nx-* so nothing here leaks into the
   page, but the palette is wired to the site's own tokens — the band is
   --band-dark, the same plate every .section--dark uses, so the footer shifts
   with the theme instead of sitting on a fixed navy of its own.

   The --nx-* names below are all dark-band values by definition: this footer
   is dark in both directions, so anything that needs to read against it uses
   the --on-dark-* family rather than --text-*.
   ========================================================================== */

.nx-footer {
	/* The .section--alt band the FAQ sits on, as it composites in the dark
	   theme: color-mix(in oklab, #070f1c 88%, transparent) over --canvas.
	   Pinned rather than var(--bg-alt) because that token goes light (#e9edf3)
	   in the Daylight theme, and this footer is dark in both directions —
	   every colour in it is drawn from the --on-dark-* family. */
	--nx-bg: #070f1b;
	--nx-text: var(--on-dark);
	--nx-muted: var(--on-dark-muted);
	/* No --on-dark-faint exists; this is that step, mixed off the muted tone. */
	--nx-faint: color-mix(in srgb, var(--on-dark-muted) 62%, transparent);
	--nx-border: var(--on-dark-border);
	--nx-accent: var(--brand);
	/* Fixed rather than var(--link-blue) — that token goes dark in the light
	   theme for white cards, which would be unreadable on this band. */
	--nx-link: #6fb2ff;
	--nx-link-hover: #a3c4ff;

	position: relative;
	margin-top: var(--section-y);
	color: var(--nx-text);
	overflow: hidden;
	/* Both ::before and ::after are spent on the corner glows, so the hairline
	   of brand light along the top edge rides in as a background layer. */
	background:
		linear-gradient(90deg, transparent, var(--brand-400), transparent) top center / 76% 1px no-repeat,
		var(--nx-bg);
	/* Lifts off the canvas rather than butting against it — and mirrors the
	   hero, which rounds its bottom corners by the same amount. */
	border-top-left-radius: clamp(var(--r-xl), 4vw, 56px);
	border-top-right-radius: clamp(var(--r-xl), 4vw, 56px);
	transition: background-color var(--t-slow) var(--ease);
}

/* Ambient brand glows, tuned to the same two lights the page mesh uses so the
   band reads as part of the site rather than a slab dropped on the end. */
.nx-footer::before {
	content: "";
	position: absolute;
	top: -240px;
	right: -160px;
	width: 620px;
	height: 460px;
	background: radial-gradient(ellipse, rgba(227, 58, 65, 0.13), transparent 65%);
	pointer-events: none;
}

.nx-footer::after {
	content: "";
	position: absolute;
	bottom: -260px;
	left: -140px;
	width: 520px;
	height: 440px;
	background: radial-gradient(ellipse, rgba(63, 155, 242, 0.09), transparent 65%);
	pointer-events: none;
}

/* Same metrics as .container. The footer was on a 1180px/32px grid of its own,
   so its content edges lined up with nothing in the page above it — the single
   loudest reason the band read as bolted on. */
.nx-footer__inner {
	position: relative;
	width: 100%;
	max-width: calc(var(--container) + var(--gutter) * 2);
	margin: 0 auto;
	padding: clamp(56px, 7vw, 84px) var(--gutter) 0;
}

/* ------------------------------------------------------- link columns */
.nx-links {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: 48px;
	padding-bottom: 56px;
	text-align: center;
}

.nx-links__col h3 {
	font-family: var(--font-mono);
	font-size: var(--fs-2xs);
	font-weight: 700;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	color: var(--nx-faint);
	margin: 0 0 20px;
}

/* align-items, not just text-align: the anchors are width:fit-content so the
   hover underline only spans the label, which means the flex column has to
   centre the boxes themselves. */
.nx-links__col ul {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 13px;
}

.nx-links__col a {
	position: relative;
	display: inline-block;
	font-size: var(--fs-xs);
	color: var(--nx-muted);
	text-decoration: none;
	width: fit-content;
	transition: color var(--t) var(--ease), transform var(--t) var(--ease);
}

/* Thin accent underline that wipes in on hover. */
.nx-links__col a::after {
	content: "";
	position: absolute;
	left: 0;
	bottom: -3px;
	width: 100%;
	height: 1px;
	background: var(--nx-accent);
	transform: scaleX(0);
	transform-origin: left;
	transition: transform var(--t-slow) var(--ease);
}

.nx-links__col a:hover {
	color: var(--nx-text);
}

.nx-links__col a:hover::after {
	transform: scaleX(1);
}

.nx-links__col a:focus-visible {
	outline: 2px solid var(--nx-accent);
	outline-offset: 3px;
	border-radius: 3px;
}

/* ------------------------------------------------------------ divider */
.nx-rule {
	height: 1px;
	border: 0;
	margin: 0 0 44px;
	background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.1) 15%, rgba(255, 255, 255, 0.1) 85%, transparent);
}

/* ------------------------------------------------------- office cards */
.nx-offices {
	display: grid;
	grid-template-columns: repeat(4, minmax(0, 1fr));
	gap: 16px;
	padding-bottom: 60px;
}

.nx-office {
	/* Per-card accent, overridden inline. */
	--office-c: var(--sky);
	position: relative;
	border-radius: var(--r-md);
	padding: 22px 20px;
	/* Transparent fill — the navy band shows straight through. */
	background: rgba(255, 255, 255, 0.028);
	border: 1px solid var(--nx-border);
	backdrop-filter: blur(14px);
	-webkit-backdrop-filter: blur(14px);
	box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05);
	transition: border-color var(--t) var(--ease), background var(--t) var(--ease), transform var(--t) var(--ease);
}

.nx-office:hover {
	border-color: color-mix(in srgb, var(--office-c) 45%, transparent);
	background: color-mix(in srgb, var(--office-c) 7%, rgba(255, 255, 255, 0.028));
	transform: translateY(-3px);
}

.nx-office h4 {
	display: flex;
	align-items: center;
	gap: 9px;
	font-size: var(--fs-sm);
	font-weight: 700;
	color: var(--nx-text);
	margin: 0 0 12px;
}

.nx-office h4 svg {
	width: 15px;
	height: 15px;
	flex-shrink: 0;
}

.nx-office__badge {
	width: 28px;
	height: 28px;
	border-radius: 9px;
	flex-shrink: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	color: var(--office-c);
	background: color-mix(in srgb, var(--office-c) 16%, transparent);
	box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--office-c) 32%, transparent),
		0 6px 16px -10px var(--office-c);
}

.nx-office address {
	font-style: normal;
	font-size: var(--fs-xs);
	line-height: 1.65;
	color: var(--nx-muted);
	margin: 0 0 12px;
}

.nx-office__contact {
	display: flex;
	flex-direction: column;
	gap: 5px;
	padding-top: 12px;
	border-top: 1px solid rgba(255, 255, 255, 0.07);
}

.nx-office__contact a {
	font-size: var(--fs-xs);
	font-weight: 500;
	color: var(--nx-link);
	text-decoration: none;
	width: fit-content;
	transition: color var(--t) var(--ease);
}

.nx-office__contact a:hover {
	color: var(--nx-link-hover);
	text-decoration: underline;
}

.nx-office__contact a:focus-visible {
	outline: 2px solid var(--nx-link);
	outline-offset: 3px;
	border-radius: 3px;
}

/* ---------------------------------------------------------- watermark */
.nx-watermark {
	position: relative;
	height: clamp(88px, 16vw, 210px);
	overflow: hidden;
	pointer-events: none;
	user-select: none;
}

.nx-watermark span {
	position: absolute;
	left: 50%;
	top: 52%;
	transform: translate(-50%, -50%);
	white-space: nowrap;
	font-size: clamp(4.4rem, 16.5vw, 13.5rem);
	font-weight: 800;
	letter-spacing: -0.02em;
	color: rgba(255, 255, 255, 0.038);
}

/* --------------------------------------------------------- bottom bar */
.nx-bottom {
	position: relative;
	width: 100%;
	max-width: calc(var(--container) + var(--gutter) * 2);
	margin: 0 auto;
	padding: 22px var(--gutter) 28px;
	border-top: 1px solid var(--nx-border);
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 16px;
	flex-wrap: wrap;
}

.nx-bottom small {
	font-size: var(--fs-2xs);
	color: var(--nx-faint);
}

.nx-bottom__end {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: 14px 24px;
}

.nx-bottom nav {
	display: flex;
	flex-wrap: wrap;
	gap: 8px 22px;
}

.nx-socials {
	display: flex;
	gap: 8px;
}

.nx-socials a {
	display: grid;
	place-items: center;
	width: 32px;
	height: 32px;
	border-radius: 9px;
	color: var(--nx-muted);
	background: rgba(255, 255, 255, 0.04);
	box-shadow: inset 0 0 0 1px var(--nx-border);
	transition: color var(--t) var(--ease), background var(--t) var(--ease), transform var(--t) var(--ease);
}

.nx-socials a svg {
	width: 15px;
	height: 15px;
}

.nx-socials a:hover {
	color: var(--nx-text);
	background: rgba(255, 255, 255, 0.1);
	transform: translateY(-2px);
}

.nx-socials a:focus-visible {
	outline: 2px solid var(--nx-accent);
	outline-offset: 3px;
}

.nx-bottom nav a {
	font-size: var(--fs-2xs);
	color: var(--nx-muted);
	text-decoration: none;
	transition: color var(--t) var(--ease);
}

.nx-bottom nav a:hover {
	color: var(--nx-text);
}

@media (max-width: 980px) {
	.nx-offices {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (max-width: 720px) {
	.nx-links {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		gap: 36px;
	}
}

@media (max-width: 560px) {
	.nx-links {
		grid-template-columns: 1fr;
		gap: 32px;
	}

	.nx-offices {
		grid-template-columns: 1fr;
	}

	/* Inline padding is left to --gutter so the footer keeps tracking the page
	   margins all the way down; only the stacking changes here. */
	.nx-bottom {
		flex-direction: column;
		align-items: flex-start;
	}
}

@media (prefers-reduced-motion: reduce) {

	.nx-office,
	.nx-socials a,
	.nx-links__col a,
	.nx-links__col a::after {
		transition: none;
	}

	.nx-office:hover,
	.nx-socials a:hover {
		transform: none;
	}
}

/* ==========================================================================
   8. HERO
   ========================================================================== */

.hero {
	position: relative;
	isolation: isolate;
	overflow: clip;
	padding-block: clamp(var(--s-8), 9vw, var(--s-11)) clamp(var(--s-7), 7vw, var(--s-9));
	background: var(--hero-bg);
	color: var(--hero-ink-muted);
	border-bottom-left-radius: clamp(var(--r-xl), 4vw, 56px);
	border-bottom-right-radius: clamp(var(--r-xl), 4vw, 56px);
	transition: background-color var(--t-slow) var(--ease);
}

/* Layer 1 — the glow field. */
.hero__bg {
	position: absolute;
	inset: 0;
	z-index: -2;
	pointer-events: none;
	background: var(--hero-glow);
}

/* Layer 2 — a surveyor grid, faded out toward the edges. */
.hero__grid {
	position: absolute;
	inset: 0;
	z-index: -1;
	pointer-events: none;
	background-image: linear-gradient(var(--grid-line) 1px, transparent 1px),
		linear-gradient(90deg, var(--grid-line) 1px, transparent 1px);
	background-size: 64px 64px;
	mask-image: radial-gradient(72% 62% at 50% 34%, #000 20%, transparent 78%);
	-webkit-mask-image: radial-gradient(72% 62% at 50% 34%, #000 20%, transparent 78%);
}

.hero__inner {
	display: grid;
	gap: clamp(var(--s-7), 6vw, var(--s-9));
	align-items: center;
	grid-template-columns: 1fr;
}

@media (min-width: 1000px) {
	/* The copy column takes the larger share so the headline holds its lines. */
	.hero__inner {
		grid-template-columns: minmax(0, 1.12fr) minmax(0, 0.88fr);
	}
}

.hero h1 {
	color: var(--hero-ink);
	font-size: var(--fs-display);
	line-height: 0.99;
	letter-spacing: -0.048em;
}

.hero__lead {
	max-width: 52ch;
	margin-top: var(--s-5);
	color: var(--hero-ink-muted);
	font-size: var(--fs-lead);
	line-height: 1.6;
	letter-spacing: -0.012em;
}

.hero .btn-row {
	margin-top: var(--s-7);
}

/* Trust strip below the buttons. */
.hero__trust {
	display: flex;
	flex-wrap: wrap;
	gap: var(--s-3) var(--s-6);
	margin-top: var(--s-7);
	padding-top: var(--s-6);
	border-top: 1px solid var(--hero-line);
}

.hero__trust li {
	display: inline-flex;
	align-items: center;
	gap: 10px;
	color: var(--hero-ink-muted);
	font-size: var(--fs-sm);
	font-weight: 550;
}

.hero__trust svg {
	width: 17px;
	height: 17px;
	color: var(--live);
	stroke-width: 2;
	flex: none;
}

/* ==========================================================================
   8b. HERO — PREMIUM PLATE  (.hero--premium, homepage only)
   A jewel-tone colour field instead of a near-black or near-white one, with
   four drifting gradient blobs, a rotating conic sheen, a drifting grid and a
   specular sweep. Every loop animates transform or background-position only,
   so the whole field composites on the GPU and nothing here triggers layout.
   --hero-p (0 → 1, written by initHeroParallax) is how far the hero has been
   scrolled away; every layer reads it at a different rate.
   ========================================================================== */

.hero--premium {
	/* The palette itself comes from the page's plate — see PLATE PALETTES in
	   section 20. Every page in the site draws its hero from the same four
	   hues and four blobs; only the values change. */

	/* The plate carries light ink in BOTH art directions — the hero owns its
	   colour, so these override the per-theme hero tokens rather than
	   following them. Buttons, badges and the trust strip already consume
	   these, so nothing else needs a hero-specific rule. */
	--hero-ink: #ffffff;
	--hero-ink-muted: rgba(228, 233, 255, 0.80);
	--hero-line: rgba(255, 255, 255, 0.16);
	--hero-surface: rgba(255, 255, 255, 0.10);
	--hero-surface-hover: rgba(255, 255, 255, 0.18);
	--hero-surface-ring: rgba(255, 255, 255, 0.22);
	--hero-chip-bg: rgba(23, 16, 54, 0.62);
	--hero-chip-ink: #ffffff;
	--hero-chip-muted: rgba(228, 233, 255, 0.74);
	--hero-chip-ring: rgba(255, 255, 255, 0.16);
	--grid-line: rgba(255, 255, 255, 0.06);

	--hero-p: 0;
	background: var(--h-plate-1);
	/* Tighter than the stock hero: the panel and the scroll cue both have to
	   land inside a 1000px-tall viewport, or neither does its job. */
	padding-block: clamp(var(--s-7), 5vw, 104px) clamp(var(--s-7), 5vw, 88px);
}

/* The live panel is the product shot, so it gets an even split with the copy
   on the wide container rather than the stock 1.12 / 0.88. */
@media (min-width: 1000px) {
	.hero--premium .hero__inner {
		grid-template-columns: minmax(0, 1fr) minmax(0, 1.04fr);
		gap: clamp(var(--s-6), 4vw, var(--s-8));
	}
}


/* Layer 1 — the base field. Four soft corners of colour over the base hue. */
.hero__plate {
	position: absolute;
	inset: 0;
	z-index: -5;
	pointer-events: none;
	background:
		radial-gradient(112% 86% at 8% -6%, var(--h-plate-2), transparent 58%),
		radial-gradient(96% 80% at 96% 2%, var(--h-plate-3), transparent 60%),
		radial-gradient(120% 104% at 44% 118%, var(--h-plate-4), transparent 66%),
		linear-gradient(152deg, var(--h-plate-1) 0%, var(--h-plate-2) 52%, var(--h-plate-1) 100%);
	background-size: 100% 100%, 100% 100%, 100% 100%, 200% 200%;
	animation: hero-plate 30s ease-in-out infinite alternate;
	transform: scale(calc(1 + var(--hero-p) * 0.08));
	transform-origin: 50% 30%;
}

@keyframes hero-plate {
	to {
		background-position: 0 0, 0 0, 0 0, 100% 100%;
	}
}

/* Layer 2 — the aurora. This is the movement you actually read as "live":
   four large blobs on independent drifts, screened over the plate. */
.hero__aurora {
	position: absolute;
	inset: -12% -6%;
	z-index: -4;
	pointer-events: none;
	mix-blend-mode: screen;
	opacity: calc(1 - var(--hero-p) * 0.55);
	transform: translate3d(0, calc(var(--hero-p) * 42px), 0);
	transition: opacity var(--t) var(--ease);
}

.hero__blob {
	position: absolute;
	display: block;
	border-radius: 50%;
	will-change: transform;
}

.hero__blob--a {
	top: -14%;
	left: -8%;
	width: clamp(320px, 44vw, 720px);
	aspect-ratio: 5 / 4;
	background: radial-gradient(circle, var(--h-blob-1), transparent 66%);
	animation: hero-drift-a 26s ease-in-out infinite alternate;
}

.hero__blob--b {
	top: -6%;
	right: -12%;
	width: clamp(300px, 40vw, 660px);
	aspect-ratio: 4 / 3;
	background: radial-gradient(circle, var(--h-blob-2), transparent 68%);
	animation: hero-drift-b 33s ease-in-out infinite alternate;
}

.hero__blob--c {
	bottom: -26%;
	left: 24%;
	width: clamp(360px, 52vw, 840px);
	aspect-ratio: 7 / 5;
	background: radial-gradient(circle, var(--h-blob-3), transparent 70%);
	animation: hero-drift-c 41s ease-in-out infinite alternate;
}

.hero__blob--d {
	top: 34%;
	left: 40%;
	width: clamp(240px, 30vw, 480px);
	aspect-ratio: 1;
	background: radial-gradient(circle, var(--h-blob-4), transparent 68%);
	animation: hero-drift-d 22s ease-in-out infinite alternate;
}

@keyframes hero-drift-a {
	to {
		transform: translate3d(18%, 22%, 0) scale(1.24);
	}
}

@keyframes hero-drift-b {
	to {
		transform: translate3d(-22%, 16%, 0) scale(1.16);
	}
}

@keyframes hero-drift-c {
	to {
		transform: translate3d(-26%, -18%, 0) scale(0.84);
	}
}

@keyframes hero-drift-d {
	to {
		transform: translate3d(24%, -26%, 0) scale(1.3);
	}
}

/* Layer 3 — a conic sheen turning once every three-quarters of a minute.
   Deliberately huge and off-centre: the wedges have to arrive as broad sheets
   of light, and a conic centre inside the frame reads as a cheap starburst. */
.hero__beam {
	position: absolute;
	top: -190%;
	right: -160%;
	bottom: -110%;
	left: -10%;
	z-index: -3;
	pointer-events: none;
	background: conic-gradient(from 0deg,
			transparent 0 6%,
			rgba(190, 228, 255, 0.16) 13%,
			transparent 24%,
			rgba(255, 168, 196, 0.14) 40%,
			transparent 55%,
			rgba(170, 150, 255, 0.18) 72%,
			transparent 86%,
			rgba(120, 240, 220, 0.12) 94%,
			transparent 100%);
	mix-blend-mode: plus-lighter;
	animation: hero-beam 46s linear infinite;
	will-change: transform;
}

@keyframes hero-beam {
	to {
		transform: rotate(360deg);
	}
}

/* Layer 4 — the surveyor grid, drifting exactly one cell so the loop is
   seamless. Scoped to the premium hero; the inner pages keep theirs still. */
.hero--premium .hero__grid {
	inset: -64px;
	mask-image: radial-gradient(76% 66% at 50% 32%, #000 18%, transparent 76%);
	-webkit-mask-image: radial-gradient(76% 66% at 50% 32%, #000 18%, transparent 76%);
	animation: hero-grid 24s linear infinite;
	transform: translate3d(0, calc(var(--hero-p) * 56px), 0);
	will-change: transform;
}

@keyframes hero-grid {
	to {
		transform: translate3d(64px, 64px, 0);
	}
}

/* Layer 5 — one specular sweep, the thing that makes the plate read as glass
   rather than as paint. Long pause, quick pass. */
.hero__glint {
	position: absolute;
	top: -40%;
	left: -40%;
	z-index: -2;
	width: 34%;
	height: 180%;
	pointer-events: none;
	background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.13) 42%,
			rgba(255, 255, 255, 0.2) 50%, rgba(255, 255, 255, 0.13) 58%, transparent);
	transform: rotate(14deg) translate3d(0, 0, 0);
	mix-blend-mode: soft-light;
	animation: hero-glint 13s var(--ease-out) infinite;
	will-change: transform;
}

@keyframes hero-glint {
	0%,
	62% {
		transform: rotate(14deg) translate3d(-30%, 0, 0);
	}
	100% {
		transform: rotate(14deg) translate3d(430%, 0, 0);
	}
}

/* Layer 6 — the plate resolves into the page canvas instead of stopping. */
.hero__veil {
	position: absolute;
	inset: 0;
	z-index: -1;
	pointer-events: none;
	background: linear-gradient(180deg, rgba(9, 6, 26, 0.24) 0%, transparent 26%,
			transparent 62%, rgba(9, 6, 26, 0.34) 100%);
}

/* ------------------------------------------------------- hero copy motion */
/* The copy column rises and fades as the hero leaves; the stage travels
   further and tips back a degree, so the two columns separate in depth. */
.hero--premium .hero__copy {
	position: relative;
	z-index: var(--z-base);
	transform: translate3d(0, calc(var(--hero-p) * -46px), 0);
	opacity: calc(1 - var(--hero-p) * 0.85);
}

.hero--premium h1 {
	text-wrap: balance;
}

/* The gradient headline stops being a flat fill and becomes a slow flow. */
.hl--flow {
	background: linear-gradient(96deg,
			var(--brand-400) 0%,
			#ff9f6e 18%,
			var(--amber) 32%,
			#7ce9ff 52%,
			#a99bff 70%,
			var(--brand-400) 88%,
			var(--amber) 100%);
	background-size: 280% 100%;
	-webkit-background-clip: text;
	background-clip: text;
	animation: hl-flow 11s ease-in-out infinite alternate;
	filter: drop-shadow(0 10px 34px rgba(244, 103, 109, 0.28));
}

@keyframes hl-flow {
	to {
		background-position: 100% 50%;
	}
}

/* --------------------------------------------------------------- scroll cue */
.hero__cue {
	display: inline-flex;
	align-items: center;
	gap: var(--s-3);
	margin-top: clamp(var(--s-7), 5vw, var(--s-8));
	color: var(--hero-ink-muted);
	font-family: var(--font-mono);
	font-size: var(--fs-2xs);
	letter-spacing: 0.2em;
	text-transform: uppercase;
	transition: color var(--t) var(--ease);
}

.hero__cue:hover {
	color: var(--hero-ink);
}

.hero__cue-rail {
	position: relative;
	display: block;
	width: 22px;
	height: 38px;
	flex: none;
	border-radius: var(--r-pill);
	box-shadow: inset 0 0 0 1px var(--hero-surface-ring);
	overflow: hidden;
}

.hero__cue-rail i {
	position: absolute;
	top: 8px;
	left: 50%;
	width: 4px;
	height: 8px;
	margin-left: -2px;
	border-radius: var(--r-pill);
	background: var(--hero-ink);
	animation: hero-cue 2.2s var(--ease-out) infinite;
}

@keyframes hero-cue {
	0% {
		transform: translateY(0);
		opacity: 0;
	}
	28% {
		opacity: 1;
	}
	100% {
		transform: translateY(17px);
		opacity: 0;
	}
}

/* ==========================================================================
   8c. HERO SIMULATION  (.sim)
   The live-ops panel that replaced the product screenshot. Structure is
   markup; the movement inside it is initHeroSim() writing transforms and
   text. Colours come from the signal tokens, never from raw hex.
   ========================================================================== */

/* Two nested elements on purpose: the outer one is the scroll-reveal target
   (it owns the entrance transform), the inner one owns the scroll parallax.
   Composing both on one element means whichever rule wins clobbers the other. */
.hero__stage {
	position: relative;
	z-index: var(--z-base);
}

.hero__stage-in {
	position: relative;
	transform: translate3d(0, calc(var(--hero-p) * -104px), 0);
}

/* The light the panel casts on the plate. Without it the panel reads as a
   sticker on the gradient rather than as something hovering above it. */
.hero__stage-in::before {
	content: "";
	position: absolute;
	inset: 6% -6% -12%;
	z-index: -1;
	pointer-events: none;
	background: radial-gradient(60% 60% at 34% 70%, rgba(34, 211, 238, 0.3), transparent 68%),
		radial-gradient(56% 56% at 78% 40%, rgba(227, 58, 65, 0.26), transparent 66%);
	filter: blur(46px);
	opacity: 0.9;
	animation: stage-glow 14s ease-in-out infinite alternate;
}

@keyframes stage-glow {
	to {
		transform: translate3d(-4%, 3%, 0) scale(1.08);
		opacity: 0.62;
	}
}

.sim {
	--sim-ring: rgba(255, 255, 255, 0.14);
	position: relative;
	border-radius: var(--r-xl);
	background: linear-gradient(168deg, rgba(19, 13, 46, 0.72), rgba(9, 7, 28, 0.86));
	box-shadow: 0 0 0 1px var(--sim-ring), inset 0 1px 0 rgba(255, 255, 255, 0.14),
		0 60px 120px -40px rgba(6, 4, 22, 0.8), 0 22px 48px -22px rgba(6, 4, 22, 0.6);
	backdrop-filter: blur(22px) saturate(1.3);
	-webkit-backdrop-filter: blur(22px) saturate(1.3);
	overflow: hidden;
	/* Illustrative telemetry, not copy. Dragging across it selected a screenful
	   of fake vehicle IDs and flashed the brand-red ::selection over the panel. */
	user-select: none;
	-webkit-user-select: none;
	/* Pointer tilt, written by initTilt(). The panel keeps a hair of
	   perspective at rest so the tilt has somewhere to travel from. */
	transform: perspective(1400px)
		rotateX(calc(var(--tilt-y, 0) * -3.4deg))
		rotateY(calc(var(--tilt-x, 0) * 4.2deg));
	transform-style: preserve-3d;
	transition: transform var(--t-slow) var(--ease-out), box-shadow var(--t-slow) var(--ease);
}

.sim:hover {
	box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.22), inset 0 1px 0 rgba(255, 255, 255, 0.18),
		0 70px 140px -44px rgba(6, 4, 22, 0.86), 0 26px 56px -24px rgba(34, 211, 238, 0.22);
}

/* The travelling edge light. A conic gradient masked to the 1px border, so
   a highlight runs continuously around the bezel. */
.sim::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 3;
	padding: 1px;
	border-radius: inherit;
	background: conic-gradient(from var(--sim-edge),
			rgba(255, 255, 255, 0.14) 0 38%,
			rgba(34, 211, 238, 0.95) 50%,
			rgba(244, 103, 109, 0.95) 62%,
			rgba(255, 255, 255, 0.14) 74% 100%);
	-webkit-mask: linear-gradient(#000, #000) content-box, linear-gradient(#000, #000);
	mask: linear-gradient(#000, #000) content-box, linear-gradient(#000, #000);
	-webkit-mask-composite: xor;
	mask-composite: exclude;
	animation: sim-edge 7s linear infinite;
	pointer-events: none;
}

@keyframes sim-edge {
	to {
		--sim-edge: 360deg;
	}
}

/* ----------------------------------------------------------- window chrome */
.sim__bar {
	position: relative;
	z-index: 2;
	display: flex;
	align-items: center;
	gap: var(--s-3);
	padding: 15px 18px;
	border-bottom: 1px solid rgba(255, 255, 255, 0.08);
	background: rgba(255, 255, 255, 0.04);
}

.sim__dots {
	display: inline-flex;
	gap: 6px;
	flex: none;
}

.sim__dots i {
	width: 9px;
	height: 9px;
	border-radius: 50%;
	background: rgba(255, 255, 255, 0.22);
}

.sim__dots i:first-child {
	background: rgba(244, 103, 109, 0.7);
}

.sim__dots i:nth-child(2) {
	background: rgba(240, 165, 43, 0.7);
}

.sim__dots i:nth-child(3) {
	background: rgba(18, 185, 129, 0.7);
}

.sim__url {
	margin-inline: auto;
	color: rgba(228, 233, 255, 0.6);
	font-family: var(--font-mono);
	font-size: var(--fs-xs);
	letter-spacing: 0.04em;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

.sim__clock {
	flex: none;
	color: rgba(228, 233, 255, 0.86);
	font-family: var(--font-mono);
	font-size: var(--fs-xs);
	font-variant-numeric: tabular-nums;
	letter-spacing: 0.06em;
}

/* ------------------------------------------------------------ panel layout */
.sim__body {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
}

@media (min-width: 560px) {
	.sim__body {
		grid-template-columns: minmax(0, 1fr) minmax(186px, 0.4fr);
	}
}

/* ------------------------------------------------------------------ the map */
.sim__map {
	position: relative;
	aspect-ratio: 16 / 10;
	overflow: hidden;
	background:
		radial-gradient(72% 62% at 62% 28%, rgba(34, 211, 238, 0.12), transparent 68%),
		radial-gradient(60% 60% at 12% 90%, rgba(139, 92, 246, 0.16), transparent 70%),
		linear-gradient(160deg, #131038, #0b0a24);
}

.sim__svg {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	display: block;
}

/* ground texture */
.sim__blocks rect {
	fill: rgba(255, 255, 255, 0.042);
	stroke: rgba(255, 255, 255, 0.07);
	stroke-width: 1;
}

.sim__roads path {
	fill: none;
	stroke: rgba(190, 208, 255, 0.14);
	stroke-width: 7;
	stroke-linecap: round;
}

/* the geofence */
.sim__zone-fill {
	fill: rgba(34, 211, 238, 0.05);
	stroke: none;
}

.sim__zone-ring {
	fill: none;
	stroke: rgba(34, 211, 238, 0.5);
	stroke-width: 1.4;
	stroke-dasharray: 7 9;
	transform-box: fill-box;
	transform-origin: 50% 50%;
	animation: sim-zone 30s linear infinite;
}

@keyframes sim-zone {
	to {
		transform: rotate(360deg);
	}
}

.sim__zone-pulse {
	fill: none;
	stroke: rgba(34, 211, 238, 0.45);
	stroke-width: 1.2;
	transform-box: fill-box;
	transform-origin: 50% 50%;
	animation: sim-zone-pulse 3.6s var(--ease-out) infinite;
}

@keyframes sim-zone-pulse {
	0% {
		transform: scale(0.72);
		opacity: 0.65;
	}
	70%,
	100% {
		transform: scale(1.18);
		opacity: 0;
	}
}

/* routes and the signal pulse that runs along each one */
.sim__route {
	fill: none;
	stroke-width: 2.2;
	stroke-linecap: round;
}

.sim__pulse {
	fill: none;
	stroke: rgba(255, 255, 255, 0.92);
	stroke-width: 2.6;
	stroke-linecap: round;
	stroke-dasharray: 26 1400;
	filter: drop-shadow(0 0 6px rgba(124, 233, 255, 0.9));
	animation: sim-pulse 5.4s var(--ease) infinite;
}

.sim__pulse--b {
	animation-duration: 6.8s;
	animation-delay: 1.2s;
	filter: drop-shadow(0 0 6px rgba(18, 185, 129, 0.9));
}

.sim__pulse--c {
	animation-duration: 8s;
	animation-delay: 2.4s;
	filter: drop-shadow(0 0 6px rgba(240, 165, 43, 0.9));
}

@keyframes sim-pulse {
	0% {
		stroke-dashoffset: 1420;
		opacity: 0;
	}
	8%,
	88% {
		opacity: 1;
	}
	100% {
		stroke-dashoffset: -40;
		opacity: 0;
	}
}

.sim__stops circle {
	fill: rgba(9, 7, 28, 0.9);
	stroke: rgba(255, 255, 255, 0.55);
	stroke-width: 1.6;
}

/* the tracked unit's breadcrumb */
.sim__trail {
	fill: none;
	stroke-width: 2.4;
	stroke-linecap: round;
	stroke-linejoin: round;
}

/* ---------------------------------------------------------------- vehicles */
.sim__veh {
	--veh: var(--live);
}

.sim__veh-halo {
	fill: var(--veh);
	opacity: 0.16;
	transform-box: fill-box;
	transform-origin: 50% 50%;
	animation: sim-veh-halo 2.6s var(--ease-out) infinite;
}

@keyframes sim-veh-halo {
	0% {
		transform: scale(0.5);
		opacity: 0.3;
	}
	75%,
	100% {
		transform: scale(1.5);
		opacity: 0;
	}
}

.sim__veh-body {
	fill: var(--veh);
	stroke: rgba(9, 7, 28, 0.85);
	stroke-width: 1.2;
}

.sim__veh-arrow {
	fill: #fff;
}

/* the lock-on reticle that follows the tracked unit */
.sim__lock {
	fill: none;
	stroke: rgba(255, 255, 255, 0.75);
	stroke-width: 1.4;
	stroke-linecap: round;
	transform-box: fill-box;
	transform-origin: 50% 50%;
	animation: sim-lock 3s var(--ease-out) infinite;
}

@keyframes sim-lock {
	0%,
	100% {
		transform: scale(1);
		opacity: 0.8;
	}
	50% {
		transform: scale(0.88);
		opacity: 1;
	}
}

/* ------------------------------------------------------------ map overlays */
/* The radar sweep. A conic wedge, circular-masked, turning over the map. */
.sim__sweep {
	position: absolute;
	top: 50%;
	left: 50%;
	width: 150%;
	aspect-ratio: 1;
	margin: -75% 0 0 -75%;
	pointer-events: none;
	background: conic-gradient(from 0deg, rgba(34, 211, 238, 0.22) 0 6%, transparent 18% 100%);
	-webkit-mask: radial-gradient(circle, #000 0 62%, transparent 72%);
	mask: radial-gradient(circle, #000 0 62%, transparent 72%);
	mix-blend-mode: screen;
	animation: sim-sweep 7.5s linear infinite;
	will-change: transform;
}

@keyframes sim-sweep {
	to {
		transform: rotate(360deg);
	}
}

/* A CRT line falling down the map — the cheapest possible "this is a feed". */
.sim__scanline {
	position: absolute;
	inset-inline: 0;
	top: 0;
	height: 28%;
	pointer-events: none;
	background: linear-gradient(180deg, transparent, rgba(124, 233, 255, 0.08) 78%,
			rgba(124, 233, 255, 0.22));
	animation: sim-scan 6s var(--ease-out) infinite;
	will-change: transform;
}

@keyframes sim-scan {
	0% {
		transform: translateY(-100%);
		opacity: 0;
	}
	12%,
	72% {
		opacity: 1;
	}
	100% {
		transform: translateY(380%);
		opacity: 0;
	}
}

/* glass readouts pinned over the map */
.sim__hud {
	position: absolute;
	z-index: 2;
	padding: 10px 13px;
	border-radius: var(--r-sm);
	background: rgba(11, 8, 32, 0.62);
	box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.12), inset 0 1px 0 rgba(255, 255, 255, 0.14),
		0 18px 34px -18px rgba(4, 2, 16, 0.9);
	backdrop-filter: blur(14px);
	-webkit-backdrop-filter: blur(14px);
	color: rgba(228, 233, 255, 0.78);
}

.sim__hud--track {
	top: 16px;
	left: 16px;
	min-width: 168px;
}

.sim__hud--fuel {
	right: 16px;
	bottom: 16px;
	min-width: 132px;
}

.sim__hud-k {
	display: flex;
	align-items: center;
	gap: 6px;
	color: rgba(228, 233, 255, 0.6);
	font-family: var(--font-mono);
	font-size: 0.6875rem;
	letter-spacing: 0.16em;
	text-transform: uppercase;
}

.sim__hud-id {
	margin-top: 5px;
	color: #fff;
	font-family: var(--font-mono);
	font-size: var(--fs-sm);
	font-weight: 600;
	letter-spacing: 0.02em;
}

.sim__hud-row {
	display: flex;
	gap: var(--s-5);
	margin-top: 8px;
}

.sim__hud-row span {
	display: flex;
	align-items: baseline;
	gap: 3px;
}

.sim__hud-row b {
	color: #fff;
	font-family: var(--font-mono);
	font-size: 1.25rem;
	font-weight: 600;
	font-variant-numeric: tabular-nums;
	line-height: 1;
}

.sim__hud-row i {
	color: rgba(228, 233, 255, 0.5);
	font-size: 0.6875rem;
	font-style: normal;
}

.sim__hud-v {
	margin-top: 4px;
	color: #fff;
	font-family: var(--font-mono);
	font-size: 1.25rem;
	font-variant-numeric: tabular-nums;
	line-height: 1.1;
}

.sim__meter {
	display: block;
	height: 5px;
	margin-top: 8px;
	border-radius: var(--r-pill);
	background: rgba(255, 255, 255, 0.14);
	overflow: hidden;
}

.sim__meter i {
	display: block;
	height: 100%;
	border-radius: inherit;
	background: linear-gradient(90deg, var(--live), #7ce9ff);
	transition: width 1.2s var(--ease-out), background var(--t-slow) var(--ease);
}

.sim__meter i.is-low {
	background: linear-gradient(90deg, var(--amber), var(--brand-400));
}

/* --------------------------------------------------------------- event feed */
/* The column is a fixed window onto the feed: the inner block is out of flow,
   so however many rows are in it — and however many lines each of those rows
   wraps to — the panel's height never moves. Rows past the bottom fade out
   under the mask instead of being cut in half. */
.sim__side {
	position: relative;
	min-height: 168px;
	overflow: hidden;
	border-top: 1px solid rgba(255, 255, 255, 0.08);
	background: rgba(255, 255, 255, 0.025);
}

.sim__side-in {
	position: absolute;
	inset: 15px 16px;
	display: flex;
	flex-direction: column;
	-webkit-mask-image: linear-gradient(180deg, #000 0 78%, transparent 98%);
	mask-image: linear-gradient(180deg, #000 0 78%, transparent 98%);
}

@media (min-width: 560px) {
	.sim__side {
		min-height: 0;
		border-top: 0;
		border-left: 1px solid rgba(255, 255, 255, 0.08);
	}
}

.sim__side-h {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--s-2);
	color: rgba(228, 233, 255, 0.58);
	font-family: var(--font-mono);
	font-size: 0.6875rem;
	letter-spacing: 0.16em;
	text-transform: uppercase;
}

.sim__side-n {
	padding: 2px 8px;
	border-radius: var(--r-pill);
	background: rgba(34, 211, 238, 0.16);
	color: #9beeff;
	font-size: 0.6875rem;
	letter-spacing: 0.04em;
	font-variant-numeric: tabular-nums;
}

.sim__feed {
	display: flex;
	flex-direction: column;
	gap: 11px;
	margin-top: 14px;
	list-style: none;
	padding: 0;
}

.sim__event {
	display: grid;
	grid-template-columns: 8px minmax(0, 1fr);
	gap: 10px;
	padding-bottom: 11px;
	border-bottom: 1px solid rgba(255, 255, 255, 0.06);
	/* Rows arrive from above and settle; initHeroSim adds .is-in next frame. */
	opacity: 0;
	transform: translateY(-10px);
	filter: blur(3px);
	transition: opacity var(--t-slow) var(--ease-out), transform var(--t-slow) var(--ease-out),
		filter var(--t-slow) var(--ease-out);
}

.sim__event.is-in {
	opacity: 1;
	transform: none;
	filter: blur(0);
}

.sim__event.is-out {
	opacity: 0;
	transform: translateY(10px);
}

.sim__event:last-child {
	border-bottom: 0;
}

.sim__event-dot {
	width: 8px;
	height: 8px;
	margin-top: 6px;
	border-radius: 50%;
	background: var(--ev, var(--live));
	box-shadow: 0 0 0 4px color-mix(in srgb, var(--ev, var(--live)) 22%, transparent);
}

.sim__event-t {
	color: rgba(233, 238, 255, 0.9);
	font-size: 0.8125rem;
	line-height: 1.4;
}

.sim__event-m {
	display: block;
	margin-top: 1px;
	color: rgba(228, 233, 255, 0.48);
	font-family: var(--font-mono);
	font-size: 0.6875rem;
	letter-spacing: 0.04em;
}

/* ------------------------------------------------------------- panel footer */
.sim__foot {
	display: flex;
	flex-wrap: wrap;
	gap: var(--s-2) var(--s-6);
	padding: 14px 18px;
	border-top: 1px solid rgba(255, 255, 255, 0.08);
	background: rgba(255, 255, 255, 0.04);
}

.sim__stat {
	display: inline-flex;
	align-items: baseline;
	gap: 6px;
	color: rgba(228, 233, 255, 0.62);
	font-size: var(--fs-xs);
}

.sim__stat b {
	color: #fff;
	font-family: var(--font-mono);
	font-size: var(--fs-sm);
	font-variant-numeric: tabular-nums;
}

.sim__stat--warn b {
	color: var(--amber);
}

.sim__stat--ok b {
	color: #6ff0c0;
}

.sim__stat--brand b {
	color: var(--brand-400);
}

/* ---------------------------------------------------------- floating chip */
/* Hung off the panel's bottom-left corner — outside the map, clear of every
   readout — and never quite still, so the composition keeps breathing. */
/* Fully clear of the panel — every edge of it is already carrying a readout,
   so the callout hangs below the bottom-left corner instead of over one. */
.chip-float--stage {
	left: 4%;
	bottom: -112px;
}

.hero__stage-in .chip-float {
	animation: chip-bob 7s ease-in-out infinite alternate;
}

@media (max-width: 999px) {
	/* Stacked layout: the space under the panel belongs to the scroll cue.
	   Two classes deep on purpose — the base .chip-float sets display:flex
	   further down the file, and a single class would lose to it. */
	.hero__stage-in .chip-float--stage {
		display: none;
	}
}

@keyframes chip-bob {
	to {
		transform: translate3d(0, -11px, 0);
	}
}

@media (max-width: 860px) {
	/* The panel is already dense; below this the side feed and the reticle
	   readouts start fighting each other for the same 300px. */
	.sim__hud--fuel {
		display: none;
	}
}

@media (max-width: 640px) {
	.sim__map {
		aspect-ratio: 4 / 3;
	}

	/* The chrome bar carries three things and has room for two. */
	.sim__url {
		display: none;
	}

	.sim__clock {
		margin-inline: auto;
	}

	/* At this width the reticle readout was eating a third of the map. */
	.sim__hud--track {
		top: 10px;
		left: 10px;
		min-width: 0;
		padding: 8px 11px;
	}

	.sim__hud-id {
		font-size: var(--fs-xs);
	}

	.sim__hud-row {
		gap: var(--s-4);
	}

	.sim__hud-row b,
	.sim__hud-v {
		font-size: 1.0625rem;
	}

	/* A fixed 2 × 2 so a digit gaining a character cannot reflow the panel. */
	.sim__foot {
		display: grid;
		grid-template-columns: 1fr 1fr;
		gap: var(--s-2) var(--s-4);
	}
}

@media (max-width: 559px) {
	/* Stacked: the feed column has no map beside it to take its height from. */
	.sim__side {
		min-height: 146px;
	}
}

/* Phones: keep the aurora and the sweep (they are pure compositor work) but
   drop the two loops that repaint a full-bleed gradient every frame. */
@media (max-width: 860px) {
	.hero__plate {
		animation: none;
	}

	.hero__beam,
	.hero__glint {
		display: none;
	}
}

/* ==========================================================================
   9. CARDS & CONTENT BLOCKS
   ========================================================================== */

/* -------------------------------------------------- the double bezel */
/* Nothing premium sits flat on the canvas. A card is an outer shell (the
   tray) holding an inner core (the plate), with concentric radii. */
.card {
	position: relative;
	display: flex;
	flex-direction: column;
	/* One step above --s-6 (32px) at desktop, easing back to it on narrow
	   screens where the gutter is already doing the work. */
	padding: clamp(var(--s-6), 2.6vw, 40px);
	border-radius: var(--r-xl);
	background: var(--surface);
	box-shadow: var(--bevel-ring), var(--bevel), var(--shadow-sm);
	isolation: isolate;
	transition: transform var(--t-slow) var(--ease), box-shadow var(--t-slow) var(--ease),
		background-color var(--t) var(--ease);
}

/* The cursor spotlight, shared by every raised surface. Driven by
   --spot-x/--spot-y from the JS, and by --spot-o so it fades in rather
   than snapping on.

   `isolation: isolate` on the host is what lets the z-index:-1 pseudo paint
   above the card's own background but still below its content. */
.card,
.plan,
.quote-card,
.post-card,
.industry-card,
.device-card,
.office-card,
.dl-item,
.form-card {
	isolation: isolate;
}

.card::before,
.plan::before,
.quote-card::before,
.post-card::before,
.industry-card::before,
.device-card::before,
.office-card::before,
.dl-item::before,
.form-card::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	border-radius: inherit;
	pointer-events: none;
	opacity: var(--spot-o, 0);
	background: radial-gradient(220px circle at var(--spot-x) var(--spot-y), var(--spot-tint), transparent 70%);
	transition: opacity var(--t-slow) var(--ease);
}

.card:hover {
	transform: translateY(-4px);
	box-shadow: 0 0 0 1px var(--hairline-strong), var(--bevel), var(--shadow-lg);
}

/* A card that is a link gets the whole surface as the hit area. */
.card--link::after {
	content: "";
	position: absolute;
	inset: 0;
	border-radius: inherit;
}

.card__head {
	display: flex;
	align-items: flex-start;
	gap: var(--s-4);
	margin-bottom: var(--s-4);
}

.card h3,
.card .h3 {
	font-size: var(--fs-h4);
	letter-spacing: -0.022em;
}

.card p {
	color: var(--text-muted);
	font-size: var(--fs-sm);
	line-height: 1.66;
}

.card > * + * {
	margin-top: var(--s-3);
}

.card__head + * {
	margin-top: 0;
}

/* Pins the CTA to the base so a row of cards forms one clean line. */
.card__foot {
	margin-top: auto;
	padding-top: var(--s-5);
}

.card--flat {
	background: transparent;
	box-shadow: none;
	padding: 0;
}

.card--flat:hover {
	transform: none;
	box-shadow: none;
}

/* Glass variant for use over dark bands and the hero. */
.card--glass {
	background: var(--on-dark-surface);
	box-shadow: 0 0 0 1px var(--on-dark-border), inset 0 1px 0 rgba(255, 255, 255, 0.09);
	color: var(--on-dark);
	backdrop-filter: blur(16px);
	-webkit-backdrop-filter: blur(16px);
}

.card--glass h3,
.card--glass .h3 {
	color: #fff;
}

.card--glass p {
	color: var(--on-dark-muted);
}

.card--dark {
	background: var(--band-dark);
	color: var(--on-dark);
	box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.08), inset 0 1px 0 rgba(255, 255, 255, 0.1),
		var(--shadow-lg);
}

.card--dark h3,
.card--dark .h3 {
	color: #fff;
}

.card--dark p {
	color: var(--on-dark-muted);
}

/* Accent card — a brand-lit top edge instead of a coloured fill. */
.card--accent {
	overflow: hidden;
}

.card--accent::after {
	content: "";
	position: absolute;
	top: 0;
	left: 10%;
	right: 10%;
	height: 1px;
	background: linear-gradient(90deg, transparent, var(--brand), transparent);
}

/* ------------------------------------------------------------ icon tiles */
.icon-tile {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 58px;
	height: 58px;
	flex: none;
	border-radius: var(--r-md);
	color: var(--brand);
	background: var(--brand-soft);
	box-shadow: inset 0 0 0 1px var(--brand-ring), inset 0 1px 0 rgba(255, 255, 255, 0.14);
	transition: transform var(--t-slow) var(--ease-spring), background-color var(--t) var(--ease);
}

.icon-tile svg {
	width: 27px;
	height: 27px;
	stroke-width: 1.6;
}

.card:hover .icon-tile {
	transform: translateY(-2px) rotate(-4deg);
}

.icon-tile--sm {
	width: 44px;
	height: 44px;
	border-radius: var(--r-sm);
}

.icon-tile--sm svg {
	width: 21px;
	height: 21px;
}

.icon-tile--live {
	color: var(--live);
	background: var(--live-soft);
	box-shadow: inset 0 0 0 1px rgba(18, 185, 129, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.14);
}

.icon-tile--amber {
	color: var(--amber);
	background: var(--amber-soft);
	box-shadow: inset 0 0 0 1px rgba(240, 165, 43, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.14);
}

.icon-tile--sky {
	color: var(--sky);
	background: var(--sky-soft);
	box-shadow: inset 0 0 0 1px rgba(63, 155, 242, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.14);
}

/* Per-tile hue. The card sets `--tile-c` inline (a token, not a raw hex) and
   the fill, ring and glow are all mixed from it, so one rule covers every
   colour in a grid without a modifier class per hue. */
.icon-tile--tint {
	--tile-c: var(--brand);
	color: var(--tile-c);
	background: linear-gradient(150deg,
			color-mix(in srgb, var(--tile-c) 22%, transparent),
			color-mix(in srgb, var(--tile-c) 8%, transparent));
	box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--tile-c) 30%, transparent),
		inset 0 1px 0 rgba(255, 255, 255, 0.16);
	transition: transform var(--t-slow) var(--ease-spring), box-shadow var(--t) var(--ease),
		background var(--t) var(--ease);
}

.card:hover .icon-tile--tint {
	box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--tile-c) 46%, transparent),
		inset 0 1px 0 rgba(255, 255, 255, 0.2),
		0 12px 26px -14px var(--tile-c);
	background: linear-gradient(150deg,
			color-mix(in srgb, var(--tile-c) 30%, transparent),
			color-mix(in srgb, var(--tile-c) 12%, transparent));
}

/* ---------------------------------------------------------------- badges */
/* No `white-space: nowrap` here on purpose. Badges carry short flags in some
   places and whole stat sentences in others ("Up to 35% lower running cost per
   vehicle"); nowrap makes the long ones set the min-content width of their
   grid track and push the page sideways at 320px. Short badges do not wrap
   anyway, so wrapping costs nothing and the layout stops depending on copy
   length. .plan__flag opts back in — it is absolutely positioned. */
.badge {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	max-width: 100%;
	padding: 6px 12px;
	/* Square-ish, not a pill — pills on every label read as boilerplate. */
	border-radius: var(--r-xs);
	background: var(--brand-soft);
	color: var(--brand);
	font-family: var(--font-mono);
	font-size: var(--fs-2xs);
	font-weight: 500;
	line-height: 1.35;
	letter-spacing: 0.09em;
	text-transform: uppercase;
}

.badge .dot-live {
	/* Keeps the dot on the first line when the label wraps. */
	align-self: flex-start;
	margin-top: 0.32em;
}

.badge--live {
	background: var(--live-soft);
	color: var(--live);
}

.badge--neutral {
	background: var(--shell-bg);
	color: var(--text-muted);
}

.badge--on-dark {
	background: var(--on-dark-surface);
	color: var(--on-dark);
	box-shadow: inset 0 0 0 1px var(--on-dark-border);
}

/* The pulsing live dot. */
.dot-live {
	position: relative;
	display: inline-block;
	width: 7px;
	height: 7px;
	flex: none;
	border-radius: 50%;
	background: var(--live);
}

.dot-live::after {
	content: "";
	position: absolute;
	inset: 0;
	border-radius: 50%;
	background: var(--live);
	animation: pulse-ring 2.4s var(--ease-out) infinite;
}

@keyframes pulse-ring {
	0% {
		transform: scale(1);
		opacity: 0.7;
	}
	70%,
	100% {
		transform: scale(3.2);
		opacity: 0;
	}
}

.chip {
	display: inline-flex;
	align-items: center;
	gap: 7px;
	padding: 8px 14px;
	border-radius: var(--r-pill);
	background: var(--glass);
	box-shadow: var(--bevel-ring), var(--bevel);
	color: var(--text-muted);
	font-size: var(--fs-xs);
	font-weight: 600;
	white-space: nowrap;
	transition: color var(--t) var(--ease), background-color var(--t) var(--ease),
		transform var(--t) var(--ease-spring);
}

a.chip:hover {
	color: var(--text-strong);
	background: var(--glass-strong);
	transform: translateY(-2px);
}

.chip svg {
	width: 14px;
	height: 14px;
	color: var(--brand);
	stroke-width: 1.9;
}

.chip-grid {
	display: flex;
	flex-wrap: wrap;
	gap: var(--s-2);
}

/* Chips that float over hero media. */
.chip-float {
	position: absolute;
	z-index: var(--z-raised);
	display: flex;
	align-items: center;
	gap: 13px;
	padding: 13px 18px;
	border-radius: var(--r-md);
	background: var(--hero-chip-bg);
	box-shadow: 0 0 0 1px var(--hero-chip-ring), inset 0 1px 0 rgba(255, 255, 255, 0.14),
		var(--shadow-lg);
	backdrop-filter: blur(18px);
	-webkit-backdrop-filter: blur(18px);
	color: var(--hero-chip-muted);
	font-size: var(--fs-xs);
	line-height: 1.35;
}

.chip-float strong {
	display: block;
	color: var(--hero-chip-ink);
	font-family: var(--font-mono);
	font-size: var(--fs-sm);
	font-weight: 600;
}

.chip-float small {
	color: var(--hero-chip-muted);
	font-size: var(--fs-2xs);
}

/* Placement is the caller's job — see .chip-float--stage in the hero section
   for the one the homepage hangs off the live panel. */

/* ----------------------------------------------------------------- lists */
.tick-list {
	display: grid;
	gap: var(--s-3);
}

.tick-list--2col {
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr));
	gap: var(--s-3) var(--s-5);
}

.tick-list li {
	position: relative;
	padding-left: 34px;
	color: var(--text-muted);
	font-size: var(--fs-sm);
	line-height: 1.6;
}

.tick-list li::before {
	content: "";
	position: absolute;
	left: 0;
	top: 3px;
	width: 22px;
	height: 22px;
	border-radius: 50%;
	background: var(--brand-soft) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23e33a41' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E") center / 13px no-repeat;
}

.tick-list--live li::before {
	background-color: var(--live-soft);
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2312b981' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E");
}

.section--dark .tick-list li,
.card--dark .tick-list li,
.card--glass .tick-list li {
	color: var(--on-dark-muted);
}

/* ------------------------------------------------------- framed screenshot */
/* A browser-chrome frame so product shots read as software, not stock art. */
.frame {
	position: relative;
	padding: 11px;
	border-radius: var(--r-xl);
	background: var(--shell-bg);
	box-shadow: var(--bevel-ring), var(--bevel), var(--shadow-lg);
}

.frame__bar {
	display: flex;
	align-items: center;
	gap: 7px;
	padding: 10px 14px 13px;
}

/* The three window dots. */
.frame__bar i {
	display: block;
	width: 10px;
	height: 10px;
	flex: none;
	border-radius: 50%;
	background: var(--hairline-strong);
}

/* The address pill, optically centred by pulling back the dots' width. */
.frame__bar span {
	margin-inline: auto;
	padding-right: 39px;
	color: var(--text-faint);
	font-family: var(--font-mono);
	font-size: var(--fs-2xs);
	letter-spacing: 0.04em;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

.frame > img,
.frame picture img {
	border-radius: var(--r-inner);
	box-shadow: 0 0 0 1px var(--hairline);
}

.figure {
	margin: 0;
}

.figure figcaption {
	margin-top: var(--s-3);
	color: var(--text-faint);
	font-size: var(--fs-xs);
	text-align: center;
}

.divider {
	height: 1px;
	margin-block: var(--s-7);
	border: 0;
	background: linear-gradient(90deg, transparent, var(--hairline-strong), transparent);
}

/* ==========================================================================
   10. SECTIONS
   ========================================================================== */

/* ------------------------------------------------- art-direction switcher */
/* The visitor-facing A/B control. A real segmented control with a sliding
   thumb, not a sun/moon icon swap. */
/* A composed, centred control — the switch is a feature of the site, so it
   is presented as one rather than tucked into a corner. */
.art-switch {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: var(--s-4);
	max-width: 720px;
	margin-inline: auto;
	padding: clamp(var(--s-5), 4vw, var(--s-8));
	border-radius: var(--r-2xl);
	background: var(--glass);
	box-shadow: var(--bevel-ring), var(--bevel);
	text-align: center;
}

.art-switch__label {
	color: var(--text-faint);
	font-family: var(--font-mono);
	font-size: var(--fs-2xs);
	text-transform: uppercase;
	letter-spacing: 0.18em;
}

.art-switch__track {
	position: relative;
	display: flex;
	width: min(100%, 400px);
	padding: 5px;
	border-radius: var(--r-pill);
	background: var(--glass);
	box-shadow: var(--bevel-ring), var(--bevel);
	backdrop-filter: blur(16px);
	-webkit-backdrop-filter: blur(16px);
}

/* The thumb travels; the buttons never move. Option order is
   [0] Control Room (dark)  [1] Daylight (light) — so light sits right. */
.art-switch__thumb {
	position: absolute;
	top: 5px;
	left: 5px;
	width: calc(50% - 5px);
	height: calc(100% - 10px);
	border-radius: var(--r-pill);
	background: linear-gradient(180deg, var(--brand-400), var(--brand-600));
	box-shadow: var(--shadow-brand), inset 0 1px 0 rgba(255, 255, 255, 0.3);
	transform: translateX(100%);
	transition: transform var(--t-slow) var(--ease-spring);
	pointer-events: none;
}

:root[data-theme="dark"] .art-switch__thumb {
	transform: translateX(0);
}

.art-switch__opt {
	position: relative;
	z-index: var(--z-base);
	/* flex:1 keeps both halves equal, which is what the thumb maths assumes. */
	flex: 1 1 0;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 8px;
	padding: 13px 16px;
	border-radius: var(--r-pill);
	color: var(--text-muted);
	font-size: var(--fs-sm);
	font-weight: 650;
	letter-spacing: -0.01em;
	white-space: nowrap;
	transition: color var(--t-slow) var(--ease);
}

.art-switch__opt:hover {
	color: var(--text-strong);
}

.art-switch__opt svg {
	width: 16px;
	height: 16px;
	stroke-width: 1.8;
}

.art-switch__opt[aria-pressed="true"] {
	color: #fff;
}

.art-switch__hint {
	max-width: 52ch;
	margin: 0;
	color: var(--text-muted);
	font-size: var(--fs-sm);
	line-height: 1.6;
}

/* --------------------------------------------------------------- metrics */
.metrics {
	display: grid;
	gap: var(--s-6);
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 210px), 1fr));
}

.metric {
	position: relative;
	padding-left: var(--s-5);
	border-left: 1px solid var(--hairline);
}

.metric::before {
	content: "";
	position: absolute;
	left: -1px;
	top: 0;
	width: 2px;
	height: 40px;
	background: var(--brand);
}

.metric__value {
	display: block;
	color: var(--text-strong);
	font-size: clamp(2.25rem, 1.5rem + 2.6vw, 3.625rem);
	font-weight: 600;
	line-height: 1.02;
	letter-spacing: -0.05em;
}

/* The +, % or / that trails a figure sits smaller and lighter than it. */
.metric__value .unit {
	color: var(--brand);
	font-size: 0.56em;
	font-weight: 500;
	vertical-align: 0.34em;
	margin-left: 1px;
}

.metric__label {
	display: block;
	margin-top: var(--s-3);
	color: var(--text-muted);
	font-size: var(--fs-sm);
	line-height: 1.5;
}

.metrics--on-dark .metric {
	border-color: var(--on-dark-border);
}

.metrics--on-dark .metric__value {
	color: #fff;
}

.metrics--on-dark .metric__label {
	color: var(--on-dark-muted);
}

/* --------------------------------------------------------------- marquee */
/* The line that introduces the logo rail. Generous space beneath it — the
   label and the rail are two separate beats, not one block. */
.marquee__lede {
	margin: 0 0 clamp(var(--s-7), 6vw, var(--s-8));
	text-align: center;
	color: var(--text-muted);
	font-size: var(--fs-sm);
	font-weight: 600;
	letter-spacing: 0.11em;
	text-transform: uppercase;
}

.marquee {
	position: relative;
	overflow: hidden;
	/* Vertical room for the chip lift and its shadow. */
	padding-block: var(--s-3);
	/* Fades at both ends instead of a hard cut. */
	mask-image: linear-gradient(90deg, transparent, #000 9%, #000 91%, transparent);
	-webkit-mask-image: linear-gradient(90deg, transparent, #000 9%, #000 91%, transparent);
}

.marquee__track {
	display: flex;
	align-items: center;
	gap: clamp(var(--s-4), 2.4vw, var(--s-6));
	width: max-content;
	animation: marquee 46s linear infinite;
	will-change: transform;
}

.marquee:hover .marquee__track {
	animation-play-state: paused;
}

@keyframes marquee {
	to {
		transform: translateX(-50%);
	}
}

/* Client logos arrive as JPEGs on a white plate and as transparent PNGs, in
   every aspect ratio going. A fixed white chip normalises all of them: one
   silhouette per logo, full colour, and no blend-mode trickery needed to hide
   the plates — which is what forced the old grayscale treatment.
   The source files are cropped to the mark itself (no baked-in plate margin),
   so this padding is the only breathing room and every logo grows until it
   touches one pair of chip edges. */
.marquee__logo {
	display: flex;
	align-items: center;
	justify-content: center;
	flex: none;
	width: clamp(142px, 15vw, 170px);
	/* Taller than it looks like it needs to be: most of these marks are square
	   or portrait, so height is what caps them, and the extra rows cost the
	   wide wordmarks nothing. */
	height: clamp(96px, 9.6vw, 112px);
	padding: 8px 12px;
	border-radius: var(--r-md);
	background: #fff;
	box-shadow: inset 0 0 0 1px rgba(16, 26, 44, 0.08), 0 10px 26px -18px rgba(16, 26, 44, 0.55);
	transition: transform var(--t) var(--ease), box-shadow var(--t) var(--ease);
}

.marquee__logo:hover {
	transform: translateY(-4px);
	box-shadow: inset 0 0 0 1px rgba(16, 26, 44, 0.14), 0 20px 36px -20px rgba(16, 26, 44, 0.65);
}

/* Claim the whole content box and let object-fit do the scaling: every mark
   grows until it touches one pair of edges, and nothing can overflow.
   Sizing with width/height rather than max-width/max-height is deliberate —
   a percentage *max*-height has no definite box to resolve against here, so
   browsers drop it and the square marks render at full width, spilling out of
   the chip. */
.marquee img {
	width: 100%;
	height: 100%;
	object-fit: contain;
	/* Punch on screen without restating the brand: at saturate(1.45) the reds
	   and purples clip into neon and stop being the client's colour, so this
	   sits just below that. The plates stay pure white either way. */
	filter: saturate(1.28) contrast(1.07);
}

/* The chip stays light in the dark theme — these marks are coloured artwork on
   a white plate, so inverting them would misrepresent the brands. Fully opaque
   rather than 0.95: the marks carry their own opaque white plates, and a
   translucent chip renders each plate as a brighter rectangle inside it. */
:root[data-theme="dark"] .marquee__logo {
	background: #fff;
	box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.16), 0 16px 32px -20px rgba(0, 0, 0, 0.85);
}

:root[data-theme="dark"] .marquee__logo:hover {
	background: #fff;
	box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.24), 0 22px 40px -20px rgba(0, 0, 0, 0.95);
}

/* ------------------------------------------------------------------ tabs */
/* Full-width bar. The tabs spread to fill it (see the flex-grow rule on
   .tabs__tab below) instead of bunching at the left edge. */
.tabs__list {
	display: flex;
	gap: 4px;
	width: 100%;
	margin-bottom: var(--s-6);
	overflow-x: auto;
	scrollbar-width: none;
	padding: 5px;
	border-radius: var(--r-pill);
	background: var(--glass);
	box-shadow: var(--bevel-ring), var(--bevel);
}

.tabs__list::-webkit-scrollbar {
	display: none;
}

.tabs__tab {
	/* Natural width by default so the row stays scrollable on narrow screens —
	   letting them shrink there would cramp the labels instead of scrolling. */
	flex: none;
	padding: 13px 26px;
	border-radius: var(--r-pill);
	color: var(--text-muted);
	font-size: var(--fs-sm);
	font-weight: 620;
	text-align: center;
	white-space: nowrap;
	transition: color var(--t) var(--ease), background-color var(--t) var(--ease),
		box-shadow var(--t) var(--ease);
}

/* Once there is room for every tab, they grow to fill the bar. `1 1 auto`
   grows each one from its own content width, so the extra space is shared in
   proportion to label length — equal `1 1 0` segments would give "Personal"
   the same slab as "Public Sector" and read as a mis-set table. */
@media (min-width: 900px) {
	.tabs__tab {
		flex: 1 1 auto;
	}
}

.tabs__tab:hover {
	color: var(--text-strong);
}

.tabs__tab[aria-selected="true"] {
	color: var(--text-strong);
	background: var(--surface);
	box-shadow: var(--bevel-ring), var(--bevel), var(--shadow-sm);
}

.tabs__panel[hidden] {
	display: none;
}

.tabs__panel {
	animation: panel-in var(--t-slow) var(--ease-out) both;
}

@keyframes panel-in {
	from {
		opacity: 0;
		transform: translateY(10px);
	}
}

/* ----------------------------------------------------------------- steps */
.steps {
	display: grid;
	gap: var(--s-7);
	/* Same reasoning as .rings — three steps, never a fourth empty track. */
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 340px), 1fr));
	counter-reset: step;
}

.step {
	position: relative;
	padding-top: var(--s-6);
	border-top: 1px solid var(--hairline);
}

/* The connecting rail between steps. */
.step::before {
	content: "";
	position: absolute;
	top: -1px;
	left: 0;
	width: 52px;
	height: 2px;
	background: var(--brand);
}

.step__num {
	display: block;
	margin-bottom: var(--s-3);
	color: var(--brand);
	font-family: var(--font-mono);
	font-size: var(--fs-2xs);
	font-weight: 500;
	letter-spacing: 0.2em;
}

.step h3 {
	font-size: var(--fs-h4);
	margin-bottom: var(--s-2);
}

.step p {
	color: var(--text-muted);
	font-size: var(--fs-sm);
	line-height: 1.66;
}

.section--dark .step {
	border-color: var(--on-dark-border);
}

.section--dark .step p {
	color: var(--on-dark-muted);
}

/* ------------------------------------------------------------- accordion */
.accordion {
	display: grid;
	gap: var(--s-3);
	/* Capped short of the container and centred, so every row is the same
	   length as every other one and the stack stays symmetrical about the
	   page axis. Stopping at 1040 rather than running the full 1320 keeps
	   the icon from drifting a long way from the shorter questions. */
	max-width: 1040px;
	margin-inline: auto;
}

/* The FAQ page runs category headings between the accordions. The accordion
   caps itself at 1040, so the headings have to take the same cap or their left
   edge would sit out at the container edge and the column would look ragged. */
.faq-list > h2 {
	max-width: 1040px;
	margin-inline: auto;
}

.accordion__item {
	border-radius: var(--r-lg);
	background: var(--surface);
	box-shadow: var(--bevel-ring), var(--bevel);
	overflow: hidden;
	transition: box-shadow var(--t) var(--ease), background-color var(--t) var(--ease);
}

.accordion__item:has(.accordion__trigger[aria-expanded="true"]) {
	box-shadow: 0 0 0 1px var(--brand-ring), var(--bevel), var(--shadow);
}

.accordion__trigger {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--s-4);
	width: 100%;
	padding: var(--s-5) clamp(var(--s-5), 2.4vw, 38px);
	color: var(--text-strong);
	font-family: var(--font-display);
	font-size: var(--fs-h4);
	font-weight: 600;
	letter-spacing: -0.02em;
	line-height: 1.35;
	text-align: left;
	transition: color var(--t) var(--ease);
}

.accordion__trigger:hover {
	color: var(--brand);
}

/* A plus that rotates into a minus — one shape, not two icons. */
.accordion__icon {
	position: relative;
	flex: none;
	width: 32px;
	height: 32px;
	border-radius: 50%;
	background: var(--shell-bg);
	transition: background-color var(--t) var(--ease), transform var(--t-slow) var(--ease);
}

.accordion__icon::before,
.accordion__icon::after {
	content: "";
	position: absolute;
	top: 50%;
	left: 50%;
	width: 13px;
	height: 1.6px;
	border-radius: 2px;
	background: currentColor;
	transform: translate(-50%, -50%);
	transition: transform var(--t-slow) var(--ease), opacity var(--t) var(--ease);
}

.accordion__icon::after {
	transform: translate(-50%, -50%) rotate(90deg);
}

.accordion__trigger[aria-expanded="true"] .accordion__icon {
	background: var(--brand-soft);
	transform: rotate(180deg);
}

.accordion__trigger[aria-expanded="true"] .accordion__icon::after {
	opacity: 0;
	transform: translate(-50%, -50%) rotate(0deg);
}

.accordion__panel {
	display: grid;
	grid-template-rows: 0fr;
	transition: grid-template-rows var(--t-slow) var(--ease);
}

.accordion__trigger[aria-expanded="true"] + .accordion__panel {
	grid-template-rows: 1fr;
}

.accordion__panel > div {
	overflow: hidden;
}

.accordion__panel p {
	padding: 0 clamp(var(--s-5), 2.4vw, 38px) var(--s-5);
	color: var(--text-muted);
	font-size: var(--fs-sm);
	line-height: 1.72;
	max-width: 76ch;
}

.accordion__panel p + p {
	padding-top: var(--s-3);
}

/* ---------------------------------------------------------- testimonials */
/* A masonry wall of quotes rather than a 3-card carousel with dots. */
.quote-wall {
	columns: 1;
	column-gap: var(--s-5);
}

@media (min-width: 720px) {
	.quote-wall {
		columns: 2;
	}
}

@media (min-width: 1080px) {
	.quote-wall {
		columns: 3;
	}
}

.quote-wall > * {
	break-inside: avoid;
	margin-bottom: var(--s-5);
}

.quote-card {
	position: relative;
	padding: clamp(var(--s-6), 2.8vw, 44px);
	border-radius: var(--r-xl);
	background: var(--surface);
	box-shadow: var(--bevel-ring), var(--bevel), var(--shadow-sm);
	transition: transform var(--t-slow) var(--ease), box-shadow var(--t-slow) var(--ease);
}

.quote-card:hover {
	transform: translateY(-3px);
	box-shadow: 0 0 0 1px var(--hairline-strong), var(--bevel), var(--shadow-lg);
}

.quote-card__mark {
	display: block;
	margin-bottom: var(--s-3);
	color: var(--brand);
	font-family: var(--font-display);
	font-size: 3.25rem;
	line-height: 0.7;
	opacity: 0.5;
}

/* The quote body is a <blockquote> here, not a <p>. Both are listed, and the
   decorative mark is excluded — `.quote-card p` alone outranks
   `.quote-card__mark` on specificity and was flattening it. */
.quote-card blockquote,
.quote-card p:not(.quote-card__mark) {
	margin: 0;
	color: var(--text);
	font-size: var(--fs-lead);
	line-height: 1.65;
}

.quote-card__author {
	display: flex;
	align-items: center;
	gap: var(--s-3);
	margin-top: var(--s-5);
	padding-top: var(--s-5);
	border-top: 1px solid var(--hairline);
}

.quote-card__author strong {
	display: block;
	color: var(--text-strong);
	font-size: var(--fs-sm);
	font-weight: 650;
}

/* :not(.avatar) matters — the initials plate is a <span> in this block too, and
   without the exclusion this rule outranks .avatar on specificity and flattens
   it back to a block of faint caption text. */
.quote-card__author span:not(.avatar) {
	display: block;
	color: var(--text-faint);
	font-size: var(--fs-xs);
}

/* Squircle, not a circle — circles everywhere read as generic. */
.avatar {
	display: grid;
	place-items: center;
	width: 52px;
	height: 52px;
	color: var(--text-strong);
	font-family: var(--font-display);
	font-size: var(--fs-sm);
	font-weight: 650;
	letter-spacing: 0.02em;
	flex: none;
	border-radius: 34%;
	object-fit: cover;
	background: var(--surface-3);
	box-shadow: var(--bevel-ring);
}

.section--dark .quote-card {
	background: var(--on-dark-surface);
	box-shadow: 0 0 0 1px var(--on-dark-border), inset 0 1px 0 rgba(255, 255, 255, 0.08);
}

.section--dark .quote-card blockquote,
.section--dark .quote-card p:not(.quote-card__mark) {
	color: var(--on-dark);
}

.section--dark .quote-card__author {
	border-color: var(--on-dark-border);
}

.section--dark .quote-card__author strong {
	color: #fff;
}

/* On a dark band the initials plate becomes a glass chip, not a light square. */
.section--dark .avatar {
	color: #fff;
	background: var(--on-dark-surface);
	box-shadow: 0 0 0 1px var(--on-dark-border);
}

/* ------------------------------------------------- testimonial slider */
/* One quote at a time on a drifting aurora. The sliding itself is native
   scroll-snap, not a transform the script owns: without JS the rail is still
   scrollable and swipeable, and touch gets real momentum for free. The script
   only adds the dots and arrows, which is why .quotes__controls stays hidden
   until the `js` class lands. */
.quotes {
	position: relative;
	background: linear-gradient(180deg, rgba(4, 9, 18, 0.55), transparent 38%, rgba(4, 9, 18, 0.5)),
		var(--band-dark);
}

.quotes__aurora {
	position: absolute;
	inset: 0;
	z-index: -1;
	overflow: hidden;
	pointer-events: none;
}

.quotes__blob {
	position: absolute;
	display: block;
	border-radius: 50%;
	filter: blur(64px);
	mix-blend-mode: screen;
	will-change: transform;
}

.quotes__blob--a {
	top: -18%;
	left: -10%;
	width: clamp(320px, 46vw, 720px);
	aspect-ratio: 4 / 3;
	background: radial-gradient(circle, rgba(63, 155, 242, 0.5), transparent 68%);
	animation: quote-drift-a 26s ease-in-out infinite alternate;
}

.quotes__blob--b {
	right: -12%;
	bottom: -22%;
	width: clamp(300px, 42vw, 660px);
	aspect-ratio: 5 / 4;
	background: radial-gradient(circle, rgba(227, 58, 65, 0.44), transparent 68%);
	animation: quote-drift-b 33s ease-in-out infinite alternate;
}

.quotes__blob--c {
	top: 24%;
	left: 46%;
	width: clamp(260px, 34vw, 540px);
	aspect-ratio: 6 / 5;
	background: radial-gradient(circle, rgba(18, 185, 129, 0.3), transparent 70%);
	animation: quote-drift-c 41s ease-in-out infinite alternate;
}

@keyframes quote-drift-a {
	to {
		transform: translate3d(14%, 18%, 0) scale(1.18);
	}
}

@keyframes quote-drift-b {
	to {
		transform: translate3d(-18%, -14%, 0) scale(1.12);
	}
}

@keyframes quote-drift-c {
	to {
		transform: translate3d(-22%, 12%, 0) scale(0.86);
	}
}

.quotes__viewport {
	overflow-x: auto;
	overflow-y: hidden;
	scroll-snap-type: x mandatory;
	scroll-behavior: smooth;
	/* overflow-y clips at the padding box, so the card's drop shadow needs
	   room here or it gets sheared off along the bottom edge. */
	padding-block: 4px 24px;
	/* The dots are the affordance here; a native bar would sit under the card. */
	scrollbar-width: none;
	-ms-overflow-style: none;
}

.quotes__viewport::-webkit-scrollbar {
	display: none;
}

.quotes__viewport:focus-visible {
	outline: 2px solid var(--brand-400);
	outline-offset: 4px;
}

.quotes__track {
	display: flex;
	gap: var(--s-5);
	margin: 0;
	padding: 0;
	list-style: none;
}

.quotes__slide {
	display: flex;
	flex: 0 0 100%;
	min-width: 0;
	scroll-snap-align: center;
	scroll-snap-stop: always;
}

.quote-card--feature {
	display: flex;
	flex-direction: column;
	width: 100%;
	margin: 0;
	padding: clamp(var(--s-6), 4vw, 56px);
	border-radius: var(--r-xl);
}

.section--dark .quote-card--feature {
	background: linear-gradient(152deg, rgba(255, 255, 255, 0.08), rgba(255, 255, 255, 0.025));
	backdrop-filter: blur(18px);
	-webkit-backdrop-filter: blur(18px);
	box-shadow: inset 0 0 0 1px var(--on-dark-border), inset 0 1px 0 rgba(255, 255, 255, 0.1),
		0 34px 66px -44px rgba(0, 0, 0, 0.95);
}

/* The card fills the rail, so a hover lift would just wobble the whole slide. */
.quote-card--feature:hover {
	transform: none;
}

.quote-card__glyph {
	display: grid;
	place-items: center;
	width: 48px;
	height: 48px;
	margin-bottom: clamp(var(--s-5), 2.4vw, var(--s-6));
	border-radius: 34%;
	color: var(--brand-400);
	background: linear-gradient(150deg, rgba(227, 58, 65, 0.24), rgba(227, 58, 65, 0.08));
	box-shadow: inset 0 0 0 1px rgba(244, 103, 109, 0.32);
}

.quote-card__glyph svg {
	width: 25px;
	height: 25px;
}

.quote-card--feature blockquote {
	flex: 1;
	font-size: clamp(1.25rem, 1.02rem + 1vw, 1.8rem);
	line-height: 1.5;
	letter-spacing: -0.011em;
	text-wrap: pretty;
}

.quote-card--feature .quote-card__author {
	margin-top: clamp(var(--s-6), 3vw, var(--s-7));
	padding-top: 0;
	border-top: 0;
}

/* Each speaker carries a hue in --avatar-c, so the rail changes colour as it
   advances instead of repeating one grey plate seven times. */
.quote-card--feature .avatar {
	--avatar-c: var(--brand);
	display: grid;
	place-items: center;
	width: 54px;
	height: 54px;
	color: #fff;
	font-size: var(--fs-sm);
	background: linear-gradient(150deg,
			color-mix(in srgb, var(--avatar-c) 82%, transparent),
			color-mix(in srgb, var(--avatar-c) 44%, transparent));
	box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--avatar-c) 58%, transparent),
		0 12px 26px -14px var(--avatar-c);
}

.quotes__controls {
	display: none;
	align-items: center;
	justify-content: space-between;
	gap: var(--s-5);
	margin-top: var(--s-3);
}

.js .quotes__controls {
	display: flex;
}

.quotes__dots {
	display: flex;
	align-items: center;
	gap: 8px;
}

.quotes__dot {
	width: 9px;
	height: 9px;
	padding: 0;
	border: 0;
	border-radius: var(--r-pill);
	background: rgba(255, 255, 255, 0.22);
	cursor: pointer;
	transition: width var(--t) var(--ease), background var(--t) var(--ease);
}

.quotes__dot:hover {
	background: rgba(255, 255, 255, 0.4);
}

.quotes__dot[aria-selected="true"] {
	width: 32px;
	background: linear-gradient(90deg, var(--brand), var(--brand-400));
}

.quotes__dot:focus-visible {
	outline: 2px solid var(--brand-400);
	outline-offset: 3px;
}

.quotes__arrows {
	display: flex;
	gap: 10px;
}

.quotes__arrow {
	display: grid;
	place-items: center;
	width: 46px;
	height: 46px;
	padding: 0;
	border: 0;
	border-radius: 50%;
	color: var(--on-dark-muted);
	background: rgba(255, 255, 255, 0.05);
	box-shadow: inset 0 0 0 1px var(--on-dark-border);
	cursor: pointer;
	transition: color var(--t) var(--ease), background var(--t) var(--ease),
		box-shadow var(--t) var(--ease), transform var(--t) var(--ease);
}

.quotes__arrow svg {
	width: 19px;
	height: 19px;
}

.quotes__arrow:hover {
	color: #fff;
	background: rgba(255, 255, 255, 0.11);
	box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.22);
	transform: translateY(-2px);
}

.quotes__arrow:focus-visible {
	outline: 2px solid var(--brand-400);
	outline-offset: 3px;
}

@media (max-width: 560px) {
	.quotes__controls {
		flex-direction: column-reverse;
		gap: var(--s-4);
	}
}

/* --------------------------------------------------------------- pricing */
.pricing {
	display: grid;
	gap: var(--s-5);
	/* align-items:stretch keeps every column the same height so the shared
	   rows (price, feature list, CTA) line up across the row. */
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr));
	align-items: stretch;
}

.plan {
	position: relative;
	display: flex;
	flex-direction: column;
	padding: clamp(var(--s-6), 2.8vw, 42px);
	border-radius: var(--r-xl);
	background: var(--surface);
	box-shadow: var(--bevel-ring), var(--bevel), var(--shadow-sm);
	transition: transform var(--t-slow) var(--ease), box-shadow var(--t-slow) var(--ease);
}

.plan:hover {
	transform: translateY(-4px);
	box-shadow: 0 0 0 1px var(--hairline-strong), var(--bevel), var(--shadow-lg);
}

/* The recommended tier is marked by colour and emphasis, not extra height. */
.plan--featured {
	background: var(--band-dark);
	color: var(--on-dark);
	box-shadow: 0 0 0 1px var(--brand-ring), inset 0 1px 0 rgba(255, 255, 255, 0.1),
		var(--shadow-lg);
}

.plan--featured .plan__name,
.plan--featured .plan__price {
	color: #fff;
}

.plan--featured .plan__desc,
.plan--featured .tick-list li {
	color: var(--on-dark-muted);
}

.plan__flag {
	position: absolute;
	top: -11px;
	left: var(--s-6);
	white-space: nowrap;
	padding: 5px 12px;
	border-radius: var(--r-xs);
	background: linear-gradient(180deg, var(--brand-400), var(--brand-600));
	color: #fff;
	font-family: var(--font-mono);
	font-size: var(--fs-2xs);
	font-weight: 500;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	box-shadow: var(--shadow-brand);
}

/* Fixed-height head block so the feature lists start at the same Y. */
.plan__head {
	min-height: 176px;
	padding-bottom: var(--s-5);
	margin-bottom: var(--s-5);
	border-bottom: 1px solid var(--hairline);
}

.plan--featured .plan__head {
	border-color: var(--on-dark-border);
}

.plan__name {
	display: block;
	color: var(--text-strong);
	font-family: var(--font-display);
	font-size: var(--fs-h4);
	font-weight: 600;
	letter-spacing: -0.022em;
}

/* The plan's headline claim. The trailing <span> is its qualifier and drops
   onto its own line, smaller and quieter, so the claim reads first. */
.plan__price {
	display: block;
	margin-top: var(--s-3);
	color: var(--text-strong);
	font-family: var(--font-display);
	font-size: clamp(1.75rem, 1.35rem + 1.5vw, 2.25rem);
	font-weight: 600;
	line-height: 1.1;
	letter-spacing: -0.032em;
}

.plan__price span,
.plan__price small {
	display: block;
	margin-top: 6px;
	color: var(--text-muted);
	font-family: var(--font-body);
	font-size: var(--fs-sm);
	font-weight: 500;
	letter-spacing: -0.01em;
}

.plan--featured .plan__price span,
.plan--featured .plan__price small {
	color: var(--on-dark-muted);
}

.plan__desc {
	margin-top: var(--s-3);
	color: var(--text-muted);
	font-size: var(--fs-sm);
	line-height: 1.6;
}

/* Pins every CTA to the base so they form one clean horizontal line. */
.plan .btn {
	margin-top: auto;
}

.plan .tick-list {
	margin-bottom: var(--s-6);
}

/* ------------------------------------------------------------------ rings */
.rings {
	display: grid;
	gap: var(--s-7);
	/* 240px, not less: at the 1320px container a smaller minimum lets auto-fit
	   open a fifth track that the four rings can never fill. */
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr));
	justify-items: center;
	text-align: center;
}

/* `.ring` is the whole item (viz + caption) and carries data-percent;
   only the <svg> inside .ring__viz is rotated so the arc starts at 12 o'clock. */
.ring {
	display: grid;
	justify-items: center;
	gap: var(--s-4);
}

.ring h4 {
	margin: 0;
}

.ring p {
	margin: 0;
	color: var(--text-muted);
	font-size: var(--fs-sm);
	line-height: 1.55;
}

.ring__viz {
	position: relative;
	width: 164px;
	height: 164px;
}

.ring__viz svg {
	width: 100%;
	height: 100%;
	transform: rotate(-90deg);
}

.ring__bg {
	fill: none;
	stroke: var(--hairline);
	stroke-width: 8;
}

.ring__fg {
	fill: none;
	stroke: var(--brand);
	stroke-width: 8;
	stroke-linecap: round;
	stroke-dasharray: 314;
	stroke-dashoffset: 314;
	transition: stroke-dashoffset 1.5s var(--ease-out);
}

.ring.is-visible .ring__fg {
	stroke-dashoffset: var(--offset, 314);
}

.ring__pct {
	position: absolute;
	inset: 0;
	display: grid;
	place-items: center;
	color: var(--text-strong);
	font-size: 1.9375rem;
	font-weight: 600;
	letter-spacing: -0.04em;
}

.section--dark .ring__bg {
	stroke: var(--on-dark-border);
}

.section--dark .ring__pct {
	color: #fff;
}

/* ------------------------------------------------------------- CTA band */
.cta-band {
	position: relative;
	padding: clamp(var(--s-7), 6vw, var(--s-9)) clamp(var(--s-5), 5vw, var(--s-9));
	border-radius: var(--r-2xl);
	background: var(--band-dark);
	color: var(--on-dark);
	text-align: center;
	isolation: isolate;
	overflow: hidden;
	box-shadow: var(--shadow-xl);
}

.cta-band::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	background: radial-gradient(58% 70% at 50% 0%, rgba(227, 58, 65, 0.28), transparent 66%),
		radial-gradient(52% 60% at 12% 100%, rgba(63, 155, 242, 0.22), transparent 64%);
}

.cta-band::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	background-image: linear-gradient(rgba(255, 255, 255, 0.045) 1px, transparent 1px),
		linear-gradient(90deg, rgba(255, 255, 255, 0.045) 1px, transparent 1px);
	background-size: 52px 52px;
	mask-image: radial-gradient(70% 70% at 50% 40%, #000, transparent 76%);
	-webkit-mask-image: radial-gradient(70% 70% at 50% 40%, #000, transparent 76%);
}

.cta-band h2 {
	color: #fff;
}

/* The global `* { margin: 0 }` leaves the band's own children flush; the
   .btn-row rule below wins on specificity and keeps its larger gap. */
.cta-band > * + * {
	margin-top: var(--s-5);
}

.cta-band .lead,
.cta-band > p {
	max-width: 62ch;
	margin-inline: auto;
	color: var(--on-dark-muted);
	font-size: var(--fs-lead);
	line-height: 1.6;
}

.cta-band .btn-row {
	justify-content: center;
	margin-top: var(--s-7);
}

/* ------------------------------------------------------------- page hero */
/* The compact hero used by every page other than the homepage. */
.page-hero {
	position: relative;
	isolation: isolate;
	overflow: clip;
	padding-block: clamp(var(--s-8), 7vw, var(--s-10)) clamp(var(--s-7), 6vw, var(--s-9));
	background: var(--hero-bg);
	color: var(--hero-ink-muted);
	border-bottom-left-radius: clamp(var(--r-xl), 4vw, 56px);
	border-bottom-right-radius: clamp(var(--r-xl), 4vw, 56px);
	transition: background-color var(--t-slow) var(--ease);
}

.page-hero::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -2;
	background: var(--hero-glow);
}

.page-hero::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	background-image: linear-gradient(var(--grid-line) 1px, transparent 1px),
		linear-gradient(90deg, var(--grid-line) 1px, transparent 1px);
	background-size: 60px 60px;
	mask-image: radial-gradient(70% 74% at 40% 30%, #000 10%, transparent 78%);
	-webkit-mask-image: radial-gradient(70% 74% at 40% 30%, #000 10%, transparent 78%);
}

.page-hero h1 {
	color: var(--hero-ink);
	max-width: 20ch;
}

.page-hero .lead,
.page-hero p {
	margin-top: var(--s-5);
	color: var(--hero-ink-muted);
}

/* The eyebrow and badges inside a hero read against the hero, not the page. */
.hero .eyebrow,
.page-hero .eyebrow {
	color: var(--hero-ink-muted);
	background: var(--hero-surface);
	box-shadow: 0 0 0 1px var(--hero-surface-ring), inset 0 1px 0 rgba(255, 255, 255, 0.16);
}

.page-hero .btn-row {
	margin-top: var(--s-6);
}

.page-hero__inner {
	display: grid;
	gap: clamp(var(--s-6), 5vw, var(--s-8));
	grid-template-columns: 1fr;
	align-items: center;
}

@media (min-width: 940px) {
	.page-hero--split .page-hero__inner {
		grid-template-columns: minmax(0, 1fr) minmax(0, 0.86fr);
	}
}

/* ------------------------------------------------------------ breadcrumb */
.breadcrumb {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--s-2);
	margin-bottom: var(--s-5);
	color: var(--hero-ink-muted);
	font-size: var(--fs-xs);
}

.breadcrumb a {
	color: var(--hero-ink-muted);
	transition: color var(--t) var(--ease);
}

.breadcrumb a:hover {
	color: var(--hero-ink);
}

.breadcrumb li:not(:last-child)::after {
	content: "/";
	margin-left: var(--s-2);
	color: var(--text-faint);
	opacity: 0.6;
}

.breadcrumb li {
	display: inline-flex;
	align-items: center;
}

.breadcrumb [aria-current="page"] {
	color: var(--hero-ink);
}

/* ----------------------------------------------------------- spec table */
.spec-table {
	width: 100%;
	font-size: var(--fs-sm);
}

/* Wide tables scroll inside their own container — the page body never does. */
.table-scroll {
	overflow-x: auto;
	border-radius: var(--r-lg);
	box-shadow: var(--bevel-ring);
	-webkit-overflow-scrolling: touch;
}

.spec-table th,
.spec-table td {
	padding: 14px var(--s-5);
	text-align: left;
	border-bottom: 1px solid var(--hairline);
	vertical-align: top;
}

.spec-table thead th {
	background: var(--surface-3);
	color: var(--text-strong);
	font-family: var(--font-mono);
	font-size: var(--fs-2xs);
	font-weight: 500;
	text-transform: uppercase;
	letter-spacing: 0.14em;
	white-space: nowrap;
}

.spec-table tbody th {
	color: var(--text-strong);
	font-weight: 620;
	white-space: nowrap;
}

.spec-table td {
	color: var(--text-muted);
}

.spec-table tbody tr {
	background: var(--surface);
	transition: background-color var(--t) var(--ease);
}

.spec-table tbody tr:hover {
	background: var(--surface-2);
}

.spec-table tbody tr:last-child th,
.spec-table tbody tr:last-child td {
	border-bottom: 0;
}

/* -------------------------------------------------------- specific cards */
.industry-card,
.device-card,
.office-card,
.dl-item {
	position: relative;
	display: flex;
	flex-direction: column;
	border-radius: var(--r-xl);
	background: var(--surface);
	box-shadow: var(--bevel-ring), var(--bevel), var(--shadow-sm);
	transition: transform var(--t-slow) var(--ease), box-shadow var(--t-slow) var(--ease);
}

.industry-card:hover,
.device-card:hover,
.office-card:hover,
.dl-item:hover {
	transform: translateY(-4px);
	box-shadow: 0 0 0 1px var(--hairline-strong), var(--bevel), var(--shadow-lg);
}

.industry-card {
	padding: var(--s-6);
	overflow: hidden;
}

.industry-card h3 {
	margin-top: var(--s-5);
	font-size: var(--fs-h4);
}

.industry-card p {
	margin-top: var(--s-2);
	color: var(--text-muted);
	font-size: var(--fs-sm);
	line-height: 1.64;
}

.device-card {
	overflow: hidden;
}

.device-card__media {
	position: relative;
	aspect-ratio: 4 / 3;
	display: grid;
	place-items: center;
	/* Roomier than before: the photo is now a tile inside the media well
	   rather than bleeding to its edges. */
	padding: clamp(var(--s-4), 2vw, var(--s-5));
	background: radial-gradient(120% 90% at 50% -10%, rgba(255, 255, 255, 0.07), transparent 68%),
		var(--surface-3);
	overflow: hidden;
}

/* The supplier shots arrive on white and on grey. Standing each one on the
   same studio plate — a soft silver gradient with its own radius and ring —
   is what stops a dark card looking like it has a white hole punched in it. */
.device-card__media img {
	width: 100%;
	height: 100%;
	object-fit: contain;
	border-radius: var(--r-md);
	background: linear-gradient(163deg, #fdfdfe 0%, #eef1f6 58%, #e4e9f1 100%);
	box-shadow: 0 0 0 1px rgba(16, 30, 51, 0.1), 0 20px 38px -26px rgba(4, 8, 20, 0.75);
	transition: transform var(--t-slower) var(--ease), box-shadow var(--t-slow) var(--ease);
}

.device-card:hover .device-card__media img {
	box-shadow: 0 0 0 1px rgba(16, 30, 51, 0.14), 0 28px 52px -28px rgba(4, 8, 20, 0.85);
}

.device-card:hover .device-card__media img {
	transform: scale(1.05);
}

.device-card__body {
	display: flex;
	flex-direction: column;
	flex: 1;
	padding: var(--s-5) var(--s-6) var(--s-6);
}

.device-card__body h3 {
	font-size: var(--fs-h4);
}

.device-card__body p {
	margin-top: var(--s-2);
	color: var(--text-muted);
	font-size: var(--fs-sm);
	line-height: 1.6;
}

.device-card__specs {
	display: grid;
	gap: var(--s-2);
	margin-top: var(--s-4);
	padding-top: var(--s-4);
	border-top: 1px solid var(--hairline);
	font-family: var(--font-mono);
	font-size: var(--fs-xs);
	color: var(--text-muted);
}

.device-card__specs li {
	display: flex;
	justify-content: space-between;
	gap: var(--s-3);
}

.device-card__specs b {
	color: var(--text-strong);
	font-weight: 500;
}

.device-card .btn {
	margin-top: auto;
}

.device-card__body > .btn {
	margin-top: var(--s-5);
}

.office-card {
	padding: var(--s-6);
}

.office-card__flag {
	display: inline-flex;
	align-items: center;
	gap: var(--s-2);
	margin-bottom: var(--s-4);
	color: var(--text-faint);
	font-family: var(--font-mono);
	font-size: var(--fs-2xs);
	text-transform: uppercase;
	letter-spacing: 0.16em;
}

.office-card address {
	color: var(--text-muted);
	font-size: var(--fs-sm);
	font-style: normal;
	line-height: 1.72;
}

.office-card a {
	color: var(--link-blue);
	transition: color var(--t) var(--ease);
}

/* Underline rather than a colour shift on hover — every blue light enough to
   read as "brighter" on the white card drops under 4.5:1. */
.office-card a:hover {
	text-decoration: underline;
	text-underline-offset: 3px;
}

/* The contact rows. These had no rules at all: an inline <svg> with a viewBox
   but no width/height has no intrinsic size, so each icon was falling back to
   the 300x150 replaced-element default and the <dl> was rendering with the
   browser's indented <dd>. Each row is now a chip plus a stack of links, and
   carries its own hue in --line-c. */
.office-card dl {
	display: grid;
	gap: var(--s-4);
	margin: var(--s-5) 0 0;
	padding-top: var(--s-5);
	border-top: 1px solid var(--hairline);
}

.office-line {
	--line-c: var(--brand);
	display: flex;
	align-items: flex-start;
	gap: var(--s-3);
}

.office-line dt {
	display: grid;
	place-items: center;
	width: 34px;
	height: 34px;
	flex: none;
	border-radius: 30%;
	color: var(--line-c);
	background: linear-gradient(150deg,
			color-mix(in srgb, var(--line-c) 20%, transparent),
			color-mix(in srgb, var(--line-c) 7%, transparent));
	box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--line-c) 28%, transparent);
}

.office-line dt svg {
	width: 17px;
	height: 17px;
}

.office-line dd {
	margin: 0;
	/* min-width lets a long address wrap inside the flex row instead of
	   forcing the card wider than its grid track. */
	min-width: 0;
	color: var(--text-muted);
	font-size: var(--fs-sm);
	line-height: 1.75;
}

/* ------------------------------------------------------------- downloads */
.dl-item {
	flex-direction: row;
	align-items: center;
	gap: var(--s-4);
	padding: var(--s-5);
}

.dl-item__icon {
	display: grid;
	place-items: center;
	width: 44px;
	height: 44px;
	flex: none;
	border-radius: var(--r-sm);
	background: var(--brand-soft);
	color: var(--brand);
	box-shadow: inset 0 0 0 1px var(--brand-ring);
}

.dl-item__icon svg {
	width: 20px;
	height: 20px;
}

.dl-item__body {
	flex: 1;
	min-width: 0;
}

.dl-item__body strong {
	display: block;
	color: var(--text-strong);
	font-size: var(--fs-sm);
	font-weight: 650;
	letter-spacing: -0.014em;
}

.dl-item__body span {
	display: block;
	margin-top: 2px;
	color: var(--text-faint);
	font-family: var(--font-mono);
	font-size: var(--fs-2xs);
	text-transform: uppercase;
	letter-spacing: 0.1em;
}

.dl-item__arrow {
	display: grid;
	place-items: center;
	width: 34px;
	height: 34px;
	flex: none;
	border-radius: 50%;
	background: var(--shell-bg);
	color: var(--text-muted);
	transition: transform var(--t) var(--ease-spring), background-color var(--t) var(--ease),
		color var(--t) var(--ease);
}

.dl-item__arrow svg {
	width: 15px;
	height: 15px;
	stroke-width: 1.9;
}

.dl-item:hover .dl-item__arrow {
	background: var(--brand);
	color: #fff;
	transform: translateY(2px);
}

/* ------------------------------------------------------------ app stores */
.store-row {
	display: flex;
	flex-wrap: wrap;
	gap: var(--s-3);
}

.store-btn {
	display: inline-flex;
	align-items: center;
	gap: 11px;
	padding: 11px 20px 11px 17px;
	border-radius: var(--r-md);
	background: var(--band-dark);
	color: #fff;
	box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.12), inset 0 1px 0 rgba(255, 255, 255, 0.14),
		var(--shadow);
	transition: transform var(--t) var(--ease-spring), box-shadow var(--t) var(--ease);
}

.store-btn:hover {
	transform: translateY(-2px);
	box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.18),
		var(--shadow-lg);
}

.store-btn svg {
	width: 24px;
	height: 24px;
	flex: none;
}

.store-btn span {
	display: block;
	font-size: 9px;
	line-height: 1.3;
	text-transform: uppercase;
	letter-spacing: 0.14em;
	opacity: 0.7;
}

.store-btn strong {
	display: block;
	font-size: var(--fs-sm);
	font-weight: 650;
	line-height: 1.25;
	letter-spacing: -0.018em;
}

/* --------------------------------------------------------------- gallery */
.gallery {
	display: grid;
	gap: var(--s-4);
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr));
}

.gallery img {
	width: 100%;
	border-radius: var(--r-lg);
	box-shadow: var(--bevel-ring), var(--shadow-sm);
	transition: transform var(--t-slow) var(--ease), box-shadow var(--t-slow) var(--ease);
}

.gallery img:hover {
	transform: translateY(-3px) scale(1.01);
	box-shadow: var(--shadow-lg);
}

/* --------------------------------------------------------- floating CTAs */
.wa-float,
.to-top {
	position: fixed;
	z-index: var(--z-sticky);
	display: grid;
	place-items: center;
	border-radius: 50%;
	transition: transform var(--t) var(--ease-spring), opacity var(--t) var(--ease),
		visibility var(--t) var(--ease), box-shadow var(--t) var(--ease);
}

.wa-float {
	right: var(--s-5);
	bottom: var(--s-5);
	width: 54px;
	height: 54px;
	background: linear-gradient(180deg, #34d072, #1da851);
	color: #fff;
	box-shadow: 0 16px 34px -12px rgba(29, 168, 81, 0.6), inset 0 1px 0 rgba(255, 255, 255, 0.28);
}

.wa-float svg {
	width: 26px;
	height: 26px;
}

.wa-float:hover {
	transform: translateY(-3px) scale(1.05);
}

.to-top {
	right: var(--s-5);
	bottom: calc(var(--s-5) + 66px);
	width: 44px;
	height: 44px;
	background: var(--glass-strong);
	color: var(--text-strong);
	box-shadow: var(--bevel-ring), var(--bevel), var(--shadow);
	backdrop-filter: blur(16px);
	-webkit-backdrop-filter: blur(16px);
	opacity: 0;
	visibility: hidden;
	transform: translateY(10px);
}

.to-top svg {
	width: 17px;
	height: 17px;
}

.to-top.is-visible {
	opacity: 1;
	visibility: visible;
	transform: translateY(0);
}

.to-top:hover {
	transform: translateY(-3px);
}

@media (max-width: 640px) {
	.wa-float {
		width: 48px;
		height: 48px;
	}
	.to-top {
		bottom: calc(var(--s-5) + 60px);
		width: 40px;
		height: 40px;
	}
}

/* --------------------------------------------------- live fleet dashboard */
/* A self-contained product widget: status composition bar, legend and a grid
   of stat tiles with sparklines. Rendered from data in naxer.js so the range
   buttons and refresh actually do something.
   It always sits on an always-dark band, so it carries its own dark palette
   rather than the theme tokens — but it takes the accent from --brand so the
   site still has exactly one accent colour. */

@property --fd-angle {
	syntax: "<angle>";
	inherits: false;
	initial-value: 0deg;
}

.fleet-dashboard {
	--fd-bg: rgba(13, 18, 28, 0.88);
	--fd-text: #eef1f7;
	--fd-muted: #8996ad;
	--fd-line: rgba(255, 255, 255, 0.08);
	--fd-accent: var(--brand);

	/* Categorical status palette — six series that must stay tellable apart,
	   so these are tuned for the dark card rather than mapped onto the
	   semantic tokens. */
	--c-idle: #4f8cff;
	--c-moving: #34d399;
	--c-stopped: #f5b942;
	--c-overspeed: #fb5d5d;
	--c-geozone: #ff9a4d;
	--c-notresponding: #8b96ad;

	width: 100%;
	color: var(--fd-text);
}

/* The dashboard gets a full-container row of its own rather than a column of
   the copy split — squeezed into half the grid it rendered well below the
   size it was designed at, and the six stat tiles could not sit on one row. */
.platform-dash {
	margin-top: clamp(var(--s-7), 6vw, var(--s-9));
}

/* Slowly rotating conic border. The 1px padding is the border. */
.fd-ring {
	padding: 1px;
	border-radius: 25px;
	background: conic-gradient(
		from var(--fd-angle),
		transparent 0%,
		color-mix(in srgb, var(--brand) 65%, transparent) 12%,
		transparent 26%,
		transparent 48%,
		rgba(79, 140, 255, 0.5) 60%,
		transparent 74%,
		transparent 100%
	);
	animation: fd-spin 9s linear infinite;
}

@keyframes fd-spin {
	to {
		--fd-angle: 360deg;
	}
}

/* --------------------------------------------------------------------------
   Framed product embed. The dashboard is a whole application rather than a
   widget — it ships its own reset, fixed navigation and four screens — so it
   is loaded in an iframe and dressed in browser chrome instead of being
   inlined. The chrome is what makes a light-UI product read as intentional
   inside a dark section: it is a window onto the product, not a panel of it.
   -------------------------------------------------------------------------- */
.pd-frame {
	border-radius: 24px;
	overflow: hidden;
	background: rgba(13, 18, 28, 0.92);
	box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06), 0 30px 60px -25px rgba(0, 0, 0, 0.7);
}

/* Three columns rather than a flex row so the address pill stays optically
   centred regardless of how wide the dots and the live chip run. */
.pd-chrome {
	display: grid;
	grid-template-columns: 1fr auto 1fr;
	align-items: center;
	gap: var(--s-3);
	padding: 12px clamp(12px, 1.6vw, 20px);
	border-bottom: 1px solid rgba(255, 255, 255, 0.08);
	background: rgba(255, 255, 255, 0.03);
}

.pd-dots {
	display: flex;
	gap: 6px;
	flex-shrink: 0;
	justify-self: start;
}

.pd-dots i {
	width: 10px;
	height: 10px;
	border-radius: 50%;
	background: rgba(255, 255, 255, 0.18);
}

.pd-dots i:first-child {
	background: rgba(251, 93, 93, 0.65);
}

.pd-dots i:nth-child(2) {
	background: rgba(245, 185, 66, 0.65);
}

.pd-dots i:last-child {
	background: rgba(52, 211, 153, 0.6);
}

.pd-url {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	justify-self: center;
	min-width: 0;
	max-width: 100%;
	padding: 6px 18px;
	border-radius: 999px;
	background: rgba(255, 255, 255, 0.06);
	color: #8996ad;
	font-size: 0.78rem;
	letter-spacing: 0.01em;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

.pd-url svg {
	width: 11px;
	height: 11px;
	flex-shrink: 0;
	opacity: 0.8;
}

.pd-live {
	display: flex;
	align-items: center;
	gap: 7px;
	justify-self: end;
	color: #8996ad;
	font-size: 0.74rem;
	font-weight: 600;
	letter-spacing: 0.04em;
	text-transform: uppercase;
	white-space: nowrap;
}

.pd-live__dot {
	width: 7px;
	height: 7px;
	border-radius: 50%;
	background: #34d399;
	box-shadow: 0 0 0 0 rgba(52, 211, 153, 0.55);
	animation: pd-pulse 2.4s ease-out infinite;
}

@keyframes pd-pulse {
	70% {
		box-shadow: 0 0 0 7px rgba(52, 211, 153, 0);
	}
	100% {
		box-shadow: 0 0 0 0 rgba(52, 211, 153, 0);
	}
}

.pd-open {
	color: #eef1f7;
	font-weight: 600;
	text-decoration: none;
	white-space: nowrap;
	border-bottom: 1px solid color-mix(in srgb, var(--brand) 55%, transparent);
	transition: color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}

.pd-open::after {
	content: " ↗";
}

.pd-open:hover,
.pd-open:focus-visible {
	color: #fff;
	border-color: var(--brand);
}

/* The embedded app owns its own scrolling, so the viewport is a fixed window
   sized to show the stat cards and the first rows of the table together. */
.pd-viewport {
	height: clamp(540px, 76vh, 880px);
	background: #eef1f6;
}

.pd-iframe {
	display: block;
	width: 100%;
	height: 100%;
	border: 0;
}

.pd-caption {
	margin: var(--s-4) auto 0;
	max-width: 62ch;
	color: var(--on-dark-muted);
	font-size: 0.9rem;
	text-align: center;
}

@media (max-width: 640px) {
	.pd-url {
		display: none;
	}
	.pd-chrome {
		gap: var(--s-2);
	}
	.pd-live {
		flex: 1;
	}
	.pd-viewport {
		height: clamp(480px, 70vh, 620px);
	}
}

@media (prefers-reduced-motion: reduce) {
	.pd-live__dot {
		animation: none;
	}
}

.fd-card {
	position: relative;
	padding: clamp(22px, 2.2vw, 34px) clamp(20px, 2.2vw, 34px) clamp(20px, 2vw, 32px);
	border-radius: 24px;
	/* No backdrop-filter: this scrolls, and blurring a scrolling surface
	   forces a continuous GPU repaint. The band behind it is a static
	   gradient, so an opaque fill is visually equivalent and far cheaper. */
	background: var(--fd-bg);
	box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06), 0 30px 60px -25px rgba(0, 0, 0, 0.7);
	overflow: hidden;
	isolation: isolate;
}

/* Ambient top glow. */
.fd-card::before {
	content: "";
	position: absolute;
	top: -60%;
	left: 10%;
	width: 60%;
	height: 140%;
	z-index: 0;
	pointer-events: none;
	background: radial-gradient(circle, color-mix(in srgb, var(--brand) 10%, transparent), transparent 65%);
}

/* Cursor spotlight, driven by the shared initSpotlight() in naxer.js via
   data-spotlight — same --spot-x/--spot-y/--spot-o contract as .card. */
.fd-card::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 0;
	pointer-events: none;
	opacity: var(--spot-o, 0);
	background: radial-gradient(260px circle at var(--spot-x) var(--spot-y), rgba(255, 255, 255, 0.07), transparent 60%);
	transition: opacity var(--t-slow) var(--ease);
}

.fd-card > * {
	position: relative;
	z-index: var(--z-base);
}

.fd-num-grad {
	background: linear-gradient(180deg, #ffffff, rgba(255, 255, 255, 0.72));
	-webkit-background-clip: text;
	background-clip: text;
	color: transparent;
}

/* ------------------------------------------------------------- fd header */
.fd-header {
	display: flex;
	align-items: flex-start;
	justify-content: space-between;
	flex-wrap: wrap;
	gap: 14px;
	margin-bottom: 18px;
}

.fd-eyebrow {
	display: block;
	margin-bottom: 6px;
	color: var(--fd-muted);
	font-family: var(--font-mono);
	font-size: 12.5px;
	font-weight: 500;
	letter-spacing: 0.14em;
	text-transform: uppercase;
}

.fd-total {
	font-size: 15px;
	color: var(--fd-muted);
}

.fd-total b {
	font-size: 20px;
	font-weight: 700;
	font-variant-numeric: tabular-nums;
}

.fd-header__right {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: 8px;
}

.fd-chip {
	padding: 7px 13px;
	border-radius: var(--r-pill);
	font-size: 12.5px;
	font-weight: 600;
	white-space: nowrap;
}

.fd-chip--ok {
	color: #7be3ad;
	background: rgba(52, 211, 153, 0.12);
	box-shadow: inset 0 0 0 1px rgba(52, 211, 153, 0.28);
}

.fd-chip--warn {
	color: #ffcf8a;
	background: rgba(255, 154, 77, 0.14);
	box-shadow: inset 0 0 0 1px rgba(255, 154, 77, 0.32);
}

.fd-live {
	display: inline-flex;
	align-items: center;
	gap: 7px;
	padding: 7px 13px 7px 11px;
	border-radius: var(--r-pill);
	color: #ffb3b5;
	background: color-mix(in srgb, var(--brand) 12%, transparent);
	box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--brand) 28%, transparent);
	font-size: 12.5px;
	font-weight: 600;
	white-space: nowrap;
}

.fd-live__dot {
	width: 7px;
	height: 7px;
	border-radius: 50%;
	background: var(--fd-accent);
	animation: fd-pulse 2s var(--ease-out) infinite;
}

@keyframes fd-pulse {
	0% {
		box-shadow: 0 0 0 0 color-mix(in srgb, var(--brand) 55%, transparent);
	}
	70% {
		box-shadow: 0 0 0 7px transparent;
	}
	100% {
		box-shadow: 0 0 0 0 transparent;
	}
}

/* ------------------------------------------------------------ fd toolbar */
.fd-toolbar {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 12px;
	margin-bottom: 22px;
}

.fd-range-group {
	display: inline-flex;
	gap: 2px;
	padding: 3px;
	border-radius: var(--r-pill);
	background: rgba(255, 255, 255, 0.04);
	box-shadow: inset 0 0 0 1px var(--fd-line);
}

.fd-range-btn {
	/* min-height keeps the tap target usable on touch; the compact look comes
	   from the small type, not from a cramped hit area. */
	display: inline-flex;
	align-items: center;
	min-height: 38px;
	padding: 8px 19px;
	border-radius: var(--r-pill);
	color: var(--fd-muted);
	font-family: inherit;
	font-size: 13px;
	font-weight: 600;
	transition: background-color var(--t) var(--ease), color var(--t) var(--ease);
}

.fd-range-btn:hover:not(.is-active) {
	color: var(--fd-text);
	background: rgba(255, 255, 255, 0.06);
}

.fd-range-btn.is-active {
	color: #fff;
	background: var(--fd-accent);
}

.fd-refresh {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 38px;
	height: 38px;
	flex: none;
	border-radius: 11px;
	color: var(--fd-muted);
	background: rgba(255, 255, 255, 0.04);
	box-shadow: inset 0 0 0 1px var(--fd-line);
	transition: color var(--t) var(--ease), background-color var(--t) var(--ease);
}

.fd-refresh:hover {
	color: var(--fd-text);
	background: rgba(255, 255, 255, 0.08);
}

.fd-refresh svg {
	width: 17px;
	height: 17px;
	stroke-width: 1.8;
	transition: transform 0.6s var(--ease);
}

.fd-refresh.is-spinning svg {
	transform: rotate(360deg);
}

/* -------------------------------------------------- fd composition bar */
.fd-bar {
	display: flex;
	width: 100%;
	height: 14px;
	margin-bottom: 14px;
	border-radius: var(--r-pill);
	background: rgba(255, 255, 255, 0.05);
	overflow: hidden;
}

.fd-bar__seg {
	height: 100%;
	width: 0%;
	background: var(--seg-color);
	transition: width 0.9s var(--ease-out);
}

.fd-bar__seg + .fd-bar__seg {
	margin-left: 2px;
}

.fd-legend {
	display: flex;
	flex-wrap: wrap;
	gap: 6px 24px;
	margin-bottom: 26px;
}

.fd-legend__item {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	color: var(--fd-muted);
	font-size: 13.5px;
}

.fd-legend__dot {
	width: 9px;
	height: 9px;
	flex: none;
	border-radius: 50%;
	background: var(--dot-color);
}

.fd-legend__item b {
	color: var(--fd-text);
	font-weight: 600;
	font-variant-numeric: tabular-nums;
}

/* ---------------------------------------------------------- fd stat grid */
/* Explicit column counts rather than auto-fit. The widget carries exactly six
   series, and auto-fit lands on 4 or 5 tracks across a range of widths, which
   strands one or two tiles on an orphan row. 2 / 3 / 6 always divide evenly. */
.fd-grid {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 14px;
}

@media (min-width: 700px) {
	.fd-grid {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}
}

/* 1180px is where a six-track row still leaves each tile wide enough for
   "Geozone Violation" to set on one line. */
@media (min-width: 1180px) {
	.fd-grid {
		grid-template-columns: repeat(6, minmax(0, 1fr));
	}
}

.fd-stat {
	--accent: var(--c-idle);
	padding: 20px 18px 18px;
	border-radius: 16px;
	background: rgba(255, 255, 255, 0.025);
	box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.07);
	opacity: 0;
	transform: translateY(6px);
	animation: fd-rise 0.5s var(--ease-out) forwards;
	animation-delay: var(--delay, 0s);
	transition: background-color var(--t) var(--ease), transform var(--t) var(--ease),
		box-shadow var(--t) var(--ease);
}

.fd-stat:hover {
	transform: translateY(-2px);
	background: color-mix(in srgb, var(--accent) 7%, rgba(255, 255, 255, 0.025));
	box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 45%, transparent);
}

@keyframes fd-rise {
	to {
		opacity: 1;
		transform: translateY(0);
	}
}

/* Tiles in an alert state keep a slow breathing ring. */
.fd-stat--alert {
	animation: fd-rise 0.5s var(--ease-out) forwards, fd-alert 2.4s var(--ease) 0.6s infinite;
}

@keyframes fd-alert {
	0%,
	100% {
		box-shadow: 0 0 0 1px color-mix(in srgb, var(--accent) 40%, transparent);
	}
	50% {
		box-shadow: 0 0 0 1px color-mix(in srgb, var(--accent) 75%, transparent),
			0 0 16px -3px color-mix(in srgb, var(--accent) 60%, transparent);
	}
}

.fd-stat__top {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 8px;
	margin-bottom: 14px;
}

.fd-stat__icon {
	display: flex;
	align-items: center;
	justify-content: center;
	flex: none;
	width: 38px;
	height: 38px;
	border-radius: 11px;
	color: var(--accent);
	background: color-mix(in srgb, var(--accent) 16%, transparent);
	box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 30%, transparent),
		0 6px 16px -9px var(--accent);
}

.fd-stat__icon svg {
	width: 20px;
	height: 20px;
	stroke-width: 1.8;
}

.fd-stat__pct {
	padding: 3px 9px;
	border-radius: var(--r-pill);
	color: var(--accent);
	background: color-mix(in srgb, var(--accent) 14%, transparent);
	font-size: 12.5px;
	font-weight: 600;
	font-variant-numeric: tabular-nums;
}

.fd-stat__num {
	margin-bottom: 5px;
	font-size: 34px;
	font-weight: 700;
	line-height: 1;
	letter-spacing: -0.02em;
	font-variant-numeric: tabular-nums;
}

.fd-stat__label {
	margin-bottom: 12px;
	color: var(--fd-muted);
	font-size: 14px;
}

.fd-stat__spark {
	display: block;
	width: 100%;
	height: 32px;
	margin-bottom: 12px;
	color: var(--accent);
	line-height: 0;
	overflow: hidden;
}

.fd-spark {
	display: block;
	width: 100%;
	height: 100%;
	overflow: hidden;
}

.fd-stat__link {
	display: inline-flex;
	align-items: center;
	gap: 5px;
	width: 100%;
	padding-top: 10px;
	border-top: 1px solid rgba(255, 255, 255, 0.07);
	color: var(--accent);
	font-size: 13px;
	font-weight: 600;
}

.fd-stat__link svg {
	width: 13px;
	height: 13px;
	stroke-width: 2.2;
	transition: transform var(--t) var(--ease-spring);
}

.fd-stat__link:hover svg {
	transform: translateX(3px);
}

@media (max-width: 480px) {
	.fd-card {
		padding: 20px 16px;
		border-radius: 16px;
	}
	.fd-toolbar {
		flex-wrap: wrap;
	}
	.fd-stat__num {
		font-size: 28px;
	}
}

@media (prefers-reduced-motion: reduce) {
	.fd-stat,
	.fd-stat--alert {
		animation: none;
		opacity: 1;
		transform: none;
	}
	.fd-bar__seg {
		transition: none;
	}
	.fd-live__dot,
	.fd-ring {
		animation: none;
	}
	.fd-card::after {
		display: none;
	}
}

/* ==========================================================================
   11. FORMS
   ========================================================================== */

.form-card {
	padding: clamp(var(--s-4), 4vw, var(--s-8));
	border-radius: var(--r-2xl);
	background: var(--surface);
	box-shadow: var(--bevel-ring), var(--bevel), var(--shadow-lg);
}

.field {
	display: grid;
	gap: 7px;
	margin-bottom: var(--s-4);
}

.field > label {
	color: var(--text-strong);
	font-size: var(--fs-xs);
	font-weight: 650;
	letter-spacing: -0.008em;
}

.field > label .req {
	color: var(--brand);
}

.field-row {
	display: grid;
	gap: var(--s-4);
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr));
}

.input,
.select,
.textarea {
	width: 100%;
	padding: 13px 16px;
	border: 0;
	border-radius: var(--r-md);
	background: var(--surface-2);
	color: var(--text);
	font-size: var(--fs-sm);
	line-height: 1.5;
	box-shadow: inset 0 0 0 1px var(--hairline);
	transition: box-shadow var(--t) var(--ease), background-color var(--t) var(--ease);
	outline: none;
}

.input::placeholder,
.textarea::placeholder {
	color: var(--text-faint);
}

.input:hover,
.select:hover,
.textarea:hover {
	box-shadow: inset 0 0 0 1px var(--hairline-strong);
}

.input:focus,
.select:focus,
.textarea:focus {
	background: var(--surface);
	box-shadow: inset 0 0 0 1px var(--brand), 0 0 0 4px var(--brand-soft);
}

.textarea {
	min-height: 138px;
	resize: vertical;
}

.select {
	appearance: none;
	padding-right: 42px;
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2355677f' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
	background-repeat: no-repeat;
	background-position: right 15px center;
	background-size: 15px;
	cursor: pointer;
}

/* -------------------------------------------------------- validation */
/* Inline and quiet — never a window.alert. */
.field__error {
	display: none;
	align-items: center;
	gap: 6px;
	color: var(--brand);
	font-size: var(--fs-xs);
	font-weight: 600;
}

.field__error svg {
	width: 13px;
	height: 13px;
	flex: none;
	stroke-width: 2;
}

.field.is-invalid .field__error {
	display: flex;
}

.field.is-invalid .input,
.field.is-invalid .select,
.field.is-invalid .textarea {
	box-shadow: inset 0 0 0 1px var(--brand), 0 0 0 4px var(--brand-soft);
}

.form-note {
	margin-top: var(--s-4);
	color: var(--text-faint);
	font-size: var(--fs-xs);
	line-height: 1.6;
}

.form-note a {
	color: var(--brand);
	text-decoration: underline;
	text-underline-offset: 0.2em;
}

/* Google renders the widget at a fixed 304px. On a 360px screen the container
   only offers ~288px inside the card, so it pushes the whole grid track wide
   and the page scrolls sideways. Scaling it is the only lever — the widget is
   a third-party iframe and its internal width cannot be styled. */
.g-recaptcha {
	margin-bottom: var(--s-4);
}

/* `zoom`, not `transform: scale()`. A transform is purely visual — the widget
   would still occupy its full 304px in layout and keep forcing the grid track
   wide. `zoom` scales the layout box, which is the whole point here. */
@media (max-width: 420px) {
	.g-recaptcha {
		zoom: 0.86;
	}
}

/* 320px is the WCAG 1.4.10 reflow baseline; the card offers ~248px there. */
@media (max-width: 359px) {
	.g-recaptcha {
		zoom: 0.78;
	}
}

/* Button busy state — the label is swapped for a track, not a spinner. */
.btn.is-busy {
	pointer-events: none;
	color: transparent;
}

.btn.is-busy::after {
	content: "";
	position: absolute;
	width: 17px;
	height: 17px;
	border-radius: 50%;
	border: 2px solid rgba(255, 255, 255, 0.35);
	border-top-color: #fff;
	animation: spin 0.7s linear infinite;
}

@keyframes spin {
	to {
		transform: rotate(360deg);
	}
}

/* Skeleton placeholder matching the shape of what is loading. */
.skeleton {
	border-radius: var(--r-sm);
	background: linear-gradient(90deg, var(--surface-3) 25%, var(--surface-2) 50%, var(--surface-3) 75%);
	background-size: 200% 100%;
	animation: shimmer 1.5s var(--ease) infinite;
}

@keyframes shimmer {
	to {
		background-position: -200% 0;
	}
}

/* ==========================================================================
   12. BLOG
   ========================================================================== */

.post-featured {
	display: grid;
	gap: clamp(var(--s-5), 4vw, var(--s-8));
	align-items: center;
	grid-template-columns: 1fr;
	padding: clamp(var(--s-5), 3vw, var(--s-6));
	border-radius: var(--r-2xl);
	background: var(--surface);
	box-shadow: var(--bevel-ring), var(--bevel), var(--shadow);
	transition: transform var(--t-slow) var(--ease), box-shadow var(--t-slow) var(--ease);
}

.post-featured:hover {
	transform: translateY(-3px);
	box-shadow: 0 0 0 1px var(--hairline-strong), var(--bevel), var(--shadow-lg);
}

@media (min-width: 860px) {
	.post-featured {
		grid-template-columns: 1.1fr 1fr;
	}
}

.post-featured__media {
	overflow: hidden;
	border-radius: var(--r-lg);
	aspect-ratio: 16 / 10;
}

.post-featured__media img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: transform var(--t-slower) var(--ease);
}

.post-featured:hover .post-featured__media img {
	transform: scale(1.04);
}

.post-featured__body h2,
.post-featured__body h3 {
	margin-block: var(--s-3);
	font-size: clamp(1.5rem, 1.2rem + 1.4vw, 2.125rem);
}

.post-featured__body p {
	color: var(--text-muted);
	font-size: var(--fs-sm);
	line-height: 1.7;
}

.post-card {
	position: relative;
	display: flex;
	flex-direction: column;
	overflow: hidden;
	border-radius: var(--r-xl);
	background: var(--surface);
	box-shadow: var(--bevel-ring), var(--bevel), var(--shadow-sm);
	transition: transform var(--t-slow) var(--ease), box-shadow var(--t-slow) var(--ease);
}

.post-card:hover {
	transform: translateY(-4px);
	box-shadow: 0 0 0 1px var(--hairline-strong), var(--bevel), var(--shadow-lg);
}

.post-card__media {
	aspect-ratio: 16 / 9;
	overflow: hidden;
	background: var(--surface-3);
}

.post-card__media img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: transform var(--t-slower) var(--ease);
}

.post-card:hover .post-card__media img {
	transform: scale(1.05);
}

.post-card__body {
	display: flex;
	flex-direction: column;
	flex: 1;
	padding: var(--s-5) var(--s-6) var(--s-6);
}

.post-card__body h3 {
	margin-block: var(--s-3);
	font-size: var(--fs-h4);
	line-height: 1.3;
}

.post-card__body p {
	color: var(--text-muted);
	font-size: var(--fs-sm);
	line-height: 1.66;
}

.post-card__body .link-arrow {
	margin-top: auto;
	padding-top: var(--s-5);
}

/* Whole card is the hit area, so the title link stays the accessible name. */
.post-card__body h3 a::after {
	content: "";
	position: absolute;
	inset: 0;
}

.post-card__meta {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--s-2) var(--s-4);
	color: var(--text-faint);
	font-family: var(--font-mono);
	font-size: var(--fs-2xs);
	text-transform: uppercase;
	letter-spacing: 0.11em;
}

.post-card__meta time {
	white-space: nowrap;
}

/* ==========================================================================
   13. UTILITIES & MOTION
   ========================================================================== */

.sr-only {
	position: absolute;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
	border: 0;
}

.center {
	text-align: center;
}

.mt-0 {
	margin-top: 0;
}
.mt-4 {
	margin-top: var(--s-4);
}
.mt-5 {
	margin-top: var(--s-5);
}
.mt-6 {
	margin-top: var(--s-6);
}
.mt-7 {
	margin-top: var(--s-7);
}
.mb-4 {
	margin-bottom: var(--s-4);
}
.mb-5 {
	margin-bottom: var(--s-5);
}
.mb-6 {
	margin-bottom: var(--s-6);
}

/* ------------------------------------------------------- scroll reveal */
/* Armed only when the `js` class is present, so content is never stranded
   invisible if the script fails to run. Heavy, cinematic entry: the element
   rises and resolves out of a blur rather than just fading. */
.js [data-reveal] {
	opacity: 0;
	transform: translateY(26px);
	filter: blur(6px);
	transition: opacity var(--t-slower) var(--ease-out), transform var(--t-slower) var(--ease-out),
		filter var(--t-slower) var(--ease-out);
	transition-delay: var(--reveal-delay, 0ms);
	will-change: transform, opacity;
}

.js [data-reveal].is-visible {
	opacity: 1;
	transform: none;
	filter: blur(0);
	/* Dropped once the animation is done so the layer is released. */
	will-change: auto;
}

/* Directional variants. */
.js [data-reveal="left"] {
	transform: translateX(-30px);
}

.js [data-reveal="right"] {
	transform: translateX(30px);
}

.js [data-reveal="scale"] {
	transform: scale(0.95);
}

.js [data-reveal="none"] {
	transform: none;
	filter: none;
}

/* A wrapper that drifts toward the cursor while the control inside keeps its
   own hover transform. Composing them on one element would conflict. */
.magnet {
	display: inline-flex;
	will-change: transform;
	transition: transform var(--t-slow) var(--ease-out);
}

/* Text that assembles line by line — used on the hero headline only.
   The padding gives descenders room; without it the clip cuts g, y and p. */
.js .reveal-lines .line {
	display: block;
	overflow: hidden;
	padding-bottom: 0.14em;
	margin-bottom: -0.1em;
}

.js .reveal-lines .line > span {
	display: block;
	transform: translateY(105%);
	transition: transform var(--t-slower) var(--ease-out);
	transition-delay: calc(var(--i, 0) * 90ms);
}

.js .reveal-lines.is-visible .line > span {
	transform: translateY(0);
}

/* ==========================================================================
   20. PREMIUM LAYER
   The plate system the whole site is built on. Section 8b built it for the
   homepage; this generalises it so every page carries the same construction
   with its own colour, and lifts the surfaces, sections and chrome to match.
   ========================================================================== */

/* ------------------------------------------------------- plate palettes */
/* Four hues and four blobs per page family. Mid-tone and saturated on
   purpose: a plate is never a white surface and never a black one. The page
   declares which family it belongs to with data-plate on <body>, so a
   visitor moving between Solutions, Hardware and Company feels the site
   change key without ever leaving the design system. */
body {
	--pl-1: #3f2a8c;
	--pl-2: #26418f;
	--pl-3: #6a2f8e;
	--pl-4: #14607e;
	--pl-b1: rgba(34, 211, 238, 0.40);
	--pl-b2: rgba(244, 103, 109, 0.38);
	--pl-b3: rgba(139, 92, 246, 0.44);
	--pl-b4: rgba(240, 165, 43, 0.28);
	/* The single accent this page tints its shadows, rules and auras with. */
	--pl-accent: 139, 92, 246;
}

/* Home — indigo into orchid, the reference plate. */
body[data-plate="home"] {
	--pl-1: #3a2a84;
	--pl-2: #2f3fa8;
	--pl-3: #7b3090;
	--pl-4: #17638c;
	--pl-b1: rgba(34, 211, 238, 0.42);
	--pl-b2: rgba(244, 103, 109, 0.40);
	--pl-b3: rgba(139, 92, 246, 0.46);
	--pl-b4: rgba(240, 165, 43, 0.30);
	--pl-accent: 124, 233, 255;
}

/* Solutions — the product pages run teal into indigo. */
body[data-plate="solutions"] {
	--pl-1: #1d5f86;
	--pl-2: #1f3f9c;
	--pl-3: #128a86;
	--pl-4: #3b2f8f;
	--pl-b1: rgba(34, 211, 238, 0.46);
	--pl-b2: rgba(18, 185, 129, 0.34);
	--pl-b3: rgba(99, 132, 246, 0.44);
	--pl-b4: rgba(244, 103, 109, 0.26);
	--pl-accent: 34, 211, 238;
}

/* Hardware — steel into violet, cooler and more metallic. */
body[data-plate="hardware"] {
	--pl-1: #2c3f96;
	--pl-2: #4a3aa0;
	--pl-3: #17608f;
	--pl-4: #6a2f86;
	--pl-b1: rgba(120, 170, 255, 0.42);
	--pl-b2: rgba(139, 92, 246, 0.42);
	--pl-b3: rgba(34, 211, 238, 0.36);
	--pl-b4: rgba(244, 103, 109, 0.24);
	--pl-accent: 120, 170, 255;
}

/* Company — indigo into plum, the warmest of the set. */
body[data-plate="company"] {
	--pl-1: #3f2a8c;
	--pl-2: #6a2f8e;
	--pl-3: #26418f;
	--pl-4: #14607e;
	--pl-b1: rgba(199, 120, 255, 0.40);
	--pl-b2: rgba(244, 103, 109, 0.36);
	--pl-b3: rgba(99, 132, 246, 0.42);
	--pl-b4: rgba(240, 165, 43, 0.26);
	--pl-accent: 199, 120, 255;
}

/* Commerce — amethyst into magenta. The pages where money is discussed get
   the richest plate in the set. */
body[data-plate="commerce"] {
	--pl-1: #6a2a8f;
	--pl-2: #92306f;
	--pl-3: #3b2b90;
	--pl-4: #17607e;
	--pl-b1: rgba(255, 130, 200, 0.36);
	--pl-b2: rgba(244, 103, 109, 0.40);
	--pl-b3: rgba(139, 92, 246, 0.46);
	--pl-b4: rgba(34, 211, 238, 0.28);
	--pl-accent: 244, 103, 109;
}

/* Content — reading pages, cooler and calmer so long copy sits quietly. */
body[data-plate="content"] {
	--pl-1: #175f7a;
	--pl-2: #2b3f92;
	--pl-3: #1f7a6a;
	--pl-4: #5a2f86;
	--pl-b1: rgba(34, 211, 238, 0.38);
	--pl-b2: rgba(18, 185, 129, 0.32);
	--pl-b3: rgba(139, 92, 246, 0.38);
	--pl-b4: rgba(120, 170, 255, 0.28);
	--pl-accent: 18, 185, 129;
}

/* Legal and 404 — the quietest plate. Still colour, never grey. */
body[data-plate="legal"] {
	--pl-1: #3a3474;
	--pl-2: #2a3f78;
	--pl-3: #56357a;
	--pl-4: #1b5a72;
	--pl-b1: rgba(139, 92, 246, 0.30);
	--pl-b2: rgba(120, 170, 255, 0.28);
	--pl-b3: rgba(34, 211, 238, 0.26);
	--pl-b4: rgba(244, 103, 109, 0.18);
	--pl-accent: 139, 92, 246;
}

/* Both heroes read the palette through one set of names. Control Room takes
   every hue deeper toward the same near-black violet, so the two art
   directions stay recognisably the same page. */
.hero--premium,
.page-hero {
	--h-plate-1: var(--pl-1);
	--h-plate-2: var(--pl-2);
	--h-plate-3: var(--pl-3);
	--h-plate-4: var(--pl-4);
	--h-blob-1: var(--pl-b1);
	--h-blob-2: var(--pl-b2);
	--h-blob-3: var(--pl-b3);
	--h-blob-4: var(--pl-b4);
}

:root[data-theme="dark"] .hero--premium,
:root[data-theme="dark"] .page-hero {
	--h-plate-1: color-mix(in srgb, var(--pl-1) 74%, #0d0822);
	--h-plate-2: color-mix(in srgb, var(--pl-2) 74%, #0d0822);
	--h-plate-3: color-mix(in srgb, var(--pl-3) 74%, #0d0822);
	--h-plate-4: color-mix(in srgb, var(--pl-4) 74%, #0d0822);
}

/* =================================================== the inner-page plate */
/* Built entirely out of what every page already ships: the section itself,
   its two pseudo-elements, and the .hero__bg / .hero__grid divs that were
   already in the markup — plus their pseudos. Six paint layers, no new
   elements on any of the 32 pages. */
.page-hero {
	/* Light ink on the plate in both directions, exactly as .hero--premium. */
	--hero-ink: #ffffff;
	--hero-ink-muted: rgba(228, 233, 255, 0.80);
	--hero-line: rgba(255, 255, 255, 0.16);
	--hero-surface: rgba(255, 255, 255, 0.10);
	--hero-surface-hover: rgba(255, 255, 255, 0.18);
	--hero-surface-ring: rgba(255, 255, 255, 0.22);
	--grid-line: rgba(255, 255, 255, 0.06);

	padding-block: clamp(var(--s-7), 5.5vw, 116px) clamp(var(--s-7), 5vw, 96px);
	background:
		radial-gradient(112% 88% at 6% -8%, var(--h-plate-2), transparent 58%),
		radial-gradient(96% 82% at 98% 0%, var(--h-plate-3), transparent 60%),
		radial-gradient(120% 106% at 46% 120%, var(--h-plate-4), transparent 66%),
		linear-gradient(152deg, var(--h-plate-1) 0%, var(--h-plate-2) 54%, var(--h-plate-1) 100%);
	color: var(--hero-ink-muted);
}

/* Layer: the conic sheen, off-centre so no starburst is ever visible. */
.page-hero::before {
	z-index: -4;
	inset: -180% -150% -110% -10%;
	background: conic-gradient(from 0deg,
			transparent 0 6%,
			rgba(190, 228, 255, 0.15) 13%,
			transparent 24%,
			rgba(255, 168, 196, 0.13) 40%,
			transparent 55%,
			rgba(170, 150, 255, 0.17) 72%,
			transparent 86%,
			rgba(120, 240, 220, 0.11) 94%,
			transparent 100%);
	mix-blend-mode: plus-lighter;
	animation: hero-beam 52s linear infinite;
	will-change: transform;
	pointer-events: none;
}

/* Layer: the bottom vignette, so the plate resolves into the canvas. */
.page-hero::after {
	z-index: -1;
	background-image: none;
	background: linear-gradient(180deg, rgba(9, 6, 26, 0.22) 0%, transparent 24%,
			transparent 60%, rgba(9, 6, 26, 0.32) 100%);
	mask-image: none;
	-webkit-mask-image: none;
}

/* Layers: the aurora. One div, three drifting blobs — the element and both
   of its pseudo-elements, each on its own timing. */
.page-hero .hero__bg {
	z-index: -3;
	inset: -14% -8%;
	background: radial-gradient(closest-side circle, var(--h-blob-1), transparent 70%);
	background-size: 62% 74%;
	background-position: 4% 0%;
	background-repeat: no-repeat;
	mix-blend-mode: screen;
	animation: hero-drift-a 29s ease-in-out infinite alternate;
	will-change: transform;
}

.page-hero .hero__bg::before,
.page-hero .hero__bg::after {
	content: "";
	position: absolute;
	inset: 0;
	background-repeat: no-repeat;
	will-change: transform;
}

.page-hero .hero__bg::before {
	background-image: radial-gradient(closest-side circle, var(--h-blob-3), transparent 70%);
	background-size: 58% 80%;
	background-position: 96% 4%;
	animation: hero-drift-b 37s ease-in-out infinite alternate;
}

.page-hero .hero__bg::after {
	background-image: radial-gradient(closest-side circle, var(--h-blob-2), transparent 72%);
	background-size: 70% 96%;
	background-position: 44% 130%;
	animation: hero-drift-c 44s ease-in-out infinite alternate;
}

/* Layer: the surveyor grid, drifting exactly one cell so it never seams. */
.page-hero .hero__grid {
	z-index: -2;
	inset: -60px;
	background-size: 60px 60px;
	mask-image: radial-gradient(74% 70% at 42% 30%, #000 14%, transparent 78%);
	-webkit-mask-image: radial-gradient(74% 70% at 42% 30%, #000 14%, transparent 78%);
	animation: page-grid 26s linear infinite;
	will-change: transform;
}

@keyframes page-grid {
	to {
		transform: translate3d(60px, 60px, 0);
	}
}

/* The breadcrumb and headline sit above every layer. */
.page-hero > .container {
	position: relative;
	z-index: var(--z-base);
}

.page-hero h1 {
	letter-spacing: -0.042em;
	text-wrap: balance;
}

.page-hero .lead,
.page-hero p {
	max-width: 62ch;
	text-wrap: pretty;
}

/* ------------------------------------------------- ambient section depth */
/* A flat band of text on a flat canvas is the thing that reads as unfinished.
   Every section gets a soft field of its page's accent, alternating sides so
   the eye is led down the page instead of scanning a stack of rectangles. */
.section::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	pointer-events: none;
	background: radial-gradient(46% 62% at 12% 8%, rgba(var(--pl-accent), 0.07), transparent 64%);
}

.section:nth-of-type(even)::after {
	background: radial-gradient(46% 62% at 88% 12%, rgba(var(--pl-accent), 0.06), transparent 64%);
}

/* Bands that already own their background do not need a second field. */
.section--dark::after,
.section--alt::after,
.section--sunken::after {
	display: none;
}

/* The hairline between two plain sections, lit in the middle. */
.section--rule {
	border-top: 1px solid transparent;
	border-image: linear-gradient(90deg, transparent, var(--hairline-strong) 22%,
			rgba(var(--pl-accent), 0.5) 50%, var(--hairline-strong) 78%, transparent) 1;
}

/* --------------------------------------------------------- premium surfaces */
/* The card already has the double bezel. What it was missing is the lit top
   edge and a shadow that carries the page's hue instead of neutral black. */
.card,
.plan,
.post-card,
.industry-card,
.device-card,
.office-card,
.dl-item,
.form-card {
	transition: transform var(--t-slow) var(--ease-spring), box-shadow var(--t-slow) var(--ease),
		background-color var(--t) var(--ease), border-color var(--t) var(--ease);
}

.card::after,
.plan::after,
.post-card::after,
.industry-card::after,
.device-card::after {
	content: "";
	position: absolute;
	top: 0;
	left: 12%;
	right: 12%;
	height: 1px;
	border-radius: var(--r-pill);
	background: linear-gradient(90deg, transparent, rgba(var(--pl-accent), 0.55), transparent);
	opacity: 0;
	transition: opacity var(--t-slow) var(--ease), left var(--t-slow) var(--ease),
		right var(--t-slow) var(--ease);
	pointer-events: none;
}

.card:hover::after,
.plan:hover::after,
.post-card:hover::after,
.industry-card:hover::after,
.device-card:hover::after {
	opacity: 1;
	left: 4%;
	right: 4%;
}

.card:hover,
.plan:hover,
.post-card:hover,
.industry-card:hover,
.device-card:hover,
.office-card:hover,
.dl-item:hover {
	box-shadow: var(--bevel-ring), var(--bevel), var(--shadow-lg),
		0 24px 60px -34px rgba(var(--pl-accent), 0.55);
}

/* --------------------------------------------------------------- chrome */
/* Scroll progress, injected by initScrollRail(). Scales on the compositor —
   it never touches width. */
.scroll-rail {
	position: fixed;
	top: 0;
	left: 0;
	z-index: var(--z-header);
	width: 100%;
	height: 2px;
	transform-origin: 0 50%;
	transform: scaleX(0);
	background: linear-gradient(90deg, rgba(var(--pl-accent), 0.9), var(--brand));
	box-shadow: 0 0 14px rgba(var(--pl-accent), 0.6);
	pointer-events: none;
}

/* The nav link's underline sweeps in from the left rather than fading. */
.nav__link::before {
	content: "";
	position: absolute;
	left: var(--s-3);
	right: var(--s-3);
	bottom: 6px;
	height: 1px;
	background: currentColor;
	opacity: 0.55;
	transform: scaleX(0);
	transform-origin: 0 50%;
	transition: transform var(--t-slow) var(--ease);
}

.nav__link:hover::before {
	transform: scaleX(1);
}

/* The current page already has its signal dot down there. */
.nav__link[aria-current="page"]::before {
	display: none;
}

/* ------------------------------------------------- the section header */
/* Every section on every page opens with one of these, so this is the single
   highest-leverage place to make a section feel composed rather than typed:
   a lit accent dot on the eyebrow, ink that falls off toward the baseline,
   and a short accent rule closing the block. */
/* Some eyebrows already ship their own dot in the markup. */
.section-head .eyebrow:has(.eyebrow__dot)::before {
	display: none;
}

.section-head .eyebrow::before {
	content: "";
	width: 6px;
	height: 6px;
	flex: none;
	border-radius: 50%;
	background: rgb(var(--pl-accent));
	box-shadow: 0 0 0 4px rgba(var(--pl-accent), 0.16), 0 0 12px rgba(var(--pl-accent), 0.8);
}

/* Derived from currentColor, so a heading that sets its own colour — the
   white ones on the dark bands — keeps it.
   `color` is deliberately NOT set to transparent: currentColor would then
   resolve against that transparent value and the gradient would be built out
   of nothing. Only the glyph fill is cleared, which also means a browser
   without -webkit-text-fill-color still renders the heading normally. */
@supports (background-clip: text) or (-webkit-background-clip: text) {
	.section-head h2,
	.section-head .h2 {
		background-image: linear-gradient(178deg, currentColor 28%,
				color-mix(in srgb, currentColor 60%, transparent) 100%);
		-webkit-background-clip: text;
		background-clip: text;
		-webkit-text-fill-color: transparent;
	}
}

.section-head::after {
	content: "";
	display: block;
	width: 64px;
	height: 2px;
	margin-top: clamp(var(--s-4), 2vw, var(--s-5));
	border-radius: var(--r-pill);
	background: linear-gradient(90deg, rgb(var(--pl-accent)), transparent);
}

.section-head--center::after {
	margin-inline: auto;
	background: linear-gradient(90deg, transparent, rgb(var(--pl-accent)), transparent);
	width: 108px;
}

/* --------------------------------------------------------------- shaders */
/* The GPU layer, injected by initShaders(). It sits between the flat plate
   and the CSS layers above it, so everything still works without WebGL —
   this only ever adds. Masked at the edges so the field dissolves into the
   plate instead of ending at the section boundary. */
.shader {
	position: absolute;
	inset: 0;
	z-index: -4;
	display: block;
	width: 100%;
	height: 100%;
	/* Enough to read as a live field, not so much that it replaces the plate
	   the CSS already lays down underneath it. */
	opacity: 0.52;
	pointer-events: none;
	-webkit-mask-image: radial-gradient(128% 118% at 50% 34%, #000 42%, transparent 96%);
	mask-image: radial-gradient(128% 118% at 50% 34%, #000 42%, transparent 96%);
}

.page-hero .shader {
	z-index: -3;
	opacity: 0.58;
}

/* The testimonial band is near-black, so the shader runs on plate hues taken
   most of the way down — a field of colour in the dark, not a light box. */
.quotes {
	--h-plate-1: color-mix(in srgb, var(--pl-1) 46%, #05030d);
	--h-plate-2: color-mix(in srgb, var(--pl-2) 52%, #05030d);
	--h-plate-3: color-mix(in srgb, var(--pl-3) 44%, #05030d);
	--h-plate-4: color-mix(in srgb, var(--pl-4) 50%, #05030d);
}

.quotes .shader {
	z-index: -1;
	opacity: 0.9;
}

/* ------------------------------------------------------ premium testimonial */
/* One quote at a time, at the size the words deserve. */
.quotes .quote-card--feature {
	position: relative;
	overflow: hidden;
}

/* The lit top edge, brightest at the corner the eye enters from. */
.quotes .quote-card--feature::before {
	content: "";
	position: absolute;
	top: 0;
	left: 8%;
	right: 8%;
	height: 1px;
	background: linear-gradient(90deg, transparent, rgba(var(--pl-accent), 0.7) 30%,
			rgba(255, 255, 255, 0.5) 55%, transparent);
}

.quote-card__glyph {
	color: rgb(var(--pl-accent));
	background: linear-gradient(150deg, rgba(var(--pl-accent), 0.26), rgba(var(--pl-accent), 0.07));
	box-shadow: inset 0 0 0 1px rgba(var(--pl-accent), 0.34),
		inset 0 1px 0 rgba(255, 255, 255, 0.16),
		0 16px 34px -20px rgba(var(--pl-accent), 0.8);
}

.quotes .quote-card--feature blockquote {
	font-family: var(--font-display);
	font-size: clamp(1.375rem, 0.95rem + 1.35vw, 2.125rem);
	font-weight: 500;
	line-height: 1.32;
	letter-spacing: -0.028em;
	text-wrap: pretty;
	color: #fff;
}

.quotes .quote-card__author .avatar {
	box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.18), 0 0 0 5px rgba(var(--pl-accent), 0.12);
}

/* The counter, so the rail says how far through it you are without counting
   dots. Tabular figures — the number must not shuffle as it changes. */
.quotes__count {
	margin-left: var(--s-4);
	color: var(--on-dark-muted);
	font-family: var(--font-mono);
	font-size: var(--fs-2xs);
	font-variant-numeric: tabular-nums;
	letter-spacing: 0.16em;
}

.quotes__count b {
	color: #fff;
	font-weight: 600;
}

.quotes__dot[aria-selected="true"] {
	background: linear-gradient(90deg, rgb(var(--pl-accent)), var(--brand-400));
	box-shadow: 0 0 14px rgba(var(--pl-accent), 0.55);
}

.quotes__arrow:hover {
	color: #fff;
	background: rgba(var(--pl-accent), 0.16);
	box-shadow: inset 0 0 0 1px rgba(var(--pl-accent), 0.5),
		0 14px 30px -16px rgba(var(--pl-accent), 0.7);
	transform: translateY(-2px);
}

/* The rail sat on the full section rhythm, which left more air above and
   below one quote than it earns this far down the page. Padding only — the
   card, the type and the controls keep the scale they were designed at, and
   the asymmetric base is preserved so it still matches its neighbours. */
.quotes {
	--quotes-y: calc(var(--section-y-tight) * 0.72);
	padding-block: var(--quotes-y) calc(var(--quotes-y) * 1.08);
}

/* The card itself, brought down a step. The quote mark, the type and the
   avatar all shrink together — scaling the padding alone would have left an
   over-large quote in a box that no longer had room for it. */
.quotes .quote-card--feature {
	padding: clamp(var(--s-5), 3vw, 40px);
}

.quotes .quote-card__glyph {
	width: 42px;
	height: 42px;
	margin-bottom: clamp(var(--s-4), 2vw, var(--s-5));
}

.quotes .quote-card__glyph svg {
	width: 22px;
	height: 22px;
}

.quotes .quote-card--feature blockquote {
	font-size: clamp(1.2rem, 0.92rem + 0.95vw, 1.7rem);
	line-height: 1.38;
}

.quotes .quote-card--feature .quote-card__author {
	margin-top: clamp(var(--s-5), 2.2vw, var(--s-6));
}

.quotes .quote-card--feature .avatar {
	width: 46px;
	height: 46px;
}

/* ------------------------------------------------------------ quote wall */
/* Seven customer quotes used to live in a dot-and-arrow carousel, which meant
   six of them were never read. As a wall they are all on the page at once,
   and the ragged column heights do the work the dots were pretending to do.
   Multicolumn rather than grid: the quotes are different lengths, and this is
   the one layout that lets them stay that way. */
.quote-wall {
	columns: 1;
	column-gap: var(--s-5);
}

@media (min-width: 720px) {
	.quote-wall {
		columns: 2;
	}
}

@media (min-width: 1120px) {
	.quote-wall {
		columns: 3;
	}
}

.quote-wall .quote-card {
	/* A quote split across a column break is unreadable. */
	break-inside: avoid;
	-webkit-column-break-inside: avoid;
	margin-bottom: var(--s-5);
	padding: clamp(var(--s-5), 2.2vw, 34px);
	background: var(--on-dark-surface);
	box-shadow: 0 0 0 1px var(--on-dark-border), inset 0 1px 0 rgba(255, 255, 255, 0.08);
	backdrop-filter: blur(12px);
	-webkit-backdrop-filter: blur(12px);
}

.quote-wall .quote-card:hover {
	background: rgba(255, 255, 255, 0.07);
	box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.18), inset 0 1px 0 rgba(255, 255, 255, 0.12),
		0 26px 60px -30px rgba(var(--pl-accent), 0.5);
}

.quote-wall .quote-card blockquote {
	font-size: var(--fs-body);
	line-height: 1.62;
}

/* The first quote leads the wall: it is the one with the 300-vehicle number. */
.quote-wall .quote-card:first-child blockquote {
	font-size: var(--fs-lead);
	line-height: 1.55;
}

.quote-wall .quote-card:first-child {
	background: rgba(255, 255, 255, 0.08);
	box-shadow: 0 0 0 1px rgba(var(--pl-accent), 0.35),
		inset 0 1px 0 rgba(255, 255, 255, 0.14), 0 30px 70px -34px rgba(var(--pl-accent), 0.4);
}

/* --------------------------------------------------- asymmetric feature rows */
/* Three identical columns is the layout every marketing page defaults to.
   A quantity query catches the rows that are exactly three cards wide and
   gives the first one the lead, so the eye enters the row instead of
   scanning it. Rows of four, six or a single orphan are left alone. */
@media (min-width: 1100px) {
	.grid-3:has(> .card):has(> :nth-child(3):last-child) {
		grid-template-columns: repeat(7, minmax(0, 1fr));
	}

	.grid-3:has(> .card):has(> :nth-child(3):last-child) > :nth-child(1) {
		grid-column: span 3;
	}

	.grid-3:has(> .card):has(> :nth-child(3):last-child) > :nth-child(2),
	.grid-3:has(> .card):has(> :nth-child(3):last-child) > :nth-child(3) {
		grid-column: span 2;
	}
}

/* Headings never leave a single word stranded on the last line. */
h1,
h2,
h3,
.h2,
.h3,
.section-head h2 {
	text-wrap: balance;
}

p,
li {
	text-wrap: pretty;
}

@media (max-width: 860px) {
	/* Same call as the homepage: the conic layer is the one that repaints a
	   full-bleed gradient every frame. */
	.page-hero::before {
		display: none;
	}
}

/* ==========================================================================
   REDUCED MOTION
   Honour the preference completely: no transforms, no blur, no loops.
   Everything must still be fully visible and usable.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
	html {
		scroll-behavior: auto;
	}

	*,
	*::before,
	*::after {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
		scroll-behavior: auto !important;
	}

	.js [data-reveal],
	.js .reveal-lines .line > span {
		opacity: 1 !important;
		transform: none !important;
		filter: none !important;
	}

	.marquee__track {
		animation: none;
		transform: none;
	}

	/* The aurora keeps its colour, it just stops drifting. */
	.quotes__blob {
		animation: none;
	}

	.quotes__viewport {
		scroll-behavior: auto;
	}

	.dot-live::after {
		animation: none;
		opacity: 0;
	}

	/* Hover lifts are movement too — flatten them. */
	.card:hover,
	.plan:hover,
	.post-card:hover,
	.quote-card:hover,
	.industry-card:hover,
	.device-card:hover,
	.office-card:hover,
	.dl-item:hover,
	.marquee__logo:hover,
	.btn:hover,
	.btn:active {
		transform: none !important;
	}

	/* The premium hero and the live panel: the colour field, the plate and the
	   map all stay — they simply stop moving. `animation: none` rather than the
	   blanket 0.01ms above, so nothing lands on a keyframe that ends at
	   opacity 0 and disappears. */
	.hero__plate,
	.hero__blob,
	.hero__beam,
	.hero--premium .hero__grid,
	.hl--flow,
	.hero__cue-rail i,
	.sim::before,
	.sim__sweep,
	.sim__scanline,
	.sim__pulse,
	.sim__zone-ring,
	.sim__zone-pulse,
	.sim__veh-halo,
	.sim__lock,
	.hero__stage-in::before,
	.hero__stage-in .chip-float {
		animation: none !important;
	}

	.hero__glint {
		display: none;
	}

	/* No parallax, no pointer tilt — both are scroll/pointer-driven movement. */
	.hero__stage-in,
	.hero--premium .hero__copy,
	.sim {
		transform: none !important;
	}
}

/* ==========================================================================
   PRINT
   ========================================================================== */

@media print {
	.topbar,
	.site-header,
	.mobile-nav,
	.wa-float,
	.to-top,
	.marquee,
	.art-switch,
	.skip-link {
		display: none !important;
	}

	body {
		background: #fff;
		color: #000;
	}

	body::before,
	body::after {
		display: none;
	}

	.card,
	.plan,
	.post-card {
		box-shadow: none;
		border: 1px solid #ccc;
	}

	a[href^="http"]::after {
		content: " (" attr(href) ")";
		font-size: 0.85em;
		word-break: break-all;
	}
}
