/* ============================================================================
   BALLY DOES AI — PREMIUM SHARED DESIGN SYSTEM  ·  premium-teal.css
   ----------------------------------------------------------------------------
   The single reusable stylesheet for every premium page. Locked to the
   Warm-Dark Teal system (TEAL-PALETTE-LOCKED.md · Set A default) with the
   Editorial Cream + Teal system (Set B) available as a `.band--cream` context.

   USAGE (per page):
     <link rel="preconnect" href="https://fonts.googleapis.com">
     <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
     <link rel="stylesheet" href="/assets/premium/premium-teal.css">
     <script src="/assets/premium/premium-motion.js" defer></script>
   Then compose from the components below. Nav + footer markup lives in
   /assets/premium/_nav-footer.html (paste-in snippet).

   RULES (do not fight these):
   · Components read tokens only — never raw hex in page CSS.
   · Deep teal fills large surfaces; --brand for CTAs/icons/keylines;
     --glow ONLY for links, focus rings, glows, italic accents.
   · Amber --accent is a spice (eyebrows, one keyline, badges) — max 10%.
   · Never pure #000/#FFF anywhere.
   · Light sections: add class="band--cream" — every token remaps to Set B.
   ============================================================================ */

@import url("https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@300..700&family=JetBrains+Mono:wght@400;500&display=swap");

/* ----------------------------------------------------------------------------
   1 · TOKENS — Set A "Warm-Dark Teal" (LOCKED DEFAULT)
   --------------------------------------------------------------------------- */
:root {
  /* neutrals (60%) — LIGHT-LED ground · Navy & Burgundy (LOCKED 2026-07-20) */
  --paper:      #F6F6F2;                    /* soft near-white canvas (default ground). NEVER #FFF fills */
  --paper-2:    #FCFCFA;                    /* tinted light panel */
  --surface:    #FFFFFF;                    /* crisp card */
  --wash:       #FCFCFA;                    /* elevated light surface (meaning inverted) */
  --wash-deep:  #EAEEF1;                    /* cool light field: behind media, quiet washes (was deep teal) */
  --ink:        #141A24;                    /* navy-black text. NEVER pure #000 */
  --muted:      #5A6270;                    /* secondary copy, captions */
  --muted-2:    #8A93A0;                    /* faint mono metadata (numbers, coords) — 2.87:1 on --paper, DECORATIVE ONLY */
  --muted-aa:   #5F6879;                    /* the same quiet grey that actually clears AA on BOTH light grounds:
                                               5.18:1 on --paper, 4.83:1 on --glass over paper. Use this the
                                               moment --muted-2 carries READABLE text (labels, categories,
                                               breadcrumbs, meta). See sharedFileRequests. */
  --black:      #0E1116;                    /* deep neutral for rare max-contrast */
  --line:       rgba(20,26,36,0.12);        /* hairlines, dividers on light */
  --line-soft:  rgba(20,26,36,0.06);
  /* PRIMARY structural anchor — NAVY */
  --navy:       #16263F;                    /* dark sections, footer, hero guest, deep headings */
  --navy-2:     #1F3253;                    /* lifted navy panel */
  --ink-inv:    #F3F5F8;                    /* text on navy/dark */
  /* PRIMARY rich accent — BURGUNDY */
  --burgundy:   #7C2D48;                    /* emphasis, one band, premium accent, keylines */
  --burgundy-2: #98354F;                    /* hover / lifted burgundy */
  /* SUPPORTING — TEAL */
  --teal:       #1C8B7C;                    /* links, secondary accents, icons */
  --teal-deep:  #146E62;                    /* small-text-safe teal (AA on light) */
  --brand:      #1C8B7C;                    /* alias: components read --brand = THE teal */
  --glow:       #1C8B7C;                    /* teal accents: links, focus, italics (no neon on paper) */
  /* ATTENTION — GREEN (sparing: primary CTAs, live dots, demo HUD) */
  --green:      #5FD433;                    /* synergy green — where the eye MUST go */
  --green-deep: #46B21F;                    /* green hover / green text on light (AA) */
  /* accent RETIRED → aliased to burgundy so brass usages become burgundy, nothing breaks */
  --accent:     var(--burgundy);
  --accent-body:var(--burgundy);
  /* derived — keep derivations here, never in page CSS */
  --brand-glow:  color-mix(in oklab, var(--brand) 22%, transparent);
  --brand-raise: color-mix(in oklab, var(--brand) 90%, #ffffff 10%); /* btn top-light */
  --accent-dim:  color-mix(in oklab, var(--accent) 12%, transparent);
  /* HERO EYEBROW LEGIBILITY (added 2026-07-22 — foundation pass)
     Nine pages hard-coded the mono hero eyebrow to rgba(243,245,248,0.7x).
     The ALPHA is the real defect: every premium hero here is a diagonal scrim
     that runs dark→light, so a 0.74-alpha near-white label dissolves the moment
     the ground crosses ~rgb(110). Use SOLID tokens, never alpha, and pair each
     with its halo — the halo is invisible on a flat ground and only earns its
     keep over a gradient or photograph (Primland's atmospheric-depth logic at
     glyph scale). Both colours clear 4.5:1 on their canonical ground; the halo
     carries the worst-case gradient midpoint over the line too.
       on-dark  #EDF1F7 vs --navy  #16263F = 13.9:1
       on-light #414B5A vs --paper #F6F6F2 =  7.8:1
     ⚠ A page agent flipping a hero light↔dark MUST swap BOTH declarations. */
  --eyebrow-on-dark:    #EDF1F7;
  --eyebrow-halo-dark:  0 0 2px rgba(11,17,27,0.55), 0 1px 12px rgba(11,17,27,0.42);
  --eyebrow-on-light:   #414B5A;
  --eyebrow-halo-light: 0 0 2px rgba(246,246,242,0.62), 0 1px 12px rgba(246,246,242,0.5);

  --glass:       rgba(20,26,36,0.035);      /* subtle dark film on the light ground */
  --glass-line:  rgba(20,26,36,0.10);
  --scrim:       20,26,36;                  /* navy rgb for rgba() scrims / recessed islands */
  --navy-grad:   linear-gradient(135deg,#16263F,#28406A);

  /* fluid type scale (minor-third → major-second blend) */
  --step--1: clamp(0.83rem, 0.80rem + 0.16vw, 0.94rem);
  --step-0:  clamp(1.00rem, 0.95rem + 0.25vw, 1.13rem);
  --step-1:  clamp(1.20rem, 1.10rem + 0.50vw, 1.50rem);
  --step-2:  clamp(1.44rem, 1.28rem + 0.80vw, 2.00rem);
  --step-3:  clamp(1.73rem, 1.48rem + 1.25vw, 2.67rem);
  --step-4:  clamp(2.07rem, 1.70rem + 1.85vw, 3.55rem);
  --step-5:  clamp(2.49rem, 1.95rem + 2.70vw, 4.74rem);
  --step-6:  clamp(2.99rem, 2.20rem + 3.90vw, 6.31rem);
  --step-7:  clamp(3.58rem, 2.45rem + 5.65vw, 8.42rem);
  --step-hero: clamp(2.85rem, 1.15rem + 7.4vw, 8.6rem);

  --font-display: "Instrument Serif", Georgia, serif;
  --font-body: "Geist", system-ui, -apple-system, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, monospace;

  /* easing — never bare linear/ease-in-out on UI */
  --ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in-out-quint: cubic-bezier(0.83, 0, 0.17, 1);
  --ease-out-quart: cubic-bezier(0.25, 1, 0.5, 1);
  --dur-fast: 0.4s;
  --dur-base: 0.7s;
  --dur-slow: 1.1s;

  /* layout rhythm */
  --shell: 1360px;
  --gutter: clamp(20px, 4vw, 52px);
  --section-y: clamp(6.5rem, 10vw, 11rem);
  --r-lg: 2rem;
  --r-md: 1.25rem;
}

/* ----------------------------------------------------------------------------
   2 · RESET / BASE
   --------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: auto; overflow-x: clip; }
html.lenis, html.lenis body { height: auto; }
.lenis.lenis-smooth { scroll-behavior: auto !important; }

body {
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  font-weight: 400;
  font-size: var(--step-0);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;
}

::selection { background: rgba(28,139,124,0.20); color: var(--ink); }
img, video, canvas { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
* { font-optical-sizing: auto; }
:focus-visible { outline: 2px solid var(--glow); outline-offset: 3px; border-radius: 4px; }

h1, h2, h3, .display { text-wrap: balance; }
p, li { text-wrap: pretty; }

.shell { max-width: var(--shell); margin-inline: auto; padding-inline: var(--gutter); }
.section { padding-block: var(--section-y); position: relative; }
/* Two adjacent .section elements each apply the FULL --section-y (up to 176px)
   on their own touching edge, so a plain section-to-section boundary stacks
   to ~350px of pure background with nothing in it - the exact "falls off
   after the hero" complaint, confirmed 2026-08-10 by screenshotting every
   page's mid/bottom half rather than trusting a DOM element-presence check
   (which had wrongly reported zero dead zones earlier). This is a single,
   sitewide root cause, not a per-page content problem: shrink the INCOMING
   section's top padding whenever it follows another .section directly, since
   the outgoing section's bottom padding already did the work of separating
   them. A section that follows something else (a full-bleed hero, a marquee)
   is untouched, so hero->first-section spacing is unaffected. */
.section + .section { padding-top: calc(var(--section-y) * 0.18); }
/* The rule above only shrank the INCOMING half; the OUTGOING section's own
   full bottom padding was still stacking underneath it and stayed the
   dominant part of the gap (confirmed by screenshot, not assumed). Shrink
   that side too, on any .section directly followed by another .section, so
   the two halves split one section-y's worth of breathing room between them
   instead of each contributing a full one. :has() has full modern-browser
   support (Chrome 105+/Safari 15.4+/Firefox 121+, all well past this B2B
   site's bar). A section followed by something that ISN'T .section (a
   full-bleed CTA band, a footer) keeps its full bottom padding on purpose. */
.section:has(+ .section) { padding-bottom: calc(var(--section-y) * 0.35); }

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 200;
  background: var(--ink); color: var(--paper); padding: 10px 18px; border-radius: 999px;
}
.skip:focus { left: 16px; top: 16px; }

/* ----------------------------------------------------------------------------
   3 · GRAIN — one fixed layer per page, paints once, kills teal banding
   --------------------------------------------------------------------------- */
body::after {
  content: "";
  position: fixed; inset: 0; z-index: 90;
  pointer-events: none;
  opacity: 0.03;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-repeat: repeat;
  mix-blend-mode: overlay;
}

/* ----------------------------------------------------------------------------
   4 · TYPOGRAPHY HELPERS
   --------------------------------------------------------------------------- */
.eyebrow {
  font-family: var(--font-mono); font-weight: 500;
  font-size: 11px; letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--muted);
  display: inline-flex; align-items: center; gap: 10px;
}
.eyebrow .tick { width: 20px; height: 1px; background: var(--accent); display: inline-block; } /* the amber spice */
.h-display {
  font-family: var(--font-display); font-weight: 400;
  font-size: var(--step-6); line-height: 1.02; letter-spacing: -0.015em;
  color: var(--ink);
}
.h-display em { font-style: italic; color: var(--glow); letter-spacing: 0.005em; }
.lede { color: var(--muted); font-size: var(--step-1); line-height: 1.55; max-inline-size: 56ch; font-weight: 300; }
/* a NOTE is read, not decoration → --muted-aa (ground-aware), not --muted-2 */
.small-note { color: var(--muted-aa); font-size: var(--step--1); }
.link-plain {
  font-family: var(--font-mono); font-size: 11.5px; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--muted); display: inline-flex; align-items: center; gap: 8px;
  transition: color var(--dur-fast) var(--ease-out-quart);
}
.link-plain:hover { color: var(--glow); }

