/* ============================================================================
   Omni-Channel — Design System
   Built on the Apple web system: photography-first, chrome recedes, one accent,
   one shadow, alternating light/dark full-bleed tiles.

   Two deliberate departures from the source spec, both for the same reason:

   1. ACCENT. The spec names Action Blue #0066cc. Ours is #2F6BFF, because the
      eight film clips are rendered with #2F6BFF data cubes. The spec's real rule
      is "one interactive colour, non-negotiable" — honouring the rule matters
      more than the hex, and two near-identical blues on one screen is exactly
      what that rule exists to prevent.
   2. TYPE. SF Pro is Apple's and cannot be served. It resolves natively via
      system-ui/-apple-system on Apple platforms; everywhere else the stack
      falls to Inter, which the spec names as the closest open equivalent.
      Per the spec's substitution note: display tracking is nudged -0.01em and
      body leading tightened 0.03, because Inter runs wider and taller than SF.
   ============================================================================ */

/* Rubik: rounded terminals, which is the same language as the clay world in
   the film — every form in those renders has a softened corner. It also
   carries Arabic, which the system stack does not do consistently. */
/* The font is requested from the document head, not from here. An @import is
   only discovered once this file has been fetched and parsed, which serialises
   two round trips before a single glyph can load — and on a slow or blocked
   connection the page renders the whole way through in a fallback face. The
   <link> in each page starts the fetch alongside this file instead. */

:root{
  /* ---- accent: one colour, every interactive element ------------------ */
  /* Primary is the darkest blue in the logo. It clears 9.54:1 on white, so
     unlike the old #2F6BFF it is safe for small text as well as for fills —
     one colour now covers both jobs instead of needing a darker twin. */
  --c-accent:        #204289;   /* every link, every pill CTA, every focus root */
  --c-accent-text:   #204289;   /* 9.54:1 on white */
  --c-accent-focus:  #204289;
  --c-accent-on-dark:#6DCFF6;   /* the logo cyan: 5.41:1 on the primary tile */
  --c-accent-deep:   #163268;   /* pressed state */
  /* the film's data cubes are #2F6BFF and stay that way — it is an illustrative
     colour inside the renders, not an interface colour */
  --c-film-blue:     #2F6BFF;
  --c-whatsapp:      #25D366;   /* only ever on WhatsApp itself */
  --c-whatsapp-ink:  #14793C;   /* one step darker than Meta's own: #178A45 lands at 4.41:1 */

  /* ---- surface -------------------------------------------------------- */
  --canvas:          #FFFFFF;
  --canvas-parchment:#F5F5F7;   /* the alternating light tile, and the footer */
  --surface-pearl:   #FAFAFC;   /* ghost-button fill: reads as a button on parchment */
  /* A slate with a navy cast rather than near-black: #272729 read as a hole in
     the page, and this sits close enough to the brand to belong to it. White
     clears 9.7:1 on it and the cyan accent 5.5:1, so nothing had to move. */
  --surface-tile-1:  #3A4257;   /* primary dark tile */
  --surface-tile-2:  #414A61;   /* one micro-step lighter, for dark-on-dark */
  --surface-tile-3:  #333B4E;   /* one micro-step darker, for the bottom of a stack */
  --surface-black:   #000000;   /* true void only: video frames, the top nav */
  /* the clips' own background, sampled from the renders — the page must match
     it exactly or a seam shows at the film's edge */
  --film-bg:         #FEFEFE;

  /* ---- ink ------------------------------------------------------------ */
  --ink:             #1D1D1F;   /* near-black, not black: keeps the page photographic */
  --ink-muted-80:    #333333;
  /* #7A7A7A measured 3.94:1 behind 14px text, under the 4.5 floor. This is the
     lightest grey that still clears it on white, so every caption, tier note
     and fine print inherits a passing value instead of being fixed one by one. */
  --ink-muted-48:    #6E6E6E;
  --on-dark:         #FFFFFF;
  --on-dark-muted:   #CCCCCC;

  /* ---- hairlines ------------------------------------------------------ */
  --hairline:        #E0E0E0;
  --divider-soft:    rgba(0,0,0,.04);

  /* ---- type ----------------------------------------------------------- */
  /* system-ui first: on Apple platforms this IS SF Pro. Cairo carries Arabic. */
  --font-display: "Rubik", system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
  --font-text:    "Rubik", system-ui, -apple-system, BlinkMacSystemFont, sans-serif;

  /* the ladder is 300 / 400 / 600 / 700. 500 is deliberately absent. */
  --t-hero:      600 clamp(34px,4.6vw,56px)/1.07 var(--font-display);
  --t-display-lg:600 clamp(28px,3.2vw,40px)/1.10 var(--font-display);
  --t-display-md:600 clamp(24px,2.6vw,34px)/1.2  var(--font-text);
  --t-lead:      400 clamp(21px,2.1vw,28px)/1.14 var(--font-display);
  --t-lead-airy: 300 clamp(19px,1.8vw,24px)/1.55 var(--font-text);
  --t-tagline:   600 21px/1.19 var(--font-display);
  --t-body-strong:600 17px/1.24 var(--font-text);
  --t-body:      400 17px/1.52 var(--font-text);
  --t-dense-link:400 17px/2.41 var(--font-text);
  --t-caption:   400 14px/1.43 var(--font-text);
  --t-caption-strong:600 14px/1.29 var(--font-text);
  --t-button:    400 17px/1 var(--font-text);
  --t-button-utility:400 14px/1.29 var(--font-text);
  --t-fine:      400 12px/1 var(--font-text);
  --t-nav:       400 12px/1 var(--font-text);

  /* negative tracking at display sizes is the whole signature */
  --track-hero:   -.72px;   /* Rubik runs wide; display needs a tighter pull */
  --track-md:     -.46px;
  --track-body:   -.374px;
  --track-caption:-.224px;
  --track-fine:   -.12px;

  /* ---- space: 8px base ------------------------------------------------ */
  --s-xxs:4px; --s-xs:8px; --s-sm:12px; --s-md:17px;
  --s-lg:24px; --s-xl:32px; --s-xxl:48px; --s-section:80px;
  --nav-h: 76px;              /* the film sits under this, never behind it */
  --pad-x: clamp(22px,5vw,80px);
  --maxw:  1440px;
  --maxw-text: 980px;

  /* ---- radius --------------------------------------------------------- */
  --r-none:0; --r-xs:5px; --r-sm:8px; --r-md:11px; --r-lg:18px; --r-pill:9999px;

  /* ---- elevation: exactly one shadow, and it is for imagery only ------- */
  --shadow-product: rgba(0,0,0,.22) 3px 5px 30px 0;

  /* ---- motion --------------------------------------------------------- */
  --dur-1:.16s; --dur-2:.28s; --dur-3:.5s; --dur-4:.8s;
  --ease:     cubic-bezier(.22,.68,.28,1);
  --ease-out: cubic-bezier(.16,.84,.36,1);

  /* ---- z scale: named, never arbitrary -------------------------------- */
  --z-base:0; --z-sticky:30; --z-nav:40; --z-overlay:50; --z-toast:60;

  /* aliases kept so existing markup keeps working */
  --bg:var(--canvas); --bg-sunken:var(--canvas-parchment); --bg-raised:var(--canvas);
  --ink-2:var(--ink-muted-80); --ink-3:var(--ink-muted-48);
  --line:var(--hairline); --line-soft:var(--divider-soft);
  --font:var(--font-text);
}

/* ============================ primitives ================================ */
*,*::before,*::after{ box-sizing:border-box }
html{ -webkit-text-size-adjust:100% }  /* no scroll-behavior: site.js owns the glide */
body{
  margin:0; background:var(--canvas); color:var(--ink);
  font:var(--t-body); letter-spacing:var(--track-body);
  -webkit-font-smoothing:antialiased; -moz-osx-font-smoothing:grayscale;
}
a{ color:inherit }
/* Form controls do not inherit type from their parent — they fall back to the
   UA default (Arial/Times). Without this the design system silently stops at
   the edge of every input, select, textarea and button on the site. */
