/* ============================================================
   Klavius — marketing site styles
   Rebuilt 2026-06 on the Klavius Design System (handoff bundle).
   Tokens: ink + indigo accent + near-white paper (NOT cream).
   Fonts (loaded in <head>): Fraunces (display), Inter (text),
   Geist Mono (labels / reg-codes). Flat surfaces, hairline
   borders, no gradients/glow. References: Sequence, Duna, Loops.
   ============================================================ */

:root {
  /* Brand */
  --ink: #0E1116;
  --paper: #FAFAF9;            /* clean neutral near-white (Duna-calm) */

  /* Accent — Indigo (locked) */
  --accent: #5046C8;
  --accent-hover: #4239AE;
  --accent-active: #372F93;
  --accent-tint: #ECEAFB;

  /* Neutrals (cool-warm tuned to paper) */
  --neutral-0: #FFFFFF;
  --neutral-100: #F0F0EE;
  --neutral-200: #E7E7E3;
  --neutral-300: #D8D8D3;
  --neutral-500: #8A8880;
  --neutral-600: #5B5F66;
  --neutral-800: #2A2D31;
  --neutral-900: #0E1116;

  /* Semantic */
  --bg: var(--paper);
  --surface: var(--neutral-0);
  --surface-sunken: var(--neutral-100);
  --text: var(--neutral-800);
  --text-strong: var(--ink);
  --text-muted: var(--neutral-600);
  --text-subtle: var(--neutral-500);
  --border: var(--neutral-200);
  --border-strong: var(--neutral-300);

  /* On ink surfaces */
  --on-ink: #F6F5F1;
  --on-ink-muted: #C9CBD0;
  --on-ink-subtle: #8A8E96;
  --on-ink-line: rgba(255,255,255,0.10);

  /* Risk / status — reserved, never branding */
  --risk-low: #138A5E;  --risk-low-tint: #E2F1EA;  --risk-low-ink: #0C6043;
  --risk-med: #D98A1F;  --risk-med-tint: #FBF0DD;  --risk-med-ink: #8A5512;
  --risk-high: #D1402A; --risk-high-tint: #FAE5E1; --risk-high-ink: #A3301F;

  /* Type */
  --font-display: "Fraunces", Georgia, "Times New Roman", serif;
  --font-text: "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-mono: "Geist Mono", "IBM Plex Mono", "JetBrains Mono", ui-monospace, monospace;

  /* Radius */
  --radius-sm: 6px; --radius-md: 8px; --radius-lg: 12px; --radius-xl: 16px; --radius-pill: 999px;

  /* Space (4px base) */
  --space-1: 4px; --space-2: 8px; --space-3: 12px; --space-4: 16px; --space-5: 20px;
  --space-6: 24px; --space-8: 32px; --space-10: 40px; --space-12: 48px; --space-16: 64px;
  --space-20: 80px; --space-24: 96px;

  --shadow-popover: 0 4px 16px rgba(15,20,25,0.10);
  --shadow-card: 0 1px 2px rgba(15,20,25,0.04), 0 18px 40px -22px rgba(15,20,25,0.18);

  --maxw: 1120px;
}

* { box-sizing: border-box; margin: 0; padding: 0; }

html { scroll-behavior: smooth; scroll-padding-top: 90px; -webkit-text-size-adjust: 100%; }

body {
  font-family: var(--font-text);
  font-weight: 400;
  color: var(--text);
  background: var(--bg);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

::selection { background: var(--accent-tint); color: var(--accent-active); }

/* Titles stay Fraunces (founder reverted the sans experiment same day,
   2026-07-23: "revenons au Fraunces pour les titres comme avant" — the
   serif IS the differentiator against GitBook's all-grotesque look). */
h1, h2, h3, h4 { font-family: var(--font-display); font-weight: 500; color: var(--text-strong); line-height: 1.1; }
a { color: var(--accent); text-decoration: none; }
img, svg { display: block; }

/* ---------- layout ---------- */
.shell { max-width: var(--maxw); margin: 0 auto; padding: 0 var(--space-8); }

section.band { padding: var(--space-24) 0; border-top: 1px solid var(--border); }

.eyebrow {
  font-family: var(--font-mono); font-size: 12px; font-weight: 500;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--accent);
  display: inline-flex; align-items: center; gap: 8px;
}
.eyebrow .dot { width: 7px; height: 7px; border-radius: 999px; background: var(--accent); }
.eyebrow.muted { color: var(--text-subtle); }
.eyebrow.muted .dot { background: var(--text-subtle); }
.eyebrow.on-ink { color: var(--on-ink-muted); }
.eyebrow.on-ink .dot { background: var(--accent); }

.sec-head { max-width: 660px; margin-bottom: var(--space-12); }
.sec-head h2 { font-size: 34px; letter-spacing: -0.015em; margin: var(--space-4) 0 var(--space-4); }
.sec-head p { color: var(--text-muted); font-size: 18px; line-height: 1.55; }
.sec-head.center { margin-left: auto; margin-right: auto; text-align: center; }

/* ---------- wordmark / monogram ---------- */
.wm { font-family: var(--font-display); font-weight: 500; letter-spacing: -0.3px; color: var(--text-strong); line-height: 1; }
.k-mono { display: block; }

/* ---------- top bar ---------- */
.topbar {
  position: sticky; top: 0; z-index: 50;
  background: color-mix(in srgb, var(--paper) 80%, transparent);
  backdrop-filter: saturate(140%) blur(12px);
  -webkit-backdrop-filter: saturate(140%) blur(12px);
  border-bottom: 1px solid transparent;
  transition: border-color .2s ease, background .2s ease;
}
.topbar.scrolled { border-bottom-color: var(--border); }
.topbar-inner {
  max-width: var(--maxw); margin: 0 auto; padding: var(--space-3) var(--space-8);
  display: flex; align-items: center; gap: var(--space-6);
}
.brand-lockup { display: flex; align-items: center; gap: var(--space-3); }
.brand-lockup .wm { font-size: 19px; }
.topbar .spacer { flex: 1; }
/* AngelList-style pill: the primary links sit in a hairline capsule so
   the bar reads brand · [pill] · actions instead of a flat link row. */
.nav-links {
  display: flex; align-items: center; gap: 2px;
  border: 1px solid var(--border); border-radius: var(--radius-pill);
  padding: 4px;
  background: color-mix(in srgb, var(--surface) 72%, transparent);
}
.nav-actions { display: flex; align-items: center; gap: var(--space-3); }

.navlink {
  font-family: var(--font-text); font-size: 14px; font-weight: 500; color: var(--text-strong);
  cursor: pointer; line-height: 1.4; padding: 6px 14px; border-radius: var(--radius-pill);
  transition: background .25s ease, color .25s ease;
  /* A nav label is a label, never a paragraph. Without this the pill lets a
     squeezed flex item break mid-phrase — « Comment ça marche » stacked onto
     two lines and knocked the bar out of alignment. */
  white-space: nowrap;
}
.navlink:hover { background: var(--accent-tint); color: var(--accent-active); }

.nav-toggle { display: none; background: none; border: 1px solid var(--border-strong); border-radius: var(--radius-md); padding: 7px; cursor: pointer; color: var(--text-strong); }

/* ---------- language switcher (EN / FR) ----------
   Two locales, so no menu: both stay visible, the current one in ink and
   the other subtle. Geist Mono at eyebrow scale so it reads as metadata
   rather than a fifth nav item, and a hairline fences it off from the
   Log in / Book-a-demo cluster. `a { color: var(--accent) }` is global in
   this file, so both states set colour explicitly — drop either
   declaration and the inactive locale turns indigo and competes with the
   real accent. */
.nav-lang {
  display: inline-flex; align-items: center;
  padding-right: var(--space-3);
  border-right: 1px solid var(--border);
}
.nav-lang a {
  font-family: var(--font-mono); font-size: 11.5px; font-weight: 500;
  letter-spacing: 0.08em; text-transform: uppercase; line-height: 1;
  color: var(--text-subtle);
  padding: 5px 7px; border-radius: var(--radius-sm);
  transition: color .25s ease;
}
.nav-lang a + a { position: relative; }
.nav-lang a + a::before {
  content: ""; position: absolute; left: 0; top: 50%;
  width: 1px; height: 10px; transform: translateY(-50%);
  background: var(--border-strong);
}
.nav-lang a:hover { color: var(--accent); }
.nav-lang a.on, .nav-lang a.on:hover { color: var(--text-strong); cursor: default; }
.nav-lang a:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Globe mark labelling the pair. It is a PNG, so it is painted as a MASK
   rather than dropped in as an <img>: the artwork supplies the shape and
   background-color supplies the ink, which means it inherits the same
   --text-subtle as the inactive locale instead of being a fixed charcoal
   that drifts from the type beside it.
   Hidden where mask-image is unsupported — a bare element with a
   background-color would otherwise render as a solid square. */
.nav-lang .globe { display: none; }
@supports ((-webkit-mask-image: url("")) or (mask-image: url(""))) {
  /* 16px against a measured 9px cap height ≈ 1.8×, which is the proportion
     the reference carries — the mark should read as a peer of the codes, not
     as a footnote to them. At 12px (1.33×) it disappeared next to the type. */
  .nav-lang .globe {
    display: block; width: 16px; height: 16px; flex: none;
    margin-right: 7px;
    background-color: var(--text-subtle);
    -webkit-mask: url(/brand/globe.png) center / contain no-repeat;
            mask: url(/brand/globe.png) center / contain no-repeat;
  }
}
/* the overlay twin is inert until the 680px block opens it */
.nav-lang.nav-lang-m { display: none; }

/* Sticky-bar anchor offset — every in-page anchor target clears the
   topbar instead of landing cut underneath it. */
[id] { scroll-margin-top: 78px; }

/* Platform dropdown — compact hairline panel (Intercom scale, not a mega
   menu): mono module tag · title · one-line description per item. Opens
   with a small rise + settle; items stagger in; chevron pivots. */
.nav-group { position: relative; }
.nav-drop-btn {
  display: inline-flex; align-items: center; gap: 6px;
  background: none; border: none;
}
.nav-drop-btn .chev { color: var(--text-subtle); }
.nav-drop-btn:hover .chev, .nav-group.open .nav-drop-btn .chev { color: currentColor; }
.nav-drop-btn .chev { transition: transform .25s cubic-bezier(.22,1,.36,1); }
.nav-group.open .nav-drop-btn .chev { transform: rotate(180deg); }
.nav-group.open .nav-drop-btn { background: var(--accent-tint); color: var(--accent-active); }
.nav-drop {
  /* Anchored to the capsule's left edge (-5px = pill padding + border),
     not centered on the trigger — centering left the panel floating
     detached to the left of the pill. Tighter 10px drop gap. */
  position: absolute; top: calc(100% + 10px); left: -5px;
  min-width: 372px; padding: var(--space-2);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: 0 12px 32px rgba(14, 17, 22, 0.10), 0 2px 8px rgba(14, 17, 22, 0.05);
  transform: translateY(8px) scale(.98);
  transform-origin: top left;
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity .2s ease, transform .24s cubic-bezier(.22,1,.36,1),
              visibility 0s linear .24s;
}
.nav-group.open .nav-drop {
  opacity: 1; visibility: visible; pointer-events: auto;
  transform: translateY(0) scale(1);
  transition-delay: 0s;
}
.drop-item {
  display: flex; align-items: flex-start; gap: var(--space-3);
  padding: 10px 12px; border-radius: var(--radius-md);
  opacity: 0; transform: translateY(5px);
  transition: opacity .26s ease var(--dd, 0s),
              transform .26s cubic-bezier(.22,1,.36,1) var(--dd, 0s),
              background .2s ease;
}
.nav-group.open .drop-item { opacity: 1; transform: none; }
.nav-group.open .drop-item:nth-child(2) { --dd: .035s; }
.nav-group.open .drop-item:nth-child(3) { --dd: .07s; }
.nav-group.open .drop-item:nth-child(4) { --dd: .105s; }
.drop-item:hover { background: var(--surface-sunken); }
/* Module icon tile — the same line-art icons as the Platform
   accordion (.pf-ic), replacing the old acronym text chips. */
.drop-ic {
  flex: 0 0 auto; width: 30px; height: 30px; margin-top: 2px;
  display: grid; place-items: center;
  color: var(--accent); background: var(--accent-tint);
  border: 1px solid var(--border); border-radius: var(--radius-md);
}
.drop-ic svg { width: 16px; height: 16px; display: block; }
.drop-txt strong { display: block; font-size: 14px; font-weight: 600; color: var(--text-strong); line-height: 1.35; }
.drop-txt small { display: block; font-size: 12.5px; color: var(--text-muted); line-height: 1.45; margin-top: 2px; }
.drop-item:hover .drop-txt strong { color: var(--accent-active); }
@media (prefers-reduced-motion: reduce) {
  .nav-drop, .drop-item, .nav-drop-btn .chev { transition: none; }
  .drop-item { opacity: 1; transform: none; }
}

