@layer myrmid.core, myrmid.tokens, myrmid.foundation, myrmid.components;
/* ──────────────────────────────────────────────────────────────────────────
   tokens/index.css — single entry point for landing-page's CSS cascade.
   PostCSS resolves these @import directives at build time (postcss-import),
   so dist/tokens.css is a single concatenated file with NO runtime @import
   chain. See architecture.md §Token File Organization (lines 537–550).

   Migrated 2026-05-29; repointed 2026-06-07 to the @myrmid/brand layer of the
   v0.5.0 workspace split. Brand tokens (color, type, space + foundation's
   motion, self-resolving) and the brand foundation primitives (layout-base,
   stigmergy, cta-interaction) now ship from @myrmid/brand. Brand wraps its
   output in cascade layers (@layer myrmid.core/tokens/foundation/components);
   landing-page's own CSS below stays UNLAYERED and therefore wins over every
   myrmid.* layer (the intended consumer model). The landing-page-specific
   supplements (site-chrome.css, crosslinks.css) load alongside the foundation
   files they extend.
   ────────────────────────────────────────────────────────────────────────── */
/* Brand tokens — color + space + type + motion (light + dark, locale-aware) */
@layer myrmid.core {
:root {
  --myr-core: 3f755db03c719af3;
}
/* ──────────────────────────────────────────────────────────────────────────
   color-tokens.css — three-axis colour system, two-layer per Story 1.3 D1.

   Axes:        --color-{mode}-{aspect}-{surface}
                  mode    ∈ { light, dark }                        (data-theme on <html>)
                  aspect  ∈ { primary, secondary, accent, surface, text, border }
                  surface ∈ { base, enterprise, smb, developer, manifesto, dpp }

   Foundation (Core) now ships ONLY the raw axis tokens. The semantic colour
   aliases (--surface-page, --ink-primary, --accent-eu-blue, …) live per-channel
   — @myrmid/brand declares the editorial values, @myrmid/app the dense values,
   both as var(--color-…) over these raw axes (Story 2.2, architecture AR-9).

   Source-of-truth values: _bmad-output/implementation-artifacts/manifesto-preview.html
   (Tom-signed canonical visual reference — UX line 551).

   Mode resolution priority (architecture.md §Theme Detection 619–627):
     1. localStorage.theme  → :root[data-theme="dark"|"light"]
     2. prefers-color-scheme → @media block (only if user hasn't forced light)
     3. light (canonical fallback baked into :root)

   Story 1.3 declares ONLY the (aspect × surface) cells the manifesto-preview
   actually uses. Aspect drift (enterprise / smb / developer / dpp) lands in
   Stories 2.x / 3.x as those surfaces are built. Don't backfill.
   ────────────────────────────────────────────────────────────────────────── */

/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Light mode — canonical fallback. Raw axis tokens.                      │
   └────────────────────────────────────────────────────────────────────────┘ */
:root {
  /* Native form controls / scrollbars match the active theme.
     Without this declaration browsers render scrollbars in their default
     light styling under data-theme="dark" — visible white slab on the page. */
  color-scheme: light dark;

  /* — surface aspect — */
  --color-light-surface-base:      #F6F6F5;  /* whitish-white substrate */
  --color-light-surface-card:      #FAFAFA;

  /* — text aspect — */
  --color-light-text-base:         #1C1C20;  /* anthracite, near-black */
  --color-light-text-secondary:    #4A4A52;
  --color-light-text-quiet:        #717178;

  /* — border aspect — */
  --color-light-border-quiet:      #E4E4E2;

  /* — accent aspect (structural-only — never on type fills) — */
  --color-light-accent-eu-blue:    #1B2D5C;  /* EU sovereign blue */
  --color-light-accent-eu-gold:    #A07C2C;  /* EU gold, AA-clean */
  --color-light-accent-eu-gold-foil: #C9A24A;  /* EU gold decorative */
  --color-light-accent-primary:    var(--color-light-accent-eu-blue);

  /* — secondary aspect (metallic finishes, structural-only) — */
  --color-light-secondary-platine: #B0B5BD;
  --color-light-secondary-steel:   #8A8E9A;

  /* — primary aspect — brand-mark channels, B&W mode-adaptive — */
  --color-light-primary-brand-bg:  #1C1C20;
  --color-light-primary-brand-fg:  #F6F6F5;

  /* — stigmergy texture (substrate dot-grid + waypoint marks + trails) — */
  --color-light-surface-grid-dot:  rgba(28, 28, 32, 0.07);
}

/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Dark mode — explicit user toggle (data-theme="dark") wins outright.    │
   │ Redeclares the raw axis tokens; channels redeclare their own aliases.  │
   └────────────────────────────────────────────────────────────────────────┘ */
:root[data-theme="dark"] {
  /* Pin native form controls / scrollbars to dark even when OS prefers light. */
  color-scheme: dark;

  --color-dark-surface-base:        #141414;  /* deep anthracite */
  --color-dark-surface-card:        #1C1C20;

  --color-dark-text-base:           #F0F0EE;  /* whitish-white, off-neutral */
  --color-dark-text-secondary:      #C4C4C6;
  --color-dark-text-quiet:          #888890;

  --color-dark-border-quiet:        #282828;

  --color-dark-accent-eu-blue:      #5D78B5;  /* lighter signal in dark */
  --color-dark-accent-eu-gold:      #D9B65C;
  --color-dark-accent-eu-gold-foil: #E0C77A;
  --color-dark-accent-primary:      var(--color-dark-accent-eu-gold);

  --color-dark-secondary-platine:   #5A5A62;
  --color-dark-secondary-steel:     #484850;

  --color-dark-primary-brand-bg:    #F0F0EE;
  --color-dark-primary-brand-fg:    #1C1C20;

  --color-dark-surface-grid-dot:    rgba(240, 240, 238, 0.05);
}

/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Dark mode — system preference, only when user hasn't forced light.    │
   │ Same raw axis tokens as the explicit branch above.                    │
   └────────────────────────────────────────────────────────────────────────┘ */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;

    --color-dark-surface-base:        #141414;
    --color-dark-surface-card:        #1C1C20;

    --color-dark-text-base:           #F0F0EE;
    --color-dark-text-secondary:      #C4C4C6;
    --color-dark-text-quiet:          #888890;

    --color-dark-border-quiet:        #282828;

    --color-dark-accent-eu-blue:      #5D78B5;
    --color-dark-accent-eu-gold:      #D9B65C;
    --color-dark-accent-eu-gold-foil: #E0C77A;
    --color-dark-accent-primary:      var(--color-dark-accent-eu-gold);

    --color-dark-secondary-platine:   #5A5A62;
    --color-dark-secondary-steel:     #484850;

    --color-dark-primary-brand-bg:    #F0F0EE;
    --color-dark-primary-brand-fg:    #1C1C20;

    --color-dark-surface-grid-dot:    rgba(240, 240, 238, 0.05);
  }
}

/* ──────────────────────────────────────────────────────────────────────────
   space-tokens.css — spacing scale. Mode axis irrelevant for spacing;
   single layer suffices.

   Raw axis layer:    --space-base-{1..7}  (canonical scale)

   The semantic alias layer (--space-{1..7}) now lives per-channel — brand and
   app each declare --space-N as var(--space-base-N) over this raw axis
   (Story 2.2). Foundation ships the raw scale only.

   Source-of-truth values: manifesto-preview.html lines 55–61.
   ────────────────────────────────────────────────────────────────────────── */

:root {
  /* — raw axis layer — */
  --space-base-1: 0.5rem;
  --space-base-2: 1rem;
  --space-base-3: 1.5rem;
  --space-base-4: 2rem;
  --space-base-5: 3rem;
  --space-base-6: 4.5rem;
  --space-base-7: 6.5rem;
}

/* ──────────────────────────────────────────────────────────────────────────
   type-tokens.css — three-axis typography system, two-layer per Story 1.3 D1.

   Raw axis layer:  --type-{mode}-text-{surface}, --type-size-*, --type-weight-*,
                    --type-line-height-*. Mode axis here mostly tweaks weight/
                    tracking to compensate for substrate contrast; full mode
                    drift lands when actual surfaces consume it.
   Core font aliases: the sans + mono spine (--font-sans, --font-mono) — shared
                     by every channel, so they stay in Core. The editorial
                     serif (--font-serif), reading measure (--measure), and the
                     editorial-serif @font-face faces moved to @myrmid/brand
                     (Story 2.2).

   Per-locale micro-adjustments (German tracking, French line-height) are
   placeholder-stubbed; Story 2.5 (locale switcher) wires lang-attribute
   selectors. NO live html[lang="…"] selectors at this story.

   Source-of-truth values: manifesto-preview.html lines 50–52, 282–303.
   ────────────────────────────────────────────────────────────────────────── */

:root {
  /* — raw axis layer: text aspect (mode dimension) — */
  --type-light-text-base:       400;   /* regular weight, light substrate */
  --type-dark-text-base:        400;   /* same — anthracite ink unchanged */

  /* — raw axis layer: typographic scale — */
  --type-size-h1-base:          clamp(2rem, 6vw, 3.25rem);
  --type-size-body-base:        1.0625rem;        /* 17px mobile */
  --type-size-body-comfortable: 1.125rem;         /* ≥768px */
  --type-size-eyebrow-base:     0.75rem;
  --type-size-meta-base:        0.8125rem;
  --type-size-small-base:       0.875rem;

  --type-weight-regular:        400;
  --type-weight-medium:         500;
  --type-weight-semibold:       600;

  --type-line-height-tight:     1.12;
  --type-line-height-base:      1.65;
  --type-line-height-loose:     1.7;

  /* — Core font aliases: the sans + mono spine (system-font fallback chain
       backs the @font-face declarations below). The editorial serif
       (--font-serif) lives in @myrmid/brand. — */
  --font-sans:  "Geist Sans", system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-mono:  "Geist Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
}

/* ──────────────────────────────────────────────────────────────────────────
   Self-hosted WOFF2 declarations — Story 1.4 D2 path (a). UX-DR8.

   • Geist Sans (regular, medium, semibold) — SIL OFL 1.1, Vercel/basement.studio;
     procured from vercel/geist-font 2026-06-07 (Story 2.1).
   • Geist Mono (regular)                 — SIL OFL 1.1, Vercel/basement.studio.

   The editorial serif and its three @font-face blocks moved to @myrmid/brand
   (Story 2.2) — Core ships only the sans + mono spine.

   Operational notes:
   • font-display: swap — system-fallback renders immediately, WOFF2 swaps in
     when ready. Avoids invisible-text FOUT.
   • License trail: public/fonts/LICENSE.md (OFL bundling clause for the Geist
     families).
   • <link rel="preload" as="font" type="font/woff2" crossorigin> tags for
     each face are emitted by templates/layouts/base-layout.eta.
   ────────────────────────────────────────────────────────────────────────── */
