﻿/* Finbard - marketing website kit Â· v2 "Advisory" (light, editorial).
   Builds on ../../colors_and_type.css */

/* ====================== DISPLAY TYPEFACE ======================
   MADE Mirage, self-hosted from assets/fonts (passthrough-copied by Eleventy).
   Only the three weights the stylesheet actually calls for are shipped - 400,
   500 and 700. Thin and Black are unused, so they are not in the repo.

   Format note: these are OTF, ~108KB per weight (327KB total) against roughly
   45KB each as WOFF2. Converting needs a tool this repo does not carry; worth a
   follow-up if display-font weight on first paint matters.

   The family name below is declared by us, so it does not need to match the
   font's internal name. font-display:swap means the fallback paints first and
   the page is never blocked on the font. */
@font-face {
    font-family: 'MADE Mirage';
    src: url('/assets/fonts/MADEMirage-Regular.otf') format('opentype');
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}
@font-face {
    font-family: 'MADE Mirage';
    src: url('/assets/fonts/MADEMirage-Medium.otf') format('opentype');
    font-weight: 500;
    font-style: normal;
    font-display: swap;
}
@font-face {
    font-family: 'MADE Mirage';
    src: url('/assets/fonts/MADEMirage-Bold.otf') format('opentype');
    font-weight: 700;
    font-style: normal;
    font-display: swap;
}

/* ====================== ADDITIVE PALETTE ======================
   Layered on top of the vendored tokens (never edit that file â€” sync-design
   regenerates it). These names deliberately do not shadow any kit token.

   Why: the kit ships one dark surface and the site used it on a single band, so
   12 of 13 sections sat within a 1.06:1 lightness of each other â€” the whole page
   lived in the top few percent of the value scale, which is what reads as
   clinical. Tonal steps alone cannot fix that (paper -> a warmer band is still
   only 1.12:1); real rhythm needs true ink bands. Measured ratios are noted so
   nobody has to re-derive them. */
:root {
    /* Display face. --font-serif is the display token: it already drives h1,
       every section h2, .pull and .cta h2, so overriding it
       here reskins all of them at once. Declared in this file, never in the
       vendored token file, which sync-design regenerates. Space Grotesk stays
       as the fallback. */
    --font-serif: 'MADE Mirage', 'Space Grotesk', 'Figtree', -apple-system, system-ui, sans-serif;

    /* structural darks â€” full-bleed section bands */
    --band-ink: #131a17; /* on-dark 16.01:1 Â· mint-accent 8.41:1 Â· amber 6.42:1 */
    --band-ink-2: #1c2723; /* nested panel on a dark band */
    --line-on-ink: rgba(243, 244, 241, 0.16);

    /* warm counterpoint â€” the kit is entirely cool. Amber carries the human,
       narrative half of the story; teal stays the machine half and the brand.
       Deliberately lighter/more orange than semantic --attention #B0801E so a
       highlight is never mistaken for a warning. */
    --amber: #d98a2b; /* FILLS, BORDERS, ICONS, and text ON DARK only (2.64:1 on paper â€” never body text on light) */
    --amber-deep: #8f5a14; /* text-safe amber on light surfaces â€” 5.52:1 on paper */
    --amber-soft: #f6e8d2; /* tint fill */
    --amber-line: rgba(217, 138, 43, 0.34);

    /* a real tonal step for sunken bands (--surface-2 was 1.06:1 vs paper) */
    --band-warm: #efede4; /* ink 14.05:1 Â· ink-body 8.49:1 */

    /* AA-safe muted ink. --ink-mu #6C766E is only 4.02:1 on --band-warm and
       3.91:1 on --surface-3 â€” a live AA failure in the secondary prose of every
       warm band. This clears it on all four surfaces. A LABEL ink: use for small
       mono labels and secondary prose, not for primary body copy. */
    --ink-label: #5c665f; /* paper 5.70 Â· surface 5.96 Â· band-warm 5.09 Â· surface-3 4.95 */

    /* The kit's --ease lands softly. This one overshoots a little, for the two
       things on the site that should arrive with weight rather than easing
       politely into place: the hero's finding panel and the mobile drawer. */
    --spring: cubic-bezier(0.16, 1.1, 0.3, 1);

    /* THE EDITORIAL RULE. --line at 0.11 alpha composites to 1.244:1 on paper â€”
       a rule you infer rather than see, and a big part of why the page read as
       thin. This lands at 2.09:1. Page structure only; seams inside a card keep
       --line / --line-soft. */
    --rule-ink: rgba(24, 33, 29, 0.34);

    /* The sticky bar's own height, 74px + its hairline. The bar sits in normal
       flow above the hero, so this is what the hero has to subtract to fill
       exactly one fold and no more. Kept as a token because the bar shortens at
       the mobile breakpoint and the hero must follow it. */
    --nav-h: 75px;
}

* {
    box-sizing: border-box;
}
body {
    margin: 0;
    background: var(--paper);
    color: var(--ink-body);
}
.wrap {
    max-width: 1140px;
    margin: 0 auto;
    padding: 0 40px;
}
a {
    cursor: pointer;
    /* the kit's --teal is 3.14:1 on paper; links need to clear AA as body text.
       Ink bands and the footer restore a light link colour themselves. */
    color: var(--teal-deep);
}

/* ---------- BUTTONS ---------- */
.btn {
    font-family: var(--font-sans);
    font-weight: 600;
    font-size: 14px;
    border-radius: var(--r-sm);
    padding: 10px 18px;
    border: 1px solid transparent;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    transition:
        transform var(--dur) var(--ease),
        box-shadow var(--dur) var(--ease),
        background var(--dur) var(--ease),
        border-color var(--dur) var(--ease);
    white-space: nowrap;
}
.btn-primary {
    background: var(--mint);
    color: var(--on-mint);
    box-shadow: 0 6px 22px -8px var(--mint-glow);
}
.btn-primary:hover {
    background: var(--mint-bright);
    transform: translateY(-2px);
    box-shadow: 0 12px 30px -8px var(--mint-glow);
}
.btn-primary:active {
    transform: translateY(0);
}
.btn-ghost {
    background: transparent;
    color: var(--ink);
    border-color: var(--line-strong);
}
.btn-ghost:hover {
    border-color: var(--ink-mu);
    background: var(--surface);
}
.btn-text {
    background: none;
    color: var(--teal-deep);
    padding: 10px 2px;
    font-weight: 600;
}
.btn-text:hover {
    color: var(--teal-strong);
}
.btn-lg {
    padding: 13px 22px;
    font-size: 15px;
}

/* ---------- NAV ---------- */
.nav {
    position: sticky;
    top: 0;
    z-index: 40;
    background: rgba(250, 250, 247, 0.82);
    backdrop-filter: blur(10px);
    border-bottom: 1px solid var(--line-soft);
}
.nav-in {
    display: flex;
    align-items: center;
    justify-content: space-between;
    height: 74px;
}
.nav-logo {
    display: flex;
    align-items: center;
    gap: 11px;
    font-weight: 600;
    font-size: 20px;
    letter-spacing: -0.02em;
    color: var(--ink);
}
.nav-links {
    display: flex;
    gap: 32px;
}
.nav-links a {
    color: var(--ink-mu);
    font-size: 15px;
    transition: color var(--dur) var(--ease);
}
.nav-links a:hover {
    color: var(--ink);
}
.nav-cta {
    display: flex;
    align-items: center;
    gap: 16px;
}

/* ---------- MOBILE NAV ----------
   The bar holds a logo, three links, a text link and a button: about 700px of
   content that had no responsive treatment at all, so below roughly 900px it
   simply overflowed and the links wrapped into each other.

   Two states below the breakpoint:

   - Without JS the bar wraps into rows. Every link stays visible and reachable,
     which is the whole no-pre-hiding rule - a drawer that only JS can open would
     leave a JS-less phone with no navigation at all.
   - finbard.js adds `js-nav`, which collapses the bar to logo + burger and mounts
     the drawer. Same progressive-enhancement shape as js-walk / js-anom.

   The drawer is appended to <body>, NOT to .nav, and this is load-bearing:
   .nav carries `backdrop-filter`, and a filter on an ancestor makes it the
   containing block for `position: fixed` descendants - inside .nav the drawer
   would be trapped in the 74px bar instead of covering the viewport. */