/* ---------- buttons ---------- */
.btn {
  font-family: var(--font-text); font-size: 14px; font-weight: 500; line-height: 1;
  /* Full pills (GitBook CTA grammar, founder call 2026-07-23). */
  border-radius: var(--radius-pill); padding: 10px 18px; cursor: pointer;
  border: 1px solid transparent; transition: all .15s ease;
  display: inline-flex; align-items: center; gap: 8px; white-space: nowrap; text-decoration: none;
}
.btn .arr { transition: transform .3s ease; display: inline-block; }
.btn:hover .arr { transform: translateX(4px); }
/* diagonal (north-east) arrow for sign-in — slides up-right on hover */
.btn .arr-ne { transition: transform .3s ease; display: inline-block; }
.btn:hover .arr-ne { transform: translate(3px, -3px); }
.btn-secondary { background: var(--surface); color: var(--text-strong); border-color: var(--border-strong); }
.btn-secondary:hover { border-color: var(--text-subtle); background: var(--neutral-100); }
.btn-ghost { background: transparent; color: var(--text-strong); }
.btn-ghost:hover { color: var(--accent); }
/* CTA: ink at rest, slides to accent on hover (DS motion) */
.btn-ink { background: var(--ink); color: var(--on-ink); transition: background .3s ease; }
.btn-ink:hover { background: var(--accent); }
.btn-onink { background: #fff; color: var(--ink); }
.btn-onink:hover { background: var(--accent); color: #fff; }
/* Book-a-demo CTA (founder call 2026-07-06): Klavius violet at rest,
   white text — the ONE conversion action owns the brand colour on every
   surface (topbar, hero, closing ink band, mobile menu). Hover/press
   walk DOWN the accent ramp; on the ink band the darker hover still
   separates cleanly from the #0E1116 background. */
.btn-accent { background: var(--accent); color: #fff; transition: background .3s ease; }
.btn-accent:hover { background: var(--accent-hover); color: #fff; }
.btn-accent:active { background: var(--accent-active); }
.btn.lg { font-size: 15px; padding: 13px 26px; }
.btn.sm { font-size: 13px; padding: 7px 12px; }

/* ---------- pills ---------- */
.pill {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px; font-weight: 500; padding: 3px 9px; border-radius: var(--radius-pill);
  font-family: var(--font-text);
}
.pill .led { width: 6px; height: 6px; border-radius: 999px; }
.pill.low { background: var(--risk-low-tint); color: var(--risk-low-ink); }
.pill.low .led { background: var(--risk-low); }
.pill.med { background: var(--risk-med-tint); color: var(--risk-med-ink); }
.pill.med .led { background: var(--risk-med); }
.pill.high { background: var(--risk-high-tint); color: var(--risk-high-ink); }
.pill.high .led { background: var(--risk-high); }
.pill.ai { background: var(--accent-tint); color: var(--accent-active); }

/* sparkle (AI marker) */
.spark { color: var(--accent); flex: none; }

/* ---------- hero (centered, Loops-style) ---------- */
.hero { padding: var(--space-20) 0 0; position: relative; z-index: 0; overflow-x: clip; }

/* Brand object — three interlocked indigo rings (the "future 3D
   element" this hero was cleaned for): ONE pre-rendered signature
   object, GitBook composition — large + CENTERED behind the product
   frame, which floats on it. Centered via left/right+margin auto (a
   transform would fight the drift keyframes); overflow-x: clip on
   .hero contains the side loops without a scroll container (`clip`,
   unlike `hidden`, doesn't couple overflow-y). Soft top fade keeps
   the CTA/undernote zone whisper where the arcs rise behind it —
   the image's own top-center is mostly air (alpha-probed). */
.hero-stage { position: relative; }
.hero-rings {
  /* Wider than its containing shell, so auto margins can't center it
     (they resolve to 0 when over-constrained) — center via left:50% +
     translateX(-50%), which every drift keyframe restates. */
  position: absolute; top: -110px; left: 50%;
  transform: translateX(-50%);
  width: clamp(520px, 118vw, 1560px); aspect-ratio: 4345 / 2430;
  background-image: image-set(
    url("brand/rings-lg-1x.webp") 1x,
    url("brand/rings-lg.webp") 2x
  );
  background-size: contain; background-repeat: no-repeat;
  /* Top fade = the arcs stay whisper behind the CTA/undernote zone;
     bottom fade = the loops recede before the marquee band's label.
     PERCENTAGES, not px — px fades overlap on the small mobile render
     (110+220px > the whole image) and wash the object out entirely. */
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 13%, #000 75%, transparent);
  mask-image: linear-gradient(to bottom, transparent, #000 13%, #000 75%, transparent);
  z-index: 0; pointer-events: none;
  animation: ringsDrift 18s ease-in-out infinite alternate;
}
.hero-stage .hero-figure, .hero-stage .scroll-cue { position: relative; z-index: 1; }
@keyframes ringsDrift {
  from { transform: translateX(-50%) translateY(-8px) rotate(-0.8deg); }
  to   { transform: translateX(-50%) translateY(8px) rotate(0.8deg); }
}
@media (prefers-reduced-motion: reduce) {
  .hero-rings { animation: none; }
}
/* Mobile: the object is small (≈300px tall) — rise less above the
   swiper so the solid knot band never sits behind the undernote text. */
@media (max-width: 680px) {
  .hero-rings { top: -40px; }
}
/* Whisper-faint dot-grid backdrop — toned down to a near-blank, Wrangle-clean
   hero so the framed demo (and a future 3D element) sit on quiet paper. */
.hero::before {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background-image: radial-gradient(color-mix(in srgb, var(--text-strong) 3%, transparent) 1px, transparent 1.6px);
  background-size: 24px 24px;
  -webkit-mask-image: radial-gradient(120% 60% at 50% 0%, #000 14%, transparent 64%);
  mask-image: radial-gradient(120% 60% at 50% 0%, #000 14%, transparent 64%);
}
/* Same dot texture for alternating sections — fades in/out vertically so the
   hairline separators stay crisp. Add the .dots class to every other band. */
.dots { position: relative; z-index: 0; }
/* Violet mesh wash — the same gradient as the app's login page, reused as a
   section background (Why Klavius). Lives in a ::before so the content stays
   above it; a vertical mask fades it into the neighbouring bands (no seam). */
.why-mesh { position: relative; z-index: 0; }
.why-mesh::before {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  /* Soft violet confined to the empty top-right, plus a fainter diagonal
     echo bottom-left to counterbalance. NO vertical mask on purpose: the
     colour is cut HARD by the section's hairline dividers (the .band
     border-top, top + bottom), matching the landing's sharp-line language
     instead of fading across them. */
  background:
    radial-gradient(58% 74% at 100% 12%, oklch(0.64 0.16 293 / 0.4), oklch(0.7 0.13 322 / 0.2) 42%, transparent 67%),
    radial-gradient(32% 40% at 82% 0%, oklch(0.72 0.13 268 / 0.22), transparent 62%),
    radial-gradient(38% 46% at -3% 103%, oklch(0.66 0.15 322 / 0.22), transparent 60%);
}
.dots::before {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background-image: radial-gradient(color-mix(in srgb, var(--text-strong) 3%, transparent) 1px, transparent 1.6px);
  background-size: 24px 24px;
  -webkit-mask-image: linear-gradient(180deg, transparent, #000 16%, #000 84%, transparent);
  mask-image: linear-gradient(180deg, transparent, #000 16%, #000 84%, transparent);
}
.hero-center { max-width: 800px; margin: 0 auto; text-align: center; }
.hero h1 { font-size: 60px; letter-spacing: -0.025em; line-height: 1.04; max-width: 26ch; margin: 0 auto; }
.hero h1 .accent { color: var(--accent); }
/* Ampersand: a touch smaller + italic so it reads as a refined connector
   between the two terms instead of dominating them (Fraunces has a lovely
   italic &). */
.amp { font-size: 0.8em; font-style: italic; }
.hero .lead { font-size: 19px; line-height: 1.55; color: var(--text-muted); max-width: 56ch; margin: var(--space-6) auto 0; }
.hero .cta-row { display: flex; flex-wrap: wrap; gap: var(--space-3); margin-top: var(--space-8); justify-content: center; }
.hero .undernote { font-size: 13.5px; color: var(--text-subtle); margin-top: var(--space-5); display: flex; align-items: center; gap: 8px; justify-content: center; }
.hero .undernote .led { width: 6px; height: 6px; border-radius: 999px; background: var(--risk-low); }
.hero-figure { max-width: 1180px; margin: var(--space-20) auto 0; }
/* Glassy bezel around the product demo (Wrangle-style): a translucent frosted
   frame with a light edge + soft float. backdrop-blur frosts the aurora behind,
   so the border reads as glass. */
.hero-frame {
  position: relative; padding: 6px; border-radius: 20px;
  background: linear-gradient(180deg, rgba(255,255,255,0.55), rgba(255,255,255,0.22));
  border: 1px solid rgba(255,255,255,0.6);
  -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.9),
    0 2px 6px rgba(15, 20, 25, 0.05),
    0 34px 64px -28px rgba(15, 20, 25, 0.22);
}
/* ── hero border-beam ──────────────────────────────────────────────
   A single Klavius-violet point orbits the glassy frame leaving a conic
   trail; a blurred copy blooms the hue outward over the bezel. Pure CSS:
   an @property angle drives the conic rotation, masked to a 1.5px border
   ring (mask-composite: exclude). Browsers without @property keep the
   static glassy border — never a broken state. landing.js flips
   --bb-play to paused when the hero scrolls offscreen. */
@property --bb-angle { syntax: "<angle>"; initial-value: 0deg; inherits: false; }
@keyframes bb-spin { to { --bb-angle: 360deg; } }
.hero-frame::before,
.hero-frame::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit;
  padding: 1.5px; pointer-events: none;
  /* Two symmetric points, 180° apart, sharing one --bb-angle animation —
     identical dynamics, mirrored across the frame. */
  background: conic-gradient(from var(--bb-angle),
    #fff 0deg, var(--accent) 6deg, transparent 70deg,
    transparent 180deg, #fff 180deg, var(--accent) 186deg, transparent 250deg,
    transparent 360deg);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask-composite: exclude;
  animation: bb-spin 7s linear infinite;
  animation-play-state: var(--bb-play, running);
}
.hero-frame::before { inset: -1px; filter: blur(12px); }
@media (prefers-reduced-motion: reduce) {
  .hero-frame::before, .hero-frame::after { animation: none; }
}
/* the product screenshot inside the glass frame — quiet hairline; the frame
   provides the float. Content fades to surface near the bottom (no hard slice). */
.hero-shot {
  position: relative; overflow: hidden; line-height: 0;
  /* Shots are now landscape viewport captures (1875x958). The frame
     matches their ratio so the whole app surface shows edge-to-edge —
     no crop, no bottom fade needed (the previous 2:1 frame existed to
     crop the old near-square 2x full-page shots). */
  aspect-ratio: 1875 / 958;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  box-shadow: 0 1px 2px rgba(15, 20, 25, 0.04);
}
/* Show the FULL screenshot width (sidebar intact), anchored to the top.
   No object-fit:cover — that was chopping the app's left edge on taller
   viewports. width:100% + height:auto keeps the real app proportions. */
.hero-slide { position: absolute; top: 0; left: 0; width: 100%; height: auto; opacity: 0; transition: opacity .8s ease; }
.hero-slide.is-active { opacity: 1; }
@media (prefers-reduced-motion: reduce) { .hero-slide { transition: none; } }

/* Hero demo — a scroll-snap SWIPER of the real product screens, on ANY
   TOUCH device (was gated on max-width:680, which dropped the swipe when
   a phone rotated to LANDSCAPE — a phone is >680px wide in landscape but
   still wants swipe, not the mouse crossfade). Pointer type is the right
   signal; landing.js's heroSnap matches this query exactly. The shots
   are landscape captures, so the frame follows their ratio (whole screen,
   no crop) and the visitor swipes across them; a mouse gets the crossfade
   + dots instead. */
@media (hover: none) and (pointer: coarse) {
  .hero-shot {
    aspect-ratio: 1875 / 958;
    display: flex; overflow-x: auto; overflow-y: hidden;
    scroll-snap-type: x mandatory;
    scrollbar-width: none; -webkit-overflow-scrolling: touch;
    background: var(--surface);
  }
  .hero-shot::-webkit-scrollbar { display: none; }
  .hero-slide {
    position: static; flex: 0 0 100%; width: 100%; height: 100%;
    object-fit: cover; object-position: top center;
    opacity: 1; transition: none; scroll-snap-align: center;
  }
}

/* ---------- app window mock ---------- */
.win { border: 1px solid var(--border-strong); border-radius: var(--radius-lg); overflow: hidden; background: var(--surface); box-shadow: var(--shadow-card); }
.win .bar { height: 38px; background: var(--neutral-100); border-bottom: 1px solid var(--border); display: flex; align-items: center; padding: 0 var(--space-4); gap: var(--space-3); }
.win .bar .dots { display: flex; gap: 6px; }
/* macOS traffic lights (founder 2026-08-05) — same hexes the hub window
   has carried since #130, so every window mock on the site closes /
   minimises / zooms in the same colours. Set per child rather than
   inline: four panels × two languages all inherit one rule. */
.win .bar .dots i { width: 10px; height: 10px; border-radius: 999px; background: var(--neutral-300); display: block; }
.win .bar .dots i:nth-child(1) { background: #EC6A5E; }
.win .bar .dots i:nth-child(2) { background: #F4BF50; }
.win .bar .dots i:nth-child(3) { background: #61C554; }
.win .bar .addr { font-family: var(--font-mono); font-size: 11px; color: var(--text-subtle); }
.win .body { padding: var(--space-5); }

.dash-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); margin-bottom: var(--space-4); }
.dash-head .t { font-size: 14px; font-weight: 600; color: var(--text-strong); display: flex; align-items: center; gap: 8px; }
.dash-head .meta { font-family: var(--font-mono); font-size: 11px; color: var(--text-subtle); }

.wtable { width: 100%; border-collapse: collapse; }
.wtable th { font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.05em; text-transform: uppercase; color: var(--text-subtle); text-align: left; padding: var(--space-2) var(--space-3); border-bottom: 1px solid var(--border); font-weight: 500; }
.wtable td { font-size: 12.5px; color: var(--text); padding: 10px var(--space-3); border-bottom: 1px solid var(--border); }
.wtable tr:last-child td { border-bottom: none; }
.wtable td .ref { font-family: var(--font-mono); font-size: 11px; color: var(--text-muted); }
.wtable td .doc { font-weight: 500; color: var(--text-strong); }

/* ── Legal / trust document pages (Security, Subprocessors) ── */
.doc-body { max-width: 760px; }
.doc-body h3 { font-family: var(--font-text); font-weight: 600; font-size: 19px; letter-spacing: -0.01em; margin: var(--space-10) 0 var(--space-3); color: var(--text-strong); }
.doc-body h3:first-of-type { margin-top: 0; }
.doc-body p { color: var(--text-muted); font-size: 16px; line-height: 1.65; margin: 0 0 var(--space-4); }
.doc-body ul { margin: 0 0 var(--space-4); padding-left: 1.15em; }
.doc-body li { color: var(--text-muted); font-size: 16px; line-height: 1.6; margin-bottom: 6px; }
.doc-body strong { color: var(--text-strong); font-weight: 600; }
.doc-body a { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; }
.doc-note { font-size: 14.5px; color: var(--text-muted); line-height: 1.6; background: var(--surface-sunken); border: 1px solid var(--border); border-radius: var(--radius-md); padding: var(--space-4) var(--space-5); margin: var(--space-5) 0; }
/* External audit-report request (Aikido). The badge SVG is SELF-HOSTED on
   purpose. Aikido's own snippet points <img src> at app.aikido.dev, which
   would put a third-party request on EVERY page load — their server would
   see every visitor's IP — and would force widening img-src in serve.json.
   Serving the file ourselves keeps the CSP untouched and keeps the
   subprocessors claim ("no separate advertising or analytics processors")
   true without an asterisk: Aikido only ever sees a visitor who clicks.
   If the badge art is ever refreshed, re-download it rather than pointing
   the src back at their domain. */
.audit-req { display: flex; align-items: center; gap: var(--space-5); flex-wrap: wrap; font-size: 14.5px; color: var(--text-muted); line-height: 1.6; background: var(--surface-sunken); border: 1px solid var(--border); border-radius: var(--radius-md); padding: var(--space-4) var(--space-5); margin: var(--space-5) 0; }
.audit-req-txt { flex: 1 1 240px; }
.audit-req-txt strong { color: var(--text-strong); font-weight: 600; }
.audit-req-badge { display: inline-flex; flex: 0 0 auto; transition: opacity .18s ease; }
.audit-req-badge:hover { opacity: 0.78; }
.audit-req-badge img { display: block; height: 32px; width: 160px; }

/* Honest "working draft" banner for the legal pages — amber (the med-risk
   tone) so it reads as in-progress, not a warning-red alarm. */
.legal-draft { font-size: 14px; line-height: 1.6; color: var(--risk-med-ink); background: var(--risk-med-tint); border: 1px solid color-mix(in srgb, var(--risk-med) 35%, var(--border)); border-radius: var(--radius-md); padding: var(--space-4) var(--space-5); margin: 0 0 var(--space-6); display: flex; flex-direction: column; gap: 6px; }
.legal-draft strong { color: var(--risk-med-ink); font-weight: 600; }
.legal-draft .legal-draft-tag { font-family: var(--font-mono); font-size: 10.5px; letter-spacing: 0.08em; text-transform: uppercase; opacity: 0.85; }
.legal-ph { font-family: var(--font-mono); font-size: 0.9em; background: color-mix(in srgb, var(--risk-med) 12%, transparent); border-radius: 4px; padding: 0.5px 5px; color: var(--risk-med-ink); }

/* EU AI Act value chain — the three-role storytelling graphic on the
   Responsible-AI trust rubric. Upstream (Anthropic) → downstream (Klavius,
   highlighted) → deployer (the client). Flat + hairline, one accent;
   stacks vertically on mobile with the arrows rotating to point down. */
.aiact-chain { display: flex; align-items: stretch; gap: var(--space-3); margin: var(--space-6) 0; }
.aiact-node { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; gap: 6px; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg); padding: var(--space-4) var(--space-5); }
.aiact-node.is-klavius { border-color: color-mix(in srgb, var(--accent) 45%, var(--border)); background: var(--accent-tint); }
.aiact-role { font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--text-subtle); }
.aiact-name { font-weight: 600; font-size: 17px; letter-spacing: -0.01em; color: var(--text-strong); }
.aiact-node.is-klavius .aiact-name { color: var(--accent-active); }
.aiact-desc { font-size: 13px; line-height: 1.5; color: var(--text-muted); }
.aiact-badge { align-self: flex-start; margin-top: 4px; font-family: var(--font-mono); font-size: 10.5px; letter-spacing: 0.02em; color: #fff; background: var(--accent); border-radius: var(--radius-pill); padding: 4px 10px; }
.aiact-badge em { font-style: italic; opacity: 0.95; }
.aiact-arrow { flex: 0 0 auto; align-self: center; color: var(--accent); font-size: 22px; line-height: 1; }
@media (max-width: 720px) {
  .aiact-chain { flex-direction: column; }
  .aiact-arrow { transform: rotate(90deg); align-self: center; }
}
.doc-meta { font-family: var(--font-mono); font-size: 12px; color: var(--text-subtle); margin-top: var(--space-12); padding-top: var(--space-5); border-top: 1px solid var(--border); }
.doc-table-wrap { overflow-x: auto; margin: var(--space-6) 0; }
.doc-table-wrap .wtable td { font-size: 14px; vertical-align: top; }
.doc-table-wrap .wtable th { font-size: 10.5px; }

/* stat grid */
.stat-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-3); }
.stat { border: 1px solid var(--border); border-radius: var(--radius-md); padding: var(--space-4); background: var(--surface); }
.stat .k { font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.05em; text-transform: uppercase; color: var(--text-subtle); }
.stat .v { font-family: var(--font-display); font-size: 26px; color: var(--text-strong); margin-top: 6px; line-height: 1; }
.stat .d { font-size: 11.5px; color: var(--text-muted); margin-top: 6px; }

/* dora gauge / progress */
.ctrl-row { display: flex; align-items: center; gap: var(--space-3); padding: 9px 0; border-top: 1px solid var(--border); }
.ctrl-row:first-child { border-top: none; }
.ctrl-row .nm { font-size: 12.5px; color: var(--text-strong); flex: 1; }
.ctrl-row .bar-track { width: 110px; height: 6px; background: var(--neutral-100); border-radius: 999px; overflow: hidden; }
.ctrl-row .bar-fill { height: 100%; background: var(--accent); border-radius: 999px; }
.ctrl-row .pct { font-family: var(--font-mono); font-size: 11.5px; color: var(--text-muted); width: 34px; text-align: right; }
/* Terms of service stay English-only — translating a contract is a legal act,
   not a copy task — so the FR footer link says so rather than dropping a French
   reader onto an English contract unannounced. */
.lang-note { opacity: .62; font-size: .92em; }

/* FR needs more room in this column: « Faible » is twice the width of "Low",
   and French puts a space before the percent sign ("100 %"). Gated so the EN
   layout is untouched. */
html[lang="fr"] .ctrl-row .pct { width: 48px; }

/* oversight timeline */
.timeline { position: relative; padding-left: var(--space-6); }
.timeline::before { content: ""; position: absolute; left: 5px; top: 4px; bottom: 4px; width: 1px; background: var(--border-strong); }
.tl-item { position: relative; padding-bottom: var(--space-5); }
.tl-item:last-child { padding-bottom: 0; }
.tl-item .node { position: absolute; left: calc(-1 * var(--space-6) + 1px); top: 3px; width: 11px; height: 11px; border-radius: 999px; background: var(--surface); border: 2px solid var(--accent); }
.tl-item .node.done { background: var(--accent); }
.tl-item .when { font-family: var(--font-mono); font-size: 11px; color: var(--text-subtle); }
.tl-item .what { font-size: 13px; color: var(--text-strong); margin-top: 2px; }
.tl-item .who { font-size: 12px; color: var(--text-muted); }

/* incident clock chips */
.clock-row { display: flex; gap: var(--space-2); flex-wrap: wrap; }
.clock { border: 1px solid var(--border); border-radius: var(--radius-md); padding: 9px 12px; flex: 1; min-width: 96px; }
.clock .c-t { font-family: var(--font-mono); font-size: 18px; color: var(--text-strong); }
.clock .c-l { font-size: 11px; color: var(--text-subtle); margin-top: 3px; }

/* ---------- regulations carousel (Kalispo-style marquee) ---------- */
.marquee-band { padding: var(--space-12) 0; }
.marquee-band .lbl { font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.07em; text-transform: uppercase; color: var(--text-subtle); text-align: center; margin-bottom: var(--space-6); }
.marquee { overflow: hidden; -webkit-mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent); mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent); }
.marquee-track { display: flex; width: max-content; animation: marquee 46s linear infinite; }
.marquee:hover .marquee-track { animation-play-state: paused; }
.marquee-set { display: flex; gap: 12px; padding-right: 12px; flex: none; }
/* 3 identical sets in the track; shift by exactly one set (-33.3333%) so
   the loop is seamless AND there are always >=2 sets under the viewport
   (prevents the "cut line" gap on wide screens). */
@keyframes marquee { from { transform: translateX(0); } to { transform: translateX(-33.3333%); } }
.reg-chip {
  display: inline-flex; align-items: center; gap: 9px; flex: none; white-space: nowrap;
  font-family: var(--font-text); font-size: 14px; font-weight: 500; color: var(--text);
  border: 1px solid var(--border); background: var(--surface);
  border-radius: var(--radius-pill); padding: 7px 16px 7px 8px;
}
.reg-flag { width: 20px; height: 20px; border-radius: 50%; overflow: hidden; flex: none; box-shadow: inset 0 0 0 1px rgba(15,20,25,0.10); }
@media (prefers-reduced-motion: reduce) {
  .marquee { -webkit-mask-image: none; mask-image: none; }
  .marquee-track { animation: none; flex-wrap: wrap; justify-content: center; gap: 10px; }
  .marquee-set { flex-wrap: wrap; justify-content: center; gap: 10px; padding-right: 0; }
  .marquee-set + .marquee-set { display: none; }
}

/* ---------- platform accordion (Duna-style) ---------- */
.pf-top { display: flex; justify-content: space-between; align-items: flex-start; gap: var(--space-6); flex-wrap: wrap; margin-bottom: var(--space-12); }
.pf-top .sec-head { margin-bottom: 0; }
.pf-explore { border-radius: var(--radius-pill); flex: none; }

.pf { display: grid; grid-template-columns: 1fr 1.12fr; gap: var(--space-12); align-items: start; }
.pf-list { display: flex; flex-direction: column; gap: var(--space-1); }
.pf-item {
  width: 100%; text-align: left; cursor: pointer; font-family: var(--font-text);
  background: transparent; border: 1px solid transparent; border-radius: var(--radius-lg);
  padding: var(--space-4) var(--space-5);
  transition: background .3s cubic-bezier(.22,1,.36,1), border-color .3s ease, box-shadow .35s ease;
}
.pf-head { display: flex; align-items: center; gap: var(--space-3); }
.pf-ic { width: 20px; height: 20px; flex: none; color: var(--text-subtle); transition: color .3s ease, transform .5s cubic-bezier(.22,1,.36,1); }
.pf-t { font-size: 16px; font-weight: 600; color: var(--text-strong); transition: color .25s ease; }
/* Content-accurate collapse for the painful-scenario copy: animate
   grid-template-rows 0fr → 1fr so it eases to the real text height — no
   max-height guessing, no early-finish snap. */
.pf-d {
  display: grid; grid-template-rows: 0fr;
  opacity: 0; visibility: hidden; padding-left: 32px;
  transition: grid-template-rows .5s cubic-bezier(.22,1,.36,1),
              opacity .32s cubic-bezier(.22,1,.36,1),
              padding-top .5s cubic-bezier(.22,1,.36,1),
              visibility 0s linear .5s;
}
.pf-d-in {
  min-height: 0; overflow: hidden;
  font-size: 14px; color: var(--text-muted); line-height: 1.55;
}
/* The active module's "what it does" lifts into the section's lead
   paragraph (#pfWhat) and crossfades on each tab click; the drawers keep
   only the painful-scenario text. */
.pf-what-display {
  /* Reserve the tallest module's height (~84px / 3 lines at the 660px lead
     width) so swapping copy never reflows the section below. */
  min-height: 84px;
  transition: opacity .22s ease, transform .22s cubic-bezier(.22,1,.36,1);
  will-change: opacity, transform;
}
.pf-what-display.swapping { opacity: 0; transform: translateY(8px); }
.pf-item:not(.active):hover { background: var(--neutral-100); }
.pf-item:not(.active):hover .pf-t { color: var(--accent); }
.pf-item:not(.active):hover .pf-ic { color: var(--text-muted); }
.pf-item.active {
  /* Sober, clear selected state: a plain card lifted with a soft shadow.
     The accent icon (below) is the only colour cue. */
  background: var(--surface); border-color: var(--border);
  box-shadow: 0 1px 2px rgba(15,20,25,0.04), 0 14px 30px -22px rgba(15,20,25,0.22);
}
.pf-item.active .pf-ic { color: var(--accent); transform: scale(1.1); }
.pf-item.active .pf-d {
  grid-template-rows: 1fr; opacity: 1; visibility: visible; padding-top: 10px;
  /* One gesture: height, fade and padding share the exact duration + easing
     and start together — no opacity delay, so the drawer opens as a single
     smooth motion instead of a staggered box-then-text reveal. */
  transition: grid-template-rows .5s cubic-bezier(.22,1,.36,1),
              opacity .5s cubic-bezier(.22,1,.36,1),
              padding-top .5s cubic-bezier(.22,1,.36,1),
              visibility 0s;
}

/* Right-hand visual — the GitBook stage (founder spec 2026-07-24):
   a rounded box a whisper off the paper (the band-emboss tone), a
   slice of the Klavius rings entering from the right, the product
   window pushed low-right with a dashed indigo guide running off the
   corner, glass chrome on the window bar. This is the SHARED template
   for every Platform sub-section — panels swap inside it. */
.pf-visual {
  position: relative; border-radius: 24px; overflow: hidden;
  background: #F5F4F0;
  padding: var(--space-8); min-height: 460px;
}
/* the ribbon holds the TOP-RIGHT CORNER, crossing the card's top and
   right edges with its own curves — no cut edge ever shows inside the
   stage (founder caught the sliced-image read on v1). The asset is the
   2026-07-24 Higgsfield knot, chroma-keyed with alpha and cropped to
   the used region; geometry locked on an offline composite mock. */
.pf-ribbon {
  position: absolute; top: -173px; right: -98px;
  width: 460px; height: 367px; pointer-events: none;
  background-image: image-set(
    url("brand/ribbon-pf-1x.webp") 1x,
    url("brand/ribbon-pf.webp") 2x
  );
  background-size: 100% 100%; background-repeat: no-repeat;
}
/* The window itself is STATIC (founder 2026-08-05: "enlève le pop up des
   navigateurs, garde-les statiques, le contenu garde son animation").
   It used to fade + rise 14px on every tab switch, which read as the
   whole browser popping in each time. All four panels share the same
   geometry, so swapping them in one frame leaves the window visually
   fixed and only its CONTENT changes — the row cascade, the bars and
   the timeline still replay (that motion is driven by .replay-prep in
   landing.js, which is independent of this transition). */
.pf-panel {
  position: absolute; left: var(--space-8); right: var(--space-8); bottom: 0;
  opacity: 0; pointer-events: none;
}
.pf-panel.active { opacity: 1; pointer-events: auto; }
/* dashed guide ALIGNED to the window (founder caught the drift): a
   constant 18px offset around the glass, rounded top-left, running off
   the stage bottom-right — it travels with each panel's crossfade. */
.pf-panel::before {
  content: ""; position: absolute;
  top: -18px; left: calc(10% - 18px); right: -70px; bottom: -70px;
  border: 1.6px dashed color-mix(in srgb, var(--accent) 55%, transparent);
  border-radius: 18px; pointer-events: none;
}
/* the window: off-axis low-right, bottom edge clipped by the stage.
   The WHOLE window is frosted glass (GitBook) — a translucent paper
   surface + backdrop blur, so the violet ribbon behind glows softly
   through its edges. Content painted ON the glass stays crisp (backdrop
   only blurs what's behind); the inset top highlight is the glass
   edge-light. */
.pf-panel .win {
  width: 90%; margin-left: auto; margin-bottom: -14px;
  /* Uniform height across ALL four modules (founder: every window must
     sit exactly where the CRA one does — 415px was its natural height;
     bottom-anchored, so equal heights = equal tops). Flex column lets
     the body's paper backing fill the glass down to the clipped edge
     when a module's content is shorter. */
  height: 415px; overflow: hidden;
  display: flex; flex-direction: column;
  background: color-mix(in srgb, var(--paper) 66%, transparent);
  backdrop-filter: saturate(150%) blur(22px);
  -webkit-backdrop-filter: saturate(150%) blur(22px);
  border-color: color-mix(in srgb, #fff 60%, transparent);
  box-shadow:
    0 24px 48px -28px rgba(15,20,25,0.28),
    inset 0 1px 0 rgba(255,255,255,0.5);
}
/* the bar reads as a distinct strip via a slightly heavier paper tint —
   no separate blur needed, the window glass already carries it */
.pf-panel .win .bar {
  background: color-mix(in srgb, var(--paper) 42%, transparent);
  border-bottom-color: color-mix(in srgb, var(--border) 60%, transparent);
}
/* content floats on the glass with a faint paper backing so dense text
   keeps contrast where a hint of ribbon glows through — the bar + the
   window edges/corner carry the strongest glass-on-ribbon reaction */
.pf-panel .win .body {
  position: relative; flex: 1;
  background: color-mix(in srgb, var(--paper) 82%, transparent);
}
@media (prefers-reduced-motion: reduce) {
  /* .pf-panel dropped from this list — it no longer carries a transition
     to neutralise (the window is static since 2026-08-05). */
  .pf-item .pf-d { transition: none; }
}

/* ---------- AI band (how Klavius works) ---------- */
.ai-steps { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-5); margin-top: var(--space-12); }
.ai-step {
  position: relative; overflow: hidden;
  border: 1px solid var(--border); border-radius: var(--radius-lg);
  background: var(--surface); padding: 12px 12px var(--space-6);
}
/* One transition list (specific enough to win over .reveal) so the
   scroll-reveal AND the hover both animate. */
.ai-steps .ai-step {
  transition: opacity .6s ease, transform .45s cubic-bezier(.22,1,.36,1),
              border-color .3s ease, box-shadow .3s ease;
}
.ai-step > .num, .ai-step > h4, .ai-step > p { position: relative; z-index: 1; padding: 0 10px; }
.ai-step .num { font-family: var(--font-mono); font-size: 24px; color: var(--accent); letter-spacing: 0.02em; margin-top: var(--space-5); }
.ai-step h4 { font-family: var(--font-text); font-size: 16px; font-weight: 600; color: var(--text-strong); margin: var(--space-3) 0 var(--space-2); }
.ai-step p { font-size: 14px; color: var(--text-muted); line-height: 1.55; }
/* The visual window: one ribbon knot traversing the three cards (three
   crops of the same image, same aspect on every card = the tube lines
   up across the gaps, GitBook's blog-card ribbon). The frosted tile
   floats on it, blurring the ribbon behind. */
.ai-visual {
  position: relative; overflow: hidden;
  border-radius: 10px; aspect-ratio: 798 / 465;
  background-size: cover; background-position: center;
  background-color: #F5F4F0;
}
.av-1 { background-image: image-set(url("brand/ribbon-how-1-1x.webp") 1x, url("brand/ribbon-how-1.webp") 2x); }
.av-2 { background-image: image-set(url("brand/ribbon-how-2-1x.webp") 1x, url("brand/ribbon-how-2.webp") 2x); }
.av-3 { background-image: image-set(url("brand/ribbon-how-3-1x.webp") 1x, url("brand/ribbon-how-3.webp") 2x); }
.ai-tile {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: 52px; height: 52px; border-radius: 14px;
  display: grid; place-items: center; color: var(--accent);
  background: color-mix(in srgb, var(--paper) 55%, transparent);
  backdrop-filter: saturate(140%) blur(10px);
  -webkit-backdrop-filter: saturate(140%) blur(10px);
  border: 1px solid rgba(255,255,255,0.78);
  box-shadow: 0 10px 24px -14px rgba(15,20,25,0.35), inset 0 1px 0 rgba(255,255,255,0.6);
}
.ai-tile svg { width: 24px; height: 24px; }
.ai-steps .ai-step:hover {
  transform: translateY(-4px);
  border-color: color-mix(in srgb, var(--accent) 30%, var(--border));
  box-shadow: 0 16px 34px -22px rgba(15,20,25,0.30);
}
@media (prefers-reduced-motion: reduce) {
  .ai-steps .ai-step { transition: none; }
  .ai-steps .ai-step:hover { transform: none; }
}

/* ---------- metrics band (carved K, GitBook grammar) ---------- */
/* Founder direction 2026-07-23: the band tone stays a WHISPER from the
   site paper (no hard flow break), the monogram sits LEFT of the
   content, and the carve is vector (SVG inner-edge filter) — after two
   image-render rounds read as "trop image réaliste": a photo of paper
   can't sit on flat paper, a carve can. */
.band-emboss { background-color: #F5F4F0; }
.emboss-grid {
  display: grid; grid-template-columns: 210px minmax(0, 1fr);
  gap: var(--space-12); align-items: center;
}
.carve-k { width: 100%; height: auto; }
@media (max-width: 960px) {
  .emboss-grid { grid-template-columns: 1fr; }
  .carve-k { display: none; }
}
.band-ink { background: var(--ink); color: var(--on-ink); border-top: none; }
.band-ink h2, .band-ink h3, .band-ink h4 { color: var(--on-ink); }
.metrics-head { max-width: 720px; margin-bottom: var(--space-12); }
.metrics-head h2 { font-size: 36px; letter-spacing: -0.02em; line-height: 1.08; }
.metrics { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-8); }
/* Big numbers in the ACCENT on paper — the GitBook stat band grammar
   (was white-on-ink; the site's one dark band is now the closing CTA). */
.metric .m-v { font-family: var(--font-display); font-size: 58px; line-height: 1; color: var(--accent); letter-spacing: -0.03em; }
.metric .m-l { font-size: 13.5px; color: var(--text-muted); margin-top: var(--space-4); line-height: 1.4; }
.metric .m-v .unit { font-size: 30px; color: var(--accent); }

/* ---------- security grid ---------- */
/* Sober Duna layout — columns split by hairlines, no bordered boxes. */
.trust-row { display: grid; grid-template-columns: repeat(3, 1fr); margin-top: var(--space-12); }
.trust-col { padding: var(--space-1) var(--space-10); border-left: 1px solid var(--border); }
.trust-col:first-child { padding-left: 0; border-left: none; }
.trust-col:last-child { padding-right: 0; }
.trust-col .ic { color: var(--accent); margin-bottom: var(--space-4); }
.trust-col .ic svg { width: 26px; height: 26px; }
.trust-col h4 { font-family: var(--font-text); font-size: 16px; font-weight: 600; color: var(--text-strong); margin-bottom: var(--space-2); }
.trust-col p { font-size: 14px; color: var(--text-muted); line-height: 1.6; }

/* ---------- closing CTA (ink) ---------- */
.cta-final { text-align: center; }
.cta-final h2 { font-size: 40px; letter-spacing: -0.02em; max-width: 18ch; margin: 0 auto var(--space-5); }
.cta-final p { font-size: 18px; color: var(--on-ink-muted); max-width: 54ch; margin: 0 auto var(--space-8); line-height: 1.55; }
.cta-final .cta-row { display: inline-flex; flex-wrap: wrap; gap: var(--space-3); justify-content: center; }

/* ---------- footer ---------- */
.foot { background: var(--ink); color: var(--on-ink); padding: var(--space-16) 0 var(--space-12); }
.foot-top { display: grid; grid-template-columns: 1.4fr 1fr 1fr 1fr; gap: var(--space-8); }
.foot .brand-lockup .wm { color: #fff; }
.foot .tagline { font-size: 13.5px; color: var(--on-ink-muted); max-width: 38ch; line-height: 1.6; margin-top: var(--space-4); }
.foot-social { display: inline-flex; margin-top: var(--space-4); color: var(--on-ink-muted); transition: color .2s ease; }
.foot-social:hover { color: #fff; }
.foot-col h5 { font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--on-ink-subtle); margin-bottom: var(--space-4); font-weight: 500; }
.foot-col a { display: block; font-size: 14px; color: var(--on-ink-muted); padding: 5px 0; }
.foot-col a:hover { color: #fff; }
.foot-bottom { display: flex; justify-content: space-between; align-items: center; gap: var(--space-4); flex-wrap: wrap; margin-top: var(--space-16); padding-top: var(--space-6); border-top: 1px solid var(--on-ink-line); }
.foot-bottom .small { font-size: 12.5px; color: var(--on-ink-subtle); }
.foot-bottom .small a { color: var(--on-ink-muted); }

/* ============================================================
   Motion — scroll reveals (Duna-style)
   ============================================================ */
.reveal { opacity: 0; transform: translateY(14px); transition: opacity .6s cubic-bezier(.2,.7,.2,1), transform .6s cubic-bezier(.2,.7,.2,1); }
.reveal.in { opacity: 1; transform: none; }
.reveal.d1 { transition-delay: .06s; }
.reveal.d2 { transition-delay: .12s; }

/* hero line-mask reveal */
/* padding-bottom + matching negative margin gives the resting glyph
   descenders (the p/y in "powered by", commas, the period) room below the
   tight 1.04 line-height so overflow:hidden doesn't clip them — layout
   between lines stays net-zero. translateY bumped past 100%+padding so the
   line is still fully masked while it slides in. */
.r-lines .ln { display: block; overflow: hidden; padding-bottom: .26em; margin-bottom: -.26em; }
.r-lines .ln > span { display: block; transform: translateY(128%); transition: transform .7s cubic-bezier(.16,.84,.3,1); transition-delay: calc(var(--i) * 90ms); }
.r-lines.in .ln > span { transform: translateY(0); }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .reveal, .r-lines .ln > span { opacity: 1 !important; transform: none !important; transition: none !important; }
}

/* ============================================================
   Responsive
   ============================================================ */
@media (max-width: 960px) {
  .hero h1 { font-size: 46px; max-width: 18ch; }
  /* Tablet topbar: brand + 5 links + 2 actions overflowed the viewport
     (pre-existing) — tighten gaps/padding so everything fits to 700px. */
  .topbar-inner { gap: var(--space-3); padding-left: var(--space-5); padding-right: var(--space-5); }
  .navlink { padding: 7px 8px; font-size: 13.5px; }
  .nav-actions { gap: var(--space-2); }
  .nav-actions .btn { padding: 9px 12px; font-size: 13.5px; }
  /* This band has no slack — brand + 5 links + 2 actions already fill it
     exactly at 700px, and the switcher at its desktop size pushed the bar
     4px over. It sheds the fence, tightens padding and steps down a half
     point so it costs ~44px instead of ~73px. Re-measure .topbar-inner
     scrollWidth at 700px before adding anything else to this bar. */
  .nav-lang { padding-right: 0; border-right: none; }
  .nav-lang a { padding: 3px 4px; font-size: 11px; letter-spacing: 0.06em; }
  .nav-lang a + a::before { height: 9px; }
}

/* The bottom of the tablet band (681–820px) fitted the old bar EXACTLY —
   zero slack — so the switcher had nowhere to go and pushed it 18px over.
   The four nav links give up 3px of side padding each (~24px), which is
   invisible at this size and is the same lever the 960px block already
   pulls. Below 681px .nav-links is hidden and the overlay's own, higher
   specificity padding takes over, so this rule is inert there. */
@media (max-width: 820px) {
  .navlink { padding: 7px 5px; }
  .metrics { grid-template-columns: repeat(2, 1fr); gap: var(--space-10) var(--space-8); }
  .ai-steps { grid-template-columns: 1fr; }
  .trust-row { grid-template-columns: 1fr; }
  .trust-col { border-left: none; border-top: 1px solid var(--border); padding: var(--space-6) 0; }
  .trust-col:first-child { border-top: none; padding-top: 0; }
  .foot-top { grid-template-columns: 1fr 1fr; gap: var(--space-10); }
  /* The Platform — the desktop 2-col accordion is replaced wholesale by the
     swipeable card carousel (built by JS, styled in the 2026-07-05 mobile
     structure pass at the end of this file). */
  .pf { display: none; }
  .pf-what-display { display: none; }

  /* How it works — the three stacked full-size cards become a vertical
     numbered timeline (Viator pattern): accent node + connecting hairline
     on a left rail, content to the right. Same copy, ~35% shorter, and the
     "sequence" the desktop horizontal line carried is back. */
  .ai-steps { gap: 0; margin-top: var(--space-8); }
  .ai-step {
    border: none; background: none; border-radius: 0; overflow: visible;
    padding: var(--space-4) 0 var(--space-4) var(--space-8);
  }
  /* the ribbon visuals are a desktop composition (the traversal needs
     the three cards side by side) — the timeline stays text-first */
  .ai-visual { display: none; }
  .ai-step .num { margin-top: 0; }
  .ai-step > .num, .ai-step > h4, .ai-step > p { padding: 0; }
  .ai-steps .ai-step:hover { transform: none; box-shadow: none; border-color: transparent; }
  .ai-step::before {
    content: ""; position: absolute; left: 5px; top: 0; bottom: 0;
    width: 1px; background: var(--border-strong);
  }
  .ai-step::after {
    content: ""; position: absolute; left: 0; top: calc(var(--space-4) + 5px);
    width: 11px; height: 11px; border-radius: 999px;
    background: var(--surface); border: 2px solid var(--accent);
  }
  .ai-step:first-child::before { top: calc(var(--space-4) + 5px); }
  .ai-step:last-child::before { bottom: auto; height: calc(var(--space-4) + 5px); }
}

@media (max-width: 680px) {
  /* ---- Mobile density pass (2026-07-05) ----
     Direction: the desktop page *shrunk with intent*, not desktop blocks
     stacked at full size. Type steps down ~15%, vertical rhythm ~25%,
     and elaboration copy yields so the hero demo lands near the fold —
     the Linear/Vanta mobile playbook for hero-demo landings. */
  .shell { padding: 0 var(--space-5); }
  section.band { padding: var(--space-12) 0; }
  .topbar-inner { padding: var(--space-3) var(--space-5); gap: var(--space-3); }
  /* nav collapse + overlay now live in their own blocks below — see the
     "nav collapse" comment, which explains why FR collapses earlier. */

  /* Hero: tighter headline, 3-line lead (the elaboration sentence is
     desktop depth — the undernote already carries the Luxembourg line),
     both CTAs on ONE row, demo visible without scrolling a full screen. */
  .hero { padding: var(--space-10) 0 var(--space-12); }
}

/* FR reaches for the tightened bar earlier than EN, because the full-size FR
   bar needs ~1030px and overflowed a 1024px laptop by 6px; EN's equivalent
   tightening only starts at 960. Same declarations as the 960px block.

   Threshold is 1080px, measured not guessed: with « Fonctionnement » and
   « Connexion » the full-size FR bar needs ~1073px once the globe mark is in
   the switcher, so full EN typography survives from 1081px up. Deliberately
   not much higher — an earlier 1100px value shrank the type across a band
   where FR fitted fine, and the bar read visibly smaller than its EN twin at
   the same width. Only tighten where the space actually runs out.
   Re-measure this number if anything is added to the bar. */
@media (max-width: 1080px) {
  html[lang="fr"] .topbar-inner { gap: var(--space-3); padding-left: var(--space-5); padding-right: var(--space-5); }
  html[lang="fr"] .navlink { padding: 7px 8px; font-size: 13.5px; }
  html[lang="fr"] .nav-actions { gap: var(--space-2); }
  html[lang="fr"] .nav-actions .btn { padding: 9px 12px; font-size: 13.5px; }
}

/* ---------- nav collapse + full-screen overlay ----------
   EN collapses to the hamburger at 680px. FR cannot use the same number:
   its bar carries ~270px more text than EN — longer labels AND much longer
   actions (« Réserver une démo », « Se connecter ») — and the 681–960 band
   was fitted to English with zero slack, so the FR bar overflowed it by
   70px. FR therefore collapses at 960px.

   The presentation rules below are shared and stay inert until .open is
   set, and .open is only ever set by clicking the toggle — which stays
   hidden for EN above 680px. So EN's 681–960 behaviour is unchanged. */
@media (max-width: 960px) {
  /* --- collapse triggers, language-gated ---
     :not(.open) is load-bearing. `html[lang="fr"] .nav-links` scores
     (0,2,1) and would outrank the `.nav-links.open` (0,2,0) overlay rule,
     so the sheet would stay display:none when the toggle was tapped. */
  html[lang="fr"] .nav-links:not(.open) { display: none; }
  html[lang="fr"] .nav-toggle { display: inline-flex; }
  html[lang="fr"] .nav-actions .btn-ghost { display: none; }
  html[lang="fr"] .nav-actions .nav-lang { display: none; }
  html[lang="fr"] .nav-actions .btn-ink { padding: 8px 13px; font-size: 13px; }

  /* --- shared overlay presentation --- */
  .nav-links.open .nav-lang-m {
    display: flex; align-items: center;
    padding: var(--space-2) 0; border-top: 1px solid var(--border);
  }
  /* 15px vertical padding on 14px text = 44px tap target */
  .nav-links.open .nav-lang-m a { font-size: 14px; padding: 15px 14px; }
  .nav-links.open .nav-lang-m a:first-child { margin-left: -14px; }
  /* text steps up to 14px here, so the mark keeps the same ~1.8x proportion */
  .nav-links.open .nav-lang-m .globe { width: 19px; height: 19px; margin-right: 9px; }
  /* Full-screen overlay menu (Calm-style): large Fraunces links stacked on
     ruled lines, the two actions anchored at the bottom. JS sets --tb-h to
     the live topbar height and locks body scroll via .nav-open. */
  .nav-links.open {
    display: flex; flex-direction: column; align-items: stretch;
    /* The topbar carries backdrop-filter, which makes IT the containing
       block for position:fixed descendants — so `bottom: 0` stops at the
       bar's own bottom (~88px) and the sheet collapses. Size the height in
       viewport units instead of relying on bottom reaching the viewport. */
    position: fixed; left: 0; right: 0; top: var(--tb-h, 59px);
    height: calc(100vh - var(--tb-h, 59px));
    height: calc(100dvh - var(--tb-h, 59px));
    z-index: 49; overflow-y: auto;
    background: var(--paper); border-top: 1px solid var(--border);
    padding: var(--space-2) var(--space-5) calc(var(--space-5) + env(safe-area-inset-bottom, 0px));
  }
  .nav-links.open .navlink {
    font-family: var(--font-display); font-size: 26px; font-weight: 500;
    color: var(--text-strong); letter-spacing: -0.01em;
    padding: var(--space-4) 0; border-radius: 0;
    border-top: 1px solid var(--border);
  }
  .nav-links.open .navlink:hover { background: none; color: var(--accent); }
  /* overlay: the pill chrome and the dropdown flatten back into the list —
     the four module links render as plain Fraunces rows again. */
  .nav-links.open { border: none; border-radius: 0; }
  .nav-links.open .nav-group { display: contents; }
  .nav-links.open .nav-drop-btn { display: none; }
  .nav-links.open .nav-drop {
    position: static; display: block; min-width: 0; padding: 0;
    background: none; border: none; box-shadow: none;
    opacity: 1; visibility: visible; pointer-events: auto; transform: none;
    transition: none;
  }
  .nav-links.open .drop-item {
    display: block; padding: var(--space-4) 0; border-radius: 0;
    border-top: 1px solid var(--border);
    opacity: 1; transform: none; transition: none;
  }
  .nav-links.open .drop-item:first-child { border-top: none; }
  .nav-links.open .drop-item:hover { background: none; }
  .nav-links.open .drop-tag, .nav-links.open .drop-txt small { display: none; }
  .nav-links.open .drop-txt strong {
    font-family: var(--font-display); font-size: 26px; font-weight: 500;
    color: var(--text-strong); letter-spacing: -0.01em; line-height: 1.4;
  }
  .nav-links.open .drop-item:hover .drop-txt strong { color: var(--accent); }
  .nav-links.open .nav-mobile-cta {
    display: flex; flex-direction: column; gap: var(--space-3);
    margin-top: auto; padding-top: var(--space-6);
  }
  .nav-mobile-cta .btn { justify-content: center; padding: 13px; font-size: 15px; }
}

/* EN collapses at 760px, not 680. It only ever "fitted" 681–740 because
   "How it works" silently wrapped onto two lines and knocked the bar out of
   alignment; once .navlink stopped wrapping, the true requirement showed up
   as 41px of overflow at 681px. The unwrapped EN bar needs ~741px with the
   globe mark in the switcher, so it folds into the hamburger at 760 — 740
   left literally zero slack, which one differently-rendered font would have
   tipped over. The overlay presentation lives in the 960px block above and
   is shared. */
@media (max-width: 760px) {
  /* Compact mobile bar: brand · Book-a-demo · menu. Sign-in lives in
     the footer + closing CTA, so it's dropped here to avoid overflow. */
  .nav-actions .btn-ghost { display: none; }
  .nav-actions .btn-ink { padding: 8px 13px; font-size: 13px; }
  /* the switcher leaves the bar and becomes the overlay's last ruled row,
     just above the two anchored CTAs */
  .nav-actions .nav-lang { display: none; }
  .nav-links:not(.open) { display: none; }
  .nav-toggle { display: inline-flex; }
}

@media (max-width: 680px) {
  .hero h1 { font-size: 33px; letter-spacing: -0.02em; }
  .hero .lead { font-size: 15.5px; line-height: 1.55; }
  .lead-more { display: none; }
  .hero .cta-row { gap: var(--space-2); margin-top: var(--space-6); flex-wrap: nowrap; }
  .hero .cta-row .btn, .cta-final .cta-row .btn {
    flex: 1; justify-content: center;
    padding: 11px 10px; font-size: 13.5px; white-space: nowrap;
  }
  .undernote { font-size: 11.5px; }

  .hero-figure { margin-top: var(--space-10); }

  /* Undernote: as flex, the wrapped 2-line text sat left-aligned with the
     LED floating mid-height — flow it as centered inline text with the dot
     riding the first line instead. */
  .hero .undernote { display: block; text-align: center; }
  .hero .undernote .led { display: inline-block; margin-right: 7px; vertical-align: 2px; }

  .sec-head h2 { font-size: 23px; }
  .sec-head p { font-size: 14.5px; }
  .stat-grid { grid-template-columns: 1fr 1fr; }

  /* Trust — icon inlines left of the heading (one row) instead of
     stacking above it; same copy, ~25% shorter rows. */
  .trust-col {
    display: grid; grid-template-columns: auto 1fr; column-gap: var(--space-3);
    align-items: center; padding: var(--space-5) 0;
  }
  .trust-col .ic { margin-bottom: 0; }
  .trust-col .ic svg { width: 22px; height: 22px; }
  .trust-col h4 { margin-bottom: 0; }
  .trust-col p { grid-column: 2; margin-top: var(--space-1); font-size: 13.5px; }

  /* Metrics: three ruled rows (value · label) instead of a 2+1 orphan
     grid — denser and more editorial, same numbers. */
  .metrics { grid-template-columns: 1fr; gap: 0; }
  .metric {
    display: grid; grid-template-columns: auto 1fr;
    align-items: baseline; gap: var(--space-5);
    padding: var(--space-4) 0;
    border-top: 1px solid var(--border);
  }
  .metric:first-child { border-top: none; padding-top: 0; }
  .metric .m-v { font-size: 34px; }
  .metric .m-v .unit { font-size: 19px; }
  .metric .m-l { margin-top: 0; text-align: right; font-size: 12.5px; }
  .metrics-head { margin-bottom: var(--space-8); }
  .metrics-head h2 { font-size: 23px; }

  .cta-final h2 { font-size: 26px; }
  .cta-final p { font-size: 15px; }
  /* Footer — brand full-width, then the three short link columns in a
     compact 2-col grid instead of a 800px single-file stack. */
  .foot-top { grid-template-columns: 1fr 1fr; gap: var(--space-8) var(--space-6); }
  .foot-top > div:first-child { grid-column: 1 / -1; }
}

/* ---------- 2026-07-04 motion & structure pass ---------- */

/* Accordion auto-tour progress — a hairline filling along the active
   item's bottom edge. JS drives scaleX; a click restarts the dwell on the
   chosen item, hovering the demo visual holds it. */
.pf-item { position: relative; overflow: hidden; }
.pf-progress {
  position: absolute; left: 0; right: 0; bottom: 0; height: 2px;
  background: var(--accent); opacity: 0;
  transform: scaleX(0); transform-origin: left;
  pointer-events: none;
  /* The dwell timer nudges scaleX every 50ms; a short transform transition
     smooths those steps into continuous motion, so when hover eases the
     speed toward 0 the bar visibly decelerates instead of stepping.
     (JS clears this inline while resetting a bar to 0 — no rewind sweep.) */
  transition: transform 90ms linear, opacity .3s ease;
}
.pf-item.active .pf-progress { opacity: .55; }
@media (prefers-reduced-motion: reduce) { .pf-progress { display: none; } }
/* ≤960 the accordion is a static fully-open list (no visual, no tour) —
   an animated dwell bar under plain text would be noise. */
@media (max-width: 960px) { .pf-progress { display: none; } }

/* Hero slideshow nav — dots + the live product URL, one quiet row.
   Grid (1fr auto 1fr) pins the dots to the exact center: the caption's
   width varies per screen and must never push the dots around. */
.hero-nav {
  display: grid; grid-template-columns: 1fr auto 1fr;
  align-items: center; column-gap: 14px;
  margin-top: 14px;
}
.hero-dots { grid-column: 2; display: flex; align-items: center; gap: 8px; }
.hero-dot {
  width: 7px; height: 7px; border-radius: 999px; padding: 0;
  border: none; cursor: pointer;
  background: var(--border);
  /* The active dot STRETCHES into a pill (width animates) instead of a
     scale bump — paired with the live scroll sync, each swipe reads as an
     immediate, satisfying hop from one pill to the next. */
  transition: background .3s ease, width .35s cubic-bezier(.22,1,.36,1);
}
.hero-dot:hover { background: var(--text-subtle); }
.hero-dot.is-active { background: var(--accent); width: 20px; }
.hero-addr {
  grid-column: 3; justify-self: start;
  font-family: var(--font-mono); font-size: 11.5px;
  color: var(--text-subtle); letter-spacing: .01em;
  /* Frosted chip (GitBook micro-detail) — the caption now sits over the
     rings' lower loops, so it earns a glass surface to stay legible. */
  background: color-mix(in srgb, var(--paper) 55%, transparent);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  padding: 5px 11px; border-radius: var(--radius-pill);
  border: 1px solid color-mix(in srgb, var(--border) 65%, transparent);
}
@media (max-width: 680px) { .hero-addr { display: none; } }

/* (2026-07-24: the old How-it-works hairline connector is gone — the
   ribbon traversing the three card visuals now carries the sequence.) */
.ai-steps { position: relative; }

/* Team — Kalipso-style founder cards (replaces the Why Klavius
   editorial columns, 2026-07-20): rectangular portrait, bold name,
   mono role, one credential bio. Placeholders share the exact frame
   so real portraits are a drop-in swap at founders/*.jpg. Hover =
   the site's card language (border + title accent + a quiet photo
   zoom), no shadows. */
.founder-grid {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-5);
}
/* Two-up (2026-08-03): a card is temporarily out of the row. The pair keeps
   the EXACT width a three-up card had — derived from the same formula, not a
   hard-coded px, so it still matches if the shell or the gap ever moves — and
   centres. Letting two cards stretch to half the shell would read as a
   different design rather than the same one with a card away, and it would
   blow the square portraits up by half. */
.founder-grid.is-duo {
  grid-template-columns: repeat(2, calc((100% - 2 * var(--space-5)) / 3));
  justify-content: center;
}
.founder-card {
  margin: 0; border: 1px solid var(--border); border-radius: var(--radius-lg);
  background: var(--surface); overflow: hidden;
  display: flex; flex-direction: column;
  transition: border-color .3s ease, transform .3s cubic-bezier(.2,.7,.2,1);
}
.founder-card:hover { border-color: var(--border-strong); transform: translateY(-3px); }
.founder-card:hover h4 { color: var(--accent-active); }
.founder-photo { aspect-ratio: 1 / 1; background: var(--surface-sunken); overflow: hidden; }
.founder-photo img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  /* Top-anchored crop: portrait-ratio photos (Justin 3:4) keep the
     head in the square frame; a no-op for square portraits. */
  object-position: top center;
  transition: transform .5s cubic-bezier(.2,.7,.2,1);
}
.founder-card:hover .founder-photo img { transform: scale(1.03); }
.founder-photo.placeholder { display: flex; align-items: center; justify-content: center; }
.founder-photo.placeholder span {
  font-family: var(--font-display); font-weight: 500; font-size: 56px;
  color: var(--text-subtle); letter-spacing: 0.02em;
}
.founder-card figcaption {
  padding: var(--space-5) var(--space-6) var(--space-6);
  display: flex; flex-direction: column; gap: var(--space-2);
}
.founder-card h4 { font-size: 21px; margin: 0; transition: color .25s ease; }
.founder-role {
  font-family: var(--font-mono); font-size: 11px; font-weight: 500;
  letter-spacing: 0.07em; text-transform: uppercase; color: var(--accent);
}
.founder-card figcaption p { margin: var(--space-1) 0 0; font-size: 14px; color: var(--text-muted); line-height: 1.55; }
/* Kalipso signature: a quiet LinkedIn link closing each card. */
.founder-li {
  margin-top: var(--space-3); align-self: flex-start;
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 13px; font-weight: 500; color: var(--accent);
  text-decoration: none; transition: color .25s ease;
}
.founder-li:hover { color: var(--accent-active); text-decoration: underline; text-underline-offset: 3px; }
@media (max-width: 960px) {
  /* .is-duo repeated so the compound selector's specificity doesn't keep the
     two-column desktop track alive on phones. */
  .founder-grid, .founder-grid.is-duo { grid-template-columns: 1fr; max-width: 420px; }
  .founder-photo { aspect-ratio: 4 / 3; }
  .founder-photo img { object-position: top center; }
  .founder-card:hover { transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .founder-card, .founder-photo img, .founder-card h4 { transition: none; }
  .founder-card:hover { transform: none; }
  .founder-card:hover .founder-photo img { transform: none; }
}

/* Closing band — the quiet second exit under the demo CTA. Block-level so
   it never shares a line with the button, with clear air above. */
.cta-sub {
  /* width:max-content sizes to the full unwrapped string and ignores the
     container, so a long line ran 31px past a 375px phone (FR hit it
     first, but EN was one longer word away from the same bug). Cap it and
     let it wrap centred. */
  display: flex; width: max-content; max-width: 100%;
  flex-wrap: wrap; justify-content: center;
  align-items: center; gap: 6px;
  margin: var(--space-8) auto 0;
  font-size: 13.5px; color: var(--on-ink-muted); text-decoration: none;
  transition: color .25s ease;
}
.cta-sub:hover { color: var(--on-ink); }
.cta-sub .arr { transition: transform .3s ease; display: inline-block; }
.cta-sub:hover .arr { transform: translateX(3px); }

/* ---------- 2026-07-05 mobile structure pass ---------- */

/* Platform mobile carousel (Mercury card pattern): one swipeable card per
   module — icon + name + "what it does" line + the SAME .win mock the
   desktop panel shows. The mocks are HTML/CSS, so unlike screenshots they
   stay legible at phone width. Built once by JS from the accordion markup;
   CSS reveals it only ≤960 where .pf is hidden. */
.pf-carousel, .pfc-dots { display: none; }
.nav-mobile-cta { display: none; }

@media (max-width: 960px) {
  .pf-carousel {
    position: relative; /* makes card offsetLeft carousel-relative for the dots */
    display: flex; gap: var(--space-3);
    overflow-x: auto; scroll-snap-type: x mandatory;
    margin: 0 calc(-1 * var(--space-8)); padding: 4px var(--space-8);
    scrollbar-width: none; -webkit-overflow-scrolling: touch;
  }
  .pf-carousel::-webkit-scrollbar { display: none; }
  .pfc-card {
    /* 80% + centre snap = the NEXT card's icon+name peek on the right
       (and the previous card's edge on the left once you're past the
       first) — the swipe affordance is the neighbour, not a hint. */
    flex: 0 0 80%; max-width: 430px; scroll-snap-align: center;
    border: 1px solid var(--border); border-radius: var(--radius-xl);
    background: var(--surface); padding: var(--space-5);
    box-shadow: 0 1px 2px rgba(15,20,25,0.04);
  }
  .pfc-card .pf-ic { color: var(--accent); }
  .pfc-what {
    font-size: 14px; color: var(--text-muted); line-height: 1.55;
    margin: var(--space-3) 0 var(--space-4);
  }
  .pfc-win { box-shadow: none; }
  /* The mocks made the cards a full viewport tall — clip them to one
     uniform height with a fade-out (the hero-shot treatment): enough to
     prove the module, short enough to keep the section moving. */
  .pfc-win { position: relative; max-height: 290px; overflow: hidden; }
  .pfc-win::after {
    content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 54px;
    background: linear-gradient(180deg, transparent, var(--surface));
    pointer-events: none;
  }
  /* compress the mock internals at card width — same content, app-density */
  .pfc-win .bar { height: 32px; }
  .pfc-win .body { padding: var(--space-4); }
  .pfc-card .wtable th { padding: 6px 8px; }
  .pfc-card .wtable td { padding: 7px 8px; font-size: 12px; }
  .pfc-card .ctrl-row { padding: 7px 0; }
  .pfc-card .ctrl-row .bar-track { width: 76px; }
  .pfc-card .stat-grid { grid-template-columns: repeat(3, 1fr); gap: 8px; }
  .pfc-card .stat { padding: 10px; }
  .pfc-card .stat .v { font-size: 20px; }
  .pfc-card .clock { padding: 7px 9px; min-width: 78px; }
  .pfc-card .clock .c-t { font-size: 15px; }
  .pfc-card .tl-item { padding-bottom: var(--space-4); }
  .pfc-dots { display: flex; justify-content: center; gap: 8px; margin-top: var(--space-5); }
  .pfc-dot {
    width: 7px; height: 7px; border-radius: 999px; padding: 0;
    border: none; cursor: pointer; background: var(--border-strong);
    /* same stretch-to-pill as the hero dots — one pagination language */
    transition: background .3s ease, width .35s cubic-bezier(.22,1,.36,1);
  }
  .pfc-dot.is-active { background: var(--accent); width: 20px; }
}
@media (max-width: 680px) {
  .pf-carousel { margin: 0 calc(-1 * var(--space-5)); padding: 4px var(--space-5); }

  /* Reveals on a phone: VISIBLE as-you-scroll appearances (founder call) —
     the observer now fires as elements enter the viewport (landing.js), so
     give the motion enough travel and time to read as an entrance, with a
     gentle cascade on the delayed siblings. The 3.5s load failsafe keeps
     captures/prerenders void-free. */
  .reveal { transform: translateY(14px); transition-duration: .55s, .55s; }
  .reveal.d1 { transition-delay: .1s; }
  .reveal.d2 { transition-delay: .2s; }

  /* Rhythm: the hero→marquee seam measured 96px against the page's 48px
     beat — tighten the marquee band so the seam sits back in rhythm. */
  .marquee-band { padding: var(--space-8) 0 var(--space-10); }
}

/* ---------- 2026-07-08 ADN pass: reveal hierarchy · problem band · Ask-Klavius replay ---------- */

/* Reveal hierarchy — section-lead blocks travel further and sharpen
   from a slight blur (the Algora premium cue, kept flat); body reveals
   keep the quiet default. .in must out-specify the base to reset. */
.reveal.reveal-lg {
  transform: translateY(26px);
  filter: blur(6px);
  transition: opacity .7s cubic-bezier(.2,.7,.2,1),
              transform .7s cubic-bezier(.2,.7,.2,1),
              filter .6s ease;
}
.reveal.reveal-lg.in { transform: none; filter: blur(0); }
@media (max-width: 680px) {
  .reveal.reveal-lg { transform: translateY(16px); }
}
@media (prefers-reduced-motion: reduce) {
  .reveal.reveal-lg { filter: none !important; }
}

/* Problem band — the intro (pains + "Until Klavius.") sits BESIDE the
   hub (founder 2026-07-24: keep it side-by-side, and make it readable
   by COMPACTING the diagram — pills closer to the centre, shorter
   connectors — rather than shrinking the column). Grid weight favours
   the hub; the compact viewBox does the rest. */
.prob-grid {
  display: grid; grid-template-columns: minmax(360px, 5fr) minmax(0, 8fr);
  gap: 44px; align-items: center;
}
.prob-rows { display: flex; flex-direction: column; margin-top: var(--space-6); }
.prob-row {
  padding: 12px 0; border-top: 1px solid var(--border);
  font-size: 15px; color: var(--text-muted); line-height: 1.5;
}
.prob-row:last-child { border-bottom: 1px solid var(--border); }
.prob-until {
  margin-top: var(--space-6);
  font-family: var(--font-display); font-size: 22px; color: var(--accent);
}
@media (max-width: 960px) {
  .prob-grid { grid-template-columns: 1fr; gap: var(--space-10); }
}
@media (max-width: 680px) {
  .prob-row { font-size: 13.5px; padding: 10px 0; }
  .prob-until { font-size: 19px; }
}

/* The hub — the problem section's infographic (GitBook's agent-hub
   grammar, read off gitbook.com and repointed at the pains): six pain
   pills wired into the product window by marching dashed connectors,
   check badges pulsing in turn. ONE inline SVG + three keyframes, the
   exact mechanics they use (dash/border march = stroke-dashoffset one
   dash period on a linear infinite loop; badgePop = scale 1→1.14→1
   with staggered delays). transform-box: fill-box is what makes the
   badge scale about its own center — without it SVG scales about the
   viewBox origin and the badges fly. */
/* The hub sits in the SAME beige rounded box as the Platform stage
   (founder 2026-07-24) — one container language across both
   illustrations. Modest padding so the pills keep breathing room from
   the frame without shrinking the diagram much. */
.hub-demo {
  background: #F5F4F0; border-radius: 24px;
  padding: 22px 26px;
}
.hub { width: 100%; height: auto; display: block; }
/* Connectors — one calm, muted, slow dashed wire (was full-accent +
   the frame; both marched, competing). */
.hub-wire path {
  stroke: #9C95E4; stroke-width: 1.3;
  stroke-dasharray: 4 4;
  animation: hubDash 1s linear infinite;
}
/* The boundary the wires land on — the GitBook grammar the founder
   pointed at (2026-08-05): the paths converge on a frame that ENCLOSES
   the record, so the window never cuts them. Same dash as the wires,
   marching a notch slower so the two rhythms read as one system rather
   than a strobe. */
.hub-frame {
  stroke: #9C95E4; stroke-width: 1.3;
  stroke-dasharray: 4 4;
  animation: hubDash 1.6s linear infinite;
}
/* The record window is REAL glass: an HTML element layered over the SVG
   (founder 2026-07-25 — "le navigateur n'est pas en verre comme nous
   voulons"). A backdrop-filter can only blur behind an HTML element, and
   it only reads if there's material behind it — hence the halo below.
   Geometry mirrors the old SVG rect (x292 y150 w200 h220 of 784×520). */
.hub-stage { position: relative; }
/* The material behind the glass (founder 2026-08-08, replacing the
   greyscale ribbon which read as a grey-black smudge): a Klavius-violet
   halo centred on the window, wider than it, so a very subtle light
   seems to emanate from behind the record around the K. It doubles as
   what the backdrop-filter refracts — delete it and the window
   flattens into a plain white card. Keep it QUIET: the visible part is
   only the 5–12% ring outside the glass. */
.hub-halo {
  position: absolute; z-index: 0; pointer-events: none;
  left: 26%; top: 12%; width: 48%; height: 76%;
  background: radial-gradient(closest-side,
    color-mix(in srgb, var(--accent) 22%, transparent) 0%,
    color-mix(in srgb, var(--accent) 10%, transparent) 45%,
    transparent 72%);
}
.hub { position: relative; z-index: 1; }
.hub-glass {
  position: absolute; z-index: 2;
  left: 37.25%; top: 28.85%; width: 25.5%; height: 42.3%;
  border-radius: 12px; overflow: hidden;
  display: flex; flex-direction: column;
  background: color-mix(in srgb, var(--paper) 62%, transparent);
  backdrop-filter: saturate(150%) blur(16px);
  -webkit-backdrop-filter: saturate(150%) blur(16px);
  border: 1px solid color-mix(in srgb, #fff 65%, transparent);
  box-shadow:
    0 16px 32px -18px rgba(15,20,25,0.30),
    inset 0 1px 0 rgba(255,255,255,0.55);
}
.hg-bar {
  height: 15.5%; flex: none; display: flex; align-items: center; gap: 4.5%;
  padding-left: 8%;
  background: color-mix(in srgb, var(--paper) 40%, transparent);
  border-bottom: 1px solid color-mix(in srgb, var(--border) 55%, transparent);
}
.hg-bar i { width: 5.5%; aspect-ratio: 1; border-radius: 999px; display: block; }
.hg-body { flex: 1; display: grid; place-items: center; }
.hg-k { width: 28%; height: auto; color: var(--accent); }
.hub-node circle { fill: var(--accent); stroke: #FFFFFF; stroke-width: 1.5; }
.hub-card { fill: #FFFFFF; stroke: var(--border); stroke-width: 1; }
.hub-ic-bg { fill: var(--accent-tint); stroke: #DED9F6; stroke-width: 0.75; }
.hub-ic { stroke: var(--accent); stroke-width: 1.5; fill: none; }
.hub-l { font-family: var(--font-text); font-size: 20px; font-weight: 600; fill: var(--text-strong); }
.hub-s { font-family: var(--font-mono); font-size: 14px; fill: #63625B; letter-spacing: -0.3px; }
.hub-badge { transform-box: fill-box; transform-origin: center; animation: hubPop 3s ease-in-out infinite; }
.hub-badge-c { fill: var(--risk-low-tint); stroke: var(--surface); stroke-width: 2; }
.hub-badge-t { fill: none; stroke: var(--risk-low-ink); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
@keyframes hubDash { to { stroke-dashoffset: -8; } }
@keyframes hubPop {
  0%, 100% { transform: scale(1); }
  5% { transform: scale(1.18); }
  10% { transform: scale(1); }
}
@media (max-width: 680px) {
  /* scaled to a phone the labels become noise — the pills read as
     icon chips, like GitBook's avatar pills */
  .hub-l, .hub-s { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .hub-wire path, .hub-frame, .hub-badge { animation: none; }
}

/* Ask-Klavius replay — a scripted, self-playing product conversation
   (landing.js). Bubbles stay flat + hairline; the accent marks only
   Klavius's side. */
.ask-chat {
  min-height: 330px; display: flex; flex-direction: column;
  justify-content: flex-end; gap: 12px; overflow: hidden;
}
.ask-msg {
  max-width: 88%; font-size: 13px; line-height: 1.55;
  border-radius: 10px; padding: 9px 12px;
}
.ask-q {
  align-self: flex-end;
  background: var(--neutral-100); border: 1px solid var(--border);
  color: var(--text-strong);
}
.ask-a {
  align-self: flex-start;
  background: var(--surface);
  border: 1px solid color-mix(in srgb, var(--accent) 25%, var(--border));
}
.ask-who {
  display: flex; align-items: center; gap: 6px;
  font-family: var(--font-mono); font-size: 10px; font-weight: 600;
  letter-spacing: .06em; text-transform: uppercase; color: var(--accent);
  margin-bottom: 5px;
}
.ask-caret {
  display: inline-block; width: 1px; height: 1em;
  background: var(--text-strong); vertical-align: -2px; margin-left: 1px;
  animation: ask-blink 1s steps(1) infinite;
}
@keyframes ask-blink { 50% { opacity: 0; } }
.ask-pop { animation: ask-pop .3s cubic-bezier(.34,1.56,.64,1) both; }
@keyframes ask-pop {
  from { opacity: 0; transform: translateY(10px) scale(.97); }
  to { opacity: 1; transform: none; }
}
.ask-typing { display: inline-flex; gap: 4px; padding: 3px 2px; }
.ask-typing i {
  width: 5px; height: 5px; border-radius: 50%;
  background: var(--text-subtle);
  animation: ask-dot 1s ease-in-out infinite;
}
.ask-typing i:nth-child(2) { animation-delay: .15s; }
.ask-typing i:nth-child(3) { animation-delay: .3s; }
@keyframes ask-dot {
  0%, 60%, 100% { transform: none; opacity: .5; }
  30% { transform: translateY(-3px); opacity: 1; }
}
.ask-cites { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 8px; }
.ask-cite {
  font-family: var(--font-mono); font-size: 10px; padding: 2px 7px;
  border: 1px solid var(--border); border-radius: 999px;
  background: var(--neutral-100); color: var(--text-muted);
}
.ask-fade-out {
  opacity: 0; transform: translateY(-6px);
  transition: opacity .35s ease, transform .35s ease;
}
@media (max-width: 680px) { .ask-chat { min-height: 300px; } }
@media (prefers-reduced-motion: reduce) {
  .ask-pop { animation: none; }
  .ask-caret, .ask-typing i { animation: none; }
}

/* ---------- Platform panel replay (founder call 2026-07-08) ----------
   When a module's drawer activates, its mock performs instead of
   crossfading in as a still: rows cascade, bars draw from zero, the
   timeline redraws. landing.js stamps per-element transition delays
   and toggles .replay-prep (hide, transitions off) → release. Scoped
   to .pf-panel so the mobile carousel's cloned mocks stay static. */
.pf-panel .wtable tbody tr,
.pf-panel .ctrl-row,
.pf-panel .tl-item,
.pf-panel .clock,
.pf-panel .stat {
  transition: opacity .45s cubic-bezier(.2,.7,.2,1),
              transform .45s cubic-bezier(.22,1,.36,1);
}
.pf-panel .bar-fill {
  transform-origin: left;
  transition: transform .7s cubic-bezier(.22,1,.36,1);
}
.pf-panel .timeline::before {
  transform-origin: top;
  transition: transform .6s cubic-bezier(.22,1,.36,1) .15s;
}
.pf-panel.replay-prep .wtable tbody tr,
.pf-panel.replay-prep .ctrl-row,
.pf-panel.replay-prep .tl-item,
.pf-panel.replay-prep .clock,
.pf-panel.replay-prep .stat {
  opacity: 0; transform: translateY(6px); transition: none;
}
.pf-panel.replay-prep .bar-fill { transform: scaleX(0); transition: none; }
.pf-panel.replay-prep .timeline::before { transform: scaleY(0); transition: none; }
@media (prefers-reduced-motion: reduce) {
  .pf-panel.replay-prep .wtable tbody tr,
  .pf-panel.replay-prep .ctrl-row,
  .pf-panel.replay-prep .tl-item,
  .pf-panel.replay-prep .clock,
  .pf-panel.replay-prep .stat { opacity: 1 !important; transform: none !important; }
  .pf-panel.replay-prep .bar-fill,
  .pf-panel.replay-prep .timeline::before { transform: none !important; }
}

/* ---------- ADN pass 2 (P4-P6): trust chips · who-it's-for · scroll cue ---------- */

/* Trust chips (P5) REMOVED 2026-07-09 on founder review — the hero
   reads cleaner without a fourth row of elements; the claims live on
   in the Trust section + security.html/subprocessors.html. */

/* Who it's for — three persona cards, ai-step's card grammar without
   the watermark icon: eyebrow persona · claim · two lines · module
   chips. The buyer finds their own desk. */
/* Who it's for — the profile deck (finish pass, founder call
   2026-08-08, corrected same day: the greying + repositioning live
   INSIDE the cards, the section band stays paper white and the rail
   stays put). Every card carries --shadow-card (this REVERSES the
   earlier "separation by border + surface tone, never shadow"
   grammar — the flat stack read as amateur on the live page). Back
   cards render their ribbon art instead of dull sunken grey — the
   copy stays hidden (that's what invites the flip) but each card
   keeps its material identity through the stack. */
.who-eyebrow {
  font-family: var(--font-mono); font-size: 11px; font-weight: 500;
  letter-spacing: 0.07em; text-transform: uppercase; color: var(--text-subtle);
  display: flex; align-items: baseline; gap: 8px;
}
/* GitBook numbered-card grammar: the INDEX carries the accent, big;
   the label goes quiet beside it. */
.wd-no { font-size: 20px; color: var(--accent); letter-spacing: .02em; }
.wd-wrap {
  display: grid; grid-template-columns: minmax(0, .9fr) minmax(0, 1.1fr);
  gap: var(--space-16); align-items: center;
}
/* Rail typography mirrors .sec-head so the section title sits on the
   same scale as every other band (the rail isn't a .sec-head because
   it doesn't carry its bottom margin / max-width). */
.wd-rail h2 { font-size: 34px; letter-spacing: -0.015em; margin: var(--space-4) 0 var(--space-4); }
.wd-lead { color: var(--text-muted); font-size: 18px; line-height: 1.55; margin: 0 0 var(--space-8); }
.wd-nav { display: flex; align-items: center; gap: var(--space-3); }
.wd-arrow {
  width: 38px; height: 38px; display: grid; place-items: center;
  border: 1px solid var(--border-strong); border-radius: 50%;
  background: var(--surface); color: var(--text-strong); cursor: pointer;
  transition: border-color .25s ease, background .25s ease, color .25s ease, transform .2s ease;
}
.wd-arrow:hover { border-color: var(--accent); color: var(--accent-active); background: var(--accent-tint); }
.wd-arrow:active { transform: scale(.92); }
.wd-count {
  font-family: var(--font-mono); font-size: 11px; letter-spacing: .06em;
  color: var(--text-muted); margin-left: var(--space-2);
}
.wd-deck { position: relative; height: 380px; }
.wd-card {
  position: absolute; inset: 0;
  border: 1px solid var(--border); border-radius: var(--radius-xl);
  background: var(--surface); padding: var(--space-8);
  box-shadow: var(--shadow-card);
  transition: transform .55s cubic-bezier(.22,1,.36,1), opacity .45s ease,
              background .45s ease, border-color .45s ease;
  will-change: transform;
}
.wd-in { display: flex; flex-direction: column; gap: var(--space-3); height: 100%; transition: opacity .35s ease; }
/* The claim + quote + answer anchor to the card's lower half — the
   ribbon gets the upper air, and every card's text lands on the same
   baseline whatever its length. The icon AND the numbered eyebrow
   stay top (founder call 2026-08-08): the anchor is the h4's
   margin-top below, not anything here. */
/* Persona ribbon art — three Higgsfield pieces in the house ribbon
   material, one per card: the sweep (operations in motion), the knot
   (four frameworks bound into one), the rising wave (the board's trend
   line). Two gradient layers keep the copy on solid surface — one fades
   the art out toward the left (headline run), one toward the bottom
   (pain + answer paragraphs) — so the ribbon lives in the top-right.
   The veils resolve to warm GREYS, not white (finish pass): the art
   fades into grey and the copy sits on that grey — inside the card
   the only near-white left is the ribbon's own ground. Since the
   finish pass the depth slots no longer reset `background`, so the
   BACK cards render their ribbon too — only the copy stays hidden. */
.wd-art {
  background-repeat: no-repeat;
  background-size: 100% 100%, 100% 100%, cover;
  background-position: 0 0, 0 0, right top;
}
.wd-art-ops {
  background-image:
    linear-gradient(180deg, rgba(242, 241, 239, 0) 24%, #F2F1EF 60%),
    linear-gradient(92deg, #F7F6F4 36%, rgba(247, 246, 244, 0) 74%),
    url("brand/ribbon-who-1.jpg");
  background-image:
    linear-gradient(180deg, rgba(242, 241, 239, 0) 24%, #F2F1EF 60%),
    linear-gradient(92deg, #F7F6F4 36%, rgba(247, 246, 244, 0) 74%),
    image-set(url("brand/ribbon-who-1-1x.jpg") 1x, url("brand/ribbon-who-1.jpg") 2x);
}
.wd-art-comp {
  background-image:
    linear-gradient(180deg, rgba(242, 241, 239, 0) 24%, #F2F1EF 60%),
    linear-gradient(92deg, #F7F6F4 36%, rgba(247, 246, 244, 0) 74%),
    url("brand/ribbon-who-2.jpg");
  background-image:
    linear-gradient(180deg, rgba(242, 241, 239, 0) 24%, #F2F1EF 60%),
    linear-gradient(92deg, #F7F6F4 36%, rgba(247, 246, 244, 0) 74%),
    image-set(url("brand/ribbon-who-2-1x.jpg") 1x, url("brand/ribbon-who-2.jpg") 2x);
}
.wd-art-board {
  /* The rising wave lives in the source's centre-right — zoom this layer
     so its crest fills the top-right corner like the other two pieces. */
  background-size: 100% 100%, 100% 100%, auto 200%;
  background-position: 0 0, 0 0, right 28%;
  background-image:
    linear-gradient(180deg, rgba(242, 241, 239, 0) 24%, #F2F1EF 60%),
    linear-gradient(92deg, #F7F6F4 36%, rgba(247, 246, 244, 0) 74%),
    url("brand/ribbon-who-3.jpg");
  background-image:
    linear-gradient(180deg, rgba(242, 241, 239, 0) 24%, #F2F1EF 60%),
    linear-gradient(92deg, #F7F6F4 36%, rgba(247, 246, 244, 0) 74%),
    image-set(url("brand/ribbon-who-3-1x.jpg") 1x, url("brand/ribbon-who-3.jpg") 2x);
}
.wd-card.wd-p0 { z-index: 3; transform: none; border-color: var(--border-strong); }
/* Back cards: no background reset any more — they keep the base
   surface AND their wd-art-* ribbon, rendered like real cards. A
   surface wash (::after, deeper = stronger) rests the art so the
   peeking slivers stay quiet; it fades off as the card comes front. */
.wd-card::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit;
  background: var(--surface); opacity: 0; pointer-events: none;
  transition: opacity .45s ease;
}
.wd-card.wd-p1 {
  z-index: 2; transform: translate(22px, -16px) rotate(2.6deg) scale(.965);
}
.wd-card.wd-p2 {
  z-index: 1; transform: translate(-18px, -28px) rotate(-2.2deg) scale(.93);
}
.wd-card.wd-p1::after { opacity: .45; }
.wd-card.wd-p2::after { opacity: .6; }
.wd-card.wd-p1 .wd-in, .wd-card.wd-p2 .wd-in { opacity: 0; }
/* exit: the front card drops away, then rejoins the back of the deck */
.wd-card.wd-out { z-index: 4; transform: translateY(48px) rotate(-5deg) scale(.98); opacity: 0; }
.wd-ic {
  flex: 0 0 auto; width: 40px; height: 40px;
  display: grid; place-items: center;
  color: var(--accent); background: var(--accent-tint);
  border: 1px solid var(--border); border-radius: var(--radius-md);
  margin-bottom: var(--space-2);
}
.wd-ic svg { width: 21px; height: 21px; display: block; }
.wd-card h4 {
  font-family: var(--font-text); font-size: 18px; font-weight: 600;
  color: var(--text-strong); margin: auto 0 0; line-height: 1.35;
}
.wd-pain {
  border-left: 2px solid var(--accent); padding-left: var(--space-4);
  font-size: 15px; line-height: 1.5; color: var(--text-strong);
  font-style: italic; margin: var(--space-1) 0 0;
}
.wd-ans { margin: 0; font-size: 14px; color: var(--text-muted); line-height: 1.6; }
@media (max-width: 960px) {
  .wd-wrap { grid-template-columns: 1fr; gap: var(--space-8); }
  .wd-deck { height: 420px; }
  .wd-card { padding: var(--space-6); }
}
@media (max-width: 680px) {
  /* Same mobile type scale as .sec-head — these overrides must live
     AFTER the base .wd-rail rules in source order to win the cascade. */
  .wd-rail h2 { font-size: 23px; }
  .wd-lead { font-size: 14.5px; }
  .wd-deck { height: 480px; }
  .wd-card.wd-p1 { transform: translate(12px, -12px) rotate(2deg) scale(.97); }
  .wd-card.wd-p2 { transform: translate(-10px, -20px) rotate(-1.8deg) scale(.94); }
}
@media (prefers-reduced-motion: reduce) {
  .wd-card, .wd-card::after, .wd-in, .wd-arrow { transition: none; }
}

/* Scroll cue — a quiet chevron under the demo, easing downward. */
.scroll-cue {
  display: flex; width: max-content; margin: var(--space-8) auto 0;
  color: var(--text-subtle);
  animation: cue-bounce 2.2s ease-in-out infinite;
}
.scroll-cue:hover { color: var(--accent); }
@keyframes cue-bounce {
  0%, 100% { opacity: .45; transform: translateY(0); }
  50% { opacity: 1; transform: translateY(6px); }
}
@media (prefers-reduced-motion: reduce) { .scroll-cue { animation: none; } }

/* mobile menu: body scroll lock + burger/close icon swap */
body.nav-open { overflow: hidden; }
.nav-toggle .ic-close { display: none; }
body.nav-open .nav-toggle .ic-burger { display: none; }
body.nav-open .nav-toggle .ic-close { display: block; }

/* ---------- pricing page (pricing.html) ---------- */
/* Module icon tile — same recipe as the nav dropdown's .drop-ic. */
.pr-ic {
  flex: 0 0 auto; width: 34px; height: 34px;
  display: grid; place-items: center;
  color: var(--accent); background: var(--accent-tint);
  border: 1px solid var(--border); border-radius: var(--radius-md);
}
.pr-ic svg { width: 18px; height: 18px; display: block; }

/* Regulatory Watch entry strip */
.pr-rw {
  display: flex; align-items: center; gap: var(--space-4);
  border: 1px solid var(--border); border-radius: var(--radius-lg);
  background: var(--surface-sunken);
  padding: var(--space-4) var(--space-5); margin-bottom: var(--space-8);
}
.pr-rw-txt { flex: 1; }
.pr-rw-txt strong { display: block; font-size: 15px; color: var(--text-strong); }
.pr-rw-txt span { font-size: 13.5px; color: var(--text-muted); line-height: 1.5; }
.pr-rw-txt em { font-style: normal; color: var(--accent-active); font-weight: 500; }

/* Module cards */
.pr-grid {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-5); align-items: stretch;
}
.pr-card {
  position: relative; display: flex; flex-direction: column; gap: var(--space-3);
  border: 1px solid var(--border); border-radius: var(--radius-lg);
  background: var(--surface); padding: var(--space-6);
  /* Must restate the .reveal opacity transition — declaring `transition`
     here REPLACES the reveal's, and the entrance would snap otherwise.
     One transform duration serves both the reveal rise and the hover lift. */
  transition: opacity .6s cubic-bezier(.2,.7,.2,1),
              transform .45s cubic-bezier(.2,.7,.2,1),
              border-color .3s ease;
}
.pr-card:hover { transform: translateY(-3px); border-color: var(--border-strong); }
.pr-card:hover h3 { color: var(--accent-active); }
.pr-card h3 { transition: color .25s ease; }
/* Core card — quiet premium: 1px accent border + a soft accent wash
   fading from the top (the .aura family — a brand-surface tint, not a
   decorative gradient). No bars, no offsets: the emphasis is contained. */
.pr-card.core {
  border-color: var(--accent);
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--accent) 5%, var(--surface)) 0%,
    var(--surface) 120px);
}
.pr-card.core:hover { border-color: var(--accent); }
.pr-badge {
  position: absolute; top: var(--space-4); right: var(--space-4);
  font-family: var(--font-mono); font-size: 10px; letter-spacing: .08em;
  text-transform: uppercase; color: #fff; background: var(--accent);
  border-radius: var(--radius-pill); padding: 3px 10px;
}
/* Icon tile fills solid on card hover — the one saturated moment. */
.pr-card .pr-ic { transition: background .3s ease, color .3s ease, border-color .3s ease; }
.pr-card:hover .pr-ic { background: var(--accent); color: #fff; border-color: var(--accent); }
.pr-card h3 { font-size: 20px; margin: 2px 0 0; }
.pr-sub { font-size: 13.5px; color: var(--text-muted); line-height: 1.55; margin: 0; }
/* Feature list — circled checks (Maze / Contractbook), airy rows (Sana). */
.pr-feat { list-style: none; margin: var(--space-2) 0 0; padding: 0; flex: 1; }
.pr-feat li {
  font-size: 13.5px; color: var(--text-strong); line-height: 1.5;
  padding: 6px 0 6px 26px; position: relative;
}
.pr-feat li::before {
  content: ""; position: absolute; left: 0; top: 8px;
  width: 16px; height: 16px; border-radius: 50%;
  background: var(--accent-tint); border: 1px solid var(--border);
}
.pr-feat li::after {
  content: ""; position: absolute; left: 5px; top: 13.5px;
  width: 7px; height: 4px;
  border-left: 1.6px solid var(--accent); border-bottom: 1.6px solid var(--accent);
  transform: rotate(-45deg);
}
/* Checks cascade in once the card's reveal lands. */
.pr-card .pr-feat li { opacity: 0; transform: translateY(4px);
  transition: opacity .4s ease, transform .4s cubic-bezier(.2,.7,.2,1); }
.pr-card.in .pr-feat li { opacity: 1; transform: none; }
.pr-card.in .pr-feat li:nth-child(1) { transition-delay: .2s; }
.pr-card.in .pr-feat li:nth-child(2) { transition-delay: .26s; }
.pr-card.in .pr-feat li:nth-child(3) { transition-delay: .32s; }
.pr-card.in .pr-feat li:nth-child(4) { transition-delay: .38s; }
.pr-card.in .pr-feat li:nth-child(5) { transition-delay: .44s; }
.pr-card.in .pr-feat li:nth-child(6) { transition-delay: .5s; }
.pr-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.pr-incl {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 11.5px; font-weight: 500; letter-spacing: .01em;
  color: var(--accent-active); background: var(--accent-tint);
  border-radius: var(--radius-pill); padding: 4px 10px;
}
.pr-incl::before {
  content: ""; width: 7px; height: 4px; margin-top: -2px;
  border-left: 1.5px solid var(--accent); border-bottom: 1.5px solid var(--accent);
  transform: rotate(-45deg);
}
.pr-card .btn { justify-content: center; text-align: center; }

/* Interactive bundle builder — Cofounder two-panel + Notion checkbox
   calculator, no figures. Left: toggleable module rows. Right: the
   live bundle summary (chips + a Stripe-style segmented meter). */
.bb {
  margin-top: var(--space-12);
  display: grid; grid-template-columns: 1.15fr 1fr; gap: var(--space-6);
  border: 1px solid var(--border); border-radius: var(--radius-lg);
  background: var(--surface); padding: var(--space-6);
}
.bb-title { font-size: 20px; margin: 0 0 var(--space-1); }
.bb-sub { font-size: 14px; color: var(--text-muted); margin: 0 0 var(--space-5); line-height: 1.55; }
.bb-mods { display: flex; flex-direction: column; gap: var(--space-3); }
.bb-mod {
  display: flex; align-items: center; gap: var(--space-3); text-align: left;
  font-family: inherit; cursor: pointer; width: 100%;
  border: 1px solid var(--border); border-radius: var(--radius-md);
  background: var(--surface); padding: var(--space-3) var(--space-4);
  transition: border-color .25s ease, background .25s ease, transform .25s cubic-bezier(.2,.7,.2,1);
}
.bb-mod:hover { border-color: var(--border-strong); transform: translateX(2px); }
.bb-mod:active { transform: scale(.99); }
.bb-mod.on { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 4%, var(--surface)); }
.bb-mod-t { flex: 1; }
.bb-mod-t strong { display: block; font-size: 14px; color: var(--text-strong); line-height: 1.35; }
.bb-mod-t small { display: block; font-size: 11.5px; color: var(--text-muted); margin-top: 1px; }
.bb-mod .pr-ic { transition: background .25s ease, color .25s ease, border-color .25s ease; }
.bb-mod.on .pr-ic { background: var(--accent); color: #fff; border-color: var(--accent); }
/* the tick — an empty ring that fills + draws its check when selected */
.bb-tick {
  flex: 0 0 auto; width: 20px; height: 20px; position: relative;
  border: 1.5px solid var(--border-strong); border-radius: 50%;
  transition: background .25s ease, border-color .25s ease;
}
.bb-tick::after {
  content: ""; position: absolute; left: 4.5px; top: 5.5px;
  width: 8px; height: 4.5px;
  border-left: 1.7px solid #fff; border-bottom: 1.7px solid #fff;
  transform: rotate(-45deg) scale(0); transform-origin: center;
  transition: transform .25s cubic-bezier(.2,.7,.2,1);
}
.bb-mod.on .bb-tick { background: var(--accent); border-color: var(--accent); }
.bb-mod.on .bb-tick::after { transform: rotate(-45deg) scale(1); }

.bb-right {
  display: flex; flex-direction: column; gap: var(--space-4);
  border: 1px solid var(--border); border-radius: var(--radius-md);
  background: var(--surface-sunken); padding: var(--space-5);
  transition: border-color .3s ease;
}
.bb.bb-full .bb-right { border-color: var(--accent); }
.bb-sum-head {
  font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .06em;
  text-transform: uppercase; color: var(--text-muted);
}
.bb-stack { display: flex; flex-direction: column; gap: 6px; }
.bb-chip {
  display: flex; align-items: center; justify-content: space-between;
  font-size: 13px; font-weight: 500; color: var(--text-strong);
  border: 1px solid var(--border); border-radius: var(--radius-md);
  background: var(--surface); padding: 8px 12px;
  transition: opacity .3s ease, transform .3s cubic-bezier(.2,.7,.2,1);
}
.bb-chip.bb-rw { border-style: dashed; }
.bb-chip em { font-style: normal; font-size: 11px; color: var(--text-muted); }
.bb-chip[data-for] { opacity: 0; transform: translateY(4px) scale(.98); height: 0; padding-top: 0; padding-bottom: 0; border-width: 0; margin: 0; overflow: hidden; }
.bb-chip[data-for].in { opacity: 1; transform: none; height: auto; padding: 8px 12px; border-width: 1px; }
/* segmented discount meter — fills a segment per module */
.bb-meter { display: flex; gap: 4px; }
.bb-meter span {
  flex: 1; height: 5px; border-radius: var(--radius-pill);
  background: var(--border); position: relative; overflow: hidden;
}
.bb-meter span::after {
  content: ""; position: absolute; inset: 0; background: var(--accent);
  transform: scaleX(0); transform-origin: left;
  transition: transform .4s cubic-bezier(.2,.7,.2,1);
}
.bb-meter span.fill::after { transform: scaleX(1); }
.bb-caption { font-size: 13px; color: var(--text-muted); line-height: 1.5; min-height: 2.6em; transition: color .3s ease; }
.bb.bb-full .bb-caption { color: var(--accent-active); }
.bb-right .btn { justify-content: center; text-align: center; margin-top: auto; }

/* Extra reveal stagger slots for the pricing grid (global .d1/.d2 exist). */
.reveal.d3 { transition-delay: .18s; }
.reveal.d4 { transition-delay: .24s; }

@media (max-width: 960px) {
  .pr-grid { grid-template-columns: 1fr; }
  .bb { grid-template-columns: 1fr; }
}
@media (max-width: 680px) {
  .pr-rw { flex-wrap: wrap; }
  .pr-rw .btn { width: 100%; justify-content: center; }
}
@media (prefers-reduced-motion: reduce) {
  .pr-card, .pr-card .pr-feat li, .bb-mod, .bb-tick, .bb-tick::after,
  .bb-chip, .bb-meter span::after, .bb-right { transition: none; }
  .pr-card .pr-feat li { opacity: 1; transform: none; }
  .pr-card:hover, .bb-mod:hover { transform: none; }
}

/* ---------- trust hub (trust.html) ---------- */
/* Rubric tabs — only the ACTIVE tab is lit (founder spec): tinted pill
   + accent text + a 2px accent underline that draws in and belongs to
   the active tab alone. Panels enter with a quiet rise; display flips
   need keyframes, not transitions. */
.tr-tabs {
  display: flex; gap: var(--space-2); flex-wrap: wrap;
  border-bottom: 1px solid var(--border);
  margin-bottom: var(--space-10);
}
.tr-tab {
  font-family: var(--font-text); font-size: 14px; font-weight: 500;
  color: var(--text-muted); background: none; border: none; cursor: pointer;
  padding: 10px 16px; border-radius: var(--radius-md) var(--radius-md) 0 0;
  position: relative;
  transition: color .25s ease, background .25s ease;
}
.tr-tab::after {
  content: ""; position: absolute; left: 12px; right: 12px; bottom: -1px;
  height: 2px; background: var(--accent);
  transform: scaleX(0); transform-origin: center;
  transition: transform .3s cubic-bezier(.2,.7,.2,1);
}
.tr-tab:hover { color: var(--text-strong); background: var(--surface-sunken); }
.tr-tab.active { color: var(--accent-active); background: var(--accent-tint); }
.tr-tab.active::after { transform: scaleX(1); }
.tr-panel { display: none; }
.tr-panel.active { display: block; animation: trPanelIn .35s cubic-bezier(.2,.7,.2,1); }
@keyframes trPanelIn {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: none; }
}
.tr-panel-lede {
  font-size: 15px; color: var(--text-muted); line-height: 1.6;
  margin: 0 0 var(--space-6); max-width: 66ch;
}
@media (prefers-reduced-motion: reduce) {
  .tr-tab, .tr-tab::after { transition: none; }
  .tr-panel.active { animation: none; }
}