@font-face {
  font-family: "Geist Sans";
  src: url("/fonts/geist-sans-regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Geist Sans";
  src: url("/fonts/geist-sans-medium.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Geist Sans";
  src: url("/fonts/geist-sans-semibold.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Geist Mono";
  src: url("/fonts/geist-mono-regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Per-locale micro-adjustments — Story 2.5.                             │
   ├────────────────────────────────────────────────────────────────────────┤
   │ German compound words pack tightly; a -0.01em tracking nudge keeps    │
   │ heading rhythm honest without compressing body legibility (AC: "DE    │
   │ type tokens use slightly tighter tracking to accommodate compound     │
   │ words"). Tracking applies via --type-tracking-tight which heading-    │
   │ level CSS consumers reference; body type stays at the default 0.     │
   │                                                                        │
   │ French diacritics ride high; bumping --type-line-height-loose from   │
   │ 1.7 → 1.75 prevents accent ascenders colliding with the descender    │
   │ row above (AC: "FR type tokens use slightly looser line-height to    │
   │ accommodate diacritics"). Body and prose blocks consume --type-      │
   │ line-height-loose at ≥768px (layout-base.css) so the lift lands      │
   │ where diacritic stacking is densest.                                  │
   └────────────────────────────────────────────────────────────────────────┘ */
:root {
  /* Default tracking (used by headings; consumers opt in). */
  --type-tracking-tight: 0;
}
html[lang="de"] {
  --type-tracking-tight: -0.01em;
}
html[lang="fr"] {
  --type-line-height-loose: 1.75;
}

/* ──────────────────────────────────────────────────────────────────────────
   motion-tokens.css — motion durations + easings, with the AC4
   reduced-motion gate at the token layer (UX line 423).

   Raw axis layer:    --motion-duration-* + --motion-easing-*
   Semantic aliases:  --motion-quick, --motion-base, --easing
                       (preserves manifesto-preview's component CSS unchanged)

   Source-of-truth values: manifesto-preview.html lines 63–66, 146–152.

   Reduced-motion gate operates in two layers:
     1. Token-layer override (spec-mandated) — re-resolves duration tokens to
        0ms when prefers-reduced-motion: reduce. Aliases inherit via var().
     2. Global escape hatch — defends against any third-party / not-yet-
        tokenized CSS by zeroing every transition-duration / animation-duration.
   ────────────────────────────────────────────────────────────────────────── */

:root {
  /* — raw axis layer — */
  --motion-duration-quick: 120ms;
  --motion-duration-base:  200ms;
  /* Story 2.8 — scroll-cue ant pulse uses --motion-duration-slow as the
     full breathing cycle (opacity 0.55↔0.85, scale 1.0↔1.06). The exit
     easing decelerates the fade-out when the visitor scrolls past the
     hero — easeIn shape so the ant disappears decisively rather than
     lingering. */
  --motion-duration-slow:  600ms;
  --motion-easing-base:    cubic-bezier(0.2, 0, 0, 1);
  --motion-easing-exit:    cubic-bezier(0.4, 0, 1, 1);

  /* — semantic alias layer — */
  --motion-quick: var(--motion-duration-quick);
  --motion-base:  var(--motion-duration-base);
  --motion-slow:  var(--motion-duration-slow);
  --easing:       var(--motion-easing-base);
  --easing-exit:  var(--motion-easing-exit);
}

/* AC4 — reduced-motion at the token layer.
   Aliases above inherit via var(), so redeclaring the raw axis tokens here
   collapses every alias-consumer's transition to 0ms automatically. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --motion-duration-quick: 0ms;
    --motion-duration-base:  0ms;
    --motion-duration-slow:  0ms;
  }
}

/* Global escape hatch — defends against any rule that hardcodes durations
   (third-party CSS, or component CSS that hasn't yet been migrated to tokens).
   Belt-and-braces with the token-layer override above; both intentional.

   Zeroing duration alone is not enough: a 5s-delayed animation still fires
   visibly, and an `iteration-count: infinite` animation with duration 0 can
   wedge the rendering thread on some engines. Override delays + clamp
   iteration to 1 alongside duration. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    transition-duration: 0ms !important;
    transition-delay:    0ms !important;
    animation-duration:  0ms !important;
    animation-delay:     0ms !important;
    animation-iteration-count: 1 !important;
  }
}

}
@layer myrmid.tokens {
/* ──────────────────────────────────────────────────────────────────────────
   color-tokens.css (brand channel) — editorial semantic colour aliases.

   These are the semantic vocabulary consumed by brand component CSS
   (--surface-page, --ink-primary, --accent-eu-blue, …). Each alias resolves to
   a raw axis token owned by @myrmid/foundation (--color-{mode}-{aspect}-{surface}).
   Brand's build feeds the emitter [foundation raw tokens, THEN these aliases],
   so the var() chains resolve per-mode against the inlined foundation raw.

   Values ARE the current (editorial / manifesto) palette — brand is the public
   landing/blog/team-store identity. App (Story 2.3) declares the SAME alias
   NAMES with dense/functional values; brand⇄app key parity is what the Epic-3
   contract test (3.3) enforces (architecture AR-9).

   Mode resolution mirrors foundation's three-branch structure:
     1. :root[data-theme="dark"]                       (explicit toggle)
     2. @media (prefers-color-scheme: dark) :root:not([data-theme="light"])
     3. :root                                            (light, canonical)
   ────────────────────────────────────────────────────────────────────────── */

/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Light mode — canonical fallback. Aliases over light raw axis.          │
   └────────────────────────────────────────────────────────────────────────┘ */
:root {
  /* ── Semantic aliases — manifesto-preview vocabulary ── */
  --surface-page:        var(--color-light-surface-base);
  --surface-card:        var(--color-light-surface-card);
  --rule-quiet:          var(--color-light-border-quiet);

  --ink-primary:         var(--color-light-text-base);
  --ink-secondary:       var(--color-light-text-secondary);
  --ink-quiet:           var(--color-light-text-quiet);

  --accent-eu-blue:      var(--color-light-accent-eu-blue);
  --accent-eu-gold:      var(--color-light-accent-eu-gold);
  --accent-eu-gold-foil: var(--color-light-accent-eu-gold-foil);
  --accent-primary:      var(--color-light-accent-primary);

  --metal-platine:       var(--color-light-secondary-platine);
  --metal-steel:         var(--color-light-secondary-steel);

  --brand-bg:            var(--color-light-primary-brand-bg);
  --brand-fg:            var(--color-light-primary-brand-fg);

  --grid-dot:            var(--color-light-surface-grid-dot);
  --trail-stroke:        var(--rule-quiet);
  --waypoint-fill:       var(--accent-primary);

  /* Text colour for content painted on --accent-primary fills (CTAs etc.).
     White on EU blue clears 8.6:1 (WCAG AAA). Decoupled from --surface-page
     because the surface alias may not always invert the accent. */
  --ink-on-accent:       #FFFFFF;
}

/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Dark mode — explicit user toggle (data-theme="dark") wins outright.    │
   │ Aliases re-bind to dark-side raw tokens.                               │
   └────────────────────────────────────────────────────────────────────────┘ */
:root[data-theme="dark"] {
  --surface-page:        var(--color-dark-surface-base);
  --surface-card:        var(--color-dark-surface-card);
  --rule-quiet:          var(--color-dark-border-quiet);

  --ink-primary:         var(--color-dark-text-base);
  --ink-secondary:       var(--color-dark-text-secondary);
  --ink-quiet:           var(--color-dark-text-quiet);

  --accent-eu-blue:      var(--color-dark-accent-eu-blue);
  --accent-eu-gold:      var(--color-dark-accent-eu-gold);
  --accent-eu-gold-foil: var(--color-dark-accent-eu-gold-foil);
  --accent-primary:      var(--color-dark-accent-primary);

  --metal-platine:       var(--color-dark-secondary-platine);
  --metal-steel:         var(--color-dark-secondary-steel);

  --brand-bg:            var(--color-dark-primary-brand-bg);
  --brand-fg:            var(--color-dark-primary-brand-fg);

  --grid-dot:            var(--color-dark-surface-grid-dot);
  /* --trail-stroke and --waypoint-fill chain via their own aliases — no redeclare. */

  /* On dark, --accent-primary becomes EU gold; deep anthracite text on EU
     gold clears 8.5:1 (WCAG AAA). */
  --ink-on-accent:       #1C1C20;
}

/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Dark mode — system preference, only when user hasn't forced light.    │
   │ Same aliases as the explicit branch above.                            │
   └────────────────────────────────────────────────────────────────────────┘ */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --surface-page:        var(--color-dark-surface-base);
    --surface-card:        var(--color-dark-surface-card);
    --rule-quiet:          var(--color-dark-border-quiet);

    --ink-primary:         var(--color-dark-text-base);
    --ink-secondary:       var(--color-dark-text-secondary);
    --ink-quiet:           var(--color-dark-text-quiet);

    --accent-eu-blue:      var(--color-dark-accent-eu-blue);
    --accent-eu-gold:      var(--color-dark-accent-eu-gold);
    --accent-eu-gold-foil: var(--color-dark-accent-eu-gold-foil);
    --accent-primary:      var(--color-dark-accent-primary);

    --metal-platine:       var(--color-dark-secondary-platine);
    --metal-steel:         var(--color-dark-secondary-steel);

    --brand-bg:            var(--color-dark-primary-brand-bg);
    --brand-fg:            var(--color-dark-primary-brand-fg);

    --grid-dot:            var(--color-dark-surface-grid-dot);

    --ink-on-accent:       #1C1C20;
  }
}

/* ──────────────────────────────────────────────────────────────────────────
   space-tokens.css (brand channel) — spacing semantic aliases.

   Semantic alias layer (--space-{1..7}) over @myrmid/foundation's raw axis
   (--space-base-{1..7}). Mode axis is irrelevant for spacing; single layer.
   App (Story 2.3) declares the same --space-N names; values may diverge.

   Source-of-truth values: manifesto-preview.html lines 55–61.
   ────────────────────────────────────────────────────────────────────────── */

:root {
  /* — semantic alias layer (manifesto-preview vocabulary) — */
  --space-1: var(--space-base-1);
  --space-2: var(--space-base-2);
  --space-3: var(--space-base-3);
  --space-4: var(--space-base-4);
  --space-5: var(--space-base-5);
  --space-6: var(--space-base-6);
  --space-7: var(--space-base-7);
}

/* ──────────────────────────────────────────────────────────────────────────
   type-tokens.css (brand channel) — editorial serif + reading measure + the
   Charter self-hosted faces.

   Brand owns the editorial serif spine. The Core sans + mono aliases
   (--font-sans / --font-mono) and the raw --type-* scale stay in
   @myrmid/foundation; this file adds only the brand-specific type vocabulary.

   • --font-serif — Charter-led stack; system serif fallback retained so text
     renders immediately under font-display: swap.
   • --measure    — editorial reading measure.

   Source-of-truth values: manifesto-preview.html lines 50–52, 282–303.
   ────────────────────────────────────────────────────────────────────────── */

:root {
  /* — editorial serif stack (system-font fallback chain backs the @font-face
       declarations below). — */
  --font-serif: Charter, "Iowan Old Style", "Source Serif Pro", "Source Serif", Cambria, Georgia, "Times New Roman", Times, serif;

  /* — reading measure — */
  --measure: 60rem;
}

/* ──────────────────────────────────────────────────────────────────────────
   Self-hosted Charter WOFF2 declarations — UX-DR8 (EU-resident, no CDN).

   • Charter (regular, italic, bold) — Bitstream Charter license, free
     redistribution; procured from practicaltypography.com 2026-05-02. Relocated
     from @myrmid/foundation into @myrmid/brand in Story 2.2.

   Operational notes:
   • font-display: swap — system-fallback renders immediately, WOFF2 swaps in
     when ready. Avoids invisible-text FOUT; CLS impact is minimal because
     Charter and Iowan Old Style have similar metrics.
   • src is root-absolute (/fonts/charter-*.woff2) — resolves on the consumer's
     own host, which copies the WOFF2 into public/fonts/. No https://, no CDN.
   • License trail: src/assets/fonts/LICENSE.md (Bitstream notice preservation
     required by the Charter license).
   ────────────────────────────────────────────────────────────────────────── */
@font-face {
  font-family: "Charter";
  src: url("/fonts/charter-regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Charter";
  src: url("/fonts/charter-italic.woff2") format("woff2");
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "Charter";
  src: url("/fonts/charter-bold.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

}
/* Brand foundation primitives — body substrate + skip-link + stigmergy texture system */
@layer myrmid.foundation {
/* ──────────────────────────────────────────────────────────────────────────
   layout-base.css — substrate, body type, skip-link.

   Foundation layout primitives consumed by every Myrmid surface:
     • Box-sizing reset.
     • <html> text-size-adjust + scroll-behavior (with reduced-motion).
     • <body> substrate (radial dot-grid + brand fonts + AA-clean type colour).
     • ::selection — inverted ink/surface for high contrast in both themes.
     • .skip-link — WCAG 2.4.1 bypass-blocks affordance.

   Lifted from landing-page/tokens/layout-base.css on 2026-05-29. Landing-page-
   specific chrome (header.site, .site-inner, .brand*, .nav, hero-reveal state
   machine, #lucie-root rules, .consent-* rules) was deliberately NOT migrated;
   those belong in the consumer that ships those markup patterns.

   Body substrate per Brand Visual System §Stigmergy Texture System Primitive 1:
     • radial-gradient(circle, var(--grid-dot) 0.7px, transparent 1.4px)
     • size: var(--grid-cadence) (28px default)
     • Mode-aware via the cascade — --grid-dot redeclares per data-theme.
     • AA constraint: dot opacity is calibrated for ≥4.5:1 body-text contrast.
   ────────────────────────────────────────────────────────────────────────── */

:root {
  --grid-cadence: 28px;
}

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

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scroll-behavior: smooth;
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

body {
  margin: 0;
  background-color: var(--surface-page);
  background-image: radial-gradient(circle, var(--grid-dot) 0.7px, transparent 1.4px);
  background-size: var(--grid-cadence) var(--grid-cadence);
  background-position: 0 0;
  color: var(--ink-primary);
  font-family: var(--font-serif);
  font-size: var(--type-size-body-base);
  line-height: var(--type-line-height-base);
  font-feature-settings: "kern" 1, "liga" 1;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  transition: background-color var(--motion-base) var(--easing),
              color            var(--motion-base) var(--easing);
}

@media (min-width: 768px) {
  body {
    font-size:   var(--type-size-body-comfortable);
    line-height: var(--type-line-height-loose);
  }
}

::selection { background-color: var(--ink-primary); color: var(--surface-page); }

.skip-link {
  position: absolute;
  top: -100px;
  left: 1rem;
  padding: var(--space-1) 0.75rem;
  background: var(--surface-card);
  color: var(--ink-primary);
  font-family: var(--font-sans);
  font-size: var(--type-size-small-base);
  text-decoration: none;
  border: 1px solid var(--rule-quiet);
  border-radius: 4px;
  z-index: 100;
}
.skip-link:focus {
  top: 0.75rem;
  outline: 2px solid var(--accent-primary);
  outline-offset: 2px;
}
}
@layer myrmid.foundation {
/* ──────────────────────────────────────────────────────────────────────────
   stigmergy.css — reusable Stigmergy Texture System primitives.

   Three reusable primitives consumed across long-form prose and section
   surfaces:
     • .stigmergy-rail — Primitive 2 (waypoint) + Primitive 3 (pheromone
       trail). Every consumer renders
         <svg class="stigmergy-rail__waypoint">
           <use href="#stigmergy-waypoint"/>
         </svg>
       as the FIRST CHILD of the .stigmergy-rail block. A rail without a
       waypoint reads as an orphan hairline, not a stigmergy waypoint —
       that is the wrong gesture (browser-tested 2026-05-13 by Tom:
       "the rail must be the rail plus an ant like in the manifesto").
     • .stigmergy-divider-strong — Primitive 4 wrapper. 240×38 viewBox,
       full ant-body row (5 columns × 3 dots, V-rhythm centre dip).
       Section-boundary marker.
     • .stigmergy-divider-soft — Primitive 5 wrapper. 200×40 render box
       (1.67× the 120×24 viewBox) for sub-pixel legibility at scroll-
       reading distance — thought-pause marker between paragraph blocks.

   Token discipline:
     • --trail-stroke → --rule-quiet by cascade (color-tokens.css).
     • --waypoint-fill → --accent-primary (EU blue light, EU gold dark).
     • --metal-platine on all divider dots (structural-only metallic).

   Accessibility: every consuming <svg> MUST carry aria-hidden="true" +
   focusable="false". The decorative role is encoded at the consumer,
   not the symbol, so the same #stigmergy-* symbols stay reusable.

   Lifted from landing-page/tokens/stigmergy.css on 2026-05-29. Landing-page-
   specific page-foot navigation (.crosslinks*, .crosslinks-table*,
   .crosslinks-cta-button) was deliberately NOT migrated; that pattern is a
   landing-page surface concern, not a foundation primitive.
   ────────────────────────────────────────────────────────────────────────── */

/* ┌────────────────────────────────────────────────────────────────────────┐
   │ .stigmergy-rail — side-line + required waypoint at the head. Apply to  │
   │ <section> or <article> elements that should read as waypoint stops on  │
   │ a trail.                                                                │
   └────────────────────────────────────────────────────────────────────────┘ */
.stigmergy-rail {
  position: relative;
  padding-left: var(--space-3);
}

.stigmergy-rail::before {
  content: "";
  position: absolute;
  top: var(--space-3);
  bottom: var(--space-3);
  left: 3px;
  width: 1px;
  background: linear-gradient(to bottom, var(--trail-stroke), transparent 92%);
  pointer-events: none;
}

.stigmergy-rail__waypoint {
  position: absolute;
  top: 0;
  left: 0;
  width: 7px;
  height: 22px;
  opacity: 0.85;
  pointer-events: none;
}

/* ┌────────────────────────────────────────────────────────────────────────┐
   │ .stigmergy-divider-strong — Primitive 4 wrapper. Centred, sized to     │
   │ editorial column. Strong section-boundary marker.                      │
   └────────────────────────────────────────────────────────────────────────┘ */
.stigmergy-divider-strong {
  display: block;
  width: 240px;
  height: 38px;
  margin: var(--space-5) auto;
}
@media (min-width: 768px) {
  .stigmergy-divider-strong {
    margin: var(--space-6) auto;
  }
}

/* ┌────────────────────────────────────────────────────────────────────────┐
   │ .stigmergy-divider-soft — Primitive 5 wrapper. Smaller envelope than   │
   │ strong, less vertical breathing. Thought-pause marker between          │
   │ paragraph blocks. Render box (200×40) is ~1.67× the 120×24 viewBox so  │
   │ the dots + rule actually read at scroll-reading distance.              │
   └────────────────────────────────────────────────────────────────────────┘ */
.stigmergy-divider-soft {
  display: block;
  width: 200px;
  height: 40px;
  margin: var(--space-3) auto;
}
@media (min-width: 768px) {
  .stigmergy-divider-soft {
    margin: var(--space-4) auto;
  }
}
}
/* Landing-page supplements to the foundation */
/* ──────────────────────────────────────────────────────────────────────────
   site-chrome.css — landing-page header chrome + hero-reveal state machine.

   Renamed 2026-05-29 from layout-base.css. The substrate + body type +
   ::selection + .skip-link primitives that used to live alongside this
   chrome now ship from @myrmid/design-system/foundation/layout-base.css.
   This file is the landing-page-specific supplement: header markup,
   the hero-reveal coordination with public/js/hero-reveal.js, and the
   #lucie-root substrate suppression.

   Sticky positioning per UX spec §Section Nav line 2123 ("Locale-aware;
   sticky"). z-index pins above page content but stays below the Lucie
   widget root (which manages its own stacking inside #lucie-root).
   `contain: layout` keeps the sticky element from triggering layout
   recalculation in the surrounding content (CLS = 0 invariant per AC).
   ────────────────────────────────────────────────────────────────────────── */
header.site {
  position: sticky;
  top: 0;
  z-index: 30;
  padding: var(--space-3) 0;
  background: var(--surface-page);
  border-bottom: 1px solid var(--rule-quiet);
  contain: layout;
  transition:
    opacity var(--motion-duration-base) var(--motion-easing-base),
    transform var(--motion-duration-base) var(--motion-easing-base);
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Hero-reveal state machine — coordinated with                           │
   │ public/js/hero-reveal.js + templates/layouts/base-layout.eta inline    │
   │ bootstrap. While the visitor is reading the hero (data-hero-mode=     │
   │ "initial"), header.site and the floating Lucie button are hidden so   │
   │ the hero owns the viewport. On first scroll input, JS flips the body  │
   │ to data-hero-mode="scrolled" — chrome fades back in and stays.        │
   │                                                                        │
   │ Progressive enhancement: if JS is disabled the body attribute is set  │
   │ by the inline <head> bootstrap (which is synchronous and reliable);   │
   │ if even that fails (no-script env), the absence of any                │
   │ data-hero-mode value leaves chrome at its default — visible.          │
   └────────────────────────────────────────────────────────────────────────┘ */
body[data-hero-mode="initial"] header.site {
  opacity: 0;
  transform: translateY(-100%);
  pointer-events: none;
}
/* No main pull-up trick. Previously body[data-hero-mode="initial"] main
   had `margin-top: -header-height` to put the hero's geometric centre
   at the true viewport centre while the header was hidden. That
   produced a 38-px vertical jump between cinematic and non-cinematic
   pages (the centre of full 100vh vs. the centre of the area below a
   visible header). Hero is now sized as `calc(100vh - header-height)`
   in hero.css, which centres its content in the area below the
   reserved-header space on EVERY state — no jump when navigating, and
   the bottom-positioned scroll-cue stays in the viewport. The header
   still fades + slides in on first reveal; the hero just doesn't
   shift to coordinate with it. */
body[data-hero-mode="initial"] .lucie-cta,
body[data-hero-mode="initial"] #lucie-root,
body[data-hero-mode="initial"] .consent-dialog,
body[data-hero-mode="initial"] .consent-trigger {
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--motion-duration-base) var(--motion-easing-base);
}
body[data-hero-mode="scrolled"] .lucie-cta,
body[data-hero-mode="scrolled"] #lucie-root,
body[data-hero-mode="scrolled"] .consent-dialog,
body[data-hero-mode="scrolled"] .consent-trigger {
  opacity: 1;
}
/* Consent + persistent trigger MUST surface eventually even if the
   visitor never scrolls — privacy choice must be reachable. hero-
   reveal.js sets data-consent-revealed="true" 6s after load; this rule
   restores opacity + pointer-events on the consent affordances
   regardless of hero-mode. */
body[data-consent-revealed="true"] .consent-dialog,
body[data-consent-revealed="true"] .consent-trigger {
  opacity: 1;
  pointer-events: auto;
}
@media (prefers-reduced-motion: reduce) {
  header.site,
  body[data-hero-mode="initial"] .lucie-cta,
  body[data-hero-mode="initial"] #lucie-root {
    transition: none;
  }
  body[data-hero-mode="initial"] header.site {
    /* No slide-in; just visibility step. */
    transform: none;
    visibility: hidden;
  }
  body[data-hero-mode="initial"] .consent-dialog,
  body[data-hero-mode="initial"] .consent-trigger {
    visibility: hidden;
  }
  body[data-consent-revealed="true"] .consent-dialog,
  body[data-consent-revealed="true"] .consent-trigger {
    visibility: visible;
  }
}
.site-inner {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  width: 100%;
  max-width: var(--measure);
  margin: 0 auto;
  padding: 0 var(--space-3);
}
@media (min-width: 768px) {
  .site-inner { padding: 0 var(--space-4); }
}
.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.625rem;
  text-decoration: none;
  color: var(--ink-primary);
  font-family: var(--font-sans);
  font-size: 1rem;
  font-weight: var(--type-weight-semibold);
}
.brand-mark { width: 32px; height: 32px; flex: 0 0 32px; }
.brand-name { letter-spacing: 0.04em; }
.nav { display: flex; align-items: center; gap: var(--space-2); }
/* Lucie widget surface dot-grid suppression — UX:522.
   The widget is its own owned surface; the stigmergy texture frames her,
   never invades her. Scope to the canonical mount root. */
#lucie-root,
#lucie-root * {
  background-image: none;
}
/* header.site sticky chrome + hero-reveal state machine + .site-inner + .brand* + .nav + #lucie-root substrate suppression */
/* ──────────────────────────────────────────────────────────────────────────
   crosslinks.css — landing-page page-foot navigation pattern.

   Renamed 2026-05-29 from stigmergy.css. The reusable Stigmergy Texture
   System primitives (.stigmergy-rail, .stigmergy-divider-strong,
   .stigmergy-divider-soft) that used to share this file now ship from
   @myrmid/design-system/foundation/stigmergy.css. The page-foot
   navigation block stays here because it is a landing-page surface
   concern — every public page has it, no other Myrmid consumer needs
   the same table layout.

   The .crosslinks block consolidates the six per-page crosslink class
   trees into one primitive. Adopted pricing's "talk-to-us" 2-col table
   shape (question on the left, outline-button CTA on the right) so
   every page foot reads the same: an <h2> "Want to know more?" header
   sits above a .crosslinks-table whose rows pair an intro <th> with an
   <a class="crosslinks-cta-button"> CTA. The block sits at page bottom;
   the strong stigmergy divider above is the visual seam, so no
   border-top here — the divider is the page-foot punctuation.
   ────────────────────────────────────────────────────────────────────────── */
.crosslinks {
  width: 100%;
  max-width: var(--measure);
  margin: 0 auto;
  /* No padding-top: the strong-divider above provides the visual gap via its
     own margin-bottom, and zero top padding aligns the .crosslinks__h2 with
     the .stigmergy-rail__waypoint (which sits at top: 0 of the rail block). */
  padding: 0 var(--space-3) var(--space-7);
}
@media (min-width: 768px) {
  .crosslinks {
    padding-left: var(--space-4);
    padding-right: var(--space-4);
  }
}
.crosslinks__h2 {
  font-family: var(--font-serif);
  font-weight: var(--type-weight-semibold);
  font-size: 1.5rem;
  line-height: var(--type-line-height-tight);
  color: var(--ink-primary);
  margin: 0 0 var(--space-3);
}
.crosslinks-table-wrapper {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.crosslinks-table {
  width: 100%;
  border-collapse: collapse;
  font-family: var(--font-serif);
  font-size: var(--type-size-body-base);
  color: var(--ink-primary);
}
.crosslinks-table tbody th {
  font-family: var(--font-serif);
  font-weight: var(--type-weight-semibold);
  text-align: left;
  padding: var(--space-3) var(--space-2);
  border-bottom: 1px solid var(--rule-quiet);
  color: var(--ink-primary);
  vertical-align: middle;
}
.crosslinks-table tbody td {
  padding: var(--space-3) var(--space-2);
  border-bottom: 1px solid var(--rule-quiet);
  vertical-align: middle;
  white-space: nowrap;
  text-align: right;
  width: 1%; /* shrink to content; the <th> column takes the slack */
}
.crosslinks-table__row:last-child th,
.crosslinks-table__row:last-child td {
  border-bottom: none;
}
.crosslinks-table__cta-stack {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: var(--space-2);
}
/* Coloured + semibold text-link CTA. Softened 2026-05-14 from outlined
   button to a text link; coloured/bolded 2026-05-14 so it still reads
   as a destination cue alongside the <th> question. Accent on idle,
   ink-primary on hover (text darkens, underline holds accent). */
.crosslinks-cta-button {
  display: inline-block;
  min-height: 44px;
  padding: 0.5rem 0;
  font-family: var(--font-serif);
  font-size: var(--type-size-body-base);
  font-weight: var(--type-weight-semibold);
  color: var(--accent-primary);
  text-decoration: underline;
  text-decoration-color: var(--accent-primary);
  text-underline-offset: 0.25em;
  transition:
    color var(--motion-quick) var(--easing),
    text-decoration-color var(--motion-quick) var(--easing);
}
.crosslinks-cta-button:hover,
.crosslinks-cta-button:focus-visible {
  color: var(--ink-primary);
  text-decoration-color: var(--ink-primary);
}
.crosslinks-cta-button:focus-visible {
  outline: 2px solid var(--ink-primary);
  outline-offset: 2px;
  border-radius: 2px;
}
/* unified page-foot navigation block (two-col table — question + CTA) */
/* Landing-page surface composition (page-by-page consumer rules) */
/* ──────────────────────────────────────────────────────────────────────────
   hero.css — Unified hero block consumer rules.

   Single source of truth for the hero composition shared by every
   "hero surface" — landing, /products + 6 product pages, /solutions +
   9 solution pages, /about, /about/team. Hero markup is generated by
   templates/partials/hero-block.eta with the locked element order:

       logo → descriptor → H1 → sub → italic brand-mark close → CTA

   FULL-BLEED CINEMATIC BY DEFAULT. On any [data-hero] section the hero
   occupies the full viewport and content sits vertically centred. The
   page header (header.site) and floating Lucie button are hidden until
   the visitor scrolls; see layout-base.css for the reveal rules and
   public/js/hero-reveal.js for the state machine.

   Brand-mark italic close is colored via --accent-primary (EU blue in
   light mode; deepens to EU-gold in dark mode via the colour-token
   cascade). Stays contrast-safe in both modes.

   Lives under tokens/** so the four-prefix stylelint regex exemption
   (Story 1.1) covers consumer rules using ad-hoc class names.
   ────────────────────────────────────────────────────────────────────── */
/* Hero fills the area BELOW the sticky header on every state — cinematic
   first paint, scrolled, or subsequent hero surfaces in the same
   session. header.site is `position: sticky` so it reserves
   header-height of vertical space at the top of the viewport
   regardless of whether it's opacity:0 (initial state) or visible.
   Subtracting that reservation from min-height puts the hero's
   geometric centre at the same viewport Y on every page (no jump when
   navigating between hero surfaces) AND keeps the bottom-positioned
   scroll-cue inside the viewport. --header-height is written on <body>
   by hero-reveal.js; the 5rem fallback ≈ 81px tracks the header's
   typical computed height (space-3 × 2 + 32px mark + 1px border) so
   the rule works before JS parses too. */
.hero {
  position: relative;
  min-height: calc(100vh - var(--header-height, 5rem));
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: var(--space-5) 0 calc(var(--space-6) + 24px);
  text-align: center;
  contain: layout;
}
@media (min-width: 768px) {
  .hero {
    padding: var(--space-6) 0 calc(var(--space-7) + 24px);
  }
}
.hero-inner {
  width: 100%;
  max-width: var(--measure);
  margin: 0 auto;
  padding: 0 var(--space-3);
}
@media (min-width: 768px) {
  .hero-inner { padding: 0 var(--space-4); }
}
/* Logo: matches the SVG HTML width/height attributes (64×64) at the
   smallest breakpoint so the browser reserves the right box for CLS
   before CSS parses; ≥768px scales up to 96px. */
.hero-mark {
  display: block;
  width: 64px;
  height: 64px;
  margin: 0 auto var(--space-3);
}
@media (min-width: 768px) {
  .hero-mark { width: 96px; height: 96px; }
}
.hero .eyebrow {
  font-family: var(--font-sans);
  font-size: var(--type-size-eyebrow-base);
  font-weight: var(--type-weight-medium);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-quiet);
  margin: 0 auto var(--space-2);
  max-width: 70ch;
}
.hero h1 {
  font-family: var(--font-serif);
  font-weight: var(--type-weight-regular);
  font-size: var(--type-size-h1-base);
  /* 1.2, not --type-line-height-tight (1.12): the ::selection highlight box
     height equals line-height, and 1.12 cropped the serif's descenders. */
  line-height: 1.2;
  letter-spacing: -0.02em;
  margin: 0 auto var(--space-3);
  color: var(--ink-primary);
  max-width: 70ch;
}
.hero-sub {
  font-family: var(--font-serif);
  font-size: var(--type-size-body-base);
  line-height: var(--type-line-height-base);
  color: var(--ink-secondary);
  margin: 0 auto var(--space-2);
  max-width: 70ch;
}
@media (min-width: 768px) {
  .hero-sub { font-size: var(--type-size-body-comfortable); }
}
/* Brand-mark italic close — colored per spec (unified hero pages).
   --accent-primary resolves to EU blue in light mode and EU gold in
   dark mode via the colour-token cascade. */
.hero-brand-mark {
  font-family: var(--font-serif);
  font-style: italic;
  font-size: var(--type-size-body-base);
  color: var(--accent-primary);
  margin: var(--space-3) auto;
  max-width: 70ch;
}
.hero-cta {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-3);
}
@media (min-width: 480px) {
  .hero-cta {
    flex-direction: row;
    flex-wrap: wrap;
    justify-content: center;
  }
}
.cta-lucie {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-sans);
  font-size: var(--type-size-body-base);
  font-weight: var(--type-weight-medium);
  background: var(--accent-primary);
  color: var(--ink-on-accent);
  border: 1px solid var(--accent-primary);
  border-radius: 6px;
  padding: 0.625rem 1.125rem;
  min-height: 48px;
  cursor: pointer;
  transition:
    border-color var(--motion-quick) var(--easing),
    color var(--motion-quick) var(--easing),
    background-color var(--motion-quick) var(--easing);
}
/* Ghost variant — same shape, transparent fill, accent ink + border. Used
   as the right-hand companion to the primary CTA in the open-DPP branch
   ("Read our manifesto" sitting next to "Become a Design Partner"). The
   shine + scale hover treatment is inherited via the base `.cta-lucie`
   selector list in tokens/cta-interaction.css. */
.cta-lucie--secondary {
  background: transparent;
  color: var(--accent-primary);
}
.cta-lucie:focus-visible {
  outline: 2px solid var(--ink-primary);
  outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
  .cta-lucie { transition: none; }
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Scroll-cue cluster — V-shape origin + 5 ant streams.                   │
   │                                                                        │
   │ Layout: absolutely-positioned block anchored to the bottom-centre of   │
   │ the hero. A V-shape "origin" mark (3 stigmergy-ants connected by two  │
   │ diverging lines, forming a clear ∨) sits at the top. Five vertical    │
   │ pheromone trails descend below; each carries one stigmergy-ant glyph  │
   │ that loops translateY(-12px → 100%) with staggered animation-delay,  │
   │ so the five ants trickle out of the V apex at different cadences.    │
   │                                                                        │
   │ Color uses --accent-primary (EU blue light / EU gold dark) so the cue │
   │ reads as a deliberate brand mark, not faint secondary ink. The V     │
   │ apex sits roughly above the leftmost-and-rightmost trail columns.    │
   │                                                                        │
   │ Visibility gates on body[data-hero-cue]: hidden by default, fades in │
   │ once hero-reveal.js sets the visible state ~2.5s after load. Fades   │
   │ out (and detaches) on body[data-hero-mode="scrolled"].                │
   └────────────────────────────────────────────────────────────────────────┘ */
.hero-scroll-cue-cluster {
  position: absolute;
  bottom: 16px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 60px;
  color: var(--accent-primary);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--motion-duration-base) var(--motion-easing-exit);
}
.hero-scroll-cue-cluster__trails {
  position: relative;
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  width: 60px;
  height: 128px;
}
.hero-scroll-cue-cluster__trail {
  position: relative;
  width: 6px;
  height: 100%;
  display: block;
}
/* Fade ants in as they enter the top quartile and out as they cross the
   bottom quartile. Using mask-image (not opacity) so the fade is local
   to each ant's position — the procession itself runs at full opacity,
   and the column's intrinsic gradient creates the "walk in / walk out"
   effect. */
.hero-scroll-cue-cluster__column {
  display: block;
  width: 6px;
  height: 128px;
  overflow: hidden;
  mask-image: linear-gradient(
    to bottom,
    transparent 0%,
    black 25%,
    black 75%,
    transparent 100%
  );
  -webkit-mask-image: linear-gradient(
    to bottom,
    transparent 0%,
    black 25%,
    black 75%,
    transparent 100%
  );
}
/* The procession group slides down exactly one ant-pitch (32px) per
   loop. Pitch = 32 (16 ant + 16 gap) gives generous spacing between
   ants. The buffer ant at n=-1 seeds the top of the loop so the column
   flow is seamless on every cycle. */
.hero-scroll-cue-cluster__procession {
  animation: hero-cue-procession 2000ms linear infinite;
}
/* Stagger the three trails so they don't march in lockstep. */
.hero-scroll-cue-cluster__trail[data-trail="0"] .hero-scroll-cue-cluster__procession {
  animation-delay: 0ms;
}
.hero-scroll-cue-cluster__trail[data-trail="1"] .hero-scroll-cue-cluster__procession {
  animation-delay: 666ms;
}
.hero-scroll-cue-cluster__trail[data-trail="2"] .hero-scroll-cue-cluster__procession {
  animation-delay: 1333ms;
}
@keyframes hero-cue-procession {
  from { transform: translateY(0); }
  to   { transform: translateY(32px); }
}
/* Cue visibility is gated on the body state machine. */
body[data-hero-cue="visible"] .hero-scroll-cue-cluster {
  opacity: 1;
}
body[data-hero-mode="scrolled"] .hero-scroll-cue-cluster {
  opacity: 0;
}
@media (prefers-reduced-motion: reduce) {
  .hero-scroll-cue-cluster__procession {
    animation: none;
  }
}
/* Story 2.1 — A1 centred/cinematic hero block (landing-page.eta consumer rules) */
/* ──────────────────────────────────────────────────────────────────────────
   aspects.css — Story 2.2 D8=b+c. Section-level aspect-cascade cells.

   Story 1.3 declared only the manifesto-aspect cells (per its `tokens/
   color-tokens.css:19` comment "ONLY the (aspect × surface) cells the
   manifesto-preview required"); Story 2.2 adds the cells THIS story
   consumes:

     • [data-aspect="enterprise"] — wraps the portfolio block (above the
       manifesto-entry CTA). "Elevated accent ratio" per prd.md:543-569 +
       UX:594 ("full system on; dividers + waypoints + grid"). Implemented
       via --opacity-accent: 1 + --waypoint-fill bound to --accent-primary
       so decorative marks paint at full opacity. **--accent-primary itself
       is NOT re-bound** — text-fill consumers (portfolio-card-cta, etc.)
       inherit the page-level mode-adaptive resolution (EU blue in light,
       EU gold in dark) which is already AA-safe per Story 1.3 token-design.
       Re-binding --accent-primary at aspect-level would force a per-mode
       wrong-colour cascade and break WCAG AA contrast.

     • [data-aspect="smb"] — wraps post-portfolio scroll content (below the
       manifesto-entry CTA, above the DPP pre-footer). Modest accent ratio
       per UX:595 ("grid only; waypoints suppressed — felt-register avoids
       structural marking"); --opacity-accent: 0.15; waypoint-fill set to
       transparent to suppress structural marking.

     • [data-aspect="dpp"] — wraps the pre-footer DPP block (rendered by
       templates/partials/dpp-cta.eta). Full Stigmergy texture per UX:597
       ("full system on for the footer-zone invitation block, but no
       waypoint on the partner-link itself"); --opacity-accent: 1.

   `developer` cell DEFERRED to Story 3.4 (first consumer at
   /products/enterprise-mesh per UX:640) per Story 1.3 "declare only what's
   needed" precedent.

   Selectors are descendant-scoped (`[data-aspect="X"]`) so the aspect
   attribute lives on a SECTION root (e.g., `<section data-aspect="enterprise">`),
   NOT on `<html>`. The cascade picks up tokens from the surrounding mode
   context (light at :root, dark at :root[data-theme="dark"]) — and per
   the contrast-discipline above, aspect cells re-bind ONLY structural
   tokens (--opacity-accent, --waypoint-fill, --trail-stroke), NEVER
   --ink-* / --surface-* / --accent-primary. Substrate stays constant
   per AC6 anthracite/whitish-white rule + WCAG AA contrast.

   Type fills stay solid-on-solid per UX:601 + UX-DR1 (no pheromone
   underline / no dot-pattern on headings / no metallic finish on type).

   Lives under tokens/** so the four-prefix stylelint regex exemption
   (Story 1.1) covers ad-hoc per-aspect declarations.
   ────────────────────────────────────────────────────────────────────────── */
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Enterprise zone — full accent ratio for decorative marks.              │
   │ --accent-primary inherits page mode-adaptive default (light:EU blue / │
   │ dark:EU gold) for AA contrast on text-fill consumers.                  │
   │ Used by: <section data-aspect="enterprise"> wrapping the portfolio    │
   │ block in templates/pages/landing-page.eta (Story 2.2 Task 7).         │
   └────────────────────────────────────────────────────────────────────────┘ */
[data-aspect="enterprise"] {
  --opacity-accent: 1;
  --waypoint-fill: var(--accent-primary);
  --trail-stroke: var(--accent-primary);
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ SMB zone — modest accent ratio (felt register; structural marking     │
   │ suppressed per UX:595).                                                │
   │ Used by: <section data-aspect="smb"> wrapping post-portfolio scroll   │
   │ content (placeholder for Story 3.x value-prop content; empty at MVP-0). │
   └────────────────────────────────────────────────────────────────────────┘ */
[data-aspect="smb"] {
  --opacity-accent: 0.15;
  --waypoint-fill: transparent;
  --trail-stroke: var(--rule-quiet);
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ DPP zone — full Stigmergy texture for the invitation register.        │
   │ Used by:                                                               │
   │  • <section data-aspect="dpp"> in templates/partials/dpp-cta.eta —    │
   │    the D1 pre-footer block on the landing root (Story 2.2 Task 3).    │
   │  • <article data-aspect="dpp"> in templates/pages/partners.eta —      │
   │    the full /partners page wrapper (Story 3.6). Same token cascade    │
   │    applied at page scope, since the entire surface IS the DPP zone.   │
   │ NOTE: per UX:629 + UX:1300, NO waypoint mark renders on the /partners  │
   │ link itself — that constraint lives at the PARTIAL level (the link     │
   │ doesn't carry a waypoint marker), not in the aspect cell.              │
   │ --accent-primary stays page mode-adaptive (light:blue / dark:gold) —   │
   │ both AA-safe. --waypoint-fill bound to --metal-platine for restrained │
   │ marker tone per UX-DR (premium-by-restraint discipline).               │
   └────────────────────────────────────────────────────────────────────────┘ */
[data-aspect="dpp"] {
  --opacity-accent: 1;
  --waypoint-fill: var(--metal-platine);
  --trail-stroke: var(--accent-primary);
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Developer zone — near-zero accent ratio per UX:640. Used by           │
   │ /products/enterprise-mesh (Story 3.4 first consumer); UX spec frames the │
   │ developer register as low-ornamentation (the substrate is the        │
   │ message; the page is a capability enumeration). --accent-primary     │
   │ stays page mode-adaptive (light:blue / dark:gold) for the rare       │
   │ accent consumers (deep-link CTA, pricing line) to land at AA.        │
   │                                                                       │
   │ Waypoint + trail are NOT suppressed here — the 2026-05-14 site-wide  │
   │ stigmergy policy admits the rail on every product surface including  │
   │ enterprise-mesh. The earlier Story 3.4 "no waypoint marks, no pheromone  │
   │ trails" carve-out is superseded.                                     │
   └────────────────────────────────────────────────────────────────────────┘ */
[data-aspect="developer"] {
  --opacity-accent: 0.05;
}
/* Story 2.2 — section-level aspect-cascade cells (enterprise/smb/dpp); developer cell deferred to Story 3.4 */
/* ──────────────────────────────────────────────────────────────────────────
   portfolio.css — Story 2.2 B1 5-up grid + card consumer rules.

   Composition lock: B1 cards-grid per ux-design-specification.md §Step 9
   §Implementation Approach line 1637, adapted to 5-up after the 2026-05-09
   MPA split (was 4-up MWB/MAH/MPA/MAM; now 5-up Workflow Builder /
   Agent Hub / Managed OpenClaw / Local Assistant / Enterprise Mesh).

   Breakpoints (per UX:1311-1316 + UX:1637 spec):
     • <600px       → 1-up (single column; mobile portrait)
     • 600–1024px   → 2-up (mobile landscape / small tablet portrait)
     • 1024–1280px  → 3-up (laptop / tablet landscape; 3+2 wrap accepted)
     • ≥1280px      → 5-up (desktop full)

   Card composition: 1px border at --rule-quiet; hover lifts to
   --accent-primary (cascades through containing section's data-aspect).
   Type fills solid-on-solid per UX:601 + UX-DR1 (no metallic on type).

   Reduced-motion: hover transition zeroed via tokens/motion-tokens.css
   global escape hatch (lines 48-57); local override is belt-and-braces
   only and unnecessary here — the token gate catches it.

   Token consumers use CURRENT (pre-migration) names; Story 1.3-update
   sweep targets are forward-compat with the same scheme as tokens/hero.css
   leading comment (Story 2.1 deferred-work.md:36).

   Forward-compat sweep targets that Story 1.3-update will resolve:
     • --measure              → --measure-site (72rem)
     • --type-size-h1-base    → --type-size-h1
     • --type-size-body-base / -comfortable → --type-size-body (stepped)
     • Hardcoded 32ch         → var(--measure-narrow)

   Lives under tokens/** so the four-prefix stylelint regex exemption
   (Story 1.1) covers the ad-hoc class names.
   ────────────────────────────────────────────────────────────────────────── */
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Pillars zone — "how the Workforce works." Six platform layers under   │
   │ every Autonomous Enterprise: cloud abstraction · collaboration ·      │
   │ stigmergy · integrations · traceability · AI Act readiness. Section   │
   │ envelope mirrors .value-prop-zone for continuous vertical rhythm.     │
   │ Cards are descriptive (not links) — no hover/focus affordance.        │
   └────────────────────────────────────────────────────────────────────────┘ */
/* First body section after the hero (it absorbed the old what-is band,
   SCP-2026-06-08), so it carries that band's larger top padding for the
   hero→section rhythm. */
.pillars-zone {
  padding: var(--space-6) 0 var(--space-6);
}
.pillars-zone > * {
  width: 100%;
  max-width: var(--measure);
  margin-left: auto;
  margin-right: auto;
  padding-left: var(--space-3);
  padding-right: var(--space-3);
}
@media (min-width: 768px) {
  .pillars-zone {
    padding: var(--space-7) 0 var(--space-7);
  }
  .pillars-zone > * {
    padding-left: var(--space-4);
    padding-right: var(--space-4);
  }
}
.pillars-heading {
  font-family: var(--font-serif);
  font-weight: var(--type-weight-regular);
  font-size: var(--type-size-h1-base);
  line-height: var(--type-line-height-tight);
  letter-spacing: -0.02em;
  text-align: center;
  color: var(--ink-primary);
  margin: 0 auto var(--space-3);
}
.pillars-intro {
  font-family: var(--font-serif);
  font-size: var(--type-size-body-base);
  line-height: var(--type-line-height-base);
  color: var(--ink-secondary);
  text-align: center;
  margin: 0 auto var(--space-5);
  max-width: 70ch;
}
@media (min-width: 768px) {
  .pillars-intro {
    font-size: var(--type-size-body-comfortable);
  }
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ §3 Six cornerstones — circular layout + center-expand (Story 8.1).      │
   │                                                                          │
   │ Progressive enhancement, three states:                                   │
   │   • No JS (baseline): .pillars-circle is a readable stack — every        │
   │     cornerstone shows name + why + how. Fully accessible, no JS needed.   │
   │   • JS + narrow viewport: stacked ACCORDION — name buttons toggle their   │
   │     detail open/closed beneath them (AC5: not a circle on mobile).        │
   │   • JS + wide viewport: RING — six round buttons around a center; the     │
   │     selected one blooms radially inward, detail inside (AC1/AC2).         │
   │                                                                          │
   │ public/js/pillars-circle.js adds [data-enhanced] + toggles .is-open on a  │
   │ slot; ALL interactive/hidden styling is gated behind                      │
   │ .pillars-circle[data-enhanced] so the no-JS baseline stays readable.      │
   │ Fly-to-center is a transition (AC4: zeroed under reduced-motion by the    │
   │ tokens/motion-tokens.css global escape hatch). Each name is an <h3>-      │
   │ wrapped <button> (WAI disclosure + heading hierarchy AC3/AC5).            │
   └────────────────────────────────────────────────────────────────────────┘ */
.pillars-circle {
  margin: 0 auto;
  max-width: var(--measure);
}
.pillars-ring {
  list-style: none;
  margin: 0;
  padding: 0;
}
/* ── Baseline (no JS) + accordion (JS, narrow): stacked slots ─────────────── */
.pillars-slot {
  background: var(--surface-card);
  border: 1px solid var(--rule-quiet);
  border-radius: 6px;
  overflow: hidden;
}
.pillars-slot + .pillars-slot {
  margin-top: var(--space-3);
}
.pillars-node-heading {
  margin: 0;
  font: inherit;
}
.pillars-node {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  margin: 0;
  padding: var(--space-3) var(--space-4);
  background: transparent;
  border: 0;
  border-radius: inherit;
  cursor: default;
  font: inherit;
  color: var(--ink-primary);
  text-align: center;
}
.pillars-node__name {
  font-family: var(--font-serif);
  font-weight: var(--type-weight-semibold);
  font-size: var(--type-size-body-comfortable);
  line-height: var(--type-line-height-tight);
}
.pillars-node-detail {
  padding: 0 var(--space-4) var(--space-4);
}
.pillars-node-detail__body {
  font-family: var(--font-serif);
  font-size: var(--type-size-body-base);
  line-height: var(--type-line-height-base);
  color: var(--ink-secondary);
  margin: 0;
}
.pillars-node-detail__body--how {
  margin-top: var(--space-2);
  color: var(--ink-quiet);
}
/* Center cue is decorative and only used by the ring layout. */
.pillars-center {
  display: none;
}
/* Ant orbit (faint path + marching ants) is ring-only: hidden in the baseline
   stack + accordion, switched on inside the wide-viewport ring media query. */
.pillars-orbit-path,
.pillars-orbit {
  display: none;
}
/* ── Enhanced (JS present) — shared between accordion + ring ──────────────── */
.pillars-circle[data-enhanced] .pillars-node {
  /* No pointer cursor: in the ring, hover itself blooms the disc, so a "click
     me" hand reads as misleading. Click + keyboard still work (native button). */
  cursor: default;
  transition: background var(--motion-base) var(--easing),
              color var(--motion-base) var(--easing);
}
.pillars-circle[data-enhanced] .pillars-node-detail[hidden] {
  display: none;
}
.pillars-circle[data-enhanced] .pillars-node:focus-visible {
  outline: 2px solid var(--accent-primary);
  outline-offset: 2px;
}
@media (hover: hover) {
  .pillars-circle[data-enhanced] .pillars-node:hover {
    color: var(--accent-primary);
  }
}
.pillars-circle[data-enhanced] .pillars-slot.is-open .pillars-node {
  background: var(--accent-primary);
  color: var(--ink-on-accent);
}
/* ── Enhanced RING (JS + wide viewport) ──────────────────────────────────── */
@media (min-width: 1024px) {
  .pillars-circle[data-enhanced] {
    position: relative;
    /* One radius drives ring placement AND the ant-orbit radius so the geometry
       can't drift apart (six centres 60deg apart sit an adjacent-distance of R).
       --pillars-node-size is the closed disc; kept < R so neighbours DON'T touch
       and the ant orbit shows through the gaps (SCP-2026-06-08).
       --pillars-bloom is the open disc. It deliberately does NOT cover the ring
       (SCP-2026-06-09): the five unselected discs slide out to
       --pillars-radius-active, shrink to --pillars-dim-scale, and dim, so the
       whole stays visible around the bloom — the section's thesis.

       RADIAL bloom (SCP-2026-06-09b): the disc inflates ALONG its radius. Its
       centre travels the full radius to the ring centre while it scales to
       k = bloom/node, so the growth is directed inward at every frame: the
       inner edge sweeps right across the centre while the outer edge retreats
       only slightly. The final bloom is CENTRED on the ring, with a radius of
       14rem — a touch inside the 15rem ant orbit, so the ants keep marching
       around the open disc. The two adjacent dimmed siblings tuck ~1.6rem
       behind the bloom's flanks (z 5 > 2), which reads as depth, not
       occlusion.

       Bloom timing is local (--pillars-bloom-dur), deliberately slower than
       the global --motion-slow: the bloom is the section's one big gesture. */
    --pillars-radius: 15rem;
    --pillars-node-size: 10.5rem;
    --pillars-bloom: 28rem;
    --pillars-bloom-dur: 700ms;
    --pillars-radius-active: 16.5rem;
    --pillars-dim-scale: 0.78;
    --pillars-dim-opacity: 0.5;
  }
  .pillars-circle[data-enhanced] .pillars-ring {
    position: relative;
    width: min(100%, 42rem);
    margin-inline: auto;
    aspect-ratio: 1 / 1;
  }
  /* Slot loses its card box; its children (heading button + detail) position
     against .pillars-ring (the nearest positioned ancestor). */
  .pillars-circle[data-enhanced] .pillars-slot {
    background: none;
    border: 0;
    border-radius: 0;
    overflow: visible;
    margin: 0;
    /* Angle lives on the SLOT (not the heading) so both children inherit it:
       the heading for ring placement, the detail for radial anchoring to the
       bloom centre. --pillars-i = 0..n-1 (inline), --pillars-count = n. */
    --pillars-angle: calc(var(--pillars-i) * (360deg / var(--pillars-count)));
  }
  /* Button placed around the ring via the rotate / counter-rotate sandwich so
     the card stays upright. The heading STAYS at its ring position when open
     (the radial bloom grows from here on ::before); its transform only changes
     for the siblings' make-room slide (.is-active block below). */
  .pillars-circle[data-enhanced] .pillars-node-heading {
    position: absolute;
    top: 50%;
    left: 50%;
    z-index: 2;
    transform: translate(-50%, -50%)
               rotate(var(--pillars-angle))
               translateY(calc(-1 * var(--pillars-radius)))
               rotate(calc(-1 * var(--pillars-angle)));
    /* Bloom-paced so the make-room slide + dim move with the bloom. */
    transition: transform var(--pillars-bloom-dur) var(--easing),
                opacity var(--pillars-bloom-dur) var(--easing);
  }
  /* Closed disc: smaller than the radius so the six discs keep clear gaps and
     the ant orbit shows between them (SCP-2026-06-08). The button is a fixed
     transparent box; the visible disc surface lives on ::before so the bloom
     can inflate with a composited transform: scale() instead of width/height
     layout thrash, while the name + detail keep their natural text size
     (SCP-2026-06-09). */
  .pillars-circle[data-enhanced] .pillars-node {
    position: relative;
    width: var(--pillars-node-size);
    height: var(--pillars-node-size);
    padding: var(--space-4);
    border: 0;
    border-radius: 50%;
    background: none;
  }
  .pillars-circle[data-enhanced] .pillars-node::before {
    content: "";
    position: absolute;
    inset: 0;
    /* Behind the button's in-flow name but inside the heading's stacking
       context (z 2/5), so it still paints above the ant orbit (z 0). */
    z-index: -1;
    border: 1px solid var(--rule-quiet);
    border-radius: 50%;
    background: var(--surface-card);
    /* Zeroed twin of the open state's radial-bloom list (same functions in
       the same order), so the browser interpolates per-component instead of
       falling back to matrix interpolation. */
    transform: rotate(var(--pillars-angle))
               translateY(0)
               scale(1)
               rotate(calc(-1 * var(--pillars-angle)));
    /* Colour/border/shadow stay snappy; the bloom's scale eases slowly. */
    transition: transform var(--pillars-bloom-dur) var(--easing),
                background var(--motion-base) var(--easing),
                border-color var(--motion-base) var(--easing),
                box-shadow var(--motion-base) var(--easing);
  }

  /* ── Ant orbit ─────────────────────────────────────────────────────────────
     A faint circle of radius R (== --pillars-radius) threads every cornerstone
     centre; #stigmergy-ant glyphs march clockwise around it. The orbit layer is
     a static 0x0 anchor at the ring centre. EACH ant is two nested 0x0 layers:
     the wrapper holds a STATIC even-spacing angle (--orbit-i), and the inner
     __spin layer turns on its own --orbit-dur (so every ant moves at a different
     speed, SCP-2026-06-08) — starting from the wrapper's even angle, the twelve
     drift apart over time. The glyph carries the radius offset + a rigid 180deg
     correction so it rides head-first. Reduced motion freezes the spin via the
     global motion-tokens gate (it zeroes animation-duration/-delay !important —
     no local gate needed); the wrapper's static angle then keeps the frozen ants
     spread around the ring instead of stacking at 0deg. Ants paint behind the
     discs (z 0 < node z 2) so they thread through each cornerstone and show in
     the gaps. */
  .pillars-circle[data-enhanced] .pillars-orbit-path {
    display: block;
    position: absolute;
    top: 50%;
    left: 50%;
    width: calc(2 * var(--pillars-radius));
    height: calc(2 * var(--pillars-radius));
    transform: translate(-50%, -50%);
    color: var(--accent-primary);
    opacity: 0.25;
    pointer-events: none;
    overflow: visible;
    z-index: 0;
  }
  .pillars-circle[data-enhanced] .pillars-orbit {
    display: block;
    position: absolute;
    top: 50%;
    left: 50%;
    width: 0;
    height: 0;
    color: var(--accent-primary);
    pointer-events: none;
    z-index: 0;
  }
  /* Wrapper: STATIC even-spacing angle from --orbit-i. This both sets each ant's
     start phase AND is the reduced-motion-safe base — when the gate neutralises
     the spin layer, the ants stay distributed around the ring. */
  .pillars-circle[data-enhanced] .pillars-orbit-ant {
    position: absolute;
    top: 0;
    left: 0;
    width: 0;
    height: 0;
    transform: rotate(calc(var(--orbit-i) * (360deg / var(--orbit-count))));
  }
  /* Spin layer: turns at this ant's own --orbit-dur, so the twelve drift apart
     from their even start (their differing speeds). Starts from 0 for all, so
     the wrapper's angle alone fixes the t=0 spacing. */
  .pillars-circle[data-enhanced] .pillars-orbit-ant__spin {
    position: absolute;
    top: 0;
    left: 0;
    width: 0;
    height: 0;
    animation: pillars-orbit-spin var(--orbit-dur, 12s) linear infinite;
  }
  .pillars-circle[data-enhanced] .pillars-orbit-ant__glyph {
    position: absolute;
    top: 0;
    left: 0;
    width: 18px;
    height: 6.75px;
    margin-left: -9px;
    margin-top: -3.375px;
    fill: currentcolor;
    transform: translateY(calc(-1 * var(--pillars-radius))) rotate(180deg);
  }
  @keyframes pillars-orbit-spin {
    to {
      transform: rotate(360deg);
    }
  }

  /* ── Radial bloom, whole stays visible (SCP-2026-06-09b) ───────────────────
     Driven solely by .is-open (set by pillars-circle.js on hover / click /
     keyboard activation — the JS owns the open state). Triggering off CSS
     :hover is deliberately avoided (it would oscillate with the geometry
     changing under the cursor); :focus-within is avoided too, so ARIA never
     desyncs. The disc inflates along its own radius: the rotate sandwich
     turns the inward translateY radial, the disc centre travels the full
     radius to the ring centre while scaling, and the matched closed/open
     transform lists keep the interpolation per-component — so the bloom grows
     out of the cornerstone's position and spreads across the centre. Name
     rises to the bloom apex, detail fades in at the centre, and the five
     unselected discs make room (outward + shrink + dim, block below), so the
     whole stays in view around the open part. */
  .pillars-circle[data-enhanced] .pillars-slot.is-open .pillars-node-heading {
    z-index: 5;
  }
  /* Keep the shared accordion accent fill off the round bloom: light disc with
     a structural accent ring (brand "structural-only accents" rule), why copy
     readable in dark ink. The button box stays transparent; the bloom is the
     scaled surface. Shadow is authored small so it lands right after the
     ~2.3x scale. */
  .pillars-circle[data-enhanced] .pillars-slot.is-open .pillars-node {
    background: none;
    color: var(--ink-primary);
  }
  .pillars-circle[data-enhanced] .pillars-slot.is-open .pillars-node::before {
    transform: rotate(var(--pillars-angle))
               translateY(var(--pillars-radius))
               scale(calc(var(--pillars-bloom) / var(--pillars-node-size)))
               rotate(calc(-1 * var(--pillars-angle)));
    border-color: var(--accent-primary);
    box-shadow: 0 4px 10px rgba(0, 0, 0, 0.16);
  }
  /* Name rides the same radial travel to the ring centre, then rises to seat
     just under the bloom's apex. The 50% term pins the name's TOP edge (not
     its centre) at the seat, so one- and two-line names land at the same
     height. Closed state is the zeroed twin list for per-component
     interpolation. Long names (e.g. "Compound Knowledge Management") get a
     fixed 15rem column so they wrap to two centred lines instead of running
     off the round edge. */
  .pillars-circle[data-enhanced] .pillars-node__name {
    transform: rotate(var(--pillars-angle))
               translateY(0)
               rotate(calc(-1 * var(--pillars-angle)))
               translateY(0);
    transition: transform var(--pillars-bloom-dur) var(--easing);
  }
  .pillars-circle[data-enhanced] .pillars-slot.is-open .pillars-node__name {
    /* flex: none — the name is a flex item in the (still 10.5rem) button box;
       without it the 15rem column would be shrunk back to the button width. */
    flex: none;
    width: 15rem;
    transform: rotate(var(--pillars-angle))
               translateY(var(--pillars-radius))
               rotate(calc(-1 * var(--pillars-angle)))
               translateY(calc(-0.5 * var(--pillars-bloom) + var(--space-5) + 50%));
  }
  /* The five unselected discs make room: slide outward a touch, shrink, dim.
     The whole stays visible around the bloom (the section's thesis) and the
     ant orbit keeps threading between them. Reuses --pillars-angle from the
     placement rule above. */
  .pillars-circle[data-enhanced].is-active .pillars-slot:not(.is-open) .pillars-node-heading {
    opacity: var(--pillars-dim-opacity);
    transform: translate(-50%, -50%)
               rotate(var(--pillars-angle))
               translateY(calc(-1 * var(--pillars-radius-active)))
               rotate(calc(-1 * var(--pillars-angle)))
               scale(var(--pillars-dim-scale));
  }

  /* Detail rides inside the bloomed disc, below the name — and shows BOTH the
     why and the how (SCP-2026-06-09c; the how was ring-hidden before). The
     container is the full 28rem bloom square, centred on the ring; the text
     follows the disc's round edge via two shape-outside floats (::before /
     ::after) whose polygons trace the left/right arcs, so every line gets the
     full chord width at its height. Meta type keeps the longest pair (FR
     Adaptive Collaboration, ~580 chars) inside the circle with headroom.

     COUPLED GEOMETRY: the polygon vertices below encode --pillars-bloom: 28rem
     with this 7.5rem padding-top (content box 28rem × 20.5rem, bloom centre
     at 50% / 104px ≈ 31.7% of the content height). If either value changes,
     re-derive the arc points: x = 224 + 224·cos(a), y = 104 + 224·sin(a) px,
     as % of the 224px × 328px float box. Browsers without shape-outside just
     get a straight full-width column (corners may graze the rim). */
  .pillars-circle[data-enhanced] .pillars-node-detail {
    position: absolute;
    top: 50%;
    left: 50%;
    width: var(--pillars-bloom);
    height: var(--pillars-bloom);
    /* Clears the name seated at the apex (up to two lines). */
    padding-top: 7.5rem;
    text-align: center;
    opacity: 0;
    transform: translate(-50%, -50%) scale(0.96);
    transition: opacity var(--pillars-bloom-dur) var(--easing),
                transform var(--pillars-bloom-dur) var(--easing);
    z-index: 6;
  }
  /* Both floats must come BEFORE the text in box order (a float declared
     after content only excludes the lines below it), so the right float hangs
     on the first paragraph's ::before, not on the container's ::after. Its
     height is the container content height (28rem − 7.5rem padding) spelled
     out, because 100% of the auto-height <p> resolves to nothing. */
  .pillars-circle[data-enhanced] .pillars-node-detail::before,
  .pillars-circle[data-enhanced] .pillars-node-detail__body--why::before {
    content: "";
    width: 50%;
    height: 20.5rem;
    shape-margin: 0.5rem;
  }
  .pillars-circle[data-enhanced] .pillars-node-detail::before {
    float: left;
    shape-outside: polygon(0% 0%, 11.4% 0%, 3.4% 14%, 0% 31.7%, 3.4% 49.4%,
                           13.4% 65.9%, 29.3% 80%, 50% 90.8%, 74.1% 97.7%,
                           100% 100%, 0% 100%);
  }
  .pillars-circle[data-enhanced] .pillars-node-detail__body--why::before {
    float: right;
    shape-outside: polygon(100% 0%, 88.6% 0%, 96.6% 14%, 100% 31.7%,
                           96.6% 49.4%, 86.6% 65.9%, 70.7% 80%, 50% 90.8%,
                           25.9% 97.7%, 0% 100%, 100% 100%);
  }
  /* Small type (not meta — 13px proved hard to read) with a locally tighter
     leading so why + how still both fit in every locale: 14px × 1.45 ≈ 20px
     lines buy back the two lines the bigger size costs against the FR worst
     case (~586 chars). No token sits between line-height-tight (1.12, display
     only) and -base (1.65), hence the literal. Baseline + accordion keep
     body-base type and leading. */
  .pillars-circle[data-enhanced] .pillars-node-detail__body {
    font-size: var(--type-size-small-base);
    line-height: 1.45;
  }
  .pillars-circle[data-enhanced] .pillars-slot.is-open .pillars-node-detail {
    opacity: 1;
    transform: translate(-50%, -50%) scale(1);
  }
  /* Belt-and-braces: the open detail wins over a stale [hidden]. */
  .pillars-circle[data-enhanced] .pillars-slot.is-open .pillars-node-detail[hidden] {
    display: block;
  }

  /* Center cue — visible when nothing is open, fades out when a disc blooms. */
  .pillars-circle[data-enhanced] .pillars-center {
    display: block;
    position: absolute;
    top: 50%;
    left: 50%;
    width: min(15rem, 48%);
    margin: 0;
    text-align: center;
    pointer-events: none;
    opacity: 1;
    transform: translate(-50%, -50%);
    transition: opacity var(--motion-base) var(--easing);
    z-index: 1;
  }
  .pillars-circle[data-enhanced].is-active .pillars-center {
    opacity: 0;
  }
  .pillars-center__cue {
    font-family: var(--font-serif);
    font-style: italic;
    font-size: var(--type-size-body-base);
    line-height: var(--type-line-height-base);
    color: var(--ink-quiet);
  }
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Value-prop zone — landing-root bridge between hero and portfolio.     │
   │ Outcome lede + 2-up Individuals / Businesses grid, each card a link   │
   │ to /solutions/<segment>/. Section envelope mirrors .enterprise-zone   │
   │ so vertical rhythm continues unbroken into the portfolio below.       │
   └────────────────────────────────────────────────────────────────────────┘ */
.value-prop-zone {
  padding: var(--space-5) 0 var(--space-6);
}
.value-prop-zone > * {
  width: 100%;
  max-width: var(--measure);
  margin-left: auto;
  margin-right: auto;
  padding-left: var(--space-3);
  padding-right: var(--space-3);
}
@media (min-width: 768px) {
  .value-prop-zone {
    padding: var(--space-6) 0 var(--space-7);
  }
  .value-prop-zone > * {
    padding-left: var(--space-4);
    padding-right: var(--space-4);
  }
}
.value-prop-heading {
  font-family: var(--font-serif);
  font-weight: var(--type-weight-regular);
  font-size: var(--type-size-h1-base);
  line-height: var(--type-line-height-tight);
  letter-spacing: -0.02em;
  text-align: center;
  color: var(--ink-primary);
  margin: 0 auto var(--space-3);
}
.value-prop-intro {
  font-family: var(--font-serif);
  font-size: var(--type-size-body-base);
  line-height: var(--type-line-height-base);
  color: var(--ink-secondary);
  text-align: center;
  margin: 0 auto var(--space-5);
  max-width: 70ch;
}
@media (min-width: 768px) {
  .value-prop-intro {
    font-size: var(--type-size-body-comfortable);
  }
}
.value-prop-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-3);
}
@media (min-width: 600px) {
  .value-prop-grid {
    grid-template-columns: repeat(2, 1fr);
    gap: var(--space-4);
  }
}
.value-prop-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-4);
  background: var(--surface-card);
  border: 1px solid var(--rule-quiet);
  border-radius: 6px;
  color: inherit;
  text-decoration: none;
  transition: border-color var(--motion-quick) var(--easing);
  min-height: 44px;
}
.value-prop-card:hover {
  border-color: var(--accent-primary);
}
.value-prop-card:focus-visible {
  border-color: var(--accent-primary);
  outline: 2px solid var(--ink-primary);
  outline-offset: 2px;
}
.value-prop-card-name {
  font-family: var(--font-serif);
  font-weight: var(--type-weight-semibold);
  font-size: var(--type-size-body-comfortable);
  line-height: var(--type-line-height-tight);
  color: var(--ink-primary);
  margin: 0;
}
.value-prop-card-body {
  font-family: var(--font-serif);
  font-size: var(--type-size-body-base);
  line-height: var(--type-line-height-base);
  color: var(--ink-secondary);
  margin: 0;
}
.value-prop-card-cta {
  font-family: var(--font-serif);
  font-size: var(--type-size-small-base);
  line-height: var(--type-line-height-base);
  color: var(--accent-primary);
  margin-top: auto;
}
/* Contact-us CTA at the bottom of the value-prop zone (landing). Inherits
   button shape from .cta-lucie (tokens/hero.css). Centred under the grid. */
.value-prop-contact-cta {
  display: flex;
  justify-content: center;
  margin-top: var(--space-4);
}
@media (min-width: 768px) {
  .value-prop-contact-cta {
    margin-top: var(--space-5);
  }
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Section + heading scaffolding                                          │
   └────────────────────────────────────────────────────────────────────────┘ */
.enterprise-zone {
  padding: var(--space-5) 0 var(--space-6);
}
.enterprise-zone > * {
  width: 100%;
  max-width: var(--measure);
  margin-left: auto;
  margin-right: auto;
  padding-left: var(--space-3);
  padding-right: var(--space-3);
}
@media (min-width: 768px) {
  .enterprise-zone {
    padding: var(--space-6) 0 var(--space-7);
  }
  .enterprise-zone > * {
    padding-left: var(--space-4);
    padding-right: var(--space-4);
  }
}
.portfolio-heading {
  font-family: var(--font-serif);
  font-weight: var(--type-weight-regular);
  font-size: var(--type-size-h1-base);
  line-height: var(--type-line-height-tight);
  letter-spacing: -0.02em;
  text-align: center;
  color: var(--ink-primary);
  margin: 0 auto var(--space-3);
}
.portfolio-intro {
  font-family: var(--font-serif);
  font-size: var(--type-size-body-base);
  line-height: var(--type-line-height-base);
  color: var(--ink-secondary);
  text-align: center;
  margin: 0 auto var(--space-5);
  max-width: 70ch;
}
@media (min-width: 768px) {
  .portfolio-intro {
    font-size: var(--type-size-body-comfortable);
  }
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ B1 grid — single column → 2-up → 3-up → 5-up.                          │
   └────────────────────────────────────────────────────────────────────────┘ */
.portfolio-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-3);
}
@media (min-width: 600px) {
  .portfolio-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 1024px) {
  .portfolio-grid { grid-template-columns: repeat(3, 1fr); }
}
@media (min-width: 1280px) {
  .portfolio-grid { grid-template-columns: repeat(5, 1fr); gap: var(--space-2); }
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Card composition                                                       │
   └────────────────────────────────────────────────────────────────────────┘ */
/* .portfolio-card is now an <a> — the whole card is the link to the
   per-product page. The redundant "Discover X →" inner CTA has been
   removed (was .portfolio-card-cta). Resetting link defaults (color,
   text-decoration) so the card reads as a static block; the existing
   border-colour hover/focus rules signal the affordance. */
.portfolio-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-3);
  background: var(--surface-card);
  border: 1px solid var(--rule-quiet);
  border-radius: 6px;
  color: inherit;
  text-decoration: none;
  transition: border-color var(--motion-quick) var(--easing);
  min-height: 44px; /* --target-standard touch-area floor per UX:1338 */
}
.portfolio-card:hover {
  border-color: var(--accent-primary);
}
.portfolio-card:focus-visible {
  border-color: var(--accent-primary);
  outline: 2px solid var(--ink-primary);
  outline-offset: 2px;
}
.portfolio-card-name {
  font-family: var(--font-serif);
  font-weight: var(--type-weight-semibold);
  font-size: var(--type-size-body-comfortable);
  line-height: var(--type-line-height-tight);
  color: var(--ink-primary);
  margin: 0;
}
.portfolio-card-tagline {
  font-family: var(--font-serif);
  font-style: italic;
  font-size: var(--type-size-body-base);
  line-height: var(--type-line-height-base);
  color: var(--ink-secondary);
  margin: 0;
}
.portfolio-card-body {
  font-family: var(--font-serif);
  font-size: var(--type-size-small-base);
  line-height: var(--type-line-height-base);
  color: var(--ink-secondary);
  margin: 0;
  max-width: 32ch;
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Hub-and-spoke variant (.portfolio-grid--hub) — Story 8.2.              │
   │ Mesh-centre topology (Tom-specced 2026-06-07):                         │
   │   • WorkSpace on top (apex, spans both cols, centered, wired).         │
   │   • TeamStore + Workforce Studio beneath it — the two feet WorkSpace   │
   │     stands on; surfaces inside the mesh, so NO trail.                  │
   │   • Enterprise Mesh at the centre (the wired hub).                     │
   │   • Local Assistant + Managed Hermes below (both wired).               │
   │   • Managed OpenClaw at the bottom — off-mesh by design (dashed, no    │
   │     trail; visual reinforcement of the boundary).                      │
   │                                                                       │
   │ Marching-ant trails ride between the Enterprise Mesh and WorkSpace /   │
   │ Local Assistant / Managed Hermes ONLY. DOM reading order is canonical  │
   │ (WorkSpace, TeamStore, Workforce Studio, Mesh, LA, MH, MOC); visual    │
   │ placement is [data-product]-driven so the accessible order is kept.    │
   │ Trail SVGs live as grid siblings in dedicated rows (3 + 5) so they     │
   │ never overlap card content. Narrow viewports collapse to one column in │
   │ source order and hide the trails — the wired-ness story becomes a      │
   │ stacked vertical read where horizontal geometry can't fit. Reduced     │
   │ motion freezes the ants via the tokens/motion-tokens.css global gate.  │
   └────────────────────────────────────────────────────────────────────────┘ */
.portfolio-grid--hub {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-3);
  position: relative;
}
.portfolio-grid--hub > .portfolio-hub-trail {
  display: none;
}
.portfolio-grid--hub > .portfolio-hub-divider {
  display: none;
}
@media (min-width: 768px) {
  .portfolio-grid--hub {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    grid-template-rows: auto auto var(--space-5) auto var(--space-5) auto auto auto;
    gap: var(--space-3);
    align-items: stretch;
    justify-items: stretch;
  }

  /* Row 1 — WorkSpace apex: spans both cols, centered + narrower, accent
     border so it reads as the lead surface sitting on the two feet. */
  .portfolio-grid--hub > [data-product="workspace"] {
    grid-column: 1 / span 2;
    grid-row: 1;
    justify-self: center;
    width: min(100%, 22rem);
    text-align: center;
    border-color: var(--accent-primary);
  }

  /* Row 2 — the two feet (surfaces inside the mesh; no trail). */
  .portfolio-grid--hub > [data-product="teamStore"]       { grid-column: 1; grid-row: 2; }
  .portfolio-grid--hub > [data-product="workforceStudio"] { grid-column: 2; grid-row: 2; }

  /* Row 3 — top trail: WorkSpace ↔ Mesh, single vertical line. */
  .portfolio-grid--hub > .portfolio-hub-trail--top {
    display: block;
    grid-column: 1 / span 2;
    grid-row: 3;
  }

  /* Row 4 — Enterprise Mesh centre hub: spans cols 1-2 (reads 2× wider),
     accent border + soft halo to read as "the centre". */
  .portfolio-grid--hub > [data-product="enterpriseMesh"] {
    grid-column: 1 / span 2;
    grid-row: 4;
    padding: var(--space-4);
    text-align: center;
    border-color: var(--accent-primary);
    box-shadow: 0 0 0 1px var(--accent-primary);
  }

  /* Row 5 — bottom trail: Mesh ↔ Local Assistant + Mesh ↔ Managed Hermes. */
  .portfolio-grid--hub > .portfolio-hub-trail--bottom {
    display: block;
    grid-column: 1 / span 2;
    grid-row: 5;
  }

  /* Row 6 — LA · MH below the Mesh (both wired). */
  .portfolio-grid--hub > [data-product="localAssistant"]     { grid-column: 1; grid-row: 6; }
  .portfolio-grid--hub > [data-product="managedHermesAgent"] { grid-column: 2; grid-row: 6; }

  /* Row 7 — soft Stigmergy divider (Primitive 5) marking the off-mesh
     boundary; reads as a thought-pause rather than a hard cut. */
  .portfolio-grid--hub > .portfolio-hub-divider {
    display: block;
    grid-column: 1 / span 2;
    grid-row: 7;
    width: 100%;
    max-width: 200px;
    height: 40px;
    margin: var(--space-4) auto 0;
    color: var(--accent-primary);
  }

  /* Row 8 — Managed OpenClaw, off-mesh by design (dashed border, no trail). */
  .portfolio-grid--hub > [data-product="managedOpenclaw"] {
    grid-column: 1 / span 2;
    grid-row: 8;
    border-style: dashed;
  }
}
@media (min-width: 1024px) {
  .portfolio-grid--hub {
    gap: var(--space-4);
  }
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Hub trail rendering — lines + marching ants.                          │
   │ Trail-line SVG stretches to its container with preserveAspectRatio    │
   │ ="none"; ants are rendered as separate fixed-pixel-size SVGs that    │
   │ animate via CSS keyframes on top/left percentages — that decouples    │
   │ ant glyph rendering from container-aspect distortion. Ants rotate so  │
   │ the smallest circle (head) leads in the direction of travel toward   │
   │ the Enterprise Mesh, not the abdomen (which is what rotate="auto" gets wrong on  │
   │ animateMotion since #stigmergy-ant's local +X points to the abdomen). │
   │ Reduced motion: tokens/motion-tokens.css zeroes animation-duration    │
   │ globally — ants freeze at the end of the keyframe (next to the Enterprise Mesh). │
   └────────────────────────────────────────────────────────────────────────┘ */
.portfolio-hub-trail {
  position: relative;
  width: 100%;
  height: 100%;
  color: var(--accent-primary);
}
.portfolio-hub-trail__lines {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
}
.portfolio-hub-ant {
  position: absolute;
  width: 18px;
  height: 6.75px;
  margin-left: -9px;
  margin-top: -3.375px;
  color: var(--accent-primary);
  fill: currentcolor;
  transform-origin: center;
  pointer-events: none;
}
/* Top trail = one vertical line (WorkSpace ↔ Enterprise Mesh); bottom trail =
   two short diagonals (Mesh ↔ Local Assistant / Managed Hermes). The vertical
   ants travel straight down/up at left 50%; the diagonal ants travel between
   the Mesh bottom-centre (50%) and the cards at 25% / 75%. Required CSS
   rotation for the ant's natural -X facing is θ = motion_angle − 180°:

     • WS→AM (down):       -90°     AM→WS (up):          +90°
     • AM→LA (down-left):  -12°     LA→AM (up-right):   +168°
     • AM→MH (down-right): -168°    MH→AM (up-left):     +12°

   Each motion keyframe carries opacity 0→1→1→0 across 0%/15%/85%/100% so ants
   fade in at the source and out at the destination. Reverse ants carry a
   half-cycle animation-delay so the pair on each line never runs in lockstep.
   Only WorkSpace / Local Assistant / Managed Hermes are wired — TeamStore +
   Workforce Studio (surfaces inside the mesh) and off-mesh Managed OpenClaw
   carry no ants. */
/* WS → AM: straight down, WorkSpace to the Enterprise Mesh top-centre. */
.portfolio-hub-ant--ws-am {
  animation: portfolio-hub-ant-ws-am 3.5s linear infinite;
}
@keyframes portfolio-hub-ant-ws-am {
  0%       { top: 0%;   left: 50%; transform: rotate(-90deg); opacity: 0; }
  15%, 85% { opacity: 1; }
  100%     { top: 100%; left: 50%; transform: rotate(-90deg); opacity: 0; }
}
/* AM → WS: straight up. Reverse of WS→AM. */
.portfolio-hub-ant--am-ws {
  animation: portfolio-hub-ant-am-ws 3.5s linear infinite 1.75s;
}
@keyframes portfolio-hub-ant-am-ws {
  0%       { top: 100%; left: 50%; transform: rotate(90deg); opacity: 0; }
  15%, 85% { opacity: 1; }
  100%     { top: 0%;   left: 50%; transform: rotate(90deg); opacity: 0; }
}
/* AM → LA: down-left from Mesh bottom-centre to LA. */
.portfolio-hub-ant--am-la {
  animation: portfolio-hub-ant-am-la 3.5s linear infinite;
}
@keyframes portfolio-hub-ant-am-la {
  0%       { top: 0%;   left: 50%; transform: rotate(-12deg); opacity: 0; }
  15%, 85% { opacity: 1; }
  100%     { top: 100%; left: 25%; transform: rotate(-12deg); opacity: 0; }
}
/* AM → MH: down-right from Mesh bottom-centre to MH. */
.portfolio-hub-ant--am-mh {
  animation: portfolio-hub-ant-am-mh 3.5s linear infinite;
}
@keyframes portfolio-hub-ant-am-mh {
  0%       { top: 0%;   left: 50%; transform: rotate(-168deg); opacity: 0; }
  15%, 85% { opacity: 1; }
  100%     { top: 100%; left: 75%; transform: rotate(-168deg); opacity: 0; }
}
/* LA → AM: up-right along the AM↔LA trail. Reverse of AM→LA. */
.portfolio-hub-ant--la-am {
  animation: portfolio-hub-ant-la-am 3.5s linear infinite 1.75s;
}
@keyframes portfolio-hub-ant-la-am {
  0%       { top: 100%; left: 25%; transform: rotate(168deg); opacity: 0; }
  15%, 85% { opacity: 1; }
  100%     { top: 0%;   left: 50%; transform: rotate(168deg); opacity: 0; }
}
/* MH → AM: up-left along the AM↔MH trail. Reverse of AM→MH. */
.portfolio-hub-ant--mh-am {
  animation: portfolio-hub-ant-mh-am 3.5s linear infinite 1.75s;
}
@keyframes portfolio-hub-ant-mh-am {
  0%       { top: 100%; left: 75%; transform: rotate(12deg); opacity: 0; }
  15%, 85% { opacity: 1; }
  100%     { top: 0%;   left: 50%; transform: rotate(12deg); opacity: 0; }
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Manifesto-entry CTA — quiet text-link (D7=a), narrative bridge.        │
   └────────────────────────────────────────────────────────────────────────┘ */
.manifesto-entry-cta {
  text-align: center;
  padding: var(--space-4) var(--space-3);
  margin: 0;
}
.manifesto-entry-cta a {
  font-family: var(--font-serif);
  font-style: italic;
  font-size: var(--type-size-body-base);
  color: var(--ink-secondary);
  text-decoration: underline;
  text-decoration-color: var(--rule-quiet);
  text-underline-offset: 0.25em;
  min-height: 44px; /* --target-standard */
  display: inline-block;
  padding: 0.5rem 0;
  transition:
    color var(--motion-quick) var(--easing),
    text-decoration-color var(--motion-quick) var(--easing);
}
.manifesto-entry-cta a:hover {
  color: var(--ink-primary);
  text-decoration-color: var(--accent-primary);
}
.manifesto-entry-cta a:focus-visible {
  outline: 2px solid var(--ink-primary);
  outline-offset: 2px;
  border-radius: 2px;
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ SMB zone — empty placeholder for Story 3.x value-prop content.        │
   │ At MVP-0 close-out the zone wrapper renders but holds no body content; │
   │ the data-aspect="smb" attribute lands the cascade for future content.  │
   └────────────────────────────────────────────────────────────────────────┘ */
.smb-zone {
  /* Intentionally empty at MVP-0 — Story 3.x adds value-prop scrollers. */
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ DPP pre-footer block — full Stigmergy aspect="dpp" cascade applies.   │
   │ Substrate dot-grid paints from tokens/layout-base.css :body; per-block │
   │ waypoint marks + trails + dividers land at Stigmergy primitive impl   │
   │ (defer to follow-up — Story 2.2 ships the structural shell + locked    │
   │ DPP voice copy + /partners link without the SVG primitives 2/3/4).      │
   └────────────────────────────────────────────────────────────────────────┘ */
.dpp-prefooter {
  padding: var(--space-6) var(--space-3);
  text-align: center;
  /* border-top removed 2026-05-13 — strong stigmergy divider injected by dpp-cta.eta partial */
  margin-top: var(--space-7);
}
@media (min-width: 768px) {
  .dpp-prefooter {
    padding: var(--space-7) var(--space-4);
  }
}
.dpp-heading {
  font-family: var(--font-serif);
  font-weight: var(--type-weight-regular);
  font-size: var(--type-size-body-comfortable);
  line-height: var(--type-line-height-tight);
  color: var(--ink-primary);
  margin: 0 auto var(--space-2);
  max-width: 60ch;
}
.dpp-line {
  font-family: var(--font-serif);
  font-style: italic;
  font-size: var(--type-size-body-base);
  line-height: var(--type-line-height-base);
  color: var(--ink-secondary);
  margin: 0 auto var(--space-3);
  max-width: 60ch;
}
.dpp-link {
  margin: 0;
}
.dpp-link a {
  font-family: var(--font-sans);
  font-size: var(--type-size-body-base);
  font-weight: var(--type-weight-medium);
  color: var(--accent-primary);
  text-decoration: underline;
  text-decoration-color: transparent;
  text-underline-offset: 0.25em;
  min-height: 44px; /* --target-standard */
  display: inline-block;
  padding: 0.5rem 0;
  transition: text-decoration-color var(--motion-quick) var(--easing);
}
.dpp-link a:hover {
  text-decoration-color: var(--accent-primary);
}
.dpp-link a:focus-visible {
  outline: 2px solid var(--ink-primary);
  outline-offset: 2px;
  border-radius: 2px;
}
/* Bottom CTA mirror — landing-page foot block that replaces the DPP
   pre-footer. Mirrors the hero CTA block visually (.hero-cta + .cta-lucie
   own the buttons themselves); this rule only owns the section padding +
   top margin so the block sits with the same vertical rhythm the
   pre-footer used to carry. */
.landing-foot-cta {
  padding: var(--space-6) var(--space-3);
  text-align: center;
  margin-top: var(--space-7);
}
@media (min-width: 768px) {
  .landing-foot-cta {
    padding: var(--space-7) var(--space-4);
  }
}
/* ════════════════════════════════════════════════════════════════════════
   Story 2.11 — Mesh-as-core landing body (SCP-2026-06-06).
   §2+3 six cornerstones (thesis lede folded in SCP-2026-06-08, the section
   heading/intro/foundation strip; ring layout lives in the §3 block above) ·
   §5 platform / surfaces layout.
   The standalone §2 what-is band was removed when it merged into §3
   (SCP-2026-06-08); its heading/intro now reuse the .pillars-heading/.pillars-
   intro styles via the relocated landing.pillars.* locale keys. */
/* ┌── §3 Sovereign Foundation base strip — the ground the six cornerstones
   │   stand on (renders beneath the ring; see the circular layout above). ───┐ */
.pillars-foundation {
  margin: var(--space-4) auto 0;
  background: var(--surface-card);
  border: 1px solid var(--rule-quiet);
  border-radius: 6px;
  padding-top: var(--space-4);
  padding-bottom: var(--space-4);
  text-align: center;
}
.pillars-foundation__name {
  font-family: var(--font-serif);
  font-weight: var(--type-weight-semibold);
  font-size: var(--type-size-body-comfortable);
  line-height: var(--type-line-height-tight);
  color: var(--ink-primary);
  margin: 0 0 var(--space-2);
}
.pillars-foundation__body {
  font-family: var(--font-serif);
  font-size: var(--type-size-body-base);
  line-height: var(--type-line-height-base);
  color: var(--ink-secondary);
  margin: 0 auto;
  max-width: 70ch;
}
/* ┌── §5 Platform / surfaces — "The matrix to transform the way you work."
   │   WorkSpace lead card (full width) → Workforce Studio + TeamStore 2-up →
   │   wired-to-the-Mesh base → quiet adjacents row. ────────────────────────┐ */
.platform-zone {
  padding: var(--space-5) 0 var(--space-6);
}
.platform-zone > * {
  width: 100%;
  max-width: var(--measure);
  margin-left: auto;
  margin-right: auto;
  padding-left: var(--space-3);
  padding-right: var(--space-3);
}
@media (min-width: 768px) {
  .platform-zone {
    padding: var(--space-6) 0 var(--space-7);
  }
  .platform-zone > * {
    padding-left: var(--space-4);
    padding-right: var(--space-4);
  }
}
.platform-heading {
  font-family: var(--font-serif);
  font-weight: var(--type-weight-regular);
  font-size: var(--type-size-h1-base);
  line-height: var(--type-line-height-tight);
  letter-spacing: -0.02em;
  text-align: center;
  color: var(--ink-primary);
  margin: 0 auto var(--space-3);
}
.platform-intro {
  font-family: var(--font-serif);
  font-size: var(--type-size-body-base);
  line-height: var(--type-line-height-base);
  color: var(--ink-secondary);
  text-align: center;
  margin: 0 auto var(--space-5);
  max-width: 70ch;
}
@media (min-width: 768px) {
  .platform-intro {
    font-size: var(--type-size-body-comfortable);
  }
}
/* Story 2.2 — B1 5-up portfolio grid + card consumer rules + manifesto-entry CTA + dpp pre-footer */
/* ──────────────────────────────────────────────────────────────────────────
   manifesto.css — Story 2.3 Manifesto Surface consumer rules.

   Lives under tokens/** so the four-prefix stylelint regex exemption
   (Story 1.1) covers ad-hoc class names (per portfolio.css/hero.css
   precedent).

   Layout discipline (Story 2.3 ACs):
     • Measure: ≤70ch on every text paragraph (article body, opening,
       closing, brand-mark, dpp-cta). Group + article headings allowed
       slightly tighter measure for hierarchy weight.
     • Native scroll preserved (no scroll-jacking — html { scroll-behavior:
       smooth } at layout-base.css is the global, no JS interception).
     • Editorial typeface (Charter, --font-serif) with --type-line-height-
       loose for generous reading rhythm.

   Stigmergy primitives (UX §Stigmergy Texture System Primitives 2–4):
     • .manifesto-waypoint — Primitive 2 left-edge mark, 7×22px envelope,
       absolutely positioned at the article's left edge. Symbol geometry +
       --waypoint-fill resolution live in templates/partials/svg-sprite.eta;
       opacity 0.85 applied here at the consumer per UX spec.
     • .manifesto-article::before — Primitive 3 pheromone trail. 1px hairline
       CSS gradient descending through the article, fading to transparent
       at 92% (linear-gradient direction + stop). Painted via ::before so
       no extra DOM, fully tokenized via --trail-stroke.
     • .manifesto-divider — Primitive 4 ant-body row divider, 240×38 SVG
       symbol centred between sections (viewBox grew from 240×36 → 240×38
       per SCP-2026-05-13 to admit full thorax + abdomen rows). Geometry +
       colour-token resolution live in svg-sprite.eta.

   Application rules (UX-DR1 + UX §Stigmergy §Application Rules):
     • NO pheromone-trail underline on body type
     • NO dot-pattern fill on headings
     • NO metallic finish on type
     • Type fills stay solid-on-solid for AA + i18n integrity.

   Reduced-motion: nothing here animates (the surface is static per Story
   2.3 — scroll-cue ant + cursor trail belong to Stories 2.8 + 2.9 on
   section-index surfaces only). Hover transitions on the DPP CTA inherit
   --motion-quick which the global escape hatch zeroes under reduced.
   ────────────────────────────────────────────────────────────────────────── */
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Article container — outer wrapper for the manifesto document.          │
   └────────────────────────────────────────────────────────────────────────┘ */
.manifesto {
  width: 100%;
  max-width: 44rem;
  margin: 0 auto;
  padding: var(--space-5) var(--space-3) var(--space-7);
  color: var(--ink-primary);
  font-family: var(--font-serif);
}
@media (min-width: 768px) {
  .manifesto {
    padding: var(--space-6) var(--space-4) var(--space-7);
  }
}
@media (min-width: 1280px) {
  .manifesto {
    max-width: 50rem;
  }
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Page H1 — restrained editorial title; document anchor for AT.          │
   └────────────────────────────────────────────────────────────────────────┘ */
.manifesto-h1 {
  font-family: var(--font-serif);
  font-weight: var(--type-weight-regular);
  font-size: var(--type-size-h1-base);
  line-height: var(--type-line-height-tight);
  letter-spacing: -0.02em;
  color: var(--ink-primary);
  margin: 0 0 var(--space-4);
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Opening / closing / brand-mark — flowing prose, ≤70ch measure.         │
   └────────────────────────────────────────────────────────────────────────┘ */
.manifesto-opening,
.manifesto-closing,
.manifesto-brand-mark,
.manifesto-team-mark {
  font-family: var(--font-serif);
  font-size: var(--type-size-body-base);
  line-height: var(--type-line-height-loose);
  color: var(--ink-primary);
  max-width: 70ch;
  margin: 0 auto var(--space-5);
}
@media (min-width: 768px) {
  .manifesto-opening,
  .manifesto-closing,
  .manifesto-brand-mark,
  .manifesto-team-mark {
    font-size: var(--type-size-body-comfortable);
  }
}
.manifesto-opening {
  font-style: italic;
  color: var(--ink-secondary);
  margin-bottom: var(--space-6);
}
.manifesto-closing {
  margin-top: var(--space-6);
  margin-bottom: var(--space-3);
  font-style: italic;
}
.manifesto-brand-mark {
  /* Story 2.10: tightened so the teamMark close sits as a near sibling. */
  margin-bottom: var(--space-2);
  color: var(--ink-secondary);
}
.manifesto-brand-mark strong {
  font-weight: var(--type-weight-semibold);
  color: var(--ink-primary);
}
/* Team mark — Story 2.10 AC8. Sits tight below the brand mark as a quieter
   sibling close; /about-tier surfaces only (gated in the template). */
.manifesto-team-mark {
  color: var(--ink-secondary);
}
.manifesto-team-mark strong {
  font-weight: var(--type-weight-semibold);
  color: var(--ink-primary);
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Section group — Three Truths / Refusals / Commitments / Purpose.       │
   └────────────────────────────────────────────────────────────────────────┘ */
.manifesto-group {
  margin: var(--space-5) 0;
}
.manifesto-group-heading {
  font-family: var(--font-serif);
  font-weight: var(--type-weight-semibold);
  font-size: var(--type-size-body-comfortable);
  line-height: var(--type-line-height-tight);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-secondary);
  margin: 0 0 var(--space-3);
  max-width: 70ch;
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Manifesto article — heading + body block. Hosts Primitive 2 waypoint   │
   │ (absolute) + Primitive 3 pheromone trail (::before hairline gradient). │
   └────────────────────────────────────────────────────────────────────────┘ */
.manifesto-article {
  position: relative;
  margin: 0 0 var(--space-5);
  padding-left: var(--space-3);
}
/* Primitive 3 — pheromone trail. 1px hairline gradient descending through
   the article, fading to transparent at 92% per UX spec line 1004. Painted
   via ::before, positioned at the same x as the waypoint mark so the trail
   appears to emanate from the column of dots. */
.manifesto-article::before {
  content: "";
  position: absolute;
  top: var(--space-3);
  left: 3px;
  width: 1px;
  height: calc(100% - var(--space-3));
  background: linear-gradient(to bottom, var(--trail-stroke), transparent 92%);
  pointer-events: none;
}
.manifesto-article-heading {
  font-family: var(--font-serif);
  font-weight: var(--type-weight-semibold);
  font-size: var(--type-size-body-comfortable);
  line-height: var(--type-line-height-tight);
  color: var(--ink-primary);
  margin: 0 0 var(--space-2);
  max-width: 60ch;
}
@media (min-width: 768px) {
  .manifesto-article-heading {
    font-size: 1.375rem;
  }
}
.manifesto-numeral {
  display: inline-block;
  margin-right: 0.4em;
  font-family: var(--font-serif);
  font-style: italic;
  font-weight: var(--type-weight-regular);
  color: var(--ink-quiet);
  letter-spacing: 0.02em;
}
.manifesto-article-body {
  font-family: var(--font-serif);
  font-size: var(--type-size-body-base);
  line-height: var(--type-line-height-loose);
  color: var(--ink-primary);
  margin: 0;
  max-width: 70ch;
}
@media (min-width: 768px) {
  .manifesto-article-body {
    font-size: var(--type-size-body-comfortable);
  }
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Primitive 2 — waypoint mark. 7×22 envelope, absolutely positioned at   │
   │ the article's left edge so the column of dots aligns with the trail.   │
   └────────────────────────────────────────────────────────────────────────┘ */
.manifesto-waypoint {
  position: absolute;
  top: 0;
  left: 0;
  width: 7px;
  height: 22px;
  opacity: 0.85;
  pointer-events: none;
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Primitive 4 — ant-body row divider between sections.                   │
   │ Centred, sized to the editorial column, no ornamentation around it.    │
   └────────────────────────────────────────────────────────────────────────┘ */
.manifesto-divider {
  display: block;
  width: 240px;
  height: 38px;
  margin: var(--space-5) auto;
}
@media (min-width: 768px) {
  .manifesto-divider {
    margin: var(--space-6) auto;
  }
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ DPP CTA — quiet footer-zone text-link (Story 2.3 AC: never a button,   │
   │ never a hero. Pattern matches portfolio.css .manifesto-entry-cta.).    │
   └────────────────────────────────────────────────────────────────────────┘ */
.manifesto-dpp-cta {
  text-align: center;
  margin: var(--space-6) 0 0;
  font-family: var(--font-serif);
  font-size: var(--type-size-body-base);
  font-style: italic;
  color: var(--ink-secondary);
}
.manifesto-dpp-cta a {
  color: var(--ink-secondary);
  text-decoration: underline;
  text-decoration-color: var(--rule-quiet);
  text-underline-offset: 0.25em;
  min-height: 44px; /* --target-standard touch-area floor */
  display: inline-block;
  padding: 0.5rem 0;
  transition:
    color var(--motion-quick) var(--easing),
    text-decoration-color var(--motion-quick) var(--easing);
}
.manifesto-dpp-cta a:hover {
  color: var(--ink-primary);
  text-decoration-color: var(--accent-primary);
}
.manifesto-dpp-cta a:focus-visible {
  outline: 2px solid var(--ink-primary);
  outline-offset: 2px;
  border-radius: 2px;
}
/* Story 2.3 — manifesto surface (≤70ch measure, editorial rhythm, Stigmergy Primitives 2–4 consumer rules) */
/* ──────────────────────────────────────────────────────────────────────────
   nav.css — Story 2.4 Section Navigation consumer rules.

   Lives under tokens/** so the four-prefix stylelint regex exemption
   (Story 1.1) covers ad-hoc class names (per portfolio.css/hero.css/
   manifesto.css precedent).

   UX spec §Section Nav (codified 2026-05-09):
     • 5 top-level entries — Products / Solutions / Manifesto / About / Pricing
     • Products + About = standard dropdowns (<details><summary>)
     • Solutions = mega-menu (<details><summary> + grid layout)
     • Manifesto + Pricing = flat <a> links
     • Sticky header on scroll, no CLS
     • Active state via aria-current="page" (server-side via surface map)
     • Desktop ≥1024px: inline 5 entries; sub-menus open as dropdowns
     • Tablet 768–1024px: inline 5 entries (tight but holds per spec line 2146)
     • Mobile <768px: hamburger toggle reveals primary nav as a sheet;
       sub-menus expand inline within the sheet (native <details> behaviour)

   The hamburger button + sheet pattern uses pure-CSS toggle via the
   data-nav-open attribute set by JS (public/js/nav-toggle.js). When JS
   fails to load, the .nav-toggle button stays hidden on desktop (no harm)
   and the primary nav stays visible on mobile (no JS-required regression).

   Reduced-motion: dropdown open/close transitions inherit --motion-quick
   which the global escape hatch zeroes under reduced. Hamburger sheet
   slide-in is instant under reduced.
   ────────────────────────────────────────────────────────────────────────── */
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Hamburger toggle button — visible on mobile only.                      │
   └────────────────────────────────────────────────────────────────────────┘ */
.nav-toggle {
  display: inline-flex;
  flex-direction: column;
  justify-content: center;
  gap: 4px;
  width: 44px;
  height: 44px;
  padding: 10px;
  background: transparent;
  border: 1px solid var(--rule-quiet);
  border-radius: 4px;
  cursor: pointer;
  color: var(--ink-primary);
}
.nav-toggle:focus-visible {
  outline: 2px solid var(--accent-primary);
  outline-offset: 2px;
}
.nav-toggle-bar {
  display: block;
  height: 2px;
  width: 100%;
  background: currentColor;
  border-radius: 1px;
}
@media (min-width: 768px) {
  .nav-toggle {
    display: none;
  }
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Primary nav — base structure.                                          │
   ├────────────────────────────────────────────────────────────────────────┤
   │ Mobile (<768px): hidden by default; revealed when the body carries     │
   │ data-nav-open="true" (set by nav-toggle.js). Sheet-style: full-width   │
   │ panel below the header.                                                │
   │ Tablet+ (≥768px): inline horizontal row, always visible.               │
   └────────────────────────────────────────────────────────────────────────┘ */
.nav--primary {
  display: none;
}
body[data-nav-open="true"] .nav--primary {
  display: block;
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  padding: var(--space-3);
  background: var(--surface-card);
  border-bottom: 1px solid var(--rule-quiet);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.04);
  z-index: 50;
}
@media (min-width: 768px) {
  .nav--primary {
    display: block;
    position: static;
    padding: 0;
    background: transparent;
    border: none;
    box-shadow: none;
  }
}
.nav-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
@media (min-width: 768px) {
  .nav-list {
    flex-direction: row;
    align-items: center;
    gap: var(--space-3);
  }
}
.nav-item {
  position: relative;
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Flat top-level entries (Manifesto, Pricing) + summary buttons.         │
   │ Shared visual language: editorial sans, quiet underline on hover/      │
   │ focus, accent underline when aria-current="page".                      │
   └────────────────────────────────────────────────────────────────────────┘ */
.nav-link,
.nav-summary {
  display: inline-flex;
  align-items: center;
  gap: 0.25em;
  padding: var(--space-1);
  min-height: 44px; /* --target-standard touch-area floor */
  font-family: var(--font-sans);
  font-size: var(--type-size-small-base);
  font-weight: var(--type-weight-medium);
  color: var(--ink-primary);
  text-decoration: underline;
  text-decoration-color: transparent;
  text-underline-offset: 0.35em;
  cursor: pointer;
  background: transparent;
  border: none;
  list-style: none;
  transition: text-decoration-color var(--motion-quick) var(--easing);
}
.nav-link:hover,
.nav-summary:hover,
.nav-link:focus-visible,
.nav-summary:focus-visible {
  text-decoration-color: var(--accent-primary);
}
.nav-link:focus-visible,
.nav-summary:focus-visible {
  outline: 2px solid var(--accent-primary);
  outline-offset: 2px;
  border-radius: 2px;
}
.nav-link[aria-current="page"],
.nav-summary[aria-current="page"] {
  text-decoration-color: var(--accent-primary);
}
/* Suppress the native <details><summary> disclosure triangle. */
.nav-summary::-webkit-details-marker { display: none; }
.nav-summary { list-style: none; }
.nav-summary::after {
  content: "";
  display: inline-block;
  width: 0.5em;
  height: 0.5em;
  margin-left: 0.25em;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg) translateY(-2px);
  transition: transform var(--motion-quick) var(--easing);
}
.nav-details[open] > .nav-summary::after {
  transform: rotate(225deg) translateY(2px);
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Standard dropdown (Products, About) sub-menu.                          │
   │ Mobile: in-flow expansion below the summary.                           │
   │ Desktop: absolute-positioned panel anchored to the parent <li>.        │
   └────────────────────────────────────────────────────────────────────────┘ */
.nav-submenu {
  list-style: none;
  margin: var(--space-1) 0 0;
  padding: var(--space-2);
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}
@media (min-width: 768px) {
  .nav-details:not(.nav-details--mega) > .nav-submenu {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    min-width: 200px;
    background: var(--surface-card);
    border: 1px solid var(--rule-quiet);
    border-radius: 8px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.06);
    z-index: 40;
  }
}
/* Story 3.32: group label inside the Products dropdown (3-group FR8j structure).
   Non-interactive; reuses .nav-mega-heading typography. First group sits flush
   under the "All products" link, later groups get a little breathing room. */
.nav-submenu-group {
  padding: var(--space-1) 0.5rem 0;
}
.nav-submenu-group + .nav-submenu-group,
.nav-submenu a + .nav-submenu-group {
  margin-top: var(--space-1);
}
.nav-submenu-group .nav-mega-heading {
  margin: 0;
}
.nav-submenu a,
.nav-mega-col a {
  display: block;
  padding: 0.5rem 0.5rem;
  min-height: 44px;
  font-family: var(--font-sans);
  font-size: var(--type-size-small-base);
  color: var(--ink-secondary);
  text-decoration: none;
  border-radius: 6px;
  transition:
    color var(--motion-quick) var(--easing),
    background-color var(--motion-quick) var(--easing);
}
.nav-submenu a:hover,
.nav-mega-col a:hover {
  color: var(--ink-primary);
  background: var(--surface-page);
}
.nav-submenu a:focus-visible,
.nav-mega-col a:focus-visible {
  outline: 2px solid var(--accent-primary);
  outline-offset: 2px;
}
.nav-submenu a[aria-current="page"],
.nav-mega-col a[aria-current="page"] {
  color: var(--ink-primary);
  font-weight: var(--type-weight-medium);
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Mega-menu (Solutions): two-axis grouping (by-size + by-sector).        │
   │ Mobile: stacked groups in flow; tree-like inside the sheet.            │
   │ Desktop: All solutions on a full-width row; 2-col groups below.        │
   └────────────────────────────────────────────────────────────────────────┘ */
.nav-mega {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin-top: var(--space-1);
  padding: var(--space-2);
}
@media (min-width: 768px) {
  .nav-details--mega > .nav-mega {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    display: grid;
    grid-template-columns: minmax(180px, 1fr) minmax(220px, 1fr);
    gap: var(--space-3);
    min-width: 480px;
    padding: var(--space-3);
    background: var(--surface-card);
    border: 1px solid var(--rule-quiet);
    border-radius: 8px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.06);
    z-index: 40;
  }
  /* All solutions leads the panel on its own full-width row; the by-size
     and by-sector groups flow into the two columns directly below it. */
  .nav-details--mega > .nav-mega > .nav-mega-col {
    grid-column: 1 / -1;
  }
}
.nav-mega-group {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}
.nav-mega-heading {
  margin: 0 0 var(--space-1);
  font-family: var(--font-sans);
  font-size: var(--type-size-eyebrow-base);
  font-weight: var(--type-weight-semibold);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ink-quiet);
}
.nav-mega-col {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Body lock when mobile sheet is open — prevents background scroll.      │
   └────────────────────────────────────────────────────────────────────────┘ */
@media (max-width: 767.98px) {
  body[data-nav-open="true"] {
    overflow: hidden;
  }
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Locale switcher (Story 2.5) — globe icon + current-locale dropdown.    │
   │ Sits inside .nav--utility between primary nav and mode toggle. Uses    │
   │ <details><summary> so the same nav-toggle.js outside-click + Esc       │
   │ handlers close it for free.                                            │
   └────────────────────────────────────────────────────────────────────────┘ */
.locale-switcher {
  position: relative;
}
.locale-switcher-summary {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  padding: 0.375rem 0.625rem;
  min-height: 32px;
  font-family: var(--font-sans);
  font-size: var(--type-size-meta-base);
  font-weight: var(--type-weight-medium);
  color: var(--ink-secondary);
  background: transparent;
  border: 1px solid var(--rule-quiet);
  border-radius: 6px;
  cursor: pointer;
  list-style: none;
  transition:
    border-color var(--motion-quick) var(--easing),
    color var(--motion-quick) var(--easing);
}
.locale-switcher-summary::-webkit-details-marker { display: none; }
.locale-switcher-summary:hover {
  color: var(--ink-primary);
  border-color: var(--metal-platine);
}
.locale-switcher-summary:focus-visible {
  outline: 2px solid var(--accent-primary);
  outline-offset: 2px;
}
.locale-switcher-icon {
  flex: 0 0 16px;
  color: currentColor;
}
.locale-switcher-label {
  letter-spacing: 0.04em;
}
.locale-switcher-menu {
  list-style: none;
  margin: 4px 0 0;
  padding: var(--space-1);
  position: absolute;
  top: calc(100% + 4px);
  right: 0;
  min-width: 160px;
  background: var(--surface-card);
  border: 1px solid var(--rule-quiet);
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.06);
  z-index: 40;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.locale-switcher-menu a {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  padding: 0.5rem 0.625rem;
  min-height: 44px; /* --target-standard touch-area floor */
  font-family: var(--font-sans);
  font-size: var(--type-size-meta-base);
  color: var(--ink-secondary);
  text-decoration: none;
  border-radius: 6px;
  transition:
    color var(--motion-quick) var(--easing),
    background-color var(--motion-quick) var(--easing);
}
.locale-switcher-menu a:hover {
  color: var(--ink-primary);
  background: var(--surface-page);
}
.locale-switcher-menu a:focus-visible {
  outline: 2px solid var(--accent-primary);
  outline-offset: 2px;
}
.locale-switcher-menu-short {
  font-weight: var(--type-weight-semibold);
  letter-spacing: 0.04em;
  color: var(--ink-primary);
  min-width: 1.5rem;
}
.locale-switcher-menu-name {
  color: var(--ink-secondary);
}
/* Story 2.4 — section navigation (5-entry top-level + sub-menus + mega-menu + hamburger + sticky header) */
/* ──────────────────────────────────────────────────────────────────────────
   consent.css — Story 2.6 Cookie Consent Interface consumer rules.

   Lives under tokens/** so the four-prefix stylelint regex exemption
   (Story 1.1) covers ad-hoc class names (per nav.css/manifesto.css
   precedent).

   COMPOSITION:
     • Dialog: sticky bottom banner. Full-width on mobile, max-width on
       desktop (anchored bottom-right). High z-index so it sits above
       the sticky header (z-index 30) and any future modal but below
       the Lucie widget.
     • Inner: card-style container with --surface-card background, 1px
       border, generous padding for readable copy.
     • Options list: each opt-in feature is a row with a checkbox +
       label + description. Default unchecked (opt-in is active).
     • Actions row: [Save] + [Reject all] buttons, equal weight + size
       per the no-dark-pattern AC. Save uses the accent fill to mark
       the primary affordance; Reject all uses the surface fill with
       the same border. Source order is Save → Reject all.
     • Persistent trigger: small bottom-left button visible whenever the
       dialog is hidden (i.e. visitor has made a choice). Allows
       withdrawal at any time per the AC.

   ACCESSIBILITY:
     • Reduced-motion: no entrance animation; the dialog appears/disappears
       instantly. The global motion escape hatch handles any inherited
       transition tokens.
     • Focus: consent.js sets focus to the first checkbox when the
       dialog opens. CSS provides visible focus-visible outlines on
       both the checkboxes and the action buttons.
     • Tab order: source order is checkbox(es) → privacy link → Save →
       Reject all. The user must engage with the choices before reaching
       the primary action.

   STATE TOGGLE:
     • Dialog visibility is driven by the `hidden` HTML attribute
       (consent.js writes / reads it). CSS [hidden] selector auto-hides.
     • Trigger visibility is driven by sibling-state: when the dialog is
       NOT hidden (i.e. open), the trigger hides — no double affordance.
   ────────────────────────────────────────────────────────────────────────── */
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Dialog — sticky bottom banner.                                         │
   └────────────────────────────────────────────────────────────────────────┘ */
.consent-dialog {
  position: fixed;
  left: var(--space-3);
  right: var(--space-3);
  bottom: var(--space-3);
  z-index: 60;
  display: flex;
  justify-content: center;
}
/* The HTML `hidden` attribute defaults to `display: none`, but our
   `display: flex` rule above overrides it. Re-pin `display: none` for
   the hidden state so consent.js's hidden=true actually hides the dialog. */
.consent-dialog[hidden] {
  display: none;
}
@media (min-width: 768px) {
  .consent-dialog {
    left: auto;
    right: var(--space-4);
    bottom: var(--space-4);
  }
}
.consent-dialog-inner {
  width: 100%;
  max-width: 520px;
  padding: var(--space-3);
  background: var(--surface-card);
  border: 1px solid var(--rule-quiet);
  border-radius: 6px;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.08);
  font-family: var(--font-sans);
  color: var(--ink-primary);
}
.consent-dialog-title {
  margin: 0 0 var(--space-1);
  font-family: var(--font-serif);
  font-size: var(--type-size-body-comfortable);
  font-weight: var(--type-weight-semibold);
  line-height: var(--type-line-height-tight);
  color: var(--ink-primary);
}
.consent-dialog-body {
  margin: 0 0 var(--space-2);
  font-family: var(--font-sans);
  font-size: var(--type-size-meta-base);
  line-height: var(--type-line-height-base);
  color: var(--ink-secondary);
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Options list — one row per opt-in feature. Default unchecked.          │
   │ Adding a new opt-in is: 1 new <li>, 1 new entry in consent.js FLAGS.   │
   └────────────────────────────────────────────────────────────────────────┘ */
.consent-options {
  list-style: none;
  margin: 0 0 var(--space-2);
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}
.consent-option-row {
  margin: 0;
}
.consent-option {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  padding: var(--space-1);
  border: 1px solid var(--rule-quiet);
  border-radius: 6px;
  cursor: pointer;
  transition: border-color var(--motion-quick) var(--easing);
}
.consent-option:hover {
  border-color: var(--metal-platine);
}
/* Switch-style toggle: real <input type="checkbox" role="switch">
   visually hidden under the styled track. The input keeps the click +
   focus target (full-size, opacity 0 above the track) so AT and
   keyboard work natively without extra JS. */
.consent-toggle {
  position: relative;
  flex: 0 0 auto;
  display: inline-block;
  width: 36px;
  height: 20px;
  margin-top: 2px;
}
.consent-option-input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  opacity: 0;
  cursor: pointer;
  z-index: 1;
}
.consent-toggle-track {
  position: absolute;
  inset: 0;
  background: var(--rule-quiet);
  border-radius: 999px;
  transition: background-color var(--motion-quick) var(--easing);
}
.consent-toggle-thumb {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 16px;
  height: 16px;
  background: var(--surface-card);
  border-radius: 50%;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.18);
  transition: transform var(--motion-quick) var(--easing);
}
.consent-option-input:checked ~ .consent-toggle-track {
  background: var(--accent-primary);
}
.consent-option-input:checked ~ .consent-toggle-track .consent-toggle-thumb {
  transform: translateX(16px);
}
.consent-option-input:focus-visible ~ .consent-toggle-track {
  outline: 2px solid var(--accent-primary);
  outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
  .consent-toggle-track,
  .consent-toggle-thumb {
    transition: none;
  }
}
.consent-option-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-family: var(--font-sans);
  font-size: var(--type-size-meta-base);
  line-height: var(--type-line-height-base);
}
.consent-option-label {
  color: var(--ink-primary);
  font-weight: var(--type-weight-medium);
}
.consent-option-description {
  color: var(--ink-secondary);
}
.consent-dialog-policy-link {
  margin: 0 0 var(--space-3);
  font-family: var(--font-sans);
  font-size: var(--type-size-meta-base);
  line-height: var(--type-line-height-base);
}
.consent-dialog-policy-link a {
  color: var(--ink-primary);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.consent-dialog-policy-link a:hover,
.consent-dialog-policy-link a:focus-visible {
  color: var(--accent-primary);
}
.consent-dialog-actions {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}
@media (min-width: 480px) {
  .consent-dialog-actions {
    flex-direction: row;
    justify-content: flex-end;
    gap: var(--space-2);
  }
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Save + Reject all buttons — equal weight per no-dark-pattern AC.       │
   │ Same size, padding, border, font-weight, hover treatment. Only the    │
   │ background colour distinguishes them — Save uses --accent-primary    │
   │ (primary CTA the user reached by ticking boxes), Reject all uses      │
   │ --surface-card with the same border.                                  │
   └────────────────────────────────────────────────────────────────────────┘ */
.consent-button {
  flex: 1 1 auto;
  min-height: 44px; /* --target-standard touch-area floor */
  padding: 0.625rem 1rem;
  font-family: var(--font-sans);
  font-size: var(--type-size-meta-base);
  font-weight: var(--type-weight-medium);
  border: 1px solid var(--rule-quiet);
  border-radius: 6px;
  cursor: pointer;
  transition:
    background-color var(--motion-quick) var(--easing),
    border-color var(--motion-quick) var(--easing),
    color var(--motion-quick) var(--easing);
}
.consent-button:focus-visible {
  outline: 2px solid var(--accent-primary);
  outline-offset: 2px;
}
.consent-button--reject {
  background: var(--surface-card);
  color: var(--ink-primary);
  border-color: var(--metal-platine);
}
.consent-button--save {
  background: var(--accent-primary);
  color: var(--ink-on-accent);
  border-color: var(--accent-primary);
}
/* Hover background-swap (reject) and brightness filter (save) removed —
   fills stay at their resting state. Scale + shine in cta-interaction.css
   are the sole hover signal for both variants. */
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Persistent withdrawal trigger — bottom-left, low-key, always-on.       │
   │ Visible only when the dialog is NOT shown (hidden attribute is set).  │
   │ Sibling-selector trick: when the dialog is hidden (default once       │
   │ choice made), reveal the trigger. When the dialog is open, hide it.   │
   └────────────────────────────────────────────────────────────────────────┘ */
.consent-trigger {
  position: fixed;
  left: var(--space-3);
  bottom: var(--space-3);
  z-index: 50;
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  padding: 0.375rem 0.625rem;
  min-height: 32px;
  background: var(--surface-card);
  border: 1px solid var(--rule-quiet);
  border-radius: 6px;
  cursor: pointer;
  font-family: var(--font-sans);
  font-size: var(--type-size-meta-base);
  color: var(--ink-secondary);
  transition:
    color var(--motion-quick) var(--easing),
    border-color var(--motion-quick) var(--easing);
}
/* Hover colour/border swap removed — resting state stays on hover.
   Scale + shine in cta-interaction.css are the sole hover signal. */
.consent-trigger:focus-visible {
  outline: 2px solid var(--accent-primary);
  outline-offset: 2px;
}
.consent-trigger-icon {
  flex: 0 0 14px;
  color: currentColor;
}
/* When dialog is open (NOT hidden), suppress the trigger to avoid the
   double-affordance. CSS adjacent-sibling selector reads the dialog's
   :not([hidden]) state. */
.consent-dialog:not([hidden]) ~ .consent-trigger {
  display: none;
}
/* Hide trigger label on narrow screens — icon-only is enough. */
@media (max-width: 479.98px) {
  .consent-trigger-label {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
  }
}
/* Story 2.6 — cookie consent dialog + persistent withdrawal trigger */
/* ──────────────────────────────────────────────────────────────────────────
   cursor-trail.css — Stigmergy Cursor Trail (Motion Exception B), rev 3.

   Rev 3: trail is landing-page-bottom-only. cursor-trail.js gates on
   [data-cursor-trail-anchor] (mounted exclusively on the SMB-zone +
   DPP-prefooter wrapper inside templates/pages/landing-page.eta). The
   18 other hero surfaces no longer render the trail.

   Lives under tokens/** so the four-prefix stylelint regex exemption
   (Story 1.1) covers ad-hoc class names (per nav.css/manifesto.css/
   consent.css/hero.css precedent).

   COMPOSITION:
     • Fixed-position SVG overlay covers the entire viewport.
     • z-index 5 — below the sticky header (z-30), Lucie widget (its own
       root), nav dropdowns, mobile sheet, consent dialog. Above the
       page content + Stigmergy substrate dot-grid.
     • pointer-events: none — the trail never intercepts clicks /
       hovers / focus from any underlying element.
     • Opacity is JS-driven (cursor-trail.js writes inline style); this
       file only defines the transition shape so the fade-on-CTA + fade-
       on-stop behaviours feel smooth.
     • Trail stroke + ant glyphs use currentColor → --accent-primary.
       This matches Stigmergy Primitive 4 (#stigmergy-divider) which
       paints its trail at var(--accent-primary) stroke-opacity 0.55 —
       cursor trail and static stigmergy now share the same accent.
       Mode-adaptive: EU blue on light, EU gold on dark.

   PRIVACY NOTE (mirrored from cursor-trail.js): no styling here writes
   anything observable to the page beyond the cursor visual itself. No
   data-* attributes captured into selectors that downstream telemetry
   could read.

   This file is loaded from tokens/index.css. The cursor-trail.js script
   appends the overlay element at runtime — which means the overlay
   doesn't appear in the HTML source and therefore never affects FOUC
   visual snapshots (Story 1.3) or first-paint screenshot tests.
   ────────────────────────────────────────────────────────────────────────── */
.cursor-trail {
  position: fixed;
  top: 0;
  left: 0;
  pointer-events: none;
  z-index: 5;
  color: var(--accent-primary);
  opacity: 0;
  /* Slower fade than rev 1 (was --motion-duration-quick 120ms) — the
     trail is intentionally lingering now; the visual decay is part of
     the brand metaphor (pheromone deposition + slow evaporation). */
  transition: opacity var(--motion-duration-slow) var(--motion-easing-base);
}
.cursor-trail-stroke {
  /* Trail segments paint as <line> elements with per-segment
     stroke-opacity computed from sample-age vs TRAIL_LIFETIME_MS in
     cursor-trail.js. Older end of the trail fades first; after the
     cursor stops the whole trail keeps fading until invisible. CSS
     declares only the look that doesn't depend on age — the stroke
     itself is set on the SVG attribute (currentColor + thin width). */
}
.cursor-trail-ant {
  color: var(--accent-primary);
  opacity: 0;
  transition: opacity var(--motion-duration-base) var(--motion-easing-base);
}
.cursor-trail-antennae {
  /* Antennae deploy ONLY when all 3 ants in a V-cluster are literally
     at their formation slots — never before, never while ants are
     moving. cursor-trail.js writes inline opacity 0/1 each frame; we
     deliberately omit a transition so the antennae snap cleanly off
     the instant any ant starts moving (cursor resumes / disperse). */
  opacity: 0;
}
/* Story 2.9 rev 3 — Motion Exception B: cursor trail overlay (landing-page bottom anchor only, cursor surfaces only) */
/* ──────────────────────────────────────────────────────────────────────────
   products.css — Story 3.1+ per-product page consumer rules.

   Lives under tokens/** so the four-prefix stylelint regex exemption
   (Story 1.1) covers ad-hoc class names (per nav.css/manifesto.css/
   consent.css/cursor-trail.css/hero.css precedent).

   The .product-page wrapper carries data-aspect so token cascades from
   tokens/aspects.css land cleanly (enterprise variant elevates accent
   ratio for the hero / CTA block). Type stays solid-on-solid (UX-DR1
   no-metallic-on-type rule).

   Composition (Story 3.1 ACs):
     • Hero: eyebrow (product name) + h1 (outcome promise) + sub.
     • Sections (what-it-does, audiences, trust, CTA block) follow a
       consistent rhythm: h2 + body + optional grid.
     • Two equal-weight static fallback CTAs in the get-started block —
       primary (book a pilot) + secondary (create account). Equal size,
       equal padding, equal min-height; only the colour treatment
       distinguishes them per UX-DR (no dark pattern between
       enterprise/SMB CTAs — both are valid choices for different
       audiences).
   ────────────────────────────────────────────────────────────────────────── */
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Page-level wrapper.                                                    │
   └────────────────────────────────────────────────────────────────────────┘ */
.product-page {
  width: 100%;
  max-width: var(--measure);
  margin: 0 auto;
  padding: var(--space-5) var(--space-3) var(--space-7);
  color: var(--ink-primary);
  font-family: var(--font-serif);
}
@media (min-width: 768px) {
  .product-page {
    padding: var(--space-6) var(--space-4) var(--space-7);
  }
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Hero block — eyebrow + h1 + sub.                                       │
   └────────────────────────────────────────────────────────────────────────┘ */
.product-hero {
  margin-bottom: var(--space-6);
  text-align: left;
}
.product-eyebrow {
  font-family: var(--font-sans);
  font-size: var(--type-size-eyebrow-base);
  font-weight: var(--type-weight-medium);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-quiet);
  margin: 0 0 var(--space-2);
}
.product-h1 {
  font-family: var(--font-serif);
  font-weight: var(--type-weight-regular);
  font-size: var(--type-size-h1-base);
  line-height: var(--type-line-height-tight);
  letter-spacing: -0.02em;
  color: var(--ink-primary);
  margin: 0 0 var(--space-3);
  max-width: 18ch;
}
.product-sub {
  font-family: var(--font-serif);
  font-size: var(--type-size-body-base);
  line-height: var(--type-line-height-loose);
  color: var(--ink-secondary);
  margin: 0;
  max-width: 60ch;
}
@media (min-width: 768px) {
  .product-sub {
    font-size: var(--type-size-body-comfortable);
  }
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Sections (what-it-does, audiences, trust, CTA block).                  │
   └────────────────────────────────────────────────────────────────────────┘ */
.product-section {
  margin: var(--space-6) auto;
  max-width: var(--measure);
}
.product-section h2 {
  font-family: var(--font-serif);
  font-weight: var(--type-weight-semibold);
  font-size: 1.5rem;
  line-height: var(--type-line-height-tight);
  color: var(--ink-primary);
  margin: 0 0 var(--space-3);
}
.product-section p {
  font-family: var(--font-serif);
  font-size: var(--type-size-body-base);
  line-height: var(--type-line-height-loose);
  color: var(--ink-primary);
  margin: 0 0 var(--space-2);
}
@media (min-width: 768px) {
  .product-section p {
    font-size: var(--type-size-body-comfortable);
  }
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Audiences grid — two-up at desktop, stacked on mobile.                 │
   └────────────────────────────────────────────────────────────────────────┘ */
.product-audience-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-3);
}
@media (min-width: 768px) {
  .product-audience-grid {
    grid-template-columns: 1fr 1fr;
  }
}
.product-audience {
  padding: var(--space-3);
  background: var(--surface-card);
  border: 1px solid var(--rule-quiet);
  border-radius: 6px;
}
.product-audience h3 {
  font-family: var(--font-serif);
  font-weight: var(--type-weight-semibold);
  font-size: var(--type-size-body-comfortable);
  line-height: var(--type-line-height-tight);
  color: var(--ink-primary);
  margin: 0 0 var(--space-2);
}
.product-audience p {
  font-family: var(--font-serif);
  font-size: var(--type-size-body-base);
  line-height: var(--type-line-height-base);
  color: var(--ink-secondary);
  margin: 0;
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Trust block — sovereignty + portability + manifesto link.              │
   └────────────────────────────────────────────────────────────────────────┘ */
.product-trust-line {
  font-style: italic;
  color: var(--ink-secondary);
}
.product-trust-link {
  margin-top: var(--space-3);
}
.product-trust-link a {
  font-family: var(--font-sans);
  font-size: var(--type-size-meta-base);
  font-weight: var(--type-weight-medium);
  color: var(--accent-primary);
  text-decoration: underline;
  text-decoration-color: transparent;
  text-underline-offset: 0.25em;
  transition: text-decoration-color var(--motion-quick) var(--easing);
}
.product-trust-link a:hover,
.product-trust-link a:focus-visible {
  text-decoration-color: var(--accent-primary);
}
.product-trust-link a:focus-visible {
  outline: 2px solid var(--ink-primary);
  outline-offset: 2px;
  border-radius: 2px;
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ CTA block — equal-weight Book a pilot + Create account.                │
   │ Visually distinct fill colour but same shape, padding, weight.         │
   └────────────────────────────────────────────────────────────────────────┘ */
.product-cta-actions {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin: var(--space-3) 0;
}
@media (min-width: 480px) {
  .product-cta-actions {
    flex-direction: row;
    flex-wrap: wrap;
  }
}
.product-cta-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px; /* --target-primary touch-area floor */
  padding: 0.75rem 1.25rem;
  font-family: var(--font-sans);
  font-size: var(--type-size-body-base);
  font-weight: var(--type-weight-medium);
  text-decoration: none;
  border: 1px solid var(--accent-primary);
  border-radius: 6px;
  cursor: pointer;
  transition:
    background-color var(--motion-quick) var(--easing),
    color var(--motion-quick) var(--easing);
}
.product-cta-button:focus-visible {
  outline: 2px solid var(--ink-primary);
  outline-offset: 2px;
}
.product-cta-button--primary {
  background: var(--accent-primary);
  color: var(--ink-on-accent);
}
.product-cta-button--secondary {
  background: transparent;
  color: var(--accent-primary);
}
/* Hover colour-flip removed (both variants) — fills stay at their resting
   state. Scale + shine in cta-interaction.css are the sole hover signal. */
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Built on Enterprise Mesh attribution — quiet line under CTAs.              │
   │ Same canonical string per locale (NFR-Q4 — referenced via             │
   │ common.attribution.builtOnMesh).                                       │
   └────────────────────────────────────────────────────────────────────────┘ */
.product-builton {
  margin: var(--space-3) 0 0;
  font-family: var(--font-sans);
  font-size: var(--type-size-meta-base);
  font-style: italic;
  color: var(--ink-quiet);
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Story 3.4 — Enterprise Mesh capability + deployment lists.                 │
   │ <dl> definition lists keep capability name → description semantics    │
   │ explicit for AT (each <dt>/<dd> pair announces correctly). The        │
   │ developer-aspect cell suppresses ornamentation; type rhythm carries   │
   │ the substrate register.                                                │
   └────────────────────────────────────────────────────────────────────────┘ */
.product-capability-list,
.product-deployment-list,
.product-use-case-list {
  margin: var(--space-3) 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-3);
}
@media (min-width: 768px) {
  .product-capability-list,
  .product-deployment-list {
    grid-template-columns: 1fr 1fr;
  }
}
.product-capability,
.product-deployment-state,
.product-use-case {
  margin: 0;
}
.product-capability dt,
.product-deployment-state dt,
.product-use-case dt {
  font-family: var(--font-serif);
  font-weight: var(--type-weight-semibold);
  font-size: var(--type-size-body-comfortable);
  line-height: var(--type-line-height-tight);
  color: var(--ink-primary);
  margin: 0 0 var(--space-1);
}
.product-capability dd,
.product-deployment-state dd,
.product-use-case dd {
  font-family: var(--font-serif);
  font-size: var(--type-size-body-base);
  line-height: var(--type-line-height-base);
  color: var(--ink-secondary);
  margin: 0;
}
/* Foundation component line — the priced line items a foundation meters,
   mirrored from pricing.yaml › publicPriceBreakdown. Reads as a quiet
   caption under the foundation body so the page stays "what it is" and
   /pricing owns "how much". */
.product-foundation__components {
  display: block;
  margin-top: var(--space-1);
  font-size: var(--type-size-body-small, 0.875rem);
  color: var(--ink-tertiary, var(--ink-secondary));
}
.product-foundation__included {
  margin: var(--space-3) 0 0;
  font-family: var(--font-serif);
  font-size: var(--type-size-body-small, 0.875rem);
  color: var(--ink-tertiary, var(--ink-secondary));
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Built-on cross-links list — runs the three on-mesh products as       │
   │ inline links. Managed OpenClaw is intentionally absent (off-mesh).   │
   └────────────────────────────────────────────────────────────────────────┘ */
.product-builton-links {
  list-style: none;
  margin: var(--space-3) 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}
@media (min-width: 600px) {
  .product-builton-links {
    flex-direction: row;
    flex-wrap: wrap;
    gap: var(--space-3);
  }
}
.product-builton-links a {
  font-family: var(--font-sans);
  font-size: var(--type-size-meta-base);
  font-weight: var(--type-weight-medium);
  color: var(--accent-primary);
  text-decoration: underline;
  text-decoration-color: transparent;
  text-underline-offset: 0.25em;
  transition: text-decoration-color var(--motion-quick) var(--easing);
}
.product-builton-links a:hover,
.product-builton-links a:focus-visible {
  text-decoration-color: var(--accent-primary);
}
.product-builton-links a:focus-visible {
  outline: 2px solid var(--ink-primary);
  outline-offset: 2px;
  border-radius: 2px;
}
/* Story 3.1+ — per-product page composition (hero, sections, audiences grid, equal-weight CTAs, built-on attribution) */
/* ──────────────────────────────────────────────────────────────────────────
   partners.css — /partners (Design Partner Program) surface consumer rules.

   The page wrapper composes `.product-page` for max-width / centring /
   padding / serif typography (tokens/products.css). This file only adds
   the partner-specific blocks that products.css doesn't cover.

   Post-DPP-rewrite layout (2026-05-14): four content sections under the
   hero — `.partner-how` (sprint cadence), `.partner-deal` (paired
   you-gain / we-gain blocks; stigmergy-rail anchored), `.partner-pricing`
   (PPA escalator), `.partner-apply` (mailto CTA). All compose
   `.product-section` so their outer rhythm cascades from products.css.

   Stigmergy: `.partner-how` + `.partner-deal` carry the `.stigmergy-rail`
   class (with a waypoint SVG) — see tokens/stigmergy.css for the primitive.
   ────────────────────────────────────────────────────────────────────────── */
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Hero — open + closed variants.                                          │
   └────────────────────────────────────────────────────────────────────────┘ */
.partner-hero {
  margin-bottom: var(--space-6);
  text-align: left;
}
.partner-hero--closed {
  margin-bottom: var(--space-7);
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ How it works — ordered sprint-cadence list.                             │
   │ Decimal markers in the sans/meta register sit alongside serif body     │
   │ copy; matches the institutional voice.                                  │
   └────────────────────────────────────────────────────────────────────────┘ */
.partner-how-steps {
  margin: var(--space-3) 0 0;
  padding-left: var(--space-4);
  list-style-position: outside;
  list-style-type: decimal;
}
.partner-how-steps > li {
  font-family: var(--font-serif);
  font-size: var(--type-size-body-base);
  line-height: var(--type-line-height-loose);
  color: var(--ink-primary);
  margin: 0 0 var(--space-3);
  padding-left: var(--space-2);
}
.partner-how-steps > li:last-child {
  margin-bottom: 0;
}
.partner-how-steps > li::marker {
  font-family: var(--font-sans);
  font-weight: var(--type-weight-medium);
  color: var(--ink-quiet);
}
@media (min-width: 768px) {
  .partner-how-steps > li {
    font-size: var(--type-size-body-comfortable);
  }
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ The deal — paired you-gain / we-gain blocks.                            │
   │ Stacks on narrow viewports; 2-column grid from 768px up. The two       │
   │ blocks share weight (1fr 1fr) so neither reads as primary.             │
   └────────────────────────────────────────────────────────────────────────┘ */
.partner-deal-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-5);
  margin-top: var(--space-4);
}
@media (min-width: 768px) {
  .partner-deal-grid {
    grid-template-columns: 1fr 1fr;
    gap: var(--space-6);
  }
}
.partner-deal-block > h3 {
  font-family: var(--font-serif);
  font-weight: var(--type-weight-semibold);
  font-size: var(--type-size-body-comfortable);
  line-height: var(--type-line-height-tight);
  color: var(--ink-primary);
  margin: 0 0 var(--space-3);
}
.partner-deal-list {
  margin: 0;
  padding-left: var(--space-4);
  list-style-position: outside;
  list-style-type: disc;
}
.partner-deal-list > li {
  font-family: var(--font-serif);
  font-size: var(--type-size-body-base);
  line-height: var(--type-line-height-loose);
  color: var(--ink-primary);
  margin: 0 0 var(--space-3);
  padding-left: var(--space-1);
}
.partner-deal-list > li:last-child {
  margin-bottom: 0;
}
.partner-deal-list > li::marker {
  color: var(--ink-quiet);
}
@media (min-width: 768px) {
  .partner-deal-list > li {
    font-size: var(--type-size-body-comfortable);
  }
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Apply CTA wrapper — bare button after the pricing section, no section  │
   │ wrapper / no heading / no intro copy (2026-05-14 Tom redirect: the     │
   │ entire apply section reduces to its CTA).                              │
   └────────────────────────────────────────────────────────────────────────┘ */
.partner-apply-cta {
  margin: var(--space-5) 0 0;
  text-align: center;
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Closed-state body paragraph — quiet secondary ink.                      │
   └────────────────────────────────────────────────────────────────────────┘ */
.partner-closed-body {
  font-family: var(--font-serif);
  font-size: var(--type-size-body-base);
  line-height: var(--type-line-height-loose);
  color: var(--ink-secondary);
  margin: var(--space-4) 0 0;
  max-width: 60ch;
}
@media (min-width: 768px) {
  .partner-closed-body {
    font-size: var(--type-size-body-comfortable);
  }
}
/* Story 3.6 — /partners DPP surface (hero spacing + cohort-terms ordered list + closed-state body); page wrapper composes .product-page */
/* ──────────────────────────────────────────────────────────────────────────
   seo-article.css — Story 3.7 SEO anchor article consumer rules.

   Lives under tokens/** so the four-prefix stylelint regex exemption
   (Story 1.1) covers ad-hoc class names (per nav.css/manifesto.css/
   consent.css/cursor-trail.css/products.css/hero.css precedent).

   COMPOSITION:
     • Editorial typography for substantive long-form prose. Charter
       serif; ≤70ch measure on body paragraphs; loose line-height for
       reading rhythm.
     • Header block: eyebrow + h1 + meta line (date · byline).
     • Body block: rendered from markdown via marked (h2/h3, p, ul/ol,
       a, strong, em, code spans). Selectors target the inline tags so
       the markdown→HTML output picks up the styles without any class
       hooks in the source markdown.

   ASPECT: data-aspect="manifesto" lands the same Stigmergy texture
   cell as the manifesto surface (Story 2.3) — articles share the
   editorial register with the manifesto and inherit substrate +
   waypoint + trail token bindings.
   ────────────────────────────────────────────────────────────────────────── */
.seo-article {
  width: 100%;
  max-width: 38rem;
  margin: 0 auto;
  padding: var(--space-5) var(--space-3) var(--space-7);
  color: var(--ink-primary);
  font-family: var(--font-serif);
}
@media (min-width: 768px) {
  .seo-article {
    padding: var(--space-6) var(--space-4) var(--space-7);
  }
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Header block.                                                          │
   └────────────────────────────────────────────────────────────────────────┘ */
.seo-article-header {
  margin-bottom: var(--space-3);
  padding-bottom: var(--space-3);
}
.seo-article-eyebrow {
  font-family: var(--font-sans);
  font-size: var(--type-size-eyebrow-base);
  font-weight: var(--type-weight-medium);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-quiet);
  margin: 0 0 var(--space-2);
}
.seo-article-h1 {
  font-family: var(--font-serif);
  font-weight: var(--type-weight-regular);
  font-size: var(--type-size-h1-base);
  line-height: var(--type-line-height-tight);
  letter-spacing: -0.02em;
  color: var(--ink-primary);
  margin: 0 0 var(--space-3);
  max-width: 26ch;
}
.seo-article-meta {
  font-family: var(--font-sans);
  font-size: var(--type-size-meta-base);
  color: var(--ink-quiet);
  margin: 0;
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Body block — markdown-rendered HTML. Targets inline tags directly.     │
   └────────────────────────────────────────────────────────────────────────┘ */
.seo-article-body h2 {
  font-family: var(--font-serif);
  font-weight: var(--type-weight-semibold);
  font-size: 1.5rem;
  line-height: var(--type-line-height-tight);
  color: var(--ink-primary);
  margin: var(--space-5) 0 var(--space-3);
}
.seo-article-body h3 {
  font-family: var(--font-serif);
  font-weight: var(--type-weight-semibold);
  font-size: 1.25rem;
  line-height: var(--type-line-height-tight);
  color: var(--ink-primary);
  margin: var(--space-4) 0 var(--space-2);
}
.seo-article-body p {
  font-family: var(--font-serif);
  font-size: var(--type-size-body-base);
  line-height: var(--type-line-height-loose);
  color: var(--ink-primary);
  margin: 0 0 var(--space-3);
  max-width: 70ch;
}
@media (min-width: 768px) {
  .seo-article-body p {
    font-size: var(--type-size-body-comfortable);
  }
}
.seo-article-body ul,
.seo-article-body ol {
  font-family: var(--font-serif);
  font-size: var(--type-size-body-base);
  line-height: var(--type-line-height-base);
  color: var(--ink-primary);
  margin: 0 0 var(--space-3);
  padding-left: 1.5rem;
  max-width: 70ch;
}
.seo-article-body li {
  margin-bottom: var(--space-1);
}
.seo-article-body a {
  color: var(--accent-primary);
  text-decoration: underline;
  text-decoration-color: var(--rule-quiet);
  text-underline-offset: 0.2em;
  transition: text-decoration-color var(--motion-quick) var(--easing);
}
.seo-article-body a:hover,
.seo-article-body a:focus-visible {
  text-decoration-color: var(--accent-primary);
}
.seo-article-body a:focus-visible {
  outline: 2px solid var(--ink-primary);
  outline-offset: 2px;
  border-radius: 2px;
}
.seo-article-body strong {
  font-weight: var(--type-weight-semibold);
  color: var(--ink-primary);
}
.seo-article-body em {
  font-style: italic;
}
.seo-article-body code {
  font-family: var(--font-mono);
  font-size: 0.9em;
  background: var(--surface-card);
  padding: 0.1em 0.3em;
  border-radius: 3px;
  border: 1px solid var(--rule-quiet);
}
.seo-article-body blockquote {
  font-family: var(--font-serif);
  font-style: italic;
  font-size: var(--type-size-body-base);
  line-height: var(--type-line-height-loose);
  color: var(--ink-secondary);
  margin: var(--space-4) 0;
  padding-left: var(--space-3);
  border-left: 2px solid var(--accent-primary);
  max-width: 70ch;
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Legal modifier — footer-linked surfaces (Legal notice, Privacy, ToS,    │
   │ ToU, Cookies, Accessibility). Editorial measure is dropped: the article │
   │ widens to ~72rem and prose flows the full width, left-aligned. SEO      │
   │ articles keep the narrow editorial register.                            │
   └────────────────────────────────────────────────────────────────────────┘ */
.seo-article--legal {
  max-width: 72rem;
}
.seo-article--legal .seo-article-h1 {
  max-width: none;
}
.seo-article--legal .seo-article-body p,
.seo-article--legal .seo-article-body ul,
.seo-article--legal .seo-article-body ol,
.seo-article--legal .seo-article-body blockquote {
  max-width: none;
}
/* Story 3.7 — SEO anchor article editorial typography (header + markdown-rendered body) */
/* ──────────────────────────────────────────────────────────────────────────
   site-footer.css — Story 3.8 site-wide footer.

   Lives under tokens/** so the four-prefix stylelint regex exemption
   (Story 1.1) covers ad-hoc class names.

   COMPOSITION:
     • Footer sits at the bottom of every page below the main content
       slot. Top border separates it from page content.
     • Inner row uses the same --measure constraint as the header so
       footer + header chrome align visually.
     • Legal-link list is horizontal at ≥768px, stacked on mobile.
     • Heading is visually hidden but present for AT (the footer is a
       <nav> so AT users hear "Legal navigation" then the link list).
     • Quiet typography: --font-sans, --type-size-meta-base,
       --ink-quiet — the footer should not compete with main content.
   ────────────────────────────────────────────────────────────────────────── */
.site-footer {
  margin-top: var(--space-7);
  padding: var(--space-4) 0;
  border-top: 1px solid var(--rule-quiet);
  background: var(--surface-page);
}
.site-footer-inner {
  width: 100%;
  max-width: var(--measure);
  margin: 0 auto;
  padding: 0 var(--space-3);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
@media (min-width: 768px) {
  .site-footer-inner {
    flex-direction: row;
    align-items: baseline;
    justify-content: space-between;
    padding: 0 var(--space-4);
  }
}
.site-footer-heading {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}
.site-footer-links {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}
@media (min-width: 600px) {
  .site-footer-links {
    flex-direction: row;
    flex-wrap: wrap;
    gap: var(--space-3);
  }
}
.site-footer-links a {
  font-family: var(--font-sans);
  font-size: var(--type-size-meta-base);
  color: var(--ink-secondary);
  text-decoration: underline;
  text-decoration-color: transparent;
  text-underline-offset: 0.3em;
  transition: text-decoration-color var(--motion-quick) var(--easing);
  min-height: 32px;
  display: inline-flex;
  align-items: center;
}
.site-footer-links a:hover,
.site-footer-links a:focus-visible {
  color: var(--ink-primary);
  text-decoration-color: var(--accent-primary);
}
.site-footer-links a:focus-visible {
  outline: 2px solid var(--accent-primary);
  outline-offset: 2px;
  border-radius: 2px;
}
.site-footer-copy {
  /* --ink-secondary, not --ink-quiet: --ink-quiet on --surface-page
     measures 4.47:1, 0.03 short of WCAG 2.2 AA (4.5:1). Aligning with
     the link colour also reads as a single quiet footer band. */
  margin: 0;
  font-family: var(--font-sans);
  font-size: var(--type-size-meta-base);
  color: var(--ink-secondary);
}
/* On tablet/phone the /lucie page becomes the dedicated full-viewport chat
   surface (paired with the lucie-mount.eta redirect at < 1024px). Hide the
   footer there so chat chrome owns the viewport — legal links remain
   reachable from every other surface. */
@media (max-width: 1023.98px) {
  body[data-surface="lucie-page"] .site-footer {
    display: none;
  }
}
/* Story 3.8 — site-wide footer with legal links visible from every page */
/* ──────────────────────────────────────────────────────────────────────────
   pricing.css — Story 3.11 /pricing surface consumer rules.

   Lives under tokens/** so the four-prefix stylelint regex exemption
   (Story 1.1) covers ad-hoc class names (per nav.css / manifesto.css /
   products.css precedent).

   Accent ratio: "modest" per UX spec §/pricing — between institutional
   (enterprise) and developer registers. data-aspect="enterprise" on the
   page root provides the token cascade; accent fills are used sparingly
   so the tier cards read cleanly.

   Composition:
     • Hero: H1 + sub + directional note (quiet italic at bottom)
     • Tier cards: 2-up grid at ≥640px, single column below
     • Token credits: editorial paragraph section
     • FAQ: definition list (dl/dt/dd) with subtle dividers
     • Enterprise: CTA section with single primary button
     • Cross-links: quiet footer-zone nav
   ────────────────────────────────────────────────────────────────────────── */
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Page-level wrapper.                                                    │
   └────────────────────────────────────────────────────────────────────────┘ */
.pricing-page {
  width: 100%;
  max-width: var(--measure);
  margin: 0 auto;
  padding: var(--space-5) var(--space-3) var(--space-7);
  color: var(--ink-primary);
  font-family: var(--font-serif);
}
@media (min-width: 768px) {
  .pricing-page {
    padding: var(--space-6) var(--space-4) var(--space-7);
  }
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Hero block.                                                            │
   └────────────────────────────────────────────────────────────────────────┘ */
.pricing-hero {
  margin-bottom: var(--space-5);
}
.pricing-h1 {
  font-family: var(--font-serif);
  font-weight: var(--type-weight-regular);
  font-size: var(--type-size-h1-base);
  line-height: var(--type-line-height-tight);
  letter-spacing: -0.02em;
  color: var(--ink-primary);
  margin: 0 0 var(--space-3);
}
.pricing-sub {
  font-family: var(--font-serif);
  font-size: var(--type-size-body-comfortable);
  line-height: var(--type-line-height-loose);
  color: var(--ink-secondary);
  margin: 0 0 var(--space-2);
  max-width: 60ch;
}
.pricing-sub-hero {
  font-family: var(--font-serif);
  font-size: var(--type-size-body-base);
  line-height: var(--type-line-height-loose);
  color: var(--ink-primary);
  margin: 0 0 var(--space-3);
  max-width: 70ch;
}
.pricing-directional-note {
  font-family: var(--font-sans);
  font-size: var(--type-size-meta-base);
  font-style: italic;
  color: var(--ink-quiet);
  margin: 0;
  max-width: 60ch;
}
/* Stigmergy primitives consumed via .stigmergy-rail{,__waypoint} and
   .stigmergy-divider-strong (tokens/stigmergy.css). Pricing's prior
   bespoke .pricing-waypoint / .pricing-divider wrappers retired
   2026-05-14 as part of the homogenize-page-layout sweep. */
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Section shared h2.                                                     │
   └────────────────────────────────────────────────────────────────────────┘ */
.pricing-section-h2 {
  font-family: var(--font-serif);
  font-weight: var(--type-weight-semibold);
  font-size: 1.5rem;
  line-height: var(--type-line-height-tight);
  color: var(--ink-primary);
  margin: 0 0 var(--space-3);
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Tier cards — page-wide, stacked one-per-row at all viewports.         │
   │ Each card carries: header → pricing-model paragraph (always visible) →│
   │ figures block (flag-gated) → includes → CTA. The pricing-model copy   │
   │ is the load-bearing unit; figures are the optional disclosure.        │
   └────────────────────────────────────────────────────────────────────────┘ */
.pricing-tiers {
  margin: var(--space-5) 0;
}
.pricing-tier-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-4);
  margin-top: var(--space-3);
}
.pricing-tier-card {
  display: grid;
  grid-template-columns: 1fr;
  padding: var(--space-4);
  background: var(--surface-card);
  border: 1px solid var(--rule-quiet);
  border-radius: 6px;
  gap: var(--space-3);
}
@media (min-width: 768px) {
  .pricing-tier-card {
    grid-template-columns: minmax(0, 1fr) auto;
    column-gap: var(--space-4);
  }
  .pricing-tier-card > *:not(.pricing-tier-card__cta) {
    grid-column: 1;
  }
  .pricing-tier-card__cta {
    grid-column: 2;
    grid-row: 1 / -1;
    align-self: end;
  }
}
.pricing-tier-card__header {
  margin-bottom: 0;
}
.pricing-tier-card__name {
  font-family: var(--font-sans);
  font-weight: var(--type-weight-medium);
  font-size: var(--type-size-body-comfortable);
  color: var(--ink-primary);
  margin: 0 0 var(--space-1);
}
.pricing-tier-card__tagline {
  font-family: var(--font-serif);
  font-size: 1.25rem;
  font-weight: var(--type-weight-regular);
  color: var(--accent-primary);
  margin: 0;
}
.pricing-tier-card__pricing-model {
  font-family: var(--font-serif);
  font-size: var(--type-size-body-base);
  line-height: var(--type-line-height-loose);
  color: var(--ink-primary);
  max-width: 70ch;
  margin: 0;
}
@media (min-width: 768px) {
  .pricing-tier-card__pricing-model {
    font-size: var(--type-size-body-comfortable);
  }
}
.pricing-tier-card__includes {
  font-family: var(--font-sans);
  font-size: var(--type-size-meta-base);
  font-style: italic;
  line-height: var(--type-line-height-base);
  color: var(--ink-quiet);
  max-width: 70ch;
  margin: 0;
}
/* Per-tier publicPrice figures block. Always rendered — page shape invariant
   under per-product flag flips. Flat-<p> tiers (AH, MOC, LA) and structured-
   <dl> tiers (WB, AM) share the .pricing-tier-card__public-price class hook.
   Visual: no callout (no grey box, no accent border). The structured <dl>
   uses the same row borders + padding as the rest of the page's tables so
   the typography matches edge-to-edge. */
.pricing-tier-card__public-price {
  font-family: var(--font-sans);
  font-size: var(--type-size-body-base);
  font-weight: var(--type-weight-regular);
  line-height: var(--type-line-height-base);
  color: var(--ink-primary);
  margin: 0;
  padding: 0;
}
.pricing-tier-card__public-price--structured {
  display: grid;
  grid-template-columns: max-content 1fr;
  column-gap: var(--space-3);
  row-gap: 0;
  width: 100%;
}
.pricing-tier-card__public-price--structured dt,
.pricing-tier-card__public-price--structured dd {
  font-family: var(--font-sans);
  font-size: var(--type-size-meta-base);
  margin: 0;
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--rule-quiet);
}
.pricing-tier-card__public-price--structured dt {
  font-weight: var(--type-weight-medium);
  color: var(--ink-secondary);
}
.pricing-tier-card__public-price--structured dd {
  font-weight: var(--type-weight-regular);
  color: var(--ink-primary);
}
.pricing-tier-card__public-price--structured dt:last-of-type,
.pricing-tier-card__public-price--structured dd:last-of-type {
  border-bottom: none;
}
.pricing-tier-card__cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 0.625rem 1rem;
  font-family: var(--font-sans);
  font-size: var(--type-size-body-base);
  font-weight: var(--type-weight-medium);
  color: var(--accent-primary);
  text-decoration: none;
  border: 1px solid var(--accent-primary);
  border-radius: 6px;
  margin-top: auto;
  transition:
    background-color var(--motion-quick) var(--easing),
    color var(--motion-quick) var(--easing);
}
/* Hover colour-flip removed — outlined fill stays at rest on hover.
   Scale + shine in cta-interaction.css are the sole hover signal. */
.pricing-tier-card__cta:focus-visible {
  outline: 2px solid var(--ink-primary);
  outline-offset: 2px;
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Token credits section.                                                 │
   └────────────────────────────────────────────────────────────────────────┘ */
.pricing-token-credits {
  margin: var(--space-5) 0;
  max-width: 70ch;
}
.pricing-token-credits__body {
  font-family: var(--font-serif);
  font-size: var(--type-size-body-base);
  line-height: var(--type-line-height-loose);
  color: var(--ink-primary);
  margin: 0;
}
@media (min-width: 768px) {
  .pricing-token-credits__body {
    font-size: var(--type-size-body-comfortable);
  }
}
/* Token-credits — three per-provider tables (Scaleway / AWS Bedrock Frankfurt
   / GCP Vertex Paris). Always rendered (provider rates are public). Each
   table is a 2-col (Model | €/M tokens). The provider name in <caption> wraps
   <a> linking to that provider's data-protection page. Single gateway-fee
   line below all three tables — applies across providers, not in any table. */
.pricing-token-credits__providers-intro {
  font-family: var(--font-sans);
  font-size: var(--type-size-meta-base);
  font-style: italic;
  color: var(--ink-quiet);
  margin: var(--space-3) 0 var(--space-2);
  max-width: 70ch;
}
.pricing-token-credits__rate-snapshot {
  font-family: var(--font-sans);
  font-size: var(--type-size-meta-base);
  font-style: italic;
  color: var(--ink-quiet);
  margin: var(--space-3) 0 var(--space-2);
  max-width: 70ch;
}
.pricing-token-credits__gateway-fee {
  font-family: var(--font-sans);
  font-size: var(--type-size-body-base);
  color: var(--ink-primary);
  margin: var(--space-3) 0 var(--space-4);
  padding: 0;
  max-width: 70ch;
}
.pricing-token-credits__gateway-fee-label {
  font-weight: var(--type-weight-medium);
  margin-right: 0.25em;
}
.pricing-token-credits-provider {
  margin: var(--space-3) 0;
}
.pricing-token-credits-provider-table {
  width: 100%;
  border-collapse: collapse;
  font-family: var(--font-sans);
  font-size: var(--type-size-meta-base);
  color: var(--ink-primary);
}
.pricing-token-credits-provider-table caption {
  text-align: left;
  font-family: var(--font-sans);
  font-size: var(--type-size-body-base);
  font-weight: var(--type-weight-medium);
  color: var(--ink-primary);
  padding-bottom: var(--space-2);
  caption-side: top;
}
.pricing-token-credits-provider-table caption a {
  color: var(--accent-primary);
  text-decoration: underline;
  text-decoration-color: transparent;
  text-underline-offset: 0.25em;
  transition: text-decoration-color var(--motion-quick) var(--easing);
}
.pricing-token-credits-provider-table caption a:hover,
.pricing-token-credits-provider-table caption a:focus-visible {
  text-decoration-color: var(--accent-primary);
}
.pricing-token-credits-provider-table caption a:focus-visible {
  outline: 2px solid var(--ink-primary);
  outline-offset: 2px;
  border-radius: 2px;
}
.pricing-token-credits-provider-table thead th {
  font-weight: var(--type-weight-medium);
  text-align: left;
  padding: var(--space-2);
  border-bottom: 2px solid var(--rule-quiet);
  color: var(--ink-secondary);
  font-size: var(--type-size-meta-base);
}
.pricing-token-credits-provider-table__model-col {
  width: 60%;
}
.pricing-token-credits-provider-table tbody th,
.pricing-token-credits-provider-table tbody td {
  padding: var(--space-2);
  border-bottom: 1px solid var(--rule-quiet);
  vertical-align: top;
}
.pricing-token-credits-provider-table tbody th {
  font-weight: var(--type-weight-regular);
  text-align: left;
  color: var(--ink-primary);
}
.pricing-token-credits-provider-table tbody td {
  color: var(--ink-secondary);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.pricing-token-credits-provider-table--continuation {
  /* Continuation table sits inside a <details>; drop its visual seam from
     the primary table so the reveal reads as additional rows of the same
     dataset, not a fresh table. */
  margin-top: 0;
}
.pricing-token-credits-provider-table--continuation tbody tr:first-child th,
.pricing-token-credits-provider-table--continuation tbody tr:first-child td {
  border-top: 1px solid var(--rule-quiet);
}
.pricing-token-credits-provider__more {
  margin: 0;
}
.pricing-token-credits-provider__more-summary {
  font-family: var(--font-sans);
  font-size: var(--type-size-meta-base);
  color: var(--accent-primary);
  cursor: pointer;
  padding: var(--space-2) 0;
  list-style: none;
}
.pricing-token-credits-provider__more-summary::-webkit-details-marker {
  display: none;
}
.pricing-token-credits-provider__more-summary::before {
  content: "+ ";
}
.pricing-token-credits-provider__more[open] > .pricing-token-credits-provider__more-summary::before {
  content: "− ";
}
.pricing-token-credits-provider__more-summary:focus-visible {
  outline: 2px solid var(--ink-primary);
  outline-offset: 2px;
  border-radius: 2px;
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ FAQ section — collapsible <details>/<summary>. Each FAQ item is a      │
   │ native <details>; the <summary> is the question, the <p> is the answer.│
   └────────────────────────────────────────────────────────────────────────┘ */
.pricing-faq {
  margin: var(--space-5) 0;
  max-width: 70ch;
}
.pricing-faq__list {
  margin: var(--space-3) 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
}
.pricing-faq__item {
  margin: 0;
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--rule-quiet);
}
.pricing-faq__item:last-child {
  border-bottom: none;
}
.pricing-faq__q {
  font-family: var(--font-serif);
  font-weight: var(--type-weight-semibold);
  font-size: var(--type-size-body-base);
  line-height: var(--type-line-height-tight);
  color: var(--ink-primary);
  margin: 0;
  cursor: pointer;
  list-style: none;
  padding-right: var(--space-3);
  position: relative;
}
.pricing-faq__q::-webkit-details-marker {
  display: none;
}
.pricing-faq__q::after {
  content: "+";
  position: absolute;
  right: 0;
  top: 0;
  font-family: var(--font-sans);
  font-weight: var(--type-weight-regular);
  color: var(--ink-quiet);
  transition: transform var(--motion-quick) var(--easing);
}
.pricing-faq__item[open] > .pricing-faq__q::after {
  content: "−";
}
.pricing-faq__q:focus-visible {
  outline: 2px solid var(--ink-primary);
  outline-offset: 2px;
  border-radius: 2px;
}
@media (min-width: 768px) {
  .pricing-faq__q {
    font-size: var(--type-size-body-comfortable);
  }
}
.pricing-faq__a {
  font-family: var(--font-serif);
  font-size: var(--type-size-body-base);
  line-height: var(--type-line-height-loose);
  color: var(--ink-secondary);
  margin: var(--space-2) 0 0;
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Talk-to-us section — 2-col table (Question | CTA). Replaces the prior │
   │ 3-card .pricing-enterprise-paths block. Sales row carries the primary │
   │ full-colored button; DPP + PIO rows carry quiet underline-on-hover    │
   │ text links.                                                            │
   └────────────────────────────────────────────────────────────────────────┘ */
.pricing-enterprise {
  margin: var(--space-5) 0;
}
.pricing-talk-to-us-wrapper {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.pricing-talk-to-us {
  width: 100%;
  border-collapse: collapse;
  font-family: var(--font-serif);
  font-size: var(--type-size-body-base);
  color: var(--ink-primary);
}
.pricing-talk-to-us tbody th {
  font-family: var(--font-serif);
  font-weight: var(--type-weight-regular);
  text-align: left;
  padding: var(--space-3) var(--space-2);
  border-bottom: 1px solid var(--rule-quiet);
  color: var(--ink-primary);
  vertical-align: middle;
}
.pricing-talk-to-us tbody td {
  padding: var(--space-3) var(--space-2);
  border-bottom: 1px solid var(--rule-quiet);
  vertical-align: middle;
  white-space: nowrap;
  width: 200px;
}
/* All 3 CTAs share the same rendered width inside the talk-to-us cells. */
.pricing-talk-to-us .pricing-cta-button {
  width: 100%;
}
.pricing-talk-to-us__row:last-child th,
.pricing-talk-to-us__row:last-child td {
  border-bottom: none;
}
/* All 3 CTAs share the same size + shape; only fill style differs. */
.pricing-cta-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 0.625rem 1.25rem;
  font-family: var(--font-sans);
  font-size: var(--type-size-body-base);
  font-weight: var(--type-weight-medium);
  text-decoration: none;
  border: 1px solid var(--accent-primary);
  border-radius: 6px;
  cursor: pointer;
  transition:
    background-color var(--motion-quick) var(--easing),
    color var(--motion-quick) var(--easing);
}
.pricing-cta-button--primary {
  background: var(--accent-primary);
  color: var(--ink-on-accent);
}
.pricing-cta-button--secondary {
  background: transparent;
  color: var(--accent-primary);
}
.pricing-cta-button:focus-visible {
  outline: 2px solid var(--ink-primary);
  outline-offset: 2px;
}
/* Cross-links retired 2026-05-14 — now served by the unified .crosslinks
   primitive in tokens/stigmergy.css. */
/* Story 3.11 — /pricing surface (tier cards, FAQ, enterprise CTA, cross-links) */
/* ──────────────────────────────────────────────────────────────────────────
   products-index.css — Story 3.12 /products index surface consumer rules.

   Hero and product card grid reuse .hero / .hero-inner (hero.css) and
   .enterprise-zone / .portfolio-grid / .portfolio-card (portfolio.css).
   This file adds only the supplements: products-index-h1 typography,
   pricing model line, and cross-links nav.

   Lives under tokens/** so the four-prefix stylelint regex exemption
   (Story 1.1) covers ad-hoc class names per nav.css / manifesto.css /
   pricing.css precedent.
   ────────────────────────────────────────────────────────────────────────── */
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Products index H1 — inside the inherited .hero-inner centred block.    │
   └────────────────────────────────────────────────────────────────────────┘ */
.products-index-h1 {
  font-family: var(--font-serif);
  font-weight: var(--type-weight-regular);
  font-size: var(--type-size-h1-base);
  line-height: var(--type-line-height-tight);
  letter-spacing: -0.02em;
  color: var(--ink-primary);
  margin: 0 0 var(--space-3);
}
.products-index-sub {
  font-family: var(--font-serif);
  font-size: var(--type-size-body-comfortable);
  line-height: var(--type-line-height-loose);
  color: var(--ink-secondary);
  max-width: 60ch;
  margin: 0 auto;
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Cards intro — narrow intro paragraph above the portfolio grid.         │
   └────────────────────────────────────────────────────────────────────────┘ */
.products-index-cards-intro {
  font-family: var(--font-serif);
  font-size: var(--type-size-body-base);
  line-height: var(--type-line-height-loose);
  color: var(--ink-secondary);
  max-width: 60ch;
  margin-bottom: var(--space-4);
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Pricing model line.                                                    │
   └────────────────────────────────────────────────────────────────────────┘ */
.products-index-pricing {
  width: 100%;
  max-width: var(--measure);
  margin: 0 auto var(--space-4);
  padding: 0 var(--space-3);
  font-family: var(--font-sans);
  font-size: var(--type-size-meta-base);
  color: var(--ink-quiet);
}
@media (min-width: 768px) {
  .products-index-pricing {
    padding: 0 var(--space-4);
  }
}
.products-index-pricing a {
  color: var(--accent-primary);
  font-weight: var(--type-weight-medium);
  text-decoration: underline;
  text-decoration-color: transparent;
  text-underline-offset: 0.25em;
  transition: text-decoration-color var(--motion-quick) var(--easing);
}
.products-index-pricing a:hover,
.products-index-pricing a:focus-visible {
  text-decoration-color: var(--accent-primary);
}
.products-index-pricing a:focus-visible {
  outline: 2px solid var(--ink-primary);
  outline-offset: 2px;
  border-radius: 2px;
}
/* Cross-links retired 2026-05-14 — served by unified .crosslinks
   primitive in tokens/stigmergy.css. */
/* Story 3.12 — /products index surface (hero h1, pricing line, cross-links; grid reuses portfolio.css) */
/* ──────────────────────────────────────────────────────────────────────────
   team-store.css — Story 3.31 /team-store marketplace surface consumer rules.

   The page wrapper composes the generic .product-page / .product-section
   primitives (tokens/products.css) for hero + prose rhythm, and the unified
   .crosslinks primitive (tokens/crosslinks.css) for the page foot — same
   precedent as /workspace and /partners. This file adds ONLY the supplement the
   shared primitives don't cover: the discovery + publisher-catalog card grid
   (the placeholder Myrmid-curated catalog cards, AC4) and its browse-only note.

   Card composition mirrors the portfolio / pricing-tier idiom: 1px border at
   --rule-quiet, 6px radius, token-driven spacing. Cards are browse-only at MVP
   (no checkout) — the "Hire team" anchor reuses the shared .crosslinks-cta-button
   affordance and resolves to the /partners placeholder.

   Lives under tokens/** so the four-prefix stylelint regex exemption (Story
   1.1) covers ad-hoc class names per products-index.css / pricing.css precedent.
   ────────────────────────────────────────────────────────────────────────── */
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Catalog card grid — placeholder Myrmid-curated catalog (browse-only).  │
   └────────────────────────────────────────────────────────────────────────┘ */
.team-store-catalog__cards {
  list-style: none;
  margin: var(--space-4) 0 var(--space-3);
  padding: 0;
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-3);
}
@media (min-width: 768px) {
  .team-store-catalog__cards {
    grid-template-columns: repeat(2, 1fr);
    gap: var(--space-4);
  }
}
.team-store-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-3);
  border: 1px solid var(--rule-quiet);
  border-radius: 6px;
}
.team-store-card__publisher {
  margin: 0;
  font-family: var(--font-sans);
  font-size: var(--type-size-meta-base);
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--ink-quiet);
}
.team-store-card__name {
  margin: 0;
  font-family: var(--font-serif);
  font-weight: var(--type-weight-regular);
  font-size: var(--type-size-h3-base, var(--type-size-body-comfortable));
  line-height: var(--type-line-height-tight);
  color: var(--ink-primary);
}
.team-store-card__body {
  margin: 0;
  font-family: var(--font-serif);
  font-size: var(--type-size-body-base);
  line-height: var(--type-line-height-loose);
  color: var(--ink-secondary);
}
/* Push the hire affordance to the card foot so cards of unequal copy length
   keep their CTAs aligned. */
.team-store-card__hire {
  margin-top: auto;
  align-self: flex-start;
}
/* Browse-only note — quiet caption under the grid (AC4: no checkout at MVP). */
.team-store-catalog__note {
  font-family: var(--font-sans);
  font-size: var(--type-size-meta-base);
  color: var(--ink-quiet);
}
/* Story 3.31 — /team-store marketplace surface (catalog card grid + browse-only note; hero + foot reuse product-page + crosslinks primitives) */
/* ──────────────────────────────────────────────────────────────────────────
   solutions-index.css — Story 3.13 /solutions index surface consumer rules.

   Hero reuses .hero / .hero-inner (hero.css).
   This file adds: solutions-index-h1, sub, by-size and by-sector section
   layout, segment list cards, not-sure affordance, and crosslinks nav.

   Lives under tokens/** so the four-prefix stylelint regex exemption
   (Story 1.1) covers ad-hoc class names per nav.css / pricing.css precedent.
   ────────────────────────────────────────────────────────────────────────── */
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Hero typography.                                                        │
   └────────────────────────────────────────────────────────────────────────┘ */
.solutions-index-h1 {
  font-family: var(--font-serif);
  font-weight: var(--type-weight-regular);
  font-size: var(--type-size-h1-base);
  line-height: var(--type-line-height-tight);
  letter-spacing: -0.02em;
  color: var(--ink-primary);
  margin: 0 0 var(--space-3);
}
.solutions-index-sub {
  font-family: var(--font-serif);
  font-size: var(--type-size-body-comfortable);
  line-height: var(--type-line-height-loose);
  color: var(--ink-secondary);
  max-width: 60ch;
  margin: 0 auto;
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Section wrappers — bysize and bysector share the same shell.           │
   └────────────────────────────────────────────────────────────────────────┘ */
.solutions-index-bysize,
.solutions-index-bysector {
  width: 100%;
  padding: var(--space-6) var(--space-3) var(--space-5);
}
@media (min-width: 768px) {
  .solutions-index-bysize,
  .solutions-index-bysector {
    padding-left: var(--space-4);
    padding-right: var(--space-4);
  }
}
.solutions-index-bysector {
  background: var(--surface-tint, transparent);
}
.solutions-index-section-inner {
  max-width: var(--measure);
  margin: 0 auto;
}
.solutions-index-section-h2 {
  font-family: var(--font-serif);
  font-weight: var(--type-weight-regular);
  font-size: var(--type-size-h2-base);
  line-height: var(--type-line-height-tight);
  letter-spacing: -0.02em;
  color: var(--ink-primary);
  margin: 0 0 var(--space-2);
}
.solutions-index-section-intro {
  font-family: var(--font-serif);
  font-size: var(--type-size-body-base);
  line-height: var(--type-line-height-loose);
  color: var(--ink-secondary);
  margin: 0 0 var(--space-4);
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Segment list — 1-col mobile, 2-col (bysize) / 3-col (bysector) wider. │
   └────────────────────────────────────────────────────────────────────────┘ */
.solutions-index-segment-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-3);
}
@media (min-width: 640px) {
  .solutions-index-bysize .solutions-index-segment-list {
    grid-template-columns: repeat(3, 1fr);
  }
  .solutions-index-bysector .solutions-index-segment-list {
    grid-template-columns: repeat(2, 1fr);
  }
}
@media (min-width: 960px) {
  .solutions-index-bysector .solutions-index-segment-list {
    grid-template-columns: repeat(3, 1fr);
  }
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Segment card — anchor fills the card.                                  │
   └────────────────────────────────────────────────────────────────────────┘ */
.solutions-index-segment-item {
  display: flex;
}
.solutions-index-segment-link {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  flex: 1;
  padding: var(--space-3);
  border: 1px solid var(--rule-quiet);
  border-radius: 4px;
  text-decoration: none;
  transition: border-color var(--motion-quick) var(--easing),
              background var(--motion-quick) var(--easing);
}
.solutions-index-segment-link:hover,
.solutions-index-segment-link:focus-visible {
  border-color: var(--accent-primary);
  background: var(--surface-tint, transparent);
}
.solutions-index-segment-link:focus-visible {
  outline: 2px solid var(--ink-primary);
  outline-offset: 2px;
  border-radius: 4px;
}
.solutions-index-segment-name {
  font-family: var(--font-sans);
  font-weight: var(--type-weight-medium);
  font-size: var(--type-size-body-base);
  color: var(--ink-primary);
}
.solutions-index-segment-tagline {
  font-family: var(--font-serif);
  font-size: var(--type-size-meta-base);
  line-height: var(--type-line-height-loose);
  color: var(--ink-secondary);
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Not-sure affordance (Lucie-gated).                                     │
   └────────────────────────────────────────────────────────────────────────┘ */
.solutions-index-notsure {
  width: 100%;
  padding: var(--space-5) var(--space-3);
}
@media (min-width: 768px) {
  .solutions-index-notsure {
    padding-left: var(--space-4);
    padding-right: var(--space-4);
  }
}
.solutions-index-notsure-intro {
  font-family: var(--font-serif);
  font-weight: var(--type-weight-medium);
  font-size: var(--type-size-body-comfortable);
  color: var(--ink-primary);
  margin: 0 0 var(--space-2);
}
.solutions-index-notsure-body {
  font-family: var(--font-serif);
  font-size: var(--type-size-body-base);
  line-height: var(--type-line-height-loose);
  color: var(--ink-secondary);
  max-width: 60ch;
  margin: 0 0 var(--space-3);
}
.solutions-index-notsure-btn {
  font-family: var(--font-sans);
  font-size: var(--type-size-body-base);
  font-weight: var(--type-weight-medium);
  color: var(--accent-primary);
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  text-decoration: underline;
  text-decoration-color: transparent;
  text-underline-offset: 0.25em;
  transition: text-decoration-color var(--motion-quick) var(--easing);
}
.solutions-index-notsure-btn:hover,
.solutions-index-notsure-btn:focus-visible {
  text-decoration-color: var(--accent-primary);
}
.solutions-index-notsure-btn:focus-visible {
  outline: 2px solid var(--ink-primary);
  outline-offset: 2px;
  border-radius: 2px;
}
/* Cross-links retired 2026-05-14 — served by unified .crosslinks
   primitive in tokens/stigmergy.css. */
/* Story 3.13 — /solutions index surface (hero h1, by-size 3-card, by-sector 6-card, crosslinks) */
/* ──────────────────────────────────────────────────────────────────────────
   solutions-sub.css — Stories 3.14–3.22 /solutions sub-page consumer rules.

   Shared layout for all nine solutions sub-pages (three by-size + six
   by-sector). Hero reuses .hero / .hero-inner (hero.css).
   ────────────────────────────────────────────────────────────────────────── */
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Hero typography.                                                        │
   └────────────────────────────────────────────────────────────────────────┘ */
.solutions-sub-h1 {
  font-family: var(--font-serif);
  font-weight: var(--type-weight-regular);
  font-size: var(--type-size-h1-base);
  line-height: var(--type-line-height-tight);
  letter-spacing: -0.02em;
  color: var(--ink-primary);
  margin: 0 0 var(--space-3);
}
.solutions-sub-hero-sub {
  font-family: var(--font-serif);
  font-size: var(--type-size-body-comfortable);
  line-height: var(--type-line-height-loose);
  color: var(--ink-secondary);
  max-width: 60ch;
  margin: 0 auto;
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Sub-hero — editorial pull-quote with emphasis.                          │
   │ Larger serif italic at medium weight + an oversized opening quote mark │
   │ in --accent-primary. Mode-adaptive accent (EU blue / EU gold) follows  │
   │ the page-level cascade. Type stays solid-on-solid (UX-DR1).            │
   └────────────────────────────────────────────────────────────────────────┘ */
.solutions-sub-subhero {
  width: 100%;
  max-width: var(--measure);
  margin: var(--space-6) auto;
  padding: 0 var(--space-3);
  font-family: var(--font-serif);
  font-size: 1.25rem;
  font-style: italic;
  font-weight: var(--type-weight-medium);
  line-height: var(--type-line-height-loose);
  color: var(--ink-primary);
}
.solutions-sub-subhero::before {
  content: "\201C";
  display: block;
  font-family: var(--font-serif);
  font-style: normal;
  font-weight: var(--type-weight-regular);
  font-size: 3.5rem;
  line-height: 0.7;
  color: var(--accent-primary);
  opacity: 0.5;
  margin: 0 0 var(--space-1);
}
@media (min-width: 768px) {
  .solutions-sub-subhero {
    font-size: 1.375rem;
    padding: 0 var(--space-4);
  }
  .solutions-sub-subhero::before {
    font-size: 4rem;
  }
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Use-cases section.                                                      │
   └────────────────────────────────────────────────────────────────────────┘ */
.solutions-sub-usecases {
  width: 100%;
  padding: var(--space-5) var(--space-3);
}
@media (min-width: 768px) {
  .solutions-sub-usecases {
    padding-left: var(--space-4);
    padding-right: var(--space-4);
  }
}
.solutions-sub-usecases-inner {
  max-width: var(--measure);
  margin: 0 auto;
}
.solutions-sub-usecases-h2 {
  font-family: var(--font-serif);
  font-weight: var(--type-weight-semibold);
  font-size: 1.5rem;
  line-height: var(--type-line-height-tight);
  color: var(--ink-primary);
  margin: 0 0 var(--space-4);
}
.solutions-sub-usecase-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-3);
}
@media (min-width: 768px) {
  .solutions-sub-usecase-list {
    grid-template-columns: 1fr 1fr;
    gap: var(--space-4);
  }
}
.solutions-sub-usecase-item {
  position: relative;
  padding: var(--space-4);
  background: var(--surface-tint, transparent);
  border: 1px solid var(--rule-quiet);
  border-radius: 6px;
  transition:
    border-color var(--motion-quick) var(--easing),
    transform var(--motion-quick) var(--easing);
}
.solutions-sub-usecase-item:hover,
.solutions-sub-usecase-item:focus-within {
  border-color: var(--accent-primary);
  transform: translateY(-1px);
}
@media (prefers-reduced-motion: reduce) {
  .solutions-sub-usecase-item {
    transition: border-color var(--motion-quick) var(--easing);
  }
  .solutions-sub-usecase-item:hover,
  .solutions-sub-usecase-item:focus-within {
    transform: none;
  }
}
.solutions-sub-usecase-name {
  font-family: var(--font-sans);
  font-weight: var(--type-weight-medium);
  font-size: var(--type-size-body-comfortable);
  color: var(--ink-primary);
  margin: 0 0 var(--space-2);
}
.solutions-sub-usecase-body {
  font-family: var(--font-serif);
  font-size: var(--type-size-body-base);
  line-height: var(--type-line-height-loose);
  color: var(--ink-secondary);
  margin: 0;
}
/* CTA section retired — solutions sub-pages now route the discovery-call
   + become-a-partner CTAs through the unified .crosslinks table at page
   foot (common.crosslinks.discoveryCall* + .becomePartner*). */
/* Cross-links retired 2026-05-14 — served by unified .crosslinks
   primitive in tokens/stigmergy.css. */
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Placeholder (SOLUTIONS_INDIVIDUALS_LIVE=false).                        │
   └────────────────────────────────────────────────────────────────────────┘ */
.solutions-sub-coming-soon {
  padding: var(--space-6) var(--space-3);
  font-family: var(--font-sans);
  font-size: var(--type-size-body-base);
  color: var(--ink-quiet);
}
/* Stories 3.14–3.22 — /solutions sub-page shared layout (hero, use cases, CTA, crosslinks) */
/* ──────────────────────────────────────────────────────────────────────────
   about.css — Stories 3.23–3.25 /about surface consumer rules.

   Hero reuses .hero / .hero-inner (hero.css).
   This file adds: about hub sections (founders, mission, values,
   crosslinks) and shared section scaffolding for /about sub-pages.
   ────────────────────────────────────────────────────────────────────────── */
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Section shell — shared across hub sections.                            │
   └────────────────────────────────────────────────────────────────────────┘ */
.about-hub-founders,
.about-hub-mission,
.about-hub-values {
  width: 100%;
  padding: var(--space-6) var(--space-3) var(--space-5);
}
@media (min-width: 768px) {
  .about-hub-founders,
  .about-hub-mission,
  .about-hub-values {
    padding-left: var(--space-4);
    padding-right: var(--space-4);
  }
}
.about-hub-mission {
  background: var(--surface-tint, transparent);
}
.about-hub-section-inner {
  max-width: var(--measure);
  margin: 0 auto;
}
.about-hub-section-h2 {
  font-family: var(--font-serif);
  font-weight: var(--type-weight-regular);
  font-size: 1.5rem;
  line-height: var(--type-line-height-tight);
  letter-spacing: -0.02em;
  color: var(--ink-primary);
  margin: 0 0 var(--space-3);
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Founders grid.                                                          │
   └────────────────────────────────────────────────────────────────────────┘ */
.about-hub-founders-list {
  list-style: none;
  margin: 0 0 var(--space-4);
  padding: 0;
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-4);
}
@media (min-width: 640px) {
  .about-hub-founders-list {
    grid-template-columns: repeat(2, 1fr);
  }
}
.about-hub-founder-card {
  padding: var(--space-3);
  border: 1px solid var(--rule-quiet);
  border-radius: 4px;
}
.about-hub-founder-name {
  font-family: var(--font-serif);
  font-weight: var(--type-weight-medium);
  font-size: var(--type-size-body-base);
  color: var(--ink-primary);
  margin: 0 0 var(--space-1);
}
.about-hub-founder-role {
  font-family: var(--font-serif);
  font-size: var(--type-size-meta-base);
  color: var(--ink-quiet);
  margin: 0 0 var(--space-2);
}
.about-hub-founder-bio {
  font-family: var(--font-serif);
  font-size: var(--type-size-body-base);
  line-height: var(--type-line-height-loose);
  color: var(--ink-secondary);
  margin: 0;
}
.about-hub-founders-team-cta {
  font-family: var(--font-serif);
  font-size: var(--type-size-meta-base);
  color: var(--ink-quiet);
  margin: 0;
}
.about-hub-founders-team-cta a {
  color: var(--accent-primary);
  font-weight: var(--type-weight-medium);
  text-decoration: underline;
  text-decoration-color: transparent;
  text-underline-offset: 0.25em;
  transition: text-decoration-color var(--motion-quick) var(--easing);
}
.about-hub-founders-team-cta a:hover,
.about-hub-founders-team-cta a:focus-visible {
  text-decoration-color: var(--accent-primary);
}
.about-hub-founders-team-cta a:focus-visible {
  outline: 2px solid var(--ink-primary);
  outline-offset: 2px;
  border-radius: 2px;
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Mission body paragraphs.                                                │
   └────────────────────────────────────────────────────────────────────────┘ */
.about-hub-mission-body {
  font-family: var(--font-serif);
  font-size: var(--type-size-body-base);
  line-height: var(--type-line-height-loose);
  color: var(--ink-secondary);
  margin: 0 0 var(--space-3);
}
.about-hub-mission-body:last-child {
  margin-bottom: 0;
}
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ Values — orbit. Six values pinned at clock positions (12, 2, 4, 6,     │
   │ 8, 10) on a faint dashed ring. Four ants animate CW around the same   │
   │ ring at 90° phase offsets — the values stay still, the ants do the    │
   │ moving. Honours prefers-reduced-motion by pausing the ants and        │
   │ distributing them statically. Mobile (<640px) falls back to a         │
   │ vertical stack since multi-line values can't compress on the ring.    │
   └────────────────────────────────────────────────────────────────────────┘ */
/* Mobile fallback: vertical stack, no orbit, no ants. */
.about-hub-values-orbit,
.about-careers-values-orbit {
  margin: 0;
}
.about-hub-values-ants,
.about-careers-values-ants {
  display: none;
}
.about-hub-values-list,
.about-careers-values-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
.about-hub-values-item,
.about-careers-values-item {
  font-family: var(--font-serif);
  font-size: var(--type-size-body-base);
  line-height: var(--type-line-height-loose);
  color: var(--ink-primary);
  margin: 0 0 var(--space-3);
  text-align: left;
}
.about-hub-values-item:last-child,
.about-careers-values-item:last-child {
  margin-bottom: 0;
}
/* Tablet+: orbit. */
@media (min-width: 640px) {
  .about-hub-values-orbit,
  .about-careers-values-orbit {
    position: relative;
    width: 100%;
    max-width: 34rem;
    aspect-ratio: 1;
    margin: var(--space-5) auto 0;
  }
  /* Faint dashed orbit ring — the trail values sit on and ants travel along. */
  .about-hub-values-orbit::before,
  .about-careers-values-orbit::before {
    content: "";
    position: absolute;
    inset: 18%;
    border-radius: 50%;
    border: 1px dashed var(--rule-quiet);
    pointer-events: none;
  }
  .about-hub-values-list,
  .about-careers-values-list {
    position: absolute;
    inset: 0;
    margin: 0;
    padding: 0;
  }
  .about-hub-values-item,
  .about-careers-values-item {
    position: absolute;
    width: max-content;
    max-width: 16ch;
    margin: 0;
    line-height: var(--type-line-height-tight);
    text-align: center;
    transform: translate(-50%, -50%);
  }
  /* 60° apart, starting at 12 o'clock. radius = 32% from centre.
     cos60° = 0.5  → 50% ± 16%.   sin60° = 0.866 → 50% ± 27.7%. */
  .about-hub-values-item:nth-child(1),
  .about-careers-values-item:nth-child(1) { top:  18%; left: 50%;   }
  .about-hub-values-item:nth-child(2),
  .about-careers-values-item:nth-child(2) { top:  34%; left: 77.7%; }
  .about-hub-values-item:nth-child(3),
  .about-careers-values-item:nth-child(3) { top:  66%; left: 77.7%; }
  .about-hub-values-item:nth-child(4),
  .about-careers-values-item:nth-child(4) { top:  82%; left: 50%;   }
  .about-hub-values-item:nth-child(5),
  .about-careers-values-item:nth-child(5) { top:  66%; left: 22.3%; }
  .about-hub-values-item:nth-child(6),
  .about-careers-values-item:nth-child(6) { top:  34%; left: 22.3%; }

  /* Ants layer — overlaps the orbit, decorative. Each ant is a full-size
     square that pins the glyph at the ring's top (12 o'clock at inset 18%)
     then rotates as a whole around its centre.
     The #stigmergy-ant glyph has its head (smallest circle, cx=1, r=0.7)
     at the LEFT of its viewBox and abdomen (largest, cx=6.5) at the right
     — so default head direction is -X. CW motion at 12 o'clock is +X,
     which would put abdomen-leading. We pre-rotate the svg 180° so the
     head points +X at 12 o'clock; the head then leads the trail at every
     position around the ring without further per-position correction. */
  .about-hub-values-ants,
  .about-careers-values-ants {
    display: block;
    position: absolute;
    inset: 0;
    pointer-events: none;
  }
  .about-hub-values-ant,
  .about-careers-values-ant {
    position: absolute;
    inset: 0;
    animation: values-ant-orbit 22s linear infinite;
    will-change: transform;
  }
  .about-hub-values-ant > svg,
  .about-careers-values-ant > svg {
    position: absolute;
    top: 18%;
    left: 50%;
    width: 18px;
    height: 7px;
    transform: translate(-50%, -50%) rotate(180deg);
    color: var(--ink-quiet);
    overflow: visible;
  }
  /* Four ants, evenly spaced at quarter positions on t=0; each carries a
     slightly different cycle duration (20/22/24/26s) so the spacing drifts
     organically over time instead of marching in lockstep. Each negative
     animation-delay is proportional to its own duration so all four start
     exactly at their 0°/90°/180°/270° positions. */
  .about-hub-values-ant:nth-child(1),
  .about-careers-values-ant:nth-child(1) { animation-duration: 20s; }
  .about-hub-values-ant:nth-child(2),
  .about-careers-values-ant:nth-child(2) { animation-duration: 22s; animation-delay:  -5.5s; }
  .about-hub-values-ant:nth-child(3),
  .about-careers-values-ant:nth-child(3) { animation-duration: 24s; animation-delay: -12s;   }
  .about-hub-values-ant:nth-child(4),
  .about-careers-values-ant:nth-child(4) { animation-duration: 26s; animation-delay: -19.5s; }
}
@keyframes values-ant-orbit {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}
/* Reduced motion: pause the orbit, distribute the four ants statically. */
@media (min-width: 640px) and (prefers-reduced-motion: reduce) {
  .about-hub-values-ant,
  .about-careers-values-ant {
    animation: none;
  }
  .about-hub-values-ant:nth-child(1),
  .about-careers-values-ant:nth-child(1) { transform: rotate(0deg);   }
  .about-hub-values-ant:nth-child(2),
  .about-careers-values-ant:nth-child(2) { transform: rotate(90deg);  }
  .about-hub-values-ant:nth-child(3),
  .about-careers-values-ant:nth-child(3) { transform: rotate(180deg); }
  .about-hub-values-ant:nth-child(4),
  .about-careers-values-ant:nth-child(4) { transform: rotate(270deg); }
}
/* Cross-links retired 2026-05-14 — served by unified .crosslinks
   primitive in tokens/stigmergy.css. */
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ About/team — sub-hero, founders list, cofounding (Story 3.24).         │
   └────────────────────────────────────────────────────────────────────────┘ */
.about-team-subhero {
  width: 100%;
  max-width: var(--measure);
  margin: var(--space-6) auto var(--space-4);
  padding: 0 var(--space-3);
  font-family: var(--font-serif);
  font-size: var(--type-size-body-base);
  font-style: italic;
  line-height: var(--type-line-height-loose);
  color: var(--ink-secondary);
}
@media (min-width: 768px) {
  .about-team-subhero {
    padding: 0 var(--space-4);
  }
}
.about-team-founders,
.about-team-cofounding {
  width: 100%;
  padding: var(--space-6) var(--space-3) var(--space-5);
}
@media (min-width: 768px) {
  .about-team-founders,
  .about-team-cofounding {
    padding-left: var(--space-4);
    padding-right: var(--space-4);
  }
}
.about-team-cofounding {
  background: var(--surface-tint, transparent);
}
.about-team-founders-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
}
.about-team-founder-card {
  padding-bottom: var(--space-6);
  border-bottom: 1px solid var(--rule-quiet);
}
.about-team-founder-card:last-child {
  border-bottom: none;
  padding-bottom: 0;
}
.about-team-founder-header {
  margin-bottom: var(--space-3);
}
.about-team-founder-name {
  font-family: var(--font-serif);
  font-weight: var(--type-weight-medium);
  font-size: var(--type-size-body-base);
  color: var(--ink-primary);
  margin: 0 0 var(--space-1);
}
.about-team-founder-role {
  font-family: var(--font-serif);
  font-size: var(--type-size-meta-base);
  color: var(--ink-quiet);
  margin: 0;
}
.about-team-founder-background,
.about-team-founder-daytodday {
  font-family: var(--font-serif);
  font-size: var(--type-size-body-base);
  line-height: var(--type-line-height-loose);
  color: var(--ink-secondary);
  margin: 0 0 var(--space-2);
}
.about-team-founder-conviction {
  margin: var(--space-3) 0 0 var(--space-2);
  padding-left: var(--space-3);
  border-left: 2px solid var(--accent-primary);
}
.about-team-founder-conviction p {
  font-family: var(--font-serif);
  font-style: italic;
  font-size: var(--type-size-body-base);
  line-height: var(--type-line-height-loose);
  color: var(--ink-primary);
  margin: 0;
}
.about-team-cofounding-body {
  font-family: var(--font-serif);
  font-size: var(--type-size-body-base);
  line-height: var(--type-line-height-loose);
  color: var(--ink-secondary);
  margin: 0;
}
/* .about-team-crosslinks retired 2026-05-14 — unified primitive. */
/* ┌────────────────────────────────────────────────────────────────────────┐
   │ About/careers — roles, culture, crosslinks (Story 3.25).               │
   └────────────────────────────────────────────────────────────────────────┘ */
.about-careers-openroles,
.about-careers-culture,
.about-careers-values {
  width: 100%;
  padding: var(--space-6) var(--space-3) var(--space-5);
}
@media (min-width: 768px) {
  .about-careers-openroles,
  .about-careers-culture,
  .about-careers-values {
    padding-left: var(--space-4);
    padding-right: var(--space-4);
  }
}
.about-careers-culture {
  background: var(--surface-tint, transparent);
}
.about-careers-roles-body {
  font-family: var(--font-serif);
  font-size: var(--type-size-body-base);
  line-height: var(--type-line-height-loose);
  color: var(--ink-secondary);
  margin: 0 0 var(--space-3);
}
.about-careers-roles-hint {
  font-family: var(--font-serif);
  font-size: var(--type-size-meta-base);
  color: var(--ink-quiet);
  margin: 0 0 var(--space-3);
}
.about-careers-roles-cta {
  display: inline-block;
  font-family: var(--font-serif);
  font-size: var(--type-size-body-base);
  font-weight: var(--type-weight-medium);
  color: var(--accent-primary);
  text-decoration: underline;
  text-decoration-color: transparent;
  text-underline-offset: 0.25em;
  transition: text-decoration-color var(--motion-quick) var(--easing);
}
.about-careers-roles-cta:hover,
.about-careers-roles-cta:focus-visible {
  text-decoration-color: var(--accent-primary);
}
.about-careers-roles-cta:focus-visible {
  outline: 2px solid var(--ink-primary);
  outline-offset: 2px;
  border-radius: 2px;
}
.about-careers-culture-body {
  font-family: var(--font-serif);
  font-size: var(--type-size-body-base);
  line-height: var(--type-line-height-loose);
  color: var(--ink-secondary);
  margin: 0 0 var(--space-3);
}
.about-careers-culture-body:last-child {
  margin-bottom: 0;
}
/* .about-careers-crosslinks retired 2026-05-14 — unified primitive. */
/* Stories 3.23–3.25 — /about hub and sub-pages (founders, mission, values, contact, crosslinks) */
/* ──────────────────────────────────────────────────────────────────────────
   tokens/widget.css — Lucie widget shell styles (Story 4.2).

   Shipped in the main tokens.css bundle (always available on every surface)
   so the CTA stub button rendered by lucie-mount.eta's inline script is styled
   before the widget JS lazy-loads.  Dead rules on LUCIE_ENABLED=false pages
   (no widget elements exist in the DOM).

   Consumed by:
     • .lucie-cta         — CTA stub (inline script) + React Dialog.Trigger
     • .lucie-overlay     — Dialog overlay (mobile only)
     • .lucie-dialog      — floating card (lower-right desktop / full-viewport mobile)
     • .lucie-status-banner — Article 50 disclosure (Story 4.4 sets canonical copy)
     • .lucie-chat-window — conversation log (Story 4.3 populates)
     • .lucie-input-bar / .lucie-input — message input (Story 4.3 enables)
     • .lucie-close       — close button
   ────────────────────────────────────────────────────────────────────────── */
/* ── Nav CTA button (Story 4.6) — inline header affordance ──────────────── */
/* Quiet chrome control — mirrors .mode-toggle / .locale-switcher-summary
   pixel-for-pixel (Tom 2026-05-13): same 32×32 square, same border /
   padding / radius / colour rhythm so the three utility-nav controls
   read as a single set. The primary "open chat" affordance remains the
   floating .lucie-cta. */
.nav-lucie-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0.375rem;
  background: transparent;
  color: var(--ink-secondary);
  border: 1px solid var(--rule-quiet);
  border-radius: 6px;
  cursor: pointer;
  flex-shrink: 0;
  line-height: 0;
  /* Story 4.7: `.nav-lucie-btn` is now an <a> (was <button>). Suppress the
     browser-default anchor underline so the icon-only chrome control stays
     visually identical to its prior button form. */
  text-decoration: none;
  transition:
    color var(--motion-quick) var(--easing),
    border-color var(--motion-quick) var(--easing);
}
.nav-lucie-btn:hover {
  color: var(--ink-primary);
  border-color: var(--metal-platine);
}
.nav-lucie-btn__icon {
  display: block;
}
.nav-lucie-btn:focus-visible {
  outline: 2px solid var(--accent-primary);
  outline-offset: 2px;
  border-radius: 6px;
}
@media (prefers-reduced-motion: reduce) {
  .nav-lucie-btn {
    transition: none;
  }
}
/* ── CTA trigger button ──────────────────────────────────────────────────── */
.lucie-cta {
  position: fixed;
  bottom: var(--space-4, 1.5rem);
  right: var(--space-4, 1.5rem);
  z-index: 990;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.875rem;
  background: var(--ink-primary);
  color: var(--surface-page);
  border: 1px solid var(--ink-primary);
  border-radius: 6px;
  cursor: pointer;
  line-height: 0;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.18);
  transition:
    box-shadow var(--motion-quick, 150ms) var(--easing, ease),
    transform var(--motion-quick, 150ms) var(--easing, ease);
}
.lucie-cta__icon {
  display: block;
}
/* Hover box-shadow lift + translate removed — fill + resting shadow stay.
   Scale + shine in cta-interaction.css are the sole hover signal. */
.lucie-cta:focus-visible {
  outline: 2px solid var(--ink-primary);
  outline-offset: 2px;
  border-radius: 6px;
}
@media (prefers-reduced-motion: reduce) {
  .lucie-cta {
    transition: none;
  }
}
/* ── Overlay (mobile only — desktop floats without backdrop) ─────────────── */
.lucie-overlay {
  display: none;
}
@media (max-width: 639px) {
  .lucie-overlay {
    display: block;
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.4);
    z-index: 9998;
    animation: lucie-overlay-in var(--motion-appear, 180ms) ease;
  }

  @media (prefers-reduced-motion: reduce) {
    .lucie-overlay {
      animation: none;
    }
  }
}
@keyframes lucie-overlay-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}
/* ── Dialog card ─────────────────────────────────────────────────────────── */
/* overflow:visible so .lucie-close can sit outside the panel (Tom 2026-05-13
   cosmetic pass: the closing cross is anchored above the dialog, not inside).
   The chat-window has its own overflow-y:auto so message history still
   scrolls independently. */
.lucie-dialog {
  position: fixed;
  bottom: 5rem; /* above the CTA button */
  right: var(--space-4, 1.5rem);
  width: 380px;
  max-width: calc(100vw - 3rem);
  max-height: 600px;
  display: flex;
  flex-direction: column;
  background: var(--surface-card);
  border: 1px solid var(--rule-quiet);
  border-radius: 8px;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12);
  z-index: 9999;
  overflow: visible;
  animation: lucie-dialog-in var(--motion-appear, 180ms) ease;
}
@keyframes lucie-dialog-in {
  from { opacity: 0; transform: translateY(0.5rem); }
  to   { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  .lucie-dialog {
    animation: none;
  }
}
/* Mobile: full viewport via CSS-only sizing — no JS-driven layout */
@media (max-width: 639px) {
  .lucie-dialog {
    inset: 0;
    width: 100%;
    max-width: 100%;
    max-height: 100%;
    height: 100%;
    border-radius: 0;
    right: 0;
    bottom: 0;
  }
}
/* ── Article 50 status banner — pinned to top of dialog ──────────────────── */
.lucie-status-banner {
  padding: var(--space-1) var(--space-3);
  background: var(--surface-page);
  border-top: 1px solid var(--rule-quiet);
  font-family: var(--font-sans);
  font-size: var(--type-size-meta-base);
  line-height: var(--type-line-height-loose);
  color: var(--ink-quiet);
  flex-shrink: 0;
}
/* ── Conversation log ────────────────────────────────────────────────────── */
/* The chat-window owns the only scrollbar inside the chat surface. The
   widget overflow:visible (above) lets the close button escape; this
   element keeps its own clip via border-radius on .lucie-dialog. */
.lucie-chat-window {
  flex: 1;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--space-3);
  min-height: 160px;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  border-top-left-radius: 8px;
  border-top-right-radius: 8px;
}
/* ── Chat messages (Story 4.3) ───────────────────────────────────────────── */
/* Brand-minimal transcript: user replies sit in an ink-filled bubble flush
   right; assistant replies are plain ink-on-card text flush left — reads
   like a transcript, not a chat-app. */
.lucie-message {
  font-family: var(--font-sans);
  font-size: var(--type-size-body-base);
  line-height: var(--type-line-height-base);
  color: var(--ink-primary);
  white-space: pre-wrap;
  word-wrap: break-word;
}
.lucie-message--user {
  align-self: flex-end;
  max-width: 80%;
  padding: 0.375rem var(--space-2);
  background: var(--ink-primary);
  color: var(--surface-page);
  border-radius: 0.75rem;
}
.lucie-message--assistant {
  align-self: stretch;
}
/* ── Loading dots — assistant streaming indicator ────────────────────────── */
.lucie-loading-dots {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 0.5rem 0;
  align-self: flex-start;
}
.lucie-loading-dots span {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--ink-quiet);
  animation: lucie-dot-pulse 1.2s ease-in-out infinite;
}
.lucie-loading-dots span:nth-child(2) { animation-delay: 0.15s; }
.lucie-loading-dots span:nth-child(3) { animation-delay: 0.3s; }
@keyframes lucie-dot-pulse {
  0%, 80%, 100% { opacity: 0.3; }
  40%           { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .lucie-loading-dots span {
    animation: none;
    opacity: 0.6;
  }
}
/* ── Error state — shown between log and input on error ──────────────────── */
.lucie-error-state {
  padding: var(--space-1) var(--space-3);
  background: var(--surface-page);
  border-top: 1px solid var(--rule-quiet);
  font-family: var(--font-sans);
  font-size: var(--type-size-meta-base);
  line-height: var(--type-line-height-loose);
  color: var(--ink-primary);
  flex-shrink: 0;
}
/* ── Input bar ───────────────────────────────────────────────────────────── */
.lucie-input-bar {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border-top: 1px solid var(--rule-quiet);
  flex-shrink: 0;
}
.lucie-input {
  flex: 1;
  min-width: 0;
  border: 1px solid var(--rule-quiet);
  border-radius: 4px;
  padding: 0.5rem var(--space-2);
  font-family: var(--font-sans);
  font-size: var(--type-size-body-base);
  color: var(--ink-primary);
  background: var(--surface-page);
  line-height: 1.4;
}
.lucie-input:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
.lucie-input:focus-visible {
  outline: 2px solid var(--ink-primary);
  outline-offset: 1px;
}
/* ── Submit button — paired with .lucie-input ────────────────────────────── */
/* Icon-only paper-plane affordance (Tom 2026-05-13). Square ink-on-ink
   target matching .lucie-cta / .nav-lucie-btn rhythm: same border-radius,
   same anthracite fill, same chrome — the chat send button is a
   miniature of the landing-page CTA button so the surface and the widget
   speak the same visual language. */
.lucie-submit {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  padding: 0;
  background: var(--ink-primary);
  color: var(--surface-page);
  border: 1px solid var(--ink-primary);
  border-radius: 6px;
  line-height: 0;
  cursor: pointer;
  transition:
    box-shadow var(--motion-quick, 150ms) var(--easing, ease),
    transform var(--motion-quick, 150ms) var(--easing, ease);
}
.lucie-submit__icon {
  display: block;
  width: 18px;
  height: 18px;
}
.lucie-submit:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
.lucie-submit:focus-visible {
  outline: 2px solid var(--ink-primary);
  outline-offset: 2px;
  border-radius: 6px;
}
@media (prefers-reduced-motion: reduce) {
  .lucie-submit {
    transition: none;
  }
}
/* ── Sentence-boundary live announcer (Story 4.5 AC3) ───────────────────── */
/* Visually hidden but accessible to screen readers (sr-only pattern). */
.lucie-live-announcer {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
/* ── Close button ────────────────────────────────────────────────────────── */
/* Anchored OUTSIDE the dialog, upper-right (Tom 2026-05-13). The button is
   absolutely positioned relative to .lucie-dialog and sits just above its
   top edge, right-aligned — it reads as a chrome control that's adjacent
   to the panel rather than inside it. On mobile the dialog fills the
   viewport, so we tuck the close back inside (top:0.5rem; right:0.5rem)
   to keep the target reachable. */
.lucie-close {
  position: absolute;
  top: -2.5rem;
  right: 0;
  width: 2rem;
  height: 2rem;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--rule-quiet);
  background: var(--surface-card);
  cursor: pointer;
  border-radius: 6px;
  font-size: 1.125rem;
  line-height: 1;
  color: var(--ink-secondary, #555);
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.12);
  transition:
    color var(--motion-quick, 150ms) var(--easing, ease),
    border-color var(--motion-quick, 150ms) var(--easing, ease);
}
.lucie-close:hover {
  color: var(--ink-primary);
  border-color: var(--metal-platine, var(--ink-primary));
}
.lucie-close:focus-visible {
  outline: 2px solid var(--ink-primary, #1a1a1a);
  outline-offset: 2px;
  border-radius: 6px;
}
@media (max-width: 639px) {
  /* Mobile full-viewport dialog: tuck the close back inside the top-right
     corner since there is no "outside" left to occupy. */
  .lucie-close {
    top: var(--space-2, 0.5rem);
    right: var(--space-2, 0.5rem);
    background: transparent;
    border-color: transparent;
    box-shadow: none;
  }
}
@media (prefers-reduced-motion: reduce) {
  .lucie-close {
    transition: none;
  }
}
/* ─────────────────────────────────────────────────────────────────────────
   Story 4.7 — dedicated /lucie chat surface.

   Page-scroll lock (Tom 2026-05-13): on /lucie the document does NOT
   scroll — header and site-footer are always visible, and the only
   scrollable region is the chat-window (.lucie-chat-window). This is
   the conversational-app convention: history scrolls inside the panel,
   the page chrome stays put.

   Layout:
     body[data-surface="lucie-page"]   100svh flex column, overflow:hidden
       └ header.site                   static (sticky is moot on a non-
                                       scrolling page; static avoids the
                                       sticky-on-flex-child quirk)
       └ main#main                     flex:1, overflow:hidden, flex column
         └ .lucie-page                 flex:1, min-height:0, overflow:hidden
           ├ .lucie-hero               compact, content-height
           └ .lucie-page-shell         flex:1, min-height:0, overflow:hidden
             └ .lucie-chat-window      flex:1, overflow-y:auto (THE scrollbar)
       └ site-footer                   static, flex-shrink:0

   Scoped via the body[data-surface] attribute so every other surface
   (landing, products, solutions, etc.) keeps its normal scrolling
   document. */
body[data-surface="lucie-page"] {
  height: 100svh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
body[data-surface="lucie-page"] > header.site {
  position: static;
  flex-shrink: 0;
}
body[data-surface="lucie-page"] > main#main {
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
body[data-surface="lucie-page"] > .site-footer {
  flex-shrink: 0;
}
.lucie-page {
  display: flex;
  flex-direction: column;
  align-items: center;
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
  max-width: var(--measure);
  margin: 0 auto;
  padding: var(--space-3) var(--space-3);
  box-sizing: border-box;
  gap: var(--space-3);
  overflow: hidden;
}
@media (min-width: 768px) {
  .lucie-page {
    padding: var(--space-3) var(--space-4) var(--space-4);
  }
}
/* Hero block — compact horizontal cluster (Tom 2026-05-13: less space).
   Logo + H1 share a baseline-aligned row; the invite line sits as a
   small caption directly below. The whole block is content-height —
   no padding bloat. */
.lucie-hero {
  display: grid;
  grid-template-columns: auto auto;
  grid-template-rows: auto auto;
  column-gap: var(--space-2);
  row-gap: 0.125rem;
  align-items: center;
  justify-content: center;
  text-align: left;
  margin: 0;
  flex-shrink: 0;
}
.lucie-hero__mark {
  grid-row: 1 / span 2;
  width: 40px;
  height: 40px;
  display: block;
  border-radius: 8px;
}
@media (min-width: 768px) {
  .lucie-hero__mark {
    width: 48px;
    height: 48px;
  }
}
.lucie-hero__title {
  margin: 0;
  font-family: var(--font-serif, var(--font-sans));
  font-size: 1.375rem;
  line-height: 1.1;
  color: var(--ink-primary);
  letter-spacing: -0.01em;
  align-self: end;
}
@media (min-width: 768px) {
  .lucie-hero__title {
    font-size: 1.625rem;
  }
}
.lucie-hero__invite {
  margin: 0;
  color: var(--ink-secondary);
  font-family: var(--font-sans);
  font-size: var(--type-size-meta-base);
  line-height: 1.35;
  align-self: start;
}
/* #lucie-page-root is the React mount point — the bundle injects
   .lucie-page-shell inside it. Make it a transparent flex pass-through
   so the flex:1 + min-height:0 chain reaches all the way down to the
   chat-window's overflow boundary. */
#lucie-page-root {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
  align-items: center;
}
.lucie-page-shell {
  display: flex;
  flex-direction: column;
  width: 100%;
  /* Chat is centered and constrained — narrower than the page measure
     because a conversation reads better in a column. */
  max-width: 44rem;
  margin: 0 auto;
  flex: 1 1 auto;
  /* min-height:0 is the unlock that lets flex:1 actually cap height,
     so .lucie-chat-window's overflow-y:auto becomes effective rather
     than the chat-window growing with content. */
  min-height: 0;
  background: var(--surface-card);
  border: 1px solid var(--rule-quiet);
  border-radius: 8px;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.06);
  overflow: hidden;
}
.lucie-page-shell .lucie-chat-window {
  border-top-left-radius: 8px;
  border-top-right-radius: 8px;
}
@media (max-width: 639px) {
  .lucie-page {
    gap: var(--space-2);
    padding: var(--space-2);
  }
  .lucie-page-shell {
    border-radius: 6px;
  }
}
/* Tablet/phone (paired with the lucie-mount.eta redirect + footer hide at
   < 1024px): /lucie is the dedicated chat surface, so the typing zone is
   pinned to the bottom of the viewport. Fixed positioning is the bulletproof
   read of "stays at the bottom of the viewport" — survives content overflow,
   keyboard reflow, and dynamic toolbars on mobile. Bottom padding on the
   page reserves space so messages don't sit behind the bar; safe-area-inset
   covers iOS home-indicator gutters. Scoped to body[data-surface="lucie-page"]
   because the same .lucie-input-bar selector also styles the floating
   dialog's input, which doesn't open on tablet/phone anymore but stays
   correct on desktop. */
@media (max-width: 1023.98px) {
  body[data-surface="lucie-page"] .lucie-page {
    padding-bottom: calc(var(--space-6) + env(safe-area-inset-bottom, 0px));
  }
  body[data-surface="lucie-page"] .lucie-input-bar {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 20;
    background: var(--surface-page);
    border-top: 1px solid var(--rule-quiet);
    padding-bottom: calc(var(--space-2) + env(safe-area-inset-bottom, 0px));
  }
}
/* Story 4.2 — Lucie widget shell (CTA, overlay, dialog card, status banner, input, close) */
/* ──────────────────────────────────────────────────────────────────────────
   llm.css — LLM-locale markdown viewer.

   The LLM locale wraps each surface's body content in an HTML page (so
   the header remains and the locale switcher works). The body is the
   raw Markdown that will be served at the parallel `.md` URL, displayed
   here inside <pre class="llm-markdown"> so humans can see exactly what
   an LLM ingestion fetcher receives.

   Goals: monospace, soft wrap (no horizontal scroll for long lines),
   readable measure, comfortable padding, inherits the substrate
   colour tokens from layout-base.css.
   ────────────────────────────────────────────────────────────────────────── */
pre.llm-markdown {
  width: 100%;
  max-width: 56rem;
  margin: 0 auto;
  padding: var(--space-5) var(--space-3) var(--space-7);
  color: var(--ink-primary);
  font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);
  font-size: 0.875rem;
  line-height: 1.55;
  white-space: pre-wrap;
  word-break: break-word;
  background: transparent;
}
/* LLM locale — markdown viewer (pre.llm-markdown inside the HTML wrapper served at /llm/{slug}/index.html) */
/* Cross-surface hover affordance — gentle scale + left→right shine on every
   button-shape CTA. Imported LAST (after every per-surface base style). NB:
   under the brand layer this ships in @layer myrmid.foundation, so unlayered
   per-surface CSS wins regardless of import order — that is fine because the
   per-surface hover colour-flips it used to compete with were already removed
   (the AR-6 cascade-regression gate). */
@layer myrmid.foundation {
/* ──────────────────────────────────────────────────────────────────────────
   tokens/cta-interaction.css — shared hover affordance for every button.

   Two stacked effects, applied on :hover and :focus-visible:
     1. Gentle scale (1.03) — smooth grow/shrink, --motion-base (200ms).
     2. Left→right shine — a low-alpha white band sweeps across the surface,
        looping while the pointer / keyboard focus stays on the button.

   Color rule: filled CTAs STAY filled on hover. The per-surface :hover blocks
   that used to invert fill/text colours (or darken via filter) have been
   removed from their respective files. Scale + shine are now the sole hover
   signal across every button-shape CTA on the site.

   In scope (every button-shape CTA — text-link CTAs intentionally untouched
   since they have no surface for a shine to traverse):

     .cta-lucie                                       (hero)
     .product-cta-button                              (products + partners)
     .pricing-tier-card__cta                          (pricing tier cards)
     .pricing-enterprise__cta.pricing-cta-button      (pricing enterprise)
     .lucie-cta                                       (floating widget)
     .consent-button                                  (cookie accept / reject)
     .consent-trigger                                 (consent withdrawal)

   Out of scope: .nav-lucie-btn — the header chat affordance is a quiet
   chrome control (mirrors .locale-switcher-summary), not a CTA. Its hover
   treatment is owned by widget.css (border-color + colour lift).

   Reduced motion: motion-tokens.css installs a global
   prefers-reduced-motion: reduce override that zeroes transition / animation
   durations and clamps iteration count to 1. No extra guard needed here.
   ────────────────────────────────────────────────────────────────────────── */

/* ── Base: clip the shine, declare the scale transition ─────────────────── */
.cta-lucie,
.product-cta-button,
.pricing-tier-card__cta,
.pricing-enterprise__cta.pricing-cta-button,
.pricing-cta-button,
.lucie-cta,
.consent-button,
.consent-trigger {
  overflow: hidden;
  transition: transform var(--motion-base) var(--easing);
}

/* Story 4.7: `.cta-lucie` is now an <a> (was <button>). Suppress the
   browser-default anchor underline so the filled-button visual treatment
   carries cleanly. Same applies to `.solutions-index-notsure-btn` (the
   /solutions index "not-sure" affordance also flipped to anchor). */
.cta-lucie,
.solutions-index-notsure-btn {
  text-decoration: none;
}

/* Only set position: relative on CTAs that don't already have a positioning
   context. .lucie-cta and .consent-trigger are position:fixed (their own
   surface CSS owns that); leaving them alone keeps them floating. */
.cta-lucie,
.product-cta-button,
.pricing-tier-card__cta,
.pricing-enterprise__cta.pricing-cta-button,
.pricing-cta-button,
.consent-button {
  position: relative;
}

/* ── Shine pseudo-element ───────────────────────────────────────────────── */
.cta-lucie::before,
.product-cta-button::before,
.pricing-tier-card__cta::before,
.pricing-enterprise__cta.pricing-cta-button::before,
.pricing-cta-button::before,
.lucie-cta::before,
.consent-button::before,
.consent-trigger::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(
    120deg,
    transparent 30%,
    rgba(255, 255, 255, 0.35) 50%,
    transparent 70%
  );
  transform: translateX(-100%);
}

/* ── Scale on hover / focus ─────────────────────────────────────────────── */
.cta-lucie:hover,
.cta-lucie:focus-visible,
.product-cta-button:hover,
.product-cta-button:focus-visible,
.pricing-tier-card__cta:hover,
.pricing-tier-card__cta:focus-visible,
.pricing-enterprise__cta.pricing-cta-button:hover,
.pricing-enterprise__cta.pricing-cta-button:focus-visible,
.pricing-cta-button:hover,
.pricing-cta-button:focus-visible,
.lucie-cta:hover,
.lucie-cta:focus-visible,
.consent-button:hover,
.consent-button:focus-visible,
.consent-trigger:hover,
.consent-trigger:focus-visible {
  transform: scale(1.03);
}

/* ── Shine sweep loops while hovered / focused ──────────────────────────── */
.cta-lucie:hover::before,
.cta-lucie:focus-visible::before,
.product-cta-button:hover::before,
.product-cta-button:focus-visible::before,
.pricing-tier-card__cta:hover::before,
.pricing-tier-card__cta:focus-visible::before,
.pricing-enterprise__cta.pricing-cta-button:hover::before,
.pricing-enterprise__cta.pricing-cta-button:focus-visible::before,
.pricing-cta-button:hover::before,
.pricing-cta-button:focus-visible::before,
.lucie-cta:hover::before,
.lucie-cta:focus-visible::before,
.consent-button:hover::before,
.consent-button:focus-visible::before,
.consent-trigger:hover::before,
.consent-trigger:focus-visible::before {
  animation: cta-shine-sweep 1100ms linear infinite;
}

@keyframes cta-shine-sweep {
  from { transform: translateX(-100%); }
  to   { transform: translateX(100%); }
}
}
/* ──────────────────────────────────────────────────────────────────────────
   tokens/anchor-links.css — spec-section-anchor-links.

   Visible "link to this section" affordance injected by
   public/js/anchor-links.js next to every section heading (h2[id], h3[id]).
   Structural-only accent per the locked visual system; the button rests
   invisible and reveals on heading hover / focus-within and on its own
   keyboard focus. The opacity transition runs on --motion-quick, which
   motion-tokens.css collapses to 0ms under prefers-reduced-motion.
   ────────────────────────────────────────────────────────────────────────── */
/* Sticky-header clearance — a directly-opened #fragment must land below the
   sticky header.site, not behind it. :where() keeps specificity at 0 so
   per-surface heading rules are never overridden. */
:where(h2[id], h3[id]) {
  scroll-margin-top: calc(var(--header-height, 5rem) + var(--space-3));
}
.anchor-link {
  margin-inline-start: var(--space-1);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.4em;
  height: 1.4em;
  padding: 0;
  vertical-align: middle;
  border: 0;
  border-radius: 4px;
  background: none;
  color: var(--ink-quiet);
  cursor: pointer;
  opacity: 0;
  transition: opacity var(--motion-quick) var(--motion-easing-base);
}
/* Reveal on heading hover / focus-within, and whenever the button itself
   is keyboard-focused (so it is never stranded invisible during Tab). */
h2[id]:hover .anchor-link,
h3[id]:hover .anchor-link,
h2[id]:focus-within .anchor-link,
h3[id]:focus-within .anchor-link,
.anchor-link:focus-visible,
.anchor-link--copied {
  opacity: 1;
}
.anchor-link:hover {
  color: var(--ink-primary);
}
.anchor-link:focus-visible {
  outline: 2px solid var(--accent-primary);
  outline-offset: 2px;
}
.anchor-link--copied {
  color: var(--accent-primary);
}
.anchor-link__icon {
  width: 1em;
  height: 1em;
}
/* Visually-hidden live region — carries the transient "copied" announcement
   to assistive tech without occupying layout. */
.anchor-live {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}
/* spec-section-anchor-links — visible "link to this section" button on every section heading + sticky-header scroll-margin clearance. */