.nav-burger {
    display: none;
    place-items: center;
    /* 44px hit target per WCAG 2.5.8, pulled flush with the wrap's padding */
    width: 44px;
    height: 44px;
    margin-right: -10px;
    padding: 0;
    border: 0;
    background: none;
    border-radius: 50%;
    color: var(--ink);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
.nav-burger:focus-visible {
    outline: 2px solid var(--teal);
    outline-offset: 2px;
}
.nav-burger-box {
    position: relative;
    width: 22px;
    height: 14px;
}
.nav-burger-box span {
    position: absolute;
    left: 0;
    width: 100%;
    height: 2px;
    border-radius: 2px;
    background: currentColor;
    transition:
        transform 0.44s var(--spring),
        width 0.3s var(--ease);
}
.nav-burger-box span:first-child {
    top: 0;
}
/* the lower bar rests short and squares up as it becomes half of the cross */
.nav-burger-box span:last-child {
    bottom: 0;
    width: 64%;
}
.nav-burger[aria-expanded='true'] .nav-burger-box span {
    width: 100%;
}
.nav-burger[aria-expanded='true'] .nav-burger-box span:first-child {
    transform: translateY(6px) rotate(45deg);
}
.nav-burger[aria-expanded='true'] .nav-burger-box span:last-child {
    transform: translateY(-6px) rotate(-45deg);
}

.nav-drawer {
    position: fixed;
    inset: 0;
    /* under the bar's 40, so the logo and the burger stay above the panel and
       the burger keeps working as the close control */
    z-index: 39;
    background-color: var(--band-ink);
    /* the brand's dot matrix, held right at the edge of visibility */
    background-image: radial-gradient(circle, rgba(22, 201, 172, 0.17) 1.4px, transparent 1.5px);
    background-size: 27px 27px;
    color: var(--on-dark);
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    gap: 28px;
    padding: 104px 32px calc(36px + env(safe-area-inset-bottom));
    overflow-y: auto;
    overscroll-behavior: contain;
    /* opens as a circle growing out of the burger: the same "it comes out of the
       control that summoned it" language as the hero's finding panel. Origin and
       radius are measured by finbard.js. */
    clip-path: circle(0px at var(--ox, 100%) var(--oy, 37px));
    visibility: hidden;
    transition:
        clip-path 0.54s var(--ease-in-out),
        visibility 0s linear 0.54s;
}
.nav-drawer.is-open {
    clip-path: circle(var(--r, 150vmax) at var(--ox, 100%) var(--oy, 37px));
    visibility: visible;
    transition:
        clip-path 0.54s var(--ease-in-out),
        visibility 0s linear 0s;
}
.nav-drawer-links {
    display: flex;
    flex-direction: column;
}
.nav-drawer-links a {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 18px;
    padding: 19px 2px;
    border-bottom: 1px solid var(--line-on-ink);
    font-family: var(--font-serif);
    font-weight: 500;
    font-size: clamp(25px, 7.6vw, 34px);
    letter-spacing: -0.4px;
    line-height: 1.1;
    color: var(--on-dark);
    text-decoration: none;
    opacity: 0;
    transform: translateY(16px);
    transition:
        opacity 0.5s var(--ease),
        transform 0.5s var(--spring);
    /* each link arrives just behind the wipe that uncovers it */
    transition-delay: calc(var(--i) * 62ms + 130ms);
}
.nav-drawer-links a:first-child {
    border-top: 1px solid var(--line-on-ink);
}
.nav-drawer-links a.active {
    color: var(--mint-accent);
}
.nav-drawer.is-open .nav-drawer-links a {
    opacity: 1;
    transform: none;
}
.nav-drawer-chev {
    flex: none;
    width: 9px;
    height: 9px;
    border-right: 2px solid var(--mint-accent);
    border-bottom: 2px solid var(--mint-accent);
    transform: rotate(-45deg);
    transition: transform 0.3s var(--ease);
}
.nav-drawer-links a:hover .nav-drawer-chev,
.nav-drawer-links a:focus-visible .nav-drawer-chev {
    transform: rotate(-45deg) translate(3px, 3px);
}
.nav-drawer-cta {
    display: flex;
    flex-direction: column;
    gap: 12px;
    opacity: 0;
    transform: translateY(16px);
    transition:
        opacity 0.5s var(--ease),
        transform 0.5s var(--spring);
    transition-delay: 330ms;
}
.nav-drawer.is-open .nav-drawer-cta {
    opacity: 1;
    transform: none;
}
.nav-drawer-cta .btn {
    width: 100%;
    justify-content: center;
    padding: 15px 22px;
    font-size: 16px;
}
/* the bar's "Sign in" carries an inline --ink-mu that is unreadable on ink, so
   finbard.js strips the clone's style attribute and this dresses it instead */
.nav-drawer-cta .btn-text {
    color: var(--on-dark-mu);
    border: 1px solid var(--line-on-ink);
}
.nav-drawer-cta .btn-text:hover {
    color: var(--on-dark);
}

/* while the drawer is up, the bar drops its paper background so the logo and the
   burger read as sitting directly on the ink panel */
html.nav-open,
html.nav-open body {
    overflow: hidden;
}
html.nav-open .nav {
    background: transparent;
    backdrop-filter: none;
    border-bottom-color: transparent;
}
html.nav-open .nav-logo {
    color: var(--on-dark);
}
html.nav-open .nav-logo .by {
    color: var(--on-dark-mu);
}
html.nav-open .nav-burger {
    color: var(--on-dark);
}

@media (max-width: 900px) {
    /* the bar shortens here, and the hero measures its fold against it */
    :root {
        --nav-h: 69px;
    }
    .nav-in {
        flex-wrap: wrap;
        height: auto;
        gap: 12px 22px;
        padding-top: 14px;
        padding-bottom: 14px;
    }
    .nav-links {
        flex-wrap: wrap;
        gap: 20px;
    }
    /* the underline is calibrated to the 74px bar; in the wrapped no-JS state it
       would otherwise float far below its link */
    .nav-links a.active::after {
        bottom: -7px;
    }
    .js-nav .nav-in {
        flex-wrap: nowrap;
        height: 68px;
        padding-top: 0;
        padding-bottom: 0;
    }
    .js-nav .nav-links,
    .js-nav .nav-cta {
        display: none;
    }
    .js-nav .nav-burger {
        display: grid;
    }
}
@media (min-width: 901px) {
    /* above the breakpoint the bar itself is the navigation */
    .nav-drawer {
        display: none;
    }
}
@media (prefers-reduced-motion: reduce) {
    .nav-drawer,
    .nav-drawer.is-open {
        clip-path: none;
        transition: none;
    }
    .nav-drawer-links a,
    .nav-drawer-cta,
    .nav-drawer-chev,
    .nav-burger-box span {
        transition: none;
    }
    .nav-drawer-links a,
    .nav-drawer-cta {
        opacity: 1;
        transform: none;
    }
}

/* ---------- shared bits ---------- */
.eyebrow {
    font-family: var(--font-mono);
    font-size: 12px;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--ink-mu);
    display: flex;
    align-items: center;
    gap: 10px;
}
.eyebrow .tick {
    width: 18px;
    height: 1px;
    background: var(--teal);
    transform-origin: left;
}
.eyebrow.teal {
    color: var(--teal-deep);
}

/* ---------- HERO ----------
   The centred build: the copy sits in a hole punched in the dot field, the same
   construction as the closing CTA, and the anomaly dots live out in the ring
   around it. See "HERO ANOMALY FIELD" below for the dots and the panel. */
.hero {
    /* the padding is a floor, not the height: on a short viewport the copy still
       gets its breathing room and the hero is allowed to run past the fold */
    padding: 84px 0 76px;
    position: relative;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    justify-content: center;
    /* exactly one fold: the viewport less the sticky bar above it. The whole
       ring of anomaly dots is placed as a percentage of this box, so a hero that
       stops short of the fold puts its lower dots in dead space and one that
       overruns it hides them - either way the field only reads at full height.

       svh, not vh: on mobile 100vh is the LARGE viewport, measured with the URL
       bar retracted, so a vh-sized hero overflows the fold on first paint by
       exactly the height of the browser chrome. svh is the smallest viewport and
       always fits. The vh line above it is the fallback for engines without svh,
       where overshooting is the safer miss. */
    min-height: calc(100vh - var(--nav-h));
    min-height: calc(100svh - var(--nav-h));
    text-align: center;
}
.hero::before {
    content: '';
    position: absolute;
    width: 900px;
    height: 900px;
    left: 50%;
    top: 50%;
    /* centred on the copy now that the hero is centred - the old build parked
       this bloom in the top-right corner, opposite a left-aligned headline */
    margin: -450px 0 0 -450px;
    background: radial-gradient(circle, rgba(22, 201, 172, 0.11), transparent 60%);
    pointer-events: none;
    z-index: 0;
    animation: heroDrift 16s ease-in-out infinite;
}
@keyframes heroDrift {
    0%,
    100% {
        transform: translate(0, 0) scale(1);
    }
    50% {
        transform: translate(-34px, 28px) scale(1.06);
    }
}
@media (prefers-reduced-motion: reduce) {
    .hero::before {
        animation: none;
    }
}
.hero .wrap {
    position: relative;
    z-index: 1;
}
.hero-dotfield {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    z-index: 0;
    opacity: 0.7;
    pointer-events: none;
    /* NO mask here. The centre is kept clear for the copy by `data-hole` on the
       canvas, i.e. inside the draw loop - see setupDotFields in finbard.js for
       why, and do not reintroduce a mask as a "simpler" version of it.

       Short version: a mask is a flat multiplier the canvas cannot see past. The
       masked build shipped and measured wrong - the field's own falloff ran the
       opposite way to the mask, so the brightest dots landed exactly where the
       mask erased them, visible alpha never cleared 0.22, and the cursor lens
       was bending dots at 0.001 alpha over the headline. The in-loop hole
       inverts the falloff to run with the hole and lets the lens locally win. */
}
.hero-center {
    position: relative;
    z-index: 2;
    /* the copy steps back while a finding is on screen. Keyed off the hero, not
       off each dot, so moving between dots does not strobe the headline - it
       dims once on the way in and lifts once on the way out. */
    transition:
        opacity 0.45s var(--ease),
        transform 0.45s var(--ease);
}
.hero.is-anom-open .hero-center {
    opacity: 0.3;
    transform: scale(0.985);
}
.hero h1 {
    font-family: var(--font-serif);
    font-weight: 500;
    /* fluid, so the centred headline holds its three lines from phone to
       desktop without a per-breakpoint override */
    font-size: clamp(38px, 4.7vw, 58px);
    line-height: 1.12;
    letter-spacing: -0.5px;
    color: var(--ink);
    /* em, not px: the measure scales with the fluid size, which is what keeps
       the long first sentence breaking into two balanced lines at every width.
       Kept narrow deliberately - every ch the copy gives up is a ch of clear
       corridor for the panel to open into. */
    max-width: 10em;
    margin: 0 auto;
    text-wrap: balance;
}
.hero h1 em {
    /* upright, not italic â€” the accent here is colour alone */
    font-style: normal;
    color: var(--teal);
}
.ln {
    display: block;
}
.hero-sub {
    font-size: 19px;
    line-height: 1.6;
    color: var(--ink-mu);
    max-width: 44ch;
    margin: 22px auto 0;
    text-wrap: pretty;
}
.hero-actions {
    display: flex;
    /* wrap or the pair's min-content (~333px) sets the hero's width and pushes a
       375px viewport into a horizontal scroll */
    flex-wrap: wrap;
    gap: 14px;
    margin-top: 32px;
    align-items: center;
    justify-content: center;
}
/* ---------- HERO ANOMALY FIELD ----------
   The five findings the hero can show are dots out in the dot-field ring: red
   for critical, yellow for attention. Hover, focus or tap one and the live
   finding card unfolds out of it. The dots are injected by finbard.js from the
   findings JSON (so with JS off there are no dead controls), and finbard.js also
   marks the hero `js-anom`, which is what turns the card from a plain centred
   block into the floating panel. Nothing here pre-hides content.

   The `.js-anom ... .finding` rules below deliberately outrank the WOW-layer
   card styles further down this file (3 classes vs 1) - in panel mode the card's
   aura and shadow take the finding's own colour instead of the standing mint. */
.hero-anomalies {
    position: absolute;
    inset: 0;
    z-index: 3;
    /* the layer is inert; only the dots themselves take the pointer */
    pointer-events: none;
}
/* One severity, one set of variables, worn by the dot, the connector hairline
   and the panel alike - which is how the panel comes up in the colour of the dot
   that opened it. rgba components rather than the --critical / --attention
   tokens because box-shadows and keyframes need the alpha variants; the opaque
   values match those tokens exactly. */
.anom-critical {
    --anom: #be4138;
    --anom-soft: rgba(190, 65, 56, 0.42);
    --anom-faint: rgba(190, 65, 56, 0.15);
    --anom-line: rgba(190, 65, 56, 0.34);
}
.anom-attention {
    --anom: #b0801e;
    --anom-soft: rgba(176, 128, 30, 0.44);
    --anom-faint: rgba(176, 128, 30, 0.16);
    --anom-line: rgba(176, 128, 30, 0.36);
}
.hero-dot {
    position: absolute;
    left: calc(var(--x) * 1%);
    top: calc(var(--y) * 1%);
    /* 44px of hit target around a 14px dot, per WCAG 2.5.8 */
    width: 44px;
    height: 44px;
    margin: -22px 0 0 -22px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: none;
    display: grid;
    place-items: center;
    cursor: pointer;
    pointer-events: auto;
    -webkit-tap-highlight-color: transparent;
}
.hero-dot:focus-visible {
    outline: 2px solid var(--anom);
    outline-offset: 2px;
}
.hero-dot-core {
    /* deliberately oversized against the field's 2.4-4px ambient dots - these
       are findings, not texture */
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background: var(--anom);
    box-shadow:
        0 0 0 4px var(--anom-faint),
        0 0 20px -1px var(--anom-soft);
    /* the blink. A pulse rather than a hard on/off: five dots strobing at 1Hz
       would trip WCAG 2.2.2 and read as a broken page, where 0.42 -> 1 over
       2.6s still unmistakably says "alive". Negative delay so the five are out
       of phase from the first frame instead of flashing in unison. */
    animation: anomBreathe 2.6s var(--ease-in-out) infinite;
    animation-delay: calc(var(--i) * -0.52s);
    transition:
        transform 0.34s var(--spring),
        box-shadow 0.34s var(--ease);
}
@keyframes anomBreathe {
    0%,
    100% {
        opacity: 0.55;
        transform: scale(0.82);
    }
    50% {
        opacity: 1;
        transform: scale(1.16);
    }
}
.hero-dot-ring {
    position: absolute;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    border: 1.5px solid var(--anom);
    opacity: 0;
    pointer-events: none;
    animation: anomPing 3.2s var(--ease) infinite;
    animation-delay: calc(var(--i) * -0.64s);
}
@keyframes anomPing {
    0% {
        transform: scale(1);
        opacity: 0.55;
    }
    70%,
    100% {
        transform: scale(3.2);
        opacity: 0;
    }
}
/* live = this dot's finding is the one on screen. The breathe stops (a moving
   target is hard to keep the pointer on) and the ping tightens into a beacon. */