/* ----------------------------------------------------------------------------
   5 · NAV — floating detached glass pill (markup in _nav-footer.html)
   --------------------------------------------------------------------------- */
.nav {
  position: fixed; top: clamp(14px, 2.2vh, 24px); left: 50%;
  transform: translateX(-50%);
  z-index: 100;
  display: flex; align-items: center; gap: clamp(14px, 2vw, 30px);
  padding: 9px 10px 9px 20px;
  border-radius: 999px;
  border: 1px solid transparent;
  transition: background var(--dur-fast) var(--ease-out-quart),
              border-color var(--dur-fast) var(--ease-out-quart),
              box-shadow var(--dur-fast) var(--ease-out-quart);
  white-space: nowrap;
}
/* Scrolled over the LIGHT page → light glass pill + dark ink text */
.nav.is-scrolled {
  background: rgba(246, 246, 242, 0.93);        /* light paper glass — 0.93 not 0.82 so headings don't bleed through mid-scroll */
  -webkit-backdrop-filter: blur(18px) saturate(140%);
  backdrop-filter: blur(18px) saturate(140%);
  border-color: var(--line);
  box-shadow: 0 18px 44px -18px rgba(20,26,36,0.22);
}
.nav__brand { display: inline-flex; align-items: baseline; gap: 9px; }
.nav__brand .nav__seal { display: block; flex: none; align-self: center; border-radius: 50%; }
.nav__brand .wm-serif {
  font-family: var(--font-display); font-style: italic; font-weight: 400;
  font-size: 20px; line-height: 1; color: var(--ink); letter-spacing: 0.01em;
}
.nav__brand .wm-mono {
  font-family: var(--font-mono); font-weight: 500; font-size: 9px;
  letter-spacing: 0.24em; text-transform: uppercase; color: var(--muted);
}
/* Stretching the whole chain — the <nav> flex item, its <ul>, its <li>s — makes
   `top: 100%` on the products panel resolve to the pill's inner bottom edge, so
   the panel's offset is a fixed 19px (9px pad + 1px border + 9px air) instead of
   a number that silently drifts with the link line-height. Stretch alone would
   also top-align the link text, so every level re-centres with align-items. */
.nav > nav { align-self: stretch; display: flex; align-items: center; }
.nav__links {
  display: flex; align-items: center; align-self: stretch;
  gap: clamp(12px, 1.6vw, 24px); list-style: none;
}
.nav__links > li { display: flex; align-items: center; }
.nav__links a {
  font-size: 13.5px; font-weight: 400; color: var(--muted);
  transition: color var(--dur-fast) var(--ease-out-quart);
}
.nav__links a:hover,
.nav__links a[aria-current="page"] { color: var(--ink); }
.nav__tel {
  font-family: var(--font-mono); font-size: 12px; letter-spacing: 0.04em;
  color: var(--ink); opacity: 0.85;
}
.nav__tel:hover { color: var(--teal-deep); }
.nav__cta {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 13.5px; font-weight: 500; color: var(--ink-inv);
  background: var(--navy);
  padding: 8px 8px 8px 16px; border-radius: 999px;
  transition: transform var(--dur-fast) var(--ease-out-quart);
}
.nav__cta .ic {
  width: 22px; height: 22px; border-radius: 999px; background: rgba(243,245,248,0.14);
  display: grid; place-items: center;
  transition: transform var(--dur-fast) var(--ease-out-quart);
}

/* AT TOP, over the navy hero dark-guest → LIGHT nav text (scoped to header only,
   so the footer's re-used .nav__brand keeps dark ink). Flips back when scrolled. */
/* …and the pill needs a GROUND to say it on. Nine pages open on a photographic
   or diagonally-scrimmed hero whose top-right corner — exactly where the phone
   number and CTA sit — runs LIGHT. With a transparent pill the white phone
   number measured 2.84–3.44:1 there (/work/, /products/*), i.e. the primary
   conversion action for a trades buyer was unreadable in daylight at scroll 0.
   `brightness()` inside backdrop-filter makes the scrim adaptive: it barely
   touches an already-dark sky (home) but firmly darkens a light corner. Scoped
   away from .nav--light, which has its own paper-glass pill, and away from
   .is-scrolled. Blur is legal here — .nav is fixed (see §16 guardrails).
   The tint is NAVY, not black: a black lozenge over the home hero's teal dawn
   sky reads as a slab pasted on the photograph, while --navy sits inside the
   palette and disappears into it. */
.nav:not(.is-scrolled):not(.nav--light) {
  background: rgba(22,38,63,0.34);
  -webkit-backdrop-filter: blur(16px) saturate(125%) brightness(0.52);
          backdrop-filter: blur(16px) saturate(125%) brightness(0.52);
  border-color: rgba(243,245,248,0.10);
  box-shadow: 0 20px 50px -26px rgba(11,17,27,0.55);
}
.nav:not(.is-scrolled) .nav__brand .wm-serif { color: var(--ink-inv); }
.nav:not(.is-scrolled) .nav__brand .nav__mark { background-color: var(--ink-inv); }
/* SOLID, never alpha — same lesson as the hero eyebrow above: a 0.82-alpha
   near-white dissolves the moment the ground lifts. #CFD7E2 keeps "DOES AI" and
   the link row deliberately quieter than the serif wordmark without going faint
   (7.9:1 on the scrimmed pill). Written as a literal, not a color-mix(): a
   computed color-mix() resolves to oklab() in getComputedStyle, which the
   rendered-pixel contrast auditor's rgb() parser skips — that would hide these
   two rules from the audit rather than fix them. */
