/* ==========================================================================
   Qwikr — the design system
   ==========================================================================

   One stylesheet for the whole marketing site.

   It exists because there were two. `theme.css` spoke in --purple/--text/--bg
   and was light-only, with dark bands hardcoded into each section. The 2026
   homepage spoke in --ink/--accent/--soft, supported dark mode, and lived
   entirely inline in a standalone .html file that no template rendered. Two
   vocabularies for the same colours, drifting, with no way to change the brand
   in one place. This file is the merge, and the old one is retired.

   Order matters and is deliberate:
     1  tokens        the only place a colour is chosen
     2  reset & base  element defaults
     3  layout        wrap, section, head
     4  components    nav, buttons, cards, prose, footer …
     5  templates     homepage, hub, feature, pricing
     6  utilities     motion, focus, print

   Two rules worth keeping:

   - A section committed to one look must not depend on a token that flips.
     `.cta{background:var(--ink)}` looked right until dark mode inverted --ink,
     turning the band light while its hardcoded white text stayed white. Those
     sections take fixed colours and are marked below.

   - Dark mode is honoured from the OS AND from an explicit toggle, so the
     [data-theme] rules must be able to win in both directions — hence the
     light override, which is not redundant.
   ========================================================================== */


/* ==========================================================================
   1. TOKENS
   ========================================================================== */

:root {
    /* Ink — text, in descending emphasis */
    --ink:        #0A2540;
    --ink-2:      #425466;
    --ink-3:      #697386;

    /* Ground — surfaces, in ascending depth */
    --white:      #FFFFFF;
    --soft:       #F6F9FC;
    --soft-2:     #EEF3F9;
    --line:       #E3E8EF;

    /* Accent — one hue, used sparingly enough that it still means something */
    --accent:     #635BFF;
    --accent-dk:  #4F46E5;
    --accent-soft:#635BFF12;

    /* Status */
    --good:       #059669;
    --warn:       #B45309;
    --bad:        #DC2626;

    /* Type */
    --sans: 'Inter', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
    --mono: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;

    /* Form */
    --r:       14px;
    --r-sm:    9px;
    --shadow:  0 1px 2px rgba(10,37,64,.04), 0 8px 24px -12px rgba(10,37,64,.10);
    --shadow-lg: 0 2px 4px rgba(10,37,64,.05), 0 20px 48px -20px rgba(10,37,64,.18);
    --max:     76rem;
    --max-prose: 44rem;

    /* Fixed — these do not flip. The dark CTA band and the nav scrim need a
       colour that survives a theme change, for the reason in the header. */
    --fixed-deep:  #0A2540;
    --fixed-deep-2:#16223C;
    --fixed-on-deep: #C7D2E1;
    --fixed-line-on-deep: #3A4D68;

    /* ---- The prism ----
       Six hues around the spectrum. They are decorative by default — washes,
       bars, borders, graphics — because several of them (amber especially) do
       not carry enough contrast on white to be set as text.

       Each hub also claims one as its own identity, which is what makes this
       worth having rather than just colourful: the hue tells you where you are.
       A page sets --hue and --hue-ink, and everything downstream follows. */
    --prism-1: #635BFF;  /* indigo   — channels   */
    --prism-2: #0EA5E9;  /* sky      — stock      */
    --prism-3: #14B8A6;  /* teal     — storefront */
    --prism-4: #F59E0B;  /* amber    — selling    */
    --prism-5: #A855F7;  /* violet   — automation */
    --prism-6: #10B981;  /* emerald  — operations */

    --prism: linear-gradient(90deg,
        var(--prism-1), var(--prism-2), var(--prism-3),
        var(--prism-4), var(--prism-5), var(--prism-6), var(--prism-1));

    /* Defaults, overridden per page. --hue is free to be vivid; --hue-ink is
       the one that has to survive being read at 12px on white. */
    --hue: var(--accent);
    --hue-ink: var(--accent);
}

/* On a near-black surface the darkened inks go muddy — every one of them lands
   between 2.5:1 and 3.6:1, well under AA — so dark mode lifts the hue instead.
   Not to the vivid hue itself: measured against the dark hero at #0F172A the
   indigo only reaches 3.80:1, so channels alone would have failed while the
   other five passed. Mixed 80% with white it clears AA across all six, the
   worst being indigo at 5.34:1.
   !important because the page sets --hue-ink inline, and inline beats a plain
   rule. This is the one place the theme has to overrule the page. */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) body {
        --hue-ink: color-mix(in srgb, var(--hue) 80%, white) !important;
    }
}
:root[data-theme="dark"] body {
    --hue-ink: color-mix(in srgb, var(--hue) 80%, white) !important;
}

@media (prefers-color-scheme: dark) {
    :root {
        --ink:#F0F4F9; --ink-2:#AFBACB; --ink-3:#8593A8;
        --white:#0B1220; --soft:#0F172A; --soft-2:#151F33; --line:#22304A;
        --accent:#8B84FF; --accent-dk:#A6A0FF; --accent-soft:#8B84FF1A;
        --good:#4ADE9B; --warn:#E2A94A; --bad:#F87171;
        --shadow:0 1px 2px rgba(0,0,0,.4), 0 12px 32px -16px rgba(0,0,0,.6);
        --shadow-lg:0 2px 6px rgba(0,0,0,.5), 0 28px 64px -24px rgba(0,0,0,.75);
        --fixed-deep:#16223C;
    }
}

/* The toggle. Must beat the media query in BOTH directions, so light is
   spelled out rather than left to the cascade. */
:root[data-theme="dark"] {
    --ink:#F0F4F9; --ink-2:#AFBACB; --ink-3:#8593A8;
    --white:#0B1220; --soft:#0F172A; --soft-2:#151F33; --line:#22304A;
    --accent:#8B84FF; --accent-dk:#A6A0FF; --accent-soft:#8B84FF1A;
    --good:#4ADE9B; --warn:#E2A94A; --bad:#F87171;
    --shadow:0 1px 2px rgba(0,0,0,.4), 0 12px 32px -16px rgba(0,0,0,.6);
    --shadow-lg:0 2px 6px rgba(0,0,0,.5), 0 28px 64px -24px rgba(0,0,0,.75);
    --fixed-deep:#16223C;
}

:root[data-theme="light"] {
    --ink:#0A2540; --ink-2:#425466; --ink-3:#697386;
    --white:#FFFFFF; --soft:#F6F9FC; --soft-2:#EEF3F9; --line:#E3E8EF;
    --accent:#635BFF; --accent-dk:#4F46E5; --accent-soft:#635BFF12;
    --good:#059669; --warn:#B45309; --bad:#DC2626;
    --shadow:0 1px 2px rgba(10,37,64,.04), 0 8px 24px -12px rgba(10,37,64,.10);
    --shadow-lg:0 2px 4px rgba(10,37,64,.05), 0 20px 48px -20px rgba(10,37,64,.18);
    --fixed-deep:#0A2540;
}


/* ==========================================================================
   2. RESET & BASE
   ========================================================================== */

*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; padding: 0; }

html { scroll-behavior: smooth; scroll-padding-top: 5rem; -webkit-text-size-adjust: 100%; }

body {
    font-family: var(--sans);
    font-size: 16px;
    line-height: 1.65;
    color: var(--ink);
    background: var(--white);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    overflow-x: hidden;
}

a { color: inherit; text-decoration: none; }

h1, h2, h3, h4 { letter-spacing: -.03em; line-height: 1.15; text-wrap: balance; font-weight: 800; }
h1 { font-size: clamp(2.4rem, 5.6vw, 4rem); line-height: 1.03; }
h2 { font-size: clamp(1.8rem, 3.6vw, 2.6rem); line-height: 1.1; }
h3 { font-size: 1.08rem; font-weight: 700; }

img, svg, video { max-width: 100%; height: auto; display: block; }

/* Skip link — the first thing in the tab order, invisible until focused.
   Hidden by clipping rather than by left:-9999px: an off-canvas element still
   counts toward the document's scroll width in some engines, which shows up as
   a phantom horizontal scrollbar nobody can find the cause of. */
.skip {
    position: absolute; top: 0; left: 0; z-index: 999;
    width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
    background: var(--accent); color: #fff; padding: .7rem 1.2rem;
    border-radius: 0 0 var(--r-sm) 0; font-weight: 600;
}
.skip:focus { width: auto; height: auto; overflow: visible; clip: auto; }

:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }

::selection { background: var(--accent); color: #fff; }


/* ==========================================================================
   3. LAYOUT
   ========================================================================== */

.wrap { max-width: var(--max); margin: 0 auto; padding: 0 1.5rem; }
.wrap-narrow { max-width: 56rem; margin: 0 auto; padding: 0 1.5rem; }

section { padding: 5.5rem 0; }
section.tight { padding: 3.5rem 0; }
.on-soft { background: var(--soft); }

/* Section heading block */
.head { max-width: var(--max-prose); margin-bottom: 3rem; }
.head.centred { margin-left: auto; margin-right: auto; text-align: center; }
.head h2 { margin: .7rem 0 .9rem; }
.head .sub { font-size: 1.06rem; color: var(--ink-2); margin: 0; }

.eyebrow {
    font-size: .72rem; font-weight: 700; letter-spacing: .14em;
    text-transform: uppercase; color: var(--hue-ink);
}

/* ---------- the prism bar ---------- */
/* Sits under the nav on every page. Three pixels of the full spectrum, drifting
   slowly — the cheapest way to get colour onto pages that are otherwise ink on
   white, and it ties the six hub identities together into one family. */
.prism-bar {
    height: 3px; width: 100%;
    background: var(--prism);
    background-size: 300% 100%;
    animation: prism-drift 24s linear infinite;
}
@keyframes prism-drift { to { background-position: 300% 0; } }

/* A hairline version, for separating sections without a hard rule. */
.prism-rule {
    height: 1px; border: 0; background: var(--prism); opacity: .5;
}

/* Gradient text. Reserved for a few words — a whole heading in gradient is
   harder to read and stops feeling special by the second one. */
.prism-text {
    background: var(--prism); background-size: 200% 100%;
    -webkit-background-clip: text; background-clip: text; color: transparent;
    animation: prism-drift 18s linear infinite;
}

@media (prefers-reduced-motion: reduce) {
    .prism-bar, .prism-text { animation: none; }
}


/* ==========================================================================
   4. COMPONENTS
   ========================================================================== */

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

.btn {
    display: inline-flex; align-items: center; justify-content: center; gap: .4rem;
    font-family: inherit; font-weight: 600; font-size: .92rem; line-height: 1.2;
    padding: .68rem 1.15rem; border-radius: var(--r-sm);
    border: 1px solid transparent; cursor: pointer; white-space: nowrap;
    transition: background .15s ease, border-color .15s ease, transform .12s ease;
}
.btn:active { transform: translateY(1px); }
.btn-lg  { padding: .82rem 1.55rem; font-size: 1rem; }
.btn-sm  { padding: .45rem .8rem; font-size: .84rem; }
.btn-block { display: flex; width: 100%; }

.btn-primary { background: var(--accent); color: #fff; }
.btn-primary:hover { background: var(--accent-dk); }

.btn-ghost { background: var(--white); color: var(--ink); border-color: var(--line); }
.btn-ghost:hover { background: var(--soft); }

.btn-quiet { background: transparent; color: var(--ink-2); }
.btn-quiet:hover { color: var(--ink); background: var(--soft); }

/* ---------- 4.2 navigation ---------- */

.site-nav {
    position: sticky; top: 0; z-index: 60;
    background: color-mix(in srgb, var(--white) 82%, transparent);
    backdrop-filter: saturate(180%) blur(12px);
    -webkit-backdrop-filter: saturate(180%) blur(12px);
    border-bottom: 1px solid var(--line);
}
.nav-in {
    max-width: var(--max); margin: 0 auto; padding: .8rem 1.5rem;
    display: flex; align-items: center; gap: 1.5rem;
}

.brand { font-weight: 800; font-size: 1.15rem; letter-spacing: -.04em; flex: 0 0 auto; }
.brand span { color: var(--accent); }

.nav-menu { display: none; align-items: center; gap: .35rem; margin-left: auto; }
.nav-end  { display: none; align-items: center; gap: .5rem; }
@media (min-width: 60rem) {
    .nav-menu, .nav-end { display: flex; }
}

.nav-menu > li { list-style: none; position: relative; }
.nav-menu > li > a, .nav-trigger {
    display: inline-flex; align-items: center; gap: .3rem;
    font-size: .9rem; font-weight: 500; color: var(--ink-2);
    padding: .5rem .75rem; border-radius: var(--r-sm);
    background: none; border: 0; font-family: inherit; cursor: pointer;
}
.nav-menu > li > a:hover, .nav-trigger:hover,
.nav-menu > li.open .nav-trigger { color: var(--ink); background: var(--soft); }
.nav-trigger::after {
    content: ""; width: .38rem; height: .38rem; margin-top: -.2rem;
    border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
    transform: rotate(45deg); transition: transform .15s ease;
}
.nav-menu > li.open .nav-trigger::after { transform: rotate(-135deg); margin-top: .1rem; }

/* Dropdown. Hidden with [hidden] rather than display rules so the markup stays
   honest for assistive tech when JS has not run. */
.nav-drop {
    position: absolute; top: calc(100% + .5rem); left: 0; z-index: 70;
    min-width: 21rem; padding: .6rem;
    background: var(--white); border: 1px solid var(--line);
    border-radius: var(--r); box-shadow: var(--shadow-lg);
}
.nav-drop[hidden] { display: none; }
.nav-drop a {
    display: block; padding: .6rem .7rem .6rem 1.75rem; border-radius: var(--r-sm);
    font-size: .9rem; font-weight: 600; color: var(--ink); position: relative;
}
/* The hub's own colour, so the menu teaches the mapping before you click it. */
.hub-swatch {
    position: absolute; left: .7rem; top: .95rem;
    width: 8px; height: 8px; border-radius: 3px;
}
.nav-drop a small {
    display: block; font-weight: 400; font-size: .8rem;
    color: var(--ink-3); margin-top: .1rem; line-height: 1.45;
}
.nav-drop a:hover { background: var(--soft); }

/* Icon buttons — theme toggle and the mobile burger */
.icon-btn {
    display: inline-grid; place-items: center; width: 2.2rem; height: 2.2rem;
    border: 1px solid var(--line); border-radius: var(--r-sm);
    background: var(--white); color: var(--ink-2); cursor: pointer;
}
.icon-btn:hover { color: var(--ink); background: var(--soft); }
.nav-burger { margin-left: auto; }
@media (min-width: 60rem) { .nav-burger { display: none; } }

/* Nav over a dark band.
   A light nav sitting on top of the cinematic hero draws a hard seam across the
   the top of the page and undoes the whole effect. The class is applied by JS
   while the top of the viewport is inside a .cine section, and removed once it
   is not — so the nav is dark over the hero and reverts for the light sections
   below it. */
.site-nav.on-dark {
    background: color-mix(in srgb, #08090A 70%, transparent);
    border-bottom-color: rgba(255,255,255,.08);
}
.site-nav.on-dark .brand { color: #fff; }
.site-nav.on-dark .brand span { color: #A8A2FF; }
.site-nav.on-dark .nav-menu > li > a,
.site-nav.on-dark .nav-trigger,
.site-nav.on-dark .btn-quiet { color: rgba(255,255,255,.72); }
.site-nav.on-dark .nav-menu > li > a:hover,
.site-nav.on-dark .nav-trigger:hover,
.site-nav.on-dark .btn-quiet:hover { color: #fff; background: rgba(255,255,255,.08); }
.site-nav.on-dark .icon-btn {
    background: rgba(255,255,255,.05); border-color: rgba(255,255,255,.14); color: rgba(255,255,255,.8);
}
.site-nav.on-dark .icon-btn:hover { background: rgba(255,255,255,.1); color: #fff; }
/* The dropdown and drawer stay on their own solid surface — a translucent panel
   over a gradient is unreadable. */
.site-nav.on-dark .nav-drop { background: #16191F; border-color: rgba(255,255,255,.14); }
.site-nav.on-dark .nav-drop a { color: #fff; }
.site-nav.on-dark .nav-drop a small { color: rgba(255,255,255,.6); }
.site-nav.on-dark .nav-drop a:hover { background: rgba(255,255,255,.07); }
.site-nav.on-dark .nav-mobile { background: #0F1114; border-top-color: rgba(255,255,255,.1); }
.site-nav.on-dark .nav-mobile a { color: rgba(255,255,255,.78); }
.site-nav.on-dark .nav-mobile h4 { color: rgba(255,255,255,.45); }

/* ---------- language switcher ---------- */

.lang { position: relative; }
.lang-btn { font-size: .72rem; font-weight: 700; letter-spacing: .04em; width: auto; padding: 0 .55rem; }
.lang-menu {
    position: absolute; top: calc(100% + .5rem); right: 0; z-index: 70;
    min-width: 10rem; padding: .4rem;
    background: var(--white); border: 1px solid var(--line);
    border-radius: var(--r-sm); box-shadow: var(--shadow-lg);
}
.lang-menu[hidden] { display: none; }
.lang-menu a {
    display: block; padding: .45rem .6rem; border-radius: 6px;
    font-size: .88rem; color: var(--ink);
}
.lang-menu a:hover { background: var(--soft); }
.lang-menu a[aria-current="true"] { color: var(--accent); font-weight: 600; }
.site-nav.on-dark .lang-menu { background: #16191F; border-color: rgba(255,255,255,.14); }
.site-nav.on-dark .lang-menu a { color: #fff; }
.site-nav.on-dark .lang-menu a:hover { background: rgba(255,255,255,.07); }

/* Mobile drawer */
.nav-mobile {
    display: none; border-top: 1px solid var(--line);
    background: var(--white); padding: .8rem 1.5rem 1.4rem;
    max-height: 78vh; overflow-y: auto;
}
.nav-mobile.open { display: block; }
@media (min-width: 60rem) { .nav-mobile { display: none !important; } }
.nav-mobile h4 {
    font-size: .7rem; letter-spacing: .12em; text-transform: uppercase;
    color: var(--ink-3); margin: 1.1rem 0 .3rem;
}
.nav-mobile a { display: block; padding: .5rem 0; font-size: .95rem; color: var(--ink-2); }
.nav-mobile a:hover { color: var(--accent); }
.nav-mobile .btn { margin-top: 1rem; }

/* ---------- 4.3 cards ---------- */

.cards { display: grid; gap: 1.1rem; }
@media (min-width: 48rem) { .cards { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 64rem) { .cards.three { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

.card {
    background: var(--white); border: 1px solid var(--line);
    border-radius: var(--r); padding: 1.5rem;
    transition: border-color .15s ease, transform .15s ease;
}
.card:hover { border-color: color-mix(in srgb, var(--accent) 35%, var(--line)); transform: translateY(-2px); }
.card h3 { margin-bottom: .5rem; }
.card p  { margin: 0; font-size: .94rem; color: var(--ink-2); line-height: 1.65; }

.ico {
    width: 2.2rem; height: 2.2rem; border-radius: 8px;
    display: grid; place-items: center; margin-bottom: .9rem;
    background: var(--accent-soft); color: var(--accent);
    font-size: 1.05rem; font-weight: 700;
}

/* ---------- 4.4 prose (editor content) ---------- */

.prose { font-size: 1.05rem; line-height: 1.75; color: var(--ink-2); }
.prose > * + * { margin-top: 1.25rem; }
.prose h2 {
    font-size: 1.55rem; color: var(--ink);
    margin-top: 2.8rem; padding-top: .2rem;
}
.prose h3 { font-size: 1.15rem; color: var(--ink); margin-top: 2rem; }
.prose strong { color: var(--ink); font-weight: 650; }
.prose a { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; }
.prose ul, .prose ol { padding-left: 1.3rem; }
.prose li + li { margin-top: .5rem; }
.prose li::marker { color: var(--ink-3); }
.prose blockquote {
    border-left: 3px solid var(--accent); background: var(--soft);
    padding: 1rem 1.25rem; border-radius: 0 var(--r-sm) var(--r-sm) 0;
    color: var(--ink); font-size: 1rem;
}
.prose code {
    font-family: var(--mono); font-size: .88em;
    background: var(--soft-2); padding: .12em .4em; border-radius: 5px;
}
.prose table { width: 100%; border-collapse: collapse; font-size: .94rem; }
.prose th, .prose td { text-align: left; padding: .7rem .8rem; border-bottom: 1px solid var(--line); }
.prose th { color: var(--ink); font-weight: 650; }
/* Tables and code must scroll inside themselves, never the page. */
.prose .scroll-x { overflow-x: auto; }

/* ---------- 4.5 code sample ---------- */

.code {
    background: var(--white); border: 1px solid var(--line); border-radius: var(--r);
    padding: 1.1rem 1.2rem; box-shadow: var(--shadow);
    font-family: var(--mono); font-size: .8rem; line-height: 1.7;
    color: var(--ink-2); overflow-x: auto;
}
.code .c { color: var(--ink-3); }
.code .k { color: var(--accent); }
.code .s { color: var(--good); }

/* ---------- 4.6 CTA band ---------- */
/* Fixed colours on purpose — see the note at the top of this file. */

.cta-band { background: var(--fixed-deep); color: #fff; padding: 5rem 0; }
.cta-band h2 { color: #fff; }
.cta-band p  { color: var(--fixed-on-deep); font-size: 1.06rem; max-width: 42ch; margin: .9rem auto 1.8rem; }
.cta-band .wrap { text-align: center; max-width: 46rem; }
.cta-band .btn-ghost { background: transparent; border-color: var(--fixed-line-on-deep); color: #fff; }
.cta-band .btn-ghost:hover { background: #16304C; }
.cta-actions { display: flex; gap: .7rem; justify-content: center; flex-wrap: wrap; }

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

.site-footer { border-top: 1px solid var(--line); padding: 3.5rem 0 2.5rem; font-size: .88rem; color: var(--ink-3); }
.f-grid { display: grid; gap: 2rem; grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (min-width: 56rem) { .f-grid { grid-template-columns: minmax(0, 2fr) repeat(3, minmax(0, 1fr)); } }
.f-col h4 {
    font-size: .74rem; letter-spacing: .1em; text-transform: uppercase;
    color: var(--ink-2); margin: 0 0 .8rem; font-weight: 700;
}
.f-col a { display: block; padding: .22rem 0; color: var(--ink-3); }
.f-col a:hover { color: var(--accent); }
.f-bot {
    margin-top: 2.5rem; padding-top: 1.5rem; border-top: 1px solid var(--line);
    display: flex; flex-wrap: wrap; gap: 1rem; justify-content: space-between;
}

/* ---------- 4.8 breadcrumbs ---------- */

.crumbs { font-size: .82rem; color: var(--ink-3); margin-bottom: 1.1rem; }
.crumbs a:hover { color: var(--accent); }
.crumbs span { margin: 0 .45rem; opacity: .6; }


/* ==========================================================================
   5. TEMPLATES
   ========================================================================== */

/* ---------- 5.1 homepage hero ---------- */

.hero { padding: 5rem 0 1rem; position: relative; }
.hero::before {
    content: ""; position: absolute; inset: 0 0 auto; height: 36rem; z-index: -1;
    background: radial-gradient(60rem 24rem at 50% -6rem, var(--accent-soft), transparent 70%);
}
.hero-grid { display: grid; gap: 3rem; align-items: center; }
@media (min-width: 64rem) { .hero-grid { grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr); gap: 4rem; } }
.hero h1 { margin: 1rem 0; }
.lede { font-size: 1.18rem; color: var(--ink-2); max-width: 34ch; margin: 0 0 1.8rem; }
.hero-cta { display: flex; flex-wrap: wrap; gap: .7rem; align-items: center; }
.hero-note { font-size: .83rem; color: var(--ink-3); margin: 1rem 0 0; }

/* The signature widget: one figure propagating to six channels. */
.sync {
    background: var(--white); border: 1px solid var(--line); border-radius: var(--r);
    box-shadow: var(--shadow); padding: 1.1rem; position: relative; overflow: hidden;
}
.sync-head {
    display: flex; align-items: center; gap: .5rem;
    padding: 0 .3rem .8rem; border-bottom: 1px solid var(--line); margin-bottom: .9rem;
}
.sync-head h3 { font-size: .86rem; font-weight: 600; }
.sync-head .sku { margin-left: auto; font-family: var(--mono); font-size: .74rem; color: var(--ink-3); }
.dot {
    width: 9px; height: 9px; border-radius: 50%; background: var(--good); flex: 0 0 auto;
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--good) 18%, transparent);
}
.truth { display: flex; align-items: baseline; gap: .6rem; padding: .5rem .3rem 1rem; flex-wrap: wrap; }
.truth .n { font-size: 3.1rem; font-weight: 800; letter-spacing: -.05em; line-height: 1; font-variant-numeric: tabular-nums; }
.truth .lbl { font-size: .78rem; color: var(--ink-3); }
.truth .tag {
    margin-left: auto; font-size: .68rem; font-weight: 700; letter-spacing: .06em;
    text-transform: uppercase; color: var(--accent); background: var(--accent-soft);
    padding: .25em .55em; border-radius: 5px; white-space: nowrap;
}
/* Below roughly a phone's width there is no room for the label beside the
   figure, and a two-line badge next to a 3rem numeral looks broken. */
@media (max-width: 25rem) { .truth .tag { display: none; } }
.chans { display: grid; gap: .4rem; }
.chan {
    display: flex; align-items: center; gap: .7rem; padding: .55rem .6rem;
    border-radius: var(--r-sm); background: var(--soft); font-size: .87rem;
}
.chan .nm { font-weight: 500; }
.chan .v {
    margin-left: auto; font-family: var(--mono); font-size: .86rem;
    font-variant-numeric: tabular-nums; color: var(--ink-2);
}
.chan .st { width: 1.1rem; text-align: center; font-size: .78rem; color: var(--good); opacity: 0; }
.chan.in .st { opacity: 1; }
.chan.in .v  { color: var(--ink); font-weight: 600; }
.chan.src {
    background: var(--accent-soft);
    box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 22%, transparent);
}
/* Waiting to be told. Without a cue, a half-propagated panel reads as a bug
   rather than as the thing the product actually does. */
.chan.wait .v  { color: var(--ink-3); opacity: .55; }
.chan.wait .st { opacity: 1; color: var(--ink-3); font-size: 0; }
.chan.wait .st::before {
    content: ""; display: inline-block; width: 5px; height: 5px; border-radius: 50%;
    background: currentColor; animation: pulse 1.1s infinite;
}
.sync-foot {
    margin-top: .9rem; padding-top: .8rem; border-top: 1px solid var(--line);
    font-size: .78rem; color: var(--ink-3); display: flex; gap: .4rem; align-items: center;
}
@keyframes pulse { 0%, 100% { opacity: .35; } 50% { opacity: 1; } }
.live { width: 6px; height: 6px; border-radius: 50%; background: var(--good); animation: pulse 2s infinite; }

/* ---------- 5.1b the manifest ---------- */
/* The hero's right-hand panel. Its job is to make breadth undeniable in one
   glance: every feature area at once, too many to read, deliberately. A shorter
   curated list would be easier to scan and would lose the entire argument. */

.manifest {
    background: var(--white); border: 1px solid var(--line); border-radius: var(--r);
    box-shadow: var(--shadow); overflow: hidden;
}
.manifest-head {
    display: flex; align-items: center; gap: .5rem;
    padding: .9rem 1.1rem; border-bottom: 1px solid var(--line); background: var(--soft);
}
.manifest-head h3 { font-size: .86rem; font-weight: 650; }
.manifest-head .count {
    margin-left: auto; font-family: var(--mono); font-size: .74rem; color: var(--accent);
    background: var(--accent-soft); padding: .2em .5em; border-radius: 5px; font-weight: 700;
}
/* Fixed height with a fade, so the list visibly runs past the bottom edge.
   Grid, NOT CSS multicol. Multicol was the obvious choice and is wrong here: a
   multicol box with a constrained height fragments its content into overflow
   columns laid out sideways, so with `columns:2; max-height:20rem` the items
   that did not fit went into columns three, four and five — off to the right,
   clipped by overflow:hidden, and invisible. Measured: a 237px box reporting a
   scrollWidth of 891px, with most of the 43 items in it unseeable.
   Worse than merely hidden, it made the fade a lie: the fade promises more
   content below, and below is where there was nothing. Grid rows flow
   downwards, so clipping means exactly what the fade says it means. */
.manifest-list {
    position: relative; max-height: 20rem; overflow: hidden;
    padding: .9rem 1.1rem;
    display: grid; grid-template-columns: minmax(0, 1fr); gap: 0 1.4rem;
    align-content: start;
    -webkit-mask-image: linear-gradient(180deg, #000 74%, transparent 100%);
    mask-image: linear-gradient(180deg, #000 74%, transparent 100%);
}
@media (min-width: 30rem) {
    .manifest-list { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
}
.manifest-list span {
    display: block; break-inside: avoid; font-size: .8rem; line-height: 1.75;
    color: var(--ink-2); padding-left: 1rem; position: relative;
}
.manifest-list span::before {
    content: "✓"; position: absolute; left: 0; top: 0;
    color: var(--good); font-size: .7rem; font-weight: 700;
}
.manifest-foot {
    padding: .8rem 1.1rem; border-top: 1px solid var(--line);
    font-size: .78rem; color: var(--ink-3);
}

/* ---------- 5.1c what it replaces ---------- */

/* minmax(0, 1fr) rather than 1fr, and min-width:0 on the item.
   A bare `1fr` is minmax(auto, 1fr), and `auto` refuses to shrink below the
   item's min-content width. Measured here: a 219px container computing a
   273px column, so both panels overflowed the page by 31px on a narrow screen.
   The same trap applies to any grid holding prose. */
.replaces { display: grid; gap: 1.1rem; align-items: start; grid-template-columns: minmax(0, 1fr); }
@media (min-width: 56rem) { .replaces { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 1.5rem; } }
.stack {
    min-width: 0;
    border: 1px solid var(--line); border-radius: var(--r); padding: 1.4rem 1.5rem;
    background: var(--white);
}
.stack li b { overflow-wrap: anywhere; }
.stack.ours { border-color: color-mix(in srgb, var(--accent) 45%, var(--line)); box-shadow: var(--shadow); }
.stack h3 { font-size: 1rem; margin-bottom: .3rem; }
.stack .note { font-size: .84rem; color: var(--ink-3); margin-bottom: 1.1rem; }
.stack ul { list-style: none; display: flex; flex-direction: column; gap: .5rem; }
/* Block with an absolutely positioned marker, NOT a flex row.
   As flex, each element inside the line became its own flex item: "A", the
   bolded name, and the trailing text all wrapped independently, so a sentence
   like "A point of sale, usually charged per till" broke into ragged fragments
   with the comma stranded. Text has to stay in normal inline flow to wrap as
   one sentence. */
.stack li {
    position: relative; padding-left: 1.15rem; min-width: 0;
    font-size: .89rem; color: var(--ink-2); line-height: 1.5;
}
.stack li::before { position: absolute; left: 0; top: 0; font-weight: 700; }
.stack li b { color: var(--ink); font-weight: 600; }
.stack.theirs li::before { content: "+"; color: var(--warn); }
.stack.ours li::before { content: "✓"; color: var(--good); font-size: .85em; }
.stack .tally {
    margin-top: 1.2rem; padding-top: .9rem; border-top: 1px solid var(--line);
    font-size: .86rem; color: var(--ink-2);
}
.stack .tally b { color: var(--ink); }

/* ---------- 5.2 stat strip ---------- */

.strip { border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); background: var(--soft); margin-top: 4rem; }
.strip-in { display: grid; gap: 1.5rem; padding: 2rem 0; grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (min-width: 56rem) { .strip-in { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.stat .n { font-size: 1.9rem; font-weight: 800; letter-spacing: -.04em; line-height: 1; font-variant-numeric: tabular-nums; }
.stat .l { font-size: .84rem; color: var(--ink-2); margin-top: .35rem; max-width: 22ch; }

/* ---------- 5.3 rule list ---------- */

.eng-row { display: grid; gap: 2.5rem; align-items: start; }
@media (min-width: 64rem) { .eng-row { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 4rem; } }
.rule-list { display: flex; flex-direction: column; }
.rule { padding: 1.1rem 0; border-top: 1px solid var(--line); }
.rule:first-child { border-top: 0; }
.rule h3 { font-size: 1rem; margin-bottom: .35rem; display: flex; gap: .6rem; align-items: baseline; flex-wrap: wrap; }
.rule h3 em { font-style: normal; font-family: var(--mono); font-size: .72rem; color: var(--ink-3); }
.rule p { margin: 0; font-size: .93rem; color: var(--ink-2); line-height: 1.65; }

/* ---------- 5.4 channel chips ---------- */

.chan-grid { display: grid; gap: .7rem; grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (min-width: 48rem) { .chan-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 64rem) { .chan-grid { grid-template-columns: repeat(6, minmax(0, 1fr)); } }
.chip {
    border: 1px solid var(--line); border-radius: 11px; padding: 1.1rem .8rem;
    text-align: center; background: var(--white); font-weight: 600; font-size: .9rem;
    transition: border-color .15s ease;
}
a.chip:hover { border-color: color-mix(in srgb, var(--accent) 40%, var(--line)); }
.chip small { display: block; font-weight: 500; font-size: .74rem; color: var(--ink-3); margin-top: .25rem; }

/* ---------- 5.5 hub template ---------- */

/* The hero carries the page's hue as a wash — two pools plus a third from
   further round the spectrum, so it reads as light rather than as a tint. This
   is what stops every hub page looking identical. */
.page-hero {
    position: relative; overflow: hidden;
    padding: 3.5rem 0 2.5rem; border-bottom: 1px solid var(--line); background: var(--soft);
}
.page-hero::before {
    content: ""; position: absolute; inset: 0; pointer-events: none;
    background:
        radial-gradient(38rem 20rem at 6% -40%, color-mix(in srgb, var(--hue) 26%, transparent), transparent 66%),
        radial-gradient(30rem 16rem at 88% -20%, color-mix(in srgb, var(--hue-2, var(--prism-5)) 18%, transparent), transparent 62%),
        radial-gradient(24rem 14rem at 52% 130%, color-mix(in srgb, var(--hue) 12%, transparent), transparent 68%);
}
.page-hero > .wrap { position: relative; }
/* The spectrum, thinned to a hairline, marking the foot of the hero. */
.page-hero::after {
    content: ""; position: absolute; left: 0; right: 0; bottom: -1px; height: 2px;
    background: var(--prism); opacity: .7;
}
.page-hero h1 { font-size: clamp(2.1rem, 4.4vw, 3.1rem); margin: .8rem 0; }
.page-hero .standfirst { font-size: 1.15rem; color: var(--ink-2); max-width: 46ch; margin: 0; }
.page-hero-actions { display: flex; flex-wrap: wrap; gap: .7rem; margin-top: 1.8rem; }

.hub-intro { max-width: var(--max-prose); margin-bottom: 3rem; }
.spokes { display: grid; gap: 1rem; }
@media (min-width: 48rem) { .spokes { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.spoke {
    position: relative; overflow: hidden;
    display: block; background: var(--white); border: 1px solid var(--line);
    border-radius: var(--r); padding: 1.4rem 1.5rem;
    transition: border-color .15s ease, transform .15s ease;
}
/* A stripe of the page's hue down the leading edge, widening on hover. */
.spoke::before {
    content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
    background: var(--hue); opacity: .55; transition: width .18s ease, opacity .18s ease;
}
.spoke:hover::before { width: 6px; opacity: 1; }
.spoke:hover { border-color: color-mix(in srgb, var(--hue) 40%, var(--line)); transform: translateY(-2px); }
.spoke h3 { font-size: 1.05rem; margin-bottom: .4rem; }
.spoke p { font-size: .92rem; color: var(--ink-2); margin: 0; line-height: 1.6; }
.spoke .more { display: inline-block; margin-top: .8rem; font-size: .85rem; font-weight: 600; color: var(--hue-ink); }

/* The feature index — dense, because there are a dozen or more per hub and as
   cards they would bury the guides above them. */
.feature-index { margin-top: 3.5rem; }
.feature-index h2 { font-size: 1.3rem; margin-bottom: 1.2rem; }
.feature-list { display: grid; gap: .5rem; grid-template-columns: minmax(0, 1fr); }
@media (min-width: 44rem) { .feature-list { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 68rem) { .feature-list { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.feature-list a {
    display: block; min-width: 0; padding: .8rem 1rem .85rem 1.6rem;
    border: 1px solid var(--line); border-radius: var(--r-sm);
    background: var(--white); position: relative;
    transition: border-color .15s ease, background .15s ease;
}
.feature-list a::before {
    content: ""; position: absolute; left: .8rem; top: 1.15rem;
    width: 5px; height: 5px; border-radius: 50%; background: var(--hue); opacity: .7;
}
.feature-list a:hover { border-color: color-mix(in srgb, var(--hue) 45%, var(--line)); background: var(--soft); }
.feature-list strong { display: block; font-size: .92rem; font-weight: 600; color: var(--ink); }
.feature-list span {
    display: block; font-size: .82rem; color: var(--ink-3); margin-top: .15rem; line-height: 1.45;
}

/* Hub cross-links at the foot of a hub */
.hub-nav { display: grid; gap: .6rem; grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (min-width: 56rem) { .hub-nav { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
/* Each cross-link wears its own hub's hue, set inline from qwikr_hubs(). */
.hub-nav a {
    position: relative; padding-left: 1.9rem;
    border: 1px solid var(--line); border-radius: var(--r-sm);
    padding-block: .8rem; padding-right: 1rem; font-size: .9rem; font-weight: 600;
    transition: border-color .15s ease, background .15s ease;
}
.hub-nav a::before {
    content: ""; position: absolute; left: .85rem; top: 50%; transform: translateY(-50%);
    width: 8px; height: 8px; border-radius: 50%; background: var(--hue);
}
.hub-nav a:hover { border-color: color-mix(in srgb, var(--hue) 55%, var(--line)); background: var(--soft); }

/* ---------- 5.6 feature template ---------- */

.feature-body { display: grid; gap: 3rem; padding: 3.5rem 1.5rem 4.5rem; max-width: var(--max); margin: 0 auto; }
@media (min-width: 64rem) { .feature-body { grid-template-columns: minmax(0, 1fr) 19rem; gap: 4rem; } }
.feature-main { min-width: 0; }

/* The searcher's own words, before any product language. */
.feature-problem {
    font-size: 1.15rem; line-height: 1.6; color: var(--ink);
    border-left: 3px solid var(--hue); padding: .2rem 0 .2rem 1.1rem;
    margin-bottom: 2.2rem; font-weight: 500;
}

.feature-aside { display: flex; flex-direction: column; gap: 1rem; }
@media (min-width: 64rem) { .feature-aside { position: sticky; top: 5.5rem; align-self: start; } }
.aside-card {
    position: relative; overflow: hidden;
    background: var(--soft); border: 1px solid var(--line); border-radius: var(--r); padding: 1.3rem;
}
/* The spectrum along the top edge, so the sidebar picks up the same family. */
.aside-card::before {
    content: ""; position: absolute; top: 0; left: 0; right: 0; height: 2px; background: var(--prism);
}
.aside-card h3 { font-size: .95rem; margin-bottom: .5rem; }
.aside-card p  { font-size: .87rem; color: var(--ink-2); margin-bottom: 1rem; line-height: 1.55; }
.aside-link { display: block; margin-top: .7rem; font-size: .85rem; color: var(--accent); font-weight: 600; text-align: center; }
.aside-related a { display: block; padding: .45rem 0; font-size: .88rem; color: var(--ink-2); border-top: 1px solid var(--line); }
.aside-related a:first-of-type { border-top: 0; }
.aside-related a:hover { color: var(--accent); }

/* ---------- 5.7 pricing ---------- */

.plans { display: grid; gap: 1.2rem; align-items: start; }
@media (min-width: 52rem) { .plans { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 68rem) { .plans { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

.plan {
    background: var(--white); border: 1px solid var(--line); border-radius: var(--r);
    padding: 1.6rem 1.4rem; display: flex; flex-direction: column; height: 100%;
}
.plan { position: relative; overflow: hidden; }
/* Each plan takes a hue further along the spectrum, so the pricing table reads
   as a progression rather than three identical boxes. */
.plan::before {
    content: ""; position: absolute; top: 0; left: 0; right: 0; height: 3px;
    background: var(--plan-hue, var(--accent));
}
.plan.featured {
    border-color: var(--accent); box-shadow: var(--shadow-lg);
}
.plan.featured::before { background: var(--prism); }
.plan-flag {
    position: absolute; top: -.7rem; left: 1.4rem;
    background: var(--accent); color: #fff; font-size: .68rem; font-weight: 700;
    letter-spacing: .08em; text-transform: uppercase; padding: .25rem .6rem; border-radius: 5px;
}
.plan-name { font-size: 1.05rem; font-weight: 700; }
.plan-desc { font-size: .87rem; color: var(--ink-3); margin-top: .25rem; min-height: 2.6em; }
.plan-price { display: flex; align-items: baseline; gap: .3rem; margin: 1.1rem 0 .2rem; }
.plan-price .amt { font-size: 2.4rem; font-weight: 800; letter-spacing: -.04em; line-height: 1; }
.plan-price .per { font-size: .84rem; color: var(--ink-3); }
.plan-vat { font-size: .76rem; color: var(--ink-3); margin-bottom: 1.2rem; }
.plan .btn { margin-bottom: 1.3rem; }
.plan-list { list-style: none; display: flex; flex-direction: column; gap: .55rem; font-size: .88rem; color: var(--ink-2); }
.plan-list li { display: flex; gap: .55rem; align-items: flex-start; line-height: 1.5; }
.plan-list li::before { content: "✓"; color: var(--good); font-weight: 700; flex: 0 0 auto; }
.plan-list li.no { color: var(--ink-3); }
.plan-list li.no::before { content: "—"; color: var(--ink-3); }

/* Comparison table */
.compare { width: 100%; border-collapse: collapse; font-size: .9rem; min-width: 42rem; }
.compare th, .compare td { padding: .75rem .9rem; border-bottom: 1px solid var(--line); text-align: left; }
.compare thead th { font-size: .78rem; letter-spacing: .06em; text-transform: uppercase; color: var(--ink-3); }
.compare tbody th { font-weight: 500; color: var(--ink-2); }
.compare td { text-align: center; }
.compare .y { color: var(--good); font-weight: 700; }
.compare .n { color: var(--ink-3); }
.compare-scroll { overflow-x: auto; border: 1px solid var(--line); border-radius: var(--r); }

/* FAQ */
.faq { max-width: 48rem; margin: 0 auto; }
.faq details { border-bottom: 1px solid var(--line); padding: 1.1rem 0; }
.faq summary { font-weight: 650; cursor: pointer; list-style: none; display: flex; gap: 1rem; align-items: flex-start; }
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
    content: "+"; margin-left: auto; color: var(--ink-3); font-weight: 400;
    font-size: 1.3rem; line-height: 1; flex: 0 0 auto;
}
.faq details[open] summary::after { content: "–"; }
.faq details p { margin-top: .8rem; color: var(--ink-2); font-size: .95rem; line-height: 1.7; }

/* ---------- 5.7b product types ---------- */

/* One column until there is genuinely room. Two columns on a narrow phone leaves
   about 65px of content per card once padding is off, which is narrower than
   words like "Configure" — minmax(0,1fr) lets the track shrink but the word
   still overflows it. */
.types { display: grid; gap: 1rem; grid-template-columns: minmax(0, 1fr); }
@media (min-width: 30rem) { .types { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 48rem) { .types { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 68rem) { .types { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

.type {
    position: relative; min-width: 0;
    border: 1px solid var(--line); border-radius: var(--r); padding: 1.25rem;
    background: var(--white); transition: border-color .16s ease, transform .16s ease;
}
.type:hover { border-color: color-mix(in srgb, var(--tint, var(--accent)) 45%, var(--line)); transform: translateY(-2px); }
.type svg { width: 34px; height: 34px; margin-bottom: .85rem; display: block; }
.type svg .s { stroke: var(--tint, var(--accent)); fill: none; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.type svg .f { fill: color-mix(in srgb, var(--tint, var(--accent)) 16%, transparent); }
.type h3 { font-size: .98rem; margin-bottom: .3rem; }
.type p { font-size: .86rem; color: var(--ink-2); margin: 0; line-height: 1.55; }

/* ---------- 5.7c capability clusters ---------- */
/* This was a flat grid of 32 identical ticked pills. It made the point about
   volume and looked like a spreadsheet. Grouping the same items into four
   hue-coded clusters keeps the density — which IS the argument — while giving
   the eye somewhere to land, and it reuses the hub colour language so the
   section belongs to the rest of the site. */

.clusters { display: grid; gap: 1rem; grid-template-columns: minmax(0, 1fr); }
@media (min-width: 40rem) { .clusters { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 72rem) { .clusters { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

.cluster {
    position: relative; overflow: hidden; min-width: 0;
    border: 1px solid var(--hair); border-radius: 16px; padding: 1.4rem 1.3rem;
    background:
        radial-gradient(20rem 12rem at 50% -20%, color-mix(in srgb, var(--tint) 20%, transparent), transparent 70%),
        linear-gradient(180deg, rgba(255,255,255,.045), rgba(255,255,255,.012));
    transition: border-color .18s ease, transform .18s ease;
}
.cluster:hover { border-color: color-mix(in srgb, var(--tint) 40%, var(--hair-2)); transform: translateY(-3px); }
.cluster::before {
    content: ""; position: absolute; top: 0; left: 0; right: 0; height: 2px;
    background: linear-gradient(90deg, transparent, var(--tint), transparent);
}
.cluster-n {
    font-family: var(--mono); font-size: .68rem; letter-spacing: .1em; text-transform: uppercase;
    color: color-mix(in srgb, var(--tint) 74%, #fff); display: block; margin-bottom: .55rem;
}
.cluster h3 { font-size: 1.02rem; color: #fff; margin-bottom: 1rem; font-weight: 650; }

.chips { display: flex; flex-wrap: wrap; gap: .4rem; }
/* Chips are links, so the cluster card cannot be one — nesting an anchor inside
   an anchor is invalid and browsers resolve it unpredictably. The card stays a
   div and every chip goes to its own page. */
.chips a {
    display: inline-block; font-size: .78rem; line-height: 1.3;
    padding: .34rem .6rem; border-radius: 7px;
    color: var(--deep-2); text-decoration: none;
    background: rgba(255,255,255,.05);
    border: 1px solid color-mix(in srgb, var(--tint) 18%, var(--hair));
    transition: color .15s ease, border-color .15s ease, background .15s ease;
}
.cluster:hover .chips a { color: var(--deep-1); border-color: color-mix(in srgb, var(--tint) 32%, var(--hair)); }
.chips a:hover {
    color: #fff;
    background: color-mix(in srgb, var(--tint) 20%, transparent);
    border-color: color-mix(in srgb, var(--tint) 55%, transparent);
}

/* The overflow line — what did not fit into four clusters, scrolling past. */
.cluster-more {
    margin-top: 1.4rem; overflow: hidden; padding: .9rem 0;
    border-top: 1px solid var(--hair); border-bottom: 1px solid var(--hair);
    -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
    mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.cluster-more div { display: flex; gap: 2.2rem; width: max-content; animation: slide 45s linear infinite; }
.cluster-more span { font-size: .84rem; color: var(--deep-3); white-space: nowrap; display: flex; align-items: center; gap: .5rem; }
.cluster-more span::before { content: ""; width: 3px; height: 3px; border-radius: 50%; background: currentColor; }

/* ---------- 5.7c-2 the callout ---------- */
/* The counterpart to the developer pitch. Deliberately the widest, plainest
   thing in the section — it is a promise from a person, not a feature. */

.callout {
    margin-top: 2.5rem; position: relative; overflow: hidden;
    border: 1px solid rgba(168,162,255,.3); border-radius: 18px;
    padding: 2rem 1.8rem;
    background:
        radial-gradient(34rem 18rem at 12% -30%, rgba(124,116,255,.22), transparent 66%),
        linear-gradient(180deg, rgba(255,255,255,.05), rgba(255,255,255,.015));
}
.callout h3 { font-size: 1.3rem; color: #fff; margin-bottom: .7rem; letter-spacing: -.02em; }
.callout p { color: var(--deep-2); font-size: 1rem; line-height: 1.7; max-width: 62ch; }
.callout p + p { margin-top: .9rem; }
.callout strong { color: #fff; font-weight: 600; }

/* ---------- 5.7d the developer section ---------- */

/* minmax(0, …) on both, and it is load-bearing here rather than defensive. An
   implicit `auto` track sizes to max-content, and the terminal's longest line is
   about 460px — so inside a 219px column everything in this section rendered
   462px wide and was silently clipped by .cine's overflow:hidden. Constraining
   the track lets the <pre> scroll inside itself instead. */
.api-split { display: grid; gap: 2rem; align-items: start; grid-template-columns: minmax(0, 1fr); }
@media (min-width: 64rem) {
    .api-split { grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr); gap: 3rem; }
}
.api-split > * { min-width: 0; }

/* A terminal, not a code block — the chrome is what says "this is a real thing
   you can call" rather than "here is an illustrative snippet". */
.term {
    border: 1px solid var(--hair-2); border-radius: 14px; overflow: hidden;
    background: #0B0D11; box-shadow: 0 30px 80px -30px rgba(0,0,0,.9);
}
.term-bar {
    display: flex; align-items: center; gap: .4rem;
    padding: .6rem .85rem; border-bottom: 1px solid var(--hair);
    background: rgba(255,255,255,.025);
}
.term-bar i { width: 9px; height: 9px; border-radius: 50%; background: rgba(255,255,255,.16); }
.term-bar span { margin-left: .5rem; font-family: var(--mono); font-size: .72rem; color: var(--deep-3); }
.term pre {
    margin: 0; padding: 1rem 1.1rem; overflow-x: auto;
    font-family: var(--mono); font-size: .76rem; line-height: 1.75; color: var(--deep-2);
}
.term .c  { color: #6A7486; }
.term .k  { color: #A8A2FF; }
.term .st { color: #4ADE9B; }
.term .n  { color: #F0B26B; }
.term .p  { color: #5AA9FF; }

.api-points { display: flex; flex-direction: column; }
.api-points > div { padding: 1.05rem 0; border-top: 1px solid var(--hair); }
.api-points > div:first-child { border-top: 0; }
.api-points h3 { font-size: .98rem; color: #fff; margin-bottom: .3rem; }
.api-points p { font-size: .89rem; color: var(--deep-2); margin: 0; line-height: 1.6; }
.api-points code {
    font-family: var(--mono); font-size: .82em; color: #A8A2FF;
    background: rgba(124,116,255,.12); padding: .1em .38em; border-radius: 5px;
}

/* ---------- 5.8 plain page & 404 ---------- */

.plain { max-width: var(--max-prose); margin: 0 auto; padding: 4.5rem 1.5rem 5rem; }
.plain h1 { font-size: clamp(2rem, 4vw, 2.7rem); margin-bottom: 1.5rem; }

.notfound { text-align: center; padding: 7rem 1.5rem; }
.notfound .code-num { font-family: var(--mono); font-size: 4rem; font-weight: 800; color: var(--accent); }


/* ==========================================================================
   6. THE CINEMATIC BAND
   ==========================================================================

   The dark hero and bento. Built after looking at how Linear, Stripe and Vercel
   actually do this in 2026, and the load-bearing lessons were:

   - Depth comes from a SURFACE PROGRESSION and hairline borders, not from
     ambient shadow. Linear steps #08090a → #0f1011 → #161718 → #23252a and
     almost never blurs a shadow to separate two things. Shadow here is used
     once, to float the product frame off the page.
   - Borders are hairlines. Low-opacity white over a dark surface reads as a
     precise edge; a solid grey reads as a box.
   - Display type is huge and tightly tracked; body type is LIGHT. The contrast
     between a 5rem headline and 400-weight prose is most of the effect.
   - Grain. A flat gradient looks synthetic; a few percent of fractal noise over
     it looks like a printed surface. This is the cheapest big win here.
   - Glass on the nav only. Everywhere else it turns to mud.

   These colours are FIXED and do not flip with the theme, for the same reason
   the CTA band's are: a section committed to one look must not be built on a
   token that inverts underneath it.
   ========================================================================== */

.cine {
    --s0: #08090A;   /* page */
    --s1: #0F1114;   /* raised */
    --s2: #16191F;   /* card */
    --s3: #212630;   /* card, hovered */
    --hair:   rgba(255,255,255,.075);
    --hair-2: rgba(255,255,255,.145);
    --deep-1: #EDF0F5;
    --deep-2: #97A2B4;
    --deep-3: #6A7486;
    --glow:   #7C74FF;

    position: relative;
    isolation: isolate;
    background: var(--s0);
    color: var(--deep-1);
    overflow: hidden;
}

/* Mesh gradient. Three offset radial pools rather than one linear ramp — a
   linear gradient has an obvious direction and reads as a background, whereas
   overlapping pools read as light in a room. */
/* Mesh gradient — six pools rather than three, spread across the band rather
   than clustered at the top. Earlier versions put every hue in one corner, so
   the colour drained out and two thirds of the section was flat near-black.
   Teal and emerald sit at the lower end deliberately: they are the coolest
   hues here and stop the bottom of a long dark section going dead. */
.cine::before {
    content: ""; position: absolute; inset: 0; z-index: -2; pointer-events: none;
    background:
        radial-gradient(58rem 30rem at 14% -10%, rgba(124,116,255,.34), transparent 62%),
        radial-gradient(44rem 26rem at 90%  2%, rgba(56,120,255,.22),  transparent 60%),
        radial-gradient(38rem 24rem at 70% 30%, rgba(168,85,247,.16),  transparent 64%),
        radial-gradient(40rem 26rem at 10% 58%, rgba(20,184,166,.15),  transparent 62%),
        radial-gradient(34rem 22rem at 82% 74%, rgba(236,72,153,.12),  transparent 62%),
        radial-gradient(46rem 28rem at 42% 98%, rgba(16,185,129,.13),  transparent 66%);
}

/* Grain — fractal noise at 4%, multiplied over the gradient. */
.cine::after {
    content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
    opacity: .045; mix-blend-mode: overlay;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* Engineering graph paper, faded out before it becomes wallpaper. */
.cine-grid {
    position: absolute; inset: 0; z-index: -2; pointer-events: none;
    background-image:
        linear-gradient(rgba(255,255,255,.032) 1px, transparent 1px),
        linear-gradient(90deg, rgba(255,255,255,.032) 1px, transparent 1px);
    background-size: 64px 64px;
    -webkit-mask-image: radial-gradient(ellipse 82% 58% at 50% 0%, #000 20%, transparent 76%);
    mask-image: radial-gradient(ellipse 82% 58% at 50% 0%, #000 20%, transparent 76%);
}

.cine a { color: inherit; }
.cine .eyebrow { color: #A8A2FF; }

/* The light-theme hero carries its own accent wash. Inside the dark band the
   mesh above is doing that job, and two stacked pools go muddy. */
.cine .hero::before { display: none; }
.cine .hero { padding: 4.5rem 0 5rem; }

/* ---------- 6.1 the badge ---------- */

.pill {
    display: inline-flex; align-items: center; gap: .5rem;
    padding: .34rem .85rem .34rem .5rem;
    border: 1px solid var(--hair-2); border-radius: 99px;
    background: rgba(255,255,255,.035);
    backdrop-filter: blur(8px);
    font-size: .78rem; font-weight: 500; color: var(--deep-2);
}
.pill b { color: var(--deep-1); font-weight: 600; }
.pill .dot { width: 6px; height: 6px; background: #4ADE9B; box-shadow: 0 0 0 3px rgba(74,222,155,.16); }

/* ---------- 6.2 display type & the rotator ---------- */

.display {
    font-size: clamp(2.5rem, 7vw, 5.2rem);
    line-height: .99; letter-spacing: -.045em; font-weight: 800;
    margin: 1.4rem 0 1.5rem; color: #fff;
}
.cine .lede { color: var(--deep-2); font-size: 1.16rem; max-width: 46ch; font-weight: 400; }
.cine .hero-note { color: var(--deep-3); }

/* Kinetic word swap. Stacked in one grid cell so the line never reflows —
   a rotator that changes the line width drags the whole paragraph around. */
.rot { display: inline-grid; vertical-align: top; text-align: left; }
.rot > span {
    grid-area: 1 / 1; opacity: 0; transform: translateY(.28em);
    background: linear-gradient(100deg, #A8A2FF, #7C74FF 42%, #5AA9FF);
    -webkit-background-clip: text; background-clip: text; color: transparent;
    animation: rot 15s cubic-bezier(.16,1,.3,1) infinite;
    white-space: nowrap;
}
.rot > span:nth-child(1) { animation-delay: 0s; }
.rot > span:nth-child(2) { animation-delay: 3s; }
.rot > span:nth-child(3) { animation-delay: 6s; }
.rot > span:nth-child(4) { animation-delay: 9s; }
.rot > span:nth-child(5) { animation-delay: 12s; }
@keyframes rot {
    0%   { opacity: 0; transform: translateY(.28em); }
    3%,18% { opacity: 1; transform: none; }
    21%,100% { opacity: 0; transform: translateY(-.28em); }
}

/* ---------- 6.3 buttons on dark ---------- */

.btn-glow {
    background: var(--glow); color: #fff;
    box-shadow: inset 0 1px 0 rgba(255,255,255,.22), 0 8px 30px -10px rgba(124,116,255,.85);
}
.btn-glow:hover { background: #8A83FF; box-shadow: inset 0 1px 0 rgba(255,255,255,.3), 0 14px 40px -10px rgba(124,116,255,1); }
.btn-hair {
    background: rgba(255,255,255,.045); color: #fff; border-color: var(--hair-2);
    backdrop-filter: blur(8px);
}
.btn-hair:hover { background: rgba(255,255,255,.09); border-color: rgba(255,255,255,.24); }

/* ---------- 6.4 the product frame ---------- */

.frame {
    position: relative; border: 1px solid var(--hair-2); border-radius: 18px;
    background: linear-gradient(180deg, var(--s2), var(--s1));
    box-shadow: 0 50px 120px -40px rgba(0,0,0,.95);
    overflow: hidden;
}
/* The specular hairline along the top edge — the single detail that makes a
   dark card look lit rather than flat. */
.frame::before {
    content: ""; position: absolute; top: 0; left: 12%; right: 12%; height: 1px;
    background: linear-gradient(90deg, transparent, rgba(255,255,255,.45), transparent);
}
.frame-bar {
    display: flex; align-items: center; gap: .5rem;
    padding: .75rem 1rem; border-bottom: 1px solid var(--hair);
    font-size: .78rem; color: var(--deep-3); font-family: var(--mono);
}
.frame-bar b { color: var(--deep-2); font-weight: 500; font-family: var(--sans); }

/* The sync widget, restyled for the dark frame. */
.cine .sync { background: transparent; border: 0; box-shadow: none; padding: 1.1rem; }
.cine .sync-head { border-bottom-color: var(--hair); }
.cine .sync-head h3 { color: var(--deep-1); }
.cine .sync-head .sku, .cine .truth .lbl, .cine .sync-foot { color: var(--deep-3); }
.cine .truth .n { color: #fff; }
.cine .truth .tag { color: #A8A2FF; background: rgba(124,116,255,.14); }
.cine .chan { background: rgba(255,255,255,.035); }
.cine .chan .v { color: var(--deep-2); }
.cine .chan.in .v { color: #fff; }
.cine .chan.src { background: rgba(124,116,255,.13); box-shadow: inset 0 0 0 1px rgba(124,116,255,.28); }
.cine .sync-foot { border-top-color: var(--hair); }

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

.marquee {
    overflow: hidden; padding: 1.6rem 0;
    border-top: 1px solid var(--hair); border-bottom: 1px solid var(--hair);
    -webkit-mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent);
    mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent);
}
.marquee-track { display: flex; gap: 3.2rem; width: max-content; animation: slide 38s linear infinite; }
.marquee-track span {
    font-size: .95rem; font-weight: 500; color: var(--deep-3); white-space: nowrap;
    display: flex; align-items: center; gap: .55rem;
}
.marquee-track span::before {
    content: ""; width: 4px; height: 4px; border-radius: 50%; background: var(--glow); opacity: .6;
}
@keyframes slide { to { transform: translateX(-50%); } }

/* ---------- 6.6 bento ---------- */

/* One column on a phone. Two columns at 267px leaves ~105px a tile, which set
   every heading one word per line and clipped the longer ones — a bento is
   supposed to look composed, and at that width it looked broken. */
.bento { display: grid; gap: 1rem; grid-template-columns: minmax(0, 1fr); }
@media (min-width: 34rem) { .bento { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 64rem) { .bento { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

.bt {
    position: relative; overflow: hidden; min-width: 0;
    border: 1px solid var(--hair); border-radius: 16px; padding: 1.35rem;
    background: linear-gradient(180deg, rgba(255,255,255,.05), rgba(255,255,255,.014));
    transition: border-color .18s ease, transform .18s ease, background .18s ease;
}
.bt:hover { border-color: var(--hair-2); transform: translateY(-3px); }
/* Only span once there are columns to span. In the single-column layout a
   span of 2 creates a phantom second track and the grid falls apart. */
.bt.wide { grid-column: span 1; }
@media (min-width: 34rem) { .bt.wide { grid-column: span 2; } }
.bt h3 { font-size: 1.02rem; color: #fff; margin-bottom: .4rem; font-weight: 650; }
.bt p { font-size: .89rem; line-height: 1.6; color: var(--deep-2); margin: 0; }
.bt .kicker {
    font-family: var(--mono); font-size: .68rem; letter-spacing: .1em; text-transform: uppercase;
    color: var(--deep-3); display: block; margin-bottom: .75rem;
}
/* Each tile carries the hue of the hub it links to, as a wash and a top edge —
   so the bento previews the colour system the rest of the site uses. */
.bt { --tile: #7C74FF; }
.bt::before {
    content: ""; position: absolute; top: 0; left: 0; right: 0; height: 2px;
    background: linear-gradient(90deg, transparent, var(--tile), transparent);
    opacity: .7; transition: opacity .18s ease;
}
.bt:hover::before { opacity: 1; }
.bt .kicker { color: color-mix(in srgb, var(--tile) 72%, #fff); }
.bt.lit {
    background: linear-gradient(180deg,
        color-mix(in srgb, var(--tile) 18%, transparent),
        color-mix(in srgb, var(--tile) 3%, transparent));
    border-color: color-mix(in srgb, var(--tile) 30%, transparent);
}
.bt .tags i { border-color: color-mix(in srgb, var(--tile) 22%, var(--hair)); }
.bt .tags { display: flex; flex-wrap: wrap; gap: .35rem; margin-top: .9rem; }
.bt .tags i {
    font-style: normal; font-size: .74rem; padding: .22rem .55rem; border-radius: 6px;
    background: rgba(255,255,255,.06); border: 1px solid var(--hair); color: var(--deep-2);
}
.bt .big {
    font-size: 2.5rem; font-weight: 800; letter-spacing: -.045em; line-height: 1;
    color: #fff; font-variant-numeric: tabular-nums;
}

.cine .head h2 { color: #fff; }
.cine .head .sub { color: var(--deep-2); }

/* The generic card, on dark. Same component, different ground. */
.cine .card {
    background: linear-gradient(180deg, rgba(255,255,255,.05), rgba(255,255,255,.014));
    border-color: var(--hair);
}
.cine .card:hover { border-color: var(--hair-2); }
.cine .card h3 { color: #fff; }
.cine .card p { color: var(--deep-2); }
.cine .ico { background: rgba(124,116,255,.18); color: #A8A2FF; }

/* ---------- 6.7 cursor spotlight ---------- */
/* The signature dark-UI hover: a soft pool of light tracking the pointer across
   a card. JS writes --mx/--my as percentages; the pool is a radial gradient in a
   pseudo-element that fades in on hover, so with no JS the card is simply a
   card. Pointer-coarse devices never get it — there is no cursor to follow, and
   on touch it would flash on tap. */
.bt::after {
    content: ""; position: absolute; inset: 0; pointer-events: none;
    opacity: 0; transition: opacity .25s ease;
    background: radial-gradient(18rem 18rem at var(--mx, 50%) var(--my, 50%),
                rgba(255,255,255,.09), transparent 68%);
}
@media (hover: hover) and (pointer: fine) {
    .bt:hover::after { opacity: 1; }
}

/* ---------- 6.8 tile artwork ---------- */

.bt-art { display: block; width: 100%; height: auto; margin-bottom: 1rem; overflow: visible; }
.bt-art .stroke { stroke: rgba(255,255,255,.22); fill: none; stroke-width: 1.25; }
.bt-art .stroke-lit { stroke: #A8A2FF; fill: none; stroke-width: 1.5; }
.bt-art .fill-soft { fill: rgba(255,255,255,.06); }
.bt-art .fill-lit { fill: rgba(124,116,255,.22); }
.bt-art .dot-lit { fill: #A8A2FF; }
.bt-art text { font-family: var(--mono); font-size: 9px; fill: rgba(255,255,255,.45); }

/* Dashes that travel — the same device as the diagram, at tile scale. */
.bt-art .flow { stroke-dasharray: 4 6; animation: dash 2.4s linear infinite; }
@keyframes dash { to { stroke-dashoffset: -20; } }

/* ---------- 6.9 the flow diagram ---------- */

.diagram-wrap {
    border: 1px solid var(--hair); border-radius: 18px; padding: 1.5rem 1rem;
    background: linear-gradient(180deg, rgba(255,255,255,.04), rgba(255,255,255,.012));
    overflow-x: auto;
}
.diagram { display: block; width: 100%; min-width: 40rem; height: auto; }
.diagram .node { fill: rgba(255,255,255,.05); stroke: rgba(255,255,255,.16); stroke-width: 1; }
.diagram .node-lit { fill: rgba(124,116,255,.16); stroke: rgba(168,162,255,.5); stroke-width: 1.25; }
.diagram .wire { stroke: rgba(255,255,255,.16); fill: none; stroke-width: 1.25; }
.diagram .pulse {
    stroke: #A8A2FF; fill: none; stroke-width: 1.75; stroke-linecap: round;
    stroke-dasharray: 14 220; animation: travel 3.4s cubic-bezier(.5,0,.5,1) infinite;
}
@keyframes travel { from { stroke-dashoffset: 234; } to { stroke-dashoffset: 0; } }

/* ---------- 6.9b the radial hub ---------- */
/* Every spoke carries traffic in BOTH directions: orders inbound, stock
   outbound. Every path declares pathLength="100", which normalises long and
   short spokes to the same coordinate space — so one dash pattern and one
   keyframe drive all sixteen pulses regardless of their real geometry. Without
   it each spoke would need its own dasharray to travel at the same speed. */

.hub-ring { fill: none; stroke: rgba(255,255,255,.07); stroke-width: 1; stroke-dasharray: 2 7; }
/* Slow contrary rotation on the two guide rings. Far too slow to notice
   directly — it just stops the diagram reading as a static picture.
   transform-box is declared rather than assumed. The origin below is in viewBox
   user units, and it only means that under `view-box`; under `fill-box` the
   same numbers resolve against each circle's own bounding box and the rings
   orbit off-centre instead of spinning in place. Engines have not always
   defaulted the same way, so it is stated. */
.hub-ring-spin,
.hub-ring-spin2,
.hub-halo-breathe { transform-box: view-box; transform-origin: 380px 280px; }

.hub-ring-spin  { animation: hub-spin 90s linear infinite; }
.hub-ring-spin2 { animation: hub-spin 60s linear infinite reverse; }
@keyframes hub-spin { to { transform: rotate(360deg); } }

.hub-halo-breathe { animation: hub-breathe 7s ease-in-out infinite; }
@keyframes hub-breathe { 0%, 100% { opacity: .75; transform: scale(1); } 50% { opacity: 1; transform: scale(1.045); } }

.hub-spoke { fill: none; stroke: rgba(255,255,255,.13); stroke-width: 1.25; }
.hub-status { fill: #4ADE9B; opacity: .85; }
/* Specular edge along the top of the core plate, same trick as the product
   frame — it is what stops a dark panel looking like a flat rectangle. */
.hub-core-lip { stroke: rgba(255,255,255,.4); stroke-width: 1; fill: none; }

.hub-pulse {
    fill: none; stroke-width: 2.25; stroke-linecap: round;
    /* 7 + 93 = 100 = pathLength, so offset 100 → 0 is exactly one traverse. */
    stroke-dasharray: 7 93;
    animation: hub-travel 3s linear infinite;
}
@keyframes hub-travel { from { stroke-dashoffset: 100; } to { stroke-dashoffset: 0; } }

/* The bloom is what makes a dash read as light travelling a wire rather than as
   a moving line. drop-shadow follows the alpha of the stroke, so it tracks the
   dash instead of haloing the whole path the way box-shadow would. */
.hub-out { stroke: #A8A2FF; filter: drop-shadow(0 0 4px rgba(168,162,255,.9)); }
/* Same path, played backwards — inbound without a second set of coordinates. */
.hub-in  { stroke: #4ADE9B; filter: drop-shadow(0 0 4px rgba(74,222,155,.85)); animation-direction: reverse; }

.hub-node { fill: rgba(255,255,255,.05); stroke: rgba(255,255,255,.16); stroke-width: 1; }
.hub-core { fill: rgba(124,116,255,.15); stroke: rgba(168,162,255,.55); stroke-width: 1.5; }
.hub-glow { fill: url(#hub-halo); }
.hub-label { font-family: var(--sans); font-size: 12.5px; font-weight: 500; fill: rgba(255,255,255,.85); }
.hub-dim   { font-family: var(--mono); font-size: 10px; fill: rgba(255,255,255,.42); }
.hub-core-name { font-family: var(--sans); font-size: 22px; font-weight: 800; fill: #fff; letter-spacing: -.6px; }

.hub-key { display: flex; flex-wrap: wrap; gap: 1.2rem; justify-content: center; margin-top: 1.1rem; }
.hub-key span { display: inline-flex; align-items: center; gap: .5rem; font-size: .82rem; color: var(--deep-2); }
.hub-key i { width: 18px; height: 2px; border-radius: 2px; display: block; }

@media (prefers-reduced-motion: reduce) {
    .hub-pulse { animation: none; stroke-dasharray: none; opacity: .5; }
    .hub-ring-spin, .hub-ring-spin2, .hub-halo-breathe { animation: none; }
}
.diagram .lbl { font-family: var(--sans); font-size: 12px; fill: rgba(255,255,255,.82); font-weight: 500; }
.diagram .lbl-dim { font-family: var(--mono); font-size: 10px; fill: rgba(255,255,255,.45); }
.diagram .big-n { font-family: var(--sans); font-size: 34px; font-weight: 800; fill: #fff; letter-spacing: -1.5px; }

@media (prefers-reduced-motion: reduce) {
    .bt-art .flow, .diagram .pulse { animation: none; }
    .diagram .pulse { stroke-dasharray: none; opacity: .55; }
}


/* ==========================================================================
   7. UTILITIES
   ========================================================================== */

/* Reveal on scroll — added by JS only when the reader has not asked for less
   motion, so the no-JS and reduced-motion cases both show content immediately. */
.rv { opacity: 0; transform: translateY(12px); transition: opacity .5s ease, transform .5s ease; }
.rv.on { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    .rv { opacity: 1; transform: none; transition: none; }
    .live, .chan.wait .st::before { animation: none; }
    *, *::before, *::after { transition-duration: .01ms !important; }

    /* The marquee stops where it is. The rotator cannot simply stop — every
       word sits in the same grid cell at opacity 0, so halting the animation
       would leave the headline with a blank gap in the middle of a sentence.
       One word is pinned visible and the rest are removed from the flow. */
    .marquee-track { animation: none; }
    .rot > span { animation: none; opacity: 0; transform: none; }
    .rot > span:first-child { opacity: 1; }
}

.visually-hidden {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

@media print {
    .site-nav, .site-footer, .cta-band, .feature-aside, .hero-cta { display: none; }
    body { color: #000; background: #fff; }
}