.hero-dot:hover .hero-dot-core,
.hero-dot:focus-visible .hero-dot-core,
.hero-dot.is-live .hero-dot-core {
    animation: none;
    opacity: 1;
    transform: scale(1.75);
    box-shadow:
        0 0 0 6px var(--anom-faint),
        0 0 30px 0 var(--anom-soft);
}
.hero-dot.is-live .hero-dot-ring {
    animation: anomBurst 1.15s var(--ease) infinite;
}
@keyframes anomBurst {
    0% {
        transform: scale(1);
        opacity: 0.8;
    }
    100% {
        transform: scale(5);
        opacity: 0;
    }
}
/* hairline drawn from the live dot to the panel edge, so the panel reads as
   having come out of that dot. Length and angle are set inline by finbard.js. */
.hero-anom-link {
    position: absolute;
    left: 0;
    top: 0;
    height: 1px;
    transform-origin: 0 50%;
    background: linear-gradient(90deg, var(--anom), rgba(0, 0, 0, 0));
    opacity: 0;
    pointer-events: none;
    transform: translate(var(--lx, 0px), var(--ly, 0px)) rotate(var(--lr, 0deg)) scaleX(0);
    transition:
        transform 0.44s var(--spring),
        opacity 0.3s var(--ease);
}
.hero-anom-link.is-on {
    opacity: 0.9;
    transform: translate(var(--lx, 0px), var(--ly, 0px)) rotate(var(--lr, 0deg)) scaleX(1);
}

/* the card's slot. Plain centred block in the source; a hero-wide positioning
   layer once JS takes over. */
.hero-findslot {
    position: relative;
    z-index: 2;
    /* the hero centres its copy; a finding is tabular data and reads left, so
       the card opts back out of the inherited centring */
    text-align: left;
}
.hero-panel {
    max-width: 420px;
    margin: 48px auto 0;
}
.js-anom .hero-findslot {
    position: absolute;
    inset: 0;
    z-index: 6;
    margin: 0;
    pointer-events: none;
}
.js-anom .hero-panel {
    position: absolute;
    left: 0;
    top: 0;
    /* narrower than the source card: it has to open inside the corridor beside
       the copy, not across it */
    width: 344px;
    max-width: none;
    margin: 0;
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    /* unfolds from the dot: origin on the facing edge, a nudge back toward the
       dot, and out of focus until it lands */
    transform: translate(var(--dx, 0px), var(--dy, 0px)) scale(0.8);
    transform-origin: var(--ox, 50%) var(--oy, 50%);
    filter: blur(9px);
    transition:
        opacity 0.24s var(--ease),
        transform 0.5s var(--spring),
        filter 0.28s var(--ease),
        left 0.52s var(--spring),
        top 0.52s var(--spring),
        visibility 0s linear 0.5s;
}
.js-anom .hero-panel.is-open {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transform: none;
    filter: none;
    transition:
        opacity 0.3s var(--ease),
        transform 0.56s var(--spring),
        filter 0.34s var(--ease),
        left 0.52s var(--spring),
        top 0.52s var(--spring),
        visibility 0s linear 0s;
}
.js-anom .hero-findslot .finding {
    border-color: var(--anom-line, var(--line));
    box-shadow:
        0 30px 64px -26px rgba(24, 33, 29, 0.32),
        0 0 30px -8px var(--anom-soft, transparent);
}
.js-anom .hero-findslot .finding:hover {
    box-shadow:
        0 34px 70px -26px rgba(24, 33, 29, 0.36),
        0 0 40px -6px var(--anom-soft, transparent);
}
.js-anom .hero-findslot .finding::before {
    background: radial-gradient(70% 70% at 72% 0%, var(--anom-faint, transparent), transparent 70%);
    opacity: 1;
}
/* dismiss control, injected with the panel - a hover-only affordance would be a
   trap on touch, where the panel is opened by tap and pinned */
.hero-panel-close {
    /* outside the corner, not inside it: at 344px the card's top row is already
       full, and an inset button lands straight on the severity chip */
    position: absolute;
    top: -11px;
    right: -11px;
    z-index: 6;
    width: 28px;
    height: 28px;
    display: none;
    place-items: center;
    padding: 0;
    border: 1px solid var(--line-strong);
    border-radius: 50%;
    background: var(--surface);
    box-shadow: var(--shadow-md);
    color: var(--ink-mu);
    font-size: 16px;
    cursor: pointer;
    line-height: 1;
}
.hero-panel-close:hover {
    color: var(--ink);
    border-color: var(--line-strong);
}
.js-anom .hero-panel.is-pinned .hero-panel-close {
    display: grid;
}
/* the field steps back while a finding is on screen, so the panel is the
   brightest thing in the hero */
.hero.is-anom-open .hero-dotfield {
    opacity: 0.5;
}
.hero-dotfield {
    transition: opacity 0.45s var(--ease);
}
@media (prefers-reduced-motion: reduce) {
    /* no blink, no ping, no blur, no travel - the panel simply is or is not
       there, and the dots sit at full strength so they are still findable */
    .hero-dot-core {
        animation: none;
        opacity: 1;
        transform: none;
        transition: none;
    }
    .hero-dot:hover .hero-dot-core,
    .hero-dot:focus-visible .hero-dot-core,
    .hero-dot.is-live .hero-dot-core {
        transform: scale(1.5);
    }
    .hero-dot-ring,
    .hero-anom-link {
        display: none;
    }
    .js-anom .hero-panel,
    .js-anom .hero-panel.is-open {
        transform: none;
        filter: none;
        transition: none;
    }
    .hero.is-anom-open .hero-dotfield,
    .hero-dotfield {
        transition: none;
    }
}

/* ---------- LIVE FINDING CARD ---------- */
.finding {
    position: relative;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-md);
    overflow: hidden;
}
.finding-glare {
    position: absolute;
    inset: 0;
    border-radius: var(--r-lg);
    opacity: 0;
    transition: opacity 0.3s var(--ease);
    pointer-events: none;
    z-index: 4;
}
.finding-top {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 16px 20px;
    border-bottom: 1px solid var(--line-soft);
}
.finding-top .lbl {
    font-family: var(--font-mono);
    font-size: 11px;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--ink-mu);
    display: flex;
    align-items: center;
    gap: 8px;
}
.live {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--teal-deep);
}
.live .d {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--mint-accent);
    box-shadow: var(--glow-mint-sm);
    animation: livepulse 2.4s var(--ease) infinite;
}
@keyframes livepulse {
    0% {
        box-shadow: 0 0 0 0 rgba(22, 201, 172, 0.5);
    }
    70% {
        box-shadow: 0 0 0 8px rgba(22, 201, 172, 0);
    }
    100% {
        box-shadow: 0 0 0 0 rgba(22, 201, 172, 0);
    }
}
.chip {
    margin-left: auto;
    display: inline-flex;
    align-items: center;
    gap: 7px;
    font-family: var(--font-mono);
    font-size: 11px;
    font-weight: 500;
    padding: 4px 10px;
    border-radius: var(--r-pill);
}
.chip .d {
    width: 6px;
    height: 6px;
    border-radius: 50%;
}
.finding-body {
    padding: 20px;
}
.finding-body h3 {
    font-family: var(--font-serif);
    font-weight: 600;
    font-size: 22px;
    color: var(--ink);
    letter-spacing: -0.1px;
}
.finding-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    margin-top: 6px;
}
.finding-row .v {
    color: var(--ink-mu);
    font-size: 15px;
}
.finding-row .amt {
    font-family: var(--font-mono);
    font-size: 20px;
    color: var(--ink);
    font-variant-numeric: tabular-nums;
}
.finding-expl {
    color: var(--ink-body);
    font-size: 15px;
    line-height: 1.55;
    margin-top: 16px;
    min-height: 66px;
}
.finding-foot {
    display: flex;
    align-items: center;
    gap: 20px;
    margin-top: 18px;
    padding-top: 16px;
    border-top: 1px solid var(--line-soft);
    font-size: 13px;
    color: var(--ink-mu);
}
.finding-foot .kv b {
    color: var(--ink);
    font-family: var(--font-mono);
    font-weight: 600;
}
.conf-wrap {
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.conf-bar {
    width: 78px;
    height: 4px;
    border-radius: 2px;
    background: var(--surface-3);
    overflow: hidden;
}
.conf-fill {
    height: 100%;
    width: 0;
    background: linear-gradient(90deg, var(--mint-accent), var(--mint-deep));
    border-radius: 2px;
    box-shadow: var(--glow-mint-sm);
}
.finding-link {
    margin-left: auto;
    color: var(--teal-deep);
    font-weight: 600;
    display: inline-flex;
    align-items: center;
    gap: 6px;
}
.scanline {
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    height: 70px;
    pointer-events: none;
    opacity: 0;
    background: linear-gradient(
        180deg,
        rgba(118, 232, 211, 0) 0%,
        rgba(118, 232, 211, 0.22) 50%,
        rgba(14, 133, 118, 0) 100%
    );
}

/* ---------- SECTIONS ---------- */
.sec {
    padding: 88px 0;
}
.sec-sunken {
    background: var(--band-warm);
    /* a tonal step this small can never carry a boundary on its own - the rule
       does the work, the tone just stops it looking like a stray line */
    border-top: 2px solid var(--ink);
    border-bottom: 1px solid var(--rule-ink);
}
/* --ink-mu drops to 4.02:1 on --band-warm, so secondary prose inside a warm
   band takes the label ink (5.09:1) instead. */
.sec-sunken .sec-head p,
.sec-sunken .srow p,
.sec-sunken .sec-card p,
.sec-sunken .story-before .story-row,
.sec-sunken .steps .step p,
.sec-sunken .faq-a,
.sec-sunken .assure-cell p,
.sec-sunken .eyebrow,
.sec-sunken .pull {
    color: var(--ink-label);
}
.sec-sunken .pull {
    color: var(--ink);
}

/* ---------- INK BANDS ----------
   Full-bleed dark sections, the main fix for the flat value range. Content that
   is already a self-contained white card (.pstage, .signal, .invcard, .demo,
   .sec-card, .finding) needs no changes and gains contrast for free; only the
   section's own type inverts. */
.sec-ink {
    background: var(--band-ink);
    border-top: 1px solid var(--band-ink);
    border-bottom: 1px solid var(--band-ink);
    color: var(--on-dark-mu);
}
.sec-ink .sec-head h2,
.sec-ink .pull {
    color: var(--on-dark);
}
/* Band-level text only. Do NOT add label classes like .mono-note or .panel-k
   here: they live inside white cards that sit ON the band, so an on-dark colour
   would render at ~2:1 against the card. */
.sec-ink .sec-head p {
    color: var(--on-dark-mu);
}
.sec-ink .eyebrow {
    color: var(--on-dark-mu);
}
.sec-ink .eyebrow .tick {
    background: var(--mint-accent);
}
/* NB: .pchecks lives inside the white .pstage card, not on the band, so it must
   keep its light-surface ink - an on-dark override here would be 2:1 on white. */
.sec-ink a:not(.btn) {
    color: var(--mint-accent);
}
/* ...but not links sitting on a light card that happens to be on the band -
   mint-accent is 2.1:1 on white. Must stay after the rule above: same
   specificity, so order decides. */
.sec-ink .meter-card a:not(.btn),
.sec-ink .price-card a:not(.btn),
.sec-ink .sec-card a:not(.btn),
.sec-ink .demo a:not(.btn) {
    color: var(--teal-deep);
}
.sec-ink .srow {
    border-bottom-color: var(--line-on-ink);
}
.sec-ink .surfaces {
    border-top-color: var(--line-on-ink);
}
.sec-ink .srow h4 {
    color: var(--on-dark);
}
.sec-ink .srow p {
    color: var(--on-dark-mu);
}
.sec-head {
    max-width: 620px;
}
.sec-head h2 {
    font-family: var(--font-serif);
    font-weight: 500;
    font-size: 40px;
    line-height: 1.17;
    letter-spacing: -0.3px;
    color: var(--ink);
    /* first child of .sec-head now that the mono kicker is gone â€” no top offset */
    margin: 0;
}
.sec-head p {
    font-size: 18px;
    color: var(--ink-mu);
    margin: 18px 0 0;
    line-height: 1.55;
}

/* transformation before/after */
.story {
    display: grid;
    grid-template-columns: 1fr 1fr;
    /* the columns used to be separated by an arrow glyph; the gap carries the
       separation on its own now */
    gap: 0 56px;
    margin-top: 48px;
    align-items: stretch;
}
.story-col {
    padding: 28px 30px;
}
.story-after {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-sm);
}
.story-lab {
    font-family: var(--font-mono);
    font-size: 11px;
    letter-spacing: 0.13em;
    text-transform: uppercase;
    margin-bottom: 20px;
}
/* the "before" column is the human cost: warm amber. the "after" is the
   machine: brand teal. */