.nav:not(.is-scrolled) .nav__brand .wm-mono,
.nav:not(.is-scrolled) .nav__links a { color: #CFD7E2; }
.nav:not(.is-scrolled) .nav__links a:hover,
.nav:not(.is-scrolled) .nav__links a[aria-current="page"] { color: var(--ink-inv); }
.nav:not(.is-scrolled) .nav__tel { color: var(--ink-inv); }
.nav:not(.is-scrolled) .nav__cta { background: var(--ink-inv); color: var(--navy); }
.nav:not(.is-scrolled) .nav__cta .ic { background: rgba(20,26,36,0.12); }
.nav__cta:hover .ic { transform: translate(2px, -1px); }
.nav__cta:active { transform: scale(0.97); }

/* Light-hero pages (about, faq, faq/*, pricing, vs, promote, trades, work,
   resources, products/*) — pin the paper-glass look at scroll=0 so the wordmark,
   links, phone, and CTA remain readable over the --paper ground. Ordered AFTER
   .nav:not(.is-scrolled) so the color overrides win at equal specificity. */
.nav.nav--light {
  background: rgba(246, 246, 242, 0.93);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
          backdrop-filter: blur(18px) saturate(140%);
  border-color: var(--line);
  box-shadow: 0 18px 44px -18px rgba(20,26,36,0.22);
}
.nav.nav--light .nav__brand .wm-serif { color: var(--ink); }
.nav.nav--light .nav__brand .wm-mono { color: var(--muted); }
.nav.nav--light .nav__links a { color: var(--muted); }
.nav.nav--light .nav__links a:hover,
.nav.nav--light .nav__links a[aria-current="page"] { color: var(--ink); }
.nav.nav--light .nav__tel { color: var(--ink); opacity: 0.85; }
.nav.nav--light .nav__cta { background: var(--navy); color: var(--ink-inv); }
.nav.nav--light .nav__cta .ic { background: rgba(243,245,248,0.14); }

/* ----------------------------------------------------------------------------
   5a · PRODUCTS DISCLOSURE — the second lozenge
   ---------------------------------------------------------------------------
   The funnel defect this fixes: /products/website|ai-chat|automation|marketing
   were reachable ONLY from the footer, so a buyer whose first question is "what
   exactly do I get" had no path to the four pages that answer it.

   Why a detached panel and not a mega-menu: the nav's whole idiom is a floating
   lozenge with nothing touching it. A dropdown welded to the pill's underside
   would read as a corporate nav bar bolted onto a boutique site. So the panel is
   a SECOND lozenge of the same family — same radius language, same glass, same
   ground-awareness — that arrives 10px below the first and is obviously the same
   object's second thought. Inside it is an editorial index (mono ordinal, name,
   one plain line), not an icon grid.

   Ground-awareness: the panel is paper by default (used by .is-scrolled and by
   .nav--light) and flips to navy glass under
   .nav:not(.is-scrolled):not(.nav--light) — the exact selector the pill itself
   uses, so panel and pill can never disagree about which ground they're on.
   Every colour is written on the INNER spans, never on the <a>, because
   `.nav:not(.is-scrolled) .nav__links a` (0,3,1) would otherwise beat any rule
   here and paint the panel's body text #CFD7E2 on paper.
   --------------------------------------------------------------------------- */
.nav__item--disc { position: relative; }
.nav__disc {
  display: inline-flex; align-items: center; gap: 6px;
  margin: 0; padding: 0; border: 0; background: none; cursor: pointer;
  font-family: var(--font-body); font-size: 13.5px; font-weight: 400;
  line-height: inherit; letter-spacing: inherit; color: var(--muted);
  transition: color var(--dur-fast) var(--ease-out-quart);
}
.nav__disc:hover,
.nav__disc[aria-expanded="true"],
.nav__disc[aria-current="true"] { color: var(--ink); }
.nav__disc-caret {
  display: grid; place-items: center; width: 9px; height: 6px; opacity: 0.6;
  transition: transform 0.3s var(--ease-out-quart), opacity var(--dur-fast) var(--ease-out-quart);
}
.nav__disc[aria-expanded="true"] .nav__disc-caret { transform: rotate(180deg); opacity: 1; }

/* `top: 100%` is exact because the <nav>/<ul>/<li> chain is stretched — 100%
   lands on the pill's content-box bottom, and +28px clears the pill's own
   padding and border to leave a measured 10px of air. left:-14px puts the
   panel's first column under the "P" of Products (its 15px padding cancels).
   transform/opacity only; nothing here triggers layout. */
.nav__panel {
  position: absolute; top: calc(100% + 28px); left: -14px;
  z-index: 2; width: 366px; padding: 15px 15px 9px;
  border-radius: 20px; border: 1px solid var(--line);
  background: rgba(246, 246, 242, 0.97);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
          backdrop-filter: blur(18px) saturate(140%);
  box-shadow: 0 26px 60px -24px rgba(20,26,36,0.32), 0 2px 6px -3px rgba(20,26,36,0.14);
  white-space: normal;
  opacity: 0; visibility: hidden; pointer-events: none;
  transform: translateY(-8px) scale(0.985); transform-origin: 30px -10px;
  transition: opacity 0.28s var(--ease-out-quart),
              transform 0.28s var(--ease-out-quart),
              visibility 0s linear 0.28s;
}
/* visibility (not [hidden] / display) is what keeps the four links out of the
   tab order while closed AND keeps the fade — same trick as .nav-menu. */
.nav__panel.is-open {
  opacity: 1; visibility: visible; pointer-events: auto;
  transform: none; transition-delay: 0s, 0s, 0s;
}
/* bridges the 10px air gap so a mouse travelling from "Products" down to the
   first row never leaves the group. Only live while open (the panel is
   pointer-events:none otherwise), so it can never eat a click on the hero. */
.nav__panel::before {
  content: ""; position: absolute; left: 0; right: 0; top: -22px; height: 22px;
}
.nav__panel-label {
  font-family: var(--font-mono); font-size: 9.5px; font-weight: 500;
  letter-spacing: 0.24em; text-transform: uppercase; color: var(--muted-aa);
  padding: 0 8px 9px; margin-bottom: 5px;
  border-bottom: 1px solid var(--line-soft);
}
.nav__panel-list { list-style: none; display: block; }
.nav__panel-list li {
  opacity: 0; transform: translateY(6px);
  transition: opacity 0.3s var(--ease-out-quart), transform 0.3s var(--ease-out-quart);
}
.nav__panel.is-open .nav__panel-list li { opacity: 1; transform: none; }
.nav__panel.is-open .nav__panel-list li:nth-child(1) { transition-delay: 0.05s; }
.nav__panel.is-open .nav__panel-list li:nth-child(2) { transition-delay: 0.09s; }
.nav__panel.is-open .nav__panel-list li:nth-child(3) { transition-delay: 0.13s; }
.nav__panel.is-open .nav__panel-list li:nth-child(4) { transition-delay: 0.17s; }
.nav__panel-list a {
  display: grid; grid-template-columns: auto 1fr; gap: 12px; align-items: start;
  padding: 8px; border-radius: 12px;
  transition: background var(--dur-fast) var(--ease-out-quart);
}
/* "you are here" has to survive being the same colour family as hover — a 10px
   teal ordinal alone was too quiet to find on a page you are already reading. */
.nav__panel-list a:hover,
.nav__panel-list a[aria-current="page"] { background: rgba(20,26,36,0.05); }
.nav__panel-n {
  font-family: var(--font-mono); font-size: 10px; font-weight: 500;
  letter-spacing: 0.1em; color: var(--muted-aa); padding-top: 4px;
  transition: color var(--dur-fast) var(--ease-out-quart);
}
.nav__panel-list a:hover .nav__panel-n,
.nav__panel-list a[aria-current="page"] .nav__panel-n { color: var(--teal-deep); }
.nav__panel-b { display: block; }
.nav__panel-b b {
  display: block; font-family: var(--font-body); font-weight: 500;
  font-size: 13.5px; line-height: 1.25; letter-spacing: -0.004em; color: var(--ink);
}
.nav__panel-b > span {
  display: block; margin-top: 2px;
  font-size: 12px; line-height: 1.4; color: var(--muted-aa);
}

/* dark ground — the pill is navy glass over a hero, so the panel is too */
.nav:not(.is-scrolled):not(.nav--light) .nav__disc { color: #CFD7E2; }
.nav:not(.is-scrolled):not(.nav--light) .nav__disc:hover,
.nav:not(.is-scrolled):not(.nav--light) .nav__disc[aria-expanded="true"],
.nav:not(.is-scrolled):not(.nav--light) .nav__disc[aria-current="true"] { color: var(--ink-inv); }
.nav:not(.is-scrolled):not(.nav--light) .nav__panel {
  background: rgba(16, 26, 41, 0.90);
  -webkit-backdrop-filter: blur(20px) saturate(130%) brightness(0.62);
          backdrop-filter: blur(20px) saturate(130%) brightness(0.62);
  border-color: rgba(243,245,248,0.14);
  box-shadow: 0 28px 64px -26px rgba(11,17,27,0.74);
}
.nav:not(.is-scrolled):not(.nav--light) .nav__panel-label {
  color: rgba(243,245,248,0.66); border-bottom-color: rgba(243,245,248,0.12);
}
.nav:not(.is-scrolled):not(.nav--light) .nav__panel-n { color: rgba(243,245,248,0.58); }
.nav:not(.is-scrolled):not(.nav--light) .nav__panel-b b { color: var(--ink-inv); }
.nav:not(.is-scrolled):not(.nav--light) .nav__panel-b > span { color: rgba(243,245,248,0.76); }
.nav:not(.is-scrolled):not(.nav--light) .nav__panel-list a:hover,
.nav:not(.is-scrolled):not(.nav--light) .nav__panel-list a[aria-current="page"] { background: rgba(243,245,248,0.07); }
/* the on-dark teal, written as a LITERAL: this is
   color-mix(in oklab, var(--glow) 62%, white 38%) resolved by hand, because a
   computed color-mix() serialises to oklab() and the rendered-pixel auditor's
   rgb() parser skips it — that hides the rule from the audit instead of
   passing it. 8.4:1 on the overlay ground. */
.nav:not(.is-scrolled):not(.nav--light) .nav__panel-list a:hover .nav__panel-n,
.nav:not(.is-scrolled):not(.nav--light) .nav__panel-list a[aria-current="page"] .nav__panel-n { color: #7FB6AC; }
/* --glow at 3px offset is only ~2.4:1 on navy; lift the ring on the dark pill */
.nav:not(.is-scrolled):not(.nav--light) .nav__disc:focus-visible,
.nav:not(.is-scrolled):not(.nav--light) .nav__links a:focus-visible,
.nav:not(.is-scrolled):not(.nav--light) .nav__brand:focus-visible,
.nav:not(.is-scrolled):not(.nav--light) .nav__tel:focus-visible,
.nav:not(.is-scrolled):not(.nav--light) .nav__panel-list a:focus-visible { outline-color: #7FB6AC; }

@media (prefers-reduced-motion: reduce) {
  .nav__panel {
    transform: none;
    transition: opacity 0.001s linear, visibility 0s linear 0.001s;
  }
  .nav__panel.is-open { transform: none; }
  .nav__panel-list li { opacity: 1; transform: none; transition: none; }
  .nav__panel.is-open .nav__panel-list li { transition-delay: 0s; }
  .nav__disc-caret { transition: none; }
}

/* ----------------------------------------------------------------------------
   5b · MOBILE NAV — toggle + full-screen overlay  (markup injected by
        .tools/inject-shared.mjs; behaviour in premium-motion.js)
   ---------------------------------------------------------------------------
   Trades trust furniture (trades-premium.md §1): the PHONE NUMBER never leaves
   the bar. Under 860px the link list collapses into the overlay; the number
   stays as literal text because ~60% of home-service buyers call rather than
   click. Under 640px "Book a call" moves into the overlay, where it is the
   largest green control on screen — the number wins the last 50px of bar.
   --------------------------------------------------------------------------- */

/* toggle is desktop-hidden; the overlay never exists above 860 */
.nav__toggle { display: none; }

@media (max-width: 860px) {
  .nav {
    left: 16px; right: 16px; transform: none;
    justify-content: space-between;
    gap: 8px; padding: 7px 7px 7px 16px;
  }
  .nav__links { display: none; }

  /* phone stays as text — compact mono, 44px tall tap target */
  .nav__tel {
    display: inline-flex; align-items: center; min-height: 44px;
    padding: 0 12px; border-radius: 999px;
    font-size: 12px; letter-spacing: 0.01em; opacity: 1;
    margin-left: auto;
  }
  .nav__cta { min-height: 44px; padding: 8px 8px 8px 14px; font-size: 13px; }
  .nav__cta .ic { width: 20px; height: 20px; }

  .nav__toggle {
    display: grid; place-items: center;
    width: 44px; height: 44px; flex: 0 0 44px;
    border: 1px solid var(--line); border-radius: 999px;
    background: transparent; color: var(--ink); cursor: pointer;
    transition: background var(--dur-fast) var(--ease-out-quart),
                border-color var(--dur-fast) var(--ease-out-quart);
  }
  .nav__toggle:hover { background: var(--glass); }
  .nav__toggle-box { display: block; position: relative; width: 18px; height: 12px; }
  .nav__toggle-box i {
    position: absolute; left: 0; width: 100%; height: 1.5px; border-radius: 2px;
    background: currentColor;
    transition: transform var(--dur-fast) var(--ease-out-quart),
                opacity 0.2s linear;
  }
  .nav__toggle-box i:first-child { top: 0; }
  .nav__toggle-box i:last-child  { bottom: 0; }
  .nav__toggle[aria-expanded="true"] .nav__toggle-box i:first-child { transform: translateY(5.25px) rotate(45deg); }
  .nav__toggle[aria-expanded="true"] .nav__toggle-box i:last-child  { transform: translateY(-5.25px) rotate(-45deg); }

  /* dark-guest nav (at top, over a navy hero) — invert the toggle chrome */
  .nav:not(.is-scrolled):not(.nav--light) .nav__toggle {
    border-color: rgba(243,245,248,0.28); color: var(--ink-inv);
  }
  .nav:not(.is-scrolled):not(.nav--light) .nav__toggle:hover { background: rgba(243,245,248,0.10); }
}

@media (max-width: 640px) {
  .nav { padding: 7px 7px 7px 14px; }
  .nav__cta { display: none; }          /* promoted into the overlay instead */
  .nav__tel { padding: 0 10px; font-size: 11.5px; }
}
@media (max-width: 360px) {
  .nav__brand .wm-mono { display: none; }
}

/* ---- the overlay itself (sibling of <header>, never a child — .nav's
        backdrop-filter would otherwise become its containing block) ---- */
.nav-menu {
  position: fixed; inset: 0; z-index: 99;
  display: flex; flex-direction: column;
  padding: calc(env(safe-area-inset-top, 0px) + 92px) var(--gutter)
           calc(env(safe-area-inset-bottom, 0px) + 24px);
  background: rgba(16, 26, 41, 0.90);
  -webkit-backdrop-filter: blur(22px) saturate(130%);
          backdrop-filter: blur(22px) saturate(130%);
  color: var(--ink-inv);
  opacity: 0; visibility: hidden;
  transition: opacity 0.34s var(--ease-out-quart), visibility 0s linear 0.34s;
  overflow-y: auto; overscroll-behavior: contain;
}
.nav-menu[hidden] { display: none; }
.nav-menu.is-open { opacity: 1; visibility: visible; transition-delay: 0s, 0s; }
@media (min-width: 861px) { .nav-menu { display: none; } }

/* bottom-aligned via auto margin, NOT justify-content:flex-end — now that the
   products group makes the content taller than a 667px phone, flex-end would
   clip the top of an overflowing flex item and the "Menu" heading would become
   unreachable by scrolling. margin-top:auto degrades to plain top-alignment. */
.nav-menu__inner { width: 100%; max-width: 34rem; margin-inline: auto; margin-top: auto; }
.nav-menu__label {
  font-family: var(--font-mono); font-size: 10px; font-weight: 500;
  letter-spacing: 0.26em; text-transform: uppercase;
  color: rgba(243,245,248,0.62);
  padding-bottom: 0.55rem; margin-bottom: 0.75rem;
  border-bottom: 1px solid rgba(243,245,248,0.14);
}
.nav-menu__label + .nav-menu__label,
.nav-menu__list + .nav-menu__label { margin-top: 2rem; }
/* the lists live inside <nav> wrappers, so the label's real previous sibling is
   the <nav> — the two selectors above never actually matched. */
.nav-menu__inner > nav + .nav-menu__label { margin-top: 1.35rem; }

.nav-menu__list { list-style: none; display: block; }
.nav-menu__list li { overflow: hidden; }        /* the mask the letters rise out of */
/* Sized down from clamp(2.1rem, 11.5vw, 3.2rem) / 0.24em when the products
   group joined the overlay. At the old size the four serif words alone ate 272px
   of a 390x844 phone and pushed the phone number and "Book a call" off the
   bottom — the two conversion actions must never cost a scroll, so the headline
   list gives up the height rather than the Direct block. Still the largest type
   on the screen by a wide margin. */
.nav-menu__list a {
  display: block; padding: 0.16em 0;
  font-family: var(--font-display); font-style: italic; font-weight: 400;
  font-size: clamp(1.85rem, 8.6vw, 2.7rem); line-height: 1.06;
  letter-spacing: 0.004em; color: var(--ink-inv);
  transform: translateY(104%);
  transition: transform 0.62s var(--ease-out-expo), color var(--dur-fast) var(--ease-out-quart);
}
/* on-dark teal literal — see §5a: --glow (#1C8B7C) is 2.4:1 on this overlay and
   fails even the large-text 3:1 floor, so the current page was the least legible
   item in the menu. #7FB6AC is the same hue lifted to 8.4:1. */
.nav-menu__list a[aria-current="page"] { color: #7FB6AC; }
.nav-menu.is-open .nav-menu__list a { transform: translateY(0); }
.nav-menu.is-open .nav-menu__list li:nth-child(1) a { transition-delay: 0.04s; }
.nav-menu.is-open .nav-menu__list li:nth-child(2) a { transition-delay: 0.08s; }
.nav-menu.is-open .nav-menu__list li:nth-child(3) a { transition-delay: 0.12s; }
.nav-menu.is-open .nav-menu__list li:nth-child(4) a { transition-delay: 0.16s; }
.nav-menu.is-open .nav-menu__list li:nth-child(5) a { transition-delay: 0.20s; }

/* PRODUCTS on a phone — a labelled group, never a second tap. A thumb should
   not have to open a sub-menu to find out what it is buying, so the four sit in
   the open with their one-liners. Denser than the big serif list above on
   purpose: this is an index, not a headline, and the overlay still has to hold
   Direct below it on a 667px screen. Reveal is opacity + translateY only — no
   translateY(104%) mask, which at this row height would read as a glitch. */
.nav-menu__products { list-style: none; display: block; }
.nav-menu__products li + li { border-top: 1px solid rgba(243,245,248,0.10); }
.nav-menu__products a {
  display: grid; grid-template-columns: auto 1fr; column-gap: 0.8rem;
  padding: 0.55rem 0; min-height: 44px; align-content: center;
  opacity: 0; transform: translateY(10px);
  transition: opacity 0.38s var(--ease-out-quart), transform 0.38s var(--ease-out-quart);
}
.nav-menu.is-open .nav-menu__products a { opacity: 1; transform: none; }
.nav-menu.is-open .nav-menu__products li:nth-child(1) a { transition-delay: 0.20s; }
.nav-menu.is-open .nav-menu__products li:nth-child(2) a { transition-delay: 0.24s; }
.nav-menu.is-open .nav-menu__products li:nth-child(3) a { transition-delay: 0.28s; }
.nav-menu.is-open .nav-menu__products li:nth-child(4) a { transition-delay: 0.32s; }
.nav-menu__products i {
  grid-row: 1 / span 2; padding-top: 0.42rem;
  font-family: var(--font-mono); font-style: normal; font-size: 10px; font-weight: 500;
  letter-spacing: 0.14em; color: rgba(243,245,248,0.58);
}
.nav-menu__products b {
  display: block; font-family: var(--font-display); font-style: italic; font-weight: 400;
  font-size: 1.32rem; line-height: 1.12; letter-spacing: 0.004em; color: var(--ink-inv);
}
.nav-menu__products span {
  display: block; grid-column: 2; margin-top: 0.18rem;
  font-size: 12.5px; line-height: 1.42; color: rgba(243,245,248,0.76);
}
.nav-menu__products a[aria-current="page"] b,
.nav-menu__products a[aria-current="page"] i { color: #7FB6AC; }

.nav-menu__direct { display: grid; gap: 0.7rem; }
.nav-menu__tel {
  display: flex; flex-direction: column; gap: 0.3rem;
  min-height: 44px; padding: 0.85rem 1.1rem;
  border: 1px solid rgba(243,245,248,0.18); border-radius: var(--r-md);
  background: rgba(243,245,248,0.05);
  transition: background var(--dur-fast) var(--ease-out-quart);
}
.nav-menu__tel:hover { background: rgba(243,245,248,0.10); }
.nav-menu__tel b {
  font-family: var(--font-mono); font-weight: 500; font-size: 1.32rem;
  letter-spacing: 0.02em; color: var(--ink-inv);
}
.nav-menu__tel span {
  display: inline-flex; align-items: center; gap: 0.5rem;
  font-size: 12.5px; color: rgba(243,245,248,0.78);
}
.nav-menu__dot {
  width: 7px; height: 7px; border-radius: 50%; flex: none;
  background: var(--green); box-shadow: 0 0 0 0 rgba(95,212,51,0.5);
  animation: bd-livepulse 2.4s ease-in-out infinite;
}
.nav-menu__cta {
  display: flex; align-items: center; justify-content: space-between;
  min-height: 52px; padding: 0.9rem 1.1rem;
  border-radius: var(--r-md);
  background: var(--green); color: #0B1A08;
  font-weight: 600; font-size: 15.5px;
}
.nav-menu__cta:active { transform: scale(0.985); }
.nav-menu__meta {
  margin-top: 1.1rem;
  font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.18em;
  text-transform: uppercase; color: rgba(243,245,248,0.5);
}

/* SHORT PHONES — an overlay holding four menu items, four products, the phone
   number and the CTA cannot fit a 667px screen at headline sizes. Rather than
   let "Book a call" drift below the fold, everything compresses once and the
   coordinate line (decoration) is the one thing that goes. The phone number in
   the bar above never moves at any height, so a call is always one tap. */
@media (max-width: 860px) and (max-height: 800px) {
  .nav-menu {
    padding-top: calc(env(safe-area-inset-top, 0px) + 88px);
    padding-bottom: calc(env(safe-area-inset-bottom, 0px) + 16px);
  }
  .nav-menu__label { padding-bottom: 0.4rem; margin-bottom: 0.45rem; }
  .nav-menu__inner > nav + .nav-menu__label { margin-top: 0.75rem; }
  .nav-menu__list a { font-size: clamp(1.45rem, 6.7vw, 2rem); padding: 0.04em 0; }
  .nav-menu__products a { padding: 0.3rem 0; }
  .nav-menu__products b { font-size: 1.16rem; }
  .nav-menu__products span { font-size: 11.5px; line-height: 1.32; }
  .nav-menu__direct { gap: 0.55rem; }
  .nav-menu__tel { padding: 0.68rem 1rem; }
  .nav-menu__tel b { font-size: 1.12rem; }
  .nav-menu__cta { min-height: 48px; padding: 0.72rem 1.1rem; }
  .nav-menu__meta { display: none; }
}

/* body scroll lock while the overlay is open */
html.nav-open, html.nav-open body { overflow: hidden; touch-action: none; }

/* The chat launcher (bally-chat.js, z-index 9000) would otherwise float above
   the overlay and sit on top of the coordinate line. Kept as a scoped override
   so the widget stays a drop-in file with no page-level knowledge. */
html.nav-open .bc {
  opacity: 0; pointer-events: none;
  transition: opacity 0.2s var(--ease-out-quart);
}

@media (prefers-reduced-motion: reduce) {
  .nav-menu { transition: opacity 0.001s linear, visibility 0s; }
  .nav-menu__list a { transform: none; transition: color 0.001s linear; }
  .nav-menu.is-open .nav-menu__list li a { transition-delay: 0s; }
  .nav-menu__products a { opacity: 1; transform: none; transition: none; }
  .nav-menu.is-open .nav-menu__products li a { transition-delay: 0s; }
  .nav__toggle-box i { transition: none; }
  .nav-menu__dot { animation: none; }
}

/* ----------------------------------------------------------------------------
   6 · BUTTONS — pill + button-in-button (nested icon island)
   --------------------------------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; gap: 12px;
  border-radius: 999px;
  font-family: var(--font-body); font-weight: 500; font-size: 15px;
  padding: 0.85rem 0.85rem 0.85rem 1.5rem;
  transform: translate3d(0,0,0);
  transition: transform var(--dur-fast) var(--ease-out-quart),
              box-shadow var(--dur-fast) var(--ease-out-quart),
              background var(--dur-fast) var(--ease-out-quart);
}
.btn:active { transform: scale(0.98); }
.btn .ic {
  width: 2rem; height: 2rem; border-radius: 999px;
  display: grid; place-items: center;
  transition: transform var(--dur-fast) var(--ease-out-quart), background var(--dur-fast) var(--ease-out-quart);
}
.btn:hover .ic { transform: translate(3px, -1px) scale(1.06); }
/* PRIMARY — GREEN attention fill, navy-ink label (high AA), green bloom on hover.
   Green is reserved for primary CTAs only (see palette hierarchy).
   The label is --black, NOT --ink. --ink flips to #F3F5F8 inside .band--deep,
   but this button's green fill does NOT flip with the ground — so on the navy
   bands (e.g. /pricing/ + /trades/ "Start at rung one") the label was going
   light-on-green at 2.42:1 while every other instance sat at 7.6:1. A fixed
   fill has to carry a fixed label; --black is stable in both token sets. */
.btn--call {
  background: linear-gradient(180deg, var(--green), var(--green-deep));
  color: var(--black);
  box-shadow: 0 10px 34px -12px rgba(70,178,31,0.55);
}
.btn--call .ic { background: rgba(20,26,36,0.14); color: var(--black); }
.btn--call:hover { box-shadow: 0 0 40px rgba(95,212,51,0.38), 0 14px 44px -12px rgba(70,178,31,0.5); }
/* GHOST — glass outline (dark film + ink text on the light ground)
   ---------------------------------------------------------------------------
   SELF-CARRIED GROUND (2026-07-27, rendered-pixel contrast audit).
   The ghost is the secondary CTA that sits beside the green primary in every
   hero — and every premium hero here is a photograph or a diagonal scrim that
   runs dark→light. A 3.5%-alpha film has no ground of its own, so the label
   inherited whatever the photo happened to be doing underneath: measured 1.04:1
   on the home hero's fog band and 1.62:1 on /vs/. Both were literally invisible.

   The fill is derived from the button's OWN label colour and inverted in
   lightness, so one rule is correct on both grounds and stays correct on pages
   built later — including pages that flip the label to light WITHOUT flipping
   any token (which is what /, /pricing/, /products/ai-chat/ and
   /products/website/ actually do via `.<x>-hero .btn--ghost { color: … }`).
     dark label  (#141A24, L .21)  → frost L .92  → near-paper, reads as today
     light label (#F3F5F8, L .97)  → frost L .14  → smoked glass on the photo
   It is painted as an INSET box-shadow, not a background, for two reasons:
   inset shadows are clipped to the border radius, and pages already override
   `background` on their hero ghosts — so a background here would be discarded
   exactly where it is needed most. Nothing overrides box-shadow on .btn--ghost.
   Browsers without relative-colour-syntax simply drop the declaration and get
   today's rendering, so this can only improve, never break.

   ⚠ DO NOT "FIX" THIS BECAUSE contrast-audit.mjs STILL FLAGS IT. That auditor
   paints its background plate with `* { color: transparent !important }`, so
   during measurement currentColor is rgba(0,0,0,0) → l resolves to 0 → the
   clamp returns 0.96 and the plate shows a near-WHITE pill exactly where the
   browser paints a near-black one. Measured with the killer sheet on and off:
   plate fill rgb(204,206,210) vs real fill rgb(13,15,20). Sampling the real
   painted pill gives 8.9–17.5:1 on every route/viewport (home 12.9, ai-chat
   16.2, website 13.2, vs 9.9, work 10.9, automation 8.9, marketing 8.7,
   pricing 17.5). The ~6 remaining ghost rows in contrast.json are that
   artifact, not a defect. */
.btn--ghost {
  border: 1px solid var(--glass-line);
  background: var(--glass);
  color: var(--ink);
  box-shadow: inset 0 0 0 100px oklch(from currentColor clamp(0.08, 1.14 - l * 1.04, 0.96) calc(c * 0.5) h / 0.82);
}
.btn--ghost .ic { background: rgba(20,26,36,0.06); }
/* INK — navy fill (neutral emphasis, dark button on light ground) */
.btn--ink { background: var(--ink); color: var(--paper); }
.btn--ink .ic { background: rgba(243,245,248,0.14); }

/* ----------------------------------------------------------------------------
   7 · DOUBLE BEZEL (Doppelrand) — every premium card/image sits in a tray
   --------------------------------------------------------------------------- */
.bezel {
  padding: 0.5rem;
  border-radius: var(--r-lg);
  background: var(--glass);
  box-shadow: inset 0 0 0 1px var(--line);
}
.bezel__core {
  border-radius: calc(var(--r-lg) - 0.5rem);
  background: var(--surface);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.8), 0 30px 60px -28px rgba(20,26,36,0.20);
  overflow: hidden;
}

/* ----------------------------------------------------------------------------
   8 · TRUST ROW — slim honest trust-furniture band (phone · facts · promise)
   Markup: <div class="trustline"><div class="shell trustline__row">
             <a class="trustline__tel" href="tel:...">…</a>
             <span class="trustline__item">…</span> … </div></div>
   --------------------------------------------------------------------------- */
.trustline {
  border-top: 1px solid var(--line-soft);
  border-bottom: 1px solid var(--line-soft);
  background: color-mix(in oklab, var(--wash) 55%, var(--paper));
}
.trustline__row {
  display: flex; align-items: center; justify-content: center;
  gap: clamp(12px, 2.2vw, 28px); flex-wrap: wrap;
  padding-block: 14px;
  font-family: var(--font-mono); font-size: 10.5px; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--muted);
  text-align: center;
}
.trustline__item { display: inline-flex; align-items: center; gap: 10px; }
.trustline__item::before {
  content: ""; width: 4px; height: 4px; border-radius: 50%;
  background: var(--brand); flex: none;
}
.trustline__tel { color: var(--ink); letter-spacing: 0.08em; display: inline-flex; align-items: center; gap: 10px; }
.trustline__tel::before {
  content: ""; width: 4px; height: 4px; border-radius: 50%;
  background: var(--accent); flex: none;              /* one amber dot marks the phone */
}
.trustline__tel:hover { color: var(--glow); }
@media (max-width: 640px) {
  .trustline__row { flex-direction: column; gap: 9px; padding-block: 16px; }
  .trustline__item::before, .trustline__tel::before { display: none; }
}

/* ----------------------------------------------------------------------------
   9 · MARQUEE — CSS-driven, pauses on hover (no JS needed)
   --------------------------------------------------------------------------- */
.marquee-band {
  border-top: 1px solid var(--line-soft);
  border-bottom: 1px solid var(--line-soft);
  padding-block: clamp(1.4rem, 2.6vh, 2.2rem);
  background: var(--paper);
}
.marquee { overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.marquee__track {
  display: flex; align-items: baseline; gap: clamp(2.4rem, 4vw, 4.5rem);
  width: max-content;
  animation: marquee 30s linear infinite;   /* linear OK: continuous conveyor, not UI easing */
  will-change: transform;
}
.marquee__track:hover { animation-play-state: paused; }
.marquee__track span {
  font-family: var(--font-display); font-style: italic;
  font-size: var(--step-3); line-height: 1; color: var(--muted);
  white-space: nowrap;
}
.marquee__track i {
  font-style: normal; align-self: center;
  width: 5px; height: 5px; border-radius: 50%;
  background: var(--brand); opacity: 0.8; flex: none;
}
@keyframes marquee { from { transform: translateX(0); } to { transform: translateX(-50%); } }

/* ----------------------------------------------------------------------------
   10 · SEQ — pinned canvas image-sequence scrub (engine in premium-motion.js)
   Markup: <section class="seq is-static" data-seq data-seq-frames="61"
             data-seq-path="/assets/scrub/home/f-{i}.webp" data-seq-pad="3"
             data-seq-scroll="+=280%"> … see home page for full anatomy.
   Ship with class "is-static" — the engine removes it when it can scrub.
   --------------------------------------------------------------------------- */
.seq { position: relative; }
.seq__stage { position: relative; height: 100svh; overflow: hidden; isolation: isolate; }
.seq__canvas { position: absolute; inset: 0; width: 100%; height: 100%; z-index: -2; }
.seq__fallback { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: -2; display: none; }
.seq__scrim {
  position: absolute; inset: 0; z-index: -1;
  background:
    /* text-safe patch: darkens the zone directly behind seq__steps so headline/
       copy stay legible over bright or busy frames, independent of frame content */
    radial-gradient(48% 44% at 50% 50%, rgba(var(--scrim),0.60) 0%, rgba(var(--scrim),0.22) 60%, transparent 100%),
    radial-gradient(120% 90% at 50% 58%, rgba(var(--scrim),0.18) 0%, rgba(var(--scrim),0.62) 78%),
    linear-gradient(180deg, var(--paper) 0%, transparent 14%, transparent 86%, var(--paper) 100%);
}
.seq__eyebrow {
  position: absolute; top: clamp(84px, 12vh, 120px); left: 50%; transform: translateX(-50%);
  font-family: var(--font-mono); font-size: 10.5px; letter-spacing: 0.3em;
  /* was rgba(243,236,224,0.55) — the last warm-cream (retired brass family) left
     in this file, and a 0.55 alpha over a scrub frame whose luminance is not
     knowable. Solid on-dark token + halo instead, same as every hero eyebrow. */
  text-transform: uppercase;
  color: var(--eyebrow-on-dark); text-shadow: var(--eyebrow-halo-dark);
}
.seq__steps { position: absolute; inset: 0; display: grid; place-items: center; text-align: center; padding-inline: var(--gutter); }
.seq__step { grid-area: 1 / 1; max-width: min(92vw, 1020px); }
.seq__step h2 {
  font-family: var(--font-display); font-weight: 400;
  font-size: var(--step-6); line-height: 1.02; letter-spacing: -0.01em;
  color: #F3ECE0; /* light — sits over dark scroll-sequence frames */
  text-shadow: 0 2px 30px rgba(8,10,14,0.72), 0 1px 8px rgba(8,10,14,0.6);
}
.seq__step h2 em {
  font-style: italic;
  /* lifted off pure --glow: a mid-teal reads too close in luminance to a bright
     photo frame to stay legible on its own — lighten it so it holds contrast
     against light AND dark portions of the scrub sequence */
  color: color-mix(in oklab, var(--glow) 62%, white 38%);
  text-shadow: 0 2px 22px rgba(8,10,14,0.85), 0 0 28px rgba(8,10,14,0.55);
}
.seq__step p {
  margin-top: 18px; color: rgba(243,236,224,0.78);
  font-weight: 300; font-size: var(--step-1); max-inline-size: 44ch; margin-inline: auto;
  text-shadow: 0 1px 18px rgba(var(--scrim),0.7);
}
.seq__bar {
  position: absolute; left: 50%; bottom: clamp(40px, 7vh, 64px); transform: translateX(-50%);
  width: min(280px, 40vw); height: 1px; background: var(--line);
}
.seq__bar i {
  position: absolute; inset: 0;
  background: var(--glow);
  transform: scaleX(0); transform-origin: left;
  display: block;
}
/* mobile / reduced: static scene, no pin */
.seq.is-static .seq__stage { height: auto; padding: var(--section-y) 0 0; overflow: visible; }
.seq.is-static .seq__canvas { display: none; }
.seq.is-static .seq__fallback {
  display: block; position: relative; inset: auto;
  aspect-ratio: 16 / 10; height: auto; border-radius: var(--r-md);
  width: calc(100% - var(--gutter) * 2); margin-inline: auto;
  border: 1px solid var(--line);
}
.seq.is-static .seq__scrim { display: none; }
.seq.is-static .seq__eyebrow { position: static; transform: none; display: block; text-align: center; margin: 30px 0 0; }
.seq.is-static .seq__eyebrow .when-scrub { display: none; }
.seq__eyebrow .when-static { display: none; }
.seq.is-static .seq__eyebrow .when-static { display: inline; }
/* CONTRAST FIX (axe, 47 serious) — in static mode the seq drops its dark canvas
   and sits on plain --paper, but .seq__eyebrow keeps rgba(243,236,224,0.55),
   which computes to ~rgb(240,236,230) on cream: 1.06:1, effectively invisible.
   Repoint the static variant at the on-light eyebrow token → 7.8:1. */
.seq.is-static .seq__eyebrow { color: var(--eyebrow-on-light); text-shadow: none; }
.seq.is-static .seq__steps { position: static; display: block; padding-block: 3rem 1rem; }
.seq.is-static .seq__step { max-width: 30ch; margin-inline: auto; padding-block: 1.6rem; }
.seq.is-static .seq__step h2 { font-size: var(--step-4); text-shadow: none; color: var(--ink); }
/* static fallback sits on plain --paper, not a photo — the lightened pastel teal
   (tuned for legibility over busy scrub frames) has weaker AA contrast on cream
   than --teal-deep, so pin it back to the small-text-safe token here */
.seq.is-static .seq__step h2 em { color: var(--teal-deep); text-shadow: none; }
.seq.is-static .seq__step p { text-shadow: none; color: var(--muted); }
.seq.is-static .seq__bar { display: none; }

/* ----------------------------------------------------------------------------
   11 · STICKY-STACK — stacking card deck (engine adds settle/dim on desktop)
   --------------------------------------------------------------------------- */
.stack { display: flex; flex-direction: column; gap: clamp(1.4rem, 3vh, 2.4rem); }
.stack-card { position: relative; --dim: 0; }
.stack-card .bezel { position: relative; }
.stack-card .bezel::after {
  content: ""; position: absolute; inset: 0; z-index: 2;
  border-radius: var(--r-lg);
  background: rgba(20,26,36,1);
  opacity: var(--dim);
  pointer-events: none;
}
@media (min-width: 768px) {
  .stack-card { position: sticky; top: calc(92px + var(--i, 0) * 14px); }
}
.stack-card .bezel__core {
  display: grid; grid-template-columns: 1fr;
  background: var(--wash);
}
@media (min-width: 880px) {
  .stack-card .bezel__core { grid-template-columns: 7fr 5fr; min-height: 58vh; }
}
.stack-card__shot { position: relative; overflow: hidden; background: var(--wash-deep); }
.stack-card__shot img {
  width: 100%; height: 100%; object-fit: cover; object-position: top center;
  aspect-ratio: 16 / 10;
}
.stack-card__shot::after {
  content: ""; position: absolute; inset: 0;
  box-shadow: inset 0 0 0 1px rgba(20,26,36,0.06);
  pointer-events: none;
}
.stack-card__body {
  padding: clamp(1.6rem, 3vw, 3rem);
  display: flex; flex-direction: column; justify-content: center; gap: 14px;
}
/* __num is the spec-sheet numbering ("01 02 03") — genuinely decorative, and the
   quiet rail is the point. Deliberately LEFT at --muted-2. */
.stack-card__num { font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.2em; color: var(--muted-2); }
/* __tier is read ("Founder tier · one page") at 10.5px. --brand teal measured
   4.06:1 on the white card; --teal-deep is the file's small-text-safe teal
   (5.5:1 on paper, and band--deep already remaps it to the bright #3FBFAD). */
.stack-card__tier {
  font-family: var(--font-mono); font-size: 10.5px; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--teal-deep);
}
.stack-card__title {
  font-family: var(--font-display); font-weight: 400;
  font-size: var(--step-4); line-height: 1; letter-spacing: -0.01em;
}
.stack-card__got { color: var(--muted); font-weight: 300; font-size: var(--step-0); line-height: 1.55; max-inline-size: 40ch; }
.stack-card__meta { font-size: var(--step--1); color: var(--muted-aa); }   /* read, not decoration */
.stack-card__cta {
  margin-top: 6px;
  display: inline-flex; align-items: center; gap: 8px;
  color: var(--ink); font-weight: 500; font-size: 14.5px;
}
.stack-card__cta .arr { transition: transform var(--dur-fast) var(--ease-out-quart); }
.stack-card:hover .stack-card__cta { color: var(--glow); }
.stack-card:hover .stack-card__cta .arr { transform: translateX(4px); }
@media (max-width: 767px) { .stack-card .bezel__core { min-height: 0; } }

/* ----------------------------------------------------------------------------
   12 · CONTACT LEDGER — label/value rows with hairlines
   --------------------------------------------------------------------------- */
.contact-ledger .row {
  display: flex; align-items: baseline; gap: 22px;
  padding-block: 15px;
  border-top: 1px solid var(--line);
  font-size: var(--step-0);
}
.contact-ledger .row:last-child { border-bottom: 1px solid var(--line); }
/* PHONE / EMAIL / HOURS — these name the value sitting next to them, so they are
   read, not decoration. --muted-2 measured 2.90:1 on the home page's light
   ground; --muted-aa is the same quiet grey that actually clears AA (5.2:1). */
.contact-ledger .label {
  font-family: var(--font-mono); font-size: 10.5px; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--muted-aa); min-width: 74px;
  transform: translateY(-2px);
}
.contact-ledger a {
  color: var(--ink); border-bottom: 1px solid var(--line);
  transition: border-color var(--dur-fast) var(--ease-out-quart), color var(--dur-fast) var(--ease-out-quart);
}
.contact-ledger a:hover { color: var(--glow); border-color: var(--brand); }
.contact-ledger .val { color: var(--muted); }

/* ----------------------------------------------------------------------------
   13 · FOOTER — the navy dark-guest closing band (markup in _nav-footer.html)
   .footer carries .band--deep itself: every shared token (ink/muted/line/
   brand/glow/burgundy) remaps to the navy context automatically, so this
   block only adds footer-specific layout — never raw hex.
   --------------------------------------------------------------------------- */
.footer {
  position: relative;
  overflow: hidden;
  padding-block: clamp(4.5rem, 8vh, 6.5rem) clamp(2rem, 4vh, 2.8rem);
}
/* faint navy-on-navy radial — the one restrained atmosphere cue, no photo, no noise beyond the global grain layer */
.footer::before {
  content: "";
  position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background:
    radial-gradient(60% 90% at 12% 0%, rgba(63,191,173,0.10), transparent 60%),
    radial-gradient(50% 70% at 100% 100%, rgba(192,85,118,0.09), transparent 60%);
}
.footer > .shell { position: relative; z-index: 1; }

/* -- closing moment: one editorial line + a single quiet CTA -- */
.footer__close {
  display: flex; align-items: center; justify-content: space-between; gap: 2rem;
  padding-bottom: clamp(2.4rem, 4.5vh, 3.4rem);
  border-bottom: 1px solid var(--line-soft);
  margin-bottom: clamp(2.6rem, 5vh, 3.6rem);
}
.footer__line {
  font-family: var(--font-display); font-weight: 400; font-style: normal;
  font-size: var(--step-3); line-height: 1.15; letter-spacing: -0.005em;
  color: var(--ink); max-inline-size: 30ch;
}
.footer__line em { font-style: italic; color: var(--glow); }
.footer__cta { flex: none; }

/* -- nav grid -- */
.footer__grid { display: grid; grid-template-columns: 1fr; gap: 2.6rem; }
@media (min-width: 820px) { .footer__grid { grid-template-columns: 1.6fr 1fr 1fr 1fr; gap: 2rem; } }
.footer__brand p { color: var(--muted); font-size: var(--step--1); max-inline-size: 34ch; margin-top: 14px; font-weight: 300; }
.footer__contact {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  margin-top: 16px; font-family: var(--font-mono); font-size: 12px; letter-spacing: 0.02em;
}
.footer__contact a { color: var(--muted); transition: color var(--dur-fast) var(--ease-out-quart); }
.footer__contact a:hover { color: var(--glow); }
.footer__contact span { color: var(--muted-2); }
.footer h4 {
  font-family: var(--font-mono); font-size: 10.5px; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--muted-2); margin-bottom: 16px; font-weight: 500;
}
.footer ul { list-style: none; display: flex; flex-direction: column; gap: 10px; }
.footer ul a, .footer ul span { color: var(--muted); font-size: 14px; transition: color var(--dur-fast) var(--ease-out-quart); }
.footer ul a:hover { color: var(--ink); }

/* -- coordinates + status rule -- */
.footer__rule {
  margin-top: clamp(2.6rem, 5vh, 4rem); padding-top: 1.6rem;
  border-top: 1px solid var(--line-soft);
  display: flex; justify-content: space-between; align-items: center; gap: 1rem 2rem; flex-wrap: wrap;
  font-family: var(--font-mono); font-size: 10.5px; letter-spacing: 0.1em;
  color: var(--muted-2); text-transform: uppercase;
}
.footer__status { display: inline-flex; align-items: center; gap: 9px; color: var(--muted-2); }
.footer__live-dot {
  width: 6px; height: 6px; border-radius: 50%; flex: none;
  background: var(--green);
  box-shadow: 0 0 0 0 rgba(95,212,51,0.55);
}

/* -- the rule yields to the floating chat launcher ---------------------------
   bally-chat.js pins `.bc` at right:22px / bottom:22px with a 60px circle, a
   pulse ring that scales to 1.32 (≈95px wide at peak → ~99px in from the right
   edge) and a soft drop shadow. MOVING the launcher sideways is the wrong
   direction: it is fixed to the viewport, so any offset that clears the footer
   would push it over content on some other page — measured at 390px, a mirrored
   bottom-LEFT slot lands on exactly the same elements. The footer yields
   instead. (bally-chat.js does now yield in TIME — it is absent over the first
   viewport and ducks while scrolling down — but this reserve must still hold
   for the at-rest state, so nothing here changes.)

   `.footer__rule` is the last line of every one of the 42 pages, and its right
   item — the "TAKING NEW BUILDS" live status — was landing inside that zone.
   Measured before the fix: the status text ends at the shell content edge, i.e.
   (100vw − ((100vw − --shell)/2 + --gutter)) — 10px clear of the circle at
   1440 (the pulse ring still swept over the final glyphs), and 31px UNDER the
   circle at 1280, which is where the /blog/ screenshot caught it.

   So reserve exactly the shortfall and no more: the natural gap between the
   shell content edge and the viewport edge already grows with the viewport, and
   past ~1480px it clears the launcher on its own — there the reserve resolves
   to 0px and the status keeps its original alignment. Padding is drawn INSIDE
   the border box, so the hairline still spans the full shell width; only the
   text moves. Below 641px the rule is a left-aligned column (see media query
   below) and the status already clears the launcher, so it is left untouched. */
:root { --fab-safe: 110px; }   /* launcher footprint incl. pulse ring + optical gap */
@media (min-width: 641px) {
  .footer__rule {
    padding-inline-end: max(0px, calc(var(--fab-safe)
                        - (100vw - min(100vw, var(--shell))) / 2
                        - var(--gutter)));
  }
}

@media (max-width: 640px) {
  .footer__close { flex-direction: column; align-items: flex-start; gap: 1.4rem; }
  .footer__line { font-size: var(--step-2); }
  .footer__rule { flex-direction: column; align-items: flex-start; gap: 10px; }
}

/* ----------------------------------------------------------------------------
   14 · REVEALS — initial hidden state is set by JS only (no-JS users see all)
   --------------------------------------------------------------------------- */
.reveal { will-change: transform, opacity; }

/* ----------------------------------------------------------------------------
   15 · .band--cream — Set B "Editorial Cream + Teal" context override
   Add to any <section> for the warm-light rest band. All shared components
   (eyebrow, h-display, bezel, buttons, ledger) restyle automatically.
   Rules: headlines --teal-deep · CTAs --brand w/ cream text ·
          brass --accent decorative-scale ONLY (use --accent-body at body size).
   --------------------------------------------------------------------------- */
/* Light-led now → .band--cream is a near-default light REST band (a hair warmer/
   raised than paper). Harmless: it no longer flips the ground dark. Emphasis em
   goes BURGUNDY here for the one premium accent moment. Seams retired. */
.band--cream {
  --paper:      #FCFCFA;                    /* elevated light rest ground */
  --wash:       #FFFFFF;                    /* crisp raised card */
  --wash-deep:  #EEF1F4;
  --ink:        #141A24;
  --muted:      #5A6270;
  --muted-2:    #8A93A0;
  --muted-aa:   #5F6879;   /* completes the ground contract. --muted-aa means "the quiet grey that clears AA
                              on THIS ground", so every ground context must state it — :root and .band--deep
                              already do. .band--cream is LIGHT, so the value matches :root and nothing changes
                              today (verified: 0 .band--cream-inside-.band--deep nestings across all 64 routes).
                              Declaring it anyway closes the trap: the first cream band nested in a deep band
                              would otherwise inherit the navy #8C96A8 and go faint on cream, which is exactly
                              the failure --muted-aa exists to prevent. 5.18:1 on #FCFCFA. */
  --line:       rgba(20,26,36,0.12);
  --line-soft:  rgba(20,26,36,0.06);
  background: var(--paper);
  color: var(--ink);
}
.band--cream ::selection { background: rgba(28,139,124,0.20); color: var(--ink); }
.band--cream .h-display em { color: var(--burgundy); }   /* the deliberate burgundy emphasis moment */
.band--cream .bezel__core {
  background: var(--wash);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.9), 0 30px 60px -28px rgba(20,26,36,0.18);
}
/* chip — badge-scale accent, now BURGUNDY (brass retired) */
.chip-warm {
  color: var(--burgundy);
  border: 1px solid color-mix(in oklab, var(--burgundy) 40%, transparent);
  background: var(--accent-dim);
  padding: 4px 10px; border-radius: 999px;
  font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.14em;
}

/* ----------------------------------------------------------------------------
   15a2 · .band--burgundy — warm-light accent band, a visibly tinted step up
   from .band--cream (which stayed intentionally near-default, see above) and
   lighter-touch than .band--deep (which stays capped at one per page). Use
   for a section that wants real color presence without going full dark —
   a pricing panel, a stat strip, a pull-quote. Ink stays the same dark
   value as cream so contrast is unaffected by the tint. Hex literals, not
   color-mix(), for the same reason .band--cream/.band--deep use them: a
   computed color-mix() resolves to oklab() in getComputedStyle, which the
   contrast auditor's rgb() parser skips.
   --------------------------------------------------------------------------- */
.band--burgundy {
  --paper:      #F7EEEF;
  --wash:       #FFFFFF;
  --wash-deep:  #F0E1E4;
  --ink:        #141A24;
  --muted:      #6B5560;
  --muted-2:    #9B838C;
  --muted-aa:   #6B5560;
  --line:       rgba(124,45,72,0.16);
  --line-soft:  rgba(124,45,72,0.07);
  --accent:     var(--burgundy);
  --accent-body: var(--burgundy);
  background: var(--paper);
  color: var(--ink);
}
.band--burgundy ::selection { background: rgba(124,45,72,0.20); color: var(--ink); }
.band--burgundy .h-display em { color: var(--burgundy); }
.band--burgundy .bezel__core {
  background: var(--wash);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.9), 0 30px 60px -28px rgba(124,45,72,0.16);
}

