/* --- ./foundation/reset.css --- */
*,*::before,*::after{box-sizing:border-box}html{scroll-behavior:smooth}body{margin:0}img,svg,video,canvas{max-width:100%;height:auto}a{color:inherit}button,input,textarea,select{font:inherit}:focus-visible{outline:2px solid var(--focus);outline-offset:3px}


/* --- ./shell/page.css --- */
html {
  -ms-overflow-style: none;
}

/* -----------------------------------------------------------------------------
   VIEW TRANSITIONS - one full-frame crossfade for page navigation and theme
   flips, so gradients, text, buttons, and the background all change at
   EXACTLY the same pace (the old per-property transitions left gradients
   snapping while solids faded - that was the choppy desync).
   -------------------------------------------------------------------------- */
@view-transition { navigation: auto; }
/* Standard browser crossfade (both directions). The one gotcha: the incoming
   page must be fully painted when it is snapshotted, or the crossfade fades to
   blank. On a view-transition navigation we reveal the incoming content
   immediately (see html.vt-nav below); first loads still play the load-in. */
::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: .32s;
  animation-timing-function: ease;
}
.vt-theme::view-transition-old(root),
.vt-theme::view-transition-new(root) {
  animation-duration: .5s;
  animation-timing-function: ease;
}
@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(root),
  ::view-transition-new(root) { animation: none; }
}
/* On a cross-document navigation the crossfade IS the entrance: show the incoming
   page instantly so its snapshot is complete and neither side flashes blank. */
html.vt-nav .site { opacity: 1 !important; transition: none !important; }
html.vt-nav .page-body > section { opacity: 1 !important; transform: none !important; transition: none !important; animation: none !important; }
/* Only the load-in state is neutralised: forcing transform/transition off on the
   element itself also killed the hover magnify on the hero buttons (they carry
   data-pz) for the rest of the visit. Once .pz-in has landed, the element's own
   rules (and :hover) take over again. */
html.vt-nav.js [data-pz] { opacity: 1 !important; animation: none !important; }
html.vt-nav.js [data-pz]:not(.pz-in) { transform: none !important; transition: none !important; }
/* Main window scrollbar: themed + visible (light purple in dark, dark in light),
   no end arrows. */
html::-webkit-scrollbar,
body::-webkit-scrollbar { width: 6px; height: 6px; }
html::-webkit-scrollbar-button,
body::-webkit-scrollbar-button { display: none; width: 0; height: 0; }
html::-webkit-scrollbar-track,
body::-webkit-scrollbar-track { background: transparent; }
html::-webkit-scrollbar-thumb,
body::-webkit-scrollbar-thumb { background: rgba(156, 140, 255, .5); border-radius: 999px; }
html::-webkit-scrollbar-thumb:hover,
body::-webkit-scrollbar-thumb:hover { background: rgba(156, 140, 255, .8); }


body {
  min-height: 100vh;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);        /* base site typeface (Helvetica Neue / Inter) */
  -webkit-font-smoothing: antialiased;
}

.site {
  position: relative;
  min-height: 100vh;
  overflow: hidden;
  background: transparent;   /* see .site-bg (grid + glow field) behind the content */
  color: var(--text);
}

/* No site-level fade: the native @view-transition crossfade is the page
   transition. Section + hero load-ins below still play on first load. */

/* Leaving: a quick fade that actually completes within the ~180ms before
   navigation, so it reads as a clean hand-off instead of a cut-off animation. */
.js.page-leaving .site {
  opacity: 0;
  transition: opacity .42s ease;
}

/* Section entrance -----------------------------------------------------------
   Sections are VISIBLE BY DEFAULT. The first-load entrance is an opt-in,
   run-once animation gated on html.enter (a static class set in <head>). This
   is deliberate: the old code hid every section (opacity:0) until JS flipped
   data-ready, so a cross-document view-transition could snapshot the incoming
   page mid-hide and crossfade to a blank frame - the "new page fades, then the
   content comes back" glitch. With visibility as the default, a snapshot (or a
   no-JS load) can never catch an empty page. On a view-transition navigation
   the pagereveal handler removes .enter (and adds .vt-nav) before the snapshot,
   so the native crossfade is the only entrance. */
@media (prefers-reduced-motion: no-preference) {
  html.enter.js .page-body > section {
    animation: sectionIn .6s ease both;
  }
  html.enter.js .page-body > section:nth-child(2) { animation-delay: .03s; }
  html.enter.js .page-body > section:nth-child(3) { animation-delay: .06s; }
  html.enter.js .page-body > section:nth-child(n+4) { animation-delay: .08s; }
}

@keyframes sectionIn {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}

.js.theme-transition,
.js.theme-transition body,
.js.theme-transition .site,
.js.theme-transition .site-header,
.js.theme-transition .drawer,
.js.theme-transition .scrim,
.js.theme-transition .site-bg,
.js.theme-transition .site-bg-grid,
.js.theme-transition .site-bg-glow,
.js.theme-transition .panel,
.js.theme-transition .cta-shine,
.js.theme-transition .btn,
.js.theme-transition .res-bar,
.js.theme-transition .ap-row,
.js.theme-transition .tm-card,
.js.theme-transition .tm-over,
.js.theme-transition .legal,
.js.theme-transition .glow {
  transition-duration: .32s !important;
  transition-timing-function: ease !important;
}

.js.theme-transition *,
.js.theme-transition *::before,
.js.theme-transition *::after {
  /* Recolor-only: transitioning filter/opacity/transform on every element made
     the theme flip stutter. Just the colour-bearing properties, and quick. */
  transition-property: background, background-color, border-color, box-shadow, color, fill, stroke !important;
  transition-duration: .32s !important;
  transition-timing-function: ease !important;
}

/* The blanket recolor above omits `transform`, which would freeze the theme
   toggle's sun/moon mid-swap. Let the icon keep its own springy spin timing
   (matches the .ti rule in frame.css) so it rotates in as the page recolors. */
.js.theme-transition .ti,
.js.theme-transition .ti svg {
  transition-property: transform, opacity !important;
  transition-duration: .42s !important;
  transition-timing-function: cubic-bezier(.5, 1.4, .4, 1) !important;
}

.js .site[data-ready="true"] .theme-btn .ti {
  animation: themeLoadSpin .72s cubic-bezier(.22, .8, .22, 1) both;
}

@keyframes themeLoadSpin {
  from { transform: rotate(-180deg) scale(.86); opacity: .55; }
  to { transform: rotate(0deg) scale(1); opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .js .site {
    opacity: 1;
    transform: none;
    transition: none;
  }
  .js.page-leaving .site {
    opacity: 1;
    transform: none;
  }
  .js .page-body > section {
    opacity: 1;
    transform: none;
    transition: none;
  }
  .js.theme-transition *,
  .js.theme-transition *::before,
  .js.theme-transition *::after {
    transition: none !important;
  }
  .js .site[data-ready="true"] .theme-btn .ti {
    animation: none;
  }
}

.page-body {
  position: relative;
  z-index: 1;
}

.site-bg {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  /* Ambient colour across the WHOLE viewport, not just the top corners -
     glass panels need something behind them to frost, or they read as
     opaque slabs. Clouds at mid and lower positions give every pane a
     visible bloom through its backdrop blur. */
  background:
    radial-gradient(circle at 12% 12%, var(--cloud-1), transparent 34rem),
    radial-gradient(circle at 86% 8%, var(--cloud-2), transparent 28rem),
    radial-gradient(circle at 78% 46%, var(--cloud-2), transparent 30rem),
    radial-gradient(circle at 12% 70%, var(--cloud-3), transparent 32rem),
    radial-gradient(circle at 55% 92%, var(--cloud-2), transparent 28rem),
    linear-gradient(180deg, var(--bg), var(--bg-2) 48%, var(--elev) 100%);
}

.site-bg-grid {
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(var(--grid) 1px, transparent 1px),
    linear-gradient(90deg, var(--grid) 1px, transparent 1px);
  /* 62px cells, NO fade mask - exactly the live site. The old bottom-fade mask
     erased the grid behind every panel in the lower half of the viewport, so
     their backdrop blur had nothing to frost and the glass read as opaque. */
  background-size: 62px 62px;
  opacity: var(--grid-op);
}

.site-bg-glow {
  position: absolute;
  inset: auto -10% 0 -10%;
  height: 44vh;
  background: linear-gradient(90deg, var(--cloud-2), var(--cloud-3));
  filter: blur(40px);
}

/* -----------------------------------------------------------------------------
   THEMED SCROLLBARS  (webkit-only so it stays a clean custom bar with no arrows)
   Thumb is light purple in dark mode and dark indigo in light mode, driven by
   the theme tokens. Add the class to any scroll area: <div class="themed-scroll">.
   Optional widths: .scroll-thin (8px) | .scroll-wide (12px).
   -------------------------------------------------------------------------- */
.themed-scroll::-webkit-scrollbar { width: 6px; height: 6px; }
.themed-scroll::-webkit-scrollbar-button { display: none; width: 0; height: 0; }
.themed-scroll::-webkit-scrollbar-track { background: transparent; box-shadow: none; }
.themed-scroll::-webkit-scrollbar-corner { background: transparent; }
.themed-scroll::-webkit-scrollbar-thumb {
  background: var(--indigo-lift);
  border-radius: 999px;
  box-shadow: none;
}
.themed-scroll::-webkit-scrollbar-thumb:hover { background: var(--indigo-bright); background-clip: content-box; }
[data-theme="light"] .themed-scroll::-webkit-scrollbar-thumb { background: var(--indigo); }
[data-theme="light"] .themed-scroll::-webkit-scrollbar-thumb:hover { background: var(--indigo-bright); }
.themed-scroll.scroll-thin::-webkit-scrollbar { width: 8px; height: 8px; }
.themed-scroll.scroll-wide::-webkit-scrollbar { width: 12px; height: 12px; }


/* Skip-to-content link: visually hidden until keyboard focus (WCAG bypass block). */
.skip-link {
  position: fixed;
  top: 10px; left: 10px;
  z-index: 1000;
  padding: 10px 16px;
  border-radius: 8px;
  background: var(--indigo);
  color: #fff;
  font: 600 14px/1 var(--font-sans);
  text-decoration: none;
  transform: translateY(-150%);
  opacity: 0;
  transition: transform .18s ease, opacity .18s ease;
}
.skip-link:focus,
.skip-link:focus-visible {
  transform: translateY(0);
  opacity: 1;
  outline: 2px solid var(--focus);
  outline-offset: 3px;
}


/* --- ./foundation/tokens.css --- */
/* =============================================================================
   SmartSettle AI - Global Design Tokens
   -----------------------------------------------------------------------------
   THE single source of truth for the whole site's colour, type, spacing, motion
   and layout values. Edit a value here once and it updates everywhere.

   • Colours are defined twice: dark defaults on `:root, [data-theme="dark"]`,
     then overridden for `[data-theme="light"]`. The theme toggle flips
     `data-theme` on <html> and #ssSite (see scripts/site.js).
   • Values below are the authored global defaults. Keep component files consuming
     these tokens instead of creating local one-off values.
   • Consume tokens with var(--name). Never hard-code a colour in a component.
   ========================================================================== */

/* -----------------------------------------------------------------------------
   1. Theme-independent foundation (same in light & dark)
   Also scoped to [data-theme] so toggling the theme keeps layout constants stable
   on the themed #ssSite wrapper.
   -------------------------------------------------------------------------- */
:root, [data-theme] {
  /* Type families ---------------------------------------------------------- */
  --font-sans: 'Helvetica Neue', Helvetica, 'Inter', Arial, sans-serif;
  --font-mono: 'IBM Plex Mono', ui-monospace, monospace;

  /* Type scale (fluid) - real values in use across the site ----------------- */
  --fs-eyebrow:   18px;                       /* mono uppercase kicker label     */
  --fs-tag:       11px;                        /* smaller mono tag (ds-tag)       */
  --fs-small:     16px;                        /* small-t / captions / panel body */
  --fs-body:      19px;                         /* default body copy               */
  --fs-lead:      clamp(18px, 2vw, 21px);      /* hero subheads / section intros  */
  --fs-h4:        21px;                          /* card / panel heading            */
  --fs-h3:        25px;                          /* subsection heading              */
  --fs-sec-title: clamp(28px, 3.1vw, 40px);    /* section title (sec-head)        */
  --fs-h2:        clamp(33px, 4.4vw, 54px);    /* major section heading           */
  --fs-h1:        clamp(46px, 6vw, 78px);      /* page title / hero headline      */
  --fs-display:   clamp(44px, 7.6vw, 104px);   /* oversized hero display          */

  --lh-tight: 1.05;
  --lh-heading: 1.15;
  --lh-body: 1.6;

  /* Spacing scale (8px base) ----------------------------------------------- */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --space-7: 48px;
  --space-8: 64px;

  /* Layout metrics --------------------------------------------------------- */
  --header-h: 92px;                          /* fixed header height (taller)   */
  --section-pad: clamp(48px, 6vw, 76px);     /* vertical section rhythm        */
  --group-gap: clamp(40px, 5vw, 60px);       /* space above a group heading    */
  --group-gap-below: 18px;                   /* space between group heading and its items */
  /* Page side gutter. Fluid: holds the wide 140px margins on desktop (where the
     content is already capped at --container) and compresses smoothly to a small
     margin on tablet/phone so nothing gets crushed into a thin column. */
  --gutter: clamp(24px, 11vw, 140px);        /* body / footer side gutter        */
  --gutter-header: clamp(18px, 6vw, 104px);  /* header runs a touch wider so the long nav has room */
  --container: 1300px;                       /* max content width              */
  --section: clamp(56px, 8vw, 104px);        /* legacy section padding token   */

  /* Radius ----------------------------------------------------------------- */
  --radius-sm: 8px;
  --radius-md: 12px;
  --radius-lg: 20px;
  --radius-pill: 999px;
  --radius: 8px;                             /* legacy alias                    */

  /* Elevation / motion ----------------------------------------------------- */
  --ease-out: cubic-bezier(.2, .7, .2, 1);
  --ease-smooth: cubic-bezier(.3, .85, .3, 1);
  --ease-reveal: cubic-bezier(.16, .78, .18, 1);
  --dur-fast: .18s;
  --dur-base: .3s;
  --dur-slow: .6s;
  --motion-window: .95s var(--ease-reveal);
  --motion-hover: .95s var(--ease-reveal);
  --motion-sheen: .9s cubic-bezier(.3, .7, .25, 1);
  --window-hover-transform: scale(1.025);
  --window-hover-shadow: inset 0 1px 0 rgba(255,255,255,.35), inset 0 0 0 1px rgba(255,255,255,.05), var(--panel-glow);

  /* Z-index scale ---------------------------------------------------------- */
  --z-bg: 0;
  --z-body: 1;
  --z-rail: 10;
  --z-header: 100000;
  --z-scrim: 50;
  --z-drawer: 60;

  /* Breakpoints (reference - for JS / container queries; @media can't read
     custom properties). Standard set the rebuild migrates toward.           */
  --bp-sm: 640px;
  --bp-md: 768px;
  --bp-lg: 1024px;
  --bp-xl: 1200px;

  /* Focus ring (used by reset.css) ---------------------------------------- */
  --focus: #8db7ff;
}

/* -----------------------------------------------------------------------------
   2. Colour tokens - DARK (default)
   -------------------------------------------------------------------------- */
:root,
[data-theme="dark"] {
  color-scheme: dark;

  /* Surfaces / backgrounds */
  --bg:        #07060B;
  --bg-2:      #0B0913;
  --elev:      #100E18;
  --panel:     rgba(255,255,255,.045);
  --panel-2:   rgba(255,255,255,.07);
  --hover:     rgba(255,255,255,.08);
  /* Lighter white veil than the old .085 - panes read as glass, not slabs. */
  --glass:     linear-gradient(160deg, rgba(140,124,255,.06), rgba(255,255,255,.015));   /* subtle glass tint (window texture, not milky) */
  --glass-hi:  rgba(255,255,255,.16);
  --glass-sheen: rgba(255,255,255,.22);

  /* Brand indigo.
     --indigo is a FILL colour: button backgrounds, bars, gradient stops. It is
     declared once here and is deliberately the same value in both themes, which
     is why it must never be used as a text colour on a dark surface: #5333EC on
     --bg #07060B measures 2.94:1, below the 4.5:1 floor for body text and below
     even the 3:1 floor for large text.
     For text, use --indigo-lift, which has a real pair: #9C8CFF on dark (7.32:1)
     and #6B53F0 on light (4.65:1). */
  --indigo:        #5333EC;
  --indigo-2:      #6A4DF5;
  --indigo-lift:   #9C8CFF;
  --indigo-bright: #7C60FF;
  --eyebrow:       #9C8CFF;   /* eyebrow label - lighter purple, readable on dark */
  --signal:        #9C8CFF;
  --grad-mid:      #9C8CFF;
  --grad-hi:       #D2C6FF;
  --icon-hover:    #7C60FF;
  --icon-rest:     #CCC7D6;
  --on-accent:     #FFFFFF;

  /* Text */
  --text:  #F4F2F8;
  --muted: #B4AFC0;
  --dim:   #8B8797;

  /* Borders / lines */
  --brd:        rgba(255,255,255,.10);
  --brd-strong: rgba(255,255,255,.18);
  --ring-pulse-glow: rgba(150,132,255,1);
  --brd-hover:  rgba(138,120,255,.6);
  --line:       rgba(255,255,255,.10);

  /* Chrome */
  --header-bg: rgba(8,7,13,.62);
  --footer-bg: #0B0913;
  --mon-frame: #FFFFFF;   /* product-monitor bezel - white pops on the dark page */

  /* Background field: grid + glow clouds + spotlight */
  --grid:      rgba(255,255,255,.5);
  --grid-op:   .07;
  --grid-lit:  rgba(156,140,255,.5);
  --cloud-1:   rgba(118,96,255,.26);
  --cloud-2:   rgba(91,69,240,.18);
  --cloud-3:   rgba(91,69,240,.12);
  --panel-spot: rgba(156,140,255,.22);
  --glow-blend: screen;

  /* Shadows / glows */
  --shadow:     0 30px 80px rgba(0,0,0,.5);
  --panel-glow: 0 20px 50px rgba(91,69,240,.28);
  --glow-2:     rgba(91,69,240,.5);          /* indigo glow behind primary buttons / CTAs */

  /* Status */
  --ok:        #34D399;  --ok-bg:     rgba(52,211,153,.13);
  --warn:      #FBBF55;  --warn-bg:   rgba(251,191,85,.13);
  --danger:    #FB7185;  --danger-bg: rgba(251,113,133,.13);
  --info-bg:   rgba(156,140,255,.14);

  /* Form fields - whiter lift on hover / once filled */
  --field-glow-brd: rgba(255,255,255,.40);
  --field-glow:     rgba(255,255,255,.12);
}

/* -----------------------------------------------------------------------------
   3. Colour tokens - LIGHT (overrides)
   -------------------------------------------------------------------------- */
[data-theme="light"] {
  color-scheme: light;

  --bg:        #F3F3F7;
  --bg-2:      #EAEAF1;
  --elev:      #FFFFFF;
  --panel:     rgba(255,255,255,.55);
  --panel-2:   rgba(255,255,255,.7);
  --hover:     rgba(83,51,236,.08);
  --glass:     linear-gradient(160deg, rgba(83,51,236,.05), rgba(255,255,255,.42));   /* subtle glass tint */
  --glass-hi:  rgba(255,255,255,.9);
  --glass-sheen: rgba(83,51,236,.18);

  --indigo-2:      #5B45F0;
  /* Was #6B53F0, a lighter purple that existed only because every token was
     given a value for both themes. On a light background the brand purple is
     perfectly legible (6.22:1) and needs no lightening, so this pair is now
     brand purple on light and the lifted purple on dark. That makes it match
     --eyebrow exactly, which is the pair that was already correct, and stops
     purple text rendering lighter than the eyebrow sitting right above it. */
  --indigo-lift:   #5333EC;
  --indigo-bright: #5333EC;
  --focus:         #5333EC;
  --eyebrow:       #5333EC;   /* eyebrow label - brand purple on light */
  --signal:        #5333EC;
  --grad-mid:      #5333EC;
  --grad-hi:       #7A63F5;
  --icon-hover:    #5333EC;
  --icon-rest:     #54515D;

  --text:  #16151C;
  --muted: #37343F;   /* darker than before for readable body text on light */
  --dim:   #625E6B;

  --brd:        rgba(22,21,28,.10);
  --brd-strong: rgba(22,21,28,.16);
  --ring-pulse-glow: rgba(91,69,240,.85);
  --brd-hover:  rgba(83,51,236,.5);
  --line:       rgba(22,21,28,.10);

  --header-bg: rgba(243,243,247,.66);
  --footer-bg: #F3F3F7;   /* matches the header's near-white, not the grayer --bg-2 */
  --mon-frame: #16151C;   /* product-monitor bezel - near-black pops on the light page */

  --grid:      rgba(22,21,28,.5);
  --grid-op:   .07;
  --grid-lit:  rgba(83,51,236,.32);
  --cloud-1:   rgba(91,69,240,.14);
  --cloud-2:   rgba(91,69,240,.08);
  --cloud-3:   rgba(91,69,240,.05);
  --panel-spot: rgba(83,51,236,.10);
  --glow-blend: normal;

  --shadow:     0 24px 60px rgba(40,30,90,.14);
  --panel-glow: 0 22px 46px rgba(83,51,236,.16);
  --glow-2:     rgba(83,51,236,.32);         /* indigo glow behind primary buttons / CTAs */

  --ok:        #0E9C6E;  --ok-bg:     rgba(14,156,110,.10);
  --warn:      #B8791A;  --warn-bg:   rgba(184,121,26,.12);
  --danger:    #D8455C;  --danger-bg: rgba(216,69,92,.10);
  --info-bg:   rgba(83,51,236,.08);

  /* Form fields - indigo lift on hover / once filled. Strong enough to
     actually register on the white light-mode panels (the old near-black
     .26 border + .08 glow read as "hover does nothing"). */
  --field-glow-brd: rgba(83,51,236,.55);
  --field-glow:     rgba(83,51,236,.18);
}


/* --- ./foundation/fonts.css --- */
/* =============================================================================
   SmartSettle AI - Self-hosted web fonts
   -----------------------------------------------------------------------------
   @font-face declarations for IBM Plex Mono (--font-mono) and Inter (the web
   fallback inside --font-sans). Files live in src/fonts/ and are copied
   into public/ by the build, so paths are relative from styles/foundation/.
   Mirrors the live Style Guide exactly.
   ========================================================================== */
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: block;
  src: url("/fonts/f8c22ec1804bd696.woff2") format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: block;
  src: url("/fonts/7635422bd10ddbbc.woff2") format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* vietnamese */
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: block;
  src: url("/fonts/62632b6375305e70.woff2") format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: block;
  src: url("/fonts/6bc0f226a5b7884a.woff2") format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: block;
  src: url("/fonts/08949f728dc52d52.woff2") format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: block;
  src: url("/fonts/3febe5c7f22e4b07.woff2") format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: block;
  src: url("/fonts/1d89462e86cb8e87.woff2") format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* vietnamese */
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: block;
  src: url("/fonts/781633d95de88040.woff2") format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: block;
  src: url("/fonts/6bb06407c97584b0.woff2") format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: block;
  src: url("/fonts/01d285447409c8a5.woff2") format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 600;
  font-display: block;
  src: url("/fonts/83109cdd4f8665b4.woff2") format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 600;
  font-display: block;
  src: url("/fonts/2b05a8695c7f9f4a.woff2") format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* vietnamese */
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 600;
  font-display: block;
  src: url("/fonts/51b74d53e106ba8a.woff2") format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 600;
  font-display: block;
  src: url("/fonts/32057cf50dd14bdb.woff2") format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 600;
  font-display: block;
  src: url("/fonts/0d1f0b8d0722224e.woff2") format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400;
  font-display: block;
  src: url("/fonts/ca157063339ac4ad.woff2") format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400;
  font-display: block;
  src: url("/fonts/71d5ee93cc1e9f1d.woff2") format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400;
  font-display: block;
  src: url("/fonts/6e9e020a25f9b56d.woff2") format('woff2');
  unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400;
  font-display: block;
  src: url("/fonts/1be3448e292fbf05.woff2") format('woff2');
  unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
}
/* vietnamese */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400;
  font-display: block;
  src: url("/fonts/5c66f9e07e90c6d4.woff2") format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400;
  font-display: block;
  src: url("/fonts/34b9c504cab7a73e.woff2") format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400;
  font-display: block;
  src: url("/fonts/3100e775e8616cd2.woff2") format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 500;
  font-display: block;
  src: url("/fonts/ca157063339ac4ad.woff2") format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 500;
  font-display: block;
  src: url("/fonts/71d5ee93cc1e9f1d.woff2") format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 500;
  font-display: block;
  src: url("/fonts/6e9e020a25f9b56d.woff2") format('woff2');
  unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 500;
  font-display: block;
  src: url("/fonts/1be3448e292fbf05.woff2") format('woff2');
  unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
}
/* vietnamese */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 500;
  font-display: block;
  src: url("/fonts/5c66f9e07e90c6d4.woff2") format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 500;
  font-display: block;
  src: url("/fonts/34b9c504cab7a73e.woff2") format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 500;
  font-display: block;
  src: url("/fonts/3100e775e8616cd2.woff2") format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 600;
  font-display: block;
  src: url("/fonts/ca157063339ac4ad.woff2") format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 600;
  font-display: block;
  src: url("/fonts/71d5ee93cc1e9f1d.woff2") format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 600;
  font-display: block;
  src: url("/fonts/6e9e020a25f9b56d.woff2") format('woff2');
  unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 600;
  font-display: block;
  src: url("/fonts/1be3448e292fbf05.woff2") format('woff2');
  unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
}
/* vietnamese */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 600;
  font-display: block;
  src: url("/fonts/5c66f9e07e90c6d4.woff2") format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 600;
  font-display: block;
  src: url("/fonts/34b9c504cab7a73e.woff2") format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 600;
  font-display: block;
  src: url("/fonts/3100e775e8616cd2.woff2") format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 700;
  font-display: block;
  src: url("/fonts/ca157063339ac4ad.woff2") format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 700;
  font-display: block;
  src: url("/fonts/71d5ee93cc1e9f1d.woff2") format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 700;
  font-display: block;
  src: url("/fonts/6e9e020a25f9b56d.woff2") format('woff2');
  unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 700;
  font-display: block;
  src: url("/fonts/1be3448e292fbf05.woff2") format('woff2');
  unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
}
/* vietnamese */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 700;
  font-display: block;
  src: url("/fonts/5c66f9e07e90c6d4.woff2") format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 700;
  font-display: block;
  src: url("/fonts/34b9c504cab7a73e.woff2") format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 700;
  font-display: block;
  src: url("/fonts/3100e775e8616cd2.woff2") format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 800;
  font-display: block;
  src: url("/fonts/ca157063339ac4ad.woff2") format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 800;
  font-display: block;
  src: url("/fonts/71d5ee93cc1e9f1d.woff2") format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 800;
  font-display: block;
  src: url("/fonts/6e9e020a25f9b56d.woff2") format('woff2');
  unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 800;
  font-display: block;
  src: url("/fonts/1be3448e292fbf05.woff2") format('woff2');
  unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
}
/* vietnamese */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 800;
  font-display: block;
  src: url("/fonts/5c66f9e07e90c6d4.woff2") format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 800;
  font-display: block;
  src: url("/fonts/34b9c504cab7a73e.woff2") format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 800;
  font-display: block;
  src: url("/fonts/3100e775e8616cd2.woff2") format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 900;
  font-display: block;
  src: url("/fonts/ca157063339ac4ad.woff2") format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 900;
  font-display: block;
  src: url("/fonts/71d5ee93cc1e9f1d.woff2") format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 900;
  font-display: block;
  src: url("/fonts/6e9e020a25f9b56d.woff2") format('woff2');
  unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 900;
  font-display: block;
  src: url("/fonts/1be3448e292fbf05.woff2") format('woff2');
  unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
}
/* vietnamese */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 900;
  font-display: block;
  src: url("/fonts/5c66f9e07e90c6d4.woff2") format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 900;
  font-display: block;
  src: url("/fonts/34b9c504cab7a73e.woff2") format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 900;
  font-display: block;
  src: url("/fonts/3100e775e8616cd2.woff2") format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}


/* --- ./foundation/typography.css --- */
/* =============================================================================
   SmartSettle AI - Typography
   -----------------------------------------------------------------------------
   Every text style on the site, documented. Values come from the live Style
   Guide (resources/smartsettle-base) so these render exactly as they do today.
   Sizes are driven by the type-scale tokens in tokens.css - edit a size once
   there and it flows through here.

   HOW TO USE: put the class on any element, e.g. <h2 class="h2">…</h2>,
   <div class="eyebrow">…</div>, <p class="lead">…</p>.
   ========================================================================== */

/* -----------------------------------------------------------------------------
   EYEBROW - small mono uppercase kicker that sits ABOVE a heading.
   Used to label a section ("ABOUT US", "OUR MISSION"). Indigo, wide tracking.
   -------------------------------------------------------------------------- */
.eyebrow {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--fs-eyebrow);
  font-weight: 700;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--eyebrow);            /* brand purple on light, lighter purple on dark */
  margin: 0 0 16px;                 /* breathing room before the heading */
}

/* -----------------------------------------------------------------------------
   HEADINGS - display hierarchy. H1 = page title / hero headline; H2 = major
   section heading; H3 = subsection; H4 = card / panel heading.
   -------------------------------------------------------------------------- */
.h1 {
  font-weight: 800;
  font-size: var(--fs-h1);
  line-height: 1.0;
  letter-spacing: -.035em;
  color: var(--text);
  margin: 0;
}
.h2 {
  font-weight: 800;
  font-size: var(--fs-h2);
  line-height: 1.03;
  letter-spacing: -.03em;
  color: var(--text);
  margin: 0;
}
.h3 {
  font-weight: 700;
  font-size: var(--fs-h3);
  line-height: 1.18;
  letter-spacing: -.02em;
  color: var(--text);
  margin: 0;
}
.h4 {
  font-weight: 700;
  font-size: var(--fs-h4);
  line-height: 1.3;
  letter-spacing: -.01em;
  color: var(--text);
  margin: 0;
}

/* -----------------------------------------------------------------------------
   SECTION HEAD - wrapper (.sec-head) + its title (.sec-title) + intro
   (.sec-intro). Use at the top of a content section; add .center to centre it.
   -------------------------------------------------------------------------- */
.sec-head { max-width: 940px; margin-bottom: 44px; }
.sec-head:only-child { margin-bottom: 0; }
.sec-head.center { margin-left: auto; margin-right: auto; text-align: center; }
.sec-title {
  font-weight: 800;
  font-size: var(--fs-sec-title);
  line-height: 1.1;
  letter-spacing: -.02em;
  color: var(--text);
  margin: 14px 0 0;
  text-wrap: balance;
}
.sec-intro {
  margin-top: 16px;
  font-size: clamp(20px, 2.1vw, 23px);
  line-height: 1.62;
  color: var(--muted);
  max-width: 760px;
}
.sec-head.center .sec-intro { margin-left: auto; margin-right: auto; }
/* Sub-text (lead) below a heading gets a clear, generous gap. */
.sec-head .lead { margin-top: 30px; }
/* Inline mono caption row - e.g. "● Featured · June 2026" above a card title.
   Pairs with .live-dot for the pulsing status marker. */
.sec-caption {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--muted);
}

/* -----------------------------------------------------------------------------
   BODY COPY
   .lead   - hero subheads & section intros: larger, lighter, easy entry.
   .body-t - the workhorse paragraph style.
   .small-t- captions, small print, panel body text.
   -------------------------------------------------------------------------- */
.lead {
  font-size: var(--fs-lead);
  line-height: 1.6;
  color: var(--muted);
  margin: 0;
  font-weight: 400;
}
.body-t {
  font-size: var(--fs-body);
  line-height: 1.74;
  color: var(--muted);
  margin: 0;
}
.small-t {
  font-size: var(--fs-small);
  line-height: 1.7;
  color: var(--muted);
  margin: 0;
}

/* -----------------------------------------------------------------------------
   MONO LABELS - uppercase micro-labels.
   .data-label - in-body data/section marker (slightly larger, full contrast).
   -------------------------------------------------------------------------- */
.data-label {
  font-family: var(--font-mono);
  font-size: 13px;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--text);
}

/* -----------------------------------------------------------------------------
   TEXT GRADIENT - animated indigo sweep across headline text or a stat number.
   Add .text-grad alongside .h1 / .stat-num for the shimmering accent.
   -------------------------------------------------------------------------- */
.text-grad {
  background: linear-gradient(90deg,
    var(--text) 0%, var(--text) 19%, var(--grad-mid) 25%, var(--text) 31%,
    var(--text) 69%, var(--grad-mid) 75%, var(--text) 81%, var(--text) 100%);
  background-size: 200% 100%;
  background-repeat: repeat;
  will-change: auto;
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  animation: gradFlow 13s linear infinite;   /* slow indigo sweep across the text */
  /* Extend the clipped box so descenders (g, y, p) aren't cut off. */
  padding-bottom: 0.16em;
}
@media (prefers-reduced-motion: reduce) { .text-grad { animation: none; } }

/* -----------------------------------------------------------------------------
   INLINE LINK - indigo text link with an underline that wipes in on hover.
   -------------------------------------------------------------------------- */
.link-i {
  position: relative;
  color: var(--indigo-lift);
  text-decoration: none;
  font-weight: 600;
  background-image: linear-gradient(currentColor, currentColor);
  background-position: 0 100%;
  background-repeat: no-repeat;
  background-size: 0 1px;
  transition: background-size .24s cubic-bezier(.2, .8, .2, 1), color .18s ease;
}
.link-i::after {
  content: none;
}
.link-i:hover { background-size: 100% 1px; }

/* -----------------------------------------------------------------------------
   PROSE - rich text blocks. Paragraphs + bulleted lists with indigo dash
   markers centred to the first line. Wrap body content in <div class="prose">.
   -------------------------------------------------------------------------- */
.prose p { font-size: var(--fs-body); line-height: 1.74; color: var(--muted); margin: 0 0 16px; }
.prose p:last-child { margin-bottom: 0; }
.prose strong { color: var(--text); font-weight: 700; }
/* Bullet lists (.prose ul / li) live in components/bullets.css - the reusable
   bullet system (plain bullets + feature rows). Edit them there. */


/* --- ./components/controls.css --- */
/* =============================================================================
   Components - Buttons, Chips & Tags
   ========================================================================== */

/* -----------------------------------------------------------------------------
   BUTTON - pill-shaped action. Base .btn + a variant:
     .btn-primary   solid indigo (main call to action)
     .btn-secondary outlined / subtle
     .btn-ghost     text-style with an arrow (.arr) that nudges on hover
     .btn-sm        smaller size
   Lifts slightly on hover (shared with the .magnify helper). Text-heavy
   controls do not scale, because transform-scaling text can look blurry while
   the browser composites it.
   -------------------------------------------------------------------------- */
.btn {
  position: relative;
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  cursor: pointer;
  border-radius: 999px;
  padding: 15px 24px 13px;
  font-family: inherit; font-size: 14px; font-weight: 700; line-height: 1;
  border: 1px solid transparent; text-decoration: none; white-space: nowrap;
  isolation: isolate; overflow: hidden;
  transition: transform var(--motion-window), box-shadow .34s ease, background .34s ease, border-color .34s ease, color .24s ease;
  --btn-sheen-soft: rgba(255,255,255,.12);
  --btn-sheen-core: rgba(255,255,255,.28);
}
.magnify, .btn {
  transition: transform var(--motion-window), box-shadow .34s ease, background .34s ease, border-color .34s ease, color .24s ease;
}
.magnify:hover, .btn:hover { transform: var(--window-hover-transform); }
.btn:active { transform: translateY(0); }
.btn:focus-visible { outline: 2px solid var(--indigo-lift); outline-offset: 2px; }

/* Variant fills (dark defaults; light overrides live further down).
     .btn-primary   solid brand indigo with an indigo glow
     .btn-secondary translucent glass with a visible border */
.btn-primary {
  color: var(--on-accent);
  background: var(--indigo);
  box-shadow: 0 4px 18px -6px var(--glow-2);
}
.btn-primary:hover {
  background: var(--indigo-2);
  box-shadow: 0 10px 26px -6px var(--glow-2);
}
.btn-secondary {
  color: var(--text);
  background: var(--glass);
  border-color: var(--brd-strong);
}
.btn-secondary:hover { border-color: var(--brd-hover); }

.btn-primary::after,
.btn-secondary::after {
  content: "";
  position: absolute;
  top: -40%;
  bottom: -40%;
  left: -56%;
  width: 30%;
  border-radius: inherit;
  pointer-events: none;
  z-index: 2;
  background:
    radial-gradient(ellipse at center, var(--btn-sheen-core) 0%, var(--btn-sheen-soft) 34%, transparent 68%),
    linear-gradient(115deg, transparent 0%, transparent 30%, var(--btn-sheen-soft) 46%, var(--btn-sheen-core) 50%, var(--btn-sheen-soft) 54%, transparent 70%, transparent 100%);
  filter: blur(4px);
  transform: translate3d(0, 0, 0) skewX(-14deg);
  opacity: 0;
  transition: transform .62s cubic-bezier(.4,.8,.3,1), opacity .28s ease;
}
.btn-primary:hover::after,
.btn-secondary:hover::after {
  transform: translate3d(540%, 0, 0) skewX(-14deg);
  opacity: .72;
}
.btn:disabled,
.btn.is-disabled {
  cursor: not-allowed;
  opacity: .48;
  transform: none;
  box-shadow: none;
  pointer-events: none;
}

/* Icon buttons are chromeless - no border/fill/sheen. They behave like the
   header .icon-link: muted at rest, magnify and turn accent-purple on hover,
   whatever variant class they also carry (.btn-secondary / .btn-ghost). */
.btn-icon {
  width: 38px;
  height: 38px;
  padding: 0;
  border-radius: var(--radius-pill);
  background: transparent;
  border-color: transparent;
  color: var(--muted);
  box-shadow: none;
}
.btn-icon::after { content: none; }        /* suppress the variant sheen sweep */
.btn-icon svg { width: 17px; height: 17px; }
.btn-icon:hover {
  background: transparent;
  border-color: transparent;
  color: var(--icon-hover);
  transform: scale(1.18);
  box-shadow: none;
}
.btn-icon:active { transform: scale(1.06); }

@keyframes arrowNudge {
  0% { transform: translateX(0); }
  50% { transform: translateX(4px); }
  100% { transform: translateX(0); }
}
.btn-ghost .arr { width: 16px; height: 16px; transition: transform var(--motion-window); }


/* Size & padding variants - authored AFTER the base .btn so they win. (The base
   .btn is imported after the V3 dump, which would otherwise override these and
   leave the header's small "Request Demo" button at full size.)
     .btn-sm    → the compact header button
     .btn-ghost → text-style button padding */
.btn-sm { padding: 9px 16px; font-size: 13px; }
.btn-ghost { color: var(--muted); padding: 13px 10px; }
.btn-ghost:hover { color: var(--text); }

[data-theme="light"] .btn-secondary {
  background: var(--glass);
  border-color: color-mix(in srgb, var(--indigo) 28%, var(--line));
  color: var(--text);
}
[data-theme="light"] .btn-secondary {
  --btn-sheen-soft: rgba(83,51,236,.18);
  --btn-sheen-core: rgba(83,51,236,.4);
}
[data-theme="light"] .btn-primary {
  --btn-sheen-soft: rgba(255,255,255,.12);
  --btn-sheen-core: rgba(255,255,255,.32);
}
[data-theme="light"] .btn-secondary:hover {
  background: color-mix(in srgb, var(--indigo) 12%, transparent);
  border-color: color-mix(in srgb, var(--indigo) 42%, var(--line));
}
[data-theme="light"] .btn-ghost {
  color: var(--indigo);
  border-color: transparent;
  background: transparent;
}
[data-theme="light"] .btn-ghost:hover {
  color: var(--indigo-2);
  background: transparent;
}

/* Icon buttons stay chromeless in EVERY theme - theme-scoped so they beat the
   light-theme .btn-secondary border/fill overrides above (equal specificity,
   declared later). They read like the header .icon-link: muted → purple+magnify. */
[data-theme] .btn-icon {
  background: transparent;
  border-color: transparent;
  box-shadow: none;
  color: var(--muted);
}
[data-theme] .btn-icon:hover {
  background: transparent;
  border-color: transparent;
  box-shadow: none;
  color: var(--icon-hover);
  transform: scale(1.18);
}

/* Segmented control - compact two/three-option picker used for review engines
   and small mode switches. Inactive choices are plain muted text; active choices
   use the normal button variants so they feel like the rest of the site. */
.seg {
  display: inline-grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  align-items: center;
  gap: 4px;
  padding: 3px;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: transparent;
}
.seg .btn {
  min-height: 26px;
  padding: 5px 9px;
  font-size: 12px;
  border: 0;
  box-shadow: none;
}
.seg .btn:not(.active) {
  background: transparent;
  color: var(--dim);
  font-weight: 650;
}
.seg .btn:not(.active):hover {
  color: var(--text);
  background: transparent;
}
.seg .btn:not(.active),
.seg .btn:not(.active):hover,
.seg .btn:not(.active):active {
  transform: none;
  box-shadow: none;
}

.drawer .btn { margin-top: 20px; justify-content: center; }

/* Mobile hamburger - chromeless (no border/box), just the bars; magnifies and
   turns purple on hover like the other header icon buttons. The bars morph to
   an X when the drawer is open. */
.menu-toggle {
  border: 0;
  background: transparent;
  color: var(--muted);
  transition: transform .28s var(--ease-out), color .24s ease;
}
.menu-toggle span {
  background: currentColor;
  transform-origin: center;
  /* snappy morph to the X */
  transition: transform .35s cubic-bezier(.5, 1.3, .4, 1), opacity .25s ease, background .24s ease;
}
.menu-toggle:hover { color: var(--icon-hover); transform: scale(1.12); }

/* Header icon buttons (theme toggle, etc.) - magnify on hover; they already
   turn purple via .icon-link:hover in the base styles.
   ONE scale, no bounce: the V3 dump also scales the button's INNER element
   (.icon-link:hover > * { scale(1.2) }) on a different clock with an overshoot
   bezier, which made the icon grow and then visibly shift as the two animations
   settled. Neutralise the inner scale and ease the outer one smoothly. */
.icon-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
  transition: transform var(--motion-window), color .24s ease, filter .24s ease;
  will-change: auto;
}
.icon-link:hover { transform: scale(1.18); color: var(--icon-hover); }
.icon-link:hover > * { transform: none; }

/* Mobile drawer - tighten spacing so the whole menu fits, hide the scrollbar,
   and give the Request Demo button clean, uncut spacing at the bottom. */
.drawer {
  padding: calc(var(--header-h) + 10px) 14px 18px;
  gap: 12px;
  transition: transform var(--motion-window), box-shadow .34s ease;
}
/* Links scroll here; the drawer itself doesn't, so the pinned CTA never moves. */
.drawer-scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  display: flex;
  flex-direction: column;
  gap: 2px;
  scrollbar-width: none;              /* Firefox */
  -ms-overflow-style: none;           /* old Edge */
}
.drawer-scroll::-webkit-scrollbar { display: none; }   /* Chrome/Safari */
.drawer-cta { flex: 0 0 auto; }
.scrim { transition: opacity .24s ease, visibility .24s ease, backdrop-filter .24s ease; }
.drawer-search {
  display: grid;
  grid-template-columns: 18px minmax(0, 1fr);
  align-items: center;
  gap: 10px;
  margin: 0 0 12px;
  padding: 10px 12px;
  border: 1px solid var(--brd-strong);
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--panel) 88%, transparent);
}
.drawer-search svg { width: 17px; height: 17px; color: var(--indigo-lift); }
.drawer-search input {
  min-width: 0;
  border: 0;
  outline: 0;
  background: transparent;
  color: var(--text);
}
.drawer-search input::placeholder { color: var(--dim); }
.drawer a {
  display: block;
  padding: 11px 12px;
  border-radius: 12px;
  font-size: 16px;
  font-weight: 600;
  color: var(--text);
  text-decoration: none;
  transition: background .18s ease, color .18s ease;
}
.drawer a:hover { background: var(--hover); }
/* Section labels - small mono uppercase kickers (PLATFORM / EXPLORE / COMPANY),
   matching the live drawer. */
.drawer-sec {
  margin: 16px 0 4px;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--dim);
}
.drawer .btn { margin-top: 14px; flex: 0 0 auto; }
.drawer .btn-primary { color: var(--on-accent); }   /* keep white text on the indigo button */
/* The generic drawer-link hover (.drawer a:hover { background:var(--hover) }) is
   more specific than .btn-primary:hover, washing the button out to unreadable
   white-on-pale. Restate the button's real hover at higher specificity so it
   behaves exactly like the wide-mode Request Demo button. */
.drawer a.btn-primary:hover { background: var(--indigo-2); color: var(--on-accent); }

/* -----------------------------------------------------------------------------
   CHIP - small rounded tag. Add .chip-mono for the uppercase mono variant, or a
   .live-dot inside for a status pip (.anim animates it).
   -------------------------------------------------------------------------- */
.chip {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 8px 14px; border-radius: 999px;
  border: 1px solid var(--brd); background: var(--panel);
  color: var(--muted); font-size: 14px;
}

/* Live status dot - teal pip with a soft glow; .anim gives it a pulse. */
.live-dot {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--signal); box-shadow: 0 0 10px var(--signal);
}
.live-dot.anim { animation: ssPulse 2s infinite, dotGlow 2.6s ease-in-out infinite; }
@media (prefers-reduced-motion: reduce) { .live-dot.anim { animation: none; } }

/* Recording light. A past event whose recording is available is not the same
   offer as an event you have to turn up to, so it should not read as the same
   thing at a glance. Red rather than purple, but the SAME soft pulse and halo
   as every other live dot on the site, so it looks like it belongs here rather
   than like a warning that something is wrong.

   This is done by re-pointing --signal on the dot itself. The base .live-dot
   rules and the dotGlow keyframes both already read var(--signal) for the fill
   and the halo, so changing that one value turns the whole thing red and the
   timing, easing and glow stay exactly as they are on the purple dots. Nothing
   here overrides `animation`, which is what keeps the two in step.

   The red is a fixed value rather than a theme token on purpose: a recording
   light has to mean the same thing on both themes. Checked against both
   backgrounds. */
.live-dot.is-rec {
  --signal: #FF3B4E;
}
/* Reduced motion is handled by the .live-dot.anim rule above, which already
   drops the animation. The dot stays visible and simply sits still. */

/* In the events list the label is mono and inline, so the dot needs to sit on
   the text baseline rather than float. */
.ev-kind .live-dot {
  display: inline-block;
  margin-right: 7px;
  vertical-align: middle;
  position: relative;
  top: -1px;
}


/* --- ./components/panels.css --- */
/* =============================================================================
   Components - Panels, Cards & CTA
   -----------------------------------------------------------------------------
   Glass surfaces used to group content. Authored from the live design; the CTA
   sheen is clipped to its rounded border (fixes the shimmer spilling past the
   edge on the bottom call-to-action windows).
   ========================================================================== */

/* -----------------------------------------------------------------------------
   PANEL - the standard glass card. Frosted background, thin border, hover lift.
   On hover: a soft spotlight (::before, follows the cursor via scripts/effects.js)
   and a diagonal sheen sweep (::after). Both are clipped by overflow:hidden.
   Usage: <div class="panel"> … </div>  (put an .accent-line at the top for a tab)
   -------------------------------------------------------------------------- */
.panel {
  position: relative;
  background: var(--glass);      /* the ONE glass token - same recipe as the live site, theme-aware */
  border: 1px solid var(--brd);
  border-radius: 20px;
  padding: 28px;
  overflow: hidden;                 /* clips spotlight + sheen to the rounded box */
  /* 10px (not 14) keeps the backdrop recognizable - heavier blur mushed the
     grid/glow into a flat tone and the pane read as opaque. */
  /* windows are see-through: no frosted backdrop */
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  box-shadow: inset 0 1px 0 var(--glass-hi);
  transition: border-color .34s ease, transform var(--motion-window), box-shadow .34s ease;
  --window-sheen-soft: rgba(255,255,255,.08);
  --window-sheen-core: rgba(255,255,255,.18);
}
.panel::before {                    /* cursor spotlight */
  content: "";
  position: absolute; inset: 0;
  opacity: 0; transition: opacity .35s ease; pointer-events: none;
  background: radial-gradient(420px circle at var(--px, 50%) var(--py, 50%), var(--panel-spot), transparent 60%);
}
.panel::after {                     /* diagonal sheen sweep - moved via background-position
                                       so it stays pinned inside the rounded box. A translate
                                       leaks past the corners here because backdrop-filter
                                       breaks the rounded overflow clip. */
  content: "";
  position: absolute;
  top: -20%;
  bottom: -20%;
  left: -42%;
  width: 24%;
  border-radius: inherit;
  pointer-events: none;
  background:
    radial-gradient(ellipse at center, var(--window-sheen-core) 0%, var(--window-sheen-soft) 34%, transparent 68%),
    linear-gradient(115deg, transparent 0%, transparent 32%, var(--window-sheen-soft) 46%, var(--window-sheen-core) 50%, var(--window-sheen-soft) 54%, transparent 68%, transparent 100%);
  filter: blur(7px);
  transform: translate3d(0, 0, 0) skewX(-14deg);
  opacity: 0;
  transition: transform .9s cubic-bezier(.4,.75,.3,1), opacity .34s ease;
}
.panel:hover {
  border-color: var(--brd-hover);
  transform: var(--window-hover-transform);
  box-shadow: var(--window-hover-shadow);
}
.panel:hover::after { transform: translate3d(580%, 0, 0) skewX(-14deg); opacity: .72; }
.panel:hover::before { opacity: 1; }
.panel > * { position: relative; z-index: 1; }

/* Accent tab - a short indigo bar, usually at the top of a panel. */
.accent-line {
  width: 44px; height: 2px; border-radius: 2px;
  background: linear-gradient(90deg, var(--indigo-lift), var(--grad-hi), transparent);
  background-size: 220% 100%;
  background-position: 100% 0;
  transition: width var(--motion-hover), background-position var(--motion-hover);
}
.panel:hover .accent-line {
  width: 62px;
  background-position: 0 0;
}

/* Dashed empty-state box (placeholders / "drop content here"). */
.box {
  border: 1px dashed var(--brd-strong);
  border-radius: 16px;
  padding: 40px 52px;
  text-align: center;
  color: var(--dim);
}

/* -----------------------------------------------------------------------------
   CTA-SHINE - the large call-to-action window (page-bottom "Request a demo"
   blocks). Glass panel with an animated conic border trace (.cta-orbit) and a
   sheen on hover.
   FIX: the sheen (::after) now sweeps via background-position while staying
   pinned inside its rounded box, so it never spills past the border. (Previously
   it used translateX and, with no overflow clip, leaked off the bottom edge.)
   -------------------------------------------------------------------------- */
.cta-shine {
  position: relative;
  isolation: isolate;
  overflow: hidden;                 /* clip the sheen inside the rounded corners (same as .panel) */
  border: 1px solid var(--brd-hover);
  border-radius: 24px;
  padding: clamp(40px, 4.6vw, 60px) clamp(26px, 3.6vw, 42px);
  background: var(--glass);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  box-shadow: inset 0 1px 0 var(--glass-hi);
  transition: box-shadow .34s ease, border-color .34s ease, transform var(--motion-window);
  will-change: auto;
  --window-sheen-soft: rgba(255,255,255,.08);
  --window-sheen-core: rgba(255,255,255,.18);
  --streak-head: #FFFFFF; --streak-core: #F2EEFF;
  --streak-tail: var(--indigo-bright); --streak-glow: var(--indigo-bright);
}
.cta-window {
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 22px;   /* even spacing between logo, heading, subline, buttons */
}
/* CTA wordmark uses the hi-res logo-*-hd.png (derived from the 3585x580 master),
   so it stays crisp at any size and can magnify with the window on hover. */
.cta-window .cta-logo { height: 48px; width: auto; margin: 0 0 2px; }
.cta-shine:hover { border-color: var(--brd-hover); transform: scale(1.045); }
.cta-shine .ds-row .btn,
.cta-shine .center-row .btn { min-width: 148px; }
.cta-window > :not(.cta-orbit) { margin-top: 0; margin-bottom: 0; }
.cta-window .lead,
.cta-window .h2 {
  transform-origin: center;
  transition: transform var(--motion-window), color .34s ease;
}
.cta-window:hover .h2 { transform: scale(1.026); }
.cta-window:hover .lead { transform: scale(1.018); color: var(--text); }
.cta-window .center-row { margin-top: 0; }
.cta-window .center-row.is-spaced { margin-top: 0; }
.cta-shine::before {
  content: none;
  display: none;
}
.cta-shine::after {
  content: "";
  position: absolute;
  top: -20%;
  bottom: -20%;
  left: -42%;
  width: 24%;
  border-radius: inherit;
  pointer-events: none;
  background:
    radial-gradient(ellipse at center, var(--window-sheen-core) 0%, var(--window-sheen-soft) 34%, transparent 68%),
    linear-gradient(115deg, transparent 0%, transparent 32%, var(--window-sheen-soft) 46%, var(--window-sheen-core) 50%, var(--window-sheen-soft) 54%, transparent 68%, transparent 100%);
  filter: blur(7px);
  transform: translate3d(0, 0, 0) skewX(-14deg);
  opacity: 0;
  transition: transform .95s cubic-bezier(.4,.75,.3,1), opacity .34s ease;
}
.cta-shine:hover::after { transform: translate3d(580%, 0, 0) skewX(-14deg); opacity: .72; }
.cta-shine > * { position: relative; z-index: 1; }
[data-theme="light"] .cta-shine {
  --streak-head: #4A1FDB; --streak-core: #6B4BEF;
  --streak-tail: #9C86F5; --streak-glow: #7A63F5;
}
[data-theme="light"] .panel,
[data-theme="light"] .cta-shine {
  --window-sheen-soft: rgba(83,51,236,.12);
  --window-sheen-core: rgba(83,51,236,.3);
}

/* Animated conic-gradient border trace that orbits the CTA.
   The @property registration is REQUIRED: without it --cta-trace is not
   animatable, the angle never advances, and the streak sits frozen. */
@property --cta-trace {
  syntax: '<angle>';
  inherits: false;
  initial-value: 0deg;
}
.cta-orbit {
  position: absolute; inset: -1px; border-radius: inherit; pointer-events: none; z-index: 2; padding: 1.6px;
  background: conic-gradient(from var(--cta-trace),
    transparent 0deg, transparent 188deg,
    color-mix(in srgb, var(--streak-tail) 26%, transparent) 268deg,
    color-mix(in srgb, var(--streak-tail) 70%, transparent) 320deg,
    var(--streak-tail) 342deg, var(--streak-core) 353deg, var(--streak-head) 360deg);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor; mask-composite: exclude;
  filter: drop-shadow(0 0 5px color-mix(in srgb, var(--streak-glow) 75%, transparent));
  animation: ctaTrace 16s linear infinite;
  opacity: .74;
  transition: opacity .28s ease, filter .28s ease;
}
.cta-shine:hover .cta-orbit {
  opacity: 1;
  filter: drop-shadow(0 0 7px color-mix(in srgb, var(--streak-glow) 78%, transparent));
}
@media (prefers-reduced-motion: reduce) { .cta-orbit { animation: none; } }

/* -----------------------------------------------------------------------------
   FEATURED ARTICLE (.tl-feat) - the Thought Leadership hero card. A two-column
   glass panel (headline + author on the left, excerpt + read-link on the right)
   wrapped in one link, with the CTA orbit tracing its border.
   Structure: <a class="panel tl-feat" href="…"><span class="cta-orbit"></span>
              <div class="tl-feat-main">…</div><div class="tl-feat-aside">…</div></a>
   -------------------------------------------------------------------------- */
.tl-feat {
  position: relative;
  isolation: isolate;
  display: grid;
  grid-template-columns: 1fr 1fr;
  padding: 0 !important;
  overflow: hidden;
  text-decoration: none;
  background: var(--glass);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  box-shadow: inset 0 1px 0 var(--glass-hi);
  transition: transform .32s cubic-bezier(.34, 1.45, .5, 1), box-shadow .35s ease, border-color .3s ease;
  --streak-head: #FFFFFF; --streak-core: #F2EEFF;
  --streak-tail: var(--indigo-bright); --streak-glow: var(--indigo-bright);
}
.tl-feat:hover { transform: translateY(-4px) scale(1.022); }
.tl-feat .cta-orbit { inset: 0; }
[data-theme="light"] .tl-feat {
  --streak-head: #4A1FDB; --streak-core: #6B4BEF;
  --streak-tail: #9C86F5; --streak-glow: #7A63F5;
}
.tl-feat-main {
  padding: clamp(24px, 2.6vw, 34px);
  position: relative;
  z-index: 1;
}
.tl-feat-main .h2 { margin-top: 20px; max-width: 15ch; }
.tl-feat-aside {
  padding: clamp(24px, 2.6vw, 34px) clamp(24px, 2.6vw, 32px);
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 14px;
}
@media (max-width: 760px) { .tl-feat { grid-template-columns: 1fr; } }

/* Author strip inside the featured card: photo + name/role. */
.tl-feat-author {
  margin-top: 22px;
  display: flex;
  align-items: center;
  /* Gap tracks the circle: a 60px avatar next to a 13px gap reads cramped. */
  gap: 16px;
}
.tl-feat-author b {
  display: block;
  font-size: 19.5px;
  line-height: 1.25;
  color: var(--text);
  font-weight: 700;
}
.tl-feat-author span {
  font-size: 13px;
  color: var(--dim);
}
/* Superseded by .ava in objects/article.css, which wraps the image so it can be
   framed and padded rather than only cropped. */

/* "Read the article →" mono link; arrow nudges + label underlines on hover. */
.tl-fwd {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--indigo-lift);
  text-decoration: none;
  align-self: flex-start;
}
.tl-fwd svg { width: 15px; height: 15px; transition: transform .28s cubic-bezier(.5, 1.4, .5, 1); }
.panel:hover .tl-fwd svg { transform: translateX(5px); }
.tl-fwd span { position: relative; }
.tl-fwd span::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -2px;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform .25s cubic-bezier(.5, .5, .2, 1);
}
.panel:hover .tl-fwd span::after { transform: scaleX(1); }

/* A published article shown full width above the upcoming grid. Reuses the
   .tl-feat card so it keeps the photo, the forward link and no underline. */
.tl-more-card {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 28px;
  padding: 28px;
  text-decoration: none;
}
.tl-more-card .h4 { margin-top: 8px; }
.tl-more-card .small-t { margin-top: 8px; }
/* Right column: the forward link, then the author row formatted exactly
   like the featured card above it (.tl-feat-author + .tl-ava). */
.tl-more-side { display: flex; flex-direction: column; align-items: stretch; gap: 14px; }
.tl-more-side .tl-fwd { align-self: flex-end; }
.tl-more-side .tl-fwd { white-space: nowrap; }
.tl-more-side .tl-feat-author { margin-top: 0; }
@media (max-width: 760px) { .tl-more-card { grid-template-columns: 1fr; } }

/* Upcoming-articles grid: simple panel cards, three-up on wide screens. */
.tl-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: 18px;
}
.tl-grid .panel { padding: 28px; display: block; }
/* Card eyebrow. One size everywhere a card carries a date, so the featured
   card, the wide card and the upcoming grid all read as the same label. */
.tl-card-date {
  font-size: 13px;
  letter-spacing: .12em;
  color: var(--indigo-lift);
}
/* Nothing is published yet behind these, so they are muted rather than accent. */
.tl-card-date.is-upcoming { color: var(--muted); }
/* The featured cards carry the live NEW / FEATURED stamp, so it reads larger
   than a plain card date. */
.sec-caption.tl-card-date, .fi-cap.tl-card-date { font-size: 15px; }
.tl-grid .h4 { margin-top: 12px; }
.tl-grid .small-t { margin-top: 10px; }

/* CTA logo must render crisp ON TOP of the glass window, never behind it. */
.cta-window .cta-logo { position: relative; z-index: 2; filter: none; -webkit-filter: none; image-rendering: auto; }



/* --- ./components/feedback.css --- */
/* =============================================================================
   Components - Alerts, Toasts & Banners
   Status messaging. Colour comes from the status tokens (ok / warn / danger /
   info) so light & dark stay in sync.
   ========================================================================== */

/* -----------------------------------------------------------------------------
   ALERT - a boxed message with an icon, title and body. Add a status class:
     .alert.info  .alert.success  .alert.warning  .alert.error
   Structure: <div class="alert success"><div class="ai">svg</div>
              <div><h6>Title</h6><p>Body</p></div><button class="ax">×</button></div>
   -------------------------------------------------------------------------- */
.alert {
  display: flex; gap: 13px; align-items: flex-start;
  padding: 15px 16px; border-radius: 15px;
  border: 1px solid var(--brd); background: var(--glass);
  backdrop-filter: blur(12px); box-shadow: inset 0 1px 0 var(--glass-hi);
}
.alert .ai {
  width: 30px; height: 30px; border-radius: 9px;
  display: flex; align-items: center; justify-content: center; flex: 0 0 auto;
}
.alert .ai svg { width: 16px; height: 16px; }
.alert h6 { margin: 0; font-size: 14px; font-weight: 700; color: var(--text); }
.alert p { margin: 3px 0 0; font-size: 13px; line-height: 1.5; color: var(--muted); }

.alert.info    { border-color: rgba(123,103,240,.4); }
.alert.info .ai    { background: var(--info-bg);   color: var(--indigo-lift); }
.alert.success { border-color: color-mix(in srgb, var(--ok) 45%, transparent); }
.alert.success .ai { background: var(--ok-bg);     color: var(--ok); }
.alert.warning { border-color: color-mix(in srgb, var(--warn) 45%, transparent); }
.alert.warning .ai { background: var(--warn-bg);   color: var(--warn); }
.alert.error   { border-color: color-mix(in srgb, var(--danger) 45%, transparent); }
.alert.error .ai   { background: var(--danger-bg); color: var(--danger); }

/* -----------------------------------------------------------------------------
   BANNER - full-width notice bar (e.g. scheduled maintenance).
   -------------------------------------------------------------------------- */
.banner {
  display: flex; align-items: center; justify-content: center; gap: 12px;
  padding: 11px 18px; border-radius: 13px;
  background: linear-gradient(90deg, var(--info-bg), transparent 70%);
  border: 1px solid rgba(123,103,240,.32);
  font-size: 13.5px; color: var(--text);
}
.banner b { font-weight: 700; }
.banner span { color: var(--muted); }


/* --- ./components/blocks.css --- */
/* =============================================================================
   Components - Content Blocks
   Stats, numbered feature rows, pillars and dividers.
   ========================================================================== */

/* -----------------------------------------------------------------------------
   GROUP LABEL - mono uppercase heading above a group of rows/cards (e.g.
   "Company", "Legal" on Resources). Spacing comes from the global tokens
   --group-gap / --group-gap-below so every group heading breathes the same.
   Every group label gets the same top gap. When a label is the first thing in
   a section, the section's own rhythm (--section-pad) already spaces it, so it
   skips its top margin instead of stacking the two gaps.
   -------------------------------------------------------------------------- */
.res-group-label {
  margin: var(--group-gap) 0 var(--group-gap-below);
  font-family: var(--font-mono);
  font-size: 18px;
  line-height: 1.1;
  font-weight: 800;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--eyebrow);
}
.section > .res-group-label:first-child { margin-top: 0; }

/* -----------------------------------------------------------------------------
   STAT - a big metric number. Pair with a .small-t caption beneath. Add
   .text-grad for the animated indigo sweep (e.g. "−63%").
   -------------------------------------------------------------------------- */
.stat-num {
  font-weight: 800; font-size: 46px; letter-spacing: -.03em;
  color: var(--text); line-height: 1;
}

/* -----------------------------------------------------------------------------
   FEATURE ROW (.ap-row) - numbered list of capabilities. A mono number (.ap-n)
   + heading + copy, with an indigo accent bar that grows in on hover.
   Structure: <div class="ap-row"><div class="ap-n">01</div>
              <div><h3>…</h3><p>…</p></div></div>
   -------------------------------------------------------------------------- */
.ap-row,
.res-bar {
  position: relative;
  display: grid;
  grid-template-columns: 68px minmax(0, 1fr);
  gap: 22px;
  padding: 28px 6px 28px 18px;
  border-bottom: 1px solid var(--line);
  align-items: baseline;
  color: inherit;
  transition: background .34s ease, color .34s ease;
}
.ap-row::before,
.res-bar::before {
  content: "";
  position: absolute;
  left: 0;
  top: 20px;
  bottom: 20px;
  width: 4px;
  border-radius: 4px;
  background: var(--indigo-bright);
  box-shadow: 0 0 12px var(--indigo-bright);
  transform: scaleY(0);
  transform-origin: center;
  opacity: 0;
  transition: transform var(--motion-hover), opacity .34s ease;
}
.ap-row:hover,
.res-bar:hover {
  background: transparent;
}
.ap-row:hover::before,
.res-bar:hover::before { transform: scaleY(1); opacity: 1; }
.ap-n,
.res-n {
  display: inline-block;
  font-family: var(--font-mono); font-size: 20px; color: var(--indigo-lift);
  font-weight: 800;
  transform-origin: left center; transition: transform var(--motion-hover), color .34s ease;
}
.ap-row:hover .ap-n,
.res-bar:hover .res-n { transform: scale(1.85); color: var(--indigo-lift); }
.ap-row h3,
.res-bar h3,
.res-bar h4 {
  display: block;
  margin: 0;
  transition: transform var(--motion-hover), color .34s ease;
  transform-origin: left center;
}
.ap-row:hover h3,
.res-bar:hover h3,
.res-bar:hover h4 { transform: scale(1.065); color: var(--text); }
.ap-row p,
.res-bar p { margin: 7px 0 0; transform-origin: left center; transition: transform var(--motion-hover), color .34s ease; }
.ap-row:hover p,
.res-bar:hover p {
  transform: scale(1.025);
  color: var(--muted);
}

/* -----------------------------------------------------------------------------
   PILLAR - column in a multi-part feature strip (dividers between columns).
   -------------------------------------------------------------------------- */
.pillar { padding: 30px 28px 28px 0; border-bottom: 1px solid var(--line); }
.pillar + .pillar { border-left: 1px solid var(--line); padding-left: 28px; }
.pillar h3 { margin: 0 0 9px; }
.pillar p { margin: 0; }
@media (max-width: 760px) { .pillars { grid-template-columns: 1fr; } .pillar + .pillar { border-left: 0; padding-left: 0; } }

/* -----------------------------------------------------------------------------
   DIVIDER - thin horizontal rule between sections.
   Always carries symmetric breathing room above AND below so it's never jammed
   against the content on either side, wherever it's dropped in. (A divider used
   as the FIRST child of a .section gets its top margin zeroed in frame.css - the
   section's own top padding already handles the space above it there.)
   -------------------------------------------------------------------------- */
.divider { height: 1px; background: var(--line); border: 0; margin: var(--divider-gap, 44px) 0; }

/* -----------------------------------------------------------------------------
   METRIC GLANCE (.glance) - compact KPI/stat groups, including the metric callouts
   used in advisor/event sections. The number lifts and shimmers on hover while
   the caption slides slightly to keep the interaction quiet but noticeable.
   -------------------------------------------------------------------------- */
.glance {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: clamp(26px, 4vw, 52px);
}
.glance-cell { padding: 0; }
/* Glance cells hosted inside glass panels (Onboarding "at a glance"). */
.panel.glance-cell { padding: 28px; }
.panel .accent-line + .glance-num { margin-top: 16px; }
.glance-num {
  display: inline-block;
  transform-origin: left center;
  font-weight: 800;
  font-size: clamp(30px, 3.4vw, 44px);
  line-height: 1;
  letter-spacing: -.03em;
  color: var(--text);
  transition: transform var(--motion-hover), color .34s ease, text-shadow .34s ease;
}
.glance-cell:hover .glance-num {
  transform: scale(1.045);
  color: var(--indigo-lift);
  animation: none;
  text-shadow: none;
}
.glance-num .u { color: var(--indigo-lift); }
.glance-cell:hover .glance-num .u {
  color: var(--indigo-lift);
  animation: none;
  text-shadow: none;
}
.glance-cell p {
  transform-origin: left center;
  transition: color .34s ease, transform var(--motion-hover);
}
.glance-cell:hover p {
  color: var(--muted);
  transform: scale(1.03);
}
/* -----------------------------------------------------------------------------
   STYLE GUIDE SCAFFOLD - global documentation layout helpers. These keep the
   guide itself on the same grid, spacing, and object language as the site.
   -------------------------------------------------------------------------- */
.ds-grid { display: grid; gap: 26px; }
.ds-row { display: flex; flex-wrap: wrap; gap: 14px; align-items: center; }
.ds-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; }
.ds-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
.style-object {
  position: relative;
  display: grid;
  grid-template-columns: minmax(180px, .55fr) minmax(0, 1fr);
  gap: clamp(18px, 4vw, 42px);
  align-items: start;
  padding: 28px 0;
  border-top: 1px solid var(--line);
}
.style-object:first-child { border-top: 0; padding-top: 0; }
.style-object.is-wide .style-object-sample { grid-column: 1 / -1; }
.style-object-name {
  margin: 0;
  font-size: 13px;
  line-height: 1.45;
  font-weight: 750;
  color: var(--text);
}
.style-object-use {
  margin: 8px 0 0;
  font-size: 13px;
  line-height: 1.55;
  color: var(--muted);
}
.style-object-code {
  display: inline-block;
  margin-top: 12px;
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1.45;
  color: var(--dim);
}
.new-style-marker {
  position: absolute;
  left: clamp(-58px, -4.4vw, -42px);
  top: 24px;
  width: 30px;
  height: 30px;
  border: 1px solid color-mix(in srgb, var(--indigo-bright) 52%, var(--line));
  border-radius: 8px;
  background: linear-gradient(145deg, var(--indigo-bright), var(--indigo));
  box-shadow: 0 8px 22px rgba(83, 51, 236, .34);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: opacity .22s ease, transform var(--motion-window), filter .22s ease;
}
.new-style-marker:hover,
.new-style-marker:focus-visible {
  transform: scale(1.12);
  filter: brightness(1.08);
}
.new-style-marker img {
  width: 28px;
  height: 28px;
  object-fit: contain;
  display: block;
}
.style-object.is-acknowledged .new-style-marker { opacity: 0; pointer-events: none; }

/* ----------------------------------------------------------------------------- 
   RESOURCE ROWS (.res-bar) - large linked rows used on Resources and index pages.
   A mono number, text group, and arrow icon share one scan-friendly row.
   -------------------------------------------------------------------------- */
.res-list { display: grid; }
.res-bar {
  grid-template-columns: 68px minmax(0, 1fr) auto;
  text-decoration: none;
}
.res-go {
  color: var(--dim);
  display: flex;
  flex: 0 0 auto;
  align-self: center;
  transition: transform var(--motion-hover), color .34s ease;
}
.res-go svg {
  width: 30px;
  height: 30px;
  display: block;
  transform-origin: center;
  transition: transform var(--motion-hover);
}
.res-bar:hover .res-go {
  color: var(--indigo-lift);
}
.res-bar:hover .res-go svg { transform: none; }
.res-bar.cta h3,
.res-bar.cta h4 { color: var(--indigo-lift); }
.res-bar.cta .res-n,
.res-bar.cta .res-go { color: var(--indigo-lift); }
[data-theme="light"] .ap-n,
[data-theme="light"] .res-n,
[data-theme="light"] .res-bar.cta h3,
[data-theme="light"] .res-bar.cta h4,
[data-theme="light"] .res-bar.cta .res-n,
[data-theme="light"] .res-bar.cta .res-go {
  color: var(--indigo);
}

/* ----------------------------------------------------------------------------- 
   LEGAL ARTICLE (.legal) - long-form Terms/Privacy copy with calm hierarchy.
   -------------------------------------------------------------------------- */
.legal { max-width: 760px; }
.legal-meta {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--dim);
  margin: 0 0 36px;
}
.legal h2 {
  font-size: clamp(20px, 2vw, 26px);
  font-weight: 700;
  letter-spacing: -.01em;
  color: var(--text);
  margin: 44px 0 0;
  padding-top: 26px;
  border-top: 1px solid var(--line);
}
.legal h2:first-of-type { border-top: 0; padding-top: 0; margin-top: 8px; }
.legal p {
  font-size: 16px;
  line-height: 1.72;
  color: var(--muted);
  margin: 14px 0 0;
}
.legal p.caps {
  font-size: 13.5px;
  line-height: 1.65;
  letter-spacing: .01em;
  color: var(--dim);
}
.legal strong { color: var(--text); font-weight: 600; }

/* h3 = a question inside an FAQ block. Sits clearly below h2 (no rule above it,
   smaller, tighter) so the section hierarchy still reads at a glance. */
.legal h3 {
  font-size: 17px;
  font-weight: 650;
  letter-spacing: -.005em;
  color: var(--text);
  margin: 28px 0 0;
}
/* Lists share the exact type of .legal p so a bulleted clause and a prose
   clause sit on the same rhythm. Marker picks up the link indigo. */
.legal ul {
  margin: 12px 0 0;
  padding-left: 20px;
  list-style: disc;
}
.legal li {
  font-size: 16px;
  line-height: 1.72;
  color: var(--muted);
  margin: 6px 0 0;
}
.legal li::marker { color: var(--indigo-lift); }
.legal li strong { color: var(--text); font-weight: 600; }
.legal a {
  position: relative;
  color: var(--indigo-lift);
  text-decoration: none;
}
.legal a::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--motion-hover);
}
.legal a:hover::after { transform: scaleX(1); }
.legal address {
  font-style: normal;
  color: var(--muted);
  font-size: 16px;
  line-height: 1.7;
  margin-top: 14px;
}

/* ----------------------------------------------------------------------------- 
   VERTICAL MARQUEE (.vmarquee) - stacked institution names used for pedigree.
   -------------------------------------------------------------------------- */
.vmarquee {
  position: relative;
  height: clamp(320px, 34vw, 430px);
  overflow: hidden;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  -webkit-mask-image: linear-gradient(transparent, #000 18%, #000 82%, transparent);
  mask-image: linear-gradient(transparent, #000 18%, #000 82%, transparent);
}
.marquee-stack {
  display: grid;
  gap: var(--copy-stack-gap, 24px);
  align-content: start;
  justify-items: center;
  text-align: center;
}
.marquee-stack .eyebrow { margin-bottom: 0; }
.marquee-stack .vmarquee { width: 100%; }
.marquee-stack .vmarquee-name { text-align: center; }
.vmarquee-track {
  display: flex;
  flex-direction: column;
  will-change: auto;
  animation: vmarqueeMove 17s linear infinite;
}
.vmarquee-group {
  display: flex;
  flex-direction: column;
  gap: 26px;
  padding-bottom: 26px;
}
.vmarquee-name {
  font-size: 26px;
  font-weight: 700;
  letter-spacing: -.018em;
  line-height: 1;
  color: var(--muted);
}
@keyframes vmarqueeMove {
  from { transform: translateY(0); }
  to { transform: translateY(-50%); }
}
@media (prefers-reduced-motion: reduce) { .vmarquee-track { animation: none; } }

/* ----------------------------------------------------------------------------- 
   TEAM CTA (.team-cta) - compact indigo text+arrow link used after team copy.
   -------------------------------------------------------------------------- */
.team-cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  margin-top: 0;
  min-height: 43px;
  padding: 15px 24px 13px;
  border-radius: 999px;
  background: var(--indigo);
  color: var(--on-accent);
  text-decoration: none;
  font-weight: 700;
  font-size: 14px;
  line-height: 1;
  white-space: nowrap;
  box-shadow: 0 4px 18px -6px var(--indigo-bright);
  transition: transform var(--motion-window), background .34s ease, box-shadow .34s ease;
}
.team-cta:hover { background: var(--indigo-2); transform: scale(1.04); }
.team-cta svg {
  width: 18px;
  height: 18px;
  transition: transform .72s cubic-bezier(.18, .95, .22, 1.18);
}
.team-cta:hover svg { animation: arrowNudge 2s ease-in-out infinite; }
.team-cta.is-spaced { margin-top: 30px; }

.center-stack {
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.section-cta { margin-top: 56px; }
.center-row {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  align-items: center;
  justify-content: center;
}
.center-row.is-spaced { margin-top: 24px; }
.split-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(290px, 1fr));
  gap: clamp(32px, 6vw, 72px);
  align-items: center;
}
.split-grid.is-hero-marquee {
  grid-template-columns: minmax(0, 1.08fr) minmax(330px, .58fr);
  align-items: stretch;
  gap: clamp(34px, 7vw, 96px);
}
.split-grid.is-hero-marquee .sec-head { margin-bottom: 0; }
.split-grid.is-hero-marquee .vmarquee {
  align-self: stretch;
  margin-top: calc(var(--fs-eyebrow) * 1.1 + 16px);
  height: calc(100% - (var(--fs-eyebrow) * 1.1 + 16px));
  min-height: 0;
  justify-self: center;
  width: min(100%, 420px);
  display: flex;
  align-items: center;
}
/* The track is lifted out of flow so the endless name stack can't inflate the
   row height - the window then stretches to match the text column exactly. */
.split-grid.is-hero-marquee .vmarquee-track {
  position: absolute;
  inset: 0;
  width: 100%;
}
.split-grid.is-hero-marquee .vmarquee-name { text-align: center; }
.split-grid.is-hero-mark {
  grid-template-columns: minmax(0, 1fr) minmax(240px, .44fr);
  align-items: start;
  gap: clamp(34px, 7vw, 96px);
}
.split-grid.is-hero-mark .sec-head { margin-bottom: 0; }
/* Hero with a featured card riding shotgun (Thought Leadership) - same family
   as .is-hero-mark (About's metal logo) and .is-hero-marquee (Our Team's name
   list): text column left, the feature object right, starting below the
   eyebrow line and ENDING level with the text column (align-items: stretch +
   a compact type scale inside the card keep its content within that height). */
.split-grid.is-hero-feature {
  grid-template-columns: minmax(0, 1fr) minmax(380px, .9fr);
  align-items: stretch;
  gap: clamp(34px, 6vw, 80px);
}
.split-grid.is-hero-feature .sec-head { margin-bottom: 0; }
.split-grid.is-hero-feature .tl-feat {
  grid-template-columns: 1fr;
  grid-template-rows: auto 1fr;   /* excerpt block absorbs any spare height */
  margin-top: calc(var(--fs-eyebrow) * 1.1 + 16px);
  height: calc(100% - (var(--fs-eyebrow) * 1.1 + 16px));
  min-height: 0;
}
/* Compact scale so the card's content fits the header's height. */
.split-grid.is-hero-feature .tl-feat-main { padding-bottom: 0; }
.split-grid.is-hero-feature .tl-feat-main .h2 {
  font-size: clamp(22px, 1.9vw, 28px);
  margin-top: 14px;
  max-width: none;
}
.split-grid.is-hero-feature .tl-feat-author { margin-top: 16px; }
.split-grid.is-hero-feature .tl-feat-aside {
  padding-top: 16px;
  gap: 12px;
  min-height: 0;
}
.split-grid.is-hero-feature .tl-feat-aside .body-t {
  font-size: 15.5px;
  line-height: 1.6;
  /* Clamp the excerpt so a long standfirst can never overflow the card. */
  display: -webkit-box;
  -webkit-line-clamp: 4;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.hero-mark-window {
  margin-top: calc(var(--fs-eyebrow) * 1.1 + 16px);
  height: clamp(168px, 16vw, 232px);
  display: grid;
  place-items: center;
  overflow: visible;
  justify-self: center;
  isolation: isolate;
}
.hero-mark-window img {
  width: min(100%, 360px);
  height: auto;
  display: block;
  object-fit: contain;
  filter:
    drop-shadow(0 18px 38px color-mix(in srgb, var(--indigo-bright) 26%, transparent))
    drop-shadow(0 0 58px color-mix(in srgb, var(--indigo-bright) 16%, transparent));
}
.split-grid.is-top { align-items: start; }
.copy-stack {
  --copy-stack-gap: 24px;
  display: grid;
  gap: var(--copy-stack-gap);
  align-content: start;
}
.copy-stack > * { margin-top: 0 !important; margin-bottom: 0 !important; }
.copy-stack .team-cta { margin-top: 0; justify-self: start; }
.split-grid.is-top:has(.marquee-stack) { align-items: stretch; }
.split-grid.is-top:has(.marquee-stack) .copy-stack { height: 100%; }
.split-grid.is-top:has(.marquee-stack) .marquee-stack {
  height: 100%;
  grid-template-rows: auto minmax(0, 1fr);
  align-content: stretch;
}
.split-grid.is-top:has(.marquee-stack) .marquee-stack .vmarquee { height: auto; min-height: 0; }
.split-grid.is-team-marquee {
  align-items: stretch;
}
.split-grid.is-team-marquee .copy-stack,
.split-grid.is-team-marquee .marquee-stack {
  height: 100% !important;
}
.split-grid.is-team-marquee .marquee-stack {
  grid-template-rows: auto minmax(0, 1fr) !important;
  align-content: stretch !important;
  align-self: stretch;
}
.split-grid.is-team-marquee .marquee-stack .vmarquee {
  height: auto !important;
  max-height: none;
  -webkit-mask-image: linear-gradient(transparent, #000 12%, #000 78%, transparent);
  mask-image: linear-gradient(transparent, #000 12%, #000 78%, transparent);
}
/* Same out-of-flow trick as the hero marquee: the window's bottom edge now
   lands level with the "Meet the team" button instead of running past it. */
.split-grid.is-team-marquee .marquee-stack .vmarquee-track {
  position: absolute;
  inset: 0;
}
.vmarquee.is-team-window {
  border-top: 0;
  border-bottom: 0;
}
@media (max-width: 860px) {
  .ds-3,
  .ds-2,
  .style-object,
  .split-grid.is-hero-marquee,
  .split-grid.is-team-marquee,
  .split-grid.is-hero-feature,
  .split-grid.is-hero-mark { grid-template-columns: 1fr; }
  .split-grid.is-hero-marquee .vmarquee,
  .split-grid.is-hero-feature .tl-feat,
  .hero-mark-window { margin-top: 0; }
  /* Stacked below the copy there's no column height to mirror. */
  .split-grid.is-hero-feature .tl-feat { height: auto; }
  /* Stacked below the copy there is no text column to mirror, so the marquee
     windows fall back to a fixed height (out-of-flow tracks have none). */
  .split-grid.is-hero-marquee .vmarquee,
  .split-grid.is-team-marquee .marquee-stack .vmarquee { height: clamp(240px, 56vw, 320px) !important; }
  .new-style-marker {
    position: static;
    margin-bottom: 12px;
  }
}

/* -----------------------------------------------------------------------------
   EVENT ROWS (.ev-list / .ev-row) - Events page listings. A centred date cell,
   the event text, and a right-side action share one row. Modifiers:
     .is-live   linked upcoming event (indigo border + Register button)
     .is-past   archive rows (date dims to match the muted copy)
   -------------------------------------------------------------------------- */
.ev-list {
  display: flex;
  flex-direction: column;
  gap: 16px;
  margin-top: 8px;
}
.ev-row {
  display: grid;
  /* 206px, not 150px: the widest kind label we carry is "Webinar recording",
     which needs 176px once the status dot and its gap are counted, plus the
     26px cell padding. At 150px it wrapped onto two lines with the dot stuck
     to the first one, which read as a rendering fault rather than a choice.
     The date cell is centred, so shorter labels just get more air around them.
     Measured in the browser, not guessed. If a longer kind is ever added,
     re-measure rather than assuming this still holds. */
  grid-template-columns: 206px 1fr auto;
  gap: 26px;
  align-items: center;
  padding: 24px 30px;
}
a.ev-row {
  text-decoration: none;
  border-color: var(--brd-hover);
}
.ev-date {
  text-align: center;
  border-right: 1px solid var(--line);
  padding-right: 26px;
  min-width: 104px;
}
.ev-when {
  font-weight: 800;
  font-size: 21px;
  color: var(--text);
  line-height: 1.05;
  white-space: nowrap;
}
.ev-row.is-past .ev-when { color: var(--muted); }
.ev-kind {
  font-size: 12.5px;
  color: var(--indigo-lift);
  margin-top: 7px;
}
.ev-row.is-past .ev-kind { color: var(--dim); }
.ev-row .h4 { margin: 0; }
.ev-row .small-t { margin-top: 8px; max-width: 560px; }
.ev-row .btn { white-space: nowrap; }
.ev-tag {
  font-size: 11px;
  color: var(--dim);
  white-space: nowrap;
}
@media (max-width: 700px) {
  .ev-row { grid-template-columns: 1fr; gap: 14px; }
  .ev-date {
    border-right: 0;
    border-bottom: 1px solid var(--line);
    padding: 0 0 12px;
    text-align: left;
  }
}

/* -----------------------------------------------------------------------------
   ONBOARDING TRACK (.ob-track / .ob-phase) - the five-step process timeline.
   A vertical rail connects numbered circular nodes; each phase carries a mono
   week kicker (.ob-wk), heading, sub, and checklist. The number lives ONLY in
   the node (no duplicated "Week 4" + "04"). Hovering a phase lights its node
   indigo and lifts the heading - the same interaction language as .ap-row.
   Structure: <div class="ob-track">
                <div class="ob-phase"><div class="ob-node">01</div>
                  <div><div class="ob-wk">Week 1</div><h3>…</h3>
                       <p class="ob-sub">…</p><ul class="ob-list">…</ul></div>
                </div> …
   -------------------------------------------------------------------------- */
.ob-track {
  position: relative;
  margin-top: 18px;
}
/* The connecting rail - runs behind the (solid) nodes, fading out at the end. */
.ob-track::before {
  content: "";
  position: absolute;
  left: 26px;
  top: 12px;
  bottom: 46px;
  width: 2px;
  border-radius: 2px;
  background: linear-gradient(
    color-mix(in srgb, var(--indigo-bright) 55%, transparent),
    color-mix(in srgb, var(--indigo-bright) 30%, transparent) 70%,
    transparent);
}
.ob-phase {
  position: relative;
  display: grid;
  grid-template-columns: 54px 1fr;
  gap: clamp(20px, 4vw, 44px);
  padding: 6px 0 46px;
}
.ob-phase:last-child { padding-bottom: 10px; }
.ob-node {
  position: relative;
  z-index: 1;
  width: 54px;
  height: 54px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-mono);
  font-size: 16px;
  font-weight: 700;
  color: var(--indigo-lift);
  background: var(--elev);
  border: 1px solid var(--brd-strong);
  transition: background .34s ease, color .34s ease, border-color .34s ease,
    box-shadow .34s ease, transform var(--motion-hover);
}
.ob-phase:hover .ob-node {
  background: var(--indigo);
  color: var(--on-accent);
  border-color: transparent;
  box-shadow: 0 0 24px color-mix(in srgb, var(--indigo-bright) 60%, transparent);
  transform: scale(1.08);
}
.ob-wk {
  font-family: var(--font-mono);
  font-size: 12.5px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--indigo-lift);
  margin-bottom: 8px;
}
.ob-phase h3 {
  margin: 0;
  font-size: clamp(20px, 2vw, 26px);
  letter-spacing: -.015em;
  transform-origin: left center;
  transition: transform var(--motion-hover);
}
.ob-phase:hover h3 { transform: scale(1.045); }
.ob-sub {
  margin: 8px 0 0;
  color: var(--muted);
  font-size: 16px;
  line-height: 1.6;
}
.ob-list {
  list-style: none;
  padding: 0;
  margin: 18px 0 0;
  display: flex;
  flex-direction: column;
  gap: 11px;
}
.ob-list li {
  position: relative;
  padding-left: 26px;
  color: var(--muted);
  font-size: 15px;
  line-height: 1.55;
}
.ob-list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 8px;
  width: 8px;
  height: 8px;
  border-radius: 2px;
  background: var(--indigo-bright);
  box-shadow: 0 0 10px var(--indigo-bright);
}
/* Footnote under the track ("timeline is driven by scope…"). */
.ob-note {
  margin-top: 26px;
  color: var(--dim);
  max-width: 60ch;
}
@media (max-width: 520px) {
  .ob-track::before { left: 21px; }
  .ob-phase { grid-template-columns: 44px 1fr; gap: 16px; }
  .ob-node { width: 44px; height: 44px; font-size: 14px; }
}

/* Desktop: lay the five phases HORIZONTALLY across the full width so the page
   is not a tall left rail with a blank right half. Nodes sit on one horizontal
   rail; week / heading / sub / checklist stack beneath each. Mobile keeps the
   vertical rail above. */
@media (min-width: 900px) {
  .ob-track {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: clamp(16px, 2vw, 30px);
    margin-top: 30px;
  }
  .ob-track::before {
    left: 5%;
    right: 5%;
    top: 27px;
    bottom: auto;
    width: auto;
    height: 2px;
    background: linear-gradient(90deg,
      transparent,
      color-mix(in srgb, var(--indigo-bright) 45%, transparent) 10%,
      color-mix(in srgb, var(--indigo-bright) 45%, transparent) 90%,
      transparent);
  }
  .ob-phase {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    grid-template-columns: none;
    gap: 14px;
    padding: 0;
  }
  .ob-phase:last-child { padding-bottom: 0; }
  .ob-wk { margin-bottom: 0; }
  .ob-phase h3 { font-size: clamp(18px, 1.4vw, 22px); }
  .ob-sub { margin-top: 0; font-size: 15px; }
  .ob-list { margin-top: 10px; gap: 8px; }
  .ob-list li { font-size: 14px; padding-left: 22px; line-height: 1.5; }
}

/* Glance cell that holds a short phrase instead of a number keeps it readable. */
.glance-num.gl-text { font-size: clamp(26px, 3vw, 40px); letter-spacing: -.01em; line-height: 1.05; }
.glance-num.gl-text .u { display: block; font-size: .5em; color: var(--muted); letter-spacing: 0; margin-top: 4px; }

/* Onboarding glance phrase: clean two-line format. */
.glance-num.gl-text { font-size: clamp(26px, 2.8vw, 38px); line-height: 1.12; letter-spacing: -.01em; }
.glance-num.gl-text .u { display: inline; font-size: 1em; color: inherit; margin: 0; }

/* Onboarding process: bigger, more readable step text. */
@media (min-width: 900px) {
  .ob-phase h3 { font-size: clamp(20px, 1.6vw, 25px); }
  .ob-sub { font-size: 17px; }
  .ob-list li { font-size: 16px; }
  .ob-wk { font-size: 13px; }
}


/* --- ./components/bullets.css --- */
/* =============================================================================
   Bullets - two reusable list styles, one shared marker
   ============================================================================= */

.f-row .f-ico {
  position: absolute;
  width: 4px;
  height: auto;
  border-radius: 4px;
  background: var(--indigo-bright);
  box-shadow: none;
  opacity: .82;
  transform: scaleY(.36);
  transform-origin: center;
  animation: none;
  will-change: auto;
  backface-visibility: hidden;
  transition: transform var(--motion-hover), opacity .34s ease, box-shadow .34s ease;
}

.prose li:hover::before,
.f-row:hover .f-ico {
  transform: scaleY(1);
  opacity: 1;
  box-shadow: 0 0 10px color-mix(in srgb, var(--indigo-bright) 48%, transparent);
}

/* Plain bullets ------------------------------------------------------------- */
.prose ul {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.prose li {
  display: flex;
  align-items: flex-start;
  gap: 14px;
  padding: 0;
  font-size: 17px;
  line-height: 1.62;
  color: var(--muted);
  transform-origin: left center;
  backface-visibility: hidden;
  transition: transform var(--motion-hover), color .34s ease;
}

.prose li::before {
  content: "";
  flex: 0 0 13px;
  width: 13px;
  height: 2px;
  border-radius: 2px;
  background: var(--indigo-bright);
  margin-top: calc(1.62em / 2 - 1px);
  opacity: .72;
  box-shadow: 0 0 0 transparent;
  animation: none;
  transform: none !important;
  transition: opacity .34s ease, box-shadow .34s ease;
}

.prose li:hover::before {
  height: 2px;
}

.prose li:hover {
  transform: scale(1.035);
  color: var(--text);
}

/* Feature rows -------------------------------------------------------------- */
.f-list { display: block; }

.f-row {
  position: relative;
  display: block;
  padding: 20px 6px 20px 30px;
  border-bottom: 1px solid var(--line);
  background: transparent;
  transition: color .34s ease;
}

.f-row:hover { background: transparent; }

.f-row .f-ico {
  left: 8px;
  top: 20px;
  bottom: 20px;
}

.f-row h4,
.f-row .h4 {
  margin: 0;
  transform-origin: left center;
  backface-visibility: hidden;
  transition: transform var(--motion-hover), color .34s ease;
}

.f-row:hover h4,
.f-row:hover .h4 {
  transform: scale(1.045);
  color: var(--text);
}

.f-row p,
.f-row .small-t {
  margin: 6px 0 0;
  transform-origin: left center;
  backface-visibility: hidden;
  transition: transform var(--motion-hover), color .34s ease;
}

.f-row:hover p,
.f-row:hover .small-t {
  transform: scale(1.012);
}

/* Two-column editorial feature grid (Platform Orchestration / Impact lists). */
.f-2 {
  display: grid;
  grid-template-columns: 1fr 1fr;
  column-gap: 54px;
  border-top: 1px solid var(--line);
}
@media (max-width: 760px) { .f-2 { grid-template-columns: 1fr; } }
.f-2.is-spaced { margin-top: 34px; }

/* Numbered feature row: a mono index replaces the bar marker.
   Markup: <div class="f-row"><div class="f-num">01</div><div>…</div></div> */
.f-row:has(.f-num) {
  display: grid;
  grid-template-columns: 40px 1fr;
  gap: 18px;
  padding-left: 6px;
  align-items: start;
}
.f-num {
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--indigo-lift);
  padding-top: 3px;
  transform-origin: left center;
  transition: transform var(--motion-hover);
}
.f-row:hover .f-num { transform: scale(1.28); }

/* Plain variant: numbered magnify rows with no dividers (home onboarding,
   platform AI orchestration). is-onecol stacks them in a single column. */
.f-2.is-plain { border-top: 0; }
.f-2.is-plain .f-row { border-bottom: 0; }
.f-2.is-onecol { grid-template-columns: 1fr; }

/* Bigger numbers and stronger magnify on hover (match the resources numbers). */
.f-num { font-size: 17px; }
.f-row:hover .f-num { transform: scale(1.4); }
.f-row:hover h4, .f-row:hover .h4 { transform: scale(1.08); }
.f-row:hover p, .f-row:hover .small-t { transform: scale(1.03); }


/* --- ./components/platform.css --- */
/* =============================================================================
   Platform modules - the marketing blocks shared by the Home, Platform, and
   Resolution Roundtable pages: hero logo stage, process flow, pillars,
   architecture stack, horizontal marquees, connected stepper, product
   monitors, and the network hub. All token-driven; nothing page-local.
   ========================================================================== */

/* -----------------------------------------------------------------------------
   HERO LOGO STAGE (.hero-logo-stage) - the big metal wordmark over the hero.
   Static image only for now; the intro reveal video/animation is intentionally
   NOT ported yet (drop a .hero-logo-video in later when the animation lands).
   -------------------------------------------------------------------------- */
.hero-logo-stage {
  position: relative;
  z-index: 3;
  width: clamp(500px, 48vw, 760px);
  max-width: 100%;
  height: clamp(92px, 9.2vw, 145px);
  margin: 0 auto 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: visible;
}
.hero-logo-static {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  filter: drop-shadow(0 18px 42px rgba(91, 69, 240, .42));
}
/* On light backgrounds the big soft glow reads as blur - keep a tight shadow. */
[data-theme="light"] .hero-logo-static { filter: drop-shadow(0 8px 18px rgba(91, 69, 240, .16)); }

/* Oversized home headline under the logo. */
.hero-grand {
  font-size: clamp(46px, 7.2vw, 98px);
  line-height: .96;
  letter-spacing: -.045em;
  text-wrap: balance;
}

/* Hero sections that centre everything (home + platform overview). */
.section.is-hero-stage {
  min-height: 90vh;
  justify-content: center;
  position: relative;
  overflow: visible;
}
.section.is-hero-stage .eyebrow { justify-content: center; }
.hero-actions {
  margin-top: 32px;
  display: flex;
  gap: 14px;
  flex-wrap: wrap;
  justify-content: center;
}
.hero-flow {
  width: 100%;
  max-width: 980px;
  margin-top: 58px;
  text-align: left;
}

/* Hero rhythm: give the grey lead room under the gradient headline, and make
   the two hero actions equal width so Request Demo and Explore The Platform
   read as a matched pair. */
.section.is-hero-stage .hero-grand { margin-top: 8px; }
.section.is-hero-stage .lead { margin-top: 30px; }
.hero-actions .btn { min-width: 232px; }

/* Small inline brand mark (arch band, CTA windows). */
.mark-inline {
  vertical-align: middle;
  filter: drop-shadow(0 4px 12px rgba(91, 69, 240, .4));
}
.cta-shine .mark-inline { height: 46px; margin-bottom: 24px; }

/* -----------------------------------------------------------------------------
   STRIKETHROUGH EMPHASIS (.strike) - "Not another ~dashboard~" red strike.
   -------------------------------------------------------------------------- */
.strike { position: relative; color: var(--dim); white-space: nowrap; }
.strike::after {
  content: "";
  position: absolute;
  left: -3%;
  right: -3%;
  top: 54%;
  height: .085em;
  min-height: 3px;
  background: var(--danger);
  border-radius: 3px;
  transform: rotate(-3.5deg);
}

/* -----------------------------------------------------------------------------
   ARCHITECTURE STACK (.arch-band / .arch-cols) - the orchestration layer band
   above four engine columns, joined by a fading connector line.
   -------------------------------------------------------------------------- */
.arch-band {
  border: 1px solid var(--brd-hover);
  border-radius: 18px;
  background: var(--glass);
  backdrop-filter: blur(12px) saturate(140%);
  -webkit-backdrop-filter: blur(12px) saturate(140%);
  box-shadow: var(--panel-glow), inset 0 1px 0 var(--glass-hi);
  padding: 26px 28px;
  text-align: center;
}
.arch-band .mark-inline { height: 30px; }
.arch-band .small-t { max-width: 560px; margin-left: auto; margin-right: auto; }
.arch-link { display: flex; align-items: center; gap: 10px; justify-content: center; }
.arch-link span { width: 2px; height: 18px; background: linear-gradient(var(--indigo-bright), transparent); }
.arch-cols {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  border: 1px solid var(--brd);
  border-radius: 18px;
  overflow: hidden;
  background: var(--panel);
}
.arch-col { padding: 24px; transition: background .28s ease; }
.arch-col + .arch-col { border-left: 1px solid var(--line); }
.arch-col:hover { background: var(--hover); }
.arch-col .f-ico { margin-bottom: 14px; }
/* Static square marker inside arch columns (the f-ico here is not a bullet). */
.arch-col .f-ico {
  position: static;
  width: 13px;
  height: 13px;
  border-radius: 3px;
  background: var(--indigo-bright);
  box-shadow: 0 0 10px var(--indigo-bright);
  opacity: 1;
  transform: none;
}
/* "Connects to…" marquee footer under the stack. */
.arch-connects { text-align: center; margin-top: 30px; }
.arch-connects .mq-label { margin-bottom: 16px; font-size: 11px; }
@media (max-width: 860px) {
  .arch-cols { grid-template-columns: 1fr 1fr; }
  .arch-col:nth-child(3) { border-left: 0; }
  .arch-col:nth-child(n+3) { border-top: 1px solid var(--line); }
}
@media (max-width: 520px) {
  .arch-cols { grid-template-columns: 1fr; }
  .arch-col + .arch-col { border-left: 0; border-top: 1px solid var(--line); }
}

/* -----------------------------------------------------------------------------
   HORIZONTAL MARQUEE (.marquee) - seamless auto-rolling ticker (two identical
   groups translate -50%). Variants: .mq-name mono tokens with indigo dots,
   .trust-item bordered cells, .plogo partner logo strip (.pmarquee mask).
   -------------------------------------------------------------------------- */
.marquee {
  position: relative;
  overflow: hidden;
  width: 100%;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
}
.marquee + .marquee { margin-top: 14px; }
/* Speed modifiers (base 42s): .is-fast trust strip, .is-slow logo roll. */
.marquee.is-fast { --mq: 34s; }
.marquee.is-slow { --mq: 72s; }
/* Centred dim caption above a marquee strip. */
.mq-label {
  display: block;
  text-align: center;
  font-size: 11.5px;
  color: var(--dim);
  margin-bottom: 22px;
}
.marquee-track {
  display: flex;
  width: max-content;
  will-change: transform;
  animation: marqueeMove var(--mq, 42s) linear infinite;
}
.marquee:hover .marquee-track { animation-play-state: paused; }
.marquee-group {
  display: flex;
  align-items: center;
  gap: var(--mq-gap, 30px);
  padding-right: var(--mq-gap, 30px);
  flex: 0 0 auto;
}
@keyframes marqueeMove { from { transform: translateX(0); } to { transform: translateX(-50%); } }
.mq-name {
  display: inline-flex;
  align-items: center;
  gap: var(--mq-gap, 30px);
  font-family: var(--font-mono);
  font-size: 15px;
  letter-spacing: .03em;
  color: var(--muted);
  white-space: nowrap;
  font-weight: 500;
}
.mq-name::after { content: ""; width: 5px; height: 5px; border-radius: 50%; background: var(--indigo-bright); opacity: .7; }
/* Trust strip: mono cells divided by hairlines, no dot gap. */
.trust-marquee { --mq-gap: 0px; }
.trust-marquee .marquee-group { gap: 0; padding-right: 0; }
.trust-item {
  font-family: var(--font-mono);
  font-size: clamp(15px, 1.7vw, 20px);
  letter-spacing: .05em;
  color: var(--muted);
  padding: 4px 36px;
  border-right: 1px solid var(--line);
  white-space: nowrap;
}
/* Partner-logo strip: theme-swapped logo pairs, slow roll, wide fade mask. */
.plogos { width: 100%; overflow: hidden; }
.plogos .marquee-group { --mq-gap: 40px; }
.plogo { height: 84px; width: auto; display: block; opacity: .82; transition: opacity .25s; }
.plogo-light { display: none; }
[data-theme="light"] .plogo-dark { display: none; }
[data-theme="light"] .plogo-light { display: block; }
.plogo-item {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: clamp(180px, 18vw, 250px);
}
.plogo-item:hover .plogo { opacity: 1; }
.pmarquee {
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 11%, #000 89%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 11%, #000 89%, transparent);
}
.pmarquee:hover .marquee-track { animation-play-state: running; }

/* -----------------------------------------------------------------------------
   CONNECTED STEPPER (.stepper) - five nodes on a flowing line (How It Works).
   Nodes ping in sequence; the line's gradient drifts continuously.
   -------------------------------------------------------------------------- */
.stepper { position: relative; display: grid; grid-template-columns: repeat(5, 1fr); gap: 22px; }
.stepper::before {
  content: "";
  position: absolute;
  top: 19px;
  left: 2%;
  right: 18%;
  height: 2px;
  background: linear-gradient(90deg, var(--indigo-bright), var(--brd-strong), var(--indigo-bright));
  background-size: 200% 100%;
  opacity: .55;
  animation: lineFlow 6s linear infinite;
}
@keyframes lineFlow { 0% { background-position: 0% 0; } 100% { background-position: 200% 0; } }
.stp { position: relative; }
.stp-node {
  position: relative;
  z-index: 1;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--elev);
  border: 1px solid var(--brd-strong);
  color: var(--indigo-lift);
  font-family: var(--font-mono);
  font-weight: 600;
  box-shadow: 0 0 0 6px var(--bg);
}
.stp h4 { margin: 18px 0 0; }
.stp p { margin: 8px 0 0; }
@media (prefers-reduced-motion: no-preference) {
  .stp-node { animation: stpPing 3s ease-in-out infinite; }
  .stp:nth-child(1) .stp-node { animation-delay: 0s; }
  .stp:nth-child(2) .stp-node { animation-delay: .4s; }
  .stp:nth-child(3) .stp-node { animation-delay: .8s; }
  .stp:nth-child(4) .stp-node { animation-delay: 1.2s; }
  .stp:nth-child(5) .stp-node { animation-delay: 1.6s; }
  @keyframes stpPing {
    0%, 70%, 100% { box-shadow: 0 0 0 6px var(--bg), 0 0 0 0 transparent; }
    35% { box-shadow: 0 0 0 6px var(--bg), 0 0 16px 2px var(--indigo-lift); }
  }
}
@media (max-width: 760px) {
  .stepper { grid-template-columns: 1fr; gap: 0; }
  .stepper::before { display: none; }
  .stp {
    display: grid;
    grid-template-columns: 40px 1fr;
    gap: 16px;
    padding: 18px 0;
    border-top: 1px solid var(--line);
    align-items: start;
  }
  .stp h4 { margin: 8px 0 0; }
}

/* -----------------------------------------------------------------------------
   PRODUCT MONITORS (.dual / .mon) - two framed screens on a soft glow, with
   the feature grid (.pm-grid) beneath. Frame colour flips per theme
   (--mon-frame in tokens.css).
   -------------------------------------------------------------------------- */
.prod-wrap { margin-top: 30px; }
.dual {
  position: relative;
  display: flex;
  gap: 8px;
  align-items: flex-start;
  justify-content: center;
  max-width: 900px;
  margin: 0 auto;
}
.dual::before {
  content: "";
  position: absolute;
  inset: -14% -6% 0;
  z-index: 0;
  border-radius: 50%;
  background: radial-gradient(58% 60% at 50% 38%, var(--cloud-1), transparent 70%);
  filter: blur(34px);
  pointer-events: none;
}
.mon {
  position: relative;
  z-index: 1;
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.mon .mon-screen {
  position: relative;
  width: 100%;
  border: 6px solid var(--mon-frame);
  border-bottom: 15px solid var(--mon-frame);
  border-radius: 10px;
  background: var(--mon-frame);
  overflow: hidden;
  box-shadow: var(--shadow), inset 0 0 0 1px var(--brd-strong);
}
.mon .mon-screen::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: -10px;
  transform: translateX(-50%);
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--indigo-bright);
  opacity: .6;
}
.mon .mon-screen img { width: 100%; display: block; }
.mon .mon-neck { width: 13%; height: 15px; background: linear-gradient(180deg, var(--brd-strong), var(--elev)); }
.mon .mon-base { width: 36%; height: 5px; border-radius: 3px; background: var(--brd-strong); }
/* Centred "AI at every layer" caption between the monitors and the grid. */
.prod-caption { margin-top: 48px; text-align: center; }
.prod-caption .eyebrow { color: var(--indigo-lift); justify-content: center; }
.prod-caption .small-t { margin: 10px auto 30px; max-width: 56ch; }
.pm-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(20px, 3vw, 38px);
  margin-top: 10px;
}
@media (max-width: 740px) { .pm-grid { grid-template-columns: 1fr 1fr; } }
@media (max-width: 460px) { .pm-grid { grid-template-columns: 1fr; } }
.pm-cell {
  position: relative;
  padding-top: 20px;
  border-top: 2px solid var(--line);
  transition: border-color .3s ease, transform .3s cubic-bezier(.22, .61, .36, 1);
}
.pm-cell:hover { transform: translateY(-4px); border-color: var(--indigo-bright); }
.pm-cell h4 { margin: 0; transition: color .3s ease; }
.pm-cell:hover h4 { color: var(--indigo-lift); }
.pm-cell p { margin: 8px 0 0; }

/* -----------------------------------------------------------------------------
   NETWORK HUB (.hub) - Roundtable orbit: SmartSettle core, dashed rings, packet
   lines to eight participant nodes. Falls back to a 2-up list under 720px.
   -------------------------------------------------------------------------- */
.hub {
  position: relative;
  width: 100%;
  max-width: 760px;
  margin: 18px auto 0;
  aspect-ratio: 1 / 1;
}
.hub-lines { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; pointer-events: none; z-index: 0; }
.hub-lines line {
  stroke: color-mix(in srgb, var(--indigo-bright) 42%, var(--brd-strong));
  stroke-width: .12;
  stroke-dasharray: .5 1.1;
  animation: hubFlow 3.4s linear infinite;
}
.hub-lines .pkt { fill: var(--indigo-bright); r: .3px; filter: drop-shadow(0 0 1.2px var(--indigo-bright)); opacity: 1; }
.hub-lines .pkt-out { fill: #B7A6FF; }
@keyframes hubFlow { to { stroke-dashoffset: -16; } }
.hub-ring { position: absolute; border-radius: 50%; border: 1px dashed color-mix(in srgb, var(--indigo-bright) 34%, var(--brd-strong)); pointer-events: none; transform-origin: 50% 50%; }
.hub-ring.r1 { inset: 8%; opacity: .8; animation: hubSpin 46s linear infinite; }
.hub-ring.r2 { inset: 26%; border-style: solid; border-color: var(--line); animation: hubSpin 40s linear infinite; }
@keyframes hubSpin { to { transform: rotate(360deg); } }
/* Core medallion: glass disc + breathing halo behind the mark. */
.hub-core {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 34%;
  height: 34%;
  border-radius: 50%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  background: radial-gradient(circle at 50% 38%, var(--info-bg), transparent 74%);
  border: 1px solid var(--brd-hover);
  box-shadow: 0 0 60px -18px var(--indigo-bright), inset 0 1px 0 var(--glass-hi);
  backdrop-filter: blur(6px) saturate(130%);
  -webkit-backdrop-filter: blur(6px) saturate(130%);
  animation: hubBreathe 4.5s ease-in-out infinite;
}
@keyframes hubBreathe {
  0%, 100% { box-shadow: 0 0 46px -20px var(--indigo-bright), inset 0 1px 0 var(--glass-hi); }
  50% { box-shadow: 0 0 74px -12px var(--indigo-bright), inset 0 1px 0 var(--glass-hi); }
}
.hub-core img { width: 44%; max-width: 74px; filter: drop-shadow(0 8px 22px rgba(91, 69, 240, .55)); }
.hub-core b { font-size: 14px; font-weight: 800; color: var(--text); margin-top: 10px; letter-spacing: -.01em; }
/* Participant chips: small glass cards, readable at a glance. */
.hub-node {
  position: absolute;
  transform: translate(-50%, -50%);
  width: 152px;
  text-align: center;
  padding: 12px 12px 13px;
  border-radius: 14px;
  border: 1px solid var(--brd);
  background: var(--glass);
  backdrop-filter: blur(8px) saturate(135%);
  -webkit-backdrop-filter: blur(8px) saturate(135%);
  box-shadow: inset 0 1px 0 var(--glass-hi);
  transition: border-color .3s ease, transform .3s cubic-bezier(.34, 1.45, .5, 1), box-shadow .3s ease;
}
.hub-node:hover {
  transform: translate(-50%, -50%) scale(1.07);
  border-color: var(--brd-hover);
  box-shadow: 0 10px 30px -12px var(--indigo-bright), inset 0 1px 0 var(--glass-hi);
  z-index: 3;
}
.hub-node::before {
  content: "";
  display: block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  margin: 0 auto 8px;
  background: var(--indigo-bright);
  box-shadow: 0 0 12px var(--indigo-bright);
  animation: markerPulse 2.6s ease-in-out infinite;
}
@keyframes markerPulse {
  0%, 100% { opacity: .6; box-shadow: 0 0 0 transparent; }
  50% { opacity: 1; box-shadow: 0 0 13px var(--indigo-bright), 0 0 6px var(--indigo-bright); }
}
.hub-node b { display: block; font-size: 13.5px; font-weight: 700; color: var(--text); line-height: 1.25; }
.hub-node span { display: block; font-size: 11.5px; color: var(--muted); margin-top: 4px; line-height: 1.35; }
/* Node positions (clock order from 12): top, 1:30, 3, 4:30, 6, 7:30, 9, 10:30. */
.hub-node.p1 { left: 50%; top: 4.5%; }
.hub-node.p2 { left: 82.17%; top: 17.83%; }
.hub-node.p3 { left: 95.5%; top: 50%; }
.hub-node.p4 { left: 82.17%; top: 82.17%; }
.hub-node.p5 { left: 50%; top: 95.5%; }
.hub-node.p6 { left: 17.83%; top: 82.17%; }
.hub-node.p7 { left: 4.5%; top: 50%; }
.hub-node.p8 { left: 17.83%; top: 17.83%; }
.hub-fallback { display: none; }
@media (max-width: 720px) {
  /* Show the real hub visual (was hidden); the list fallback is no longer needed. */
  .hub-fallback { display: none; }
  .hub { margin-top: 8px; }
  .hub-node { width: 96px; padding: 7px 7px 8px; border-radius: 11px; }
  .hub-node b { font-size: 10.5px; line-height: 1.18; }
  .hub-node span { font-size: 9px; line-height: 1.25; margin-top: 2px; }
  .hub-node::before { width: 6px; height: 6px; margin-bottom: 5px; }
}
@media (max-width: 420px) {
  .hub-node { width: 82px; padding: 6px; }
  .hub-node b { font-size: 9.5px; }
  .hub-node span { font-size: 8px; }
}
/* Fallback rows share the aside accent bar. */
.ss-aside { border-left: 2px solid var(--indigo-bright); padding-left: 16px; }
.ss-aside b { font-size: 13px; color: var(--text); }

/* -----------------------------------------------------------------------------
   CALLOUT BAND (.callout-band) - a slim horizontal glass ribbon for secondary
   calls-to-action (e.g. Home's T+1 pointer). Icon | copy | button in one row,
   visually distinct from the big editorial insight cards.
   -------------------------------------------------------------------------- */
.callout-band {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: clamp(18px, 3vw, 34px);
  align-items: center;
  padding: clamp(20px, 2.4vw, 28px) clamp(22px, 2.6vw, 34px);
  border: 1px solid var(--brd-hover);
  border-radius: 18px;
  background: var(--glass);
  backdrop-filter: blur(10px) saturate(140%);
  -webkit-backdrop-filter: blur(10px) saturate(140%);
  box-shadow: var(--panel-glow), inset 0 1px 0 var(--glass-hi);
  text-decoration: none;
  transition: transform var(--motion-window), border-color .3s ease;
}
.callout-band:hover { transform: scale(1.012); }
.callout-band h3 {
  margin: 0;
  font-size: clamp(18px, 1.8vw, 24px);
  letter-spacing: -.015em;
  color: var(--text);
}
.callout-band p {
  margin: 6px 0 0;
  font-size: 14.5px;
  line-height: 1.55;
  color: var(--muted);
  max-width: 62ch;
}
.callout-band .btn { white-space: nowrap; }
@media (max-width: 760px) {
  .callout-band { grid-template-columns: 1fr; text-align: left; }
  .callout-band .t1-clock { display: none; }
}

/* Mono clock badge used beside the "T+1 in Europe" eyebrow. */
.eyebrow.has-clock { display: inline-flex; align-items: center; gap: 12px; }
.t1-clock {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 46px;
  height: 46px;
  border-radius: 50%;
  border: 1px solid var(--brd-strong);
  color: var(--indigo-lift);
}
.t1-clock svg { animation: t1tick 6s steps(12) infinite; transform-origin: center; }
@keyframes t1tick { to { transform: rotate(360deg); } }

/* Platform page utility visuals */
.rc-wall {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 28px;
}
.rc-wall span {
  display: inline-flex;
  align-items: center;
  min-height: 38px;
  padding: 9px 15px;
  border: 1px solid var(--brd);
  border-radius: var(--radius-pill);
  background: var(--glass);
  color: var(--muted);
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: .08em;
  text-transform: uppercase;
  transition: border-color .3s ease, color .3s ease, transform var(--motion-window);
}
.rc-wall span:hover {
  color: var(--text);
  border-color: var(--brd-hover);
  transform: var(--window-hover-transform);
}
.rc-wall.is-systems span { min-width: 150px; justify-content: center; }
.timeline-rail {
  position: relative;
  padding: clamp(28px, 3vw, 44px);
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 18px;
  align-items: center;
}
.timeline-rail .small-t { grid-column: 1 / -1; margin: 14px 0 0; text-align: center; }
.tl-stop {
  position: relative;
  z-index: 2;
  display: inline-flex;
  justify-content: center;
  align-items: center;
  min-height: 82px;
  border: 1px solid var(--brd);
  border-radius: 18px;
  background: var(--panel);
  font-family: var(--font-mono);
  font-size: clamp(26px, 3vw, 40px);
  font-weight: 800;
  color: var(--muted);
}
.tl-stop.is-now { color: var(--ok); border-color: var(--ok); box-shadow: 0 0 32px -16px var(--ok); }
.tl-stop.is-risk { color: var(--warn); border-color: var(--warn); }
.tl-line {
  position: absolute;
  left: 12%;
  right: 12%;
  top: calc(50% - 24px);
  height: 2px;
  background: var(--brd);
  overflow: hidden;
}
.tl-line i {
  display: block;
  width: 42%;
  height: 100%;
  background: linear-gradient(90deg, transparent, var(--indigo-lift), transparent);
  animation: lineFlow 4.8s linear infinite;
}
@media (max-width: 760px) {
  .timeline-rail { grid-template-columns: 1fr; }
  .tl-line { display: none; }
}


/* The header nav gap used to be set here, which meant a page stylesheet quietly
   controlled the header on every page of the site. Moved to shell/frame.css
   beside the rest of the header rules. */


/* Platform overview hero no longer carries the metal logo or the flow diagram,
   so drop the 90vh empty stage and tighten the rhythm above the monitors. */
#overview.section.is-hero-stage { min-height: auto; justify-content: flex-start; padding-block: var(--section-pad); }
#overview .hero-grand { font-size: clamp(38px, 5.2vw, 72px); }

/* ---- Two side-by-side showcase cards (Roundtable + Europe T+1). ---- */
.two-card { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(18px, 2.4vw, 28px); }
@media (max-width: 820px) { .two-card { grid-template-columns: 1fr; } }
.showcase-card { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 10px; padding: clamp(28px, 3vw, 46px); text-decoration: none; }
.showcase-card .sc-title { font-size: clamp(22px, 2vw, 28px); margin: 4px 0; letter-spacing: -.02em; }
.showcase-card .small-t { max-width: 46ch; }
.showcase-card .sc-cta { margin-top: 16px; }
.showcase-card[href] { transition: transform var(--motion-window), border-color .34s ease; }
.showcase-card[href]:hover { transform: scale(1.015); border-color: var(--brd-hover); }

/* ---- Platform monitors: 2x2 zig-zag (monitor / text, text / monitor). ---- */
.mon-grid { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(28px, 4.5vw, 72px); align-items: center; }
@media (max-width: 900px) { .mon-grid { grid-template-columns: 1fr; gap: 40px; } }
.mon-copy { display: flex; flex-direction: column; gap: clamp(26px, 3.5vw, 44px); align-items: center; text-align: center; }
.mon-block .lead { margin-top: 10px; }
.mon-block .small-t { margin-top: 8px; }

/* ---- Resolution Roundtable band: visual left, copy right-aligned right. ---- */
.rt-band { display: grid; grid-template-columns: 1fr 1fr; align-items: center; gap: clamp(24px, 4vw, 56px); padding: clamp(30px, 4vw, 56px); text-decoration: none; }
@media (max-width: 820px) { .rt-band { grid-template-columns: 1fr; } }
.rt-band-viz { display: flex; justify-content: center; }
.rt-band-viz img { max-width: 220px; width: 100%; height: auto; }
.rt-band-copy { display: flex; flex-direction: column; align-items: flex-end; text-align: right; gap: 10px; }
@media (max-width: 820px) { .rt-band-copy { align-items: flex-start; text-align: left; } }
.rt-band-copy .sec-intro { max-width: 46ch; }
.rt-band-copy .sc-cta { margin-top: 14px; }
.rt-band[href] { transition: transform var(--motion-window), border-color .34s ease; }
.rt-band[href]:hover { transform: scale(1.01); border-color: var(--brd-hover); }

/* ---- Monitor copy blocks: real headings (not spaced-out eyebrows), readable body. ---- */
.mon-copy { gap: clamp(28px, 3.5vw, 46px); }
.mon-h { font-size: clamp(20px, 1.9vw, 27px); font-weight: 600; letter-spacing: -.015em; line-height: 1.22; color: var(--text); margin: 0; }
.mon-block .lead { font-size: clamp(16px, 1.3vw, 19px); line-height: 1.55; margin-top: 10px; color: var(--muted); }
.mon-block .small-t { font-size: 16px; line-height: 1.66; margin-top: 10px; }
.mon-block .small-t + .small-t { margin-top: 8px; }

/* ---- Roundtable clock: no casing, bigger, smooth continuous spin. ---- */
.t1-clock { width: auto; height: auto; border: 0; }
.t1-clock svg { width: 30px; height: 30px; animation: t1tick 12s linear infinite; }

/* ---- Roundtable hub: bigger centered mark, dotted counter-spinning rings,
   and thin symmetrical diamonds between the parties. ---- */
.hub-core img { width: 62%; max-width: 130px; }
.hub-core b { display: none; }
.hub-ring.r3 { inset: 4.5%; border-style: dashed; border-color: color-mix(in srgb, var(--indigo-bright) 30%, var(--brd-strong)); opacity: .6; animation: hubSpin 58s linear infinite reverse; }
.hub-ring.r4 { inset: 1%; border-style: dashed; border-color: color-mix(in srgb, var(--indigo-bright) 22%, var(--brd-strong)); opacity: .45; animation: hubSpin 72s linear infinite; }
.hub-diamond { fill: none; stroke: color-mix(in srgb, var(--indigo-bright) 26%, var(--brd-strong)); stroke-width: .12; }

/* Roundtable geometry (full .hub only, NOT the homepage .hub-mini): dotted node
   ring enlarged to sit evenly between the inner dashed ring and the outer ring;
   the 8 nodes + both squares ride it; each card is anchored by its pulsing dot
   (16px from the card top) instead of its center, so the dot lands on the corner. */
.hub:not(.hub-mini) { --dot-anchor: 16px; }
.hub:not(.hub-mini) .hub-ring.r3 { inset: 4.5%; }
.hub:not(.hub-mini) .hub-node { transform: translate(-50%, calc(-1 * var(--dot-anchor))); }
.hub:not(.hub-mini) .hub-node:hover { transform: translate(-50%, calc(-1 * var(--dot-anchor))) scale(1.07); }
.hub:not(.hub-mini) .hub-node.p1 { left: 50%;    top: 4.5%; }
.hub:not(.hub-mini) .hub-node.p2 { left: 82.17%; top: 17.83%; }
.hub:not(.hub-mini) .hub-node.p3 { left: 95.5%;  top: 50%; }
.hub:not(.hub-mini) .hub-node.p4 { left: 82.17%; top: 82.17%; }
.hub:not(.hub-mini) .hub-node.p5 { left: 50%;    top: 95.5%; }
.hub:not(.hub-mini) .hub-node.p6 { left: 17.83%; top: 82.17%; }
.hub:not(.hub-mini) .hub-node.p7 { left: 4.5%;   top: 50%; }
.hub:not(.hub-mini) .hub-node.p8 { left: 17.83%; top: 17.83%; }
@media (max-width: 720px) { .hub:not(.hub-mini) { --dot-anchor: 10px; } }
@media (max-width: 420px) { .hub:not(.hub-mini) { --dot-anchor: 9px; } }

/* ============================================================
   Resolution Roundtable INTRO (roundtable .hub only; NEVER .hub-mini).
   Load: all grey + static, nothing drawn. S1: grey metal mark rises in.
   S2 = POWER ON, all in unison at one pace: mark morphs to purple; each ring
   is DRAWN by its OWN tracer particle sweeping its circumference (independent,
   each starting from a different point, tracing the ring in its trail); the two
   diamonds draw on as connections between the nodes; the straight dotted spokes
   grow out from the centre. S3 = settle: each ring hands off to its dashed
   spinning self, particles launch, spokes drift slowly + perpetually. */
@keyframes hubFlowRamp { from { stroke-dashoffset: 0; } to { stroke-dashoffset: -4; } }
.hub-mark-metal { position: absolute; left: 50%; top: 50%; width: 62%; max-width: 130px; height: auto; transform: translate(-50%, -50%) scale(.82); opacity: 0; pointer-events: none; z-index: 2; filter: grayscale(1) drop-shadow(0 8px 20px rgba(0,0,0,.4)); transition: opacity 1.1s ease, transform 1.4s cubic-bezier(.22,.9,.3,1); }

/* SVG orbit-ring scaffold (roundtable only; replaces the CSS border rings). */
.hub-rings { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; pointer-events: none; z-index: 0; }
.hub-rings circle { fill: none; }
.rt-ring, .rt-spin, .rt-draw-wrap { transform-box: view-box; transform-origin: 50% 50%; }
.hub .rt-ring.rr0 { transform: rotate(60deg); }
.hub .rt-ring.rr1 { transform: rotate(8deg); }
.hub .rt-ring.rr2 { transform: rotate(140deg); }
.hub .rt-ring.rr3 { transform: rotate(235deg); }
.hub .rt-ring.rr4 { transform: rotate(320deg); }
.rt-draw  { stroke-width: .12; stroke-linecap: round; }
.rt-final { stroke-width: .12; stroke-dasharray: .42 .5; }
.rt-ring.rr0 .rt-final, .rt-ring.rr2 .rt-final { stroke-dasharray: none; stroke-width: .12; }
.hub-core img.hub-mark-vid { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); width: 100%; max-width: 250px; height: auto; pointer-events: none; filter: drop-shadow(0 6px 18px rgba(91,69,240,.5)); }

/* ---- REST: grey, static, nothing drawn ---- */
.hub.rt-intro:not(.hub-mini) .hub-core { opacity: 0; border-color: transparent; background: none; box-shadow: none; backdrop-filter: none; -webkit-backdrop-filter: none; animation: none; transition: opacity .9s ease; }
.hub.rt-intro:not(.hub-mini) .hub-core > img.hub-mark-purple { opacity: 0; transition: opacity 1.3s ease; }
/* Static soft glow on the network lines + rings (no pulse). */
.hub.rt-intro:not(.hub-mini) .hub-spokes,
.hub.rt-intro:not(.hub-mini) .hub-diamond,
.hub.rt-intro:not(.hub-mini) .rt-final { filter: drop-shadow(0 0 2px var(--ring-pulse-glow)); }
.hub.rt-intro:not(.hub-mini) .rt-final { opacity: 0; stroke: var(--brd-strong); transition: opacity .8s ease, stroke 1.3s ease; }
.hub.rt-intro:not(.hub-mini) .rt-draw { stroke: var(--brd-strong); stroke-dasharray: 1 1; stroke-dashoffset: 1; opacity: 1; transition: stroke-dashoffset 4.8s cubic-bezier(.4,.05,.3,1), stroke 1.9s ease, opacity 1.1s ease; }
.hub.rt-intro:not(.hub-mini) .rt-spin { animation: none; }
.hub.rt-intro:not(.hub-mini) .hub-diamond { stroke: var(--brd-strong); stroke-dasharray: 1 1; stroke-dashoffset: 1; opacity: 0; transition: stroke-dashoffset 4.8s cubic-bezier(.4,.05,.3,1), stroke 1.9s ease, opacity 1.2s ease; }
.hub.rt-intro:not(.hub-mini) .hub-lines line { stroke: var(--brd-strong); stroke-width: .15; stroke-dasharray: .014 .018; opacity: 0; transform: scale(0); transform-box: view-box; transform-origin: 50% 50%; animation: none; transition: transform 4s cubic-bezier(.4,.05,.3,1), opacity 1.8s ease, stroke 1.9s ease; }
.hub.rt-intro:not(.hub-mini) .hub-node { filter: grayscale(1); opacity: .55; transition: filter 1.3s ease, opacity 1.3s ease, transform .3s cubic-bezier(.34, 1.45, .5, 1), border-color .3s ease, box-shadow .3s ease; }
.hub.rt-intro:not(.hub-mini) .hub-node::before { background: var(--brd-strong); box-shadow: none; animation: none; transition: background 1.3s ease, box-shadow 1.3s ease; }
.hub.rt-intro:not(.hub-mini) .pkt { opacity: 0; r: .2px; transition: opacity 2.2s ease; }

/* ---- STAGE 1: grey metal mark rises from nothing ---- */
.hub.rt-intro.rt-s1:not(.hub-mini) .hub-core { opacity: 1 !important; }
.hub.rt-intro.rt-s1:not(.hub-mini) .hub-mark-metal { opacity: 1 !important; transform: translate(-50%, -50%) scale(1); }
.hub.rt-intro.rt-s1:not(.hub-mini) .rt-draw { stroke-dashoffset: 0; }
.hub.rt-intro.rt-s1:not(.hub-mini) .hub-diamond { stroke-dashoffset: 0; opacity: 1; }
.hub.rt-intro.rt-s1:not(.hub-mini) .hub-lines line { opacity: 1; transform: scale(1); }

/* ---- STAGE 2: POWER ON -- draw + trace + colour, all in unison ---- */
.hub.rt-intro.rt-s2:not(.hub-mini) .hub-mark-metal { opacity: 0 !important; }
.hub.rt-intro.rt-s2:not(.hub-mini) .hub-core > img.hub-mark-purple { opacity: 1 !important; }
.hub.rt-intro.rt-s2:not(.hub-mini) .hub-core { border-color: transparent; background: none; box-shadow: none; animation: none; }
.hub.rt-intro.rt-s2:not(.hub-mini) .rr0 .rt-draw, .hub.rt-intro.rt-s2:not(.hub-mini) .rr0 .rt-final { stroke: color-mix(in srgb, var(--indigo-bright) 56%, var(--brd-strong)); }
.hub.rt-intro.rt-s2:not(.hub-mini) .rr1 .rt-draw, .hub.rt-intro.rt-s2:not(.hub-mini) .rr1 .rt-final { stroke: color-mix(in srgb, var(--indigo-bright) 56%, var(--brd-strong)); }
.hub.rt-intro.rt-s2:not(.hub-mini) .rr2 .rt-draw, .hub.rt-intro.rt-s2:not(.hub-mini) .rr2 .rt-final { stroke: color-mix(in srgb, var(--indigo-bright) 56%, var(--brd-strong)); }
.hub.rt-intro.rt-s2:not(.hub-mini) .rr3 .rt-draw, .hub.rt-intro.rt-s2:not(.hub-mini) .rr3 .rt-final { stroke: color-mix(in srgb, var(--indigo-bright) 56%, var(--brd-strong)); }
.hub.rt-intro.rt-s2:not(.hub-mini) .rr4 .rt-draw, .hub.rt-intro.rt-s2:not(.hub-mini) .rr4 .rt-final { stroke: color-mix(in srgb, var(--indigo-bright) 56%, var(--brd-strong)); }
.hub.rt-intro.rt-s2:not(.hub-mini) .hub-diamond { stroke: color-mix(in srgb, var(--indigo-bright) 56%, var(--brd-strong)); }
.hub.rt-intro.rt-s2:not(.hub-mini) .hub-lines line { stroke: color-mix(in srgb, var(--indigo-bright) 56%, var(--brd-strong)); }
.hub.rt-intro.rt-s2:not(.hub-mini) .hub-node { filter: none !important; opacity: 1 !important; }
.hub.rt-intro.rt-s2:not(.hub-mini) .hub-node::before { background: var(--indigo-bright); box-shadow: 0 0 12px var(--indigo-bright); animation: markerPulse 2.6s ease-in-out infinite; }

/* ---- STAGE 3: settle -- tracer hands off to the dashed spinning ring; particles + drift ---- */
.hub.rt-intro.rt-s3:not(.hub-mini) .rt-draw { opacity: 0; transition: opacity 1.1s ease .15s; }
.hub.rt-intro.rt-s3:not(.hub-mini) .rt-final { opacity: .85; transition: opacity 1s ease; }
.hub.rt-intro.rt-s3:not(.hub-mini) .hub-core { box-shadow: none; animation: none; }
.hub.rt-intro.rt-s3:not(.hub-mini) .rr1 .rt-spin { animation: hubSpin 46s linear infinite; }
.hub.rt-intro.rt-s3:not(.hub-mini) .rr2 .rt-spin { animation: hubSpin 40s linear infinite; }
.hub.rt-intro.rt-s3:not(.hub-mini) .rr3 .rt-spin { animation: hubSpin 58s linear infinite reverse; }
.hub.rt-intro.rt-s3:not(.hub-mini) .rr4 .rt-spin { animation: hubSpin 72s linear infinite; }
.hub.rt-intro.rt-s3:not(.hub-mini) .hub-lines line { animation: hubFlowRamp 40s ease-in 1, hubFlow 80s linear 40s infinite; }
.hub.rt-intro.rt-s3:not(.hub-mini) .pkt { opacity: 1 !important; }



/* ---- Difference: text left, bullets stacked right with icon separators. ---- */
.diff-split { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(32px, 5vw, 72px); align-items: start; }
@media (max-width: 900px) { .diff-split { grid-template-columns: 1fr; gap: 30px; } }
.pill-sep { display: flex; align-items: center; padding: 20px 0; }

/* Roundtable band: square placeholder visual, no icon. */
.rt-band-viz { aspect-ratio: 1 / 1; max-width: 260px; width: 100%; margin-inline: auto; border: 1px solid var(--brd); border-radius: 16px; background: var(--glass); }
.rt-band-viz img { display: none; }

/* One consistent, readable body size for every monitor copy block. */
.mon-block .lead, .mon-block .small-t { font-size: clamp(20px, 2.1vw, 23px); line-height: 1.62; color: var(--muted); margin-top: 12px; }
.mon-h + .lead, .mon-h + .small-t, .mon-h + .mon-tt { margin-top: 12px; }
/* Today / Tomorrow: mono label on its own line, paragraph beneath, clear gap. */
.mon-tt { margin-top: 20px; }
.mon-tt:first-of-type { margin-top: 14px; }
.mon-tt-label { display: block; font-family: var(--font-mono); text-transform: uppercase; letter-spacing: .12em; font-size: 13px; color: var(--indigo-lift); margin-bottom: 6px; }
.mon-tt .small-t { margin-top: 0; }


/* Right-aligned monitor copy cell (AI orchestration beside the first monitor). */
.mon-copy-right { text-align: center; align-items: center; }

/* Uniform hero top spacing across platform, roundtable, europe (match aux pages). */
.hero-lead { padding-top: 88px; position: relative; }
/* The aurora clips its glow to the section box; that clip edge landed right below
   the header and read as a hard "wall". Extend the aurora up behind the fixed
   header so the clip line hides under it and the glow fades in naturally. */
.hero-lead .aurora { top: calc(-1 * var(--header-h) - 40px); -webkit-mask-image: linear-gradient(to bottom, #000 55%, transparent 100%); mask-image: linear-gradient(to bottom, #000 55%, transparent 100%); }
.t1p-hero.hero-lead { align-items: start; }

/* Logo is the light source: pulsing glow follows the mark shape; disc glow dialed down */
.hub:not(.hub-mini) .hub-core { box-shadow: inset 0 1px 0 var(--glass-hi), 0 0 42px -26px var(--indigo-bright); animation: none; }


/* --- ./components/roundtable.css --- */
/* Resolution Roundtable page. The bespoke hero instrument (rt-hero/rt-stage/
   rt-ring/etc.) and the old value-prop sections (rt-statement, rf-strip,
   sw-grid, rt-t1band, rt-showcase) were superseded by the shared platform.css
   modules (hub, tl-grid, f-2) now used on this page. Only the small overrides
   below are still live. */

/* Participant value cards need real left/right padding so text is not flush to
   the card edge. */
.tl-grid > .panel { padding: clamp(22px, 2.2vw, 30px); }

/* Network copy sits below the hub visual, centered, with breathing room. */
.rt-net-copy { margin-top: clamp(96px, 9vw, 132px); }


/* --- ./components/home.css --- */
/* =============================================================================
   Home modules - the editorial blocks unique to the home page: insight cards,
   module headers, event teasers, the onboarding split, and the team band.
   All token-driven and reusable on any page that wants a teaser module.
   ========================================================================== */

/* -----------------------------------------------------------------------------
   MODULE HEADER (.mod-head) - eyebrow on the left, "All …" arrow link right.
   -------------------------------------------------------------------------- */
.mod-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 20px;
  margin-bottom: 22px;
  flex-wrap: wrap;
}
.mod-head .eyebrow { margin: 0; }
.mod-more {
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  transition: color .2s;
}
.mod-more:hover { color: var(--text); }
.mod-more svg { transition: transform .3s cubic-bezier(.22, .61, .36, 1); }
.mod-more:hover svg { transform: translateX(4px); }

/* -----------------------------------------------------------------------------
   FEATURED INSIGHT (.feat-insight) - editorial two-column teaser card: title +
   dek + byline on the left, pull-quote and tags on the right. One big link.
   -------------------------------------------------------------------------- */
.feat-insight {
  display: grid;
  grid-template-columns: 1.06fr .94fr;
  overflow: hidden;
  text-decoration: none;
  align-items: stretch;
  padding: 0 !important;   /* columns carry their own padding */
}
@media (max-width: 820px) { .feat-insight { grid-template-columns: 1fr; } }
.fi-main {
  padding: clamp(28px, 3vw, 46px);
  display: flex;
  flex-direction: column;
}
.fi-cap {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--indigo-lift);
}
.fi-title {
  margin: 18px 0 0;
  font-weight: 800;
  font-size: clamp(26px, 3vw, 40px);
  line-height: 1.08;
  letter-spacing: -.025em;
  color: var(--text);
  max-width: 16ch;
  text-wrap: balance;
}
.fi-dek {
  margin: 16px 0 0;
  font-size: 15.5px;
  line-height: 1.62;
  color: var(--muted);
  max-width: 46ch;
}
.fi-go {
  margin-top: auto;
  padding-top: 26px;
  display: inline-flex;
  align-items: center;
  gap: 11px;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--indigo-lift);
  text-decoration: none;
}
/* Hyperlink style + animation matched exactly to the thought-leadership .tl-fwd
   link: mono uppercase indigo, chevron nudges, underline GROWS FROM THE LEFT on
   hover (grows on the containing panel's hover for links inside a card). */
.hy { display: inline-flex; align-items: center; gap: 8px; font-family: var(--font-mono); font-size: 13.5px; letter-spacing: .08em; text-transform: uppercase; color: var(--indigo-lift); text-decoration: none; }
.hy-t { position: relative; }
.hy-t::after { content: ""; position: absolute; left: 0; right: 0; bottom: -2px; height: 1px; background: currentColor; transform: scaleX(0); transform-origin: left center; transition: transform .25s cubic-bezier(.5, .5, .2, 1); }
.hy:hover .hy-t::after,
.rt-home:hover .hy-t::after,
.t1-panel:hover .hy-t::after,
.feat-insight:hover .hy-t::after { transform: scaleX(1); }
.hy-chev { width: 16px; height: 16px; transition: transform .28s cubic-bezier(.5, 1.4, .5, 1); }
/* .hy-chev bounce is JS-driven (effects.js arr-bounce, now also targets .hy-chev) */
/* Featured card: read-link sits on the right under the pull-quote. */
.fi-read { align-self: flex-start; margin-top: 28px; }

.fi-side {
  position: relative;
  padding: clamp(30px, 3.4vw, 48px);
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.fi-mark {
  font-family: Georgia, 'Times New Roman', serif;
  font-size: 72px;
  line-height: .4;
  color: var(--indigo-lift);
  opacity: .55;
  transition: opacity .35s ease, text-shadow .35s ease;
}
.fi-pull {
  margin: 18px 0 0;
  font-size: clamp(24px, 2.3vw, 32px);
  line-height: 1.35;
  font-weight: 700;
  letter-spacing: -.015em;
  color: var(--text);
  text-wrap: balance;
}
.fi-pull span { color: var(--indigo-lift); transition: color .35s ease; }
.feat-insight:hover .fi-mark { opacity: .95; text-shadow: 0 0 18px rgba(129, 120, 255, .75), 0 0 44px rgba(129, 120, 255, .4); }
.feat-insight:hover .fi-pull span { animation: accentFlash .6s ease-out 1; }
@keyframes accentFlash {
  0%, 100% { color: var(--indigo-lift); text-shadow: none; }
  42% { color: var(--grad-hi); text-shadow: 0 0 13px color-mix(in srgb, var(--indigo-lift) 75%, transparent); }
}
.fi-tags { margin-top: 24px; display: flex; flex-wrap: wrap; gap: 8px; }
.fi-tag {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--muted);
  padding: 6px 12px;
  border: 1px solid var(--brd);
  border-radius: 999px;
  background: var(--panel);
}
/* Compact byline row inside the insight card. */
.byrow { display: flex; align-items: center; gap: 17px; margin-top: 24px; }
/* .byrow's headshot is a .ava now, see objects/article.css. */
.byrow b { display: block; font-size: 19.5px; line-height: 1.25; color: var(--text); font-weight: 700; }
.byrow span { display: block; font-size: 16px; color: var(--dim); line-height: 1.35; }

/* -----------------------------------------------------------------------------
   EVENT TEASERS (.evt-grid) - one featured event panel + a column of minis.
   -------------------------------------------------------------------------- */
.evt-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(26px, 4vw, 60px);
  align-items: stretch;
}
@media (max-width: 820px) { .evt-grid { grid-template-columns: 1fr; } }

/* A single event should not sit in a half-width column with empty space beside
   it, so the grid collapses to one track when there is only one card. */
.evt-grid:has(> :only-child) { grid-template-columns: 1fr; }

/* Going full width is not enough on its own: the card is a vertical stack, so
   a lone card leaves its content huddled in the top-left and the rest of the
   panel empty. On wide screens the stack becomes a banner row instead -
   status and date in a left column, title and blurb beside them, action on the
   far right - so the content spans the panel it sits in. Below the breakpoint
   the grid is already single-column and the original stack is the right shape,
   so none of this applies. */
@media (min-width: 821px) {
  /* One grid across the whole card so every element shares the same rows.
     `display: contents` dissolves the inner wrapper, which lets the button -
     a sibling of that wrapper in the markup - sit in the same grid as the text
     rather than being centred against the card as a whole.

     The status chip occupies row 1 on its own. Everything else sits in row 2,
     so the date, the name, the description and the action all centre on the
     same line as each other. Centring on the full block instead would put them
     midway between the chip and the date, which reads as misaligned. */
  .evt-grid:has(> :only-child) .evt-feat {
    display: grid;
    grid-template-columns: auto minmax(0, max-content) minmax(0, 1fr) auto;
    column-gap: clamp(22px, 3.4vw, 52px);
    row-gap: 6px;
    align-items: center;
    min-height: 0;
    padding: 30px 38px;
  }
  .evt-grid:has(> :only-child) .evt-feat > div { display: contents; }

  .evt-grid:has(> :only-child) .evt-tag     { grid-area: 1 / 1; }
  .evt-grid:has(> :only-child) .evt-when-xl { grid-area: 2 / 1; margin: 0; }
  .evt-grid:has(> :only-child) .evt-name    { grid-area: 2 / 2; margin: 0; }
  .evt-grid:has(> :only-child) .evt-loc     {
    grid-area: 2 / 3;
    margin: 0;
    max-width: none;
    font-size: 13.5px;
    line-height: 1.6;
  }
  .evt-grid:has(> :only-child) .evt-btn     { grid-area: 2 / 4; align-self: center; }
}
.evt-feat {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 26px;
  min-height: 236px;
  text-decoration: none;
}
.evt-tag {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-mono);
  font-size: 15px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--indigo-lift);
}
.evt-when-xl {
  margin: 14px 0 0;
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: clamp(20px, 2vw, 26px);
  letter-spacing: .04em;
  color: var(--indigo-lift);
}
/* Past card in the In market strip. An event that has already happened sits next
   to one you can still book, so it must not compete for the same attention: the
   purple eyebrow and date are the loudest thing on an upcoming card, and reading
   identically on a past one makes the strip look like two equal offers. Dropping
   both to the neutral grey keeps the card legible and clickable (the recording
   is still worth watching) while letting the upcoming event win the glance.
   Same treatment as the past rows on the events page, which use --dim.

   Only the TEXT goes grey. The recording pip keeps its red because .live-dot
   paints itself from var(--signal) rather than currentColor, so colour set here
   never reaches it, and nothing here touches `animation`, so it keeps pulsing. */
.evt-feat.is-past .evt-tag,
.evt-feat.is-past .evt-when-xl { color: var(--dim); }

.evt-name {
  margin: 10px 0 0;
  font-size: clamp(24px, 2.7vw, 34px);
  font-weight: 700;
  letter-spacing: -.02em;
  color: var(--text);
}
.evt-loc { margin: 8px 0 0; font-size: 14px; line-height: 1.55; color: var(--muted); max-width: 42ch; }
.evt-cta {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 14px;
  font-weight: 700;
  color: var(--text);
  text-decoration: none;
}
.evt-cta svg { transition: transform .3s cubic-bezier(.22, .61, .36, 1); }
.evt-btn { min-width: 172px; justify-content: center; }

.evt-col { display: flex; flex-direction: column; gap: 18px; }
.evt-mini {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 20px;
  align-items: center;
  text-decoration: none;
  padding: 24px 28px;
  flex: 1;
}
a.evt-mini { border-color: var(--brd-hover); }
.evt-mini .ev-date-b { text-align: center; min-width: 84px; }
.evt-mini .ev-date-b b { display: block; font-weight: 800; font-size: 24px; letter-spacing: -.01em; color: var(--text); line-height: 1.05; white-space: nowrap; }
.evt-mini .ev-date-b span {
  display: block;
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--indigo-lift);
  margin-top: 6px;
}
.evt-mini h4 { margin: 0; font-size: 20px; font-weight: 700; color: var(--text); }
.evt-mini p { margin: 8px 0 0; font-size: 16px; line-height: 1.6; color: var(--muted); }

/* -----------------------------------------------------------------------------
   SPLIT TEASER (.split2) - copy on the left, a panel on the right (Onboarding
   teaser). The mini step list (.ob-steps) lives inside the panel.
   -------------------------------------------------------------------------- */
.split2 {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(20px, 2.2vw, 38px);
  align-items: stretch;
}
@media (max-width: 820px) { .split2 { grid-template-columns: 1fr; gap: 30px; } }
.split2 .sec-title { margin-top: 14px; max-width: 19ch; letter-spacing: -.02em; }
.split2 .sec-intro { max-width: 40ch; }
.split2 .btn { margin-top: 28px; }
.split2 .panel {
  padding: clamp(20px, 2.2vw, 30px) clamp(26px, 3vw, 40px);
  align-self: stretch;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.ob-steps { display: flex; flex-direction: column; flex: 1; justify-content: space-between; }
.ob-steps .obs {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 20px;
  padding: 22px 0;
  border-top: 1px solid var(--line);
  align-items: start;
}
.ob-steps .obs:first-child { border-top: 0; }
.ob-steps .obs i { font-family: var(--font-mono); font-size: 17px; color: var(--indigo-lift); font-style: normal; padding-top: 2px; }
.ob-steps .obs b { font-size: 23px; color: var(--text); font-weight: 700; letter-spacing: -.015em; }
.ob-steps .obs p { margin: 7px 0 0; font-size: 17px; color: var(--muted); line-height: 1.6; }

/* -----------------------------------------------------------------------------
   TEAM BAND (.team-band) - centred quote, overlapping avatars, pedigree strip.
   -------------------------------------------------------------------------- */
.team-band { text-align: center; }
.team-band .eyebrow { justify-content: center; }
.team-quote {
  font-size: clamp(26px, 3.5vw, 46px);
  line-height: 1.2;
  font-weight: 700;
  letter-spacing: -.025em;
  color: var(--text);
  max-width: 26ch;
  margin: 16px auto 0;
  text-wrap: balance;
}
.team-quote span { color: var(--indigo-lift); }
.team-ava { display: flex; justify-content: center; margin-top: 24px; }
.team-ava img {
  width: 58px;
  height: 58px;
  border-radius: 50%;
  object-fit: cover;
  margin-left: -14px;
  border: 2px solid var(--bg);
  box-shadow: 0 4px 14px rgba(0, 0, 0, .3);
}
.team-ava img:first-child { margin-left: 0; }
.pedigree { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px 0; margin-top: 18px; }
.pedigree .pi {
  font-family: var(--font-mono);
  font-size: 15px;
  color: var(--text-2, var(--muted));
  padding: 3px 18px;
  border-right: 1px solid var(--line);
}
.pedigree .pi:last-child { border-right: 0; }
.team-band .btn { margin-top: 24px; }


/* -----------------------------------------------------------------------------
   ONBOARDING panel - roomier so the step list fills the window.
   -------------------------------------------------------------------------- */
.split2 > .panel { padding: clamp(30px, 3.2vw, 46px) clamp(28px, 3.4vw, 46px); display: flex; flex-direction: column; justify-content: stretch; }

/* -----------------------------------------------------------------------------
   T+1 EUROPE section (.t1-panel) - copy on the left, live countdown on the right.
   Countdown cells are transparent bordered windows to match the theme.
   -------------------------------------------------------------------------- */
.t1-panel {
  display: grid;
  grid-template-columns: 1.35fr .9fr;
  gap: clamp(24px, 3vw, 48px);
  align-items: center;
  padding: clamp(30px, 3.4vw, 48px);
  row-gap: 12px;
}
@media (max-width: 860px) { .t1-panel { grid-template-columns: 1fr; } }
.t1-copy .h2 { margin: 14px 0 0; max-width: 24ch; }
.t1-copy .lead { margin: 16px 0 0; max-width: 50ch; font-size: clamp(17px, 1.45vw, 20px); line-height: 1.65; }
.t1-actions { margin-top: 24px; }
/* London mark stands alone on the right. */
.t1-visual { display: flex; justify-content: center; align-items: center; }
.t1-mark { display: block; width: min(100%, 400px); height: auto; filter: drop-shadow(0 18px 44px rgba(0,0,0,.45)); }

/* Top row - eyebrow + live countdown, one line. Spacing below it comes from
   the panel's own grid row-gap, same as the gap between copy and visual. */
.t1-top {
  grid-column: 1 / -1;
}
.t1-top .eyebrow { display: inline-flex; align-items: center; gap: 9px; margin: 0; }
.t1-count-timer {
  color: var(--text);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  letter-spacing: normal;
  text-transform: none;
}


/* -----------------------------------------------------------------------------
   FLOW3 - hero pipeline. Three windows joined by arrows; no dividers.
   -------------------------------------------------------------------------- */
.flow3 { display: grid; grid-template-columns: 1fr auto 1fr auto 1fr; gap: 14px; align-items: stretch; margin-top: clamp(30px, 4vw, 48px); text-align: left; }
.f3 { padding: 24px 26px; display: flex; flex-direction: column; gap: 10px; }
.f3.is-core { border-color: var(--brd-strong); box-shadow: 0 0 34px -12px var(--glow-2), inset 0 1px 0 var(--glass-hi); }
.f3-k { font-family: var(--font-mono); font-size: 11px; letter-spacing: .14em; text-transform: uppercase; color: var(--indigo-lift); }
.f3-t { margin: 0; font-size: clamp(17px, 1.5vw, 20px); font-weight: 700; letter-spacing: -.015em; color: var(--text); }
.f3-d { margin: 0; font-size: 14.5px; line-height: 1.55; color: var(--muted); }
.f3-link { display: flex; align-items: center; color: var(--indigo-lift); opacity: .8; }
.f3-link svg { animation: arrBounce 2.6s cubic-bezier(.45,0,.55,1) infinite; }
@media (max-width: 900px) { .flow3 { grid-template-columns: 1fr; } .f3-link { justify-content: center; transform: rotate(90deg); } }

/* -----------------------------------------------------------------------------
   PLATFORM EXPLORER (.px-panel) - interactive tabbed window, no dividers.
   -------------------------------------------------------------------------- */
.px-panel { padding: clamp(26px, 3vw, 40px) clamp(26px, 3.2vw, 44px); }
.px-tabs { display: flex; gap: 10px; flex-wrap: wrap; }
.px-views { display: grid; margin-top: clamp(24px, 2.6vw, 36px); }
.px-copy h3 { margin: 0; font-size: clamp(22px, 2.2vw, 30px); font-weight: 700; letter-spacing: -.02em; color: var(--text); }
.px-copy p { margin: 12px 0 0; font-size: clamp(16px, 1.35vw, 18px); line-height: 1.65; color: var(--muted); max-width: 56ch; }
.px-stat { text-align: left; }
.px-stat b {
  display: block; font-weight: 800; font-size: clamp(52px, 6vw, 84px);
  letter-spacing: -.04em; line-height: 1; color: var(--text);
}
.px-stat span { display: block; margin-top: 10px; font-size: 15px; line-height: 1.55; color: var(--indigo-lift); max-width: 30ch; }

/* -----------------------------------------------------------------------------
   ARROW BOUNCE - arrows bounce while hovered; effects.js freezes the current
   offset on leave and transitions it home so it never snaps.
   -------------------------------------------------------------------------- */
@keyframes arrBounce { 0%, 100% { transform: translateX(0); } 50% { transform: translateX(6px); } }
@keyframes arrBounceBack { 0%, 100% { transform: translateX(0); } 50% { transform: translateX(-6px); } }
.tl-back .arr-bouncing { animation-name: arrBounceBack; }
.arr-bouncing { animation: arrBounce 2.2s cubic-bezier(.45,0,.55,1) infinite; }
.arr-return { transition: transform .45s cubic-bezier(.22,.61,.36,1); }


/* =============================================================================
   PROOF BAR (.proof-grid) - three count-up windows under the hero, replaces
   the retired .flow3 pipeline. Network figures only, no user counts. No
   dividers, no icons.
   ========================================================================== */
.proof-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; margin-top: clamp(30px, 4vw, 48px); text-align: left; }
.proof-cell { padding: 26px 30px; display: flex; flex-direction: column; gap: 8px; }
.proof-num { font-size: var(--fs-h2); font-weight: 800; line-height: 1; letter-spacing: -.03em; color: var(--text); font-variant-numeric: tabular-nums; }
.proof-lbl { font-family: var(--font-mono); font-size: 12.5px; letter-spacing: .1em; text-transform: uppercase; color: var(--muted); }
@media (max-width: 760px) { .proof-grid { grid-template-columns: 1fr; } }

/* =============================================================================
   EXCEPTION MONITOR DUO (.mon-duo) - two equal demo monitors, white --mon-frame
   bezel over a theme-aware screen, each carrying the S mark. LEFT: a never
   stopping exception ticker with column headers; filters type in and highlight
   matches while non-matches collapse, then backspace out and everything returns,
   all while it keeps scrolling. Communication alerts pop up now and then. RIGHT:
   one long dashboard with mixed chart types scrolling perpetually. NO dividers.
   ========================================================================== */
.mon-duo { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; align-items: start; margin-top: clamp(28px, 3.4vw, 44px); }
@media (max-width: 900px) { .mon-duo { grid-template-columns: 1fr; } }
.mon-col { display: flex; flex-direction: column; gap: 14px; min-width: 0; }

.duo-mon { background: var(--mon-frame); border-radius: 20px; padding: 7px; box-shadow: var(--panel-glow); transition: transform var(--motion-window), box-shadow var(--motion-window); min-width: 0; }
.duo-mon:hover { transform: var(--window-hover-transform); box-shadow: var(--window-hover-shadow); }
.mon-screen { background: var(--bg-2); border-radius: 14px; overflow: hidden; position: relative; height: 430px; display: flex; flex-direction: column; }

.mon-head { display: flex; align-items: center; gap: 9px; padding: 13px 18px 11px; font-family: var(--font-mono); font-size: 11px; letter-spacing: .16em; text-transform: uppercase; color: var(--dim); white-space: nowrap; flex: 0 0 auto; }
.mon-head .mon-mark { width: 32px; height: 32px; max-width: 32px; object-fit: contain; flex: 0 0 auto; }
.mon-title { color: var(--muted); font-weight: 700; }
.mon-dots { margin-left: auto; display: inline-flex; gap: 6px; }
.mon-dots i { width: 7px; height: 7px; border-radius: 50%; background: var(--brd-strong); }
.mon-dots i:first-child { background: var(--ok); box-shadow: 0 0 7px var(--ok); }

/* LEFT: query bar, column headers, ticker feed, comms alert */
/* The query line reserves TWO lines of height whether or not it needs them.

   The longest query is 45 characters and on a 320px phone it had seven pixels
   of slack, so it was one wider font away from running off the side of the
   screen. Letting it wrap solves that, but a line appearing and disappearing
   every few seconds would shove the feed underneath it up and down forever.

   Reserving the space means the second line costs nothing when it arrives: it
   drops into room that was already there, and the bezel, the margins and the
   panel height never move. The feed below is flex: 1, so it absorbs the
   difference by itself.

   display is block rather than flex on purpose. As flex children the prompt,
   the text and the caret are three columns, so a wrapped caret would sit beside
   the block instead of after the last character. Inline, the caret follows the
   text across the wrap the way a real one does. */
.mon-query {
  display: block;
  padding: 8px 18px 9px;
  font-family: var(--font-mono);
  font-size: 11.5px;
  line-height: 1.38;
  color: var(--muted);
  flex: 0 0 auto;
  min-height: calc(1.38em + 17px);
}
/* Below 900px the two monitors stack and each one gets the full column, which
   is where the long queries start to wrap. Only reserve the second line here,
   so the wider layout does not carry 17px of empty space it never uses. */
@media (max-width: 900px) {
  .mon-query { min-height: calc(2 * 1.38em + 17px); }
}
.mon-caret-pre { color: var(--indigo-lift); font-weight: 700; margin-right: 7px; }
/* normal, not nowrap: the reserved second line above is what makes this safe. */
.mon-q { color: var(--text); white-space: normal; }
.mon-caret { width: 7px; height: 12px; background: var(--indigo-lift); display: inline-block; margin-left: 2px; vertical-align: -2px; animation: monCaret 1.05s steps(1) infinite; }
@keyframes monCaret { 0%, 50% { opacity: 1; } 51%, 100% { opacity: 0; } }

.mon-cols { display: grid; grid-template-columns: 50px 74px 50px 1fr auto; gap: 12px; padding: 6px 18px 8px; font-family: var(--font-mono); font-size: 9px; letter-spacing: .14em; text-transform: uppercase; color: var(--dim); flex: 0 0 auto; }
.mon-cols-st { justify-self: end; }

.mon-feed { flex: 1; min-height: 0; overflow: hidden; position: relative; }
.mon-track { display: flex; flex-direction: column; will-change: transform; }

.mon-r { display: grid; grid-template-columns: 50px 74px 50px 1fr auto; gap: 12px; align-items: center; padding: 9px 18px; max-height: 44px; overflow: hidden; transition: max-height .45s var(--ease-reveal), opacity .4s ease, padding .45s var(--ease-reveal), background .4s ease; }
.mon-r.is-match { background: color-mix(in srgb, var(--indigo-lift) 20%, transparent); box-shadow: inset 3px 0 0 var(--indigo-lift); }
.mon-r.is-out { max-height: 0; opacity: 0; padding-top: 0; padding-bottom: 0; }
.mon-time, .mon-cp, .mon-mkt { font-family: var(--font-mono); font-size: 11px; color: var(--dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.mon-cp { color: var(--muted); }
.mon-rc { justify-self: start; font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .03em; color: var(--muted); padding: 4px 11px; border: 1px solid var(--brd-strong); border-radius: var(--radius-pill); white-space: nowrap; }
.mon-chip { justify-self: end; font-family: var(--font-mono); font-size: 9.5px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; padding: 4px 10px; border-radius: var(--radius-pill); border: 1px solid; white-space: nowrap; transition: color .45s ease, background .45s ease, border-color .45s ease; }
.st-pred    { color: var(--warn);        background: var(--warn-bg); border-color: var(--warn); }
.st-resolve { color: var(--indigo-lift); background: var(--info-bg); border-color: var(--indigo-lift); }
.st-settle  { color: var(--ok);          background: var(--ok-bg);   border-color: var(--ok); }
.st-fail    { color: var(--danger);      background: var(--danger-bg); border-color: var(--danger); }

.mon-alert { position: absolute; left: 16px; right: 16px; bottom: 14px; display: flex; align-items: center; gap: 10px; padding: 10px 14px; border-radius: 12px; background: var(--elev); border: 1px solid var(--indigo-lift); box-shadow: 0 10px 30px rgba(0,0,0,.4); color: var(--text); font-family: var(--font-mono); font-size: 11px; opacity: 0; transform: translateY(140%); transition: transform .5s var(--ease-reveal), opacity .4s ease; pointer-events: none; z-index: 3; }
.mon-alert svg { width: 15px; height: 15px; color: var(--indigo-lift); flex: 0 0 auto; }
.mon-alert.show { opacity: 1; transform: translateY(0); }

/* RIGHT: long dashboard, vertical marquee, mixed chart types */
.mon-dash { flex: 1; min-height: 0; overflow: hidden; position: relative; }
.mon-dash-track { display: flex; flex-direction: column; will-change: transform; animation: monScroll 58s linear infinite; }
@keyframes monScroll { from { transform: translateY(0); } to { transform: translateY(-50%); } }
.mon-dash:hover .mon-dash-track { animation-play-state: paused; }
.dash-unit { display: flex; flex-direction: column; gap: 20px; padding: 14px 18px 24px; }
.dash-kpis { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }
.dash-kpi { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.dash-k-l { font-family: var(--font-mono); font-size: 9px; letter-spacing: .12em; text-transform: uppercase; color: var(--dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dash-k-n { font-family: var(--font-mono); font-size: 21px; font-weight: 700; color: var(--text); line-height: 1; letter-spacing: -.02em; }
.dash-k-d { font-family: var(--font-mono); font-size: 9.5px; color: var(--dim); }
.dash-k-d.is-good { color: var(--ok); }
.dash-title { margin: 0 0 11px; font-family: var(--font-mono); font-size: 13px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }
.mon-dist { display: flex; flex-direction: column; gap: 10px; }
.mon-drow { display: grid; grid-template-columns: 116px 1fr; gap: 12px; align-items: center; }
.mon-drow span { font-family: var(--font-mono); font-size: 10.5px; color: var(--muted); white-space: nowrap; }
.mon-dbar { display: block; height: 4px; border-radius: 2px; background: var(--brd); }
.mon-dbar b { display: block; height: 100%; border-radius: 2px; background: var(--indigo-lift); }
.mon-spark { display: block; width: 100%; }
.dash-spark { height: 60px; }
.mon-spark polyline { fill: none; stroke: var(--indigo-lift); stroke-width: 1.6; opacity: .7; }
/* donut */
.dash-donut { display: flex; align-items: center; gap: 20px; }
.donut { width: 92px; height: 92px; transform: rotate(-90deg); flex: 0 0 auto; }
.donut circle { fill: none; stroke-width: 13; }
.donut-track { stroke: var(--brd); }
.donut-seg.s-ok { stroke: var(--ok); } .donut-seg.s-ind { stroke: var(--indigo-lift); } .donut-seg.s-warn { stroke: var(--warn); }
.dash-legend { display: flex; flex-direction: column; gap: 8px; }
.dash-legend .lg { font-family: var(--font-mono); font-size: 10.5px; color: var(--muted); position: relative; padding-left: 17px; white-space: nowrap; }
.dash-legend .lg::before { content: ""; position: absolute; left: 0; top: 3px; width: 9px; height: 9px; border-radius: 2px; }
.lg.s-ok::before { background: var(--ok); } .lg.s-ind::before { background: var(--indigo-lift); } .lg.s-warn::before { background: var(--warn); }
/* vertical bars */
.dash-vbars { display: flex; align-items: flex-end; gap: 8px; height: 74px; }
.dash-vbars i { flex: 1; min-width: 6px; background: var(--indigo-lift); border-radius: 3px 3px 0 0; opacity: .85; }
.dash-vbars i:last-child { background: var(--indigo-bright); opacity: 1; }
/* area chart */
.dash-area { display: block; width: 100%; height: 70px; }
.dash-area polygon { fill: var(--info-bg); }
.dash-area polyline { fill: none; stroke: var(--indigo-lift); stroke-width: 1.6; opacity: .85; }
/* penalty */
.dash-pen { display: flex; flex-direction: column; gap: 5px; }
.dash-pen span { font-family: var(--font-mono); font-size: 10.5px; color: var(--dim); }
.dash-pen b { font-family: var(--font-mono); font-size: 13px; color: var(--text); font-weight: 700; }

.mon-src { margin: 0; font-family: var(--font-mono); font-size: 12px; letter-spacing: .05em; color: var(--dim); line-height: 1.55; }

@media (max-width: 560px) {
  .mon-r, .mon-cols { grid-template-columns: 48px 1fr auto; }
  .mon-cp, .mon-mkt, .mon-cols span:nth-child(2), .mon-cols span:nth-child(3) { display: none; }
  .mon-drow { grid-template-columns: 92px 1fr; }
  .mon-screen { height: 396px; }
}
@media (prefers-reduced-motion: reduce) { .mon-dash-track { animation: none; } .mon-caret { animation: none; } .duo-mon { transition: none; } }
html.anim-off .mon-dash-track, html.anim-off .mon-caret { animation-play-state: paused; }

/* =============================================================================
   PUZZLE LOAD-IN (.pz) - above-the-fold hero + first-screen windows drop into
   place on load with a soft overshoot. JS (effects.js) adds .pz then .pz-in
   staggered, and sets the per-index direction vars. Reduced motion: no .pz.
   ========================================================================== */
.pz { opacity: 0; transform: translateY(16px); }
.pz-in { opacity: 1; transform: none; transition: opacity 1s ease, transform 1s ease; will-change: opacity, transform; }

/* =============================================================================
   T+1 LONDON MARK hover - the wrap scales up further on hover (smooth
   transition), the img floats slowly while hovered, and glides home from any
   point in the loop on leave (freeze + transition, handled in effects.js).
   ========================================================================== */
.t1-mark-wrap { display: inline-block; transition: transform .5s var(--ease-reveal); will-change: transform; }
.t1-mark-wrap.is-lift { transform: scale(1.13); }
@keyframes t1FloatY { 0%, 100% { transform: translateY(-2px); } 50% { transform: translateY(-13px); } }
.t1-mark.is-floating { animation: t1FloatY 2.8s ease-in-out infinite; }
.t1-mark.t1-return { transition: transform .6s cubic-bezier(.22, .61, .36, 1); }
@media (prefers-reduced-motion: reduce) { .t1-mark.is-floating { animation: none; } .t1-mark-wrap { transition: none; } }


/* Monitor unit: the screen sits on a stand, and the whole unit links to the
   platform page. Stand uses --mon-frame so it matches the bezel in both themes. */
.mon-unit { display: flex; flex-direction: column; align-items: center; text-decoration: none; color: inherit; }
.mon-unit .duo-mon { width: 100%; }
.mon-neck2 { width: 16%; height: 15px; background: var(--mon-frame); opacity: .92; }
.mon-base2 { width: 48%; height: 6px; border-radius: 3px; background: var(--mon-frame); opacity: .92; box-shadow: 0 8px 16px rgba(0,0,0,.28); }
.mon-src-l { color: var(--indigo-lift); text-transform: uppercase; letter-spacing: .12em; margin-right: 8px; }


/* Monitor header mark: white icon on dark, flipped to black on light theme
   (single white PNG, brightness(0) renders it solid black). */
[data-theme="light"] .mon-head .mon-mark { filter: brightness(0); }

body.index .section.is-hero-stage { min-height: 100vh; }

/* Team pages: the vertical company marquee was removed, so let the copy fill. */
.split-grid.is-hero-marquee, .split-grid.is-team-marquee { grid-template-columns: 1fr; }



/* Landing: keep a large gap between the alone hero and the body that reveals. */
body.index .container.section.is-hero-stage { margin-bottom: clamp(120px, 26vh, 300px); }

/* Home Resolution Roundtable box: mini hub left, copy right-aligned. */
.rt-home { display: grid; grid-template-columns: 220px 1fr; gap: clamp(24px, 4vw, 48px); align-items: center; padding: clamp(28px, 3.6vw, 46px); text-decoration: none; transition: transform var(--motion-window), border-color .3s ease; }
.rt-home:hover { transform: scale(1.012); border-color: var(--brd-hover); }
@media (max-width: 760px) { .rt-home { grid-template-columns: 1fr; } }
.rt-home-copy { text-align: right; }
.rt-home-copy .h2 { margin-bottom: 0; }
.rt-home-copy .lead { margin-top: 14px; }
.rt-home-copy .t1-actions { display: flex; justify-content: flex-end; margin-top: 16px; }
@media (max-width: 760px) { .rt-home-copy { text-align: left; } .rt-home-copy .t1-actions { justify-content: flex-start; } }
.hub-mini { width: 200px; max-width: 200px; aspect-ratio: 1 / 1; margin: 0 auto; }

/* Onboarding teaser: button near the text, bullets bigger and filling the height. */
.split2 > div:first-child { display: flex; flex-direction: column; align-items: flex-start; }
.split2 .btn { margin-top: 22px; }
.split2 .f-2.is-onecol { justify-content: space-between; }
.split2 .f-2.is-onecol .h4 { font-size: 20px; }
.split2 .f-2.is-onecol .small-t { font-size: 16px; }
.split2 .f-2.is-onecol .f-num { font-size: 18px; }

/* Trusted partnerships: bigger label and bigger logos. */
.data-label.mq-label { font-size: 15px; letter-spacing: .16em; }
.plogo { max-width: 260px; }
.plogo[src*="ssc-advent"] { height: 54px; }

/* Landing: near-normal gap between hero and body (hero is a full-viewport
   centered header; body reveals on scroll). */
body.index .container.section.is-hero-stage { margin-bottom: 0; }

/* Onboarding teaser: button sits right under the copy, columns top-aligned. */
.split2 > div:first-child { display: block; }
.split2 .btn { margin-top: 24px; }
.split2 .f-2.is-onecol { justify-content: flex-start; }

/* Mini hub magnifies on hover in the home Roundtable box. */
.hub-mini { transition: transform var(--motion-hover); }
.rt-home:hover .hub-mini { transform: scale(1.06); }

/* Kill the load flash: hide [data-pz] before the JS runs (js class is set in
   an early head script), reveal via .pz-in; reduced motion shows them. */
html.enter.js [data-pz] { opacity: 0; }
html.js [data-pz].pz-in { opacity: 1; }
@media (prefers-reduced-motion: reduce) { html.js [data-pz] { opacity: 1; } }

/* Home hero: fill exactly the viewport below the fixed header so the space
   above the logo equals the space below the buttons (true vertical center). */
body.index .container.section.is-hero-stage { min-height: calc(100vh - var(--header-h)); justify-content: safe center; padding-block: clamp(48px, 7vh, 130px); }

/* Bare buttons: no casing, label + arrow only. */
.btn.is-bare { border: 0; background: transparent; box-shadow: none; padding-left: 0; padding-right: 0; }
.btn.is-bare:hover { background: transparent; }
/* rt-home / t1-panel arrows now use the SAME hover bounce as every other arrow
   (effects.js adds .arr-bouncing at 2.2s). The old fast arrNudge loop bounced
   quicker and clipped at the panel edge, so it's removed for consistency. */

/* Home arrows adopt the thought-leadership feature-card purple, EXCEPT arrows
   inside buttons, which inherit the button's text colour (white on primary). */
body.index .arr { color: var(--indigo-lift); }
body.index .btn .arr { color: currentColor; }

/* Mini hub: node dots only, rings keep spinning, magnify more on hover. */
.hub-mini { width: 220px; max-width: 220px; }
.hub-mini .hub-node { width: auto; padding: 0; border: 0; background: none; box-shadow: none; -webkit-backdrop-filter: none; backdrop-filter: none; }
.hub-mini .hub-node b, .hub-mini .hub-node span { display: none; }
.hub-mini .hub-node::before { margin: 0; width: 6px; height: 6px; }
.hub-mini .hub-core { width: 42%; height: 42%; }
/* The metallic mark inside the homepage Resolution Roundtable card. Scoped to
   .hub-mini so the full-size hub on /platform and the roundtable page are
   untouched. Base rule is 62% capped at 130px (platform.css). */
.hub-mini .hub-core img { width: 72%; max-width: 100px; }
.rt-home:hover .hub-mini { transform: scale(1.1); }

/* Featured insight caption + event date bigger; section links bigger. */
.fi-cap { font-size: 15px; letter-spacing: .04em; }
.evt-when-xl { font-size: clamp(30px, 3vw, 44px); }
.mod-head .btn-ghost { font-size: 16px; padding: 10px 18px; }


/* Whole-page reveal: sections rise and fade in smoothly and slowly. */
html.js .site .container.section.rv { opacity: 0; will-change: opacity; }
html.js .site .container.section.rv.rv-in { opacity: 1; transition: opacity .9s ease; }
@media (prefers-reduced-motion: reduce) { html.js .site .container.section.rv { opacity: 1; transform: none; } }

/* 'Explore the platform' button under the monitors, with clear separation
   before the Resolution Roundtable section. */
.mon-cta { display: flex; justify-content: center; margin-top: clamp(30px, 4vw, 48px); margin-bottom: 0; }


/* Onboarding teaser layout (home + platform).
   Button sits tight under the paragraph. The step column matches the left
   column height and space-between spreads the four steps from the TOP OF THE
   HEADING (padding clears the eyebrow) down to the BOTTOM OF THE BUTTON.
   A smaller column gap pulls the steps left. */
.split2 > div:first-child { display: block; }
.split2 .sec-intro { margin-bottom: 0; }
.split2 .btn { margin-top: 14px; }
.split2 .f-2.is-onecol {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding-top: 38px;   /* clears the eyebrow so step 1 aligns with the heading top */
}
.split2 .f-2.is-onecol .f-row { padding: 0; border-bottom: 0; }

/* Home onboarding only: widen the left column and let the heading use more width
   so it wraps into fewer lines, shrinking the whole section. (Platform onboarding
   keeps its own balance.) */
/* Above the 820px collapse point ONLY. Without the query this rule sits after
   the `@media (max-width: 820px) { .split2 { grid-template-columns: 1fr } }`
   rule at the top of this file, wins on source order at any width, and holds
   the two columns side by side on a phone, which pushes the right column off
   the edge of the screen. */
@media (min-width: 821px) {
  body.index .split2 { grid-template-columns: 1.22fr .78fr; }
}
body.index .split2 .sec-title { max-width: 28ch; }


/* --- ./pages/reception.css --- */
/* =============================================================================
   Reception page, October 1 2026 (co-hosted with Abacus).

   Save as src/styles/pages/reception.css and add
     @import url("/styles/pages/pages/reception.css");
   to src/styles/index.css AFTER ./components/home.css and BEFORE
   ./effects/effects.css. The order matters: two rules in here deliberately
   out-rank home.css's scroll-reveal rule, and the reduced-motion backstop in
   effects/reduced-motion.css must stay last in the file as it is today.

   Every colour is a token. The two hard-coded purples (#5333EC light,
   #9C8CFF dark) are the SmartSettle icon fill and its trace stroke: they are
   the logo's own brand colours and must not follow the theme accent if that
   ever changes. They are commented in place.

   Dead rules from earlier drafts were removed programmatically (a selector is
   dropped only when one of its classes appears nowhere in the markup and is
   never added by script) and the result was pixel-verified against the
   approved mock. See HANDOFF.md, "How I verified".
   ========================================================================== */

.ab-cta-lockup { display: flex; align-items: center; justify-content: center; gap: 22px; }
/* Date, time and place directly under the h1, one plain line with pipe
   separators (the Dreamforce / Money20/20 pattern). Text colour, no label
   styling, no chip. */
.ab-when { display: flex; align-items: center; flex-wrap: wrap; gap: 6px 0; margin: 16px 0 0; font-size: 18px; font-weight: 600; letter-spacing: 0; color: var(--muted); }
.ab-when-sep { display: inline-block; width: 1.5px; height: 1em; margin: 0 .75em; background: var(--eyebrow); border-radius: 1px; }
.sec-head .ab-when { max-width: none; }
/* Hamburger widths: the three facts stack, and the divider turns on its side,
   same length and weight, between the rows. */
@media (max-width: 1079px) {
  .ab-when { flex-direction: column; align-items: flex-start; gap: 0; }
  .ab-when-sep { width: 1em; height: 1.5px; margin: 10px 0; }
}
.sec-head .ab-when + .lead { margin-top: 16px; }
@media (max-width: 640px) {
  .ab-when { font-size: 17px; }
}
#register { padding-top: 40px; }
.ab-draws { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: clamp(18px, 2.6vw, 40px); margin-top: 0; }
.ab-bullet { position: relative; padding: 24px 22px; text-align: center; transform-origin: center; transition: transform var(--motion-hover); }
.ab-bullet .h4 { margin: 0; font-size: 20px; transition: color .45s ease; }
.ab-bullet:hover .h4 { color: var(--eyebrow); }
.ab-bullet .small-t { margin: 8px 0 0; font-size: 16px; }
.ab-trace { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; pointer-events: none; }
.ab-trace path { fill: none; stroke: var(--eyebrow); stroke-width: 1.6px; stroke-linecap: round; vector-effect: non-scaling-stroke; stroke-dasharray: 100 100; stroke-dashoffset: 91; transition: stroke-dashoffset .62s cubic-bezier(.4, 0, .2, 1); }
.ab-bullet:hover { transform: scale(1.035); }
.ab-bullet:hover .ab-trace path { stroke-dashoffset: 0 !important; }
@media (max-width: 1079px) {
  .ab-draws { grid-template-columns: 1fr; gap: 14px; }
  .ab-bullet { text-align: left; padding: 18px 16px; margin-left: -16px; }
  .ab-trace path { stroke-dashoffset: 94; }
  .ab-trace .ab-trace-b { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .ab-bullet, .ab-trace path { transition: none; }
  .ab-bullet:hover { transform: none; }
}
/* Room between the date line and the headline. */
.sec-head .ab-when + .h1 { margin-top: 26px; }
/* The h1 follows the intro wrapper, not the date line, so the sibling rule
   above no longer reaches it. Same gap as h1 to lead (30px). */
.ab2-head .ab2-intro + .h1 { margin-top: 30px; }
/* CTA lockup: the two-tone SmartSettle logo and the horizontal Abacus logo.
   Marks are matched by height (SmartSettle's icon fills 90% of its box, the
   Abacus mark 99%, hence the 37px box) and the Abacus wordmark was rebuilt at
   the same cap height as ours. Wordmarks take the page text colour in light
   mode and white in dark; the icon purples follow the theme tokens. */
.ab-cta-lockup { display: flex; align-items: center; justify-content: center; gap: 22px; flex-wrap: wrap; }
.ab-cta-ss, .ab-cta-ab { display: inline-flex; transition: transform var(--motion-hover); }
.ab-cta-ss { height: 40px; }
.ab-cta-ab { height: 37px; }
.ab-cta-ss svg, .ab-cta-ab svg { height: 100%; width: auto; }
.ab-cta-ss:hover, .ab-cta-ab:hover { transform: scale(1.04); }
.ab-ss .ab-ss-icon { fill: #5333EC; }
.ab-ss .ab-ss-word { fill: var(--text); }
[data-theme="dark"] .ab-ss .ab-ss-icon { fill: #9C8CFF; }
[data-theme="dark"] .ab-ss .ab-ss-word { fill: #FFFFFF; }
.ab-abacus-h .ab-word { fill: var(--text); }
[data-theme="dark"] .ab-abacus-h .ab-word { fill: #FFFFFF; }
/* Draw-in, once, when the CTA lockup scrolls into view. Nothing in the
   lockup is visible until then. Every path (the two SmartSettle blades, the
   twelve SmartSettle letters, the three Abacus chevrons, the six Abacus
   letters) is traced at the same pace with stroke-dashoffset, then fills.
   The x arrives last: grows from nothing, spins in and settles with a
   bounce. Independent of the hover effects. Disabled under reduced motion. */
.js .ab-cta-lockup .ab-ss-icon, .js .ab-cta-lockup .ab-mark-p, .js .ab-cta-lockup .ab-letter { fill-opacity: 0; stroke-linecap: round; stroke-linejoin: round; stroke-dasharray: 100 100; stroke-dashoffset: 100; }
/* Stroke widths in each SVG's own units (no non-scaling-stroke: that makes
   Chrome measure the dash in screen pixels and breaks pathLength). About 1px. */
.ab-cta-lockup .ab-ss-icon, .ab-cta-lockup .ab-ss-word { stroke-width: 4.5; }
.ab-cta-lockup .ab-mark-p { stroke-width: 20; }
.ab-cta-lockup .ab-abacus-h .ab-word { stroke-width: 5.6; }
/* letters sit in a 3.56x scaled group */
.ab-cta-lockup .ab-ss-icon { stroke: #5333EC; }
[data-theme="dark"] .ab-cta-lockup .ab-ss-icon { stroke: #9C8CFF; }
.ab-cta-lockup .ab-ss-word { stroke: var(--text); }
[data-theme="dark"] .ab-cta-lockup .ab-ss-word { stroke: #FFFFFF; }
.ab-cta-lockup .ab-abacus-h .ab-word { stroke: var(--text); }
[data-theme="dark"] .ab-cta-lockup .ab-abacus-h .ab-word { stroke: #FFFFFF; }
.ab-cta-lockup.is-drawn .ab-ss-icon, .ab-cta-lockup.is-drawn .ab-mark-p, .ab-cta-lockup.is-drawn .ab-letter { animation: abTrace 3.6s cubic-bezier(.3, .05, .55, 1) forwards, abFill 1.6s cubic-bezier(.4, 0, .3, 1) 3.3s forwards; }
@keyframes abTrace { to { stroke-dashoffset: 0; } }
@keyframes abFill { to { fill-opacity: 1; stroke-opacity: 0; } }
.ab-x-wrap { display: inline-flex; transform-origin: center; }
.js .ab-x-wrap { opacity: 0; transform: scale(2.6) rotate(135deg); }
.ab-cta-lockup.is-drawn .ab-x-wrap { animation: abXIn 1.6s cubic-bezier(.2, .9, .3, 1) 3.9s forwards; }
/* Stamp-in: the x drops from large and turned, lands with a squash, and
   settles. The blur sells the drop; filter is cheap on a 34px box. */
@keyframes abXIn {
  0%   { opacity: 0; transform: scale(2.6) rotate(135deg); filter: blur(3px); }
  55%  { opacity: 1; transform: scale(.86) rotate(-10deg); filter: blur(0); }
  72%  { transform: scale(1.1) rotate(5deg); }
  86%  { transform: scale(.97) rotate(-2deg); }
  100% { opacity: 1; transform: scale(1) rotate(0deg); }
}
@media (prefers-reduced-motion: reduce) {
  .js .ab-cta-lockup .ab-ss-icon, .js .ab-cta-lockup .ab-mark-p, .js .ab-cta-lockup .ab-letter { fill-opacity: 1; stroke: none; stroke-dasharray: none; animation: none !important; }
  .js .ab-x-wrap { opacity: 1; transform: none; animation: none !important; }
}

/* The x between the logos: two bars, the same construction as the header
   menu toggle in its open state. They fold in from a flat pair on load. The
   whole x spins a half turn with a spring when the window is hovered, and
   spins back when the pointer leaves. Purple follows the theme, same values
   as the SmartSettle icon beside it. */
.ab-x { position: relative; width: 34px; height: 34px; flex: 0 0 auto; transform-origin: center; transition: transform .75s cubic-bezier(.34, 1.56, .64, 1); }
.ab-x span { position: absolute; left: 3px; right: 3px; top: 50%; height: 2.4px; margin-top: -1.2px; border-radius: 1px; background: var(--eyebrow); }
.ab-x span:nth-child(1) { transform: rotate(45deg); }
.ab-x span:nth-child(2) { transform: rotate(-45deg); }
.cta-shine:hover .ab-x { transform: rotate(180deg) scale(1.1); }
@media (prefers-reduced-motion: reduce) {
  .ab-x, .ab-x span { animation: none; transition: none; }
  .cta-shine:hover .ab-x { transform: none; }
}
@media (max-width: 1079px) {
  .ab-cta-lockup { flex-direction: column; gap: 18px; }
}
@media (max-width: 640px) {
  .ab-cta-ss { height: 32px; }
  .ab-cta-ab { height: 30px; }
}
/* The three draws: plain f-rows with the accent bar, no step numbers, because
   these are not a sequence. */
.ab-draws { padding-top: 38px; }
.ab-draws .f-row .h4 { font-size: 20px; }
.ab-draws .f-row .small-t { font-size: 16px; }
#register { scroll-margin-top: 90px; }
/* =============================================================================
   Load sequence variant. The page opens with an empty body. The lockup
   traces in at the top, centred; then the hero copy rises in line by line,
   the three draws follow, "Registration is live" lands with the pulsing
   dot, and only then do the back link, the form and the CTA appear.
   ========================================================================== */
.ab2-hero .sec-head.center { max-width: 820px; }
.ab2-lockup { justify-content: center; margin: 12px 0 34px; }
/* v3: the lockup, eyebrow and date line ARE the hero. Logos at h1 height,
   the two lines scaled with them. Stacked widths step back down. */
.ab2-lockup .ab-cta-ss { height: clamp(44px, 5.8vw, 76px); }
.ab2-lockup .ab-cta-ab { height: clamp(41px, 5.4vw, 70px); }
.ab2-lockup .ab-x { width: clamp(34px, 4.4vw, 58px); height: clamp(34px, 4.4vw, 58px); }
.ab2-head .ab2-eyebrow { font-size: clamp(18px, 3vw, 40px); margin-bottom: 20px; }
.ab2-head .ab-when { font-size: clamp(11px, 1.47vw, 19.6px); font-family: var(--font-mono); font-weight: 700; letter-spacing: .2em; text-transform: uppercase; }
/* The line is set to break after the time on purpose: date and time on the
   first row, the place on its own row beneath. The divider that would sit at
   the end of the first row is dropped, because a rule hanging at a line break
   reads as a hyphen. Below the hamburger breakpoint all three facts stack and
   both dividers come back, turned on their side. */
/* Two rows, always: date and time on the first, the place on the second.
   The divider that belongs between them lives in the second row and is shown
   only once the line stacks, where it becomes the third horizontal rule. */
.ab2-head .ab2-when-2 { margin-top: 10px; }
.ab2-head .ab-when-stack { display: none; }
@media (max-width: 1079px) {
  .ab2-head .ab2-when-2 { margin-top: 0; }
  .ab2-head .ab-when-stack { display: block; }
}
.ab2-head .ab-when-sep { height: .9em; }
.ab2-lockup { margin-bottom: 44px; flex-wrap: nowrap; gap: 22px; }
/* The head is as wide as the container so the big lockup sits on one line;
   the grey paragraph keeps its reading measure. */
.ab2-hero .sec-head.center.ab2-head { max-width: none; }
.ab2-head .lead { max-width: 820px; }
@media (max-width: 1079px) {
  .ab2-lockup { flex-wrap: wrap; }
}
.ab2-head .ab2-intro + .lead { margin-top: 30px; }
/* 30px from the All events link to the top of the logos: the same distance
   the webinar page keeps between its All events link and its date label. */
.ab2-backrow { text-align: left; margin-bottom: 26px; }
.ab2-hero { position: relative; }
/* HERO START POSITION, matched to /events/29-july-webinar/ by measurement.
   That page's hero section carries a flat 56px top padding, so its All events
   link sits at y=148 at every width and its purple meta line at y=196. This
   page was inheriting --section-pad instead, a clamp that resolves to 76px at
   1280 and 48px at 390, which put the back link 20px too low on desktop and
   8px too high on a phone. Flat 56 here reproduces the webinar exactly, and
   because the 26px .ab2-backrow margin already gives the same 30px gap, the top
   of the logo lockup lands on the webinar's meta line without moving anything
   else. The selector has to out-rank .page-body > section, hence the tag. */
.page-body > section.ab2-hero { padding-top: 56px; }

.ab2-head .ab2-eyebrow { color: var(--text); margin: 0 0 14px; }
.ab2-head .ab-when { justify-content: center; color: var(--eyebrow); }
/* Dividers and the x pulse in step with the live dot. */
/* The x as one drawn shape (one SVG path, two strokes), so the colour and
   glow breathe as a single entity rather than two overlapping bars. */
.ab-x-svg svg { width: 100%; height: 100%; display: block; overflow: visible; }
.ab-x-svg path { fill: none; stroke: var(--eyebrow); stroke-width: 2.4; stroke-linecap: round; }
/* Phase B of the reveal: the eyebrow settles in from wide, blurred tracking;
   the date line then builds left to right, each fact fading up and each
   divider growing out of its centre. Different in kind from the rise used
   for everything after it. */
.js .ab2-eyebrow { opacity: 0; letter-spacing: .7em; filter: blur(5px); transition: opacity 1s ease, letter-spacing 1.3s cubic-bezier(.2, .8, .2, 1), filter 1s ease; }
.ab2-eyebrow.is-in { opacity: 1; letter-spacing: .2em; filter: blur(0); }
/* Slower and softer than it was. .6s read as hasty against the long fall the
   lines are making underneath it. */
.js .ab2-when > span { opacity: 0; transform: translateY(6px); transition: opacity 1.15s ease, transform 1.25s cubic-bezier(.22, .8, .24, 1); }
.js .ab2-when > .ab-when-sep { transform: scale(0); transition: transform .95s cubic-bezier(.22, .8, .24, 1); }
.ab2-when.is-in > span { opacity: 1; transform: none; }
.ab2-when.is-in > .ab-when-sep { transform: scale(1); }
/* No per-part stagger: both purple lines and every divider in them fade in
   together, at the same rate, at the same moment. */
.ab2-head .ab-when { font-size: clamp(11px, 1.47vw, 19.6px); font-family: var(--font-mono); font-weight: 700; letter-spacing: .2em; text-transform: uppercase; }
/* The line is set to break after the time on purpose: date and time on the
   first row, the place on its own row beneath. The divider that would sit at
   the end of the first row is dropped, because a rule hanging at a line break
   reads as a hyphen. Below the hamburger breakpoint all three facts stack and
   both dividers come back, turned on their side. */
/* Two rows, always: date and time on the first, the place on the second.
   The divider that belongs between them lives in the second row and is shown
   only once the line stacks, where it becomes the third horizontal rule. */
.ab2-head .ab2-when-2 { margin-top: 10px; }
.ab2-head .ab-when-stack { display: none; }
@media (max-width: 1079px) {
  .ab2-head .ab2-when-2 { margin-top: 0; }
  .ab2-head .ab-when-stack { display: block; }
}
.ab2-head .ab-when-sep { width: 2px; height: .9em; border-radius: 1px; background: var(--dim); }
@media (max-width: 1079px) {
  .ab2-head .ab-when-sep { width: 1em; height: 2px; }
}
@media (prefers-reduced-motion: reduce) {
  .ab2-head .ab-when-sep, .ab2-lockup .ab-x span { animation: none; }
}
.ab2-head .h1 { text-wrap: balance; }
.ab2-head .lead { margin-left: auto; margin-right: auto; }
/* 64px from the lead to the bullet titles and 64px from the bullet text to the next section. */
.ab2-hero .sec-head.ab2-head { margin-bottom: 0; }
.ab2-draws { padding-top: 0; margin-top: 40px; margin-bottom: 2px; }
/* The body rearranges at the same width the header and footer do, so the change
   is eased rather than snapped. Only properties that are cheap to animate are
   listed: gap and padding move, the grid track count itself cannot be
   transitioned and does not need to be, because the eased gap and padding carry
   the eye through the reflow. Excluded under reduced motion by the site-wide
   backstop in effects/reduced-motion.css. */
.ab2-draws, .ab-draws { transition: gap .42s cubic-bezier(.22,.61,.36,1), margin-top .42s cubic-bezier(.22,.61,.36,1); }
.ab2-draws .ab-bullet, .ab-draws .ab-bullet { transition: padding .42s cubic-bezier(.22,.61,.36,1), margin-left .42s cubic-bezier(.22,.61,.36,1), text-align .01s; }
.ab2-lockup, .ab-lockup-static { transition: gap .42s cubic-bezier(.22,.61,.36,1); }
.ab2-hero { text-align: center; }
/* The reveal itself: every piece starts down and clear, rises into place. */
/* The reveal itself: each piece rises and comes into focus (a soft blur
   clearing as it lands) on a long expo curve, so it unfolds rather than pops. */
.js .ab2-in { opacity: 0; visibility: hidden; transform: translateY(22px); filter: blur(6px); transition: opacity 1s ease, transform 1.3s cubic-bezier(.16, 1, .3, 1), filter 1s ease, visibility 0s 1.3s; }
.ab2-in.is-in { opacity: 1; visibility: visible; transform: none; filter: blur(0); transition-delay: 0s, 0s, 0s, 0s; }
/* Late sections (form, CTA). Specificity matches the site's .rv reveal rule
   and sits after it, so this owns the fade; without that the .rv-in rule
   snapped them to opacity 1 on intersection. */
html.js .site .container.section.ab2-late { animation: none; opacity: 0; visibility: hidden; transform: translateY(26px); filter: blur(6px); transition: opacity 1.2s ease, transform 1.5s cubic-bezier(.16, 1, .3, 1), filter 1.2s ease, visibility 0s 1.5s; }
html.js .site .container.section.ab2-late.is-in { opacity: 1; visibility: visible; transform: none; filter: blur(0); transition-delay: 0s, 0s, 0s, 0s; }
/* Below the fold the section also waits for the site's own scroll reveal
   (.rv-in), so it fades in as it enters the viewport instead of already
   sitting there at full opacity. */
html.js .site .container.section.ab2-late.is-in:not(.rv-in) { opacity: 0; visibility: hidden; transform: translateY(26px); filter: blur(6px); }
/* And once the site has marked it revealed, it still hides again on replay
   (this outranks the site's .rv.rv-in rule by one class). */
html.js .site .container.section.ab2-late.rv-in:not(.is-in) { opacity: 0; visibility: hidden; transform: translateY(26px); filter: blur(6px); }

/* Intro stage: the lockup, eyebrow and date line are one group. On load the
   script transforms the group to the centre of the viewport, enlarged, and
   plays the reveal there. After a hold it eases back to its real place and
   size (transform only, so the layout never moves), and only then does the
   rest of the page rise in. */
/* No will-change here on purpose: a pinned compositor layer is rasterised
   once at 1x and then only stretched, which is the blur seen on phones. Left
   alone, Chrome re-rasterises the SVGs at the staged scale once they are still. */
.ab2-intro > * { transform-origin: center center; }
/* Release, piece by piece. The lockup leads on a curve with a small overshoot;
   the eyebrow follows 140ms behind, the date line 280ms behind that. The
   eyebrow keeps its own settle-in transitions alongside the travel, so it
   still fades and tightens into place during phase one. A brief blur rides
   each piece while it travels and clears as it lands. */
/* The four transform transitions that used to live here are gone. The release
   is no longer four blocks moving: every line is driven individually from
   site.js, on the translate and scale properties, so these pieces never carry an
   inline transform for a transition to act on. The eyebrow keeps its own
   opacity, tracking and blur transition, which is still doing real work. */
.ab2-intro.is-live > .ab2-eyebrow { transition: transform 1.7s cubic-bezier(.16, 1, .3, 1) .14s, opacity 1s ease, letter-spacing 1.3s cubic-bezier(.2, .8, .2, 1), filter 1s ease; }
/* The second purple row is its own element and its own intro piece, so it
   travels home 140ms behind the first exactly the way the eyebrow trails the
   lockup. It is done this way, rather than as an offset applied to a child at
   landing, because an offset has to appear from somewhere: applied in CSS it
   displaces the row through the whole of phase one, applied in script at the
   moment of landing it lands as a visible jump. Both were tried. */
/* The motion-blur trail, retimed to the fall it is meant to trail. It was 1.7s
   with delays up to .42s, tuned to the old four-piece release; against a 1050ms
   fall that left the blur still clearing long after the lines had landed. The
   delays now track roughly when each container's contents actually move: the
   lockup holds beats 0 and 1, the eyebrow beat 2, the first date row beats 3 to
   5, the second row beats 6 and 7. */
.ab2-intro.is-landing > .ab2-lockup { animation: ab2Trail 1.15s ease both; }
.ab2-intro.is-landing > .ab2-eyebrow { animation: ab2Trail 1.08s ease .14s both; }
.ab2-intro.is-landing > .ab2-when { animation: ab2Trail 1.05s ease .21s both; }
.ab2-intro.is-landing > .ab2-when-2 { animation: ab2Trail .94s ease .42s both; }
@keyframes ab2Trail { 0% { filter: blur(0); } 30% { filter: blur(1.6px); } 100% { filter: blur(0); } }
@media (prefers-reduced-motion: reduce) {
  .ab2-intro > * { animation: none !important; transition: none !important; }
}
/* Register section: its eyebrow, title, line and panel reveal the same way as
   the hero pieces (rise, blur clearing), a beat apart, and only once the
   section is in view (the site's .rv-in) AND the sequence has reached it. */
.js .ab2-gate:not(.rv-in) .ab2-in.is-in { opacity: 0; visibility: hidden; transform: translateY(22px); filter: blur(6px); }
html.js .site .container.section.ab2-gate { animation: none; transition: none; }
html.js .site .container.section.ab2-gate.rv { opacity: 1; }
/* Registration swap. The window never goes away: it holds its height, the form
   settles out, the window eases down to fit the confirmation, and the
   confirmation rises in. Height is animated only while .is-swapping is on, so
   the panel's own reveal transition is untouched the rest of the time. */
.ab2-gate .panel.is-swapping { contain: layout paint; }
/* The window's spotlight and its blurred diagonal sheen are switched off while
   the height is animating. They are two full-size painted layers, one of them
   blurred, and repainting both on every frame of a 620ms collapse is the
   difference between smooth and not. Neither is visible mid-swap anyway. */
.ab2-gate .panel.is-swapping::before, .ab2-gate .panel.is-swapping::after { display: none; }
/* The site has no .ss-form[hidden] rule, and .ss-form { display: flex } is an
   author rule, so it beats the browser's [hidden] and a hidden form keeps its
   space. Without this the confirmation would appear under a still-visible form
   and the window would collapse to the wrong height. Scoped to this page so it
   does not depend on the site-wide fix; that fix is still worth making, see
   the phase 1 list. */
.ab2-gate .ss-form[hidden] { display: none; }
.js .ab2-gate .ss-form { transition: opacity .3s ease, transform .38s cubic-bezier(.4, 0, .2, 1); }
.ab2-gate .ss-form.is-out { opacity: 0; transform: translateY(-8px); pointer-events: none; }
/* The register title and its line sit inside the window, above the form, and
   leave with it. Sized to the confirmation's own title and body so the window
   reads as one thing before and after the swap. The status eyebrow stays
   outside the window, top right. */
.ab2-gate .ab2-gate-top { display: flex; justify-content: flex-start; margin-bottom: 14px; }
.ab2-gate .ab-reg-head .sec-title { margin-top: 0; font-size: var(--fs-h3); line-height: 1.18; letter-spacing: -.02em; }
.ab2-gate .ab-reg-head .sec-intro { margin-top: 10px; font-size: var(--fs-body); line-height: 1.74; }
.js .ab2-gate .ab-reg-head { transition: opacity .3s ease, transform .38s cubic-bezier(.4, 0, .2, 1); }
.ab2-gate .ab-reg-head.is-out { opacity: 0; transform: translateY(-8px); pointer-events: none; }
.ab2-gate .ab-reg-head[hidden] { display: none; }
/* The confirmation sits centred in the window. The site's .form-success padding
   is deliberately lopsided (44 top, 12 bottom) because it normally appears
   under a submit button that is still taking up room. Here the window collapses
   around it instead, so the padding is the panel's and it is even. */
.ab2-gate .form-success { padding: 0; }
.ab2-gate .panel.is-done { padding: clamp(34px, 3.6vw, 48px) 28px; }
.js .ab2-gate .form-success > * { opacity: 0; transform: translateY(12px); }
.ab2-gate .form-success.is-shown > * { opacity: 1; transform: none; transition: opacity .6s ease, transform .7s cubic-bezier(.16, 1, .3, 1); }
.ab2-gate .form-success.is-shown > *:nth-child(2) { transition-delay: .1s; }
.ab2-gate .form-success.is-shown > *:nth-child(3) { transition-delay: .2s; }
/* The window's own hover magnify, restored. .ab2-in.is-in pins transform to
   none at the same specificity as .panel:hover and lands after panels.css, so
   the register window was lighting up without magnifying. */
.ab2-gate .panel.ab2-in.is-in:hover { transform: var(--window-hover-transform); }
@media (prefers-reduced-motion: reduce) {
  .ab2-gate .panel.is-swapping, .js .ab2-gate .ss-form, .ab2-gate .form-success > * { transition: none; }
  .js .ab2-gate .form-success > * { opacity: 1; transform: none; filter: none; }
}
/* Review controls, top right of the hero: a HubSpot arm/disarm switch and the
   replay. Both are temporary. Delete the .ab2-tools block from the markup and
   these rules once the page is linked from the site. With the switch gone the
   form posts normally, because the gate reads true when the button is absent. */
.ab2-tools { position: fixed; top: 104px; right: 20px; z-index: 90; }
/* The four controls collapse into one dropdown so they read as a single review
   affordance rather than a toolbar competing with the page. Built on <details>
   so open and close need no script: the phase 2 deletion stays a single markup
   block plus these rules, exactly as before. */
.ab2-tools > summary { list-style: none; user-select: none; }
.ab2-tools > summary::-webkit-details-marker { display: none; }
.ab2-tools-toggle { gap: 7px; }
.ab2-tools-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--muted); transition: background .25s ease; }
/* The dot turns purple whenever the HubSpot switch inside is armed, so the
   closed state still says whether a submission would post for real. */
.ab2-tools:has([data-hs-toggle][aria-pressed="true"]) .ab2-tools-dot { background: var(--eyebrow); }
.ab2-tools-chev { width: 13px; height: 13px; transition: transform .28s cubic-bezier(.2, .9, .3, 1); }
.ab2-tools[open] .ab2-tools-chev { transform: rotate(180deg); }
.ab2-tools-menu { position: absolute; top: calc(100% + 8px); right: 0; min-width: 190px; display: flex; flex-direction: column; align-items: stretch; gap: 6px; padding: 10px; border-radius: 14px; border: 1px solid var(--brd); background: var(--elev); box-shadow: 0 18px 40px -18px rgba(0,0,0,.45); }
.ab2-tools-menu .ab2-btn, .ab2-tools-menu .ab-replay { width: 100%; justify-content: flex-start; gap: 8px; }
.ab2-tools-menu .ab-replay { padding: 0 13px; }
@starting-style { .ab2-tools[open] .ab2-tools-menu { opacity: 0; transform: translateY(-6px); } }
.ab2-tools-menu { transition: opacity .22s ease, transform .28s cubic-bezier(.2, .9, .3, 1); }
/* The replay icon keeps its spin on hover, but the button is now a full row, so
   spinning the whole row would tilt the label with it. Spin just the icon. */
.ab2-tools-menu .ab2-replay:hover { transform: none; }
.ab2-tools-menu .ab2-replay svg { transition: transform var(--motion-hover); }
.ab2-tools-menu .ab2-replay:hover svg { transform: rotate(-40deg); }
.ab2-btn, .ab-replay { position: static; height: 32px; display: inline-flex; align-items: center; justify-content: center; border-radius: 999px; border: 1px solid var(--brd); background: var(--panel); color: var(--muted); cursor: pointer; font-family: var(--font-mono); font-size: 10px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; transition: color .25s ease, border-color .25s ease, opacity .25s ease, transform var(--motion-hover); }
.ab2-btn { padding: 0 13px; }
.ab-replay { width: 32px; padding: 0; }
.ab2-tools-menu .ab-replay { width: 100%; }
.ab-replay svg { width: 15px; height: 15px; }
.ab2-btn:hover, .ab-replay:hover { color: var(--eyebrow); border-color: var(--brd-hover); }
.ab2-btn:focus-visible, .ab-replay:focus-visible { outline: 2px solid var(--eyebrow); outline-offset: 3px; }
.ab2-replay:hover { transform: rotate(-40deg); }
.ab2-btn[disabled] { opacity: .4; cursor: default; }
.ab2-btn[disabled]:hover { color: var(--muted); border-color: var(--brd); }
.ab2-hs { gap: 9px; padding-left: 10px; }
.ab2-sw { position: relative; flex: none; width: 28px; height: 15px; border-radius: 999px; background: var(--brd); transition: background .25s ease; }
.ab2-sw-knob { position: absolute; top: 2px; left: 2px; width: 11px; height: 11px; border-radius: 50%; background: var(--muted); transition: transform .25s cubic-bezier(.2, .9, .3, 1), background .25s ease; }
.ab2-hs[aria-pressed="true"] { color: var(--eyebrow); border-color: var(--eyebrow); }
.ab2-hs[aria-pressed="true"] .ab2-sw { background: var(--eyebrow); }
.ab2-hs[aria-pressed="true"] .ab2-sw-knob { transform: translateX(13px); background: #FFFFFF; }
@media (max-width: 1079px) { .ab2-tools { top: 100px; right: 12px; } }
/* Replay reset: everything fades out together, flat, no stagger and no
   per-child delays, before the sequence restarts. */
#main.ab2-reset .ab2-in, #main.ab2-reset .ab2-gate .ab2-in, #main.ab2-reset .ab2-b, #main.ab2-reset .ab2-when > *, #main.ab2-reset .ab2-late, #main.ab2-reset .ab2-lockup .ab-x-wrap { transition-duration: .4s !important; transition-delay: 0s !important; }
#main.ab2-reset .ab2-lockup .ab-ss-icon, #main.ab2-reset .ab2-lockup .ab-mark-p, #main.ab2-reset .ab2-lockup .ab-letter { transition: fill-opacity .4s ease, stroke-opacity .4s ease; }
/* Lockup hover stays; the hover spin needs a hover target: the hero lockup itself. */
.ab2-lockup:hover .ab-x { transform: rotate(180deg) scale(1.1); }
/* Static lockup in the CTA: same sizes, always visible, no draw-in. */
.ab-lockup-static { display: flex; align-items: center; justify-content: center; gap: 22px; flex-wrap: wrap; }
.ab-lockup-static .ab-cta-ss, .ab-lockup-static .ab-cta-ab { display: inline-flex; transition: transform var(--motion-hover); }
.ab-lockup-static .ab-cta-ss { height: 40px; }
.ab-lockup-static .ab-cta-ab { height: 37px; }
.ab-lockup-static .ab-cta-ss:hover, .ab-lockup-static .ab-cta-ab:hover { transform: scale(1.04); }
.ab-lockup-static .ab-x-static { opacity: 1; transform: none; }
.ab-ss-static .ab-ss-icon { fill: #5333EC; }
.ab-ss-static .ab-ss-word { fill: var(--text); }
[data-theme="dark"] .ab-ss-static .ab-ss-icon { fill: #9C8CFF; }
[data-theme="dark"] .ab-ss-static .ab-ss-word { fill: #FFFFFF; }
.ab-ab-static .ab-word { fill: var(--text); }
[data-theme="dark"] .ab-ab-static .ab-word { fill: #FFFFFF; }
@media (max-width: 1079px) {
  .ab2-draws .ab-bullet { text-align: center; margin-left: 0; padding: 22px 16px; }
  .ab2-draws .ab-trace path { stroke-dashoffset: 91; }
  .ab2-draws .ab-trace .ab-trace-b { display: block; }
}
@media (max-width: 1079px) {
  .ab2-lockup { flex-direction: column; gap: 16px; }
  .ab-lockup-static { flex-direction: column; gap: 16px; }
  .ab2-head .ab-when { align-items: center; }
}
@media (prefers-reduced-motion: reduce) {
  .js .ab2-in, html.js .site .container.section.ab2-late, .js .ab2-eyebrow, .js .ab2-when > span { opacity: 1; visibility: visible; transform: none; filter: none; filter: none; letter-spacing: .2em; transition: none; }
  .js .ab2-when > .ab-when-sep { transform: none; transition: none; }
}

/* =============================================================================
   DATE LINE SIZE IN HAMBURGER MODE
   Once the page is in hamburger mode the date line reads 10% larger.

   This lives at the END of the file deliberately. `.ab2-head .ab-when` is
   declared twice earlier with identical content, once around line 161 and again
   around line 226, so an override placed between them is silently beaten by the
   second copy at equal specificity. Anything that needs to win has to come after
   both. The duplicate pair is worth collapsing one day; until then, do not move
   this block up.

   Both rows share this one selector, so date, time and place scale together and
   cannot drift apart. Measured before the change: both rows were already
   identical to each other, IBM Plex Mono 700 at 18.816px on desktop and 11px at
   390, in the same face as the eyebrow above them. Nothing needed unifying,
   only enlarging.
   ========================================================================== */
@media (max-width: 1079px) {
  .ab2-head .ab-when { font-size: clamp(12.1px, 1.617vw, 21.56px); }
}

/* =============================================================================
   ITEM 4: THE EYEBROW TWO-LINE FLASH ON A PHONE

   "NYC Cocktail Reception" starts its reveal at .7em tracking and animates in
   to .2em. At 390px the string at .7em is far wider than the 348px column, so
   it wrapped to two lines, then snapped back to one partway through the
   animation. That snap is the roughly 0.2s flash.

   Two guards, because either alone is not enough:

   white-space: nowrap makes the two-line state impossible at any tracking. On
   its own it would just trade the wrap for horizontal overflow.

   So the start tracking is also reduced below the breakpoint, to a value the
   column can hold at the widest moment of the animation. The effect still reads
   as letters drawing together, just over a shorter distance, which is the only
   honest option on a narrow screen: there is no room for the wide version.
   ========================================================================== */
.ab2-head .ab2-eyebrow { white-space: nowrap; }
@media (max-width: 1079px) {
  /* :not(.is-in) matters. Without it this also beats the settled rule at equal
     specificity, because it comes later in the file, and the tracking never
     animates at all on a phone. Scoped this way it only sets where the reveal
     STARTS from; .ab2-eyebrow.is-in still lands it at .2em. */
  .js .ab2-eyebrow:not(.is-in) { letter-spacing: .26em; }
}

/* The review dropdown no longer holds the tuning panel, but keep it able to
   grow: it still carries four controls and their labels. */
.ab2-tools-menu { min-width: 200px; }


/* --- ./pages/platform-page.css --- */
/* Platform page. Unique visuals for /platform/, composed from tokens. */

/* Outreach demo window */
.odemo { display: grid; align-content: space-between; gap: 14px; padding: 24px; }
.odemo-head { display: flex; align-items: center; gap: 10px; font-family: var(--font-mono); font-size: 12px; letter-spacing: .14em; text-transform: uppercase; color: var(--indigo-lift); }
.odemo-mail { border: 1px solid var(--brd); border-radius: 14px; padding: 16px 18px; background: var(--bg-2); display: grid; gap: 9px; font-family: var(--font-mono); font-size: 13.5px; color: var(--muted); }
.odemo-mail .to b { color: var(--text); font-weight: 400; }
.odemo-body { min-height: 44px; line-height: 1.55; color: var(--dim); }
.odemo-status { display: flex; gap: 10px; align-items: center; }
.odemo-step { font-family: var(--font-mono); font-size: 11px; letter-spacing: .12em; text-transform: uppercase; border: 1px solid var(--brd); color: var(--dim); border-radius: 999px; padding: 5px 12px; transition: all .4s var(--ease-reveal); }
.odemo.s0 .odemo-step.d0, .odemo.s1 .odemo-step.d1, .odemo.s2 .odemo-step.d2 { color: var(--ok); border-color: var(--ok); background: var(--ok-bg); }
.odemo-sub { color: var(--dim); font-size: 14px; line-height: 1.55; }

/* Inventory and prediction rail */
.trail-svg { display: block; width: 100%; height: auto; overflow: visible; }
.trail-line { stroke: var(--brd-strong); stroke-width: 2; }
.trail-draw { stroke: var(--indigo-bright); stroke-width: 2.4; stroke-dasharray: 1; stroke-dashoffset: 1; transition: stroke-dashoffset 1.6s var(--ease-reveal); }
.io-in .trail-draw { stroke-dashoffset: 0; }
.trail-stop circle { fill: var(--elev); stroke: var(--brd-strong); stroke-width: 2.4; }
.trail-stop.hot circle { stroke: var(--indigo-bright); filter: drop-shadow(0 0 12px var(--indigo-bright)); }
.trail-pulse { fill: none; stroke: var(--indigo-bright); stroke-width: 2; opacity: 0; }
.io-in .trail-pulse { animation: trailPulse 2.6s ease-out infinite; }
@keyframes trailPulse { 0% { transform: scale(.4); opacity: .8; } 70% { transform: scale(2.1); opacity: 0; } 100% { opacity: 0; } }
html.anim-off .trail-pulse { animation-play-state: paused; }
.trail-t { fill: var(--text); font-size: 30px; font-weight: 700; text-anchor: middle; }
.trail-l { fill: var(--muted); font-family: var(--font-mono); font-size: 13.5px; letter-spacing: .1em; text-transform: uppercase; text-anchor: middle; }
.trail-zone { fill: var(--warn-bg); stroke: var(--warn); stroke-width: 1.2; stroke-dasharray: 5 6; opacity: .8; }
.trail-zl { fill: var(--warn); font-family: var(--font-mono); font-size: 13.5px; letter-spacing: .1em; text-transform: uppercase; text-anchor: middle; }
.trail-note { margin-top: 10px; text-align: center; color: var(--dim); font-family: var(--font-mono); font-size: 12.5px; letter-spacing: .12em; text-transform: uppercase; }

/* Connections */
.conn-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; max-width: 980px; margin-inline: auto; }
.conn { display: grid; gap: 6px; padding: 20px 22px; text-align: left; }
.conn b { font-family: var(--font-mono); font-size: 15px; letter-spacing: .1em; text-transform: uppercase; color: var(--text); font-weight: 400; }
.conn span { color: var(--dim); font-size: 14.5px; }

/* Getting connected strip */
.gc-strip { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0; position: relative; max-width: 1100px; margin-inline: auto; }
.gc-stop { position: relative; padding: 26px 22px 6px; }
.gc-stop::before { content: ""; position: absolute; top: 0; left: 0; right: 0; height: 2px; background: var(--brd-strong); }
.gc-stop::after { content: ""; position: absolute; top: -4px; left: 0; width: 10px; height: 10px; border-radius: 50%; background: var(--indigo-bright); box-shadow: 0 0 12px var(--indigo-bright); }
.gc-line { position: absolute; top: 0; left: 0; height: 2px; width: 0; background: var(--indigo-bright); transition: width 1.8s var(--ease-reveal); z-index: 1; }
.io-in .gc-line { width: 100%; }
.gc-stop .num { font-family: var(--font-mono); font-size: 12px; letter-spacing: .14em; color: var(--indigo-lift); }
.gc-stop h3 { margin: 8px 0 6px; font-size: 20px; }
.gc-stop p { margin: 0; color: var(--muted); font-size: 15.5px; line-height: 1.55; }

/* Outcomes pivot */
.pivot { max-width: 880px; margin-inline: auto; padding: 24px clamp(18px, 2.4vw, 30px); }
.pivot-tabs { display: flex; gap: 8px; margin-bottom: 20px; flex-wrap: wrap; }
.pv-row { display: grid; grid-template-columns: .55fr 1fr auto; gap: 16px; align-items: center; }
.pv-row span { font-family: var(--font-mono); font-size: 13px; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }
.pv-bar { height: 10px; border-radius: 999px; background: rgba(255,255,255,.05); overflow: hidden; }
.pv-bar b { display: block; height: 100%; width: 0; border-radius: 999px; background: linear-gradient(90deg, var(--indigo), var(--indigo-bright)); transition: width 1.1s var(--ease-reveal); }
.pv-n { font-family: var(--font-mono); font-size: 13px; color: var(--indigo-lift); font-variant-numeric: tabular-nums; }
.pivot-note { margin-top: 18px; color: var(--dim); font-size: 15px; }

/* T+1 band */
.t1-band { display: grid; grid-template-columns: auto 1fr auto; gap: clamp(18px, 3vw, 40px); align-items: center; padding: 26px clamp(20px, 3vw, 38px); max-width: 1100px; margin-inline: auto; }
.t1-band img { height: 74px; width: auto; }
.t1-band-chip { font-family: var(--font-mono); font-size: 12px; letter-spacing: .12em; text-transform: uppercase; color: var(--indigo-lift); }
.t1-band p { margin: 6px 0 0; color: var(--text); font-size: clamp(18px, 1.6vw, 22px); line-height: 1.45; }

@media (max-width: 1050px) {
  .gc-strip { grid-template-columns: repeat(2, 1fr); gap: 26px 0; }
  .conn-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 680px) {
  .gc-strip, .conn-grid { grid-template-columns: 1fr; }
  .t1-band { grid-template-columns: 1fr; text-align: left; }
}
@media (prefers-reduced-motion: reduce) {
  .trail-pulse { animation: none; }
}

/* =============================================================================
   Platform page - reimagined instruments (pl-*). Token-driven, light/dark aware.
   Reveals key on the site's .io-in (added by [data-io] in effects.js).
   ========================================================================== */

/* Layout shells */
.pl-split{display:grid;grid-template-columns:1fr 1fr;gap:clamp(28px,4vw,60px);align-items:center}
.pl-split2{display:grid;grid-template-columns:.82fr 1.18fr;gap:clamp(22px,3vw,40px);align-items:center}
.pl-split .sec-head{margin-bottom:0}
.sec-head.is-centered{margin-inline:auto;text-align:center;max-width:880px}
.sec-head.is-right{text-align:right}
.sec-head.is-right .eyebrow{justify-content:flex-end}

/* Instrument reveal (soft fade-up; inner animations play on .io-in) */
.pl-layerstack,.pl-ledger,.pl-resolver,.pl-matrix,.pl-t1{
  opacity:0;transform:translateY(18px);
  transition:opacity var(--dur-slow) var(--ease-reveal),transform var(--dur-slow) var(--ease-reveal);
}
.pl-layerstack.io-in,.pl-ledger.io-in,.pl-resolver.io-in,.pl-matrix.io-in,.pl-t1.io-in{opacity:1;transform:none}

/* Shared SVG ink (theme aware) */
.pl-dial text{font-family:var(--font-mono)}
.pl-hair{stroke:var(--brd)}
.pl-ink-indigo{stroke:var(--indigo-bright)}
.pl-ink-lift{stroke:var(--indigo-lift)}
.pl-ink-warn{stroke:var(--warn)}
.pl-svg-text{fill:var(--text)}
.pl-svg-lift{fill:var(--indigo-lift)}
.pl-svg-dim{fill:var(--dim)}
.pl-svg-danger{fill:var(--danger)}
.pl-lg-indigo{fill:var(--indigo-bright)}
.pl-lg-lift{fill:var(--indigo-lift)}
.pl-lg-warn{fill:var(--warn)}

/* ---- One layer: interactive stack, no card. Hover lifts a participant. ---- */
.pl-layerstack{display:flex;justify-content:center;padding:20px 0 40px;min-height:300px}
.pl-stack{position:relative;width:440px;height:230px;max-width:100%}
.pl-tab{font-family:var(--font-mono);font-size:11px;letter-spacing:.08em;color:var(--dim);text-transform:uppercase}
.pl-unified-in{text-align:center}
.pl-u-main{font-weight:700;font-size:17px;color:var(--text);letter-spacing:-.01em}
.pl-u-sub{font-family:var(--font-mono);font-size:11px;color:var(--indigo-lift);letter-spacing:.06em;margin-top:6px}

/* ---- Golden truth: reconcile your record vs each counterparty, field by field ---- */
.pl-ledger{border-radius:var(--radius-lg);border:1px solid var(--brd-strong);background:var(--elev);
  box-shadow:var(--shadow);padding:20px 22px;min-height:300px}
.pl-lhead{display:flex;align-items:center;gap:8px;font-family:var(--font-mono);font-size:11px;color:var(--muted);
  letter-spacing:.08em;text-transform:uppercase;padding-bottom:12px;border-bottom:1px solid var(--brd)}
.pl-lcount{margin-left:auto;color:var(--dim);text-transform:none}
.pl-t0{margin-left:12px;color:var(--indigo-lift);border:1px solid var(--brd-hover);border-radius:6px;padding:2px 7px}
.pl-cmp-cols,.pl-row{display:grid;grid-template-columns:96px 1fr 1fr 20px;align-items:center;gap:12px}
.pl-cmp-cols{padding:12px 0 6px;font-family:var(--font-mono);font-size:10px;letter-spacing:.06em;text-transform:uppercase;color:var(--dim)}
.pl-row{padding:9px 0;border-bottom:1px solid var(--line);font-family:var(--font-mono);font-size:12.5px}
.pl-k{color:var(--dim);letter-spacing:.04em;text-transform:uppercase;font-size:10.5px}
.pl-ours{color:var(--text)}
.pl-theirs{color:var(--muted);transition:color .3s}
.pl-row.checking .pl-theirs{color:var(--indigo-lift)}
.pl-row.bad .pl-theirs{color:var(--danger)}
.pl-chk{width:18px;height:18px;border-radius:50%;border:1px solid var(--brd);position:relative;justify-self:end}
.pl-row.checking .pl-chk{border-color:var(--warn)}
.pl-row.checking .pl-chk::after{content:"";position:absolute;inset:4px;border-radius:50%;background:var(--warn)}
.pl-row.ok .pl-chk{border-color:var(--ok);background:var(--ok-bg)}
.pl-row.ok .pl-chk::after{content:"";position:absolute;left:6px;top:3px;width:4px;height:8px;border:solid var(--ok);border-width:0 2px 2px 0;transform:rotate(45deg)}
.pl-row.bad .pl-chk{border-color:var(--danger);background:var(--danger-bg)}
.pl-row.bad .pl-chk::before,.pl-row.bad .pl-chk::after{content:"";position:absolute;left:8px;top:4px;width:1.6px;height:9px;background:var(--danger);border-radius:2px}
.pl-row.bad .pl-chk::before{transform:rotate(45deg)}
.pl-row.bad .pl-chk::after{transform:rotate(-45deg)}
.pl-verdict{min-height:44px;margin-top:14px}
.pl-ok,.pl-flag{display:none;align-items:center;gap:10px;padding:11px 13px;border-radius:var(--radius-md);font-size:12px;color:var(--text)}
.pl-ok{background:var(--ok-bg);border:1px solid var(--ok)}
.pl-flag{background:var(--danger-bg);border:1px solid var(--danger)}
.pl-rd{width:11px;height:11px;border-radius:50%;flex:0 0 auto}
.pl-ok .pl-rd{background:var(--ok)}
.pl-flag .pl-rd{background:var(--danger)}

/* ---- Signature: root-cause resolver dial (keeps re-locking on the live cause) ---- */
.pl-resolver{display:flex;flex-direction:column;align-items:center;padding:20px 24px 26px}
.pl-dial{width:100%;max-width:660px;height:auto}
.pl-beam{stroke:var(--warn)}
.pl-reason-box{fill:var(--danger-bg);stroke:var(--danger);stroke-opacity:.5}
.pl-dial g.pl-ring{transform-box:view-box;transform-origin:230px 185px}
.pl-dial-cap{max-width:560px;text-align:center;margin:14px auto 0;color:var(--muted);font-size:var(--fs-small)}

/* ---- T+1: the silver London mark ---- */
.pl-t1{display:grid;grid-template-columns:1.05fr .95fr;gap:clamp(28px,4vw,56px);align-items:center}
.pl-t1-copy .sec-title{margin-top:8px}
.pl-t1-art{display:flex;justify-content:center}
.pl-t1-art .t1-mark{width:min(100%,380px)}

/* ---- Analytics: counterparty x root-cause heat matrix, with counts + legend ---- */
.pl-matrix{padding:24px}
.pl-mx-head{font-family:var(--font-mono);font-size:11px;color:var(--dim);text-transform:uppercase;letter-spacing:.08em;margin:0 0 14px}
.pl-mx-grid{display:grid;grid-template-columns:96px repeat(5,1fr);gap:6px;align-items:center}
.pl-colh{font-family:var(--font-mono);font-size:9.5px;color:var(--dim);letter-spacing:.02em;text-transform:uppercase;text-align:center;line-height:1.2}
.pl-rowh{font-family:var(--font-mono);font-size:11px;color:var(--muted);text-align:right;padding-right:8px}
.pl-mx-foot{display:flex;justify-content:space-between;align-items:center;gap:16px;margin-top:16px;flex-wrap:wrap}
.pl-mx-legend{display:inline-flex;align-items:center;gap:8px;font-family:var(--font-mono);font-size:10.5px;color:var(--dim)}
.pl-mx-ramp{width:80px;height:8px;border-radius:3px;background:linear-gradient(90deg,transparent,var(--indigo-bright))}
.pl-mx-call{display:inline-flex;align-items:center;gap:8px;font-family:var(--font-mono);font-size:10.5px;color:var(--warn)}
.pl-mx-call::before{content:"";width:12px;height:12px;border-radius:3px;border:1.6px solid var(--warn)}

/* ---- Today / tomorrow ---- */
.pl-today,.pl-tomorrow{position:relative}
.pl-today{display:flex;flex-direction:column;justify-content:center;gap:14px;min-height:280px;padding:clamp(26px,3vw,40px)}
.pl-today-line{font-size:var(--fs-h3);line-height:1.3;color:var(--text);font-weight:500;letter-spacing:-.01em;margin:0}
.pl-tomorrow > .eyebrow{margin-bottom:12px}
.pl-tomorrow .rt-stage{margin:0}
.pl-tag{position:absolute;top:16px;right:18px;font-family:var(--font-mono);font-size:10px;letter-spacing:.1em;text-transform:uppercase;padding:3px 9px;border-radius:6px;z-index:4}
.pl-tag.live{color:var(--ok);background:var(--ok-bg);border:1px solid var(--ok)}
.pl-tag.dev{color:var(--indigo-lift);background:var(--info-bg);border:1px solid var(--brd-hover)}

@media (max-width:900px){
  .pl-split,.pl-split2,.pl-t1{grid-template-columns:1fr}
  .pl-stack{width:100%}
  .sec-head.is-right{text-align:left}
  .sec-head.is-right .eyebrow{justify-content:flex-start}
}

@media (prefers-reduced-motion:reduce){
  .pl-layerstack,.pl-ledger,.pl-resolver,.pl-matrix,.pl-t1{opacity:1;transform:none}
}

/* Keep the Roundtable's outside seat labels inside the narrower platform column */
.pl-tomorrow .rt-instrument{max-width:600px;margin-inline:auto;display:block}
.pl-tomorrow .rt-stage{padding-inline:clamp(18px,3vw,52px)}
@media (max-width:900px){ .pl-tomorrow .rt-instrument{max-width:520px} }

/* Roundtable fit, tuned: smaller instrument + more column share so labels clear */
.pl-split2{grid-template-columns:.66fr 1.34fr}
.pl-tomorrow .rt-instrument{max-width:500px}
.pl-tomorrow .rt-stage{padding-inline:clamp(8px,1.6vw,22px)}
@media (max-width:900px){ .pl-split2{grid-template-columns:1fr} .pl-tomorrow .rt-instrument{max-width:460px} }


/* --- ./pages/t1.css --- */
/* T+1 in Europe page. Signature: the live countdown and the window
   compression rail. The deadline is the monument. */

.t1p-hero { display: grid; grid-template-columns: 1.08fr .92fr; gap: clamp(30px, 4.5vw, 70px); align-items: center; }
.t1p-hero .lead { max-width: 620px; }
.t1p-art { display: grid; justify-items: center; gap: 26px; }
.t1p-art .t1-mark { width: min(100%, 430px); }

.t1p-count { display: flex; gap: clamp(14px, 2vw, 26px); font-variant-numeric: tabular-nums; }
.t1p-count .cell { text-align: center; border: 1px solid var(--brd); border-radius: 16px; background: var(--glass); padding: 14px 18px 12px; min-width: 86px; }
.t1p-count b { font-size: clamp(30px, 3.2vw, 46px); font-weight: 700; color: var(--text); display: block; line-height: 1; }
.t1p-count span { font-family: var(--font-mono); font-size: 11px; letter-spacing: .14em; text-transform: uppercase; color: var(--dim); display: block; margin-top: 8px; }

/* The compression rail */
.cmp { display: grid; gap: 26px; padding: clamp(26px, 3.4vw, 44px); }
.cmp-row { display: grid; grid-template-columns: 92px 1fr; gap: 18px; align-items: center; }
.cmp-tag { font-family: var(--font-mono); font-size: 15px; letter-spacing: .1em; text-transform: uppercase; color: var(--muted); }
.cmp-rail { position: relative; border: 1px solid var(--brd); border-radius: 14px; background: var(--bg-2); padding: 12px; display: flex; gap: 10px; overflow: hidden; transition: width 1.6s var(--ease-reveal); width: 100%; }
.cmp-row.is-t1 .cmp-rail { width: 100%; }
.io-in .cmp-row.is-t1 .cmp-rail { width: 54%; }
.cmp-chip { font-family: var(--font-mono); font-size: 12px; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); border: 1px solid var(--brd); border-radius: 999px; padding: 8px 14px; white-space: nowrap; flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.cmp-row.is-t1 .cmp-chip { border-color: var(--brd-strong); }
.cmp-note { display: flex; justify-content: space-between; gap: 18px; font-family: var(--font-mono); font-size: 12.5px; letter-spacing: .1em; text-transform: uppercase; color: var(--dim); flex-wrap: wrap; }
.cmp-note .warn { color: var(--warn); }

/* Cited stats */
.t1p-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
.t1p-stat { display: grid; gap: 10px; padding: 30px 28px; align-content: start; }
.t1p-stat .n { font-size: clamp(48px, 5vw, 74px); font-weight: 700; line-height: 1; color: var(--text); font-variant-numeric: tabular-nums; letter-spacing: -.02em; }
.t1p-stat .d { color: var(--muted); line-height: 1.55; }
.t1p-stat .src { font-family: var(--font-mono); font-size: 11.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--dim); margin-top: 6px; }

/* The T+0 answer */
.t0-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.t0-row { display: grid; grid-template-columns: 1fr auto; gap: 8px 16px; padding: 24px 26px; align-items: center; }
.t0-row b { grid-column: 1; grid-row: 1; }
.t0-row .tag { grid-column: 2; grid-row: 1; justify-self: end; }
.t0-row .tag { font-family: var(--font-mono); font-size: 11px; letter-spacing: .12em; text-transform: uppercase; color: var(--ok); border: 1px solid var(--ok); background: var(--ok-bg); border-radius: 999px; padding: 5px 12px; }
.t0-row b { font-size: 19px; color: var(--text); }
.t0-row p { grid-column: 1 / -1; margin: 0; color: var(--muted); line-height: 1.6; font-size: 15.5px; }
.t0-hl { grid-column: 1 / -1; padding: 30px clamp(24px, 3vw, 40px); display: grid; grid-template-columns: 1fr auto; gap: 10px 22px; align-items: center; }
.t0-hl b { grid-column: 1; grid-row: 1; }
.t0-hl .tag { grid-column: 2; grid-row: 1; justify-self: end; }
.t0-hl .tag { font-family: var(--font-mono); font-size: 11px; letter-spacing: .12em; text-transform: uppercase; color: var(--ok); border: 1px solid var(--ok); background: var(--ok-bg); border-radius: 999px; padding: 5px 12px; }
.t0-hl b { font-size: clamp(21px, 2vw, 27px); color: var(--text); }
.t0-hl p { grid-column: 1 / -1; margin: 0; color: var(--muted); line-height: 1.65; }

/* Readiness checklist */
.chk { max-width: 980px; margin-inline: auto; display: grid; gap: 14px; }
.chk-row { display: grid; grid-template-columns: 1fr 1fr; gap: 10px 26px; padding: 22px 26px; align-items: center; }
.chk-row .gap { color: var(--text); font-size: 17.5px; line-height: 1.5; }
.chk-row .fix { color: var(--muted); line-height: 1.55; font-size: 15.5px; display: flex; align-items: center; gap: 12px; }
.chk-row .fix svg { flex: 0 0 auto; color: var(--ok); }

/* Road to October 2027 */
.road-panel { padding: clamp(26px, 3.4vw, 46px); }
.road-svg { display: block; width: 100%; height: auto; overflow: visible; }
.road-line { stroke: var(--brd-strong); stroke-width: 2; }
.road-draw { stroke: var(--indigo-bright); stroke-width: 2.6; stroke-dasharray: 1; stroke-dashoffset: 1; transition: stroke-dashoffset 2.2s var(--ease-reveal); }
.io-in .road-draw { stroke-dashoffset: 0; }
.road-stop circle { fill: var(--elev); stroke: var(--brd-strong); stroke-width: 2.4; }
.road-stop.now circle { stroke: var(--indigo-bright); filter: drop-shadow(0 0 12px var(--indigo-bright)); }
.road-stop.fin circle { stroke: var(--ok); filter: drop-shadow(0 0 12px var(--ok)); }
.road-h { fill: var(--text); font-size: 21px; font-weight: 700; text-anchor: middle; }
.road-l { fill: var(--muted); font-family: var(--font-mono); font-size: 13px; letter-spacing: .1em; text-transform: uppercase; text-anchor: middle; }

@media (max-width: 1050px) {
  .t1p-hero { grid-template-columns: 1fr; }
  .t1p-stats { grid-template-columns: 1fr; }
  .t0-grid { grid-template-columns: 1fr; }
}
@media (max-width: 680px) {
  .cmp-row { grid-template-columns: 1fr; }
  .chk-row { grid-template-columns: 1fr; }
  .t1p-count .cell { min-width: 64px; padding: 10px 12px 9px; }
}
@media (prefers-reduced-motion: reduce) {
  .cmp-rail, .road-draw { transition: none; }
  .io-in .cmp-row.is-t1 .cmp-rail { width: 54%; }
}

/* Europe T+1 hero: center the countdown under the London mark, and give the
   hero sub and actions room to breathe. */
.t1p-art { display: flex; flex-direction: column; align-items: center; text-align: center; }
.t1p-art .t1-mark-wrap { display: flex; justify-content: center; }
.t1p-count { justify-content: flex-start; margin: clamp(26px, 3.5vw, 44px) 0 0; }  /* timer sits below the hero text */
.t1p-hero .lead { margin: 18px 0 0; }
.t1p-hero .hero-actions { justify-content: center; margin-top: clamp(22px, 3vw, 34px); }  /* buttons sit under the mark */

/* Europe stats: unboxed, thought-leadership metric styling (purple flashing
   unit, left accent, magnify on hover) with larger, more readable body text. */
.t1p-stats { align-items: start; }
.t1p-stat { position: relative; padding: 22px 6px 22px 20px; background: none; border: 0; transition: transform .4s cubic-bezier(.22,.61,.36,1); }
.t1p-stat::before { content: ""; position: absolute; left: 0; top: 14px; bottom: 14px; width: 2px; border-radius: 2px; background: var(--indigo-bright); box-shadow: 0 0 12px var(--indigo-bright); transform: scaleY(0); opacity: 0; transition: transform .36s cubic-bezier(.22,.61,.36,1), opacity .28s ease; }
.t1p-stat:hover::before { transform: scaleY(1); opacity: 1; }
.t1p-stat .stat-num { font-size: clamp(46px, 4vw, 60px); font-weight: 800; line-height: 1; color: var(--text); letter-spacing: -.03em; font-variant-numeric: tabular-nums; transform-origin: left center; transition: transform .4s cubic-bezier(.22,.61,.36,1); }
.t1p-stat:hover .stat-num { transform: translateX(8px) scale(1.06); }
.t1p-stat .stat-num .u { color: var(--indigo-lift); }
.t1p-stat .stat-num .u.is-pct { margin-left: .06em; }
.t1p-stat:hover .stat-num .u { animation: uShimmer .6s ease-out 1; }
.t1p-stat .d { font-size: 17px; line-height: 1.62; color: var(--muted); margin: 6px 0 0; transform-origin: left center; transition: color .3s ease, transform .38s cubic-bezier(.22,.61,.36,1); }
.t1p-stat:hover .d { color: var(--text); transform: translateX(8px) scale(1.02); }

/* T+0 answer windows: bigger, more readable body text. */
.t0-row p, .t0-hl p { font-size: 17px; line-height: 1.66; }
.t0-row b { font-size: 20px; }

/* Readiness: unboxed rows, larger text, hairline dividers, hover magnify. */
.chk-row { background: none; border: 0; border-bottom: 1px solid var(--line); border-radius: 0; padding: 22px 6px; transition: transform .34s var(--ease-out); }
.chk-row:last-child { border-bottom: 0; }
.chk-row:hover { transform: scale(1.01); }
.chk-row .gap { font-size: 18px; color: var(--muted); }
.chk-row .fix { font-size: 17px; color: var(--text); }

/* Readiness redesign: boxed problem -> fix rows, larger readable text. */
.chk { max-width: 1080px; display: grid; gap: 16px; }
.chk-row { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: clamp(16px, 3vw, 40px); padding: 24px clamp(22px, 3vw, 34px); border: 1px solid var(--brd); border-radius: 16px; background: var(--glass); transition: transform .3s ease, border-color .3s ease; }
.chk-row:hover { transform: scale(1.008); border-color: var(--brd-hover); }
.chk-row.panel:hover { transform: var(--window-hover-transform); }
.chk-tag { display: block; font-family: var(--font-mono); font-size: 11.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--dim); margin-bottom: 8px; }
.chk-tag.is-ok { color: var(--ok); }
.chk-gap p { margin: 0; font-size: 18px; line-height: 1.5; color: var(--muted); }
.chk-fix p { margin: 0; font-size: 18px; line-height: 1.5; color: var(--text); font-weight: 500; display: flex; gap: 10px; align-items: flex-start; }
.chk-fix svg { flex: 0 0 auto; color: var(--ok); margin-top: 1px; }
.chk-arrow { color: var(--indigo-lift); display: flex; }
@media (max-width: 760px) { .chk-row { grid-template-columns: 1fr; } .chk-arrow { display: none; } }


/* --- ./pages/error.css --- */
/* -----------------------------------------------------------------------------
   404. Header and footer are the shared shell; the middle is deliberately
   empty apart from the mark.

   The art is centred by letting the section absorb whatever vertical space is
   left between the header and the footer, rather than by guessing a height.
   #ssSite.site is already a flex container with a full-viewport minimum, so
   main only has to become a flex item that grows, and the section only has to
   grow inside it. That stays correct at every window size, and on a short
   window the section simply stops growing and the page scrolls as normal.

   Measured before this rule at 1440x900: the art's centre sat 66px above the
   true midpoint, partly because the section's own min-height was smaller than
   the space available and partly because .section pads 56px at the top and
   76px at the bottom. Both are neutralised here.

   Note: base.njk writes <body class="v3-page {{ pageKey }}">, so this page also
   carries the class "404". A CSS selector cannot start with a digit, hence
   [data-page="404"], which base.njk sets alongside it.
   -------------------------------------------------------------------------- */
body[data-page="404"] #main.page-body {
  flex: 1;
  display: flex;
  flex-direction: column;
}

.err-stack {
  flex: 1;
  min-height: clamp(320px, 46vh, 640px);
  justify-content: center;
  padding-top: 0;
  padding-bottom: 0;
}

.err-art {
  display: block;
  width: min(760px, 62vw);
  height: auto;
  margin: 0 auto;
}

/* Must take its colour from the theme token, not inherit and dim. Verified: an
   opacity-only rule rendered as near-black text on the near-black dark
   background and was effectively invisible. */
.err-msg {
  margin: 22px 0 0;
  font-size: clamp(17px, 1.5vw, 20px);
  color: var(--muted);
}

@media (max-width: 760px) { .err-art { width: 82vw; } }


/* --- ./pages/search.css --- */
/* -----------------------------------------------------------------------------
   SEARCH RESULTS (/search/)

   This file is deliberately short. The page is built almost entirely out of
   components that already exist, so there is very little here that is new:

     .sec-head / .eyebrow / .h1 / .sec-intro   the standard page header
     .f-list / .f-row / .f-ico / .h4 / .small-t  the feature-row list, the same
                                               unboxed row with a left accent
                                               bar and a hover magnify used on
                                               the platform and Europe T+1 pages
     .sec-caption                              the mono micro-label
     .data-label                               the mono section tag
     .btn .btn-secondary                       the empty-state action

   The only genuinely new thing is the search bar, and that is a deliberate
   restatement of the header's .site-search in shell/frame.css: no box, no
   border, no fill, an icon that lights up, and a hairline that turns indigo and
   glows on focus. The header version also expands on hover, which is pointless
   here because the bar is the point of the page, so that part is dropped.
   -------------------------------------------------------------------------- */

.srch-stack { max-width: 860px; }
.srch-stack .sec-head { margin-bottom: 30px; }

/* --- The bar. Modelled on .site-search, unboxed. --------------------------

   The bar spans the full width of .srch-stack on purpose, so its hairline lines
   up exactly with the dividers between the results below it. A narrower bar
   read as a separate, unrelated element.

   Two states drive the colour, and they are deliberately not the same thing:

     :focus-within   the cursor is in the field
     .has-query      the field has text in it, focused or not

   The second one is why arriving from the header with a query already typed
   shows a purple bar rather than a grey one: the page is not focused, but there
   is a search in progress and the bar should say so. Clearing the field fades
   it back to grey and the placeholder returns. scripts/site.js toggles the
   class; every transition below is symmetrical, so it fades both ways.

   The purple is var(--icon-hover), which is already a theme pair: #7C60FF on
   dark, #5333EC on light. Same token the header search uses.
   -------------------------------------------------------------------------- */
.srch-bar {
  position: relative;
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 6px 2px 14px 0;
  border-bottom: 1px solid var(--line);
}
/* The live underline, exactly the treatment .site-search::after uses. */
.srch-bar::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 2px;
  border-radius: 999px;
  background: var(--icon-hover);
  box-shadow: 0 0 12px color-mix(in srgb, var(--icon-hover) 28%, transparent);
  opacity: 0;
  transform: scaleX(.02);
  transform-origin: left center;
  transition: transform var(--motion-window), opacity .34s ease;
}
.srch-bar:focus-within::after,
.srch-bar.has-query::after {
  opacity: 1;
  transform: scaleX(1);
}

.srch-btn {
  flex: none;
  width: 34px;
  height: 34px;
  border: 0;
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--muted);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: color .24s ease, transform var(--motion-window), filter .34s ease;
}
.srch-btn svg { width: 20px; height: 20px; }
.srch-bar:focus-within .srch-btn,
.srch-bar.has-query .srch-btn,
.srch-btn:hover {
  color: var(--icon-hover);
  transform: scale(1.12);
  filter: drop-shadow(0 0 10px color-mix(in srgb, var(--icon-hover) 72%, transparent));
}

.srch-bar input {
  flex: 1 1 auto;
  min-width: 0;
  border: 0;
  background: transparent;
  color: var(--text);
  font: inherit;
  font-size: clamp(20px, 2.4vw, 26px);
  font-weight: 500;
  letter-spacing: -.01em;
  padding: 6px 0;
}
.srch-bar input::placeholder { color: var(--dim); font-weight: 400; }
/* The native clear button is a grey bitmap that cannot be restyled, only
   filtered. Hidden, and replaced by .srch-clear below. */
.srch-bar input::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; display: none; }
/* Same reasoning as .site-search in shell/frame.css: the default ring draws a
   rectangle around a field that has deliberately no box, and the focus state
   here is already unmistakable without it. The bar's hairline doubles in
   height, turns indigo and gains a glow, and the icon scales and glows too, so
   focus is signalled by size and light, not by colour alone. */
.srch-bar input:focus,
.srch-bar input:focus-visible { outline: none; }

/* --- Results -------------------------------------------------------------- */
.srch-count { margin: 22px 0 0; min-height: 1.4em; color: var(--dim); }
.srch-results:empty { display: none; }
.srch-results { margin-top: 10px; }

/* .f-row is a div elsewhere on the site. Here the whole row is the link. */
a.srch-row { text-decoration: none; color: inherit; }
a.srch-row:last-child { border-bottom: 0; }
.srch-row .srch-sec {
  font-size: 11.5px;
  letter-spacing: .14em;
  color: var(--dim);
  margin-bottom: 7px;
  transform-origin: left center;
  transition: color .34s ease;
}
.srch-row:hover .srch-sec { color: var(--indigo-lift); }
.srch-row:hover .h4 { color: var(--indigo-lift); }
/* The matched words. A tint rather than colour alone, so it survives both
   themes and does not rely on hue to be noticed. */
.srch-row mark {
  background: color-mix(in srgb, var(--indigo-lift) 24%, transparent);
  color: var(--text);
  border-radius: 3px;
  padding: 0 2px;
}

.srch-all-lead { margin: 40px 0 4px; color: var(--dim); }
.srch-all[hidden] { display: none; }

/* --- No match ------------------------------------------------------------
   A dead end is the wrong answer for somebody who arrived with a question, so
   this block is built to move them on rather than to apologise. It sits on the
   same left edge as the results and the bar, with real air around the actions
   instead of a button jammed under a paragraph.
   ------------------------------------------------------------------------ */
.srch-none {
  max-width: 60ch;
  padding: 34px 0 8px;
}
.srch-none-lead {
  margin: 0;
  font-size: clamp(20px, 2vw, 24px);
  line-height: 1.4;
  letter-spacing: -.01em;
  color: var(--text);
}
.srch-none-lead b { color: var(--indigo-lift); font-weight: 700; }
.srch-none-body {
  margin: 14px 0 0;
  font-size: 17px;
  line-height: 1.68;
  color: var(--muted);
}
.srch-none-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 30px;
}
.srch-none-try {
  margin: 30px 0 0;
  padding-top: 20px;
  border-top: 1px solid var(--line);
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: .12em;
  text-transform: uppercase;
  line-height: 1.9;
  color: var(--dim);
}

@media (max-width: 520px) {
  .srch-none-actions { gap: 10px; }
  .srch-none-actions .btn { flex: 1 0 100%; justify-content: center; }
}

@media (max-width: 640px) {
  .srch-bar { gap: 10px; }
  .srch-bar input { font-size: 19px; }
}

/* -----------------------------------------------------------------------------
   CLEAR BUTTON (.srch-clear)

   Two bars that swing into a cross, borrowed from the FAQ plus icon and the
   menu button so the site has one idea about how a cross is drawn rather than
   three. Same easing as the FAQ icon.

   It is not in the tab order. Escape already clears the field and is faster for
   anyone using a keyboard, and a control that only exists while there is text
   is a confusing thing to land on.
   -------------------------------------------------------------------------- */
.srch-clear {
  position: relative;
  flex: 0 0 auto;
  width: 30px;
  height: 30px;
  margin-left: 10px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  border-radius: 50%;
  opacity: 0;
  visibility: hidden;
  transition: opacity .35s ease, visibility .35s;
}
.srch-clear i {
  position: absolute;
  left: 7px;
  top: 14px;
  width: 16px;
  height: 1.5px;              /* thin, like the menu bars, not the browser's slab */
  border-radius: 2px;
  background: var(--indigo-lift);
  transform: rotate(0deg) scaleX(.2);
  transition: transform .6s cubic-bezier(.3, .8, .3, 1), background .3s ease;
}
/* Shown by site.js on the same condition that lights the bar: there is a query.
   The bars grow out from the middle and rotate into the cross. Going away, they
   unwind and fold back in. */
.srch-bar.has-query .srch-clear { opacity: 1; visibility: visible; }
.srch-bar.has-query .srch-clear i:first-child { transform: rotate(45deg) scaleX(1); }
.srch-bar.has-query .srch-clear i:last-child  { transform: rotate(-45deg) scaleX(1); }

.srch-clear:hover i { background: var(--indigo-bright); }
.srch-clear:hover i:first-child { transform: rotate(225deg) scaleX(1); }
.srch-clear:hover i:last-child  { transform: rotate(135deg) scaleX(1); }
.srch-clear:focus-visible { outline: 2px solid var(--indigo-lift); outline-offset: 2px; }

@media (prefers-reduced-motion: reduce) {
  .srch-clear i { transition: none; }
  .srch-clear:hover i:first-child { transform: rotate(45deg) scaleX(1); }
  .srch-clear:hover i:last-child  { transform: rotate(-45deg) scaleX(1); }
}


/* --- ./components/forms.css --- */
/* =============================================================================
   Forms - inputs, selects, textareas, labels  (form windows)
   -----------------------------------------------------------------------------
   The authored, documented source of truth for form controls (Contact,
   Request Demo). Wrap fields in <form class="ss-form">; each field is a
   <label> that contains its text then the control:

     <form class="ss-form">
       <div class="form-grid">                          two-up on wide, stacks on narrow
         <label>Name<input type="text" placeholder="…"></label>
         <label>Inquiry type<select>…</select></label>
       </div>
       <label>Message<textarea rows="4"></textarea></label>
       <button class="btn btn-primary">Submit</button>
     </form>

   Controls fill their label, share one radius/border, and lift on focus with an
   indigo focus ring. Selects get a custom chevron (native arrow removed).
   ========================================================================== */

/* Sits clear of any heading above it (e.g. "How can we help?" in the panel). */
.ss-form { display: flex; flex-direction: column; gap: 18px; margin-top: 22px; }
/* An author rule beats the browser's [hidden] rule, so without this a form that
   script has hidden keeps its space and the success block appears underneath a
   still-visible form. Affects /request-demo/, /contact/ and the webinar page. */
.ss-form[hidden] { display: none; }

/* Submit keeps its natural width at the left edge (live-site behavior) instead
   of stretching across the flex column. Add .is-wide-submit on the form when
   the button should span the whole card (e.g. Request Demo). */
.ss-form > button[type="submit"] { align-self: flex-start; }
.ss-form.is-wide-submit > button[type="submit"] { align-self: stretch; width: 100%; }


/* Label = field title stacked above its control. */
.ss-form label {
  display: flex;
  flex-direction: column;
  gap: 8px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
  letter-spacing: .01em;
}

/* Two fields per row on wide screens; each drops to full width under ~210px. */
.form-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 18px;
}

/* Shared control base - input, select, textarea. */
.ss-form input,
.ss-form select,
.ss-form textarea {
  font: inherit;
  font-size: 15px;
  font-weight: 400;
  line-height: 1.45;
  color: var(--text);
  background: var(--panel);
  border: 1px solid var(--brd);
  border-radius: 11px;
  min-height: 49px;
  padding: 12px 15px 13px;
  outline: none;
  width: 100%;
  transition: border-color .2s, box-shadow .2s, background .2s;
}

.ss-form textarea { resize: vertical; min-height: 120px; }

.ss-form input::placeholder,
.ss-form textarea::placeholder { color: var(--dim); }

/* Whiter lift on hover, and persistently once a field is filled (completed).
   :not(:placeholder-shown) = the input/textarea now holds a value. */
.ss-form input:hover,
.ss-form select:hover,
.ss-form textarea:hover,
.ss-form input:not(:placeholder-shown),
.ss-form textarea:not(:placeholder-shown) {
  border-color: var(--field-glow-brd);
  box-shadow: 0 0 0 1px var(--field-glow-brd), 0 0 16px var(--field-glow);
  background-color: var(--elev);   /* not `background` - keeps the select chevron */
}

/* Focus - indigo ring + slightly lifted surface. */
.ss-form input:focus,
.ss-form select:focus,
.ss-form textarea:focus {
  border-color: var(--brd-hover);
  box-shadow: 0 0 0 3px var(--info-bg);
  background-color: var(--elev);   /* not `background` - keeps the select chevron */
}

/* Select - native arrow removed, custom chevron drawn from two gradients. */
.ss-form select {
  appearance: none;
  -webkit-appearance: none;
  cursor: pointer;
  padding-right: 38px;
  background-image:
    linear-gradient(45deg, transparent 50%, var(--muted) 50%),
    linear-gradient(135deg, var(--muted) 50%, transparent 50%);
  background-position: calc(100% - 19px) center, calc(100% - 14px) center;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}
.ss-form option { background: var(--elev); color: var(--text); font-weight: 500; padding: 10px 14px; }

/* Light mode: glassy see-through fields (match dark-mode transparency) */
[data-theme="light"] .ss-form input,
[data-theme="light"] .ss-form select,
[data-theme="light"] .ss-form textarea { background-color: rgba(255,255,255,.2); }
.ss-form option:checked { background: var(--hover); color: var(--text); }
/* Until a real value is chosen, a required select shows its "Select …" prompt
   in the same grey as input placeholders. (:invalid = required + empty value;
   forms are novalidate so this never blocks submission.) */
.ss-form select:required:invalid { color: var(--dim); }

/* -----------------------------------------------------------------------------
   Request Demo layout - three-up field grid with starred titles.
     <label><span class="field-title">First Name<span class="req">*</span></span>
            <input …></label>
   -------------------------------------------------------------------------- */
.request-demo-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 18px;
}
@media (max-width: 900px) {
  .request-demo-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* A field left alone on the last row stretches to the full card width instead
     of sitting half width with dead space beside it. Scoped to the two-column
     state on purpose: at three columns the third child is the end of a full row,
     not a lone field, and this rule would wrongly stretch it. */
  .request-demo-grid > label:last-child:nth-child(odd) { grid-column: 1 / -1; }
}
@media (max-width: 640px) { .request-demo-grid { grid-template-columns: 1fr; } }
.field-title {
  display: inline-flex;
  align-items: baseline;
  gap: 2px;
}
.req { color: var(--indigo-lift); margin-left: 0; }

/* Success state - hidden via the [hidden] attribute until site.js reveals it
   after a confirmed submission (form hides, this block takes its place). */
.form-success {
  display: grid;
  gap: 16px;
  padding: 44px 0 12px;   /* drop the confirmation lower, clear of the submit button */
}
.form-success[hidden] { display: none; }


/* Accessible inline form error (role="alert"), replacing alert() dialogs. */
.form-error {
  margin: 0 0 16px;
  padding: 11px 15px;
  border-radius: 10px;
  background: rgba(229, 72, 77, .12);
  border: 1px solid rgba(229, 72, 77, .55);
  color: var(--text);
  font-size: 14px;
  line-height: 1.45;
}
.ss-form [aria-invalid="true"] {
  border-color: #e5484d !important;
  box-shadow: 0 0 0 1px rgba(229, 72, 77, .4);
}


/* --- ./components/faq.css --- */
/* =============================================================================
   FAQ - accordion, group labels, and the gated "unlock" block  (FAQ page)
   -----------------------------------------------------------------------------
   Questions are native <details>/<summary> so they work without JS:

     <div class="faq-group-label">General</div>
     <div class="faq-list">
       <details class="faq-item">
         <summary class="faq-q">Question?<span class="faq-ico"></span></summary>
         <div class="faq-a"><p>Answer.</p></div>
       </details>
     </div>

   The gated section wraps a .faq-gate-head (pitch + .faq-unlock mini-form) and
   its own .faq-list. Until site.js adds .unlocked to .faq-gate, the questions
   are dimmed and locked (a small padlock replaces the +). Locked items swap
   icons with a springy rotate; unlocking is remembered per-browser.
   ========================================================================== */

.faq-list {
  border-top: 1px solid var(--line);
  max-width: 860px;
}
.faq-item { border-bottom: 1px solid var(--line); }

/* Question row - full-width click target with the +/× icon on the right. */
.faq-q {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding: 26px 4px;
  font-size: clamp(17px, 1.7vw, 21px);
  font-weight: 600;
  color: var(--text);
  transition: color .2s;
}
.faq-q::-webkit-details-marker { display: none; }
.faq-q:hover { color: var(--indigo-lift); }

/* Hover: the question magnifies from the left (same language as Resource rows)
   while the + icon pulses. Wrap the question in .faq-q-text so only the text
   scales, not the icon. */
.faq-q-text {
  transform-origin: left center;
  transition: transform var(--motion-hover);
}
.faq-q:hover .faq-q-text { transform: scale(1.05); }
.faq-q:hover .faq-ico { animation: faqIcoPulse 1.3s ease-in-out infinite; }
@media (prefers-reduced-motion: reduce) { .faq-q:hover .faq-ico { animation: none; } }
@keyframes faqIcoPulse {
  0%, 100% { transform: scale(1); filter: none; }
  50% { transform: scale(1.28); filter: drop-shadow(0 0 7px var(--indigo-bright)); }
}

/* Plus icon drawn from two bars; the vertical bar spins away when open. */
.faq-ico {
  position: relative;
  width: 18px;
  height: 18px;
  flex: 0 0 auto;
}
.faq-ico::before,
.faq-ico::after {
  content: "";
  position: absolute;
  background: var(--indigo-bright);
  border-radius: 2px;
  transition: transform .6s cubic-bezier(.3, .8, .3, 1);
}
.faq-ico::before { left: 0; top: 8px; width: 18px; height: 2px; }
.faq-ico::after { left: 8px; top: 0; width: 2px; height: 18px; }
details[open] .faq-ico::after { transform: rotate(90deg); opacity: 0; }
details[open] .faq-ico::before { transform: rotate(180deg); }

/* Answer body - fades/slides in when the item opens. */
.faq-a { overflow: hidden; }
.faq-a p {
  margin: 0 0 18px;
  padding-right: 42px;
  font-size: 16px;
  line-height: 1.7;
  color: var(--muted);
}
details[open] .faq-a { animation: faqOpen .4s ease; }
@keyframes faqOpen {
  from { opacity: 0; transform: translateY(-8px); }
  to { opacity: 1; transform: none; }
}

/* Mono category label above each question group ("General", "T+1 in Europe"). */
.faq-group-label {
  font-family: var(--font-mono);
  font-size: 16px;
  font-weight: 700;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--indigo-lift);
  margin: 50px 0 6px;
}
.section > .faq-group-label:first-child { margin-top: 0; }

/* -----------------------------------------------------------------------------
   Gated block - glass pitch panel + inline unlock form above locked questions.
   The head is a .panel (glass, spotlight, sheen sweep, hover magnify all come
   from the global panel object) - use <div class="panel faq-gate-head">.
   -------------------------------------------------------------------------- */
.faq-gate-head {
  margin-top: 54px;
  padding: clamp(24px, 3vw, 34px);
  border-color: var(--brd-hover);
  border-radius: 18px;
  max-width: 860px;
}
.faq-gate-head h3 {
  margin: 0;
  font-size: clamp(20px, 2vw, 26px);
  letter-spacing: -.015em;
}
.faq-gate-head p {
  margin: 9px 0 0;
  color: var(--muted);
  font-size: 15px;
  line-height: 1.62;
  max-width: 62ch;
}

/* Unlock mini-form - a compact .ss-form (all field styling - glass controls,
   hover lift, focus ring, select chevron - comes from the global form object;
   use <form class="ss-form faq-unlock">). This layer only sets the layout:
   a three-up grid (First/Last/Email, then Company/Ecosystem + Unlock),
   collapsing to two then one column as the gate narrows. */
.faq-unlock {
  margin-top: 22px;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
  align-items: end;
}
.faq-unlock label {
  font-size: 12px;
  gap: 7px;
}
/* Unlock fills its grid cell and matches the field height beside it. */
.faq-unlock > button[type="submit"] {
  align-self: end;
  justify-self: stretch;
  width: 100%;
  min-height: 49px;
}
@media (max-width: 720px) { .faq-unlock { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 480px) { .faq-unlock { grid-template-columns: 1fr; } }
.faq-unlocked-note {
  margin-top: 18px;
  display: none;
  align-items: center;
  gap: 10px;
  font-size: 13px;
  font-family: var(--font-mono);
  letter-spacing: .04em;
  color: var(--ok);
}
/* The pip pulses green: --signal feeds the shared dotGlow keyframes, so
   re-pointing it at --ok makes the standard .anim pulse glow green here. */
.faq-unlocked-note .live-dot {
  background: var(--ok);
  box-shadow: 0 0 10px var(--ok);
  --signal: var(--ok);
}
.faq-gate.unlocked .faq-unlock { display: none; }
.faq-gate.unlocked .faq-unlocked-note { display: flex; }
/* Same breathing room below the gate panel as above it (54px). */
.faq-gate .faq-list { margin-top: 54px; }
.faq-gate:not(.unlocked) .faq-q {
  color: var(--dim);
  cursor: default;
  pointer-events: none;
}

/* Locked items carry BOTH icons stacked; lock and + crossfade on unlock. */
.faq-ico-wrap {
  position: relative;
  width: 18px;
  height: 18px;
  flex: 0 0 auto;
}
/* Slow, springy crossfade: each padlock melts away as its + spins in. */
.faq-ico-wrap .faq-ico {
  position: absolute;
  inset: 0;
  transition: opacity .9s ease, transform 1.15s cubic-bezier(.3, 1.25, .4, 1);
}
.lk-lock {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--dim);
  transition: opacity .9s ease, transform 1.15s cubic-bezier(.3, 1.25, .4, 1);
}
.faq-gate:not(.unlocked) .faq-ico-wrap .faq-ico { opacity: 0; transform: scale(.4) rotate(-90deg); }
.faq-gate.unlocked .lk-lock { opacity: 0; transform: rotate(90deg) scale(.3); pointer-events: none; }


/* --- ./components/team-cards.css --- */
/* =============================================================================
   Team / headshot cards  (.tm-card)
   -----------------------------------------------------------------------------
   Portrait tiles with a frosted hover state: at rest the photo shows with the
   name + role below it; on hover (or keyboard focus) a blurred overlay fades in,
   the name rises to the top with a LinkedIn badge, and the bio reveals. The
   whole tile is a link to the person's LinkedIn.

   Markup:
     <div class="tm-grid">
       <article class="tm-card" tabindex="0">
         <a class="tm-frame" href="…" target="_blank" rel="noopener" aria-label="Name on LinkedIn">
           <img class="tm-photo" src="…" alt="Name" style="object-position:50% 18%">
         </a>
         <div class="tm-over">
           <div class="tm-over-head">
             <div class="tm-over-id"><h3>Name</h3><p>Role</p></div>
             <span class="tm-li" aria-hidden="true"><svg …>…</svg></span>
           </div>
           <p class="tm-bio">Short bio…</p>
         </div>
         <div class="tm-meta"><h3>Name</h3><p>Role</p></div>
       </article>
     </div>

   Per-photo framing uses named .tm-crop-* classes so every headshot adjustment
   is kept global and reviewable. Touch devices (no hover) fall back to a static,
   always-open card.
   ========================================================================== */

.tm-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 30px 22px;
}
.tm-grid-roster {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
}
.tm-grid-roster > .tm-card { flex: 0 1 calc((100% - 88px) / 5); min-width: 0; }

.tm-card { position: relative; cursor: pointer; outline: none; }
.tm-card:hover,
.tm-card:focus-within { z-index: 5; }

/* Portrait frame - indigo gradient behind a cover photo, lifts on hover. */
.tm-frame {
  position: relative;
  display: block;
  text-decoration: none;
  cursor: pointer;
  aspect-ratio: 7 / 10;
  border-radius: 18px;
  overflow: hidden;
  background: #fff;
  border: 0;
  box-shadow: none;
  transition: box-shadow .34s ease, transform var(--motion-window);
}
.tm-card:hover .tm-frame,
.tm-card:focus-visible .tm-frame,
.tm-card:focus-within .tm-frame {
  box-shadow: 0 18px 44px -28px color-mix(in srgb, var(--indigo-bright) 58%, transparent);
  transform: none;
}
.tm-frame:focus-visible {
  outline: 2px solid var(--indigo-bright);
  outline-offset: 4px;
}

/* The headshot - covers the frame, zooms slightly on hover. */
.tm-photo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 16%;
  transform: translate(var(--tx, 0%), var(--ty, 0%)) scale(var(--z, 1));
  transform-origin: 50% 50%;
  will-change: auto;
  transition: transform var(--motion-hover);
}
.tm-crop-david { object-position: 50% 19%; }
.tm-crop-cynthia,
.tm-crop-ken { object-position: 50% 15%; }
.tm-crop-tracy { object-position: 50% 18%; }
.tm-crop-ben { object-position: 50% 28%; }
.tm-crop-george { object-position: 50% 3%; }
.tm-crop-jonathan {
  object-position: 50% 0%;
  --z: 1.46;
  --ty: 15%;   /* nudged down so the face sits level with the rest of the row */
}
.tm-crop-scott { object-position: 50% 8%; --z: 1.16; }
.tm-crop-neil {
  object-position: 50% 10%;
  --z: 1.18;
  --ty: 11%;
}
.tm-card:hover .tm-photo,
.tm-card:focus-within .tm-photo {
  transform: translate(var(--tx, 0%), var(--ty, 0%)) scale(calc(var(--z, 1) * 1.06));
}

/* Frosted hover overlay - sits over the frame; clicks pass through to the link. */
.tm-over {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  aspect-ratio: 7 / 10;
  z-index: 3;
  border-radius: 18px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  padding: 18px 18px 19px;
  pointer-events: none;
  backdrop-filter: blur(9px) saturate(.95) brightness(.9);
  -webkit-backdrop-filter: blur(9px) saturate(.95) brightness(.9);
  background: linear-gradient(180deg, rgba(8, 6, 16, .42) 0%, rgba(8, 6, 16, .26) 45%, rgba(8, 6, 16, .54) 100%);
  opacity: 0;
  transition: opacity .42s ease;
}
.tm-card:hover .tm-over,
.tm-card:focus-within .tm-over { opacity: 1; }

.tm-over-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 10px;
  opacity: 0;
  transform: translateY(-16px);
  transition: opacity .42s ease, transform var(--motion-hover);
}
.tm-card:hover .tm-over-head,
.tm-card:focus-within .tm-over-head { opacity: 1; transform: translateY(0); }

.tm-over-id h3 { margin: 0; font-size: 20px; font-weight: 700; color: #fff; letter-spacing: -.014em; line-height: 1.14; text-shadow: 0 1px 10px rgba(0, 0, 0, .5); }
.tm-over-id p { margin: 6px 0 0; font-size: 15px; font-weight: 600; font-family: var(--font-mono); letter-spacing: .05em; text-transform: uppercase; color: #D9D2FF; text-shadow: 0 1px 8px rgba(0, 0, 0, .55); }

/* Overlay action badges. LinkedIn uses its brand blue; booking uses the
   SmartSettle indigo cube with a white hurricane mark. */
.tm-actions {
  flex: 0 0 auto;
  display: grid;
  gap: 8px;
  justify-items: end;
  pointer-events: auto;
}
.tm-action {
  position: relative;
  flex: 0 0 auto;
  width: 31px;
  height: 31px;
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  text-decoration: none;
  color: #fff;
  transform-origin: center;
  transition: box-shadow .34s ease, filter .34s ease;
}
.tm-action:hover,
.tm-action:focus-visible {
  filter: brightness(1.08);
}
.tm-action:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 2px;
}
.tm-li {
  background: #0A66C2;
  box-shadow: 0 6px 18px rgba(10, 102, 194, .55);
}
.tm-book {
  background: linear-gradient(145deg, var(--indigo-bright), var(--indigo));
  box-shadow: 0 6px 18px rgba(83, 51, 236, .58);
}
.tm-action svg,
.tm-action img {
  width: 17px;
  height: 17px;
  display: block;
  object-fit: contain;
  transform-origin: center;
  transition: transform var(--motion-window);
}
.tm-book img { width: 36px; height: 36px; }
.tm-action:hover svg,
.tm-action:focus-visible svg,
.tm-action:hover img,
.tm-action:focus-visible img { transform: scale(1.18); }
.tm-book[data-tip]::after {
  content: attr(data-tip);
  position: absolute;
  right: calc(100% + 12px);
  top: 50%;
  transform: translateY(-50%);
  width: max-content;
  max-width: 190px;
  padding: 7px 9px;
  border-radius: 8px;
  background: color-mix(in srgb, var(--elev) 94%, transparent);
  border: 1px solid var(--brd-strong);
  color: var(--text);
  font-size: 11px;
  line-height: 1.25;
  font-weight: 650;
  letter-spacing: 0;
  white-space: nowrap;
  box-shadow: 0 10px 24px rgba(0,0,0,.28);
  opacity: 0;
  pointer-events: none;
  transition: opacity .16s ease;
}
.tm-book[data-tip]:hover::after,
.tm-book[data-tip]:focus-visible::after {
  opacity: 1;
}

.tm-bio {
  margin: auto 0;
  font-size: 14.5px;
  line-height: 1.48;
  color: #fff;   /* overlay sits on a dark photo scrim - stay white in both themes */
  text-wrap: pretty;
  font-weight: 400;
  text-shadow: 0 1px 8px rgba(0, 0, 0, .5);
  opacity: 0;
  transform: translateY(14px);
  transition: opacity .44s ease .06s, transform .95s var(--ease-reveal) .06s;
}
.tm-card:hover .tm-bio,
.tm-card:focus-within .tm-bio { opacity: 1; transform: translateY(0); }

/* Name + role shown below the photo at rest; fades out as the overlay opens. */
.tm-meta { padding: 14px 2px 0; transition: opacity .34s ease, transform var(--motion-hover); }
.tm-card:hover .tm-meta,
.tm-card:focus-within .tm-meta { opacity: 0; transform: none; }
.tm-meta h3 { margin: 0; font-size: 20px; font-weight: 700; color: var(--text); letter-spacing: -.014em; }
.tm-meta p { margin: 6px 0 0; font-size: 15.5px; line-height: 1.35; font-weight: 650; color: var(--indigo-lift); font-family: var(--font-mono); letter-spacing: .04em; text-transform: uppercase; }

/* Touch devices - no hover, so show a static open card (overlay flattened out). */
@media (hover: none) {
  .tm-over {
    position: static;
    aspect-ratio: auto;
    overflow: visible;
    opacity: 1;
    background: none;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    padding: 13px 2px 0;
  }
  .tm-over-head { opacity: 1; transform: none; }
  .tm-over-id h3 { color: var(--text); }
  .tm-actions { justify-items: start; grid-auto-flow: column; }
  .tm-action { box-shadow: none; }
  .tm-book[data-tip]::after { display: none; }
  .tm-bio { opacity: 1; transform: none; color: var(--muted); margin: 9px 0 0; font-size: 14.5px; }
  .tm-photo { filter: none !important; }
  .tm-meta { display: none; }
}

@media (max-width: 1180px) {
  .tm-grid-roster > .tm-card { flex-basis: calc((100% - 44px) / 3); }
}
@media (max-width: 760px) {
  .tm-grid-roster > .tm-card { flex-basis: calc((100% - 22px) / 2); }
}
@media (max-width: 540px) {
  .tm-grid-roster > .tm-card { flex-basis: 100%; }
}


/* --- ./components/webinar.css --- */
/* =============================================================================
   Webinar recap page (/resources/webinar-jul29)
   -----------------------------------------------------------------------------
   Kept in its own file rather than in blocks.css so the recap feature can be
   branched, shipped, or reverted without touching the shared long-form styles
   that the Privacy and Terms pages depend on.
   ========================================================================== */

/* -----------------------------------------------------------------------------
   GATED WEBINAR RECAP (.wg-player / .wg-gate) - resources/webinar-jul29.
   The player mount ships EMPTY and hidden. site.js injects an iframe into it
   only after the Worker grants access, so there is no video URL in the page
   source. Do not put a fallback iframe in here.
   -------------------------------------------------------------------------- */
.wg-player {
  position: relative;
  margin: 0 0 34px;
  aspect-ratio: 16 / 9;
  border: 1px solid var(--brd);
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: #000;
}
.wg-player[hidden] { display: none; }
.wg-player iframe,
.wg-player video { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; object-fit: contain; background: #000; }

/* Belt and braces on the download affordance. controlsList="nodownload" is the
   real mechanism (set in site.js); this hides the button in WebKit builds that
   ignore it. Neither is a security control - the actual protection is that the
   host only serves the file to smartsettle.ai with a signed, expiring URL. */
.wg-player video::-webkit-media-controls-download-button { display: none; }

/* Captions. ::cue is the only hook browsers give for subtitle text, and it
   accepts a deliberately short list of properties - background, colour, font,
   line-height. Sizing is a percentage because it resolves against the video
   box, so it scales with the player instead of fighting it. The same rules are
   duplicated in a STYLE block inside the .vtt file, which is what applies when
   the track is served cross-origin. */
.wg-player video::cue {
  background: rgba(11, 10, 16, .80);
  color: #F4F3FA;
  font-family: var(--font-sans, system-ui), sans-serif;
  font-size: 88%;
  line-height: 1.45;
}
.wg-player video::-webkit-media-text-track-display { padding-bottom: 6px; }
.wg-player video::-webkit-media-controls-enclosure { overflow: hidden; }
.wg-gate { scroll-margin-top: 100px; transition: opacity .32s ease, transform .32s ease; }

/* Handing over from form to player: the panel lifts and fades, the player
   fades up in its place. Without this the video simply popped into existence.
   site.js sets [hidden] on the panel once the fade finishes, so it leaves the
   layout entirely rather than sitting there invisible. */
.wg-gate.is-dismissed { opacity: 0; transform: translateY(-8px); pointer-events: none; }
.wg-player { opacity: 0; transition: opacity .45s ease .06s, transform .45s ease .06s; transform: translateY(8px); }
.wg-player.is-live { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .wg-gate, .wg-player { transition: none; transform: none; }
}
.wg-covered { margin-top: 56px; }

/* Honeypot. Positioned off-canvas rather than display:none, because bots skip
   fields that are display:none but still fill ones they can "see" in the DOM. */
.hp-field {
  position: absolute;
  left: -9999px;
  top: auto;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* -----------------------------------------------------------------------------
   CHAPTER STRIP (.wg-chapters)

   Sits flush under the player, so it reads as part of it rather than as a
   separate widget. No browser allows drawing inside its native video scrubber,
   so this is the closest honest thing: a second bar, immediately below, where
   each segment is as wide as its chapter is long. Glance at it and you can see
   that the Q&A is the last quarter of the recording.

   Built entirely in JS from the chapters VTT, so if that fetch fails there is
   simply no strip and the player is exactly as it was.
   -------------------------------------------------------------------------- */
/* Only when a strip was actually built: the player keeps its own rounded
   bottom and its margin when there are no chapters. */
.wg-player.has-chapters {
  margin-bottom: 0;
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
}
.wg-chapters { margin: 0 0 34px; }

.wg-rail {
  display: flex;
  gap: 2px;
  height: 12px;
  border-radius: 0 0 14px 14px;
  overflow: hidden;
  background: var(--panel);
  border: 1px solid var(--brd);
  border-top: 0;
  padding: 2px;
}
.wg-seg {
  position: relative;
  flex: 1 1 0;
  min-width: 4px;
  padding: 0;
  border: 0;
  border-radius: 3px;
  background: var(--line);
  cursor: pointer;
  overflow: hidden;
  transition: background .18s ease, transform .18s ease;
}
.wg-seg:hover { background: var(--brd-hover); transform: scaleY(1.35); }
.wg-seg:focus-visible { outline: 2px solid var(--indigo-lift); outline-offset: 2px; }
/* The played portion of each segment. Width is set from currentTime in JS. */
.wg-seg-fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: 0;
  display: block;
  background: var(--indigo-lift);
  border-radius: inherit;
}
.wg-seg.is-current { background: var(--brd-hover); }
.wg-seg.is-current .wg-seg-fill { background: var(--grad-hi); }

.wg-now {
  margin: 14px 0 0;
  font-size: 18px;
  font-weight: 600;
  line-height: 1.35;
  color: var(--text);
}
.wg-now[data-state="idle"] { font-weight: 500; color: var(--muted); }

/* Chapter titles on hover, BELOW the strip. Above meant covering the bottom of
   the picture, including the native controls, which is the one part of the
   frame you cannot afford to hide. Positioned in JS because the left offset
   depends on which segment you are over, and clamped there so a tooltip near
   either end stays inside the layout. */
.wg-chapters { position: relative; }
.wg-tip {
  position: absolute;
  /* Just under the rail, not under the whole block: tight to the strip you are
     pointing at. It covers the status line while you hover, which is fine,
     because the line and the tooltip are saying the same kind of thing. */
  top: 26px;
  transform: translateX(-50%);
  z-index: 3;
  display: flex;
  gap: 10px;
  align-items: baseline;
  width: max-content;
  max-width: min(440px, 92%);
  padding: 9px 13px;
  border-radius: 10px;
  border: 1px solid var(--brd);
  background: var(--bg);
  box-shadow: 0 14px 38px rgba(0, 0, 0, .3);
  color: var(--text);
  font-size: 14px;
  line-height: 1.35;
  pointer-events: none;
}
.wg-tip[hidden] { display: none; }
.wg-tip-t {
  font-family: var(--font-mono);
  font-size: 12.5px;
  color: var(--indigo-lift);
  flex: 0 0 auto;
}

/* -----------------------------------------------------------------------------
   WHAT WE COVERED (.f-row[data-seek])

   The navigation for this page, so it is bigger at rest than a supporting list.

   THIS IS THE RESOURCES ROW RECIPE, COPIED. Do not improve it.

   The rows on /resources/ are the smoothest magnify on the site, and the
   difference turned out to be a single property: they do not animate a glow.
   A blurred shadow on text has to be repainted from scratch at every frame, at
   every new size, and no amount of layer promotion helps because the shadow is
   part of the paint. That repaint is what made the letters step through sizes
   instead of gliding. Removing it fixed the choppiness outright.

   So: same mono 800 weight at 20px, same --indigo-bright resting to
   --indigo-lift lit, same 1.85 on the number, same --motion-hover timing, and
   crucially the same short transition list of transform and colour only.

   The headings keep the purple and the slightly larger 1.10, which are this
   page's choices. Everything about HOW it moves comes from the resources rows.

   The "this section is playing" signal is a pulsing dot beside the timecode,
   because a dot can pulse forever without touching text paint at all.
   -------------------------------------------------------------------------- */
[data-webinar-jumps] .f-row { padding-top: 22px; padding-bottom: 22px; }
[data-webinar-jumps] .f-row.is-jump { cursor: pointer; }
[data-webinar-jumps] .f-row.is-jump:focus-visible {
  outline: 2px solid var(--indigo-lift);
  outline-offset: 6px;
  border-radius: 10px;
}

/* The number, matched to .res-n property for property. It looked skinny
   because it had no weight of its own and fell back to regular. */
[data-webinar-jumps] .f-num {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 20px;
  font-weight: 800;
  color: var(--indigo-lift);
  padding-top: 0;
  /* Anchor the scale to the top of the DIGITS, not the top of the box.
     Every glyph sits some distance below its own line box, and that gap scales
     with everything else, so anchoring the box corner still walked the digits
     downward: measured at 4x, the ink dropped 5px while the box stayed put.
     0.325em is where the digit tops actually sit in this mono face, measured
     rather than guessed, so scaling now pivots on the ink itself.

     No vertical nudge on top of that. Matching the digit tops to the cap height
     mathematically made them read high, because round glyphs like 0 and 3
     overshoot a flat cap and have to sit a hair lower to look level. The resting
     position was always right. The only thing wrong was the drift on magnify,
     and the pivot alone fixes that. In em so it survives a font-size change. */
  transform-origin: left 0.325em;
  transition: transform var(--motion-hover), color .34s ease;
}
[data-webinar-jumps] .f-row.is-jump:hover .f-num,
[data-webinar-jumps] .f-row.is-active .f-num {
  transform: scale(1.85);
  color: var(--indigo-lift);
}

[data-webinar-jumps] .f-row .h4 {
  display: block;
  margin: 0;
  font-size: 21px;
  /* Same corner anchor as the number. If one grows from its middle and the
     other from its top they drift apart by a pixel or two at full size, which
     is small enough to look like a mistake rather than a choice. Anchored the
     same way they are locked together at every point in the movement. */
  transform-origin: left top;
  transition: transform var(--motion-hover), color .34s ease;
}
[data-webinar-jumps] .f-row.is-jump:hover .h4,
[data-webinar-jumps] .f-row.is-active .h4 {
  transform: scale(1.10);
  /* Theme purple, not white: light purple on dark, dark purple on light. */
  color: var(--indigo-lift);
}

[data-webinar-jumps] .f-row .small-t {
  font-size: 16px;
  margin-top: 8px;
  transform-origin: left center;
  transition: transform var(--motion-hover), color .34s ease;
}
[data-webinar-jumps] .f-row.is-jump:hover .small-t,
[data-webinar-jumps] .f-row.is-active .small-t {
  transform: scale(1.025);
  color: var(--muted);
}

.wg-jump-t {
  display: inline-block;
  margin-left: 10px;
  font-family: var(--font-mono);
  font-size: 14px;
  font-weight: 500;
  color: var(--dim);
  vertical-align: middle;
  transition: color .34s ease;
}
[data-webinar-jumps] .f-row.is-jump:hover .wg-jump-t,
[data-webinar-jumps] .f-row.is-active .wg-jump-t { color: var(--text); }

/* Playing now. The same dot as the event cards, and the only thing on this list
   that answers the video rather than the pointer: hovering a row never shows it,
   and it is absent before playback starts and after the recording ends.

   The dot is a CHILD of this wrapper, not the wrapper itself. .live-dot.anim
   animates its own opacity, so opacity set on it directly is ignored and every
   row showed a half-lit dot. Nested opacity multiplies, so the wrapper can hide
   it outright while the pulse carries on underneath. */
.wg-jump-live {
  display: inline-block;
  margin-left: 9px;
  vertical-align: middle;
  opacity: 0;
  transform: scale(.4);
  transition: opacity .55s ease, transform .55s var(--ease-reveal);
}
.wg-jump-live .live-dot { display: block; }
[data-webinar-jumps] .f-row.is-active .wg-jump-live { opacity: 1; transform: scale(1); }

@media (prefers-reduced-motion: reduce) {
  [data-webinar-jumps] .f-num,
  [data-webinar-jumps] .f-row .h4,
  [data-webinar-jumps] .f-row .small-t { transform: none !important; }
}

/* The recording light on the page's own date line. Same red pip as the event
   cards, sitting on the text baseline rather than floating above it: .live-dot
   is a block, so inline it needs to be told how to sit. */
.wg-rec-dot {
  display: inline-block;
  margin-right: 9px;
  vertical-align: middle;
  position: relative;
  top: -1px;
}


/* --- ./objects/article.css --- */
/* =============================================================================
   EDITORIAL ARTICLE - the global margin structure for long-form articles
   (Thought Leadership pieces). Reuse this object for every future article;
   do NOT restyle margins per page.
   -----------------------------------------------------------------------------
   Page skeleton (two sections share one centred 720px column):

     <section class="container section" data-screen-label="Article">
       <div class="tl-article">
         <a class="tl-back" href="…">← Thought Leadership</a>
         <div class="tl-article-date">June 2026 · Market Structure</div>
         <h1 class="h1 tl-article-title">Headline</h1>
         <div class="tl-byline"> <a class="author-chip">…</a> </div>
       </div>
     </section>
     <section class="container section is-article-body" data-rail="Article">
       <div class="tl-article">
         <p class="tl-lead">Standfirst…</p>
         <div class="tl-body"> <h2>…</h2> <p>…</p> </div>
       </div>
     </section>

   THE MARGIN CONTRACT (keep these as they are):
   - Article column: max-width 720px, centred (margin: 0 auto).
   - Header→body: the body section carries no top padding (.is-article-body),
     so the standfirst sits 34px under the byline (its own margin-top).
   - Body rhythm: h2 +46px above, paragraphs +18px, pull quotes 64px block
     margins, metrics rows 36px block margins.
   ========================================================================== */

.tl-article {
  max-width: 720px;
  margin: 0 auto;
}

/* The body section flows straight on from the article header - no section gap.
   (Overrides the global section rhythm at higher specificity, no !important.) */
.page-body > section + section.is-article-body { padding-top: 0; }

/* Mono date/topic kicker between the back link and the headline.
   .is-accent recolors it indigo (e.g. the live-webinar kicker). */
.tl-article-date {
  font-family: var(--font-mono);
  font-size: 13.5px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--dim);
  margin-top: 26px;
}
/* Accent variant - indigo, and larger: it carries date + time on event pages. */
.tl-article-date.is-accent {
  color: var(--indigo-lift);
  font-size: 16px;
  font-weight: 600;
}
.tl-article-title {
  margin-top: 14px;
  font-size: clamp(34px, 4.6vw, 58px);
  line-height: 1.04;
  letter-spacing: -.035em;
}

/* "← Thought Leadership" return link - arrow nudges, label underlines. */
.tl-back {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-mono);
  font-size: 14px;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--indigo-lift);
  text-decoration: none;
}
.tl-back svg { width: 17px; height: 17px; transition: transform .28s cubic-bezier(.5, 1.4, .5, 1); }
.tl-back:hover svg { transform: translateX(-5px); }
.tl-back span { position: relative; }
.tl-back span::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -2px;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: right center;
  transition: transform .25s cubic-bezier(.5, .5, .2, 1);
}
.tl-back:hover span::after { transform: scaleX(1); transform-origin: left center; }

/* Byline strip under the headline. */
.tl-byline {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-top: 26px;
  padding-top: 22px;
  border-top: 1px solid var(--line);
}

/* -----------------------------------------------------------------------------
   Author chip - avatar + name/role that links out and reveals a bio card on
   hover/focus. Reusable anywhere an author is credited.
   -------------------------------------------------------------------------- */
.author-chip {
  position: relative;
  z-index: 5;
  display: inline-flex;
  align-items: center;
  gap: 17px;
  text-decoration: none;
  transition: transform .3s cubic-bezier(.22, .61, .36, 1);
}
.author-chip:hover,
.author-chip:focus-visible {
  transform: translateY(-2px);
  outline: none;
  z-index: 60;
}
.author-ava {
  width: 68px;
  height: 68px;
  border-radius: 50%;
  overflow: hidden;
  flex: 0 0 auto;
  background: #fff;
  box-shadow: 0 0 0 1px var(--brd-strong);
  transition: box-shadow .32s ease, transform .35s cubic-bezier(.34, 1.45, .5, 1);
}
.author-ava img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 29%;
  display: block;
}
.author-chip:hover .author-ava,
.author-chip:focus-visible .author-ava {
  box-shadow: 0 0 0 2px var(--indigo-bright), 0 8px 20px color-mix(in srgb, var(--indigo-bright) 34%, transparent);
  transform: scale(1.06);
}
.author-meta {
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.author-chip .author-name {
  /* Family stated rather than inherited, and the weight dropped from 800 to
     the 700 both card bylines use. Inter does ship 800, so this was never a
     different face, only the one place on the site running two steps heavier
     than every other author name. */
  font-family: var(--font-sans);
  font-size: 20.5px;
  font-weight: 700;
  color: var(--text);
  line-height: 1.25;
  text-decoration: underline transparent;
  text-underline-offset: 3px;
  text-decoration-thickness: 1.5px;
  transition: text-decoration-color .25s ease;
}
.author-chip:hover .author-name,
.author-chip:focus-visible .author-name { text-decoration-color: var(--indigo-bright); }
.author-role {
  font-family: var(--font-sans);
  font-size: 16px;
  color: var(--dim);
  line-height: 1.25;
  margin-top: 2px;
}
.author-bio {
  position: absolute;
  left: 0;
  bottom: calc(100% + 13px);
  top: auto;
  width: 360px;
  max-width: 82vw;
  background: var(--elev);
  border: 1px solid var(--brd-hover);
  border-radius: 14px;
  padding: 15px 18px 16px;
  font-size: 13.5px;
  line-height: 1.6;
  color: var(--muted);
  box-shadow: var(--shadow);
  text-wrap: pretty;
  opacity: 0;
  visibility: hidden;
  transform: translateY(8px);
  transform-origin: left bottom;
  transition: opacity .26s ease, transform .3s cubic-bezier(.22, .61, .36, 1), visibility .26s;
  pointer-events: none;
  z-index: 40;
}
.author-bio::before {
  content: "About the author";
  display: block;
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: .15em;
  text-transform: uppercase;
  color: var(--indigo-lift);
  margin-bottom: 7px;
  font-weight: 500;
}
.author-chip:hover .author-bio,
.author-chip:focus-visible .author-bio {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

/* -----------------------------------------------------------------------------
   Article typography - standfirst, running copy, drop word, pull quote.
   -------------------------------------------------------------------------- */
.tl-lead {
  font-size: clamp(19px, 2vw, 22px);
  line-height: 1.55;
  color: var(--text);
  font-weight: 500;
  margin: 34px 0 0;
  letter-spacing: -.01em;
}
.tl-body { margin-top: 8px; }
.tl-body h2 {
  font-size: clamp(21px, 2.2vw, 27px);
  font-weight: 700;
  letter-spacing: -.015em;
  color: var(--text);
  margin: 46px 0 0;
}
.tl-body p {
  font-size: 17.5px;
  line-height: 1.78;
  color: var(--muted);
  margin: 18px 0 0;
}
.tl-body p:first-of-type { clear: left; }
.tl-body strong { color: var(--text); font-weight: 700; }
/* --indigo-lift, not --indigo: --indigo is a fill colour with no dark pair and
   renders at 2.94:1 on the dark page. See the note in foundation/tokens.css. */
.tl-body strong.accent { color: var(--indigo-lift); }

/* Oversized opening word floated into the first paragraph. */
.tl-dropword {
  float: left;
  font-size: 3.05em;
  font-weight: 800;
  line-height: .8;
  padding: 8px 16px 2px 0;
  margin-top: 4px;
  color: var(--indigo-lift);
  letter-spacing: -.02em;
}

/* Centred pull quote with the indigo bar; magnifies as it scrolls through
   the viewport on browsers that support scroll-driven animations. */
.tl-body p.tl-pull {
  position: relative;
  margin: 64px auto;
  padding: 0 8px;
  max-width: 680px;
  border: 0;
  text-align: center;
  text-wrap: balance;
  font-size: clamp(26px, 3.4vw, 40px);
  line-height: 1.28;
  font-weight: 700;
  color: var(--text);
  letter-spacing: -.022em;
  transform-origin: center center;
}
.tl-body p.tl-pull::before {
  content: "";
  display: block;
  position: static;
  width: 48px;
  height: 3px;
  border-radius: 3px;
  margin: 0 auto 26px;
  background: var(--indigo-bright);
  box-shadow: 0 0 14px var(--indigo-bright);
}
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .tl-body p.tl-pull {
      animation: pullMagnify linear both;
      animation-timeline: view();
      animation-range: cover 12% cover 88%;
    }
  }
}
@keyframes pullMagnify {
  0% { opacity: .32; transform: scale(.9); }
  50% { opacity: 1; transform: scale(1.05); }
  100% { opacity: .32; transform: scale(.9); }
}

/* -----------------------------------------------------------------------------
   In-article metric rows - stat + description pairs with the hover bar.
   -------------------------------------------------------------------------- */
.tl-metrics {
  margin: 36px 0;
  border-top: 1px solid var(--line);
}
.tl-metric {
  position: relative;
  display: grid;
  grid-template-columns: minmax(150px, 200px) 1fr;
  gap: 28px;
  align-items: center;
  padding: 24px 4px 24px 16px;
  border-bottom: 1px solid var(--line);
  transition: padding-left .32s cubic-bezier(.22, .61, .36, 1);
}
.tl-metric::before {
  content: "";
  position: absolute;
  left: 0;
  top: 20px;
  bottom: 20px;
  width: 2px;
  border-radius: 2px;
  background: var(--indigo-bright);
  box-shadow: 0 0 12px var(--indigo-bright);
  transform: scaleY(0);
  transform-origin: center;
  opacity: 0;
  transition: transform .36s cubic-bezier(.22, .61, .36, 1), opacity .28s ease;
}
.tl-metric:hover::before { transform: scaleY(1); opacity: 1; }
.tl-metric .stat-num {
  margin: 0;
  transform-origin: left center;
  will-change: transform;
  transition: transform .4s cubic-bezier(.22, .61, .36, 1);
}
.tl-metric:hover .stat-num { transform: translateX(8px) scale(1.1); }
.tl-metric .stat-num .u { color: var(--indigo-lift); margin-left: -.05em; }
/* Unit gap correction. The default -.05em is tuned for wide-bearing digits
   like "1" (12.1M reads with a clear ~8px ink gap). "4" and "5" carry almost
   no right bearing, so % and B need positive margins to land the SAME visual
   gap (values measured from glyph ink at 800/46px). */
.tl-metric .stat-num .u.is-pct { margin-left: .12em; }
.tl-metric .stat-num .u.is-b { margin-left: .08em; }
.tl-metric:hover .stat-num .u { animation: uShimmer .6s ease-out 1; }
@keyframes uShimmer {
  0%, 100% { color: var(--indigo-lift); text-shadow: none; }
  42% { color: var(--grad-hi); text-shadow: 0 0 13px color-mix(in srgb, var(--indigo-lift) 75%, transparent); }
}
.tl-metric .d {
  font-size: 15.5px;
  line-height: 1.62;
  color: var(--muted);
  margin: 0;
  transform-origin: left center;
  will-change: transform;
  transition: color .3s ease, transform .38s cubic-bezier(.22, .61, .36, 1);
}
.tl-metric:hover .d { color: var(--text); transform: translateX(8px) scale(1.03); }
@media (max-width: 600px) {
  .tl-metric { grid-template-columns: 1fr; gap: 8px; padding: 22px 4px; }
}

/* End-of-article CTA sits 48px under the last paragraph. */
.tl-article .cta-shine { margin-top: 48px; }

/* -----------------------------------------------------------------------------
   AUTHOR AVATAR (.ava)
   One framing for every headshot, everywhere. The source portraits are 640x1138
   and the chosen circle is 790px across, centred at 320, 464. That circle is
   WIDER than the image, so the photo cannot fill it: 640/790 is 81.01% of the
   circle, leaving a sliver either side. That sliver is white on purpose, so the
   cut-out reads as the subject on a card rather than as a crop that ran out.

   Every number below is that one circle expressed against the box:
     width  640 / 790 = 81.01%
     height 1138 / 790 = 144.05%   (set by the width, so it is not declared)
     left   0.5 - 320/790 = 9.49%
     top    0.5 - 464/790 = -8.73%
   Change the circle and change these four together, nothing else.
   -------------------------------------------------------------------------- */
.ava {
  position: relative;
  flex: 0 0 auto;
  border-radius: 50%;
  overflow: hidden;
  background: #fff;
  box-shadow: 0 0 0 1px var(--brd);
}
.ava img {
  position: absolute;
  left: 9.49%;
  top: -8.73%;
  width: 81.01%;
  height: auto;
  display: block;
}
/* Sizes are named for the slot, not a pixel value, so they can be tuned without
   the class turning into a lie. */
.ava.is-card    { width: 60px; height: 60px; }   /* blog cards */
.ava.is-feature { width: 72px; height: 72px; }   /* homepage featured card */

/* The article byline already had its own wrapper, so it only needs the framing. */
.author-ava img {
  position: absolute;
  left: 9.49%;
  top: -8.73%;
  width: 81.01%;
  height: auto;
  object-fit: unset;
  object-position: unset;
}
.author-ava { position: relative; }

/* The name and role sit in a two-line block beside a circle. align-items:center
   on the row centres the block, but only if the block's own height is the sum
   of two predictable lines, which is what the line-heights above pin down. The
   flex rows are restated here so a future change to one does not quietly drop
   the centring on another. */
.tl-byline,
.tl-feat-author,
.byrow { align-items: center; }
.author-meta,
.tl-feat-author > div,
.byrow > div { display: flex; flex-direction: column; justify-content: center; }


/* --- ./pages/article-ai-post-trade.css --- */
/* =============================================================================
   ARTICLE FIGURES - "How AI Is Changing Post-Trade Operations for the Better"
   -----------------------------------------------------------------------------
   Page-scoped feature visuals. Everything is composed from foundation/tokens.css.

   ONE RULE ACROSS EVERY FIGURE:
   all of the content is readable at rest, and the motion plays ONCE when the
   figure first enters the viewport. Nothing is hidden behind a hover. The
   trigger is the `is-lit` class, added by article-ai-post-trade.js on first
   intersection and never removed, so a figure stays in its finished state for
   the rest of the visit.

   Devices, in reading order, none repeated:
     1. .five     the five questions magnify in sequence and stay magnified
     2. .feeds    six sources slide in off the edges into one record, one at a time
     3. .stl      settlement checks change state as a playhead sweeps the axis
     4. .ask      question types, answer resolves out of a running cypher
     5. .markfig  the mark traces itself slowly and fills in brand purple
     6. .gov      controls write themselves out, get their mark, then roll

   No rules between items anywhere: spacing does the separating.
   ========================================================================== */

/* -----------------------------------------------------------------------------
   Shared plumbing
   -------------------------------------------------------------------------- */
.tl-body .fig { margin: 44px 0; padding: 0; }

/* Break out of the 720px article column for the wide instruments. The max()
   stops the breakout ever coming out NARROWER than the column itself, which it
   did at the middle widths where the page gutter is at its widest. */
.tl-body .fig-wide {
  --wide: max(100%, min(1060px, calc(100vw - 2 * var(--gutter))));
  width: var(--wide);
  margin-left: 50%;
  transform: translateX(-50%);
}

.tl-body .fig ul,
.tl-body .fig ol { list-style: none; margin: 0; padding: 0; }

/* Snap a figure back to its rest state with no motion at all. Used for one
   frame by SSFig.replay so a replay starts from zero rather than from wherever
   the previous run had got to. */
.ss-noanim,
.ss-noanim *,
.ss-noanim *::before,
.ss-noanim *::after {
  transition: none !important;
  animation: none !important;
}


/* =============================================================================
   1 · .five - the five questions
   At rest all five are on the page, small and dim. On view they magnify one
   after another, top to bottom, and stay magnified.
   The list is a block centred on the column, but the lines share one left edge
   and the numbers sit in their own gutter: centring each line individually made
   the stack read ragged. Growth is from the left edge for the same reason.
   ========================================================================== */
.five { }
.five-list {
  display: grid;
  gap: 22px;
  width: fit-content;
  max-width: 100%;
  margin: 0 auto;
  padding: 16px 0 20px;
}
.five-q {
  position: relative;
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 16px;
  align-items: baseline;
  font-size: clamp(20px, 2.5vw, 29px);
  font-weight: 600;
  line-height: 1.28;
  letter-spacing: -.02em;
  color: var(--dim);
  transform: scale(.78);
  transform-origin: left center;
  opacity: .28;
  /* One long, single-direction ease. The earlier spring overshoot is what made
     the cascade feel jumpy rather than played. */
  transition:
    transform 1.55s var(--ease-reveal),
    opacity   1.05s cubic-bezier(.3, .7, .3, 1),
    color     1.05s ease;
  transition-delay: calc(var(--i) * .3s);
  will-change: transform, opacity;
}
.five.is-lit .five-q { transform: scale(1); opacity: 1; color: var(--text); }

/* Hover only makes sense once the cascade has finished. `is-settled` (added by
   the script when the last line lands) drops the stagger delay, otherwise a
   hover on line five would wait most of a second before answering. */
/* The site's hover magnify, not one of my own: --window-hover-transform is
   scale(1.025) and --motion-hover is .95s of --ease-reveal. Every magnify on
   this page uses those two so the article behaves like the rest of the site. */
.five.is-settled .five-q {
  transition: transform var(--motion-hover), color .45s ease;
  transition-delay: 0s;
  cursor: default;
}
.five.is-settled .five-q:hover { transform: var(--window-hover-transform); }
.five.is-settled .five-q:hover .five-n { color: var(--grad-hi); }

/* No rule under each question: the magnification alone carries the beat. */

.five-n {
  font-family: var(--font-mono);
  font-size: .78em;
  font-weight: 600;
  letter-spacing: .16em;
  color: var(--dim);
  transition: color .95s ease;
  transition-delay: calc(var(--i) * .27s + .16s);
}
.five.is-lit .five-n { color: var(--indigo-lift); }
.five-t { text-wrap: pretty; }

@media (max-width: 620px) {
  .five-list { gap: 17px; width: auto; }
  .five-q { gap: 11px; }
}


/* =============================================================================
   2 · .puzzle - the shape in the middle
   Eight sources arrive from beyond the edges and interlock. Four of them meet
   at the centre of the board, and the hole their inner edges leave between them
   is the mark. Nothing is added to finish the record: the record is finished by
   the shape the pieces make. The outline then draws in purple, the board locks
   gold, and a soft bloom comes out of the hole.

   The hole is a mask over the whole board rather than eight hand-cut pieces:
   exact, and it survives any change to the grid. The gold is the system's
   --warn pair; there is no gold token, and a literal hex here would be the only
   hard-coded colour on the page.
   ========================================================================== */
.puzzle {
  --beat: .5s;
  --seat: 4.6s;      /* 7 * beat + the last piece's travel */
  --lock: 5s;
  --logo: 5.7s;      /* the mark arrives once the board has gone gold */
}

/* Centred over the board, which is itself centred in the column. */
.pz-head {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 14px;
  padding-bottom: 14px;
}
.pz-head-k {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: .22em;
  text-transform: uppercase;
  font-weight: 600;
  color: var(--dim);
  transition: color 1.1s ease;
  transition-delay: var(--lock);
}
.puzzle.is-lit .pz-head-k { color: var(--warn); }
.pz-head-id {
  font-size: 17px;
  font-weight: 800;
  letter-spacing: -.02em;
  color: var(--text);
}

.pz-stage {
  position: relative;
  overflow: hidden;          /* this is what puts the pieces off screen */
}
.pz-svg { display: block; width: 100%; height: auto; }

/* ---- the eight pieces --------------------------------------------------- */
.pz-piece {
  transform: translate(var(--tx), var(--ty)) rotate(var(--rot));
  transform-origin: 470px 370px;
  opacity: 0;
  will-change: transform, opacity;
  transition:
    transform 1.3s var(--ease-reveal),
    opacity    .5s ease;
  transition-delay: calc(var(--o) * var(--beat));
}
.puzzle.is-lit .pz-piece { transform: translate(0px, 0px) rotate(0deg); opacity: 1; }


/* Two paths per piece. The base is the panel and never changes; the gold is a
   translucent wash laid over it. Tinting the panel itself with --warn-bg turned
   the white pieces into flat beige, because --warn-bg is an alpha colour and it
   was replacing the white rather than sitting on it. */
.pz-base {
  fill: var(--panel-2);
  fill-rule: evenodd;
}
.pz-shape {
  fill: transparent;
  fill-rule: evenodd;
  stroke: var(--brd-strong);
  stroke-width: 1.2;
  vector-effect: non-scaling-stroke;
  transition: fill 1.2s ease, stroke 1.2s ease;
  transition-delay: var(--lock);
}
.puzzle.is-lit .pz-shape { fill: var(--warn-bg); stroke: var(--warn); }
/* The mark, arriving in the window the cutter left. The board is cut with the
   silhouette, counter and all, so nothing is standing inside the shape for
   this to fight with. It is the only brand purple on the figure, and it lands
   after the board has locked, so the sequence reads: pieces, record, mark. */
.pz-logo {
  fill: var(--indigo-bright);
  opacity: 0;
  transform-origin: 470px 370px;
}
.puzzle.is-lit .pz-logo {
  animation: pzLogo 1.9s var(--ease-reveal) both;
  animation-delay: var(--logo);
}
@keyframes pzLogo {
  from { opacity: 0; transform: scale(.975); }
  to   { opacity: 1; transform: scale(1); }
}

.pz-t1, .pz-t2 {
  text-anchor: middle;
  font-family: var(--font-sans);
  fill: var(--muted);
  transition: fill 1.2s ease;
  transition-delay: var(--lock);
}
/* The board is no longer stretched across the wide measure, so a viewBox unit
   is close to a CSS pixel and the labels can simply be set at a readable size
   instead of being scaled down to nothing. */
.pz-t1 { font-size: 37px; font-weight: 700; letter-spacing: -.015em; }
.pz-t2 { font-size: 31px; font-weight: 500; }
.puzzle.is-lit .pz-t1 { fill: var(--text); }

/* Nothing sits in the middle: the cutter took it. What you see through the
   shape is the page, and the line around it is the border of whichever pieces
   the cutter bit into. */


/* =============================================================================
   3 · .stl - settlement checks, caught before settlement
   A horizontal timeline. The axis runs trade date to settlement, ticks carry
   the sense of time passing, and a one pixel playhead sweeps across them. Each
   row is one check; it changes state when the playhead reaches that position.

   STATE MODEL, and nothing outside it
     grey    unverified     the check has not completed yet
     amber   fail risk      predictive, this may fail
     red     expected fail  concrete, this will fail unless someone acts
     purple  verified       fixed and confirmed

   A segment takes the colour of the state that STARTED it, so the line after a
   red dot stays red until the next dot lands. Every class here is prefixed:
   the panel uses names like row, label, chip and dot, all of which already mean
   something else on this site.
   ========================================================================== */
.stl {
  --stl-rule: var(--hair, rgba(94, 65, 238, .10));
  --stl-tickh: 16px;
  --stl-tick: #b8b3d2;
  --stl-tick-major: #8d86b5;
  --stl-tick-rule: rgba(94, 65, 238, .12);
  --stl-axis: var(--muted);
  --stl-grey-txt: var(--muted);
  --stl-grey-bg: rgba(124, 120, 137, .13);
  --stl-amber: #e0921a;
  --stl-amber-txt: #8a5a05;
  --stl-amber-bg: rgba(224, 146, 26, .15);
  --stl-red: #e0455f;
  --stl-red-txt: #b02439;
  --stl-red-bg: rgba(224, 69, 95, .13);
  --stl-purple: #5e41ee;
  --stl-purple-dot: #6b53f0;
  --stl-purple-txt: #4630c4;
  --stl-purple-bg: rgba(94, 65, 238, .11);
  /* Settlement reached. The only place green is used, and it means done. */
  --stl-green: #12a878;
  --stl-green-txt: #0a7550;
  --stl-green-bg: rgba(18, 168, 120, .14);
  --stl-track: rgba(94, 65, 238, .20);
}
/* The signal colours are tuned for the light page. On the dark page the same
   hues sit far too close to the background, the purple worst of all, so every
   one of them is lifted here. The meanings do not change, only the values. */
[data-theme="dark"] .stl {
  --stl-rule: rgba(255, 255, 255, .09);
  --stl-tick: #6d6890;
  --stl-tick-major: #8f89b5;
  --stl-tick-rule: rgba(255, 255, 255, .13);

  --stl-amber: #f2ac3f;
  --stl-amber-txt: #f5c377;
  --stl-amber-bg: rgba(242, 172, 63, .16);

  --stl-red: #ff667c;
  --stl-red-txt: #ff93a3;
  --stl-red-bg: rgba(255, 102, 124, .16);

  --stl-purple: #9179ff;
  --stl-purple-dot: #a692ff;
  --stl-purple-txt: #bcaeff;
  --stl-purple-bg: rgba(145, 121, 255, .18);
  --stl-track: rgba(145, 121, 255, .24);

  --stl-green: #2fd7a0;
  --stl-green-txt: #64e3ba;
  --stl-green-bg: rgba(47, 215, 160, .17);
}

/* No surface and no column field: the timeline sits on the page like every
   other figure in this article, so it follows the theme instead of fighting it. */
.stl-panel {
  position: relative;
  width: 100%;
  padding: 2px 0 0;
  color: var(--text);
}
.stl-axis {
  position: relative;
  display: flex;
  justify-content: space-between;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--stl-axis);
  margin-bottom: 9px;
}
/* Grey until the sweep actually gets there. It is a destination, not a
   result, so it has no business being green from the first frame. */
.stl-end { color: var(--stl-axis); transition: color .5s ease; }
.stl-end.is-settled { color: var(--stl-green); }
.stl-end.is-settled { animation: stlSettle 1.6s cubic-bezier(.2, .8, .3, 1) both; }
@keyframes stlSettle {
  0%   { text-shadow: none; letter-spacing: .18em; opacity: .85; }
  35%  { text-shadow: 0 0 14px rgba(14, 156, 110, .55); letter-spacing: .24em; opacity: 1; }
  100% { text-shadow: 0 0 0 rgba(14, 156, 110, 0); letter-spacing: .18em; opacity: 1; }
}
/* Ticks are a scale, not an effect. They sit still on a hairline; the playhead
   is the only thing that moves across them. A taller mark every fifth gives
   the eye something to count. */
.stl-ticks {
  position: relative;
  height: var(--stl-tickh);
  margin-bottom: 20px;
  border-bottom: 1px solid var(--stl-tick-rule);
}
/* Readable standing still, not only under the lens: every tick is a real mark
   at rest and every fifth is heavier and full height, so the scale can be
   counted without waiting for the sweep. */
.stl-ticks i {
  position: absolute;
  bottom: 0;
  width: 1px;
  height: 10px;
  background: var(--stl-tick);
  transform-origin: bottom center;
  transform: scaleY(.62);
  opacity: .62;
  will-change: transform, opacity;
}
.stl-ticks i.is-major {
  width: 2px;
  height: var(--stl-tickh);
  background: var(--stl-tick-major);
  opacity: .85;
}

/* The playhead fills this box, so it spans the ticks to the last line by
   construction. It used to be measured and set in pixels, which drifted the
   moment anything above it reflowed. It starts on the line the ticks stand on
   rather than cutting through them, and bottom 12px is the last row's 8px of
   padding plus the 4px under its 2px line. */
.stl-body { position: relative; }
.stl-rows { position: relative; transition: opacity .42s ease; }
/* The last half second of the hold, so a cycle ends by fading out rather
   than by everything vanishing on one frame. */
.stl-rows.is-cycling { opacity: 0; }
.stl-row {
  position: relative;
  padding: 0 0 20px;
  margin-bottom: 16px;
  border-bottom: 1px solid var(--stl-rule);
}
.stl-row:last-child { border-bottom: 0; margin-bottom: 0; padding-bottom: 8px; }
.stl-label {
  font-size: 16.5px;
  font-weight: 700;
  letter-spacing: -.01em;
  line-height: 1.25;
  margin-bottom: 9px;
  color: var(--text);
}
/* One status line, held in place. Fades out, swaps, fades back in, so there is
   never a frame with two states on the same row. */
.stl-status {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 9px;
  min-height: 19px;
  margin-bottom: 15px;
  opacity: 1;
  transition: opacity .22s ease;
}
.stl-status.is-swapping { opacity: 0; }
.stl-chip {
  display: inline-block;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  line-height: 1.35;
  padding: 3px 7px;
  border-radius: 3px;
  white-space: nowrap;
}
.stl-chip.is-grey   { color: var(--stl-grey-txt);   background: var(--stl-grey-bg); }
.stl-chip.is-amber  { color: var(--stl-amber-txt);  background: var(--stl-amber-bg); }
.stl-chip.is-red    { color: var(--stl-red-txt);    background: var(--stl-red-bg); }
.stl-chip.is-purple { color: var(--stl-purple-txt); background: var(--stl-purple-bg); }
.stl-chip.is-green  { color: var(--stl-green-txt);  background: var(--stl-green-bg); }
.stl-cause { font-size: 15.5px; line-height: 1.5; }
.stl-cause.is-grey   { color: var(--stl-grey-txt); }
.stl-cause.is-amber  { color: var(--stl-amber-txt); }
.stl-cause.is-red    { color: var(--stl-red-txt); }
.stl-cause.is-purple { color: var(--stl-purple-txt); }
.stl-cause.is-green  { color: var(--stl-green-txt); }

.stl-track { position: relative; height: 10px; }
.stl-base {
  position: absolute;
  left: 0; right: 0; top: 4px;
  height: 2px;
  background: var(--stl-track);
  border-radius: 2px;
}
.stl-seg {
  position: absolute;
  top: 4px;
  height: 2px;
  border-radius: 2px;
  transition: background-color .6s cubic-bezier(.22, .78, .3, 1);
}
.stl-seg.is-amber  { background: var(--stl-amber); }
.stl-seg.is-red    { background: var(--stl-red); }
.stl-seg.is-purple { background: var(--stl-purple); }
.stl-dot {
  position: absolute;
  top: 5px;
  width: 9px; height: 9px;
  margin-left: -4.5px; margin-top: -4.5px;
  border-radius: 50%;
  background: currentColor;
  animation: stlPop .5s cubic-bezier(.2, .9, .25, 1.35) both;
  transition: color .6s cubic-bezier(.22, .78, .3, 1);
}
.stl-dot.is-amber  { color: var(--stl-amber); }
.stl-dot.is-red    { color: var(--stl-red); }
.stl-dot.is-purple { color: var(--stl-purple-dot); }
.stl-dot.is-green  { color: var(--stl-green); }
@keyframes stlPop { from { transform: scale(.2); opacity: 0; } to { transform: scale(1); opacity: 1; } }
.stl-dot::after {
  content: "";
  position: absolute;
  inset: -4px;
  border-radius: 50%;
  background: currentColor;
  opacity: .15;
}
.stl-dot.is-live::after { animation: stlRing 2.1s cubic-bezier(.25, .6, .35, 1) infinite; }
@keyframes stlRing {
  0%   { transform: scale(.75); opacity: .32; }
  65%  { transform: scale(1.9); opacity: 0; }
  100% { transform: scale(1.9); opacity: 0; }
}
/* Present from the first frame. It only collapses once settlement is reached. */
.stl-head {
  position: absolute;
  top: var(--stl-tickh);
  bottom: 12px;
  /* Same weight as a major tick, and it starts ON the rule the ticks stand on
     rather than one pixel under it, so the two read as one continuous mark. */
  width: 2px;
  background: color-mix(in srgb, var(--text) 26%, transparent);
  pointer-events: none;
  transform-origin: center;
  transition: transform .95s cubic-bezier(.4, 0, .2, 1), opacity .95s ease;
}
.stl-head.is-collapsed { transform: scaleY(0); opacity: 0; }
/* No instant reset any more: coming out of is-collapsed runs the same
   transition backwards, so the line grows from its middle back to full
   height instead of snapping in. */

@media (max-width: 760px) {
  .stl-axis { font-size: 10px; }
  .stl-label { font-size: 15px; }
  .stl-cause { font-size: 13.5px; }
}


/* =============================================================================
   4 · .ask - the plain-English console
   The question types. The answer is not boxed: it resolves out of character
   noise, left to right, behind a travelling scan line, then sits at full
   reading contrast.
   ========================================================================== */
.ask {
  border: 1px solid var(--brd);
  border-radius: var(--radius-lg);
  background: var(--elev);
  overflow: hidden;
  box-shadow: var(--shadow);
}
.ask-bar {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 11px 18px;
  border-bottom: 1px solid var(--line);
}
.ask-k {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--indigo-lift);
  font-weight: 600;
}
.ask-dots { display: inline-flex; gap: 5px; }
.ask-dots i { width: 5px; height: 5px; border-radius: 50%; background: var(--brd-strong); }
.ask-state {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--dim);
}
/* Fixed geometry, sized to the longest line each slot ever holds. The question
   and the answer both change length every cycle, so the boxes reserve exactly
   what they need: the window must neither breathe nor carry dead space. */
/* The question slot is two lines tall whether or not this question needs two.
   At narrow widths several of them wrap, and a one-line slot let the wrapped
   second line run straight through the rule below it. */
.ask-body { padding: 22px 22px 20px; height: 178px; }
.ask-line { display: flex; align-items: baseline; gap: 10px; height: 58px; }
.ask-caret { font-family: var(--font-mono); font-size: 17px; color: var(--indigo-lift); line-height: 1; }
.ask-q {
  font-size: 18px;
  font-weight: 600;
  line-height: 1.45;
  color: var(--text);
  letter-spacing: -.01em;
}
.ask-cursor {
  display: inline-block;
  width: 9px; height: 18px;
  transform: translateY(2px);
  background: var(--indigo-bright);
  animation: askBlink 1s steps(1) infinite;
}
@keyframes askBlink { 0%, 49% { opacity: 1; } 50%, 100% { opacity: 0; } }

/* The answer region. A rule wipes open, a scan line crosses once, and the
   characters lock in behind it. No box, no tinted panel. */
.ask-out { position: relative; margin-top: 6px; padding-top: 16px; height: 72px; }
.ask-rule {
  position: absolute;
  left: 0; right: 0; top: 0;
  height: 1px;
  background: color-mix(in srgb, var(--indigo-bright) 45%, transparent);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform .5s var(--ease-out);
}
.ask-out.is-open .ask-rule { transform: scaleX(1); }
/* Centre the mark against the whole answer, not its first line, so it stays
   put whether the answer wraps to one line or three. */
.ask-a { display: flex; gap: 11px; align-items: center; }
/* The mark stands in for a bullet, and only appears once there is an answer. */
.ask-arrow {
  flex: 0 0 auto;
  width: 15px;
  /* No nudge. .ask-a centres it, so it lands right on one line or three;
     the old translateY was a leftover from when this row was baseline-aligned. */
  opacity: 0;
  transition: opacity .3s ease;
}
.ask-arrow .ask-mk { display: block; width: 100%; height: auto; }
.ask-arrow .ask-mk path { fill: var(--indigo-bright); }
.ask-out.is-open .ask-arrow { opacity: 1; }
.ask-a-t {
  font-size: 16px;
  line-height: 1.65;
  color: var(--text);
  font-weight: 500;
  letter-spacing: -.005em;
  text-wrap: pretty;
}
/* Characters still resolving read as noise: mono, dim, no weight. */
.ask-a-t .n {
  font-family: var(--font-mono);
  font-weight: 400;
  color: var(--indigo-lift);
  opacity: .55;
}


/* =============================================================================
   5 · .markfig - the mark, drawn
   Starts empty. The first line types itself while the mark traces, then that
   line goes as the mark fills in brand purple, and the line that actually
   matters arrives underneath it, larger. No numbers: there are none worth
   claiming for this section.
   ========================================================================== */
.mk-stage {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
  padding: 22px 0 26px;
  text-align: center;
}

/* Line one. Typed by the script, then dismissed. */
.mk-top {
  min-height: 1.5em;
  font-family: var(--font-mono);
  font-size: 13.5px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--dim);
  transition: opacity 2.3s var(--ease-reveal), transform 2.3s var(--ease-reveal);
  transition-delay: var(--after, 2.4s);
}
/* Dimmed, not dismissed: it is still the first half of the sentence. */
.markfig.is-lit .mk-top { opacity: .38; transform: translateY(-4px); }

.mk-mark { position: relative; display: block; width: clamp(84px, 10vw, 108px); }
.mk-svg { display: block; width: 100%; height: auto; overflow: visible; }

/* The trace. pathLength="1" normalises both blades so one dash rule draws
   either of them regardless of their real length, and both are always at the
   same fraction, so they draw together. */
.mk-t {
  fill: none;
  stroke: var(--indigo-bright);
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
  stroke-dasharray: 1 1;
  stroke-dashoffset: 1;
}
/* No CSS animation on the trace: a second clock is exactly what let it drift.
   The script writes stroke-dashoffset every frame from the same progress value
   that drives the typing, so the two cannot separate. The stroke runs on the
   continuous value and the text on the same value rounded to whole characters,
   which is what keeps the line smooth while the text still ticks over one
   letter at a time. */

/* The fill arrives behind the finished outline, in the brand purple. */
.mk-f {
  fill: var(--indigo-bright);
  opacity: 0;
  transform-origin: 91px 95px;
}
.markfig.is-lit .mk-f {
  animation: mkFill 2.3s var(--ease-reveal) both;
  animation-delay: var(--after, 2.4s);
}
@keyframes mkFill {
  from { opacity: 0; transform: scale(.965); }
  to   { opacity: 1; transform: scale(1); }
}

.mk-glow {
  position: absolute;
  inset: -36%;
  border-radius: 50%;
  background: radial-gradient(circle, color-mix(in srgb, var(--indigo-bright) 34%, transparent), transparent 68%);
  opacity: 0;
}
.markfig.is-lit .mk-glow { animation: mkBloom 3s ease-out var(--after, 2.4s) both; }
@keyframes mkBloom {
  0%   { opacity: 0;   transform: scale(.6); }
  35%  { opacity: 1;   transform: scale(1.05); }
  100% { opacity: .3;  transform: scale(1); }
}

/* Line two. The one worth reading, so it is the one that is set large. */
.mk-btm {
  font-size: clamp(22px, 2.8vw, 31px);
  font-weight: 700;
  line-height: 1.25;
  letter-spacing: -.025em;
  color: var(--text);
  text-wrap: balance;
  opacity: 0;
  transform: translateY(10px);
  /* Same delay, same duration, same easing as the fill above. They are one
     event and they have to be described identically or they drift apart. */
  transition: opacity 2.3s var(--ease-reveal), transform 2.3s var(--ease-reveal);
  transition-delay: var(--after, 2.4s);
}
.markfig.is-lit .mk-btm { opacity: 1; transform: none; }


/* =============================================================================
   6 · .gov - the control ledger
   Line and note write themselves out together, slowly. When both finish the row
   pulses, and only then does its mark get drawn. When the last one lands the
   ledger ripples top to bottom in one smooth pass and every row ends magnified
   and lit. The marks carry no box: mark, line, rule, nothing else.
   ========================================================================== */
.gov-row {
  display: grid;
  grid-template-columns: 30px 1fr;
  gap: 16px;
  will-change: transform;
  /* Centred, so the mark sits on the optical middle of the line and its note. */
  align-items: center;
  padding: 13px 2px;
  transform-origin: left center;
}

.gov-check { display: flex; align-items: center; justify-content: center; }
.gov-check svg {
  width: 19px; height: 19px;
  fill: none;
  stroke: var(--indigo-bright);
  stroke-width: 2.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  overflow: visible;
}
.gov-check path {
  stroke-dasharray: 26;
  stroke-dashoffset: 26;
  transition: stroke-dashoffset .75s cubic-bezier(.3, .8, .3, 1);
}
.gov-row.is-done .gov-check path { stroke-dashoffset: 0; }
.gov-row.is-done .gov-check svg { filter: drop-shadow(0 0 7px color-mix(in srgb, var(--indigo-bright) 65%, transparent)); }

.gov-txt { display: block; min-height: 52px; }
.gov-name {
  display: block;
  font-size: 19px;
  font-weight: 600;
  line-height: 1.35;
  color: var(--muted);
  transition: color .5s ease;
}
.gov-note {
  display: block;
  margin-top: 3px;
  font-family: var(--font-mono);
  font-size: 14px;
  letter-spacing: .04em;
  line-height: 1.5;
  color: var(--dim);
  transition: color .5s ease;
}
/* Characters still resolving read as noise, exactly as they do in the console. */
.gov-name .n, .gov-note .n {
  font-family: var(--font-mono);
  font-weight: 400;
  color: var(--indigo-lift);
  opacity: .55;
}

/* The beat every row lands on once the cypher clears. */
.gov-row.is-pulse { animation: govPulse .72s cubic-bezier(.37, 0, .28, 1) 1; }
@keyframes govPulse {
  0%   { transform: scale(1); }
  45%  { transform: scale(1.04); }
  100% { transform: scale(1); }
}

/* All systems go: one smooth pass down the ledger that ENDS magnified. */
.gov-ledger.is-roll .gov-row {
  animation: govRoll 1.45s cubic-bezier(.37, 0, .28, 1) both;
  animation-delay: calc(var(--i) * .17s);
}
/* The one deliberate exception to the hover-magnify rule on this page: this is
   a ripple, not a hover, so it rises past the resting scale and comes back to
   it rather than stopping there. Symmetric ease in and out, no overshoot. */
@keyframes govRoll {
  0%   { transform: scale(1); }
  45%  { transform: scale(1.05); }
  100% { transform: scale(1); }
}
.gov-ledger.is-roll .gov-check svg {
  animation: govFlash 1.45s ease-out both;
  animation-delay: calc(var(--i) * .17s);
}
@keyframes govFlash {
  0%, 100% { filter: drop-shadow(0 0 7px color-mix(in srgb, var(--indigo-bright) 65%, transparent)); }
  45%      { filter: drop-shadow(0 0 13px var(--indigo-bright)) brightness(1.2); }
}

/* Settled: a rail draws the height of the ledger. */
.gov { position: relative; }
.gov-rail { display: none; }
.gov-rail-unused {
  position: absolute;
  left: -16px;
  top: 4px; bottom: 4px;
  width: 1px;
  background: linear-gradient(180deg, var(--indigo-bright), color-mix(in srgb, var(--indigo-bright) 8%, transparent));
  transform: scaleY(0);
  transform-origin: top center;
  transition: transform 1.25s var(--ease-reveal);
}
.gov.is-set .gov-rail-unused { transform: scaleY(1); }


.gov-ledger.is-set .gov-name { color: var(--text); }
/* The sub line takes its purple on the first frame of the ripple, so the
   colour arrives with the movement rather than after it. */
.gov-ledger.is-set .gov-note,
.gov-ledger.is-roll .gov-note { color: var(--indigo-lift); }
.gov-note { transition: color .45s var(--ease-reveal); }
.gov-ledger.is-roll .gov-note { transition-delay: calc(var(--i) * .17s); }


/* =============================================================================
   The mid-article quote
   The homepage featured-card quote: the same .fi-mark and .fi-pull objects out
   of components/home.css, with the accent span on the payoff clause. It is set
   larger here because it is the only quote on the page rather than one panel of
   a card. It magnifies ONCE as it comes into view and stays there, and the
   accent is lit from the moment it arrives. Nothing about it responds to the
   pointer.
   ========================================================================== */
.tl-body .q-feat {
  margin: 74px auto;
  max-width: 700px;
  padding: 8px 4px;
  text-align: center;
  transform: scale(.93);
  transform-origin: center center;
  opacity: .55;
  will-change: transform, opacity;
  transition:
    transform 1.4s var(--ease-reveal),
    opacity   1.1s ease;
}
.tl-body .q-feat.is-lit { transform: scale(1); opacity: 1; }

.tl-body .q-feat .fi-mark { line-height: .8; opacity: .95; text-shadow: 0 0 18px rgba(129, 120, 255, .55); }
.tl-body .q-feat .fi-pull {
  margin-top: 8px;
  font-size: clamp(28px, 3.4vw, 44px);
  line-height: 1.28;
  letter-spacing: -.022em;
  text-wrap: balance;
}
.tl-body .q-feat .fi-pull span { color: var(--grad-hi); }


/* =============================================================================
   Closing statement
   Drawn corner brackets, left aligned, signed. Draws once on view.
   ========================================================================== */
/* The site's own rule puts 48px under the body and the closing block sits on
   66px above it, so the page ended lopsided. Both are 66px now. */
.tl-article .cta-shine { margin-top: 104px; }

.tl-body .close-note {
  position: relative;
  margin: 66px 0 0;
  padding: 40px clamp(22px, 4vw, 44px);
}
.cn-br {
  position: absolute;
  width: 0; height: 0;
  border: 0 solid var(--indigo-bright);
  opacity: 0;
  transition: width .85s var(--ease-reveal), height .85s var(--ease-reveal), opacity .45s ease;
}
.close-note.is-lit .cn-br { width: 34px; height: 34px; opacity: 1; }
.cn-br.is-tl { top: 0; left: 0; border-top-width: 1.5px; border-left-width: 1.5px; }
.cn-br.is-tr { top: 0; right: 0; border-top-width: 1.5px; border-right-width: 1.5px; transition-delay: .12s; }
.cn-br.is-bl { bottom: 0; left: 0; border-bottom-width: 1.5px; border-left-width: 1.5px; transition-delay: .24s; }
.cn-br.is-br { bottom: 0; right: 0; border-bottom-width: 1.5px; border-right-width: 1.5px; transition-delay: .36s; }

.tl-body .cn-q {
  margin: 0;
  font-size: clamp(21px, 2.6vw, 29px);
  line-height: 1.4;
  font-weight: 600;
  letter-spacing: -.02em;
  color: var(--text);
  text-wrap: pretty;
}
.tl-body .cn-sig {
  margin: 26px 0 0;
  font-family: var(--font-mono);
  font-size: 14px;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--dim);
}
/* Name on its own line, role and company underneath it. */
.tl-body .cn-sig span {
  display: block;
  font-size: 21px;
  letter-spacing: .04em;
  color: var(--indigo-lift);
  font-weight: 700;
  margin-bottom: 6px;
}


/* -----------------------------------------------------------------------------
   Reduced motion: every figure shows its finished state immediately.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .five-q, .five-n, .pz-piece, .pz-shape, .pz-v, .pz-head-k,
  .five-q { transform: none; opacity: 1; color: var(--text); }
  .five-n { color: var(--indigo-lift); }
  .five-q::after { animation: none; }
  .pz-piece { transform: none; opacity: 1; }
  .pz-logo { animation: none; opacity: 1; }
  .pz-shape { fill: var(--warn-bg); stroke: var(--warn); }
  .pz-v { fill: var(--text); }
  .pz-head-k { color: var(--warn); }
  /* The timeline renders its resolved frame from the script; all that is
     needed here is to stop the marker and the settlement label pulsing. */
  .stl-dot, .stl-dot::after, .stl-end { animation: none !important; }
  .stl-status { transition: none; }
  .stl-head { display: none; }
  .stl-ticks i { transform: scaleY(.62) !important; opacity: .62 !important; }
  .mk-t { animation: none; stroke-dashoffset: 0; }
  .mk-f { animation: none; opacity: 1; }
  .mk-glow { animation: none; opacity: .3; }
  .mk-top { opacity: .38; }
  .mk-btm { opacity: 1; transform: none; }
  .ask-cursor { animation: none; }
  .gov-ledger.is-roll .gov-row, .gov-ledger.is-roll .gov-check svg, .gov-row.is-pulse { animation: none; }
  .cn-br { width: 34px; height: 34px; opacity: 1; }
}


/* --- ./effects/effects.css --- */
/* =============================================================================
   Effects - Ambient background & motion
   -----------------------------------------------------------------------------
   The animated atmosphere. CSS here defines how the effects look; the motion
   that follows the cursor is driven by scripts/effects.js.
   ========================================================================== */

/* -----------------------------------------------------------------------------
   GLOW - two soft light orbs (#glowCloud lag + #glowCore tight) that trail the
   cursor. Fixed, behind content, screen-blended. Fades out when the pointer
   leaves the page. Position is set each frame by scripts/effects.js.
   -------------------------------------------------------------------------- */
.glow {
  position: fixed; left: 0; top: 0; border-radius: 50%;
  /* z-index 0 (matches the live site): the orbs must paint BEHIND the page
     content so glass panels frost them via backdrop-filter. At z-index 2 they
     floated above every panel and the whole see-through effect vanished. */
  pointer-events: none; z-index: 0;
  mix-blend-mode: var(--glow-blend); will-change: auto;
  opacity: .9;
  transition: opacity .5s ease;
}
.glow-cloud { width: 600px; height: 600px; background: radial-gradient(circle, var(--cloud-1), transparent 60%); }
.glow-core  { width: 210px; height: 210px; background: radial-gradient(circle, var(--cloud-2), transparent 60%); }

/* -----------------------------------------------------------------------------
   AURORA - drifting colour clouds inside a section. Add
   <div class="aurora"><b class="a1"></b><b class="a2"></b><b class="a3"></b></div>
   as the first child of a hero/section.
   -------------------------------------------------------------------------- */
/* Full-viewport width so the glow reaches the window edges (fading out there)
   instead of being clipped at the narrow content margins. */
.aurora { position: absolute; top: 0; bottom: 0; left: 50%; width: 100vw; transform: translateX(-50%); overflow: hidden; pointer-events: none; z-index: 0; }
.aurora b {
  position: absolute; display: block; border-radius: 50%;
  filter: blur(72px); opacity: .55; mix-blend-mode: var(--glow-blend); will-change: auto;
}
.aurora .a1 { width: 42vw; height: 42vw; left: -6vw; top: -10vw; background: radial-gradient(circle, var(--cloud-1), transparent 67%); animation: drift1 26s ease-in-out infinite; }
.aurora .a2 { width: 38vw; height: 38vw; right: -6vw; top: -6vw; background: radial-gradient(circle, var(--cloud-2), transparent 66%); animation: drift2 32s ease-in-out infinite; }
.aurora .a3 { width: 34vw; height: 34vw; left: 34vw; top: 14vw; background: radial-gradient(circle, var(--cloud-3), transparent 66%); animation: drift3 38s ease-in-out infinite; }

/* -----------------------------------------------------------------------------
   KEYFRAMES - the shared motion library. Components reference these by name
   (e.g. .text-grad, .live-dot.anim, .aurora b, .cta-orbit). All token-driven so
   they read correctly in both themes.
   -------------------------------------------------------------------------- */
/* Animated indigo sweep across headline text / stat numbers (.text-grad). */
@keyframes gradFlow { 0% { background-position: 0% 0; } 100% { background-position: -200% 0; } }

/* Live status pip (.live-dot.anim) - a gentle opacity breathe + glow bloom. */
@keyframes ssPulse { 0%, 100% { opacity: .5; } 50% { opacity: 1; } }
@keyframes dotGlow { 0%, 100% { box-shadow: 0 0 6px var(--signal); } 50% { box-shadow: 0 0 16px var(--signal), 0 0 6px var(--signal); } }

/* Footer place separator dot (.foot-place i) - pulses purple with a soft halo. */
@keyframes dotPulse {
  0%, 100% { opacity: .55; color: var(--indigo-lift); text-shadow: 0 0 0 transparent; }
  50%      { opacity: 1;   color: var(--grad-hi);     text-shadow: 0 0 14px var(--signal), 0 0 7px var(--indigo-lift); }
}

/* Drifting aurora clouds (.aurora b). */
@keyframes drift1 { 0%, 100% { transform: translate(0, 0) scale(1); }    50% { transform: translate(6vw, 4vw) scale(1.12); } }
@keyframes drift2 { 0%, 100% { transform: translate(0, 0) scale(1.06); } 50% { transform: translate(-5vw, 5vw) scale(.92); } }
@keyframes drift3 { 0%, 100% { transform: translate(0, 0) scale(1); }    50% { transform: translate(-4vw, -5vw) scale(1.1); } }

/* Rotating conic border trace on CTA panels (.cta-shine / --cta-trace). */
@keyframes ctaTrace { to { --cta-trace: 360deg; } }

/* -----------------------------------------------------------------------------
   SECTION RAIL - removed per request (the floating scroll indicator).
   -------------------------------------------------------------------------- */
.rail { display: none !important; }

/* -----------------------------------------------------------------------------
   PERFORMANCE - keep the renderer from being pinned by the always-on ambient
   animations (drifting glow clouds, gradient headline, pulses).
   • While the tab is hidden, pause every animation (scripts/effects.js toggles
     .anim-off on <html>).
   • For users who prefer reduced motion, stop the ambient motion entirely.
   -------------------------------------------------------------------------- */
html.anim-off *,
html.anim-off *::before,
html.anim-off *::after { animation-play-state: paused !important; }

@media (prefers-reduced-motion: reduce) {
  .aurora b,
  .text-grad,
  .cta-orbit,
  .prose li::before,
  .foot-place i,
  .live-dot.anim { animation: none !important; }
  .glow { display: none; }
}


/* --- ./shell/frame.css --- */
/* =============================================================================
   Shell page frame
   -----------------------------------------------------------------------------
   Full-bleed dark canvas with a centred content column.

   The imported V3 dump sets `body { display:flex }` with a cream background -
   that was built for the full-screen STANDALONE pages, where .site fills the
   viewport. On the shared shell pages it shrank .site to its content width and
   centred it, leaking the cream body colour down both sides, and left the header
   wider than the page content.

   Making .site full-width fixes both: the dark canvas covers the viewport, and
   .header-inner / .container / .footer-top all resolve to the SAME centred
   column (they each use width:min(1000px, 100% - gutter)).
   ========================================================================== */
html, body { background: var(--bg); }
body { display: block; color: var(--text); }
.site {
  width: 100%;
  min-height: 100vh;
  display: flex;                 /* sticky-footer column: pins the footer to the */
  flex-direction: column;        /* bottom on short pages instead of leaving a gap */
  overflow-x: clip;
  padding-top: var(--header-h);
  background: transparent;   /* let the fixed .site-bg grid + glow field show through */
  color: var(--text);
}   /* clip full-viewport glow without creating a scroll container */
.site > .page-body { flex: 1 0 auto; }   /* content grows to fill, pushing footer down */
.site > .site-footer { flex: 0 0 auto; }

/* Header, content and footer ALL share one centred width - the header never
   extends past the body margins. Narrow, tight, balanced column. */
.container,
.footer-top,
.footer-bottom-inner { width: min(1300px, calc(100% - var(--gutter))); }
/* The header bar runs a touch wider (smaller gutter) so the long nav has room
   before it collapses to the hamburger; both use fluid gutters so they
   compress cleanly on tablet/phone instead of clinging to a fixed margin. */
.header-inner { width: min(1340px, calc(100% - var(--gutter-header))); }
.container,
.header-inner,
.footer-top,
.footer-bottom-inner { margin-inline: auto; }

.section { padding-block: var(--section-pad); }
.text-param {
  --text-color: inherit;
  --text-size: inherit;
  --text-weight: inherit;
  color: var(--text-color);
  font-size: var(--text-size);
  font-weight: var(--text-weight);
}

.site-header {
  position: fixed !important;
  top: 0;
  left: 0;
  right: 0;
  height: var(--header-h);
  z-index: var(--z-header);
  transform: none !important;
  isolation: isolate;
  pointer-events: auto;
  background: var(--header-bg);
  border-bottom: 1px solid var(--line);
  backdrop-filter: blur(22px) saturate(160%);
  -webkit-backdrop-filter: blur(22px) saturate(160%);
}
.header-inner {
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
}

.nav { display: flex; align-items: center; }
.nav-link,
.nav-dd-btn {
  color: var(--muted);
  cursor: pointer;
  text-decoration: none;
  white-space: nowrap;
  font-family: inherit;
  font-weight: 600;
}
.nav-dd { position: relative; }
.nav-dd-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 0;
  border: 0;
  background: transparent;
}
.caret {
  width: 6px;
  height: 6px;
  border-right: 1.6px solid currentColor;
  border-bottom: 1.6px solid currentColor;
  transform: rotate(45deg) translate(-1px, -1px);
  transition: transform .25s ease;
}
.nav-dd:hover .caret { transform: rotate(-135deg) translate(-1px, -1px); }
.dd-menu {
  position: absolute;
  top: calc(100% + 16px);
  left: 50%;
  min-width: 248px;
  padding: 8px;
  border-radius: 18px;
  background: var(--elev);
  border: 1px solid var(--brd);
  box-shadow: var(--shadow);
  opacity: 0;
  visibility: hidden;
  transform: translateX(-50%) translateY(8px);
  transition: opacity .24s ease, visibility .24s ease, transform var(--motion-window);
}
.nav-dd:hover .dd-menu,
.nav-dd:focus-within .dd-menu {
  opacity: 1;
  visibility: visible;
  transform: translateX(-50%) translateY(0);
}
.dd-menu::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 100%;
  height: 18px;
}
.dd-link {
  display: block;
  padding: 11px 14px;
  border-radius: 12px;
  font-size: 15px;
  font-weight: 600;
  color: var(--text);
  text-decoration: none;
  transition: background .32s ease, color .2s ease;
}
.dd-link small {
  display: block;
  margin-top: 2px;
  color: var(--dim);
  font-size: 12.5px;
  font-weight: 500;
}
.dd-link:hover { background: var(--hover); }
.dd-link-cta {
  color: var(--on-accent);
  background: var(--indigo);
  font-weight: 700;
  margin-top: 4px;
  box-shadow: 0 4px 18px -6px var(--glow-2);
}
.dd-link-cta small { color: var(--on-accent); opacity: .82; font-weight: 500; }
.dd-link-cta:hover { background: var(--indigo-2); }

.header-tools {
  display: flex;
  align-items: center;
  gap: 12px;
  flex: 0 0 auto;
}
.theme-btn { position: relative; width: 40px; height: 40px; }
.ti {
  position: relative;
  width: 19px;
  height: 19px;
  transition: transform .28s cubic-bezier(.4,1.4,.5,1), filter .25s ease;
}
.ti svg {
  position: absolute;
  inset: 0;
  width: 19px;
  height: 19px;
  transition: transform .55s cubic-bezier(.5,1.5,.4,1), opacity .4s ease;
}
[data-theme="dark"] .ti-moon { opacity: 1; transform: rotate(0deg) scale(1); }
[data-theme="dark"] .ti-sun { opacity: 0; transform: rotate(110deg) scale(.3); }
[data-theme="light"] .ti-moon { opacity: 0; transform: rotate(-110deg) scale(.3); }
[data-theme="light"] .ti-sun { opacity: 1; transform: rotate(0deg) scale(1); }

.menu-toggle {
  display: none;
  width: 40px;
  height: 40px;
  border-radius: var(--radius-pill);
  cursor: pointer;
  position: relative;
  flex: 0 0 auto;
}
.menu-toggle span {
  position: absolute;
  left: 11px;
  right: 11px;
  height: 1.8px;
  border-radius: 2px;
}
.menu-toggle span:nth-child(1) { top: 14px; }
.menu-toggle span:nth-child(2) { top: 19px; }
.menu-toggle span:nth-child(3) { top: 24px; }

.scrim {
  position: fixed;
  inset: 0;
  z-index: var(--z-scrim);
  background: rgba(0,0,0,.5);
  backdrop-filter: blur(3px);
  opacity: 0;
  visibility: hidden;
}
.site.menu-open .scrim,
.scrim.open { opacity: 1; visibility: visible; }
.drawer {
  position: fixed;
  top: 0;
  right: 0;
  z-index: var(--z-drawer);
  width: min(360px, 86vw);
  height: 100%;
  background: var(--elev);
  border-left: 1px solid var(--brd);
  box-shadow: var(--shadow);
  transform: translateX(102%);
  overflow: hidden;   /* the inner .drawer-scroll scrolls; the CTA stays pinned */
  display: flex;
  flex-direction: column;
}
.site.menu-open .drawer,
.drawer.open { transform: translateX(0); }

.site-header .menu-toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(5px) rotate(45deg); }
.site-header .menu-toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.site-header .menu-toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-5px) rotate(-45deg); }

/* --- Header / nav responsive strategy ---------------------------------------
   The body content keeps wide side margins for readability, but the header bar
   spans a little wider (smaller gutter) so the long nav has room. The nav is
   also compacted, letting the full menu hold until a genuinely tight window
   before collapsing to the hamburger. */
/* Header nav spacing. This value used to live in components/platform.css as a
   `.site-header .nav` override, so a page stylesheet was silently setting the
   header spacing on every page. Same value, moved here where the header lives.
   `.nav` appears exactly once in base.njk and only inside the header, so the
   plain selector is enough.

   Worth knowing before touching this: the gap floor is NOT what limits the
   header. Measured across the live site, the nav plus the tools group stops
   fitting at about 1070px, while this clamp does not bottom out until roughly
   867px. That is why the collapse breakpoint below is 1080 and lowering this
   gap further would not buy room. */
.nav { gap: clamp(26px, 3vw, 44px); }

/* Header page links - slightly larger, and they magnify on hover (same springy
   feel as the icon buttons).
   Magnify technique (dual copy, like the brand logo's purple hover swap): each
   label holds an in-flow copy at the resting size (.nl-rest) plus an absolutely
   centered copy pre-typeset at the magnified size (.nl-big = 15.5px × 1.1).
   Hover scales both while crossfading, so both settled states are native crisp
   rasters - animating one copy either smeared the glyphs (composited texture)
   or shimmered per-frame (main-thread re-raster): the choppiness. */
.site-header .nav-link,
.site-header .nav-dd-btn {
  font-size: 15.5px;
  transition: color .2s ease;
}
.site-header .nav-link { display: inline-block; }
.site-header .nav-link:hover,
.site-header .nav-dd:hover .nav-dd-btn { color: var(--icon-hover); }

.site-header .nl { position: relative; display: inline-block; }
.site-header .nl-rest,
.site-header .nl-big {
  display: inline-block;
  /* --ease-out (no overshoot): a springy bezier over-scaled then settled back,
     reading as a choppy double-movement. */
  transition: transform var(--motion-window), opacity .34s ease;
}
.site-header .nl-big {
  position: absolute; left: 50%; top: 50%;
  font-size: 17.05px; white-space: nowrap;
  transform: translate(-50%, -50%) scale(.9091);
  opacity: 0;
}
.site-header .nav-link:hover .nl-rest,
.site-header .nav-dd:hover .nav-dd-btn .nl-rest { transform: scale(1.1); opacity: 0; }
.site-header .nav-link:hover .nl-big,
.site-header .nav-dd:hover .nav-dd-btn .nl-big { transform: translate(-50%, -50%) scale(1); opacity: 1; }

/* Brand logo - behaves like the theme toggle: normal colour at rest, accent
   purple on hover (crossfading to the logo-purple-*.png assets, generated from
   logo-white.png at the theme accent colours - a CSS mask approach hung the
   browser compositor, so real bitmaps it is), and magnifies on hover. The
   .logo-hover imgs sit stacked on the .logo-base imgs; the theme's
   logo-dark/logo-light display rules pick which pair is active. */
/* No will-change here: keeping the brand permanently composited made the GPU
   resample the logo bitmap at a fractional offset - it painted crisp on load,
   then went blurry once the layer was promoted. Promotion now only happens
   during the hover transition itself. */
.brand { position: relative; transition: transform var(--motion-window); }
.brand {
  display: inline-flex;
  align-items: center;
  height: 28px;
  flex: 0 0 auto;
}
.logo-light { display: none; }
.logo-dark { display: block; }
[data-theme="light"] .logo-light { display: block; }
[data-theme="light"] .logo-dark { display: none; }
.brand img.logo-light,
.foot-brand img.logo-light { display: none; }
.brand img.logo-dark,
.foot-brand img.logo-dark { display: block; }
[data-theme="light"] .brand img.logo-light,
[data-theme="light"] .foot-brand img.logo-light { display: block; }
[data-theme="light"] .brand img.logo-dark,
[data-theme="light"] .foot-brand img.logo-dark { display: none; }
/* Pin both logo boxes to stable pixel sizes so the browser rasterizes them
   cleanly during hover and theme transitions. */
.brand img { width: auto; height: 28px; }
.brand-logo { height: 28px; width: auto; display: block; color: var(--text); transition: color .34s ease; }
.brand:hover .brand-logo { color: var(--indigo-lift); }
.foot-brand img { width: auto; height: 24px; }

/* Footer columns: let the PRODUCT column size to its longest link so
   "The Resolution Roundtable" sits on one line - v3-export's 1fr squeezed it
   below its natural width and wrapped it. That freed-up width made COMPANY
   and CONNECT stretch wider than their content needs while sitting close
   together, reading as cramped; widen the gap to give the three right
   columns room to breathe. Desktop only; the ≤1000px layouts in v3-export
   (2-col / 1-col) have plenty of room and stay as-is. */
@media (min-width: 1001px) {
  .footer-top {
    grid-template-columns: minmax(280px, 1.25fr) repeat(3, minmax(170px, .75fr));
    column-gap: clamp(44px, 5vw, 76px);
    align-items: start;
  }
  .foot-col { min-width: 0; }
  .foot-col a { max-width: 24ch; }
}
.brand:hover { transform: scale(1.08); }
.brand img { transition: opacity .34s ease; }
.brand img.logo-hover { position: absolute; left: 0; top: 50%; translate: 0 -50%; opacity: 0; }
.brand:hover img.logo-base { opacity: 0; }
.brand:hover img.logo-hover { opacity: 1; }

.site-footer {
  position: relative;
  z-index: 1;
  border-top: 1px solid var(--line);
  background: var(--footer-bg);
  margin-top: auto;
}
.footer-top {
  padding: 44px 0 32px;
  display: grid;
  grid-template-columns: 1.7fr 1fr 1fr 1fr;
  gap: 36px;
}
.foot-brand img { margin-bottom: 14px; }
.foot-tag {
  max-width: 262px;
  margin: 0 0 16px;
  color: var(--muted);
  font-size: 14.5px;
  line-height: 1.65;
}
.foot-col h5,
.foot-col .foot-h {
  margin: 0 0 13px;
  color: var(--dim);
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .16em;
  text-transform: uppercase;
}
.foot-col a {
  display: block;
  margin-bottom: 9px;
  color: var(--muted);
  font-size: 14.5px;
  font-weight: 500;
  text-decoration: none;
  transition: color .2s ease;
}
.foot-col a:hover { color: var(--icon-hover); }
.footer-bottom { border-top: 1px solid var(--line); }
.footer-bottom-inner {
  padding: 16px 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
}
.footer-bottom-inner span { font-size: 13px; }
.foot-legal {
  display: flex;
  gap: 8px;
  align-items: center;
}
.foot-legal a {
  color: var(--dim);
  text-decoration: none;
  transition: color .2s ease;
}
.foot-legal a:hover { color: var(--icon-hover); }

/* The theme toggle's icon sits ~10px inside its invisible 40px button, so the
   flexbox's equal side gaps LOOK unequal (logo→Platform reads tighter than
   Company→toggle). Shift the nav right to balance the two optically. */
.site-header .nav { margin-left: 18px; }
.site-header .header-tools { position: relative; }
.site-header .theme-btn,
.site-header .desk-cta {
  transition: opacity .34s ease, transform var(--motion-window), filter .34s ease;
}

/* Header search: hover/focus expands the input. Rather than sliding the nav off
   to the left (which ran it off-screen at tight widths), we FADE the rest of the
   header out so the search has the bar to breathe - nav, Request Demo and the
   theme toggle fade together, then return on blur. The SmartSettle AI brand mark
   stays put and fully visible throughout (never fades with the rest). */
.site-header .brand {
  transition: transform .5s var(--ease-out), opacity .34s ease;
}
/* `display .4s allow-discrete` lets the nav FADE in/out as it collapses to the
   hamburger across the 900px breakpoint, instead of snapping (modern browsers;
   older ones fall back to an instant swap). */
.site-header .nav {
  transition: transform .4s var(--ease-out), opacity .3s ease, display .4s allow-discrete;
}
.site-header .header-inner:has(.site-search:hover) .nav,
.site-header .header-inner:has(.site-search:focus-within) .nav {
  opacity: 0;
  transform: translateX(-8px);
  pointer-events: none;
}
.site-header .header-tools:has(.site-search:hover) .theme-btn,
.site-header .header-tools:has(.site-search:focus-within) .theme-btn,
.site-header .header-tools:has(.site-search:hover) .desk-cta,
.site-header .header-tools:has(.site-search:focus-within) .desk-cta {
  opacity: 0;
  transform: translateX(-18px);
  filter: blur(2px);
  pointer-events: none;
}
.site-search {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: flex-end;
  width: 38px;
  height: 38px;
  transition: width 1.25s var(--ease-reveal);   /* slow, smooth expand */
}
.site-search:hover,
.site-search:focus-within { width: min(300px, 30vw); }
.site-search::after {
  content: "";
  position: absolute;
  left: 38px;
  right: 8px;
  bottom: 5px;
  height: 1px;
  border-radius: 999px;
  background: var(--icon-hover);
  box-shadow: 0 0 12px color-mix(in srgb, var(--icon-hover) 28%, transparent);
  opacity: 0;
  transform: scaleX(.02);
  transform-origin: left center;
  transition: transform var(--motion-window), opacity .34s ease;
}
.site-search:hover::after,
.site-search:focus-within::after {
  opacity: 1;
  transform: scaleX(1);
}
.site-search-btn {
  position: relative;
  z-index: 2;
  width: 38px;
  height: 38px;
  border: 0;
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--muted);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: color .24s ease, transform var(--motion-window), filter .34s ease;
}
.site-search-btn svg { width: 17px; height: 17px; }
.site-search:hover .site-search-btn,
.site-search:focus-within .site-search-btn {
  color: var(--icon-hover);
  transform: scale(1.12);
  filter: drop-shadow(0 0 10px color-mix(in srgb, var(--icon-hover) 72%, transparent));
}
.site-search input {
  position: absolute;
  right: 0;
  width: 100%;
  height: 38px;
  border: 0;
  border-radius: 0;
  background: transparent;
  color: var(--text);
  padding: 0 8px 0 40px;
  opacity: 0;
  pointer-events: none;
  transform: translateX(8px);
  transform-origin: right center;
  transition: opacity .5s ease .3s, transform 1.25s var(--ease-reveal);
}
.site-search:hover input,
.site-search:focus-within input {
  opacity: 1;
  pointer-events: auto;
  transform: translateX(0);
}
.site-search input::placeholder { color: var(--dim); }
/* Chromium draws a native clear button inside type="search". In this header it
   lands on top of the search icon, which reads as a stray glyph rather than a
   control. Escape clears the field, so nothing is lost by removing it. */
.site-search input::-webkit-search-cancel-button,
.site-search input::-webkit-search-decoration,
.drawer-search input::-webkit-search-cancel-button,
.drawer-search input::-webkit-search-decoration { -webkit-appearance: none; appearance: none; display: none; }

/* Opened by a click on the icon rather than by hover. The click handler in
   scripts/site.js focuses the field, so :focus-within already does the work;
   this class keeps the field open on touch, where focus can be lost to the
   soft keyboard before the transition finishes. */
.site-search.is-open { width: min(300px, 30vw); }
.site-search.is-open::after { opacity: 1; transform: scaleX(1); }
.site-search.is-open input { opacity: 1; pointer-events: auto; transform: translateX(0); }
.site-search.is-open .site-search-btn {
  color: var(--icon-hover);
  transform: scale(1.12);
  filter: drop-shadow(0 0 10px color-mix(in srgb, var(--icon-hover) 72%, transparent));
}
/* The reset's blue :focus-visible ring reads as a stray border inside the open
   search bar; the indigo underline + glowing icon already signal focus here. */
.site-search input:focus,
.site-search input:focus-visible { outline: none; }

/* Dropdown section labels - same treatment as the mobile drawer's categories. */
.dd-sec {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-family: var(--font-mono);
  font-size: 10.5px;
  line-height: 1;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--dim);
  margin: 14px 14px 7px;
  opacity: .82;
}
.dd-sec::before {
  content: "";
  width: 12px;
  height: 1px;
  border-radius: 999px;
  background: currentColor;
  opacity: .58;
}
.dd-menu .dd-sec:first-child { margin-top: 8px; }

.dd-link-cta {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  transition: transform var(--motion-window), background .34s ease, box-shadow .34s ease;
  transform-origin: center;
}
.dd-link-cta::after {
  content: "";
  position: absolute;
  top: -40%;
  bottom: -40%;
  left: -56%;
  width: 30%;
  border-radius: inherit;
  pointer-events: none;
  background:
    radial-gradient(ellipse at center, rgba(255,255,255,.22) 0%, rgba(255,255,255,.1) 34%, transparent 68%),
    linear-gradient(115deg, transparent 0%, transparent 30%, rgba(255,255,255,.08) 46%, rgba(255,255,255,.2) 50%, rgba(255,255,255,.08) 54%, transparent 70%, transparent 100%);
  filter: blur(4px);
  transform: translate3d(0, 0, 0) skewX(-14deg);
  opacity: 0;
  transition: transform .62s cubic-bezier(.4,.8,.3,1), opacity .28s ease;
}
.dd-link-cta:hover {
  transform: scale(1.035);
  box-shadow: 0 12px 26px -10px var(--glow-2);
}
.dd-link-cta:hover::after {
  transform: translate3d(540%, 0, 0) skewX(-14deg);
  opacity: .72;
}
.dd-link-cta > * { position: relative; z-index: 1; }

/* Hero sits comfortably below the header (not jammed against it). */
.page-body > section:first-child { padding-top: 56px; }

/* Let the background glow reach the window edges: sections that contain an
   aurora don't clip it (the aurora clips its own clouds to the hero height, and
   .site clips any horizontal overflow at the viewport edge). Only the text
   content stays in the narrow column. */
.section:has(.aurora) { overflow: visible; }

/* Section rhythm - one consistent gap between sections (not doubled top+bottom
   padding), so the space between e.g. "About Us" and "Our Mission" matches the
   clean spacing on the style guide. */
.page-body > section { padding-top: var(--section-pad); padding-bottom: 0; }
/* The V3 dump zeroes follow-on sections with a more specific selector
   (.page-body > section + section { padding-top:0 }); restate the rhythm at the
   same specificity here (imported last) so --section-pad actually applies. */
.page-body > section + section { padding-top: var(--section-pad); }
.page-body > section:last-child { padding-bottom: var(--section-pad); }
/* A divider at the very top of a section gets no extra top margin (the section's
   own padding already spaces it from the section above) but keeps breathing room
   below it so it isn't jammed against the heading that follows. */
.section > .divider:first-child { margin-top: 0; margin-bottom: 30px; }

/* Compact nav so the header fits the narrow column that aligns with the body:
   "Our Team" and "Thought Leadership" live in the Company dropdown (top-level
   shows Platform · The Resolution Roundtable · Company). The nav AND the Request
   Demo button stay together until the window is tight, then everything collapses
   to the hamburger at once (<1080px).

   WHY 1080 AND NOT 900. The breakpoint used to be 900, but the header stops
   fitting long before that. Measured in Chrome against the live site, stepping
   the viewport down in 10px steps: .header-tools clears .header-inner's right
   edge at 1080, is 6px past it at 1070, and 151px past it at 900, by which
   point "Request a Demo" is off-screen entirely. Nothing produced a horizontal
   scrollbar, so the overflow was silent: the tools group just ate the right
   gutter and then clipped. Collapsing at 1080 means the full nav is only ever
   shown at a width where it actually fits. If you change this number, re-measure
   rather than guessing: the sweep is cheap and the failure is invisible. */
.site-header .nav .nav-collapsible { display: none; }
/* Both sides of the swap animate rather than snap. `display` is transitioned
   with allow-discrete so the element stays visible for the duration of the
   fade instead of vanishing on the first frame.
   These previously carried `display: ... !important`, which silently defeated
   the whole effect: an !important discrete change cannot be transitioned, so
   the nav and hamburger swapped instantly. The !important was not needed for
   the cascade either. Every rule below is `.site-header .x` (0,2,0) or tighter,
   which already beats the base `.nav` / `.menu-toggle` declarations (0,1,0).
   Do not put !important back.

   THE CHOREOGRAPHY. The nav and the hamburger occupy opposite ends of the same
   bar, so the transition reads as a single movement rather than two unrelated
   fades: the nav peels away toward the right, in the direction of the button
   that replaces it, and the hamburger's three rules then draw themselves in
   from that same side, top line first. Widening runs it in reverse, the nav
   unfolding left to right.

   Built with keyframes, not transitions, for one specific reason: the spans
   also carry the burger-to-X transform when the drawer opens. A transition on
   the spans would inherit the stagger delays and make that X morph feel
   laggy. An animation runs once on appearance and then hands the element back.

   Fill mode is `backwards`, deliberately not `both`. Backwards holds the from
   state during the stagger delay so nothing flashes at full opacity before its
   turn, then releases the element completely once the animation ends. `both`
   would keep the final frame applied forever, pinning `transform` on every nav
   item and on the burger spans, which would fight the hover magnify and the
   burger-to-X morph respectively.

   effects/reduced-motion.css caps every animation at 1ms site-wide, so this
   needs no separate reduced-motion branch. */
.site-header .menu-toggle {
  transition: transform .28s var(--ease-out), color .24s ease, opacity .3s ease, display .3s allow-discrete;
}
@keyframes navItemIn {
  from { opacity: 0; transform: translateX(18px) scale(.94); }
}
@keyframes burgerRuleIn {
  from { opacity: 0; transform: translateX(10px) scaleX(.35); }
}
@media (min-width: 1080px) {
  .site-header .nav { display: flex; opacity: 1; }
  .site-header .menu-toggle { display: none; opacity: 0; transform: scale(.85); }
  .site-header .header-tools .desk-cta { display: inline-flex; }
  /* Each nav item unfolds after the one to its left. 50ms apart is enough to
     read as a sequence without the last item feeling late.

     THE DELAYS SKIP 4 AND 5 ON PURPOSE. The nav markup has SIX children, but
     two of them, Our Team and Blog, carry .nav-collapsible and are permanently
     display:none (they live in the Company dropdown instead, see the rule
     above). So the visible order on screen is children 1, 2, 3, 6, and the
     delays have to follow the positions that actually render, not 1 through 4.
     Getting this wrong is silent: Company simply animates first alongside
     Platform and the left-to-right sequence collapses, which is exactly what
     happened on the first attempt. If the nav gains or loses an item, count the
     VISIBLE children again rather than assuming they are contiguous. */
  .site-header .nav > * { animation: navItemIn .36s var(--ease-out) backwards; }
  .site-header .nav > *:nth-child(2) { animation-delay: .05s; }
  .site-header .nav > *:nth-child(3) { animation-delay: .10s; }
  .site-header .nav > *:nth-child(6) { animation-delay: .15s; }
  /* Belt and braces: a hidden item should never hold an animation. */
  .site-header .nav > .nav-collapsible { animation: none; }
}
@media (max-width: 1079px) {
  .site-search { display: none; }
  /* Collapse the whole nav + desktop CTA to the hamburger (which opens the
     mobile drawer). */
  .site-header .nav { display: none; opacity: 0; transform: translateX(18px); }
  .site-header .header-tools .desk-cta { display: none; }
  .site-header .menu-toggle { display: inline-flex; opacity: 1; transform: none; }
  /* The three rules draw in from the right, top one leading. */
  .site-header .menu-toggle span { animation: burgerRuleIn .3s var(--ease-out) backwards; }
  .site-header .menu-toggle span:nth-child(2) { animation-delay: .06s; }
  .site-header .menu-toggle span:nth-child(3) { animation-delay: .12s; }
  /* Hamburger fades in when the window narrows past the breakpoint. */
  @starting-style { .site-header .menu-toggle { opacity: 0; transform: scale(.85); } }
}
@media (max-width: 1000px) {
  .footer-top {
    grid-template-columns: 1fr 1fr;
    gap: 30px;
  }
}
@media (max-width: 440px) {
  .footer-top { grid-template-columns: 1fr; }
}

.footer-bottom-inner span,
.footer-bottom-inner a,
.foot-place {
  font-family: var(--font-sans);
  letter-spacing: 0;
  color: var(--dim);
}
/* PHONE FOOTER.

   On a wide screen the bottom row is three things across: copyright, legal
   links, cities. On a phone that same row wrapped into an awkward L, with the
   cities jammed against the right edge under the links.

   Instead: two columns that each stack, copyright on the left and legal on the
   right, then the cities on their own centred row underneath. Two short lines
   read better than one long one at this width, and the separator dot between
   the legal links goes, because stacked items do not need a divider. The city
   dot stays, since that line is still one line.

   Desktop is untouched: it keeps the three-across layout and one line each. */
@media (max-width: 700px) {
  .footer-bottom-inner { align-items: flex-start; row-gap: 6px; }

  .foot-copy,
  .foot-legal {
    display: flex;
    flex-direction: column;
    gap: 3px;
    line-height: 1.45;
  }
  .foot-legal { align-items: flex-end; text-align: right; gap: 4px; }
  .foot-legal i { display: none; }

  .foot-place {
    flex: 1 0 100%;
    text-align: center;
    justify-content: center;
    margin-top: 8px;
  }
}
.foot-place i {
  font-style: normal;
  margin: 0 8px;
  animation: dotPulse 2.6s ease-in-out infinite;   /* pulsing purple separator dot */
}
@media (prefers-reduced-motion: reduce) { .foot-place i { animation: none; } }

/* Condensed footer in hamburger mode: brand block on the left, one curated link
   column on the right. Full columns are hidden below the nav breakpoint.

   THIS NUMBER MUST TRACK THE NAV BREAKPOINT ABOVE. The footer condenses when
   the header is in hamburger mode, so the two switch together and the page has
   one narrow layout rather than two half-states. It was hard-coded to 899 and
   stayed there when the nav moved to 1080, which left a 180px band where the
   header was a hamburger while the footer still showed its wide layout. If the
   nav breakpoint moves again, move this with it. */
.foot-mini { display: none; }
@media (max-width: 1079px) {
  /* ONE COLUMN OF LINKS, not one column of footer. The three wide link columns
     collapse to the single curated .foot-mini list, which sits beside the brand
     block rather than under it. `align-items: start` is what tops that list
     level with the footer logo; without it the grid stretches both cells and
     the list drifts down. */
  .footer-top { grid-template-columns: 1fr 1fr !important; gap: 28px !important; align-items: start; }
  .footer-top .foot-col:not(.foot-mini) { display: none; }
  /* Right aligned so the two halves bracket the width rather than both hugging
     the left. */
  .foot-mini { display: block; text-align: right; }
  /* Shrink each link box to its text so hovering only lights up when over the
     words (block links would span the whole column width), and push each one
     to the right edge to match the block's alignment. */
  .foot-mini a { display: block; width: fit-content; margin-left: auto; max-width: none; }
}


/* --- ./effects/reduced-motion.css --- */
/* =============================================================================
   REDUCED MOTION - the site-wide backstop.

   Individual components already switch off their own animations when the
   visitor has asked for less motion. That worked as far as it went, but it
   only ever covered the animations somebody remembered: an audit on
   2026-08-03 found twenty looping animations with no escape at all, including
   the spinning rings on the homepage and the Roundtable page, the partner
   logo marquee, the clock, and the flowing connector lines.

   Naming every selector is the wrong shape of fix, because the next animation
   somebody adds is missed again. This block covers everything, including
   anything added later, so the per-component rules become belt and braces
   rather than the only defence.

   WHY THESE EXACT VALUES

   animation-duration: 1ms, not 0. A zero-length transition does not fire
   `transitionend`, and effects.js listens for it twice (the arrow return at
   effects.js:125 and the T+1 mark return at effects.js:362) to clean up after
   itself. 1ms is imperceptible and still fires the event.

   animation-iteration-count: 1, not `animation: none` and not
   `animation-play-state: paused`. Setting the count to 1 with a 1ms duration
   lands each animation on its END state. That matters: `sectionIn` in
   shell/page.css animates opacity 0 to 1 with `fill-mode: both`, so freezing
   it at the start would leave whole sections invisible. Every looping
   animation on this site ends where it started (a full 360 degree spin, a
   pulse returning to rest, a marquee translated by exactly one of its two
   identical halves), so jumping to the end is visually a no-op for them.

   The reveal-on-scroll rules that set `opacity: 1` under reduced motion in
   components/home.css and shell/page.css are still required and still do the
   real work of keeping content visible. Do not remove them.

   This file is imported LAST in styles/index.css so it wins on source order.
   ============================================================================= */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 1ms !important;
    animation-delay: 0ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
    transition-delay: 0ms !important;
  }

  /* The load-in reveal, which was invisible under reduced motion until now.
     effects.js deliberately does NOT add the .pz / .pz-in classes when the
     visitor has asked for less motion, and relies on this CSS to leave the
     elements in place. components/home.css already tries to do that with
     `html.js [data-pz] { opacity: 1 }`, but it loses on specificity to
     `html.enter.js [data-pz] { opacity: 0 }` two lines above it: two classes
     beats one. The result, measured on 2026-08-03 with Chromium emulating
     `prefers-reduced-motion: reduce`, was that the homepage h1, the lead
     paragraph and both hero buttons had a computed opacity of 0 and never
     recovered, on the live site. Same on /platform/.

     !important rather than a specificity duel, because this file is the
     backstop and the reveal machinery lives in three separate stylesheets. */
  html.js [data-pz],
  html.enter.js [data-pz],
  html.js .site .container.section.rv,
  html.js .page-body > section {
    opacity: 1 !important;
    transform: none !important;
  }

  html {
    scroll-behavior: auto !important;
  }

  /* The ambient background glows drift continuously and are purely decorative. */
  .glow {
    display: none;
  }
}