.story-before .story-lab {
    color: var(--amber-deep);
}
.story-after .story-lab {
    color: var(--teal-deep);
}
.story-row {
    display: flex;
    gap: 12px;
    padding: 13px 0;
    border-bottom: 1px solid var(--line-soft);
    align-items: flex-start;
    font-size: 15px;
    line-height: 1.45;
}
.story-row:last-child {
    border-bottom: 0;
}
.story-row .ic {
    flex-shrink: 0;
    margin-top: 1px;
}
.story-before .story-row {
    color: var(--ink-mu);
}
.story-after .story-row {
    color: var(--ink);
}

/* surfaces list */
.surfaces {
    margin-top: 46px;
    border-top: 1px solid var(--line);
}
.srow {
    display: grid;
    grid-template-columns: 40px 1fr 1.4fr;
    gap: 28px;
    align-items: start;
    padding: 26px 4px;
    border-bottom: 1px solid var(--line);
}
.srow .ic {
    color: var(--teal);
    margin-top: 2px;
    transition: transform var(--dur) var(--ease);
}
.srow:hover .ic {
    transform: translateY(-2px);
}
.srow h4 {
    font-family: var(--font-sans);
    font-weight: 600;
    font-size: 18px;
    color: var(--ink);
}
.srow p {
    color: var(--ink-mu);
    font-size: 15px;
    line-height: 1.55;
}

/* ---------- ASK DEMO ---------- */
.demo {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0;
    margin-top: 46px;
    border: 1px solid var(--line);
    border-radius: var(--r-xl);
    overflow: hidden;
    background: var(--surface);
}
.demo-left {
    padding: 34px;
    border-right: 1px solid var(--line);
}
.demo-right {
    position: relative;
    min-height: 420px;
    background: var(--surface-2);
}
.ask {
    display: flex;
    align-items: center;
    gap: 11px;
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--r-sm);
    padding: 12px 14px;
    margin-top: 22px;
}
.ask input {
    flex: 1;
    background: none;
    border: 0;
    outline: none;
    color: var(--ink);
    font-family: var(--font-sans);
    font-size: 15px;
}
.ask input::placeholder {
    color: var(--ink-faint);
}
.suggest {
    display: flex;
    flex-wrap: wrap;
    gap: 9px;
    margin-top: 16px;
}
.suggest button {
    font-family: var(--font-sans);
    font-size: 13px;
    color: var(--ink-mu);
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--r-pill);
    padding: 8px 13px;
    cursor: pointer;
    transition: all var(--dur) var(--ease);
}
.suggest button:hover,
.suggest button.on {
    color: var(--teal-deep);
    border-color: var(--teal-line);
    background: var(--teal-tint);
}
.answer {
    margin-top: 24px;
    font-size: 15px;
    line-height: 1.65;
    color: var(--ink-body);
}
.reason {
    margin: 14px 0;
    border-left: 2px solid var(--teal-line);
    padding-left: 14px;
    display: flex;
    flex-direction: column;
    gap: 7px;
}
.reason .step {
    font-family: var(--font-mono);
    font-size: 12.5px;
    color: var(--ink-mu);
    display: flex;
    gap: 10px;
    align-items: baseline;
    line-height: 1.5;
}
.reason .step b {
    color: var(--teal-deep);
    font-weight: 600;
    flex-shrink: 0;
}
.cursor {
    display: inline-block;
    width: 7px;
    height: 16px;
    background: var(--teal);
    margin-left: 2px;
    vertical-align: -2px;
    animation: blink 1s step-end infinite;
}
@keyframes blink {
    50% {
        opacity: 0;
    }
}