/* 15a3 · .cta-seal — the mark itself, faint, behind a closing CTA's headline.
   Sits as a sibling right after a *__halo glow div so it paints above the
   glow's gradient and below the normal-flow text (both share z-index:-1;
   DOM order breaks the tie). Never interactive, never announced. */
.cta-seal {
  position: absolute; right: clamp(1rem, 4vw, 3.5rem); bottom: clamp(0.5rem, 3vw, 2rem);
  width: min(120px, 16vw); aspect-ratio: 1; opacity: 0.5;
  pointer-events: none; z-index: 0; user-select: none;
}

/* 15a4 · .orb-field — soft blurred colour orbs that drift slowly behind a dark
   section. transform + opacity only (GPU, no layout thrash), one shared
   keyframe set. Give the host element position:relative and overflow:hidden
   or clip so the blur doesn't bleed past the section edge. */
.orb-field { position: absolute; inset: 0; overflow: hidden; pointer-events: none; z-index: 0; }
.orb-field .orb { position: absolute; border-radius: 50%; filter: blur(60px); will-change: transform; }
.orb-field .orb--burgundy {
  width: 42vw; height: 42vw; max-width: 560px; max-height: 560px; left: -12%; top: -10%;
  background: radial-gradient(circle, var(--burgundy) 0%, transparent 70%);
  opacity: 0.32; animation: orbDrift1 26s ease-in-out infinite;
}
.orb-field .orb--teal {
  width: 36vw; height: 36vw; max-width: 480px; max-height: 480px; right: -10%; top: 22%;
  background: radial-gradient(circle, var(--glow) 0%, transparent 70%);
  opacity: 0.30; animation: orbDrift2 32s ease-in-out infinite;
}
.orb-field .orb--green {
  width: 28vw; height: 28vw; max-width: 380px; max-height: 380px; left: 32%; bottom: -14%;
  background: radial-gradient(circle, #5FD433 0%, transparent 70%);
  opacity: 0.18; animation: orbDrift3 38s ease-in-out infinite;
}
@keyframes orbDrift1 { 0%,100% { transform: translate(0,0) scale(1); } 50% { transform: translate(6%, 8%) scale(1.08); } }
@keyframes orbDrift2 { 0%,100% { transform: translate(0,0) scale(1); } 50% { transform: translate(-8%, -6%) scale(0.94); } }
@keyframes orbDrift3 { 0%,100% { transform: translate(0,0) scale(1); } 50% { transform: translate(5%, -7%) scale(1.1); } }
@media (prefers-reduced-motion: reduce) { .orb-field .orb { animation: none !important; } }

/* ----------------------------------------------------------------------------
   15b · .band--deep — NAVY dark-guest context (the one dark band per page:
   a hero band, stat strip, or footer). Remaps every token to the navy ground
   with brighter accents so shared components (eyebrow, h-display, bezel, buttons,
   ledger, footer) restyle automatically. Use SPARINGLY — one per page.
   --------------------------------------------------------------------------- */
.band--deep {
  --paper:      #16263F;                    /* navy ground */
  --paper-2:    #1F3253;
  --surface:    #1F3253;                    /* lifted navy card */
  --wash:       #1F3253;
  --wash-deep:  #142440;
  --ink:        #F3F5F8;                    /* light text on navy */
  --muted:      #AEB9CB;
  --muted-2:    #8C96A8;   /* lifted from #7E8A9C — 4.3:1 → 5.1:1 on navy, clears AA for the footer's mono micro-labels */
  --muted-aa:   #8C96A8;   /* --muted-aa means "the quiet grey that clears AA on THIS ground". On navy that is
                              #8C96A8 (5.1:1); the light-ground #5F6879 would be near-invisible here. Redefining
                              it once keeps every --muted-aa component ground-aware without per-rule overrides. */
  --line:       rgba(243,245,248,0.14);
  --line-soft:  rgba(243,245,248,0.07);
  /* brighter accents on the dark ground */
  --teal:       #3FBFAD;
  --teal-deep:  #3FBFAD;
  --brand:      #2FB0A0;
  --glow:       #4CCBB8;
  --burgundy:   #C05576;
  --burgundy-2: #D06A88;
  --accent:     #C05576;
  --accent-body:#C05576;
  --brand-glow:  color-mix(in oklab, var(--glow) 40%, transparent);
  --brand-raise: color-mix(in oklab, var(--brand) 86%, #ffffff 14%);
  --accent-dim:  color-mix(in oklab, var(--accent) 20%, transparent);
  --glass:       rgba(243,245,248,0.05);
  --glass-line:  rgba(243,245,248,0.14);
  --scrim:       11,17,27;                  /* navy-black for scrims on dark */
  background: var(--paper);
  color: var(--ink);
}
.band--deep ::selection { background: rgba(76,203,184,0.28); color: var(--ink); }
.band--deep .bezel__core {
  background: var(--surface);
  box-shadow: inset 0 1px 0 rgba(243,245,248,0.06), 0 30px 60px -24px rgba(0,0,0,0.5);
}
/* green stays the attention CTA on navy; navy .btn--ink flips to a light fill */
.band--deep .btn--ink { background: var(--ink-inv); color: var(--navy); }
.band--deep .btn--ink .ic { background: rgba(20,26,36,0.12); }

/* ----------------------------------------------------------------------------
   16 · PERFORMANCE + REDUCED-MOTION GUARDRAILS (do not remove)
   · animate transform/opacity/filter only · backdrop-blur on fixed/sticky only
   · grain is one fixed pointer-events-none layer · DPR capped in motion engine
   --------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  .marquee__track { animation: none; }
  .marquee { -webkit-mask-image: none; mask-image: none; overflow-x: auto; }
}

/* ============================================================
   AI-FEEL GLOW ACCENTS (additive · safe · all pages) — 2026-07-20
   Subtle premium glow signalling "the AI is live". Filter/text-shadow/
   hover only; no layout changes; reduced-motion safe.
   ============================================================ */
@keyframes bd-livepulse { 0%,100% { box-shadow: 0 0 0 0 rgba(63,191,173,.55); } 50% { box-shadow: 0 0 0 5px rgba(63,191,173,0); } }
@media (prefers-reduced-motion: no-preference) {
  .nav-pill__live-dot, [class*="live-dot"], [class*="__live"] { animation: bd-livepulse 2.4s ease-in-out infinite; }
}
.btn--call, .btn--ink, .btn--primary, .nav-pill__cta {
  filter: drop-shadow(0 6px 18px rgba(30,138,124,.28));
  transition: filter .25s cubic-bezier(.32,.72,0,1), transform .2s cubic-bezier(.32,.72,0,1);
}
.btn--call:hover, .btn--ink:hover, .btn--primary:hover, .nav-pill__cta:hover {
  filter: drop-shadow(0 10px 26px rgba(63,191,173,.5));
}
h1 em, h2 em, .hero-em, .accent, [class*="__accent"] { text-shadow: 0 0 28px rgba(63,191,173,.26); }
.bezel { transition: box-shadow .3s cubic-bezier(.32,.72,0,1), transform .3s cubic-bezier(.32,.72,0,1), border-color .3s ease; }
.bezel:hover { box-shadow: 0 0 0 1px rgba(63,191,173,.25), 0 24px 60px -24px rgba(30,138,124,.45); transform: translateY(-2px); }
@media (prefers-reduced-motion: reduce) { .bezel:hover { transform: none; } }

/* ============================================================================
   17 · BLOG POST HEADER — readable meta (repairs all 9 /blog/<slug>/ pages)
   ----------------------------------------------------------------------------
   The .pa-* header styles live in a <style> block inside each post, which the
   browser reads AFTER this stylesheet — so these overrides carry one extra
   class (.pa-hero, which wraps all of them) to win on specificity rather than
   order. Nine files, one defect each; fixing it here fixes all nine at once and
   keeps any post generated later correct by default.

   What was wrong (measured on painted pixels, not declared values):
     a.pa-back / .pa-meta   var(--muted-2) #8A93A0 → 2.87:1 on --paper
     span.pa-meta__cat      var(--brand)   #1C8B7C → 3.85:1 on --paper
   Both are the two failure patterns the token block already names: --muted-2 is
   DECORATIVE ONLY (faint mono numbering), and the teal is too light at small
   sizes. The repair is the token that exists for exactly this — --muted-aa
   (5.2:1 on paper) and --teal-deep (5.7:1), both of which are STILL quieter
   than the deck (--muted 5.7:1) and far quieter than the headline (--ink ~15:1).

   DELIBERATELY LEFT ALONE — these are decoration, not text:
     .pa-meta__dot   3px aria-hidden separator painted in --muted-2
     .pa-hero__halo  radial teal wash behind the headline
   The byline LINK ("Hunter Ballantyne") already sits at --muted (5.7:1) and is
   untouched: the hierarchy headline → deck → meta, and the "the name is the
   link" cue inside the meta line, both survive this change intact.
   ========================================================================== */
.pa-hero .pa-back          { color: var(--muted-aa); }
.pa-hero .pa-back:hover    { color: var(--teal-deep); }
.pa-hero .pa-meta          { color: var(--muted-aa); }
.pa-hero .pa-meta a:hover  { color: var(--teal-deep); }
.pa-hero .pa-meta__cat     { color: var(--teal-deep); }

/* ==========================================================================
   §18 · BLOG POST PROSE LINKS — the same too-light-teal defect as §17, one
   level down the page. .prose p a / .prose li a paint --glow #1C8B7C, which
   is 3.85:1 on --paper: under AA for body copy, and this is the most-read
   text on the site. --teal-deep #146E62 is the file's small-text-safe teal
   (5.7:1) and is already what §17 uses for the meta category and hovers, so
   the post reads as one system rather than two greens.

   Specificity note: the post styles live in a per-page <style> block the
   browser reads AFTER this sheet, so document order loses. Their rule is
   `.prose p a, .prose li a` = (0,1,2); `.pa-article .prose a` = (0,2,1)
   wins on class count. All 9 /blog/<slug>/ posts carry .pa-article.

   The underline is kept and its colour tracks the text at 55% so the link
   still reads as a link, just at a weight the eye can actually resolve.
   ========================================================================== */
.pa-article .prose a        { color: var(--teal-deep); text-decoration-color: rgba(20,110,98,0.55); }
.pa-article .prose a:hover  { text-decoration-color: var(--teal-deep); }

/* ==========================================================================
   CHAPTER HOOK — the page-to-page connective tissue.

   The site is meant to read as ONE numbered story: 01 home -> 02 the AI ->
   03 the website -> 04 pricing -> 05 the work -> 06 book -> 07 about, with
   the side chapters (demo, vs, faq, blog, marketing, automation) feeding
   back into the spine. Every page ends by handing the visitor forward.

   This component was authored four separate times as .next-hook (home),
   .wk-hook (work), .pl-hook (pricing) and .wsp-hook (website) — identical
   markup and near-identical rules, each scoped to one page. That is why the
   other seven pages simply had no hook: there was no shared component to
   reach for. It lives here now so any page can drop in the markup and get
   the chapter hook for free.

   Pure tokens, so it inverts correctly inside .band--deep (navy) without a
   second rule. The trailing arrow is the nested button-in-button treatment
   used across the site, not a naked glyph.
   ========================================================================== */
.next-hook__wrap { margin-top: clamp(2.4rem, 5vh, 3.4rem); display: flex; justify-content: center; }
.next-hook {
  display: inline-flex; align-items: center; gap: 16px;
  padding: 14px 16px 14px 22px; border-radius: 999px;
  background: var(--glass); border: 1px solid var(--line);
  transition: border-color var(--dur-fast) var(--ease-out-quart),
              background var(--dur-fast) var(--ease-out-quart),
              transform var(--dur-fast) var(--ease-out-quart);
}
.next-hook:hover { border-color: rgba(28,139,124,0.4); background: rgba(28,139,124,0.07); transform: translateY(-1px); }
.next-hook .step { font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--muted-2); }
.next-hook .lbl  { font-size: 14.5px; color: var(--ink); font-weight: 500; }
.next-hook .lbl b { color: var(--teal-deep); font-weight: 600; }
.next-hook .arr {
  width: 2rem; height: 2rem; border-radius: 999px; flex: none; display: grid; place-items: center;
  background: rgba(28,139,124,0.12); color: var(--teal-deep);
  transition: transform var(--dur-fast) var(--ease-out-quart);
}
.next-hook:hover .arr { transform: translateX(3px); }

@media (max-width: 767px) {
  .next-hook { flex-wrap: wrap; gap: 10px 14px; padding: 16px 18px; }
}
/* Motion is a nicety; the hook must never move for someone who asked it not to. */
@media (prefers-reduced-motion: reduce) {
  .next-hook, .next-hook .arr { transition: none; }
  .next-hook:hover { transform: none; }
  .next-hook:hover .arr { transform: none; }
}