button, input, select, textarea, optgroup{
  font:inherit; letter-spacing:inherit; color:inherit;
}
img{ max-width:100%; display:block }
::selection{ background:var(--c-accent); color:#fff }
:focus-visible{ outline:2px solid var(--c-accent-focus); outline-offset:3px; border-radius:var(--r-sm) }

/* ============================ layout ==================================== */
.wrap{ max-width:var(--maxw); margin-inline:auto; padding-inline:var(--pad-x) }
.section{ padding-block:var(--s-section) }
/* Two section skins. Both were used throughout the page but never defined here,
   so every section rendered as the same flat white sheet with no divisions —
   the alternation IS the page's rhythm, so it has to exist. */
.section--sunken{ background:var(--canvas-parchment) }
.section--hair{ border-top:1px solid var(--divider-soft) }
/* two sunken sections in a row would read as one long block */
.section--sunken + .section--sunken{ border-top:1px solid var(--hairline) }
.stack > * + *{ margin-top:var(--s-md) }
.grid{ display:grid; gap:var(--s-lg) }
.grid--2{ grid-template-columns:repeat(auto-fit,minmax(320px,1fr)) }
.grid--3{ grid-template-columns:repeat(auto-fit,minmax(260px,1fr)) }
.grid--4{ grid-template-columns:repeat(auto-fit,minmax(212px,1fr)) }
.split{ display:grid; grid-template-columns:minmax(0,.92fr) minmax(0,1.08fr);
        gap:clamp(32px,5vw,80px); align-items:center }
@media (max-width:834px){ .split{ grid-template-columns:1fr; gap:var(--s-xl) } }

/* ---- tiles: the colour change IS the divider. No borders, no shadows. --- */
.tile{ padding-block:var(--s-section); padding-inline:var(--pad-x) }
.tile--light{ background:var(--canvas); color:var(--ink) }
.tile--parchment{ background:var(--canvas-parchment); color:var(--ink) }
.tile--dark{ background:var(--surface-tile-1); color:var(--on-dark) }
.tile--dark-2{ background:var(--surface-tile-2); color:var(--on-dark) }
.tile--dark-3{ background:var(--surface-tile-3); color:var(--on-dark) }
.tile--dark .lede, .tile--dark-2 .lede, .tile--dark-3 .lede{ color:var(--on-dark-muted) }
.tile--dark a:not(.btn), .tile--dark-2 a:not(.btn), .tile--dark-3 a:not(.btn){ color:var(--c-accent-on-dark) }

/* ============================ type ====================================== */
.display,.hero-display{ font:var(--t-hero); letter-spacing:var(--track-hero); margin:0; text-wrap:balance }
.h1{ font:var(--t-display-lg); letter-spacing:0; margin:0; text-wrap:balance }
.h2{ font:var(--t-display-lg); letter-spacing:0; margin:0; text-wrap:balance }
.h3{ font:var(--t-display-md); letter-spacing:var(--track-md); margin:0 }
.tagline{ font:var(--t-tagline); letter-spacing:.231px; margin:0 }
.lead,.lede{ font:var(--t-lead); letter-spacing:.196px; color:var(--ink-muted-80); margin:0; max-width:52ch }
.lead--airy{ font:var(--t-lead-airy); letter-spacing:0 }
.body-strong{ font:var(--t-body-strong); letter-spacing:var(--track-body) }
.small,.caption{ font:var(--t-caption); letter-spacing:var(--track-caption); color:var(--ink-muted-80); margin:0 }
.fine{ font:var(--t-fine); letter-spacing:var(--track-fine); color:var(--ink-muted-48) }
.measure{ max-width:46ch }
p{ text-wrap:pretty }

/* One named kicker, used sparingly — not above every section. */
.eyebrow{
  font:var(--t-caption-strong); letter-spacing:var(--track-caption);
  color:var(--c-accent-text); margin:0 0 var(--s-sm);
}
.eyebrow--quiet{ color:var(--ink-muted-48) }

/* ============================ button ==================================== */
/* Two grammars only: a pill for actions, a small rect for utility. */
.btn{
  display:inline-flex; align-items:center; justify-content:center; gap:var(--s-xs);
  font:var(--t-button); letter-spacing:var(--track-body);
  text-decoration:none; white-space:nowrap; cursor:pointer;
  padding:11px 22px; border-radius:var(--r-pill); border:1px solid transparent;
  background:var(--c-accent); color:#fff;
  transition:transform var(--dur-1) var(--ease), background var(--dur-1) var(--ease);
}
.btn:active{ transform:scale(.95) }   /* the system-wide press micro-interaction */
.btn--accent{ background:var(--c-accent) }
/* ghost pill: the second CTA when two sit together */
.btn--ghost{ background:transparent; color:var(--c-accent-text); border-color:currentColor }
.tile--dark .btn--ghost{ color:var(--c-accent-on-dark) }
.btn--pearl{ background:var(--surface-pearl); color:var(--ink-muted-80);
             border-radius:var(--r-md); padding:8px 14px; font:var(--t-caption);
             border:3px solid var(--divider-soft) }
.btn--utility{ background:var(--ink); color:var(--on-dark); border-radius:var(--r-sm);
               padding:8px 15px; font:var(--t-button-utility); letter-spacing:var(--track-caption) }
.btn--link{ background:none; color:var(--c-accent-text); padding:0; border:0; border-radius:0 }
.btn--link:active{ transform:none }
.btn--lg{ font:300 18px/1 var(--font-text); padding:14px 28px }

/* ============================ chip / pill =============================== */
.pill{
  display:inline-flex; align-items:center; gap:var(--s-xxs);
  font:var(--t-caption); letter-spacing:var(--track-caption); color:var(--ink);
  padding:12px 16px; border-radius:var(--r-pill);
  border:1px solid var(--hairline); background:var(--canvas); white-space:nowrap;
}
.pill--selected{ border:2px solid var(--c-accent-focus) }
.pill--accent{ color:var(--c-accent-text); border-color:var(--c-accent-text) }
.pill--wa{ color:var(--c-whatsapp-ink); border-color:rgba(37,211,102,.4) }
.pills{ display:flex; flex-wrap:wrap; gap:var(--s-xs) }

/* ============================ card ====================================== */
/* Hairline border, no shadow. Elevation is a surface change, not a shadow. */
.card{
  background:var(--canvas); border:1px solid var(--hairline);
  border-radius:var(--r-lg); padding:var(--s-lg);
  transition:transform var(--dur-2) var(--ease);
}
.card--link{
  text-decoration:none; display:grid; align-content:start;
  transition:transform var(--dur-2) var(--ease), border-color var(--dur-2) var(--ease),
             box-shadow var(--dur-2) var(--ease);
}
/* A card that is a link has to answer the pointer. Lift, a border that commits
   to the accent, and the arrow stepping forward — three cheap signals, one
   gesture. */
.card--link:hover{
  transform:translateY(-3px);
  border-color:color-mix(in srgb,var(--c-accent) 38%,transparent);
  box-shadow:0 14px 30px -22px rgba(10,16,32,.34);
}
.card--link:hover .btn--link{ color:var(--c-accent-deep) }
/* the arrow steps forward on transform rather than on a width change */
.card--link .btn--link{ display:inline-block }
.card--link:hover .btn--link{ transform:translateX(4px) }
.card--link .btn--link{ transition:color var(--dur-1) var(--ease), transform var(--dur-2) var(--ease) }
.card--link:focus-visible{ transform:translateY(-3px) }
.card--link:active{ transform:scale(.99) }
@media (prefers-reduced-motion:reduce){
  .card--link, .card--link .btn--link, .card--link .btn--link::after{ transition:none }
  .card--link:hover{ transform:none }
}
.card--flush{ padding:0; overflow:hidden }
.card img{ border-radius:var(--r-sm) }
/* the step number on a process card: a counter, not a heading */
.card__num{
  display:inline-flex; align-items:center; justify-content:center;
  min-width:30px; height:30px; padding-inline:8px; margin-bottom:var(--s-sm);
  border-radius:var(--r-pill); background:#EBF1FF; color:var(--c-accent);
  font:var(--t-caption-strong); letter-spacing:var(--track-caption);
}

/* the one shadow in the system, and it is only ever for product imagery */
.product-shot{ box-shadow:var(--shadow-product) }

/* ============================ stat ====================================== */
.stats{ display:grid; grid-template-columns:repeat(auto-fit,minmax(190px,1fr)); gap:var(--s-xl) }
.stat b{ display:block; font:var(--t-display-lg); letter-spacing:0; margin-bottom:var(--s-xs) }
.stat span{ font:var(--t-caption); letter-spacing:var(--track-caption); color:var(--ink-muted-80) }
.tile--dark .stat span{ color:var(--on-dark-muted) }

/* ============================ list ====================================== */
.ticks{ list-style:none; margin:0; padding:0; display:grid; gap:var(--s-sm) }
.ticks li{ font:var(--t-body); letter-spacing:var(--track-body); padding-left:1.3rem; position:relative }
.ticks li::before{
  content:''; position:absolute; left:0; top:.62em; width:5px; height:5px;
  border-radius:1px; background:var(--c-accent);
}
.links{ list-style:none; margin:0; padding:0 }
.links a{ font:var(--t-dense-link); color:var(--ink-muted-80); text-decoration:none }
.links a:hover{ text-decoration:underline }

/* ============================ nav =======================================
   One glass treatment, used by the masthead and by the channel subnav, so the
   two never drift apart. Real glass needs four things working together, not
   just a blur: a translucent fill so colour comes through, saturation boost so
   what shows through stays lively instead of going grey, a hairline at the
   bottom edge, and a top inner highlight that reads as the lit edge of a pane.

   The fill has to stay translucent — an opaque bar with a blur behind it is
   just an opaque bar. That is the usual mistake. */
.glass{
  /* explicit rgba, not color-mix: the mixed value animates through oklab and
     the alpha stops resolving cleanly across the state change */
  background:rgba(255,255,255,.60);
  -webkit-backdrop-filter:saturate(185%) blur(22px);
  backdrop-filter:saturate(185%) blur(22px);
  border-bottom:1px solid rgba(10,16,32,0);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.55);
  transition:background var(--dur-3) var(--ease),
             border-bottom-color var(--dur-3) var(--ease),
             box-shadow var(--dur-3) var(--ease);
}
/* once the page has moved under it, the pane commits: denser fill, visible edge */
.glass.is-stuck{
  background:rgba(255,255,255,.82);
  border-bottom-color:rgba(10,16,32,.10);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.75), 0 1px 14px -8px rgba(10,16,32,.22);
}
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .glass{ background:rgba(255,255,255,.94) }
  .glass.is-stuck{ background:#fff }
}

/* Three columns, not two: the outer pair take equal free space so the links
   land on the page's true centre no matter how wide the logo or the button is.
   A flex row with space-between centres nothing — it only pushes things apart. */