/* ---------- CTA + FOOTER ---------- */
.cta {
    text-align: center;
    padding: 104px 0;
    /* the closing sequence opens on a heavy editorial rule */
    border-top: 2px solid var(--ink);
    position: relative;
    overflow: hidden;
}
.cta .wrap {
    position: relative;
    z-index: 1;
}
.cta-dotfield {
    position: absolute;
    inset: 0;
    /* REQUIRED: <canvas> is a replaced element with an intrinsic 300x150 size, so
       inset:0 alone does not stretch it - without these it renders as a small
       patch pinned to the top-left corner. */
    width: 100%;
    height: 100%;
    z-index: 0;
    opacity: 0.5;
    pointer-events: none;
    /* clear in the middle, field around the edges: the type sits in the hole
       rather than on top of the densest part of the grid */
    mask-image: radial-gradient(62% 78% at 50% 50%, transparent 26%, #000 82%);
    -webkit-mask-image: radial-gradient(62% 78% at 50% 50%, transparent 26%, #000 82%);
}
.cta h2 {
    font-family: var(--font-serif);
    font-weight: 500;
    font-size: 48px;
    letter-spacing: -0.5px;
    color: var(--ink);
    line-height: 1.16;
    max-width: 18ch;
    /* `auto` sides keep it centred; no top offset now the kicker is gone */
    margin: 0 auto;
}
.cta p {
    font-size: 18px;
    color: var(--ink-mu);
    margin: 18px auto 0;
    max-width: 44ch;
}
/* the closing credit line: wider than .cta p's 44ch so it holds one line, and
   `auto` side margins so it stays centred (an inline `margin: x 0 0` would
   silently kill the centring) */
.cta .cta-fine {
    margin: 24px auto 0;
    max-width: 72ch;
}
footer {
    /* the closing ink plate - anchors the page instead of fading out into
       another near-white band */
    border-top: 0;
    background: var(--band-ink);
    color: var(--on-dark-mu);
    padding: 56px 0 40px;
}
footer .nav-logo,
footer .foot-grid h5 {
    color: var(--on-dark);
}
footer .foot-grid a,
footer .foot-bottom,
footer .foot-links a,
footer .bymesh {
    color: var(--on-dark-mu);
}
footer .foot-grid a:hover,
footer .foot-links a:hover {
    color: var(--mint-accent);
}
footer .foot-bottom {
    border-top-color: var(--line-on-ink);
}
footer .bymesh b {
    color: var(--on-dark);
}
.foot-grid {
    display: grid;
    grid-template-columns: 1.6fr 1fr 1fr 1fr;
    gap: 32px;
}
.foot-grid h5 {
    font-family: var(--font-mono);
    font-size: 11px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--ink-mu);
    margin: 0 0 16px;
    font-weight: 500;
}
.foot-grid a {
    display: block;
    color: var(--ink-body);
    font-size: 14px;
    margin-bottom: 11px;
}
.foot-grid a:hover {
    color: var(--teal-deep);
}
.foot-bottom {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-top: 48px;
    padding-top: 26px;
    border-top: 1px solid var(--line);
    color: var(--ink-label);
    font-size: 13px;
}
.foot-links {
    display: flex;
    gap: 22px;
}
.foot-links a {
    color: var(--ink-label);
}
.foot-links a:hover {
    color: var(--ink);
}

@media (max-width: 980px) {
    /* Narrow: no room in the ring for a floating panel, so the field flattens
       into a row of five dots under the copy and the panel drops in beneath
       them. The h1 needs no override - it is fluid (clamp) now. finbard.js
       stops writing left/top below this width, so no !important is needed. */
    .hero {
        /* the fold min-height from the base rule still applies - stacked, the
           box is taller than its content on anything but a small phone, and the
           narrow hole is a proportion of that box, so the field looks the same
           at any height (measured: ~51% of the grid drawn from 598px to 863px).
           Only the padding tightens. */
        padding: 76px 0 80px;
    }
    .hero-dotfield {
        opacity: 0.42;
    }
    .hero-center {
        order: 1;
    }
    .hero-anomalies {
        order: 2;
        position: static;
        inset: auto;
        display: flex;
        justify-content: center;
        align-items: center;
        gap: 22px;
        margin: 38px auto 0;
    }
    .hero-dot {
        position: relative;
        left: auto;
        top: auto;
        margin: 0;
    }
    /* JS off: no controls exist, so the card is just a block under the dots. */
    .hero-findslot {
        order: 3;
        position: static;
        inset: auto;
        padding: 0 40px;
    }
    .hero-panel {
        position: relative;
        left: auto;
        top: auto;
        width: 100%;
        max-width: 430px;
        margin: 28px auto 0;
    }
    /* JS on: the panel floats over the hero rather than dropping in beneath the
       dots. In flow it added its own height on every open - the hero grew by a
       card (406px on a 390px phone) and everything below it jumped down, so
       reading a second finding meant chasing the page. Overlaying costs no
       layout in either state. It centres on the hero, which leaves the dot row
       below it uncovered, so you can still switch findings while one is open. */
    .js-anom .hero-findslot {
        position: absolute;
        inset: 0;
        z-index: 6;
        margin: 0;
        padding: 0 24px;
        display: flex;
        align-items: center;
        justify-content: center;
        pointer-events: none;
    }
    .js-anom .hero-panel {
        /* the slot owns placement, so the panel's own transform stays free for
           the open/close animation */
        position: relative;
        left: auto;
        top: auto;
        width: 100%;
        max-width: 430px;
        margin: 0;
        pointer-events: auto;
        transform: translateY(16px) scale(0.97);
        transform-origin: 50% 0;
        filter: blur(6px);
        /* Overlaid now, so a closed panel costs no layout either way. Kept
           display:none so it is not a tab stop or a hit target while closed;
           finbard.js flips the hero to `is-anom-open` a frame before it opens
           the panel, so the transition still runs. */
        display: none;
    }
    .js-anom.is-anom-open .hero-panel {
        display: block;
    }
    .js-anom .hero-panel.is-open {
        transform: none;
        filter: none;
    }
    .hero-anom-link {
        display: none;
    }
    .story {
        grid-template-columns: 1fr;
        gap: 28px;
    }
    .demo {
        grid-template-columns: 1fr;
    }
    .demo-right {
        min-height: 300px;
    }
    .srow {
        grid-template-columns: 32px 1fr;
        gap: 18px;
    }
    .srow p {
        grid-column: 2;
    }
    .foot-grid {
        grid-template-columns: 1fr 1fr;
    }
    .outcomes {
        grid-template-columns: 1fr;
    }
    .outcome + .outcome {
        border-left: 0;
        border-top: 1px solid var(--line);
    }
    .trust-in {
        gap: 20px;
    }
}

/* ====================== WOW LAYER ====================== */
/* finding card: ambient mint aura + magnetic lift */
.finding {
    transition:
        transform 0.4s var(--ease),
        box-shadow 0.4s var(--ease);
}
.finding::before {
    content: '';
    position: absolute;
    inset: -1px;
    border-radius: var(--r-lg);
    background: radial-gradient(70% 70% at 72% 0%, var(--mint-accent-soft), transparent 70%);
    opacity: 0.55;
    transition: opacity 0.6s var(--ease);
    pointer-events: none;
}
.finding:hover {
    transform: translateY(-5px);
    box-shadow: var(--shadow-lg), var(--glow-mint);
}
.finding:hover::before {
    opacity: 1;
}
.finding-top,
.finding-body {
    position: relative;
    z-index: 1;
}

/* CTA dot-ripple â€” echoes the FinbardMark logo's dot-matrix. Rounded mint
   dots scale in from the button's center outward, staggered by distance
   from center. The `.cta-dots` layer + its dots are injected by finbard.js;
   the reveal + per-dot stagger live here. */
.btn-primary {
    position: relative;
    overflow: hidden;
    isolation: isolate;
}
.cta-dots {
    position: absolute;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    overflow: hidden;
    border-radius: inherit;
}
.cta-dots i {
    position: absolute;
    width: 3px;
    height: 3px;
    margin: -1.5px 0 0 -1.5px;
    border-radius: 50%;
    background: #fff;
    opacity: 0;
    transform: scale(0);
    transform-origin: center;
    transition:
        transform 0.55s var(--ease),
        opacity 0.4s var(--ease);
}
.btn-primary:hover .cta-dots i,
.btn-primary:focus-visible .cta-dots i,
.btn-primary.cta-showcase .cta-dots i {
    opacity: calc(var(--o, 0.7) * 0.42);
    transform: scale(1);
    transition-delay: calc(var(--d, 0) * 0.5s);
}
.btn-primary:active .cta-dots i {
    transition-delay: calc(var(--d, 0) * 0.22s);
}
@media (prefers-reduced-motion: reduce) {
    .cta-dots {
        display: none;
    }
}

/* PROOF â€” trust strip */
.trust {
    padding: 28px 0;
    border-bottom: 1px solid var(--line-soft);
}
.trust-in {
    display: flex;
    align-items: center;
    gap: 34px;
    flex-wrap: wrap;
    justify-content: center;
}
.trust .lbl {
    font-family: var(--font-mono);
    font-size: 11px;
    letter-spacing: 0.13em;
    text-transform: uppercase;
    color: var(--ink-label);
}
.trust .name {
    font-family: var(--font-serif);
    font-size: 19px;
    font-weight: 600;
    color: var(--ink-mu);
    letter-spacing: -0.1px;
    opacity: 0.62;
    transition:
        opacity var(--dur) var(--ease),
        color var(--dur) var(--ease);
}
.trust .name:hover {
    opacity: 1;
    color: var(--ink);
}

/* PROOF â€” outcome band */
.outcomes {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    border: 1px solid var(--line);
    border-radius: var(--r-xl);
    overflow: hidden;
    background: var(--surface);
    box-shadow: var(--shadow-sm);
}
.outcome {
    padding: 34px 32px;
    display: flex;
    flex-direction: column;
    gap: 14px;
    transition: background var(--dur) var(--ease);
}
.outcome:hover {
    background: var(--surface-2);
}
.outcome + .outcome {
    border-left: 1px solid var(--line);
}
.o-cat {
    display: flex;
    align-items: center;
    gap: 8px;
    font-family: var(--font-mono);
    font-size: 11px;
    font-weight: 500;
    letter-spacing: 0.13em;
    text-transform: uppercase;
    color: var(--teal-deep);
}
.o-num {
    font-family: var(--font-mono);
    font-size: 46px;
    font-weight: 600;
    color: var(--teal);
    letter-spacing: -1.5px;
    font-variant-numeric: tabular-nums;
    line-height: 1;
}
.outcome .lab {
    font-size: 14px;
    color: var(--ink-mu);
    line-height: 1.5;
}

/* ====================== MULTI-PAGE ADDITIONS ====================== */
/* by-Mesh lockup in nav + footer */
.bymesh {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-family: var(--font-mono);
    font-size: 11px;
    color: var(--ink-mu);
    white-space: nowrap;
}
.bymesh b {
    color: var(--ink);
    font-weight: 600;
}
.nav-logo .stack {
    display: flex;
    flex-direction: column;
    line-height: 1;
}
.nav-logo .stack .by {
    font-family: var(--font-mono);
    font-size: 10px;
    letter-spacing: 0.04em;
    color: var(--ink-mu);
    font-weight: 400;
    margin-top: 3px;
}
.nav-links a.active {
    color: var(--ink);
}
.nav-links a {
    position: relative;
}
.nav-links a.active::after {
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    bottom: -26px;
    height: 2px;
    background: var(--teal);
}

/* assurance band â€” the pricing/onboarding promises */
.assure {
    /* Ink. This strip now carries the dark moment directly under the hero that
       the removed statement band used to provide, so the top of the page still
       has a hard contrast step instead of running light all the way to the first
       warm section. */
    background: var(--band-ink);
    border-top: 0;
    border-bottom: 0;
}
.assure-in {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 0;
}
.assure-cell {
    display: flex;
    gap: 14px;
    align-items: flex-start;
    /* the cells' own padding is what gives the band its depth - it has no
       section padding of its own */
    padding: 56px 32px;
}
.assure-cell + .assure-cell {
    border-left: 1px solid var(--line-on-ink);
}
.assure-cell .ic {
    width: 38px;
    height: 38px;
    border-radius: var(--r-md);
    /* on ink: --teal is thin, --mint-accent reads at 8.4:1 */
    background: rgba(22, 201, 172, 0.12);
    color: var(--mint-accent);
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}
.assure-cell h4 {
    font-size: 16px;
    color: var(--on-dark);
    font-weight: 600;
    margin: 0;
}
.assure-cell p {
    font-size: 13.5px;
    color: var(--on-dark-mu);
    margin: 5px 0 0;
    line-height: 1.5;
}

/* credibility strip */
.cred {
    padding: 34px 0;
    border-top: 1px solid var(--rule-ink);
}
.cred-in {
    display: flex;
    align-items: center;
    gap: 18px;
    flex-wrap: wrap;
    justify-content: center;
}
.cred-badge {
    display: inline-flex;
    align-items: center;
    gap: 9px;
    font-family: var(--font-mono);
    font-size: 12px;
    color: var(--ink-body);
    border: 1px solid var(--line);
    border-radius: var(--r-pill);
    padding: 9px 15px;
    background: var(--surface);
    transition: all var(--dur) var(--ease);
}
.cred-badge:hover {
    border-color: var(--teal-line);
    color: var(--teal-deep);
}
.cred-badge .ic {
    color: var(--teal);
    display: flex;
}

/* page hero (interior pages) */
.phero {
    padding: 84px 0 44px;
    position: relative;
    overflow: hidden;
}
.phero::before {
    content: '';
    position: absolute;
    width: 560px;
    height: 560px;
    right: -160px;
    top: -200px;
    background: radial-gradient(circle, rgba(22, 201, 172, 0.09), transparent 62%);
    pointer-events: none;
    z-index: 0;
    animation: heroDrift 16s ease-in-out infinite;
}
.phero .wrap {
    position: relative;
    z-index: 1;
}
.phero h1 {
    font-family: var(--font-serif);
    font-weight: 500;
    font-size: 52px;
    letter-spacing: -0.5px;
    color: var(--ink);
    line-height: 1.15;
    margin: 0;
    max-width: 18ch;
}
.phero h1 em {
    font-style: italic;
    /* same accent as the home and early-access heroes - interior pages should not
       be the odd one out */
    color: var(--teal);
}
.phero .lead {
    font-size: 19px;
    color: var(--ink-mu);
    max-width: 50ch;
    margin: 22px 0 0;
    line-height: 1.55;
}

/* PRICING */
.price-wrap {
    display: grid;
    grid-template-columns: 1.15fr 0.85fr;
    gap: 24px;
    margin-top: 8px;
}
.price-card {
    border: 1px solid var(--line);
    border-radius: var(--r-xl);
    background: var(--surface);
    box-shadow: var(--shadow-md);
    overflow: hidden;
}
/* the recommended plan is bordered in solid ink rather than a teal hairline */
.price-card.feature {
    border: 2px solid var(--band-ink);
    box-shadow: var(--shadow-lg);
}
.price-head {
    padding: 30px 32px;
    border-bottom: 1px solid var(--line-soft);
}
.price-head .tier {
    font-family: var(--font-mono);
    font-size: 12px;
    letter-spacing: 0.13em;
    text-transform: uppercase;
    /* --teal is only 3.28:1 on white; the deep tone clears AA at this size */
    color: var(--teal-deep);
}
.price-head .amt {
    font-family: var(--font-mono);
    font-size: 46px;
    font-weight: 600;
    color: var(--ink);
    letter-spacing: -1.5px;
    margin-top: 14px;
    line-height: 1;
    display: flex;
    align-items: baseline;
    gap: 8px;
}
.price-head .amt .per {
    font-size: 15px;
    color: var(--ink-mu);
    font-weight: 400;
    letter-spacing: 0;
}
.price-head .sub {
    font-size: 14px;
    color: var(--ink-label);
    margin-top: 12px;
    line-height: 1.5;
}
.price-body {
    padding: 26px 32px;
}
.price-row {
    display: flex;
    gap: 11px;
    align-items: flex-start;
    padding: 9px 0;
    font-size: 14.5px;
    color: var(--ink-body);
}
.price-row .ic {
    color: var(--teal);
    flex-shrink: 0;
    margin-top: 2px;
}
.price-foot {
    padding: 0 32px 30px;
}
.meter-card {
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    /* white, so it reads as a card on the ink band and its labels clear AA */
    background: var(--surface);
    padding: 26px 28px;
}
.meter-card h4 {
    font-size: 16px;
    color: var(--ink);
    font-weight: 600;
    margin: 0 0 4px;
}
.meter-card .msub {
    font-size: 13.5px;
    color: var(--ink-mu);
    margin-bottom: 20px;
    line-height: 1.5;
}
.meter-readout {
    font-family: var(--font-mono);
    font-size: 38px;
    font-weight: 600;
    color: var(--teal-deep);
    letter-spacing: -1px;
    font-variant-numeric: tabular-nums;
}
.meter-readout .u {
    font-size: 14px;
    color: var(--ink-mu);
    font-weight: 400;
    margin-left: 6px;
}
.slider {
    -webkit-appearance: none;
    appearance: none;
    width: 100%;
    height: 5px;
    border-radius: 3px;
    background: var(--surface-3);
    outline: none;
    margin: 18px 0 8px;
}
.slider::-webkit-slider-thumb {
    -webkit-appearance: none;
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background: var(--mint);
    border: 2px solid #fff;
    box-shadow:
        0 2px 8px -2px var(--mint-glow),
        var(--glow-mint-sm);
    cursor: pointer;
}
.slider::-moz-range-thumb {
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background: var(--mint);
    border: 2px solid #fff;
    cursor: pointer;
}
/* only visible when the volume slider is at its ceiling */
.est-over {
    font-family: var(--font-mono);
    font-size: 12px;
    line-height: 1.5;
    color: var(--ink-label);
    margin: 14px 0 0;
}
.meter-scale {
    display: flex;
    justify-content: space-between;
    font-family: var(--font-mono);
    font-size: 11px;
    color: var(--ink-label);
}
/* segmented control (scan depth) */
.seg {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 4px;
    background: var(--surface-3);
    border-radius: var(--r-sm);
    padding: 4px;
}
.seg-btn {
    font-family: var(--font-sans);
    font-size: 12.5px;
    font-weight: 600;
    color: var(--ink-mu);
    background: transparent;
    border: 0;
    border-radius: 5px;
    padding: 9px 6px;
    cursor: pointer;
    transition: all var(--dur) var(--ease);
}
.seg-btn:hover {
    color: var(--ink);
}
.seg-btn.on {
    background: var(--surface);
    color: var(--teal-deep);
    box-shadow: var(--shadow-sm);
}
/* estimator fields */
.est-field {
    margin-top: 18px;
}
.est-row {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    font-size: 13px;
    color: var(--ink-mu);
    margin-bottom: 2px;
}
.est-row b {
    font-family: var(--font-mono);
    color: var(--ink);
    font-size: 13px;
}

/* FAQ */
.faq {
    border-top: 1px solid var(--line);
    margin-top: 8px;
}
.faq-item {
    border-bottom: 1px solid var(--line);
    padding: 22px 4px;
    cursor: pointer;
}
.faq-q {
    display: flex;
    align-items: center;
    gap: 14px;
    font-size: 17px;
    color: var(--ink);
    font-weight: 600;
    /* body sans, not the display face - a question sits at body scale and reads
       as a sentence, not as a section title */
    font-family: var(--font-sans);
}
.faq-q .ic {
    margin-left: auto;
    color: var(--teal);
    transition: transform var(--dur) var(--ease);
}
.faq-item.open .faq-q .ic {
    transform: rotate(45deg);
}
.faq-a {
    font-size: 15px;
    color: var(--ink-mu);
    line-height: 1.6;
    max-height: 0;
    overflow: hidden;
    transition:
        max-height 0.35s var(--ease),
        margin 0.35s var(--ease),
        opacity 0.35s var(--ease);
    opacity: 0;
}
.faq-item.open .faq-a {
    /* headroom for the longest answer once it wraps on a narrow viewport â€”
       the cap only exists to animate the reveal, so it must never clip */
    max-height: 460px;
    margin-top: 12px;
    opacity: 1;
}

/* PLATFORM steps */
.steps {
    display: flex;
    flex-direction: column;
    margin-top: 8px;
}
.steps .step {
    display: grid;
    grid-template-columns: 64px 1fr;
    gap: 26px;
    padding: 30px 0;
    border-bottom: 1px solid var(--line);
    position: relative;
}
.steps .step:last-child {
    border-bottom: 0;
}
/* solid ink numeral: the strongest black moment in the light sections */
.step-n {
    font-family: var(--font-mono);
    font-size: 14px;
    font-weight: 500;
    color: var(--paper);
    border: 0;
    border-radius: var(--r-md);
    width: 48px;
    height: 48px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--band-ink);
}
.steps .step h3 {
    font-family: var(--font-serif);
    font-size: 24px;
    font-weight: 600;
    color: var(--ink);
    margin: 0;
}
.steps .step p {
    font-size: 16px;
    color: var(--ink-mu);
    margin: 8px 0 0;
    line-height: 1.55;
    max-width: 60ch;
}
.steps .step .meta {
    font-family: var(--font-mono);
    font-size: 12px;
    color: var(--teal-deep);
    margin-top: 12px;
    display: inline-flex;
    align-items: center;
    gap: 8px;
}

/* connectors grid */
.conns {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 12px;
    margin-top: 8px;
}
.conn {
    border: 1px solid var(--line);
    border-radius: var(--r-md);
    background: var(--surface);
    padding: 18px 16px;
    display: flex;
    align-items: center;
    gap: 11px;
    transition: all var(--dur) var(--ease);
}
.conn:hover {
    border-color: var(--teal-line);
    transform: translateY(-2px);
    box-shadow: var(--shadow-sm);
}
.conn .dot {
    width: 9px;
    height: 9px;
    border-radius: 2px;
    flex-shrink: 0;
}
.conn .nm {
    font-size: 14px;
    color: var(--ink);
    font-weight: 500;
}
.conn .st {
    font-family: var(--font-mono);
    font-size: 11px;
    color: var(--ink-label);
    margin-left: auto;
}

/* security cards */
.sec-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 14px;
    margin-top: 8px;
}
/* five cards without a hole in the last row: 3 up, then 2 wide */
.sec-grid.g5 {
    grid-template-columns: repeat(6, 1fr);
}
.sec-grid.g5 > * {
    grid-column: span 2;
}
.sec-grid.g5 > *:nth-child(4),
.sec-grid.g5 > *:nth-child(5) {
    grid-column: span 3;
}
.sec-card {
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    background: var(--surface);
    padding: 26px;
    box-shadow: var(--shadow-sm);
    transition: all var(--dur) var(--ease);
}
.sec-card:hover {
    transform: translateY(-3px);
    box-shadow: var(--shadow-md);
    border-color: var(--teal-line);
}
.sec-card .ic {
    width: 42px;
    height: 42px;
    border-radius: var(--r-md);
    background: var(--teal-tint);
    color: var(--teal);
    display: flex;
    align-items: center;
    justify-content: center;
    margin-bottom: 18px;
}
.sec-card h4 {
    font-size: 17px;
    color: var(--ink);
    font-weight: 600;
    margin: 0;
}
.sec-card p {
    font-size: 14px;
    color: var(--ink-mu);
    margin: 8px 0 0;
    line-height: 1.55;
}

/* mesh band â€” the "by Mesh" trust moment */
.meshband {
    /* same ink as .sec-ink so the dark bands read as one system, not two darks */
    background: var(--band-ink);
    color: var(--on-dark);
    padding: 64px 0;
}
.meshband .wrap {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 48px;
    align-items: center;
}
.meshband .eyebrow {
    color: var(--mint-accent);
}
.meshband h2 {
    font-family: var(--font-serif);
    font-weight: 500;
    font-size: 34px;
    letter-spacing: -0.3px;
    color: var(--on-dark);
    line-height: 1.15;
    margin: 0;
}
.meshband p {
    font-size: 16px;
    color: var(--on-dark-mu);
    line-height: 1.6;
    margin: 16px 0 0;
}
.meshband .lock {
    display: flex;
    align-items: center;
    gap: 16px;
    justify-content: center;
    flex-wrap: wrap;
}
.meshband .lock-side {
    display: flex;
    align-items: center;
    gap: 12px;
}
.meshband .lock .x {
    color: var(--on-dark-mu);
    font-size: 22px;
}
.meshband .lock .nm {
    font-family: var(--font-serif);
    font-size: 30px;
    font-weight: 600;
    color: var(--on-dark);
    letter-spacing: -0.2px;
}
/* Sized off the wordmark's cap height, not the file box: the "M" glyph runs
   taller than the letters, so matching image height to the Finbard name would
   read as a size mismatch. Width is left to the intrinsic ratio. */
.meshband .lock-mesh {
    height: 30px;
    width: auto;
    max-width: 100%;
    display: block;
}

@media (max-width: 980px) {
    .assure-in {
        grid-template-columns: 1fr;
    }
    /* the deeper padding is what gives the band its weight beside the three
       cells; stacked, it is paid three times over and the band runs to 618px on
       a phone, so this one keeps the original depth */
    .assure-cell {
        padding: 42px 32px;
    }
    .assure-cell + .assure-cell {
        border-left: 0;
        border-top: 1px solid var(--line);
    }
    .price-wrap {
        grid-template-columns: 1fr;
    }
    .conns {
        grid-template-columns: 1fr 1fr;
    }
    .sec-grid,
    .sec-grid.g5 {
        grid-template-columns: 1fr;
    }
    .sec-grid.g5 > *,
    .sec-grid.g5 > *:nth-child(4),
    .sec-grid.g5 > *:nth-child(5) {
        grid-column: auto;
    }
    .phero h1 {
        font-size: 40px;
    }
    .meshband .wrap {
        grid-template-columns: 1fr;
        gap: 28px;
    }
    .step {
        grid-template-columns: 48px 1fr;
        gap: 18px;
    }
}

/* ====================== LEGAL + ERROR PAGES ====================== */
.legal {
    max-width: 760px;
    margin: 0 auto;
    padding: 0 40px 96px;
}
.legal .updated {
    font-family: var(--font-mono);
    font-size: 13px;
    color: var(--ink-label);
    margin-top: 10px;
}
.legal section {
    margin-top: 38px;
}
.legal section h2 {
    font-family: var(--font-serif);
    font-weight: 500;
    font-size: 24px;
    letter-spacing: -0.2px;
    color: var(--ink);
    margin: 0;
}
.legal p {
    font-size: 16px;
    color: var(--ink-body);
    line-height: 1.7;
    margin-top: 13px;
}
.legal ul {
    margin: 13px 0 0;
    padding-left: 20px;
    color: var(--ink-body);
    line-height: 1.7;
}
.legal li {
    margin-top: 8px;
}
.legal a {
    color: var(--teal-deep);
}
.legal a:hover {
    color: var(--teal-strong);
}

.errpage {
    text-align: center;
    padding: 120px 0 140px;
}
.errpage .code {
    font-family: var(--font-mono);
    font-size: 88px;
    font-weight: 600;
    color: var(--teal-deep);
    letter-spacing: -3px;
    line-height: 1;
}
.errpage h1 {
    font-family: var(--font-serif);
    font-weight: 500;
    font-size: 34px;
    letter-spacing: -0.3px;
    color: var(--ink);
    margin: 18px 0 0;
}
.errpage p {
    font-size: 18px;
    color: var(--ink-mu);
    margin: 16px 0 0;
}
.errpage .home {
    margin-top: 30px;
}

/* ask demo â€” evidence rows */
.ev-row {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 10px;
    padding: 13px 0;
    border-bottom: 1px solid var(--line-soft);
}
.ev-nm {
    color: var(--ink);
    font-weight: 500;
    font-size: 14px;
}
.ev-id {
    font-family: var(--font-mono);
    font-size: 12px;
    color: var(--ink-label);
}
.ev-val {
    font-family: var(--font-mono);
    font-size: 14px;
    color: var(--ink);
    align-self: center;
    font-variant-numeric: tabular-nums;
}
.ev-val.flag {
    color: var(--critical);
}

/* ====================== HOW-IT-WORKS PIPELINE ====================== */
.pipeline-wrap {
    position: relative;
    margin-top: 44px;
}
.pipeline {
    position: relative;
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: 16px;
}
.pstage {
    position: relative;
    z-index: 1;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-sm);
    padding: 20px 18px;
    transition:
        transform 0.4s var(--ease),
        box-shadow 0.4s var(--ease),
        border-color 0.4s var(--ease);
}
.pstage > * {
    position: relative;
    transition: opacity 0.4s var(--ease);
}
/* Dimming is applied ONLY while JS drives the walk â€” never pre-hide (no-JS shows all lit).

   It dims the card's CONTENTS, not the card. Fading the whole .pstage made it
   translucent, so the connecting rail - which runs through every card's centre
   and is only ever meant to show in the 16px gaps - bled through the unvisited
   cards and read as a line drawn on top of them. Keeping the card's own
   background and border opaque keeps the rail behind the cards at all times. */