.mast{
  position:fixed; inset:0 0 auto 0; z-index:var(--z-nav);
  /* auto, not 1fr, for the outer tracks. With `1fr auto 1fr` the nav claimed the
     middle and the logo's track was squeezed to whatever was left — 66px at
     768 and 0 at 375 — so the global img{max-width:100%} crushed the wordmark
     to a quarter of its width. Sizing the outer tracks to their content means
     the logo is never the thing that gives way. */
  display:grid; grid-template-columns:auto minmax(0,1fr) auto; align-items:center;
  column-gap:var(--s-md);
  min-height:76px; padding:var(--s-md) var(--pad-x);
}
.mast__nav{ justify-self:center }
.mast > .btn{ justify-self:end }
/* max-width:none defeats the global img rule: this is a fixed-height wordmark
   with a 7:1 ratio, and letting it be clamped by its box distorts it rather
   than scaling it. */
.mark{ flex-shrink:0 }
.mark__logo{ height:38px; width:auto; max-width:none; display:block }
.mark{ display:inline-flex; align-items:center; text-decoration:none }
/* Blue's mark carries its own divider on its right edge; the product mark sits
   after it. Both images share one height so they read as a single lockup. */
.mark{ gap:clamp(8px,.8vw,12px) }
.mark__orca{ height:40px }
.mark__intel{ height:40px }
/* between two marks that carry no divider of their own */
.mark__bar{ width:2px; height:30px; border-radius:2px; background:#204289; flex:none }
.site-foot__brand .mark__bar{ background:rgba(255,255,255,.55); height:24px }
.mast nav{ display:flex; align-items:center; gap:var(--s-xl) }
/* The page you are on is stated in the accent; the one you are not is held
   back. Both stay links — quiet is not disabled, so the muted one still clears
   contrast and still answers the pointer. */
.mast nav a:not(.btn){
  font:600 14px/1.29 var(--font-text); letter-spacing:var(--track-caption);
  color:var(--ink-muted-48); text-decoration:none; position:relative;
  transition:color var(--dur-1) var(--ease);
}
.mast nav a:not(.btn)::after{
  content:''; position:absolute; left:0; right:0; bottom:-6px; height:1.5px;
  background:var(--c-accent); border-radius:2px;
  transform:scaleX(0); transform-origin:50% 50%;
  transition:transform var(--dur-2) var(--ease-out);
}
.mast nav a:not(.btn):hover{ color:var(--ink) }
.mast nav a:not(.btn):hover::after,
.mast nav a[aria-current]::after{ transform:scaleX(1) }
.mast nav a[aria-current]{ color:var(--c-accent-text) }
.mast .btn{ padding:8px 16px; font:var(--t-button-utility) }

/* On a finger, the masthead links are 18px tall and the button 36 — both under
   the 44px target. The links grow their HIT area rather than their box, through
   an invisible overlay: padding would drag the hover underline away from the
   text it belongs to. */
@media (pointer:coarse){
  .mast nav a:not(.btn){ position:relative }
  .mast nav a:not(.btn)::before{
    content:''; position:absolute; left:-10px; right:-10px; top:50%;
    height:44px; transform:translateY(-50%);
  }
  .mast .btn{ padding-block:12px }
}

/* ---- section rhythm ----------------------------------------------------
   One ladder everywhere, so no section invents its own gaps:
     eyebrow -> heading   12   tight: they are one unit
     heading -> lede      17   a breath, still the same thought
     lede    -> content   48   a real break: the argument stops, evidence starts */
.eyebrow{ margin-block:0 var(--s-sm) }
.h2 + .lede, .h1 + .lede, h2 + .lede,
.display + .lede, .hero-display + .lede{ margin-top:var(--s-md) }
.lede + .grid, .lede + .loop, .lede + .cardset, .lede + .tiers,
.h2 + .grid, .h2 + .loop, .h2 + .cardset, .h2 + .tiers,
h2 + .grid, h2 + .loop, h2 + .cardset, h2 + .tiers{ margin-top:var(--s-xxl) }
.card .pill + *{ margin-top:var(--s-md) }
.card .h3 + *,  .card h3 + *{ margin-top:var(--s-xs) }
.card p + .btn, .card p + .btn--link{ margin-top:var(--s-md) }

/* ---- primary tile ------------------------------------------------------
   Inverting here is what makes a section read as a panel laid over the film
   rather than another white sheet continuing it. Every text role has to be
   restated: .lede and .caption carry dark ink by default and would otherwise
   land at ~1.3:1 on the navy, which is invisible, not subtle. */
.tile--primary{ background:var(--c-accent); color:var(--on-dark) }
.tile--primary .h2, .tile--primary h2,
.tile--primary .h3, .tile--primary h3,
.tile--primary .display{ color:var(--on-dark) }
.tile--primary .lede,
.tile--primary .caption,
.tile--primary .small,
.tile--primary > p, .tile--primary .interlude__in > p{ color:#C6D2EC }
.tile--primary .eyebrow{ color:var(--c-accent-on-dark) }
/* the cards stay white: solid panels reading on top of the tile */
.tile--primary .card{ background:var(--canvas); color:var(--ink) }
.tile--primary .card .h3, .tile--primary .card h3{ color:var(--ink) }
.tile--primary .card .caption,
.tile--primary .card .small,
.tile--primary .card p{ color:var(--ink-muted-80) }
.tile--primary .card__n{ color:var(--c-accent); background:#EBF1FF }
.tile--primary a:not(.btn){ color:var(--c-accent-on-dark) }
.tile--primary .btn{ background:var(--on-dark); color:var(--c-accent) }
.tile--primary .btn:hover{ background:#EDF1FA }

/* ============================ footer ====================================
   Navy, matching the primary tile, so the page closes on the brand rather than
   fading out on white. Columns collapse without a breakpoint. */
.site-foot{
  /* Intelligencia's own gradient, deep blue to the logo's cyan, with the
     network of the mark faint across it — the same room as the homepage close */
  position:relative; overflow:hidden; isolation:isolate;
  background:
    radial-gradient(120% 90% at 100% 0%, rgba(12,227,244,.35) 0%, transparent 55%),
    linear-gradient(125deg, #1B3A8C 0%, #1F55B0 38%, #1590C8 78%, #13AEDB 100%);
  color:var(--on-dark);
  padding:var(--s-section) var(--pad-x) var(--s-xl);
}
.site-foot::after{ content:''; position:absolute; right:-8%; top:-30%; width:min(680px,70vw); aspect-ratio:1;
  pointer-events:none; z-index:-1; opacity:.12;
  background:url(assets/brand/intelligencia-mark.svg) center / contain no-repeat;
  animation:foot-net 18s ease-in-out infinite alternate }
@keyframes foot-net{ to{ transform:rotate(8deg) scale(1.06) } }
@media (prefers-reduced-motion:reduce){ .site-foot::after{ animation:none } }
.site-foot__in{ max-width:var(--maxw); margin-inline:auto }
.site-foot__grid{
  display:grid; grid-template-columns:1.6fr 1fr 1.3fr 1fr;
  gap:clamp(28px,3.4vw,60px); align-items:start;
}
.site-foot__brand .mark__logo{ height:30px; filter:brightness(0) invert(1) }
/* three marks side by side in the footer: they wrap rather than crowd the columns */
.site-foot__brand .mark{ flex-wrap:wrap; row-gap:12px }
.site-foot__brand p{
  margin-top:var(--s-lg); max-width:32ch;
  font:var(--t-body); color:#DCE5F7;
}
.site-foot h3{
  font:var(--t-caption-strong); letter-spacing:var(--track-caption);
  color:var(--on-dark); margin:0 0 var(--s-md);
}
.site-foot ul{ list-style:none; margin:0; padding:0; display:grid; gap:var(--s-sm) }
.site-foot li{ font:var(--t-caption); color:#DCE5F7; line-height:1.5 }
.site-foot li b{ display:block; color:var(--on-dark); font-weight:600; margin-bottom:2px }
.site-foot a{
  color:#DCE5F7; text-decoration:none;
  transition:color var(--dur-1) var(--ease);
}
.site-foot a:hover{ color:var(--on-dark) }
.site-foot__legal{
  margin-top:var(--s-section); padding-top:var(--s-lg);
  border-top:1px solid rgba(255,255,255,.16);
  display:flex; flex-wrap:wrap; gap:var(--s-md) var(--s-lg);
  align-items:center; justify-content:space-between;
}
/* 12px on navy needs more than the column-heading tint carries: #8FA6D4 is
   3.89:1 there, which is under the floor for text this small. */
.site-foot__legal p, .site-foot__legal a{ font:var(--t-fine); color:#DCE5F7; margin:0 }
@media (max-width:1000px){
  .site-foot__grid{ grid-template-columns:1fr 1fr }
  .site-foot__brand{ grid-column:1 / -1 }
}
@media (max-width:560px){ .site-foot__grid{ grid-template-columns:1fr } }

/* ============================ rise ======================================
   Everything after the film arrives the way the film's second half does: it
   climbs up over what is behind it with a rounded leading edge, instead of
   simply scrolling into place. Three things are needed for that to read as one
   panel covering another rather than as a gap:

   - an opaque surface, so the section genuinely covers what it passes;
   - a rounded top edge with a shadow above it, so you see an edge arriving;
   - a negative top margin equal to the radius, so the next edge tucks under
     the last one instead of leaving a sliver of the page showing through.

   Unlike the pinned Tool panel these are normal-flow elements, so they CAN be
   driven by a view() timeline — a pinned element never travels, which is why
   that panel needs script and this does not. */
.rise{
  position:relative; z-index:1;
  background:var(--canvas);
  border-radius:26px 26px 0 0;
  /* just enough to read as an edge arriving. Anything heavier turns into a
     grey band across the page and the sections stop looking connected. */
  box-shadow:0 -8px 22px -18px rgba(10,16,32,.16);
}
.rise.section--sunken{ background:var(--canvas-parchment) }
.rise.section--hair{ border-top:0 }        /* the edge IS the divider now */
.rise + .rise, .rise + .site-foot{ margin-top:-26px }
/* .rise sets an opaque light surface; the footer keeps its own */
.site-foot.rise{ border-radius:26px 26px 0 0;
  background:
    radial-gradient(120% 90% at 100% 0%, rgba(12,227,244,.35) 0%, transparent 55%),
    linear-gradient(125deg, #1B3A8C 0%, #1F55B0 38%, #1590C8 78%, #13AEDB 100%) }

@supports (animation-timeline: view()){
  @media (prefers-reduced-motion:no-preference){
    .rise{
      animation:rise-in linear both;
      animation-timeline:view();
      /* the first sixth of its travel: long enough to read, short enough that
         the section is settled well before you are reading it */
      animation-range:cover 0% cover 15%;
      transform-origin:50% 100%;
      will-change:transform;
    }
    /* transform only: it runs on the compositor. The corner radius used to
       animate too, and a radius change repaints the whole section on every
       scroll frame — the single largest cost of scrolling these pages. */
    @keyframes rise-in{
      from{ transform:translateY(7vh) scale(.955) }
      to  { transform:none }
    }
  }
}

/* ============================ reveal ====================================
   Motion is an enhancement, never a gate. The default state of every element
   here is VISIBLE; only when JS is alive (html.js) does it start hidden and
   animate in. A dead script, a headless render or a reduced-motion setting
   therefore ships readable content instead of a blank section — which is the
   failure mode this file previously had. */
.reveal > *{ opacity:1; transform:none }
.js .reveal > *{
  opacity:0; transform:translateY(18px);
  transition:opacity var(--dur-4) var(--ease-out), transform var(--dur-4) var(--ease-out);
  transition-delay:calc(var(--i,0) * 70ms);
}
.js .reveal.is-in > *{ opacity:1; transform:none }

/* ---- portal section: argument beside evidence -------------------------
   The picture is not a band above the text, it is the evidence for the claim
   the section makes, so it sits beside the whole argument — headline, lede and
   the detail block together in one column — rather than above a wall of it.

   The media rail is a FIXED-HEIGHT box, and that is what fixes the rhythm.
   These twenty-seven pictures run from 0.64 to 2.54 in aspect, so sizing them
   by width gave every row a different height and the pages read as unaligned;
   one row was 62% of the viewport tall. A constant box with the image
   contained inside it gives every row the same footprint whatever shape the
   picture is, and nothing can tower again. The pictures are cut out, so the
   slack inside the box is invisible — it simply reads as a smaller picture. */
.psec{
  display:grid;
  grid-template-columns:minmax(0,1fr) minmax(0,1.08fr);
  gap:clamp(30px,4vw,72px);
  align-items:start;
}
/* Alternation is written into the markup rather than derived from :nth-child —
   these pages carry a different number of sections each, and a positional rule
   restarts the rhythm every time one is added or removed. */
/* The tracks swap with the content. Reordering alone moved the column into the
   NARROW track on flipped rows, so every other section handed the picture more
   width than the argument it was supporting. */
.psec--flip{ grid-template-columns:minmax(0,1.08fr) minmax(0,1fr) }
.psec--flip .psec__col{ order:2 }

/* The column, not the viewport, is what the blocks inside it must respond to:
   .pgrid and .pcase hold three columns and only collapse at a 900px VIEWPORT,
   so in a 670px column at desktop width they stayed three across and crushed
   their cards to ~210px. Container queries put that decision where it belongs. */
.psec__col{ min-width:0; container-type:inline-size }
.psec__col .h2{ max-width:20ch }
.psec__col .lede{ max-width:52ch; margin-top:var(--s-lg) }

.psec__media{
  margin:0; min-width:0;
  height:clamp(380px,55vh,620px);
  display:flex; align-items:center; justify-content:center;
  position:sticky; top:calc(var(--nav-h) + 32px);
}
.psec__media img{
  max-width:100%; max-height:100%; width:auto; height:auto;
  object-fit:contain; display:block;
  filter:drop-shadow(0 22px 34px rgba(10,16,32,.16));
}
.psec__media figcaption{
  margin-top:var(--s-md); text-align:center;
  font:var(--t-fine); color:var(--ink-muted-48);
}

/* The first block after the lede owns the gap, so the column keeps one rhythm
   whichever block a section happens to carry. */
.psec__col > :is(.pvs,.pgrid,.pcols,.pcase,.pflow,.pwire,.pbody){
  margin-top:clamp(30px,3.4vw,48px);
}

/* Every selector here is scoped through .psec__col deliberately. A container
   query adds no specificity of its own, and the block definitions it is meant
   to override live ~300 lines further down the file — unscoped, these lost on
   source order and .pgrid stayed three across at 178px a card. */
@container (max-width:1000px){
  .psec__col .pgrid,
  .psec__col .pcase{ grid-template-columns:repeat(2,minmax(0,1fr)) }
}
@container (max-width:470px){
  .psec__col .pgrid,
  .psec__col .pcase,
  .psec__col .pvs,
  .psec__col .pcols{ grid-template-columns:1fr; gap:var(--s-lg) }
  .psec__col .pflow__row{ grid-template-columns:1fr; gap:var(--s-xs); padding:var(--s-md) 0 }
  .psec__col .pwire__row{ grid-template-columns:1fr; gap:var(--s-xs) }
}

/* ---- entrance ----------------------------------------------------------
   The hidden state is scoped to :not(.is-in) so that arriving is the absence of
   a rule rather than a rule that has to out-rank one. The first version fought
   its own cascade: the flipped variant and the stacked-layout override both
   carry the same specificity as .is-in and sit below it in the file, so a
   flipped row below the breakpoint stayed offset after it had been revealed. */
.js .reveal > .psec{ opacity:1; transform:none; transition:none }

.js .psec.reveal > .psec__media{
  transition:opacity .86s var(--ease-out), transform .86s var(--ease-out);
  transition-delay:140ms;
}
.js .psec.reveal:not(.is-in) > .psec__media{
  opacity:0; transform:translate3d(34px, 24px, 0) scale(.962);
}
.js .psec.psec--flip.reveal:not(.is-in) > .psec__media{
  transform:translate3d(-34px, 24px, 0) scale(.962);
}

@media (max-width:900px){
  .psec{ grid-template-columns:1fr; gap:var(--s-xl) }
  .psec--flip .psec__col{ order:0 }
  /* Sticky is pointless once the rail sits above the text it belonged beside,
     and it would pin the picture over the reading. */
  .psec__media{ position:static; height:clamp(300px,46vh,460px) }
  .js .psec.reveal:not(.is-in) > .psec__media,
  .js .psec.psec--flip.reveal:not(.is-in) > .psec__media{
    transform:translate3d(0, 22px, 0) scale(.975);
  }
}

/* ---- per-letter -------------------------------------------------------- */
[data-letters]{ opacity:1 }
.js [data-letters] .wrd{ display:inline-block }
.js [data-letters] .ltr{
  display:inline-block; white-space:pre;
  opacity:0; transform:translateY(.38em);
  /* No blur. A filter on a letter span is cheap; a filter on three thousand of
     them is not — the page carried 3,790 filtered elements and a single style
     pass cost 76ms against a 16.7ms frame. Opacity and travel read as the same
     move and composite for free. */
  transition:opacity .62s var(--ease-out),
             transform .62s var(--ease-out);
  transition-delay:calc(var(--l,0) * var(--step,22ms));
  /* NO will-change. It promotes every letter to its own compositor layer, and
     features.html splits into 3,789 of them — 3,789 layers, each holding a 5px
     blur. That is what made the page crawl. The transition composites fine
     without the hint. */
}
.js [data-letters].is-in .ltr{ opacity:1; transform:none }

@media (prefers-reduced-motion:reduce){
  .js .reveal > *,
  .js [data-letters] .ltr{
    opacity:1 !important; transform:none !important; transition:none !important;
  }
}

/* ============================ trust & clients ===========================
   Badges and client marks arrive in every shape and weight there is. Two rules
   keep a wall of them from looking like a jumble: give every mark the same
   optical height rather than the same box, and let the grid breathe. */
/* A certification badge is evidence, so it has to be legible — at 76px these
   read as coloured smudges. Each one now sits in its own fixed-height frame:
   the frame equalises five wildly different aspect ratios (Cvent is 2:1, the
   eWizard editor badge is taller than it is wide) while the artwork inside
   is free to be as large as its own shape allows. The source files were also
   cropped to their ink, so none of the height is spent on transparent margin. */
/* The copy is centred above the evidence rather than beside it, which lets the
   badges run the full width and be read at a size worth reading.

   Two grids, not one flowing grid: relying on the column count to break between
   the platform badges and the three Meta ones works at exactly one width and
   interleaves them at every other. Each family gets its own row. */
.trust__head{ text-align:center; max-width:var(--maxw-text); margin-inline:auto }
/* Every section after the film is centred: heading, lede and any note under
   them. The evidence below each one keeps its own alignment — a centred
   heading over a left-aligned table is fine, a left-aligned heading over a
   centred row of logos is not. */
.rise .wrap > .h1,
.rise .wrap > .h2,
.rise .wrap > .lede,
.rise .wrap > .small,
.clients__head{ text-align:center; margin-inline:auto }
.rise .wrap > .h2.measure{ max-width:24ch }
.rise .wrap > .lede{ max-width:62ch }
.rise .wrap > .pills{ justify-content:center }
.clients__head .h2{ max-width:24ch; margin-inline:auto }
.clients__head .lede{ max-width:60ch; margin-inline:auto }
.trust__head .h2{ max-width:22ch; margin-inline:auto }
.trust__head .lede{ max-width:62ch; margin-inline:auto }
.certs-set{ display:grid; gap:var(--s-lg); margin-top:var(--s-section);
            max-width:1180px; margin-inline:auto }
.certs--meta{ grid-template-columns:repeat(3,minmax(0,1fr)) }
.certs{
  display:grid; grid-template-columns:repeat(auto-fit,minmax(180px,1fr));
  gap:var(--s-lg); align-items:stretch;
}
/* the name sits with the badge, not in a list somewhere else that the reader
   has to map back onto seven near-identical seals */
.cert{
  margin:0; display:grid; grid-template-rows:1fr auto; justify-items:center;
  gap:var(--s-md); padding:var(--s-lg);
  min-height:190px; border:1px solid var(--hairline); border-radius:var(--r-lg);
  background:var(--canvas);
  transition:border-color var(--dur-2) var(--ease), transform var(--dur-2) var(--ease);
}
.cert:hover{ border-color:color-mix(in srgb,var(--c-accent) 34%,transparent); transform:translateY(-2px) }
.cert img{ max-height:148px; max-width:100%; width:auto; object-fit:contain; align-self:center }
.cert figcaption{ text-align:center; display:grid; gap:3px; max-width:26ch }
.cert figcaption b{ font:600 13px/1.3 var(--font-text); letter-spacing:var(--track-caption); color:var(--ink) }
.cert figcaption span{ font:400 12px/1.4 var(--font-text); color:var(--ink-muted-48) }
/* the wide marks would otherwise be capped by height and end up half the size */
.cert--wide img{ max-height:98px }
@media (prefers-reduced-motion:reduce){ .cert{ transition:none } .cert:hover{ transform:none } }

/* Client marks stay in their own colours — a pharma wall greyed out reads as a
   list of logos, in colour it reads as a list of companies. The one thing that
   IS equalised is optical height, since these are drawn at wildly different
   densities. */
/* A moving band rather than a static wall. Two things make it work:

   1. The row is duplicated. The track holds two identical copies and travels
      exactly one copy's width, so the moment it would show the seam it is
      already back where it started — the loop has no visible jump and needs no
      JS to reset it.
   2. The edges are masked, not cut. A logo sliding under a hard container edge
      reads as broken; fading it out reads as a band that continues past the
      page. The mask is on the frame, the animation on the track, so the two
      never fight.

   Hovering pauses it, because a mark you are trying to read should hold still.
   The marks stay in their own colours — a pharma wall greyed out reads as a
   list of logos; in colour it reads as a list of companies. */
.marquee{
  position:relative; overflow:hidden;
  -webkit-mask-image:linear-gradient(90deg,transparent 0,#000 7%,#000 93%,transparent 100%);
          mask-image:linear-gradient(90deg,transparent 0,#000 7%,#000 93%,transparent 100%);
}
.marquee__track{
  display:flex; width:max-content;
  animation:marquee-right var(--marquee-dur,46s) linear infinite;
}
.marquee:hover .marquee__track,
.marquee:focus-within .marquee__track{ animation-play-state:paused }
.marquee__row{
  display:flex; align-items:center; flex:0 0 auto;
  gap:clamp(44px,5vw,88px); list-style:none; margin:0;
  padding:var(--s-xs) clamp(22px,2.5vw,44px) var(--s-xs) 0;
}
.marquee img{
  max-height:44px; max-width:224px; width:auto; object-fit:contain;
  transition:transform var(--dur-2) var(--ease);
}
.marquee img:hover{ transform:scale(1.06) }
/* travels one full copy, so the second copy lands exactly where the first was */
@keyframes marquee-right{ from{ transform:translate3d(-50%,0,0) } to{ transform:translate3d(0,0,0) } }
@media (prefers-reduced-motion:reduce){
  .marquee{ -webkit-mask-image:none; mask-image:none; overflow-x:auto }
  .marquee__track{ animation:none }
  .marquee img{ transition:none }
}

/* the static wall is kept for anywhere a band would be wrong (print, a short
   list that would loop too obviously) */
.logowall{
  display:flex; flex-wrap:wrap; align-items:center; justify-content:center;
  gap:clamp(30px,3.6vw,64px) clamp(34px,4.4vw,74px);
}
.logowall img{
  max-height:44px; max-width:min(100%,224px); width:auto; object-fit:contain;
  transition:transform var(--dur-2) var(--ease);
}
.logowall img:hover{ transform:scale(1.05) }
@media (prefers-reduced-motion:reduce){ .logowall img{ transition:none } .logowall img:hover{ transform:none } }

/* ============================ portal pages ==============================
   Three sections a channel page needs that the channels overview does not:
   the case for the channel, one worked example, and the questions a buyer
   actually asks. Each is a plain reading layout — the mockups above them are
   doing the showing, so these are here to be read. */
.pcase{
  display:grid; grid-template-columns:repeat(3,minmax(0,1fr));
  gap:clamp(24px,3vw,48px); margin-top:var(--s-xxl);
}
.pcase h3{ font:var(--t-body-strong); letter-spacing:var(--track-body); margin:0 0 var(--s-xs) }
.pcase p{ font:var(--t-body); letter-spacing:var(--track-body); color:var(--ink-muted-80); margin:0 }
@media (max-width:900px){ .pcase{ grid-template-columns:1fr; gap:var(--s-lg) } }

/* the worked example. The time marker sits in its own column so the sequence
   reads down the page, and what is recorded at each step is set apart from
   what happened — they are two different claims. */
.pflow{ margin-top:var(--s-xxl) }
.pflow__row{
  display:grid; grid-template-columns:minmax(96px,120px) minmax(0,1.15fr) minmax(0,.85fr);
  gap:clamp(18px,2.4vw,40px); padding:var(--s-lg) 0; border-top:1px solid var(--hairline);
  align-items:start;
}
.pflow__row:last-child{ border-bottom:1px solid var(--hairline) }
.pflow__row b{ font:var(--t-caption-strong); letter-spacing:.04em; color:var(--c-accent-text) }
.pflow__row p{ font:var(--t-body); letter-spacing:var(--track-body); color:var(--ink); margin:0 }
.pflow__row span{ display:block; font:var(--t-caption); letter-spacing:var(--track-caption);
                  color:var(--ink-muted-80) }
.pflow__row span i{
  display:block; font:var(--t-fine); font-style:normal; font-weight:600;
  letter-spacing:.08em; text-transform:uppercase; color:var(--ink-muted-48);
  margin-bottom:4px;
}
@media (max-width:820px){
  .pflow__row{ grid-template-columns:1fr; gap:var(--s-xs); padding:var(--s-md) 0 }
  .pflow__row span{ padding-top:var(--s-xs) }
}

.pqa{
  display:grid; grid-template-columns:repeat(2,minmax(0,1fr));
  gap:clamp(26px,3.2vw,56px); margin-top:var(--s-xxl);
}
.pqa h3{ font:var(--t-body-strong); letter-spacing:var(--track-body); margin:0 0 var(--s-xs);
         max-width:34ch }
.pqa p{ font:var(--t-body); letter-spacing:var(--track-body); color:var(--ink-muted-80);
        margin:0; max-width:52ch }
@media (max-width:820px){ .pqa{ grid-template-columns:1fr; gap:var(--s-lg) } }

/* The way into a channel's own page belongs to the last feature, not to a
   strip of its own underneath. On its own it read as a stray button after the
   content had ended; sitting under the final feature's copy it reads as the
   next thing to do once you have finished reading. */
.step__more{ margin-top:var(--s-lg); align-self:start }


/* ---- a channel page opens on itself ---------------------------------
   These are standalone pages, not a chapter lifted out of the overview, so
   each one opens on its own full-bleed head rather than on a section heading
   that only makes sense in a longer sequence. */
.phero{
  background:
    radial-gradient(115% 85% at 78% 12%,
      color-mix(in srgb, var(--c-accent) 74%, #fff) 0%, transparent 62%),
    linear-gradient(158deg,
      color-mix(in srgb, var(--c-accent) 88%, #fff) 0%,
      var(--c-accent) 44%,
      color-mix(in srgb, var(--c-accent) 80%, #000) 100%);
  color:var(--on-dark);
  padding:clamp(140px,19vh,206px) var(--pad-x) clamp(64px,9vh,104px);
}
.phero__in{
  max-width:var(--maxw); margin-inline:auto;
  display:grid; grid-template-columns:minmax(0,.92fr) minmax(0,1.08fr);
  gap:clamp(26px,3.6vw,60px); align-items:center;
}
/* No ch cap on the hero headline. 15ch computes to 400px while "Email carries
   the depth." needs 465px and its column offers 565px, so the cap — not the
   space — was breaking every one of these headlines onto two lines. The column
   is already the measure: .phero__in is capped at --maxw and the copy track is
   .92fr of it, so the line can never exceed ~565px however wide the screen is.
   Headlines that genuinely outrun that still wrap, and text-wrap:balance keeps
   the two lines even rather than leaving one word stranded. */
.phero__copy .h1{ color:var(--on-dark) }
.phero__copy .lede{ color:#C6D2EC; max-width:46ch; margin-top:var(--s-lg) }
.phero__copy .eyebrow{ color:var(--c-accent-on-dark) }
.phero__copy .btn{ margin-top:var(--s-xl) }
.phero .showcase{ margin:0 }
.phero .showcase img{
  border-radius:var(--r-lg);
  box-shadow:0 40px 90px -40px rgba(0,0,0,.55), 0 2px 8px rgba(0,0,0,.3);
}
/* Email has no showcase render, so its hero was a narrow column of copy with
   half the bay empty beside it. With nothing to sit next to, the copy takes
   the width and the measure opens up instead of leaving a hole. */
.phero__in:not(:has(.showcase)){ grid-template-columns:minmax(0,1fr) }
.phero__in:not(:has(.showcase)) .h1{ max-width:26ch }
.phero__in:not(:has(.showcase)) .lede{ max-width:62ch }

@media (max-width:900px){
  .phero__in{ grid-template-columns:1fr; gap:var(--s-lg) }
}

/* The feature heading types itself out on every swap, so its letters lean a
   little further than the one-shot headings do — they are read as an arrival,
   not as a page settling. */
.js .step h3 .ltr{ transition-duration:.5s }


/* six items, so the bar may wrap rather than push the button off the end */
.mast__nav{ flex-wrap:wrap; row-gap:2px }
/* The button exists only for the panel, so it is absent wherever the panel is.
   Declared before the query and re-declared there through `.mast` — at equal
   specificity source order decides, and a base rule sitting after the query
   would have hidden the button at every width. */
.mast__menu,
.mast__nav-cta{ display:none }

/* `.mast .mast__nav`, not `.mast__nav`: the base rule is `.mast nav` at (0,1,1)
   and a lone class is (0,1,0), so the tighter gap never applied and the sixth
   link wrapped to its own row at 1024, standing the bar up to 103px. */
@media (max-width:1180px){
  .mast .mast__nav{ gap:var(--s-lg) }
  .mast .mast__nav a{ font-size:13px }
}

/* ---- masthead below the desktop nav's real minimum ----------------------
   The breakpoint is measured, not chosen: wordmark 265 + six links and their
   gaps ~500 + the CTA 130 + page padding ~88 needs about 1020px. The old
   860px cut left a band where all three fought for the same row.

   The hide it used to do was dead anyway — `.mast__nav` is (0,1,0) and lost to
   `.mast nav` at (0,1,1), so the desktop nav rendered at every width and simply
   wrapped, standing the fixed header up to 203px on a phone. Every selector
   below therefore carries `.mast` to clear that bar, and the nav becomes a real
   panel rather than disappearing: hiding it would leave a phone with no way to
   reach five of the six pages. */
@media (max-width:1023px){
  .mast{ grid-template-columns:auto 1fr auto auto; column-gap:var(--s-sm) }
  .mast .mast__menu{
    display:inline-flex; align-items:center; justify-content:center;
    grid-column:3; justify-self:end;
    width:46px; height:46px; margin-inline:calc(var(--s-xs) * -1) 0;
    padding:0; border:0; background:none; color:inherit; cursor:pointer;
    border-radius:var(--r-sm);
  }
  .mast__menu svg{ width:24px; height:24px; display:block }
  .mast__menu path{
    stroke:currentColor; stroke-width:1.6; stroke-linecap:round; fill:none;
    transform-origin:12px 12px;
    transition:transform var(--dur-2) var(--ease-out), opacity var(--dur-1) linear;
  }
  .mast.is-open .mast__menu-top{ transform:translateY(5px) rotate(45deg) }
  .mast.is-open .mast__menu-mid{ opacity:0 }
  .mast.is-open .mast__menu-bot{ transform:translateY(-5px) rotate(-45deg) }

  .mast > .btn{ grid-column:4 }

  .mast .mast__nav{
    grid-column:1 / -1;
    position:absolute; inset:100% 0 auto 0;
    display:grid; gap:0; justify-self:stretch;
    padding:var(--s-xs) var(--pad-x) var(--s-md);
    background:var(--canvas);
    border-top:1px solid var(--divider-soft);
    box-shadow:0 26px 44px -30px rgba(10,16,32,.45);
    /* closed: taken out of the tab order as well as out of sight */
    visibility:hidden; opacity:0; transform:translateY(-10px);
    transition:opacity var(--dur-2) var(--ease-out),
               transform var(--dur-2) var(--ease-out),
               visibility 0s var(--dur-2);
  }
  .mast.is-open .mast__nav{
    visibility:visible; opacity:1; transform:none; transition-delay:0s;
  }
  /* 52px rows: the desktop links were 18px tall, well under the 44px a finger
     needs, and a phone is the one place they are only ever touched. */
  .mast .mast__nav a:not(.btn){
    display:flex; align-items:center; min-height:52px;
    font:600 17px/1.3 var(--font-text); letter-spacing:var(--track-body);
    border-bottom:1px solid var(--divider-soft);
  }
  .mast .mast__nav a:not(.btn):last-child{ border-bottom:0 }
  /* the desktop underline is a hover affordance; a touch list does not need it */
  .mast .mast__nav a:not(.btn)::after{ display:none }

  /* The CTA lives in the panel, not the bar, once the bar cannot hold it.
     Measured at 375: wordmark 265 + button 46 + CTA 130 plus padding needs
     ~495px of a 331px row, so something had to leave — and a CTA squeezed to a
     70px pill would have been worth less than this full-width one. */
  .mast .mast__nav-cta{
    display:flex; align-items:center; justify-content:center;
    margin-top:var(--s-md); min-height:52px; width:100%;
  }
}

@media (min-width:600px) and (max-width:1023px){
  .mast .mast__nav-cta{ display:none }   /* the bar still has room for it here */
}
@media (max-width:599px){
  .mast > .btn{ display:none }
  /* 38px of wordmark is 265px of width at a 7:1 ratio, and with the button and
     the page padding that overruns a 320px row. Scaling the mark is the right
     give here — it stays legible and stays in proportion, which is what the
     previous max-width clamp destroyed. */
  .mark__logo{ height:30px }
  .mark__orca{ height:32px }
  .mark__intel{ height:31px }
  .mark__bar{ height:24px }
  .mast{ grid-template-columns:auto 1fr auto }
  .mast .mast__menu{ grid-column:3 }
}

@media (max-width:1023px) and (prefers-reduced-motion:reduce){
  .mast .mast__nav{ transition:none }
  .mast__menu path{ transition:none }
}


/* ============================ behind a head ============================
   Three soft masses of light drifting slowly toward the same point and easing
   apart again. It carries the page's argument — separate things gathering —
   without drawing a diagram of it, which is what the previous version did and
   why it read as stray hairlines over the gradient.

   Everything here is transform and opacity on three elements, so it composites
   and costs nothing. Blur lives on the element, not on a backdrop filter: a
   backdrop filter over a full-bleed gradient repaints the whole head. */
.phero, .bk-head, .head{ position:relative; overflow:hidden }
.phero__in, .bk-head__in, .head__in{ position:relative; z-index:1 }

.headfx{
  position:absolute; inset:-18%; z-index:0; pointer-events:none;
  contain:strict;
}
.headfx i{
  position:absolute; display:block; border-radius:50%;
  filter:blur(70px); opacity:.42; will-change:transform;
  animation:head-drift 26s cubic-bezier(.45,0,.55,1) infinite alternate;
}
.headfx i:nth-child(1){
  width:46%; aspect-ratio:1; left:6%; top:2%;
  background:radial-gradient(circle, color-mix(in srgb,#fff 62%,transparent) 0%, transparent 68%);
  animation-duration:24s;
}
.headfx i:nth-child(2){
  width:38%; aspect-ratio:1; left:44%; top:44%;
  background:radial-gradient(circle, color-mix(in srgb,#7FA8FF 70%,transparent) 0%, transparent 66%);
  animation-duration:31s; animation-delay:-9s; opacity:.34;
}
.headfx i:nth-child(3){
  width:30%; aspect-ratio:1; left:66%; top:8%;
  background:radial-gradient(circle, color-mix(in srgb,#fff 48%,transparent) 0%, transparent 70%);
  animation-duration:38s; animation-delay:-17s; opacity:.3;
}
/* toward the same point, then away — never returning to the same place twice
   in a row, which is what makes a loop of this length read as drift */
@keyframes head-drift{
  0%   { transform:translate3d(0,0,0) scale(1) }
  50%  { transform:translate3d(14%, 8%, 0) scale(1.14) }
  100% { transform:translate3d(-8%, 14%, 0) scale(.94) }
}
@media (prefers-reduced-motion:reduce){
  .headfx i{ animation:none }
}

/* ---- the four section types the channel pages needed --------------------
   Built from the same tokens as everything else: the accent, the hairline, the
   type scale. Nothing here introduces a colour, a radius or a shadow the rest
   of the site does not already use. */

/* Prose sat as a 734px column in a 1265px bay — too wide to read comfortably
   at 86 characters, and too narrow to look deliberate beside the full-width
   sections either side of it. Set beside its own heading it does both: the
   claim holds the left, the argument runs at a proper measure on the right. */
.psplit{
  display:grid; grid-template-columns:minmax(0,.82fr) minmax(0,1.18fr);
  gap:clamp(28px,4vw,84px); align-items:start;
}
.psplit .phead .h2{ max-width:16ch }
.psplit .phead .lede{ max-width:34ch }
/* 62ch measured at 79 characters a line — ch is the width of a zero, which in
   a proportional face is wider than the average letter, so the unit overstates
   the measure by about a sixth. 55ch lands at roughly 70. */
.pbody{ max-width:55ch; margin-top:0 }
@media (max-width:900px){
  .psplit{ grid-template-columns:1fr; gap:var(--s-lg) }
  .psplit .phead .h2, .psplit .phead .lede{ max-width:none }
}
.pbody .body{ font:var(--t-body); letter-spacing:var(--track-body);
              color:var(--ink-muted-80); margin:0 0 var(--s-md) }
.pbody .body:last-child{ margin-bottom:0 }

/* a capability set. Six of them, so three across rather than the three-up
   grid the argument sections use. */
.pgrid{
  display:grid; grid-template-columns:repeat(3,minmax(0,1fr));
  gap:clamp(22px,2.6vw,40px); margin-top:var(--s-xxl);
}
.pgrid h3{ font:var(--t-body-strong); letter-spacing:var(--track-body); margin:0 0 var(--s-xs) }
.pgrid p{ font:var(--t-body); letter-spacing:var(--track-body); color:var(--ink-muted-80); margin:0 }
@media (max-width:900px){ .pgrid{ grid-template-columns:1fr; gap:var(--s-lg) } }

/* Two columns of equal weight. Deliberately NOT a winner-and-loser table:
   both sides carry the same rule, the same type and the same width, because
   the argument is a division of labour rather than a comparison. */
.pvs{
  display:grid; grid-template-columns:repeat(2,minmax(0,1fr));
  gap:clamp(24px,3vw,56px); margin-top:var(--s-xxl);
}
.pvs__col b{
  display:block; padding-bottom:var(--s-sm); margin-bottom:var(--s-md);
  border-bottom:2px solid var(--c-accent);
  font:var(--t-caption-strong); letter-spacing:.06em; text-transform:uppercase;
  color:var(--c-accent-text);
}
.pvs__col ul{ list-style:none; margin:0; padding:0; display:grid; gap:var(--s-md) }
.pvs__col li{
  font:var(--t-body); letter-spacing:var(--track-body); color:var(--ink-muted-80);
  padding-left:var(--s-md); position:relative;
}
.pvs__col li::before{
  content:''; position:absolute; left:0; top:.62em;
  width:5px; height:5px; border-radius:50%; background:var(--c-accent);
}
@media (max-width:820px){ .pvs{ grid-template-columns:1fr; gap:var(--s-xl) } }

/* what passes between this channel and each of the others */
/* two reported columns. Its own name rather than .cols: .cols belongs to the
   channels page, and stripping that class off these pages by name took this
   section with it the first time. */
.pcols{
  display:grid; grid-template-columns:repeat(2,minmax(0,1fr));
  gap:clamp(26px,3.4vw,64px); margin-top:var(--s-xxl);
}
.pcols h3{
  font:var(--t-caption-strong); letter-spacing:.06em; text-transform:uppercase;
  color:var(--ink-muted-48); margin:0 0 var(--s-md);
  padding-bottom:var(--s-sm); border-bottom:1px solid var(--hairline);
}
.pcols ul{ list-style:none; margin:0; padding:0; display:grid; gap:var(--s-sm) }
.pcols li{
  font:var(--t-body); letter-spacing:var(--track-body); color:var(--ink-muted-80);
  padding-left:var(--s-md); position:relative;
}
.pcols li::before{
  content:''; position:absolute; left:0; top:.62em;
  width:5px; height:5px; border-radius:50%; background:var(--c-accent);
}
@media (max-width:820px){ .pcols{ grid-template-columns:1fr; gap:var(--s-xl) } }

.pwire{ margin-top:var(--s-xxl) }
.pwire__row{
  display:grid; grid-template-columns:minmax(140px,220px) minmax(0,1fr);
  gap:clamp(18px,2.4vw,44px); align-items:start;
  padding:var(--s-lg) 0; border-top:1px solid var(--hairline);
}
.pwire__row:last-child{ border-bottom:1px solid var(--hairline) }
.pwire__row b{ font:var(--t-body-strong); letter-spacing:var(--track-body); color:var(--ink) }
.pwire__row p{ font:var(--t-body); letter-spacing:var(--track-body);
               color:var(--ink-muted-80); margin:0; max-width:55ch }
@media (max-width:760px){
  .pwire__row{ grid-template-columns:1fr; gap:var(--s-xs); padding:var(--s-md) 0 }
}

/* Questions. <details> rather than a scripted accordion: it opens without
   JavaScript, it is keyboard-operable for free, and the answer is in the DOM
   whether or not it is open — which matters for anyone reading the page with
   assistive tech, and for anything indexing it. */
/* Two columns across the full bay. A grid and not CSS columns: multi-column
   reflows its content across the column boundary when a height changes, so
   opening one question made items jump from one side to the other — measured at
   five moved. In a grid each item keeps its cell; opening one only pushes what
   is beneath it. */
/* One column, every question the full width of the wrap. Two columns put the
   answers on different baselines and made opening one shove its neighbour
   down; a single stack reads top-to-bottom the way a question list should. */
.pfaq{ margin-top:var(--s-xl); max-width:none; display:block }
.pfaq{ counter-reset:faq }
.pfaq__q{ border-bottom:1px solid var(--hairline); counter-increment:faq; overflow:hidden }
.pfaq__q:first-child{ border-top:1px solid var(--hairline) }
.pfaq__q summary{
  cursor:pointer; list-style:none; position:relative;
  display:grid; grid-template-columns:52px minmax(0,1fr) 40px; align-items:center; gap:0 var(--s-sm);
  padding:var(--s-lg) 0;
  font:var(--t-body-strong); font-size:clamp(16px,1.25vw,19px); letter-spacing:var(--track-body); color:var(--ink);
  transition:color .35s var(--ease), padding .45s var(--ease-out,ease-out);
}
.pfaq__q summary::-webkit-details-marker{ display:none }
/* the question's number, small and quiet until it is the open one */
.pfaq__q summary::before{
  content:counter(faq, decimal-leading-zero);
  font:600 12px/1 var(--font-text); letter-spacing:.12em; color:var(--ink-muted-48);
  transition:color .35s var(--ease);
}
/* a round button whose plus turns into a minus */
.pfaq__q summary::after{
  content:''; justify-self:end; width:40px; height:40px; border-radius:50%;
  border:1px solid var(--hairline);
  background:
    linear-gradient(currentColor,currentColor) center / 14px 2px no-repeat,
    linear-gradient(currentColor,currentColor) center / 2px 14px no-repeat;
  color:var(--ink);
  transition:transform .5s cubic-bezier(.65,0,.35,1), background-color .35s var(--ease), border-color .35s var(--ease), color .35s var(--ease);
}
.pfaq__q summary:hover{ color:var(--c-accent-text) }
.pfaq__q summary:hover::after{ border-color:var(--c-accent); color:var(--c-accent) }
.pfaq__q summary:focus-visible{ outline:2px solid var(--c-accent); outline-offset:3px }
.pfaq__q.is-open summary{ color:var(--c-accent-text) }
.pfaq__q.is-open summary::before{ color:var(--c-accent) }
.pfaq__q.is-open summary::after{
  transform:rotate(180deg); color:#fff; border-color:var(--c-accent); background-color:var(--c-accent);
  background-size:14px 2px, 2px 0;
}
.pfaq__q p{
  margin:0; padding:0 56px var(--s-lg) calc(52px + var(--s-sm)); max-width:none;
  font:var(--t-body); letter-spacing:var(--track-body); color:var(--ink-muted-80);
  /* going, the answer clears out quickly, ahead of the height; coming, it
     rises in once there is room for it */
  opacity:0; transform:translateY(-8px);
  transition:opacity .18s var(--ease), transform .3s var(--ease);
}
.pfaq__q.is-open p{ opacity:1; transform:none;
  transition:opacity .45s var(--ease) .1s, transform .6s var(--ease-out,ease-out) .1s }
@media (max-width:600px){
  .pfaq__q summary{ grid-template-columns:36px minmax(0,1fr) 34px }
  .pfaq__q summary::after{ width:34px; height:34px }
  .pfaq__q p{ padding:0 0 var(--s-lg) calc(36px + var(--s-sm)) }
}
@media (prefers-reduced-motion:reduce){
  .pfaq__q summary::after, .pfaq__q p{ transition:none }
}

/* ============================ intro =====================================
   Every page opens on the ORCA mark, and every page leaves through the same
   white. intro.js builds the splash as the first thing in <body>:

     1. the arrow runs in alone, centred — not a flat spin: it travels along
        its own ring, head chasing tail, the way the mark is drawn
     2. it slides into place and the words arrive beside it
     3. the whole mark shrinks and flies into the header, next to Blue's,
        while the white lifts off the page underneath

   Step 3 is measured from the header's own <img> at run time, so the mark
   lands on it at any width. No script, no splash: the page simply shows. */
.boot{ position:fixed; inset:0; z-index:100; display:grid; place-items:center }
.boot__bg{ position:absolute; inset:0; background:var(--canvas);
           transition:opacity .6s var(--ease) .18s }
.boot__logo{ position:relative; width:min(520px,74vw); transform-origin:0 0; will-change:transform }
.boot__logo svg{ display:block; width:100%; height:auto; overflow:visible }
.boot.is-flying{ pointer-events:none }
.boot.is-flying .boot__bg{ opacity:0 }
.boot.is-flying .boot__logo{ transition:transform .85s cubic-bezier(.55,0,.15,1) }
.boot .orca-word, .boot .orca-connect, .boot .orca-tag{
  transform-box:fill-box; animation:orca-in .7s cubic-bezier(.2,.8,.2,1) both;
}
.boot .orca-word   { animation-delay:1.55s }
.boot .orca-connect{ animation-delay:1.68s }
.boot .orca-tag    { animation-delay:1.82s }
@keyframes orca-in{ from{ opacity:0; transform:translateX(-5%) } to{ opacity:1; transform:none } }
/* the header's own mark stays out of sight until the flying one lands on it */
html.is-intro .mast .mark__orca, html.is-intro .mast .mark__intel{ opacity:0 }
/* the Intelligencia splash is wider than ORCA's: the name runs beside the mark */
.boot__logo--intel{ width:min(660px,84vw) }
html.is-booting, html.is-booting body{ overflow:hidden }

/* leaving: the same white comes back up before the next page is asked for,
   so one page's intro follows the last page's exit with no flash between */
.boot-leave{ position:fixed; inset:0; z-index:100; background:var(--canvas);
             opacity:0; pointer-events:none; transition:opacity .32s var(--ease) }
.boot-leave.is-on{ opacity:1; pointer-events:auto }

@media (prefers-reduced-motion:reduce){
  .boot .orca-word, .boot .orca-connect, .boot .orca-tag{ animation:none }
  .boot.is-flying .boot__logo{ transition:none }
  .boot-leave{ transition:none }
}

/* ============================ motion (motion.js) =========================
   Pages marked data-motion run their scroll and entrances from script, so the
   CSS rise stands down on them; the pieces below are what that script draws. */
html[data-motion].js .rise{ animation:none }
.mw{ display:inline-block; will-change:transform, filter, opacity }
.cur{
  position:fixed; left:0; top:0; z-index:95; pointer-events:none;
  display:grid; place-items:center; width:88px; height:88px; margin:-44px 0 0 -44px;
  border-radius:50%; background:var(--c-accent); color:#fff;
  font:600 12px/1 var(--font-text); letter-spacing:.08em; text-transform:uppercase;
  transform:scale(0); will-change:transform;
}
@media (hover:none), (prefers-reduced-motion:reduce){ .cur{ display:none } }
html.lenis, html.lenis body{ height:auto }
.lenis.lenis-smooth{ scroll-behavior:auto !important }

/* ==========================================================================
   Films — a video section with its poster and one caption card per scene
   (driven by film.js). Shared by the homepage opening and the platform page.
   ========================================================================== */
/* ---- the films ---------------------------------------------------------
   Two autoplaying videos, each with its poster (the film's first frame) on
   screen until the stream can play. The copy is written into the page, one
   card per scene, and the script only decides which card is showing from the
   video's own clock — so the words change with the picture, not the wheel. */
.vfilm{ background:var(--film-bg) }
.vfilm__stage{
  position:sticky; top:var(--nav-h);
  height:calc(100svh - var(--nav-h)); overflow:hidden;
  background:var(--film-bg);
}
.vfilm__video{
  position:absolute; inset:0; width:100%; height:100%;
  object-fit:cover; object-position:center; display:block;
  background:var(--film-bg);
  /* The films are pictures, not players. No pointer reaches them, so no
     browser draws its hover chrome over them — Firefox's picture-in-picture
     toggle ignores the attribute and only this keeps it away. */
  pointer-events:none; user-select:none; -webkit-user-select:none;
}
.vfilm__video::-webkit-media-controls{ display:none !important }
/* The film's first frame as a real image, laid over the video until the
   video is actually playing. A <video> poster alone is not enough: some
   browsers drop it to a blank or black frame the moment loading starts, and
   the film is held back until it can play through, which can take a while. */
.vfilm__poster{
  position:absolute; inset:0; width:100%; height:100%; z-index:1;
  object-fit:cover; object-position:center; display:block;
  pointer-events:none; user-select:none;
  transition:opacity .7s var(--ease);
}
.vfilm.is-playing .vfilm__poster{ opacity:0 }
/* The first film's scale belongs to the opening (the motion script scrubs it
   with the scroll), so nothing here may transition transform — a CSS
   transition on a property GSAP is writing every frame turns into lag. */

/* one grid cell for every card, anchored at the bottom, so a short card and a
   long one sit on the same baseline and swap without the stage moving */
.vfilm__copy{
  position:absolute; left:50%; transform:translateX(-50%); z-index:3;
  bottom:calc(clamp(24px,4.5vh,56px) + env(safe-area-inset-bottom,0px));
  width:min(1000px, calc(100% - clamp(32px,12vw,220px)));
  display:grid; margin:0; padding:0; list-style:none; text-align:center;
}
.vfilm__scene{
  grid-area:1/1; align-self:end;
  padding:clamp(12px,1.2vw,18px) clamp(22px,2.4vw,36px) clamp(14px,1.3vw,20px);
  border-radius:18px;
  /* the same glass the film's copy has always sat in: a thin fill, and the
     blur / saturate / brightness stack doing the work of legibility */
  background:rgba(255,255,255,.17);
  -webkit-backdrop-filter:blur(15px) saturate(180%) brightness(1.12);
  backdrop-filter:blur(15px) saturate(180%) brightness(1.12);
  border:1px solid rgba(255,255,255,.5);
  box-shadow:0 26px 64px -34px rgba(10,16,32,.46),
             inset 0 1.5px 0 rgba(255,255,255,.95),
             inset 0 -1px 0 rgba(10,16,32,.06);
  color:var(--c-film-ink, #204289);
  opacity:0; visibility:hidden; transform:translateY(16px) scale(.985);
  transition:opacity .55s var(--ease), transform .8s var(--ease-out),
             visibility 0s linear .55s;
}
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .vfilm__scene{ background:rgba(255,255,255,.93) }
}
.vfilm__scene.is-on{
  opacity:1; visibility:visible; transform:none;
  transition:opacity .6s var(--ease) .12s, transform .9s var(--ease-out) .12s, visibility 0s;
}
/* inside the card the lines arrive one after another, the way the section
   headings below do, rather than as one block */
.vfilm__scene > *{
  opacity:0; transform:translateY(10px); filter:blur(4px);
  transition:opacity .5s var(--ease), transform .7s var(--ease-out), filter .6s var(--ease);
}
.vfilm__scene.is-on > *{ opacity:1; transform:none; filter:none }
.vfilm__scene.is-on > :nth-child(1){ transition-delay:.22s }
.vfilm__scene.is-on > :nth-child(2){ transition-delay:.34s }
.vfilm__scene.is-on > :nth-child(3){ transition-delay:.46s }
.vfilm__title, .vfilm__body{
  text-shadow:0 1px 10px rgba(255,255,255,.92), 0 0 4px rgba(255,255,255,.85);
}
.vfilm__title{
  font:600 clamp(20px,2.1vw,31px)/1.14 var(--font-display);
  letter-spacing:-.025em; margin:0 0 .22rem; text-wrap:balance; color:inherit;
}
.vfilm__body{
  font:400 clamp(13px,1vw,15.5px)/1.5 var(--font-text);
  margin:0 auto; max-width:78ch; text-wrap:pretty; color:inherit;
}
.vfilm__cta{
  display:inline-block; margin-top:.55rem;
  font:600 14px/1 var(--font-text); text-decoration:none;
  padding:.9em 1.7em; border-radius:999px;
  background:var(--c-accent); color:#fff;
  box-shadow:0 8px 30px color-mix(in srgb,var(--c-accent) 32%,transparent);
  transition:transform .2s ease, box-shadow .2s ease, background .2s ease;
}
.vfilm__cta:hover{
  background:var(--c-accent-press,#1E52D8); color:#fff; transform:translateY(-2px);
  box-shadow:0 14px 40px color-mix(in srgb,var(--c-accent) 42%,transparent);
}
@media (max-width:860px){
  .vfilm__copy{ width:calc(100% - 32px); bottom:calc(20px + env(safe-area-inset-bottom,0px)) }
}
@media (prefers-reduced-motion:reduce){
  .vfilm__scene, .vfilm__scene > *{ transition:none !important }
}

/* the scene titles arrive word by word (see the script), so the card's own
   line-by-line entrance applies to everything but the title */
.vfilm__scene > .vfilm__title{ opacity:1; transform:none; filter:none; transition:none }
.vfilm__title .w{ display:inline-block }

/* The links sit on the page's true centre: on a wide screen the two outer
   tracks share the free space equally, but never shrink below their content,
   so the wordmark is still never the thing that gives way. */
@media (min-width:1024px){
  .mast{ grid-template-columns:minmax(max-content,1fr) auto minmax(max-content,1fr) }
}

/* On a portrait phone the film is shown whole, across the full width, rather
   than cropped to the height of the screen: a 16:9 picture cover-fitted to a
   tall screen kept barely a third of its width. */
@media (max-width:860px) and (orientation:portrait){
  .vfilm__video, .vfilm__poster{ object-fit:contain; object-position:center 42% }
}