.js-walk .pstage:not(.is-active):not(.is-done) > * {
    opacity: 0.5;
}
.pstage.is-active {
    transform: translateY(-4px);
    box-shadow: var(--shadow-md), var(--glow-mint);
    border-color: var(--teal-line);
}
.pstage-ic {
    width: 40px;
    height: 40px;
    border-radius: var(--r-md);
    background: var(--teal-tint);
    color: var(--teal-deep);
    display: flex;
    align-items: center;
    justify-content: center;
    margin-bottom: 14px;
}
.pstage-k {
    font-family: var(--font-mono);
    font-size: 11px;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--ink-mu);
}
.pstage h4 {
    font-size: 15px;
    color: var(--ink);
    font-weight: 600;
    margin: 7px 0 0;
    line-height: 1.3;
}
.pstage p {
    font-size: 13px;
    color: var(--ink-mu);
    line-height: 1.5;
    margin: 9px 0 0;
}
.pchecks {
    list-style: none;
    padding: 0;
    margin: 11px 0 0;
    display: flex;
    flex-direction: column;
    gap: 7px;
}
.pchecks li {
    font-family: var(--font-mono);
    font-size: 12px;
    color: var(--ink-mu);
    display: flex;
    align-items: center;
    gap: 8px;
    transition: color 0.35s var(--ease);
}
.pchecks li::before {
    content: '';
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--line-strong);
    flex-shrink: 0;
    transition:
        background 0.35s var(--ease),
        box-shadow 0.35s var(--ease);
}
.pchecks li.lit {
    color: var(--ink);
}
.pchecks li.lit::before {
    background: var(--positive);
    box-shadow: 0 0 8px -1px var(--positive);
}
.pstage-out .poutcome {
    margin-top: 4px;
}
.pstage-out .poutcome p {
    margin-top: 9px;
}
.poutcome[hidden] {
    display: none;
}
.pipe-rail {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    z-index: 0;
    pointer-events: none;
    overflow: visible;
}
.pipe-rail [data-pipe-seg] {
    fill: none;
    stroke: var(--teal-line);
    stroke-width: 2;
}
.pipe-rail [data-pipe-token] {
    fill: var(--mint-accent);
    filter: drop-shadow(0 0 5px rgba(22, 201, 172, 0.85));
    opacity: 0;
}

/* ====================== INVESTIGATION â€” connect the dots ====================== */
.inv {
    position: relative;
    margin-top: 44px;
    display: grid;
    grid-template-columns: 0.82fr 1.18fr;
    gap: 60px;
    align-items: center;
}
.inv-signals {
    position: relative;
    z-index: 1;
    display: flex;
    flex-direction: column;
    gap: 14px;
}
.signal {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r-md);
    box-shadow: var(--shadow-sm);
    padding: 16px 18px;
    transition:
        transform 0.4s var(--ease),
        opacity 0.4s var(--ease),
        border-color 0.4s var(--ease),
        box-shadow 0.4s var(--ease);
}
.js-walk .signal:not(.is-fired) {
    opacity: 0.55;
}
.signal.is-fired {
    opacity: 1;
    transform: translateY(-2px);
    border-color: var(--teal-line);
    box-shadow: var(--shadow-md);
}
.signal-k {
    font-family: var(--font-mono);
    font-size: 11px;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--teal-deep);
    display: flex;
    align-items: center;
    gap: 7px;
}
.signal p {
    font-size: 13.5px;
    color: var(--ink-body);
    line-height: 1.5;
    margin: 9px 0 0;
}
.signal .sev {
    display: inline-block;
    margin-top: 12px;
    font-family: var(--font-mono);
    font-size: 11px;
    font-weight: 600;
    padding: 3px 10px;
    border-radius: var(--r-pill);
    color: var(--attention);
    background: var(--attention-tint);
    border: 1px solid var(--attention-line);
}
.inv-rail {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    z-index: 0;
    pointer-events: none;
    overflow: visible;
}
.inv-rail [data-inv-seg] {
    fill: none;
    /* --teal-line is 0.32 alpha, which composites to roughly #14312b on the ink
       band - a rail you have to be told is there. The decorative mint reads
       against ink, which is what it is for. */
    stroke: var(--mint-accent);
    stroke-opacity: 0.5;
    stroke-width: 2;
}
/* the apex of the stacked fan-in: lights as the third stream lands, just before
   the card pulses. Positioned by finbard.js; only drawn in the stacked layout. */
.inv-rail [data-inv-node] {
    fill: var(--mint-accent);
    filter: drop-shadow(0 0 7px rgba(22, 201, 172, 0.9));
    opacity: 0;
    transition: opacity 0.45s var(--ease);
}
.inv-rail.is-merged [data-inv-node] {
    opacity: 1;
}
@media (min-width: 981px) {
    .inv-rail [data-inv-node] {
        display: none;
    }
}
.invcard {
    position: relative;
    z-index: 1;
    /* .finding already transitions transform + box-shadow; this rule is later in
       the file at equal specificity, so it has to restate them or the wake-up
       fade would be the only thing eased. */
    transition:
        opacity 0.5s var(--ease),
        box-shadow 0.5s var(--ease);
}
/* The investigation IS the payoff, so it must not read as already-true while the
   three signals are still arriving - otherwise the section shows its answer
   before it shows its work. Held dormant under .js-walk (set by finbard.js, so
   the card stays fully lit with JS off) until the third stream lands and
   setupInvestigation promotes it to .is-correlated.

   Deliberately opacity-only: the rail's endpoints are measured from the card's
   bounding box, and a translate or scale here would move them out from under the
   streams that already landed. */
.js-walk .invcard:not(.is-correlated) {
    opacity: 0.5;
    box-shadow: var(--shadow-sm);
}
/* the mint halo and the "correlated" heartbeat are the card's two loudest claims
   on the eye - both wait for the signals */
.js-walk .invcard:not(.is-correlated)::before {
    opacity: 0;
}
.js-walk .invcard:not(.is-correlated) .live .d {
    animation: none;
    box-shadow: none;
}
.invcard.is-correlating {
    animation: invPulse 1.1s var(--ease);
}
@keyframes invPulse {
    0% {
        box-shadow: var(--shadow-md);
    }
    45% {
        box-shadow:
            var(--shadow-lg),
            0 0 0 3px var(--mint-accent-soft);
    }
    100% {
        box-shadow: var(--shadow-md);
    }
}

@media (max-width: 980px) {
    .pipeline {
        grid-template-columns: 1fr;
    }
    .inv {
        grid-template-columns: 1fr;
        /* the row gap IS the funnel's band: the three streams fan down through it
           from the foot of the signals into the card's top edge */
        gap: 64px;
    }
}

@media (prefers-reduced-motion: reduce) {
    .pstage,
    .signal,
    .invcard {
        opacity: 1 !important;
        transform: none !important;
    }
    .pipe-rail [data-pipe-token] {
        display: none;
    }
    /* the apex node stays - it does not travel, it just marks where the streams
       meet, which is the point of the stacked layout. Only the fade goes. */
    .inv-rail [data-inv-node] {
        transition: none;
    }
    .invcard.is-correlating {
        animation: none;
    }
}

/* ====================== SHARED TEXT UTILITIES ======================
   These were repeated inline style attributes. Promoted to classes so a section
   can invert to a dark surface â€” an inline style outranks any class, so themable
   type cannot live in a style attribute. */
/* visually hidden but still announced - the accessible name of an anomaly dot,
   which is otherwise a bare coloured circle */
.vh {
    position: absolute;
    width: 1px;
    height: 1px;
    clip-path: inset(50%);
    overflow: hidden;
    white-space: nowrap;
}
/* Display face is for titles only. A pull quote is still section prose, so it
   takes the body sans at a larger size rather than MADE Mirage. */
.pull {
    font-family: var(--font-sans);
    font-weight: 500;
    font-size: 23px;
    line-height: 1.45;
    letter-spacing: -0.2px;
    color: var(--ink);
    max-width: 38ch;
    margin: 30px 0 0;
}
.pull-sm {
    font-size: 21px;
    line-height: 1.5;
    letter-spacing: -0.2px;
    max-width: 44ch;
    margin: 26px 0 0;
}
.callout {
    margin-top: 34px;
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    background: var(--surface);
    padding: 24px 26px;
}
.callout p {
    font-size: 15px;
    color: var(--ink-body);
    line-height: 1.6;
    margin: 10px 0 0;
}
.mono-note {
    font-family: var(--font-mono);
    font-size: 12px;
    color: var(--ink-label);
    letter-spacing: 0.02em;
}
.mono-note-c {
    text-align: center;
    margin-top: 20px;
}
.panel-k {
    font-family: var(--font-mono);
    font-size: 11px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--ink-label);
    margin-bottom: 16px;
}

/* inline ink highlight: a solid black stamp on a single phrase. Used sparingly â€”
   one per section at most, or it stops being emphasis. */
.mark {
    background: var(--band-ink);
    color: var(--paper);
    padding: 0.06em 0.3em;
    border-radius: 3px;
    box-decoration-break: clone;
    -webkit-box-decoration-break: clone;
}
.sec-ink .mark {
    background: var(--mint-accent);
    color: var(--band-ink);
}
/* amber eyebrow, for the sections about cost and human effort */
.eyebrow.warm {
    color: var(--amber-deep);
}
.eyebrow.warm .tick {
    /* --amber is 2.64:1 on paper, under even the 3:1 graphical threshold */
    background: var(--amber-deep);
}

/* ====================== EARLY ACCESS ====================== */
.ea {
    position: relative;
    overflow: hidden;
    padding: 62px 0 88px;
    border-bottom: 1px solid var(--line);
}
.ea::before {
    content: '';
    position: absolute;
    inset: 0;
    background:
        radial-gradient(900px 420px at 50% -12%, var(--teal-tint), transparent 65%),
        linear-gradient(var(--paper), var(--paper));
    z-index: -2;
}
.ea-dotfield {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    z-index: -1;
    opacity: 0.5;
    pointer-events: none;
}
.ea .wrap {
    position: relative;
}
.ea-grid {
    display: grid;
    grid-template-columns: 1.05fr 0.95fr;
    gap: 56px;
    align-items: start;
}
.ea h1 {
    font-family: var(--font-serif);
    font-weight: 500;
    font-size: 54px;
    line-height: 1.15;
    letter-spacing: -0.5px;
    color: var(--ink);
    margin: 0;
}
.ea h1 em {
    font-style: italic;
    color: var(--teal);
}
.ea-sub {
    font-size: 18px;
    line-height: 1.6;
    color: var(--ink-mu);
    max-width: 46ch;
    margin: 20px 0 0;
}

/* the 100-transaction grid â€” the page's argument, in the brand's dot language */
.txblock {
    margin: 38px 0 0;
    padding: 0;
}
.txblock figcaption {
    display: block;
    margin-bottom: 18px;
}
.txcap-k {
    display: block;
    font-family: var(--font-mono);
    font-size: 11px;
    letter-spacing: 0.13em;
    text-transform: uppercase;
    color: var(--teal-deep);
    margin-bottom: 8px;
}
/* a figure caption is prose, so body sans - the mono kicker above it carries
   the label role and MADE Mirage stays on titles */
.txcap {
    display: block;
    font-family: var(--font-sans);
    font-weight: 500;
    font-size: 18px;
    line-height: 1.55;
    letter-spacing: -0.1px;
    color: var(--ink);
    max-width: 42ch;
}
.txgrid {
    display: grid;
    grid-template-columns: repeat(10, 1fr);
    gap: 8px;
    max-width: 340px;
}
.tx {
    width: 100%;
    aspect-ratio: 1;
    border-radius: 50%;
    background: var(--line-strong);
    opacity: 0.45;
    transition:
        transform 0.34s var(--ease),
        opacity 0.34s var(--ease),
        background 0.34s var(--ease),
        box-shadow 0.34s var(--ease);
}
.tx-seen {
    background: var(--teal);
    opacity: 1;
}
.tx-flag {
    background: var(--critical);
    opacity: 1;
    box-shadow: 0 0 0 3px var(--critical-tint);
}
.tx-flag.tx-warn {
    background: var(--attention);
    box-shadow: 0 0 0 3px var(--attention-tint);
}
/* JS pre-state: unread, then swept in. Never hidden â€” only dimmed. */
.js-tx .tx {
    transform: scale(0.55);
    opacity: 0.2;
    background: var(--line-strong);
    box-shadow: none;
}
.js-tx .tx.is-read {
    transform: scale(1);
    opacity: 0.45;
}
.js-tx .tx.is-seen {
    background: var(--teal);
    opacity: 1;
}
.js-tx .tx.is-hit {
    background: var(--critical);
    opacity: 1;
    box-shadow: 0 0 0 3px var(--critical-tint);
    animation: txpop 0.5s var(--ease);
}
.js-tx .tx.is-hit.is-warn {
    background: var(--attention);
    box-shadow: 0 0 0 3px var(--attention-tint);
}
.tx.is-lit {
    transform: scale(1.55);
    z-index: 1;
}
@keyframes txpop {
    0% {
        transform: scale(1);
    }
    55% {
        transform: scale(1.9);
    }
    100% {
        transform: scale(1);
    }
}
.txlegend {
    display: flex;
    flex-wrap: wrap;
    gap: 18px;
    margin-top: 18px;
    font-family: var(--font-mono);
    font-size: 11.5px;
    color: var(--ink-mu);
}
.txlg {
    display: inline-flex;
    align-items: center;
    gap: 7px;
}
.txlg .tx {
    width: 9px;
    aspect-ratio: 1;
    flex-shrink: 0;
}
/* the form card */
.ea-formwrap {
    position: sticky;
    top: 92px;
}
.ea-card {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-md);
    padding: 28px 28px 26px;
}
.ea-card-head h2 {
    font-family: var(--font-serif);
    font-weight: 500;
    font-size: 26px;
    letter-spacing: -0.2px;
    color: var(--ink);
    margin: 0;
}
.ea-card-head p {
    font-family: var(--font-mono);
    font-size: 12px;
    color: var(--ink-mu);
    margin: 9px 0 0;
}
.ea-form {
    margin-top: 22px;
}
.ea-field + .ea-field,
.ea-row + .ea-field,
.ea-field + .ea-row {
    margin-top: 15px;
}
.ea-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 12px;
}
.ea-field label {
    display: block;
    font-size: 12.5px;
    font-weight: 600;
    color: var(--ink-body);
    margin-bottom: 7px;
}
.ea-field label .opt {
    font-weight: 400;
    color: var(--ink-label);
}

.ea-err {
    font-size: 12.5px;
    line-height: 1.45;
    color: var(--critical);
    margin: 7px 0 0;
}
/* the control carrying an error reads as invalid, not just the text below it */
.ea-field:has(.ea-err) input,
.ea-field:has(.ea-err) textarea,
.ea-field:has(.ea-err) .ms-toggle {
    border-color: var(--critical);
}

/* Honeypot: off-screen rather than display:none or hidden, both of which some
   bots skip. tabindex="-1" keeps it out of the keyboard path for real users. */
.ea-hp {
    position: absolute;
    left: -9999px;
    width: 1px;
    height: 1px;
    overflow: hidden;
}

/* ---------- multi-select dropdown ----------
   .ms-native is the real <select multiple>, kept in the DOM so it still submits.
   Hidden with clip rather than display:none, because a display:none control is
   dropped from form submission in some engines. */
.ms {
    position: relative;
}
.ms-native {
    position: absolute;
    width: 1px;
    height: 1px;
    clip-path: inset(50%);
    overflow: hidden;
    pointer-events: none;
}
.ms-toggle {
    width: 100%;
    display: flex;
    align-items: center;
    gap: 10px;
    font-family: var(--font-sans);
    font-size: 14.5px;
    text-align: left;
    color: var(--ink);
    background: var(--paper);
    border: 1px solid var(--line-strong);
    border-radius: var(--r-sm);
    /* min-height pins this to the same 41px as the sibling inputs, so the control
       does not jump taller once pills appear */
    min-height: 41px;
    padding: 5px 12px;
    cursor: pointer;
    transition:
        border-color var(--dur) var(--ease),
        box-shadow var(--dur) var(--ease);
}
.ms-toggle:hover {
    border-color: var(--ink-mu);
}
.ms-toggle:focus-visible,
.ms.is-open .ms-toggle {
    outline: none;
    border-color: var(--teal);
    box-shadow: 0 0 0 3px var(--teal-tint);
}
.ms-label {
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 5px;
    overflow: hidden;
}
.ms-label.is-empty {
    color: var(--ink-label);
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* the chosen systems, named, rather than an uninformative count */
.ms-pill {
    flex-shrink: 0;
    max-width: 12ch;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 12px;
    line-height: 1;
    padding: 4px 9px;
    border-radius: var(--r-pill);
    background: var(--band-ink);
    color: var(--paper);
}
.ms-more {
    flex-shrink: 0;
    font-family: var(--font-mono);
    font-size: 11.5px;
    color: var(--ink-label);
}
.ms-caret {
    width: 12px;
    height: 12px;
    flex-shrink: 0;
    color: var(--ink-mu);
    transition: transform var(--dur) var(--ease);
}
.ms.is-open .ms-caret {
    transform: rotate(180deg);
}
.ms-panel {
    position: absolute;
    top: calc(100% + 6px);
    left: 0;
    right: 0;
    z-index: 20;
    max-height: 264px;
    overflow-y: auto;
    background: var(--surface);
    border: 1px solid var(--line-strong);
    border-radius: var(--r-md);
    box-shadow: var(--shadow-md);
    padding: 6px;
}
.ms-group-k {
    display: flex;
    align-items: center;
    gap: 9px;
    font-family: var(--font-mono);
    font-size: 10px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--ink-label);
    padding: 12px 8px 7px;
}
/* hairline trailing the group name, so the two groups read as sections */
.ms-group-k::after {
    content: '';
    flex: 1;
    height: 1px;
    background: var(--line);
}
/* NB: these are scoped under .ms deliberately. A bare `.ms-row` (0,1,0) loses to
   the generic `.ea-field label` (0,1,1), which forces display:block and drops the
   text onto its own line below the checkbox. Same story for the input, which
   `.ea-field input` otherwise stretches to 100% width. */
.ms .ms-row {
    position: relative;
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 14px;
    font-weight: 400;
    color: var(--ink-body);
    margin: 0;
    padding: 8px;
    border-radius: var(--r-sm);
    cursor: pointer;
    transition: background var(--dur) var(--ease);
}
.ms .ms-row:hover {
    background: var(--band-warm);
}
/* the native box is the only control that cannot be styled to match, so it is
   hidden (still focusable) and .ms-box is drawn in its place */
.ms .ms-row input {
    position: absolute;
    opacity: 0;
    width: 1px;
    height: 1px;
    min-height: 0;
    padding: 0;
    border: 0;
    margin: 0;
    pointer-events: none;
}
.ms-box {
    flex-shrink: 0;
    width: 17px;
    height: 17px;
    border: 1.5px solid var(--line-strong);
    border-radius: 5px;
    background: var(--surface);
    display: flex;
    align-items: center;
    justify-content: center;
    color: transparent;
    transition:
        background var(--dur) var(--ease),
        border-color var(--dur) var(--ease),
        color var(--dur) var(--ease);
}
.ms-box svg {
    width: 12px;
    height: 12px;
}
.ms-row:hover .ms-box {
    border-color: var(--ink-mu);
}
.ms-row:has(input:checked) .ms-box {
    background: var(--band-ink);
    border-color: var(--band-ink);
    color: var(--paper);
}
.ms-row:has(input:checked) {
    color: var(--ink);
}
.ms-row:has(input:focus-visible) {
    outline: 2px solid var(--teal);
    outline-offset: -1px;
}
.ms-txt {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.ea-field input,
.ea-field select,
.ea-field textarea {
    width: 100%;
    font-family: var(--font-sans);
    font-size: 14.5px;
    color: var(--ink);
    background: var(--paper);
    border: 1px solid var(--line-strong);
    border-radius: var(--r-sm);
    padding: 11px 12px;
    transition:
        border-color var(--dur) var(--ease),
        box-shadow var(--dur) var(--ease);
}
.ea-field textarea {
    resize: vertical;
    line-height: 1.5;
}
.ea-field input::placeholder,
.ea-field textarea::placeholder {
    color: var(--ink-faint);
}
.ea-field input:focus,
.ea-field select:focus,
.ea-field textarea:focus {
    outline: none;
    border-color: var(--teal-deep);
    box-shadow: 0 0 0 3px var(--teal-tint);
}
.ea-field input:user-invalid {
    border-color: var(--critical);
}
.ea-submit {
    width: 100%;
    justify-content: center;
    margin-top: 20px;
}
.ea-fine {
    font-size: 12px;
    line-height: 1.55;
    color: var(--ink-mu);
    margin: 14px 0 0;
}
.ea-done {
    text-align: center;
    padding: 12px 0 6px;
}
.ea-done-mark {
    width: 46px;
    height: 46px;
    margin: 0 auto 16px;
    border-radius: 50%;
    background: var(--teal-tint);
    color: var(--teal-deep);
    display: flex;
    align-items: center;
    justify-content: center;
}
.ea-done h3 {
    font-family: var(--font-serif);
    font-weight: 500;
    font-size: 22px;
    letter-spacing: -0.2px;
    color: var(--ink);
    margin: 0;
}
.ea-done p {
    font-size: 14.5px;
    line-height: 1.6;
    color: var(--ink-mu);
    margin: 12px 0 0;
}
.ea-assure {
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
    justify-content: center;
    margin-top: 18px;
    font-family: var(--font-mono);
    font-size: 11.5px;
    color: var(--ink-label);
}
.ea-assure span {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

/* closing line */
.ea-close {
    text-align: center;
}
.ea-close p {
    font-family: var(--font-serif);
    font-weight: 500;
    font-size: 34px;
    line-height: 1.15;
    letter-spacing: -0.3px;
    color: var(--ink);
    margin: 0;
}
.ea-close p.em {
    color: var(--teal);
    font-style: italic;
}
.ea-close .btn {
    margin-top: 28px;
}

@media (max-width: 980px) {
    .ea-grid {
        grid-template-columns: 1fr;
        gap: 40px;
    }
    .ea-formwrap {
        position: static;
    }
    .ea h1 {
        font-size: 38px;
    }
    .ea-close p {
        font-size: 26px;
    }
    .txgrid {
        max-width: 100%;
    }
}
@media (max-width: 560px) {
    /* two selects side by side truncate their option text on a phone */
    .ea-row {
        grid-template-columns: 1fr;
        gap: 15px;
    }
    .ea h1 {
        font-size: 33px;
    }
    /* An integration row is a name plus a right-aligned status, about 180px of
       min-content that will not shrink. Two of them per row put the page into a
       horizontal scroll on a phone - which also stretched the fixed-position nav
       drawer past the viewport, since an overflowing document widens the initial
       containing block. */
    .conns {
        grid-template-columns: 1fr;
    }
    /* The lockup is about 345px of min-content and stops fitting on one line at
       roughly a 425px viewport. Left to wrap it breaks after the ×, stranding
       the separator at the end of the Finbard row instead of sitting between
       the two brands. Stack it instead, so the × still reads as the join. */
    .meshband .lock {
        flex-direction: column;
        gap: 14px;
    }
}
@media (prefers-reduced-motion: reduce) {
    .js-tx .tx,
    .js-tx .tx.is-read,
    .js-tx .tx.is-seen,
    .js-tx .tx.is-hit {
        transform: none;
        animation: none;
    }
    .tx.is-lit {
        transform: none;
        outline: 2px solid var(--ink);
        outline-offset: 2px;
    }
}
