/* =====================================================================
   BehaviorGPT — standalone waitlist landing page
   Self-contained styles (this page does not use the shared styles.css).
   Aesthetic: Oxygen Mono for headings and structural type, Oxygen for prose,
   generous whitespace, no hard border lines. The hero headline types itself out
   with a blinking caret.
   The decision tree mirrors the Unbox intelligence demo.
   ===================================================================== */

:root {
  /* Two faces, one rule. --font-mono (Oxygen Mono) carries every heading plus
     the structural type around it: eyebrows, labels, tags, figures, chart
     furniture, nav/footer chrome, the terminal, and the typewriter hero headline
     (intro line + rotating word). --font-sans (Oxygen) carries the prose: leads,
     descriptions, FAQ answers, modal copy. Body defaults to sans, so a prose
     rule can simply omit the declaration; the mono cases are always explicit.
     Oxygen ships 300/400/700 — a 500/600 request resolves to the nearest of
     those. Oxygen Mono ships 400 only, so weight on mono type is synthesized. */
  --font-sans: 'Oxygen', system-ui, -apple-system, Helvetica, Arial, sans-serif;
  --font-mono: 'Oxygen Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

  /* ===== Type scale =====
     Every font-size on the page comes from one of these steps — no raw px in
     component rules. Sizes are rem off the 16px root, so they track the root.
     Fixed rem for body/UI; one shared clamp() method for the two fluid heading
     tiers. The only value outside this scale is .hero-title, which fits a fixed
     string to the viewport width with a bespoke calc() (see its comment). */
  --fs-2xs:  0.625rem;   /* 10px — in-viz SVG node labels */
  --fs-xs:   0.6875rem;  /* 11px — eyebrows, captions, footer, fineprint, errors, tooltip */
  --fs-sm:   0.8125rem;  /* 13px — meta nav, small buttons, form labels + inputs, hero sub */
  --fs-base: 0.9375rem;  /* 15px — body copy, primary button */
  --fs-md:   1rem;       /* 16px — section lead, long-form body (docs, FAQ answers) */
  --fs-lg:   1.25rem;    /* 20px — FAQ question, modal title */
  --fs-heading: clamp(1.375rem, 1rem + 1.4vw, 1.625rem);    /* 22 → 26px — column & panel headings */
  --fs-display: clamp(1.4375rem, 1rem + 1.5vw, 1.6875rem);  /* 23 → 27px — section titles */

  --text: #1a1a1a;
  --text-secondary: #3f4147;
  --text-muted: #6b7280;
  --text-faint: #9aa0aa;

  --bg: #ffffff;
  --bg-subtle: #fafbfc;
  --border: #e7e8ec;
  --border-strong: #e4e6ea;

  /* ===== Brand palette =====
     Seven hue families, five shades each (dark / bright / vivid / light /
     pastel). Every chromatic color on the page is drawn from this set; the
     neutrals above (text / bg / borders) stay grayscale by design. */
  --yellow-dark: #6e5e1f;  --yellow-bright: #efc13a;  --yellow-vivid: #f4d63f;  --yellow-light: #f3e67b;  --yellow-pastel: #fcf7cb;
  --orange-dark: #6b3d14;  --orange-bright: #e2893c;  --orange-vivid: #ec9a56;  --orange-light: #f3c79a;  --orange-pastel: #f7e4cd;
  --green-dark:  #2f6b1e;  --green-bright:  #59a83e;  --green-vivid:  #8ed965;  --green-light:  #b8e7a1;  --green-pastel:  #daf3cc;
  --blue-dark:   #16266c;  --blue-bright:   #2f72e6;  --blue-vivid:   #49a5e6;  --blue-light:   #9bcfec;  --blue-pastel:   #d7effb;
  --purple-dark: #3d1e8e;  --purple-bright: #6a2fe5;  --purple-vivid: #8e5bf3;  --purple-light: #c3a9f2;  --purple-pastel: #e6ddf7;
  --pink-dark:   #6d1e53;  --pink-bright:   #b73f90;  --pink-vivid:   #e25ab1;  --pink-light:   #ec9bca;  --pink-pastel:   #f7daeb;
  --red-dark:    #6d1616;  --red-bright:    #d53f30;  --red-vivid:    #ec6a5a;  --red-light:    #ee9b8f;  --red-pastel:    #f7dad3;

  /* Semantic roles mapped onto the palette */
  --accent: var(--blue-bright);       /* primary blue, matches the Unbox intelligence tree */
  --accent-hover: #2560cc;            /* blue between --blue-bright and --blue-dark */
  --accent-soft: var(--blue-pastel);
  --success: var(--green-bright);
  --error: var(--red-bright);
  --black: #131313;

  --viz-grey: #cfcfcf;                /* neutral background dots in the embedding cloud */

  /* ===== Motion scale =====
     Same method as the type scale: every duration and easing on the page comes
     from one of these steps, so components that share a gesture share a pace and
     the whole page reads as one system. No raw durations or curves in component
     rules.

     Two curves only:
       --ease-out  things arriving, or turning in place. Fast out of the gate,
                   settles gently — the right read for anything appearing.
       --ease-io   boxes changing size or position. The slow start matters: a
                   panel that begins growing at full speed lurches.

     Steps are roughly 1.5x apart and picked by how far the thing actually
     travels, which is why they differ — a hover tint moves nothing, a domain
     panel crosses half the viewport. Beats that must line up reference each
     other's token instead of restating a number (.tnode's delay is --t-draw,
     ucFade's is --t-expand), so re-timing one place re-times its partner. */
  --ease-out: cubic-bezier(0.22, 0.61, 0.36, 1);
  --ease-io:  cubic-bezier(0.45, 0, 0.2, 1);

  --t-hover:   0.18s;   /* hover + focus affordance: tint, lift, arrow nudge */
  --t-state:   0.28s;   /* committed small state: marker turn, modal in, recolor */
  --t-open:    0.45s;   /* content opening or fading as a block: FAQ, use cases */
  --t-draw:    0.6s;    /* one stroke drawing itself */
  --t-reveal:  0.65s;   /* on-scroll reveal */
  --t-expand:  0.8s;    /* big layout expand: domain split, tree refit */
  --t-stagger: 80ms;    /* one beat between staggered siblings */
}

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

html {
  font-size: 16px;
  -webkit-text-size-adjust: 100%;
}

body {
  font-family: var(--font-sans);
  color: var(--text);
  background: var(--bg);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* Full-bleed UMAP breaks out to 100vw; clip horizontally so the scrollbar
     width never spills into a stray horizontal scroll. */
  overflow-x: clip;
}

a { color: inherit; text-decoration: none; }
img, svg { display: block; max-width: 100%; }
button { font: inherit; color: inherit; background: none; border: none; cursor: pointer; }

/* ===== Layout ===== */
.page {
  max-width: 1156px;   /* ~1cm wider content on each side */
  margin: 0 auto;
  padding: 0 24px;
}

.section {
  padding: 72px 0;
}

@media (max-width: 700px) {
  .section { padding: 48px 0; }
}

/* ===== Site chrome (header / footer) ===== */
.site-head {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  /* Match the homepage nav frame (1200px, 16/24px padding) so the brand logo
     sits at the identical top-left position on both pages. */
  max-width: 1200px;
  margin: 0 auto;
  padding: 16px 16px 0;
  z-index: 70;               /* over the full-screen hero canvas and its overlay */
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}
.brand { position: relative; display: inline-flex; align-items: center; }
/* Logo height mirrors the homepage: 28px below 768px, 34px at/above (see media). */
.brand img { height: 28px; width: auto; }
/* The mark is 31x28 — under a thumb's width. Overlay the shortfall instead of
   padding it, so the logo stays pinned to the same top-left point it shares
   with the homepage nav. Nothing sits within 22px of it, so nothing is stolen. */
.brand::after { content: ''; position: absolute; inset: -8px; }

.site-head-nav { display: flex; align-items: center; gap: 22px; }
.head-link {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--text-muted);
  transition: color var(--t-hover) var(--ease-out);
}
.head-link:hover { color: var(--text); }

/* Desktop: match the homepage nav's 24px padding and 34px logo height. */
@media (min-width: 768px) {
  .site-head { padding: 24px 24px 0; }
  .brand img { height: 34px; }
}

@media (max-width: 560px) {
  /* Match the homepage's mobile logo top: its nav padding is 16px but the
     hamburger centres the logo 2px lower, so pin this header to 18px to align. */
  .site-head { padding-top: 18px; }
  .head-link { display: none; }
}

.site-foot {
  margin-top: 32px;
  border-top: 1px solid var(--border);
}
.foot-inner {
  max-width: 1156px;   /* ~1cm wider content on each side */
  margin: 0 auto;
  padding: 26px 24px 40px;
  display: flex;
  align-items: center;
  gap: 22px;
  flex-wrap: wrap;
}
.foot-brand { position: relative; display: inline-flex; align-items: center; opacity: 0.8; }
.foot-brand img { height: 20px; width: auto; }   /* keep the 36:33 mark from squashing to a square */
.foot-brand::after { content: ''; position: absolute; inset: -12px; }   /* 20px mark, 44px target */
.foot-nav { display: flex; gap: 22px; flex-wrap: wrap; }
.foot-nav a, .foot-copy {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--text-muted);
}
.foot-nav a { transition: color var(--t-hover) var(--ease-out); }
.foot-nav a:hover { color: var(--text); }
.foot-copy { margin-left: auto; }

@media (max-width: 560px) {
  .foot-copy { margin-left: 0; flex-basis: 100%; }
}

.section-eyebrow {
  display: block;
  text-align: center;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 14px;
}

.section-title {
  font-family: var(--font-mono);
  font-weight: 400;
  font-size: var(--fs-display);
  line-height: 1.15;
  text-align: center;
  color: var(--text);
  margin-bottom: 44px;
}

/* Lead line under a section title: states the section's value proposition
   before the supporting grid. Pulled up under the title, then spaced off
   the content below. */
.section-lead {
  font-family: var(--font-sans);
  font-size: var(--fs-md);
  line-height: 1.5;
  text-align: center;
  color: var(--text-secondary);
  max-width: 640px;
  margin: -24px auto 48px;
}

/* ===== Motion (driven by behaviorgpt-motion.js) ===== */
/* On-scroll reveals: the hidden state is gated on .motion-ok (added by JS, and
   never under reduced motion), so crawlers and no-JS visitors always see the
   full page. Tagged elements fade and rise once as they enter; grouped
   elements stagger via --reveal-i, set per element from JS. */
html.motion-ok [data-reveal] {
  opacity: 0;
  transform: translateY(18px);
  transition:
    opacity var(--t-reveal) var(--ease-out),
    transform var(--t-reveal) var(--ease-out);
  transition-delay: calc(var(--reveal-i, 0) * var(--t-stagger));
}
html.motion-ok [data-reveal].is-revealed { opacity: 1; transform: none; }

/* Hero content must not flash before the embedding cloud settles. Hide it from
   the very first paint — before JS adds .motion-ok — so it never renders and
   fades; JS reveals it on 'bgpt:hero-ready' (with a 6s fallback). The
   reduced-motion rule below forces it visible with !important for those users. */
.hero [data-reveal]:not(.is-revealed) { opacity: 0; }

@media (prefers-reduced-motion: reduce) {
  [data-reveal] { opacity: 1 !important; transform: none !important; transition: none !important; }
}

/* ===== Hero: full-screen embedding stage with an overlaid headline ===== */
/* The stage breaks out of the centered .page column to fill the whole viewport,
   so the cloud floats edge to edge and its outer points are never clipped by a
   band. The cloud's on-screen size is held constant from behaviorgpt-viz.js. */
.hero-stage {
  position: relative;
  width: 100vw;
  margin-left: calc(50% - 50vw);
  height: 100vh;
  height: 100dvh;           /* track the iOS URL bar where supported */
  overflow: hidden;
}

/* Headline + CTA float centered over the cloud. The layer ignores pointer
   events so drag-to-rotate and hover reach the canvas beneath; only the
   interactive controls (the CTA) re-enable them. */
.hero {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;         /* text sits in the lower band, clear of the cloud */
  text-align: center;
  padding: 0 24px clamp(40px, 6vh, 96px);   /* bottom padding = how far down the text sits */
  pointer-events: none;
}
.hero button,
.hero a { pointer-events: auto; }

.hero-title {
  font-family: var(--font-mono);
  font-weight: 400;
  /* Two lines: the fixed intro ("The foundation model for") on top and the
     rotating word on its own line below (see .rotator). The intro stays on a
     single row, scaled to the viewport width (capped at 39px on wide screens).
     Intentionally outside the --fs-* scale: this fits a fixed string to the
     viewport, which a type step can't express. */
  font-size: clamp(28px, calc((100vw - 52px) / 20), 39px);
  line-height: 1.16;
  letter-spacing: -0.012em;
  color: var(--text);
  white-space: nowrap;
  text-align: center;
  margin: 0 auto;
}

/* On phones the sentence wraps to two lines so the type can stay large. */
@media (max-width: 640px) {
  .hero-title {
    white-space: normal;
    font-size: min(32px, calc((100vw - 48px) / 10.2));
  }
}

/* The rotating word sits on its own line beneath the intro, so it centers
   cleanly for every word (short or long) and the intro line above it never
   shifts. Alignment is inherited from .hero-title; same upright Oxygen Mono. */
.rotator {
  display: block;
  font-weight: 400;
  /* Reserve one line's height so the button below never jumps when the
     typewriter empties the word between rotations. 1lh tracks the line-height;
     the em value is the fallback for browsers without the lh unit. */
  min-height: 1.16em;
  min-height: 1lh;
}

/* ===== Hero typewriter (driven by behaviorgpt-motion.js) =====
   A steady (non-blinking) caret marks active typing only: it rides the intro
   line while that types, then the rotating word while a word is being typed or
   deleted (JS toggles .is-typing). It disappears during the idle hold between
   words, so nothing blinks at rest. JS adds these classes only, so no-JS and
   reduced-motion visitors see the full, static headline. */
.hero-title.caret-intro .hero-intro::after,
.hero-title.caret-rotator.is-typing .rotator::after {
  content: '';
  display: inline-block;
  width: 0.5ch;
  height: 1em;
  margin-left: 0.06em;
  vertical-align: -0.12em;
  background: currentColor;
}

@media (prefers-reduced-motion: reduce) {
  .hero-title.caret-intro .hero-intro::after,
  .hero-title.caret-rotator.is-typing .rotator::after { display: none; }
}

/* Soft subheader between the rotating headline and the CTA. */
.hero-sub {
  margin: 18px 0 0;
  font-family: var(--font-sans);
  font-size: var(--fs-base);
  font-weight: 400;
  color: var(--text-muted);
  letter-spacing: 0.01em;
}

.hero-actions {
  margin-top: 18px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  flex-wrap: wrap;
}

.btn-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: #eeeeee;
  color: var(--text);
  border-radius: 999px;
  padding: 9px 20px;
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  font-weight: 500;
  transition: background-color var(--t-hover) var(--ease-out);
}

.btn-pill:hover { background: #e2e2e2; }

/* The page's primary call to action lands at 38px tall, just under the 44px a
   thumb wants. Grow it on phones only — on a pointer device 38px is already
   comfortably clickable and the pill's proportions are part of the hero. */
@media (max-width: 640px) {
  .btn-pill { min-height: 44px; }
}
.btn-arrow { transition: transform var(--t-hover) var(--ease-out); }
.btn-pill:hover .btn-arrow { transform: translateX(4px); }

/* Compact pill used in the header. */
.btn-pill-sm { padding: 9px 20px; font-size: var(--fs-sm); }

/* ===== UMAP box (visual only, no text inside) ===== */
/* Fills the hero stage edge to edge. The canvas is sized to the full stage so
   no points are clipped; behaviorgpt-viz.js scales the render group down to keep
   the cloud's on-screen size the same as the old band. */
/* Barely-there dot grid behind the cloud (z-index 0, before .umap-box in the
   DOM so it sits behind the transparent canvas). JS fades its opacity to 0 as
   the hero scrolls away, so it only textures the landing view. */
.hero-dots {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image: radial-gradient(circle, rgba(26, 26, 26, 0.06) 1px, transparent 1.6px);
  background-size: 20px 20px;
  will-change: opacity;
}

.umap-box {
  position: absolute;
  inset: 0;
  z-index: 0;
  background: transparent;
  overflow: hidden;
}

.umap-box canvas {
  position: absolute;
  inset: 0;
  display: block;
}

.umap-fallback {
  position: absolute;
  inset: 0;
  z-index: 1;
  background-image: radial-gradient(circle, var(--viz-grey) 1.4px, transparent 1.6px);
  background-size: 24px 24px;
  opacity: 0.5;
}
.umap-fallback[hidden] { display: none; }

/* ===== Docs + decision tree ===== */
/* Stacked and centered to match the other sections: eyebrow + title + copy sit
   centered on top, the tree visual centered below. */
.docs-grid {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 48px;
}

@media (max-width: 860px) {
  .docs-grid { gap: 36px; }
}

/* Intro: statement on the left, terminal on the right. The right column gets a
   little more room for the wider code lines. Stacks below 860px. */
.intro-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
  gap: 48px;
  align-items: center;
  width: 100%;
  max-width: 1080px;
  margin-inline: auto;
}
.intro-text {
  text-align: left;
  max-width: none;   /* the grid column already bounds the width */
}
@media (max-width: 860px) {
  .intro-grid { grid-template-columns: 1fr; gap: 32px; }
}

/* Terminal: dark panel with a macOS-style title bar. Colors are drawn from the
   brand palette so the syntax tokens match the rest of the page. */
.terminal {
  position: relative;   /* anchors the phone scroll-fade below */
  border-radius: 12px;
  overflow: hidden;
  background: #1b1d23;
  border: 1px solid #2a2d36;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.18);
  font-family: var(--font-mono);
}
.terminal-bar {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 8px 12px;
  background: #23262e;
  border-bottom: 1px solid #2a2d36;
}
.terminal-dot { width: 9px; height: 9px; border-radius: 50%; background: #3a3d46; }
.terminal-dot:nth-child(1) { background: var(--red-vivid); }
.terminal-dot:nth-child(2) { background: var(--yellow-vivid); }
.terminal-dot:nth-child(3) { background: var(--green-bright); }
.terminal-title { margin-left: 8px; font-size: var(--fs-xs); color: #8a8f9a; }

/* Light/dark toggle, pinned to the right of the title bar. */
.terminal-theme {
  position: relative;
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  padding: 0;
  border: 0;
  border-radius: 5px;
  background: none;
  color: #8a8f9a;
  cursor: pointer;
  transition: color var(--t-hover) var(--ease-out),
              background-color var(--t-hover) var(--ease-out);
}
.terminal-theme:hover { color: #d7dae1; background: rgba(255, 255, 255, 0.08); }
/* The switch reads as a 16px glyph but takes taps over 40px, which is what a
   thumb actually needs. An overlay rather than padding, so the title bar's
   height and the icon's position stay exactly where they were. */
.terminal-theme::after { content: ''; position: absolute; inset: -12px; }
.terminal-theme svg { width: 13px; height: 13px; display: block; }
/* Show the icon for the mode the button switches TO: moon while light, sun
   while dark. */
.terminal .icon-moon { display: none; }
.terminal.is-light .icon-sun { display: none; }
.terminal.is-light .icon-moon { display: block; }

.terminal-body {
  margin: 0;
  padding: 12px 16px;
  overflow-x: auto;
  font-family: var(--font-mono);
  /* Fluid: caps at 13px on desktop, shrinks toward 11px on phones so the code
     fits without heavy horizontal scroll. The em-based min-height tracks it. */
  font-size: clamp(11px, 3.3vw, var(--fs-sm));
  line-height: 1.45;
  color: #d7dae1;
  /* Lines are kept short enough to fit; if the panel gets narrow it scrolls
     rather than wrapping mid-statement. */
  white-space: pre;
  overflow-x: auto;
  tab-size: 4;
}
.terminal-body code { font-family: inherit; }

/* Phones: the samples run to 66 characters, which at 13px wants ~430px inside a
   ~290px panel — two thirds of every line sat off-screen behind nothing but a
   hard crop. Step the code down and trim the gutters so most of a line lands at
   rest, and fade the trailing edge so the remainder reads as scroll rather than
   as text that has been cut off. `white-space: pre` stays: the sample is code,
   and wrapping it mid-statement would be worse than scrolling it. */
@media (max-width: 640px) {
  .terminal-body { font-size: var(--fs-xs); padding: 12px; }
  .terminal::after {
    content: '';
    position: absolute;
    top: 34px;          /* the title bar's height — the fade covers only the code */
    right: 0;
    bottom: 0;
    width: 24px;
    pointer-events: none;   /* never eats a swipe meant for the scroller */
    background: linear-gradient(to right, rgba(27, 29, 35, 0), #1b1d23);
  }
  .terminal.is-light::after {
    background: linear-gradient(to right, rgba(251, 251, 252, 0), #fbfbfc);
  }
}

.tok-com { color: var(--text-muted); font-style: italic; }
.tok-kw  { color: var(--purple-light); }
.tok-str { color: var(--green-vivid); }
.tok-def { color: var(--blue-vivid); }
.tok-num { color: var(--orange-vivid); }
.tok-op  { color: #d7dae1; }

/* Light theme (the default) — panel, chrome, and syntax tokens recolored for a
   white background with enough contrast to stay readable. Removing .is-light
   falls back to the dark styles above. */
.terminal.is-light {
  background: #fbfbfc;
  border-color: var(--border);
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.08);
}
.terminal.is-light .terminal-bar {
  background: #f1f2f5;
  border-bottom-color: var(--border);
}
.terminal.is-light .terminal-title { color: #6b7280; }
.terminal.is-light .terminal-theme { color: #6b7280; }
.terminal.is-light .terminal-theme:hover { color: #1b1d23; background: rgba(0, 0, 0, 0.06); }
.terminal.is-light .terminal-body { color: #383a42; }
.terminal.is-light .tok-com { color: #9aa0aa; }
.terminal.is-light .tok-kw  { color: #a626a4; }
.terminal.is-light .tok-str { color: #50a14f; }
.terminal.is-light .tok-def { color: #4078f2; }
.terminal.is-light .tok-num { color: #b76b01; }
.terminal.is-light .tok-op  { color: #383a42; }

/* Phones: tighten the panel padding and title bar so the smaller code font has
   more room and the chrome doesn't dominate. */
@media (max-width: 560px) {
  .terminal-body { padding: 10px 12px; }
  .terminal-bar { padding: 7px 10px; }
}

/* Use-case picker variant of the intro grid: the left column stretches to the
   terminal's height so the list can spread evenly across it. */
.intro-grid--usecases { align-items: stretch; }
.usecase-col { display: flex; flex-direction: column; }

/* Pin the code panel to the tallest snippet (17 lines at line-height 1.45,
   plus the 12px top/bottom padding — border-box includes it), so switching to
   a shorter use case leaves trailing space rather than shrinking the section. */
#terminalBody { min-height: calc(1.45em * 17 + 24px); }

.usecase-lead {
  font-family: var(--font-mono);
  font-size: var(--fs-md);
  line-height: 1.6;
  color: var(--text-secondary);
  margin: 0 0 20px;
}

/* The list fills the remaining column height; each item flex-grows so the five
   rows divide the block evenly, with a hairline divider between them. */
.usecase-list {
  display: flex;
  flex-direction: column;
  flex: 1;
  border-top: 1px solid var(--border);
}

.usecase-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex: 1;
  width: 100%;
  padding: 14px 2px;
  background: none;
  border: 0;
  border-bottom: 1px solid var(--border);   /* divider between alternatives */
  text-align: left;
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: var(--fs-md);
  color: var(--text-secondary);
  /* Tint is a hover affordance; flex-grow resizes the row, so it takes the
     size curve and the committed-state step (it only moves on selection). */
  transition: color var(--t-hover) var(--ease-out),
              flex-grow var(--t-state) var(--ease-io);
}
.usecase-item:hover { color: var(--text); }
.usecase-item:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
/* The selected row grows taller than the rest so the active state reads at a
   glance. flex-grow animates for a smooth expand/collapse. */
.usecase-item.is-active { color: var(--text); flex-grow: 1.6; }
.usecase-item.is-active .usecase-label { font-weight: 600; }

/* Marker: a "+" built from two bars. Selecting an item rotates it 45° so the
   plus reads as an "×". */
.usecase-marker {
  position: relative;
  width: 18px;
  height: 18px;
  flex: none;
  color: var(--text-faint);
  /* Same step and curve as the FAQ's "+" marker — both turn a plus into an ×
     on select, so both turn at the same pace. */
  transition: transform var(--t-state) var(--ease-out),
              color var(--t-state) var(--ease-out);
}
.usecase-marker::before,
.usecase-marker::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  background: currentColor;
  border-radius: 1px;
}
.usecase-marker::before { width: 13px; height: 1.5px; transform: translate(-50%, -50%); }
.usecase-marker::after  { width: 1.5px; height: 13px; transform: translate(-50%, -50%); }
.usecase-item.is-active .usecase-marker {
  transform: rotate(45deg);
  color: var(--accent);
}

@media (max-width: 860px) {
  /* Stacked: no shared height to fill, so give rows their natural size. */
  .usecase-item { flex: 0 0 auto; }
}

/* align-self: stretch gives this a DEFINITE width (the full .page column) instead
   of shrink-to-fit. Without it, a percentage width on .tree-box below has no
   definite basis to resolve against and silently collapses to auto (no breakout). */
.docs-visual { display: flex; flex-direction: column; align-items: center; gap: 16px; align-self: stretch; }
/* Gentle breakout past the .page column. Width is COLUMN-relative (a % of the
   content column, ~1108px), NOT viewport-relative — so it scales with the page
   and never jumps to a full-bleed edge-to-edge width on normal windows. The
   92vw cap only engages on small screens to avoid clipping. Centered by the
   parent flex; body overflow-x: clip guards against a horizontal scrollbar. */
.tree-box { width: 60%; max-width: none; }
.tree-box svg { width: 100%; height: auto; display: block; overflow: visible; }
.tree-caption {
  font-size: var(--fs-xs);
  color: var(--text-muted);
  text-align: center;
  font-family: var(--font-mono);
}

/* --- model tree: one persistent model node growing a whole tree per domain --- */
/* The fit group is scaled/translated to map the visible nodes into the viewBox;
   transitioning that transform is what zooms the model big when it stands alone
   and shrinks the whole visual as the tree grows. Origin pinned to the viewBox
   top-left so the JS translate+scale maps points exactly.
   Shares --t-expand and the size curve with .domain-split below: both are "a
   large block resizing", and they used to run at 0.95s vs 0.8s, so a visitor
   scrolling between them felt two different paces. */
.tree-fit {
  transform-box: view-box;
  transform-origin: 0 0;
  transition: transform var(--t-expand) var(--ease-io);
}

/* A domain's whole tree lives in one .tree-branch group so it can fade as a
   single unit on collapse — every line and node disappears in unison, no matter
   its own entrance animation. */
.tree-branch { transition: opacity var(--t-open) var(--ease-out); }
.tree-branch.leaving { opacity: 0; }

/* Edges are solid and fully drawn by default; the .draw class makes a line
   reveal itself from parent to child by sweeping stroke-dashoffset 1 -> 0. Works
   because each path carries pathLength="1", so dasharray:1 is exactly one full
   line and no measuring is needed. */
.tedge {
  fill: none;
  stroke: var(--border-strong);
  stroke-width: 1.5;
}
.tedge.b-retail  { stroke: var(--blue-bright);   stroke-width: 2; }
.tedge.b-finance { stroke: var(--orange-bright); stroke-width: 2; }

@keyframes tdraw { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }
.tedge.draw { stroke-dasharray: 1; animation: tdraw var(--t-draw) var(--ease-out) forwards; }

/* "extend, then place": the node stays hidden (backwards fill) for the length of
   its line's draw, then pops as the line lands. The delay IS --t-draw — the same
   token the edge above animates on — so the handoff cannot drift out of sync. */
.tnode.enter {
  transform-box: fill-box;
  transform-origin: center;
  animation: tpop var(--t-open) var(--ease-out) var(--t-draw) both;
}

@keyframes tpop {
  0% { opacity: 0; transform: scale(.6); }
  100% { opacity: 1; transform: scale(1); }
}

.tnode circle {
  fill: #fff;
  stroke: var(--border-strong);
  stroke-width: 1.5;
  transition: fill var(--t-state) var(--ease-out),
              stroke var(--t-state) var(--ease-out),
              stroke-width var(--t-state) var(--ease-out);
}

/* the shared model at the root -- the one model every domain branches from */
.tnode.root circle { stroke: var(--text); stroke-width: 2.5; }
.tnode.root .lbl { fill: var(--text); font-weight: 600; }

/* the domain node the model drops into -- emphasized in its own color */
.tnode.domain circle { stroke-width: 2.5; }
.tnode.domain .lbl { font-weight: 600; }

.tnode.b-retail  circle { stroke: var(--blue-bright); }
.tnode.b-finance circle { stroke: var(--orange-bright); }

/* the concrete prediction each use case leads to -- filled and emphasized in
   the domain color, so every leaf reads as one more thing the model predicts. */
.tnode.result circle { stroke-width: 2.5; }
.tnode.result.b-retail  circle { fill: var(--blue-pastel);   stroke: var(--blue-bright); }
.tnode.result.b-finance circle { fill: var(--orange-pastel); stroke: var(--orange-bright); }

/* Node icons: Lucide line art, tinted to the node's color. Stroke width is in
   the icon's own 24-unit space, so it scales with the node like everything else. */
.tnode .glyph-icon {
  fill: none;
  stroke: var(--text-muted);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.tnode.root .glyph-icon { stroke: var(--text); }
.tnode.b-retail  .glyph-icon { stroke: var(--blue-bright); }
.tnode.b-finance .glyph-icon { stroke: var(--orange-bright); }
.tnode.result.b-retail  .glyph-icon { stroke: var(--blue-dark); }
.tnode.result.b-finance .glyph-icon { stroke: var(--orange-dark); }
.tnode .lbl {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  fill: var(--text-muted);
  text-anchor: middle;
  paint-order: stroke;
  stroke: var(--bg);
  stroke-width: 3.5px;
  stroke-linejoin: round;
}
.tnode.result .lbl { font-weight: 600; }
.tnode.result.b-retail  .lbl { fill: var(--blue-dark); }
.tnode.result.b-finance .lbl { fill: var(--orange-dark); }

@media (prefers-reduced-motion: reduce) {
  .tnode.enter { animation: none; }
  .tree-fit, .tree-branch { transition: none; }
}

/* ===== Domain split (Retail / Finance toggle) =====
   Neutral by default: two equal panels split by a dark central divider, each
   showing only its domain label. Selecting a panel expands it (label rises to
   the top, use cases fade in) while the other collapses to a thin rail with a
   rotated, still-clickable label. Same expand easing as the decision tree fit
   so the motion reads as one system. */
.domain-split {
  display: flex;
  border-radius: 18px;
  overflow: hidden;
  /* Neutral (nothing picked yet): half height, just the two centered labels.
     On the first pick the JS sets data-active and the section grows to full
     height. Explicit `height` (not min-height) so the active panel's cards —
     laid out the instant it opens — can't beat it and snap the box tall; they
     stay clipped by overflow:hidden while faded out.
     The height *transition* is NOT here: this element is also [data-reveal],
     and that rule (html.motion-ok [data-reveal], higher specificity) sets a
     `transition` shorthand that would replace ours wholesale, leaving height
     un-eased — it would jump to full and the label's top:50% would teleport
     down before its own top->7% ran. So the transition lives in the merged
     rule below. */
  height: clamp(300px, 36vh, 360px);
  /* Inset ~1cm per side off the 1156px .page column; must match .spec-grid's
     max-width exactly so the two sections stay equal width. */
  max-width: 1080px;
  margin-inline: auto;
  width: 100%;
}
.domain-split[data-active] {
  height: clamp(600px, 72vh, 720px);
}
/* One `transition` declaration for both the reveal (opacity/transform) and the
   open-expand (height). Equal specificity to the reveal rule but later in
   source, so it wins; the shorthand can only be replaced, not extended, so the
   reveal's curve/delay is repeated verbatim and height is appended. */
html.motion-ok .domain-split {
  transition:
    opacity var(--t-reveal) var(--ease-out),
    transform var(--t-reveal) var(--ease-out),
    height var(--t-expand) var(--ease-io);
  transition-delay: calc(var(--reveal-i, 0) * var(--t-stagger));
}

.domain-panel {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 40px 32px;
  cursor: default;
  position: relative;
  overflow: hidden;          /* clip content as the panel collapses to a rail */
  /* One easing for the whole gesture. padding and min-height must ride the same
     curve as the flex sizes: with border-box they floor the panel's flex base
     size, so an instant padding change on the collapsing rail redistributes the
     row's free space in a single frame — a visible sideways snap of the title. */
  transition: flex-basis var(--t-expand) var(--ease-io),
              flex-grow var(--t-expand) var(--ease-io),
              padding var(--t-expand) var(--ease-io),
              min-height var(--t-expand) var(--ease-io);
}
/* Central divider — rides the panel boundary as the split resizes. Drawn as a
   gradient rule that fades to transparent at the top and bottom so it dissolves
   into the background on both edges instead of ending in a hard line. */
.domain-panel + .domain-panel::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 2px;
  background: linear-gradient(
    to bottom,
    transparent,
    var(--blue-bright) 18%,
    var(--blue-bright) 82%,
    transparent
  );
  pointer-events: none;
}

.domain-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; border-radius: 4px; }

/* The label is taken out of flow so its vertical position is transform/top
   driven — that's what lets it glide (center -> pinned top / center -> rotated
   rail) instead of snapping when flex reflows. */
.domain-label {
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  font-family: var(--font-mono);
  font-weight: 400;
  font-size: var(--fs-heading);
  line-height: 1.1;
  color: var(--text);
  text-align: center;
  white-space: nowrap;
  transition: top var(--t-expand) var(--ease-io),
              transform var(--t-expand) var(--ease-io);
  /* Span stays full-width for centering, but is not itself a hit target — only
     the inner button (sized to its text) receives clicks. */
  pointer-events: none;
}

/* The actual toggle: hugs the label text, so the click target is the word, not
   the surrounding panel. Inherits the label's font/color via the global button
   reset. */
.domain-toggle {
  pointer-events: auto;
  cursor: pointer;
  padding: 0;
  position: relative;
  transition: transform var(--t-hover) var(--ease-out);
}
/* Hover affordance: the word lifts slightly and an underline wipes in from the
   centre, signalling it is the clickable target. */
.domain-toggle::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -0.18em;
  height: 2px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: center;
  transition: transform var(--t-hover) var(--ease-out);
}
/* A little arrow paired with the label word; it nudges right on hover in step
   with the underline wipe and the word's lift — all three are one hover gesture,
   so all three are --t-hover (they used to split 0.25s/0.28s and drifted). */
.domain-toggle::before {
  content: ">";
  position: absolute;
  left: 100%;
  top: 50%;
  margin-left: 0.28em;
  font-size: 0.72em;
  line-height: 1;
  transform: translateY(-50%);
  transition: transform var(--t-hover) var(--ease-out);
}
.domain-toggle:hover { transform: scale(1.06); }
.domain-toggle:hover::after { transform: scaleX(1); }
.domain-toggle:hover::before { transform: translateY(-50%) translateX(0.3em); }
/* Finance mirrors retail: chevron sits to the left, points and nudges left. */
.domain-panel[data-domain="finance"] .domain-toggle::before {
  content: "<";
  left: auto;
  right: 100%;
  margin-left: 0;
  margin-right: 0.28em;
}
.domain-panel[data-domain="finance"] .domain-toggle:hover::before { transform: translateY(-50%) translateX(-0.3em); }

/* Use cases — out of flow until active (so the neutral label truly centers),
   then a flex box that fills the panel and centers the cards below the title. */
.domain-body { display: none; width: 100%; }

/* Active panel: the sibling collapsing to a fixed 72px rail lets this one absorb
   the rest (base flex-grow already does the growing). The title glides to a fixed
   top anchor and stays put; cards center in the space beneath it (padding-top
   clears the pinned title). */
.domain-panel.is-active .domain-label { top: 7%; transform: translateY(0); }
.domain-panel.is-active .domain-body {
  display: flex;
  flex: 1 1 auto;
  width: 100%;
  align-items: center;
  justify-content: center;
  padding-top: clamp(64px, 11%, 104px);
  /* Hold the cards until the width transition has settled, otherwise the 1fr
     columns keep resizing under the visible text and it reflows mid-fade. The
     delay IS --t-expand — the token the panel resizes on — so the two stay
     locked together if that step is ever re-timed. */
  animation: ucFade var(--t-open) var(--ease-out) var(--t-expand) both;
}

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

/* Collapsed panel: thin rail. The title stays vertically centered (top:50%) and
   gains rotation, so it glides down-to-center while rotating into the rail. */
.domain-panel.is-collapsed { flex: 0 0 72px; padding: 24px 0; }
.domain-panel.is-collapsed[data-domain="retail"]  .domain-label { transform: translateY(-50%) rotate(-90deg); }
.domain-panel.is-collapsed[data-domain="finance"] .domain-label { transform: translateY(-50%) rotate(90deg); }

/* Use-case cards: identical to the fns cards, three across. */
.uc-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 32px;
  margin: 0;
  width: 100%;
}

@media (prefers-reduced-motion: reduce) {
  .domain-split, .domain-panel, .domain-label, .domain-toggle, .domain-toggle::after, .domain-toggle::before { transition: none; }
  .domain-toggle:hover { transform: none; }   /* keep the underline cue, drop the lift */
  .domain-panel.is-active .domain-body { animation: none; }
}

@media (max-width: 640px) {
  .domain-split { flex-direction: column; min-height: 0; }
  .domain-panel { min-height: 200px; padding: 32px 24px; }
  /* Stacked layout: the divider runs along the top edge and fades left/right. */
  .domain-panel + .domain-panel::before {
    left: 0;
    right: 0;
    top: 0;
    bottom: auto;
    width: auto;
    height: 2px;
    background: linear-gradient(
      to right,
      transparent,
      var(--blue-bright) 18%,
      var(--blue-bright) 82%,
      transparent
    );
  }
  .domain-panel.is-collapsed { flex: 0 0 56px; min-height: 0; padding: 0; }
  .domain-panel.is-collapsed .domain-label { transform: translateY(-50%); }
  .domain-panel.is-active .domain-body { padding-top: clamp(52px, 14%, 72px); }
  .uc-grid { grid-template-columns: 1fr; gap: 28px; }
}

/* ===== Use-case cards (domain toggle) ===== */
.fn-icon { color: var(--text); margin-bottom: 12px; }
.fn-name {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--text);
  margin-bottom: 10px;
}
.fn-desc {
  font-family: var(--font-sans);
  font-size: var(--fs-base);
  line-height: 1.55;
  color: var(--text-muted);
  /* Fixed height for the description block so the metrics divider below starts
     at the same Y on every card in the row, regardless of copy length. Sized to
     fit the longest description at the 3-column desktop width. */
  min-height: 10.5em;
}

/* Deployment metrics on a use-case card: an accent figure with a muted note.
   A card can carry one or two (assortment shows categorization + stock). */
.fn-metrics {
  margin: 16px 0 0;
  padding-top: 16px;
  border-top: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: 12px;
}
/* Finance cards carry the same divider as retail but no figures yet; reserve a
   little room below it so the layout is stable when numbers are added later. */
.fn-metrics-empty { min-height: 3em; }
.fn-metric { margin: 0; }
.fn-stat {
  font-family: var(--font-mono);
  font-size: 1.75rem;
  font-weight: 600;
  line-height: 1.1;
  color: var(--accent);
}
.fn-stat-note {
  margin: 4px 0 0;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  line-height: 1.4;
  color: var(--text-muted);
}

/* Domain-split intro: two columns (retail left, finance right) that sit above
   and align with the two panels, replacing the single centered section lead.
   Width matches .domain-split / .spec-grid so the columns line up. */
.domain-intro {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 40px;
  max-width: 1080px;
  margin: -24px auto 40px;
  text-align: left;
  font-family: var(--font-sans);
}
.domain-intro p {
  margin: 0;
  font-size: var(--fs-md);
  line-height: 1.5;
  color: var(--text-secondary);
}
@media (max-width: 640px) {
  .domain-intro { grid-template-columns: 1fr; gap: 20px; }
}

/* ===== At a glance: model lineage spec cards ===== */
/* Four bordered cards (v1–v3 + flagship). Unlike the borderless use-case cards,
   these carry a light frame so the lineage reads as four distinct models. The
   name/desc min-heights keep the attribute dividers aligned across the row. */
.spec-grid {
  display: grid;
  /* Two-up so each card stays large enough to read comfortably. */
  grid-template-columns: repeat(2, 1fr);
  gap: 20px;
  width: 100%;
  /* Inset ~1cm per side off the 1156px .page column; shared verbatim with
     .domain-split so the two sections stay exactly equal width. */
  max-width: 1080px;
  margin-inline: auto;
}

.spec-card {
  display: flex;
  flex-direction: column;
  padding: 26px 24px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--bg-subtle);
  /* Each card opens its model-detail modal, so the whole card is the hit target. */
  position: relative;
  cursor: pointer;
  transition: border-color var(--t-hover) var(--ease-out),
              transform var(--t-hover) var(--ease-out),
              box-shadow var(--t-hover) var(--ease-out);
}
.spec-card:hover {
  border-color: var(--border-strong);
  transform: translateY(-2px);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.06);
}
.spec-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

/* Affordance that the card opens something; nudges on hover with the card. The
   card itself is the button, so this stays decorative (aria-hidden). */
.spec-plus {
  position: absolute;
  top: 14px;
  right: 16px;
  font-family: var(--font-mono);
  font-size: var(--fs-lg);
  line-height: 1;
  color: var(--text-faint);
  /* Matches the card's own lift: one hover, one pace. */
  transition: color var(--t-hover) var(--ease-out),
              transform var(--t-hover) var(--ease-out);
}
/* 45°, not 90°: a "+" is symmetric under a quarter turn, so rotate(90deg) left
   the glyph looking untouched and the hover cue never actually read. 45° turns
   it into an × — the same gesture as the FAQ and use-case markers. */
.spec-card:hover .spec-plus { color: var(--accent); transform: rotate(45deg); }

.spec-name {
  font-family: var(--font-mono);
  font-size: var(--fs-md);
  font-weight: 500;
  line-height: 1.3;
  color: var(--text);
  margin-bottom: 8px;
  /* Every model name fits one line at every card width, so no min-height is
     needed to keep the descriptions starting at one Y. */
  padding-right: 28px; /* clears the absolutely positioned .spec-plus */
}

.spec-desc {
  font-family: var(--font-sans);
  font-size: var(--fs-xs);
  line-height: 1.5;
  color: var(--text-muted);
  margin: 0 0 18px;
  min-height: 3em;   /* two lines: aligns the attribute divider across cards */
}

/* Attribute list: pushed to the card foot (margin-top:auto) so the divider sits
   at the same height on every card regardless of copy above it. */
.spec-attrs {
  margin: auto 0 0;
  padding-top: 16px;
  border-top: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.spec-attr { margin: 0; }
.spec-attr dt {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin-bottom: 3px;
}
.spec-attr dd {
  margin: 0;
  font-family: var(--font-mono);
  font-size: var(--fs-base);
  line-height: 1.4;
  color: var(--text);
}

@media (max-width: 640px) {
  .spec-grid { grid-template-columns: 1fr; gap: 16px; }
  .spec-desc { min-height: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .spec-card, .spec-plus { transition: none; }
  .spec-card:hover { transform: none; }
  .spec-card:hover .spec-plus { transform: none; }
}

/* Behavior-transfer section: two columns, narrative left, benchmark figure right,
   at the shared 1080px content width. */
.transfer-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 48px;
  max-width: 1080px;
  margin: 0 auto 36px;
  align-items: stretch;   /* text column matches the figure height */
}
/* Lead sentence + three headline stats beside the figure. Top-aligned so the
   first line sits level with the figure caption; one shared gap (28px) between
   the sentence and the first stat and between every stat. */
.transfer-grid-text {
  text-align: left;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  gap: 28px;
}
.transfer-lead {
  font-family: var(--font-sans);
  font-size: var(--fs-md);
  line-height: 1.55;
  color: var(--text-secondary);
  margin: 0;
}
.transfer-stats {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 28px;
}
.transfer-stat { display: flex; flex-direction: column; gap: 4px; }
.transfer-stat-num {
  font-family: var(--font-mono);
  font-size: clamp(1.75rem, 1.2rem + 2vw, 2.5rem);
  font-weight: 600;
  line-height: 1;
  color: var(--accent);
}
.transfer-stat-note {
  font-family: var(--font-sans);
  font-size: var(--fs-md);
  line-height: 1.4;
  color: var(--text-secondary);
}
/* Figure fills its grid column instead of the standalone half-width cap. */
.transfer-grid .bench-chart { max-width: none; margin: 0; }

/* Reproducible-results section: note + left-aligned CTA, cards stacked in the
   right grid column. */
.repro-datasets-label {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin-bottom: 8px;
}
.repro-datasets ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.repro-datasets li {
  position: relative;
  padding-left: 16px;
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  line-height: 1.4;
  color: var(--text-secondary);
}
.repro-datasets li::before {
  content: ">";
  position: absolute;
  left: 0;
  color: var(--accent);
}
.transfer-grid .bench-grid {
  grid-template-columns: 1fr;
  max-width: none;
  margin: 0;
  gap: 14px;
}
/* Shorter cards when stacked in the grid column. */
.transfer-grid .bench-card { padding: 14px 18px; gap: 3px; }
.transfer-grid .bench-stat { font-size: 1.4rem; }

.repro-try {
  font-family: var(--font-sans);
  font-size: var(--fs-sm);
  line-height: 1.5;
  color: var(--text-muted);
  margin: 0;
}
.repro-try a { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; }
@media (max-width: 760px) {
  .transfer-grid { grid-template-columns: 1fr; gap: 28px; }
}

/* ===== Benchmarks ===== */
/* Public finance/payments dataset results as stat cards, plus the request CTA.
   Width matches the other content blocks (1080px). */
.bench-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
  max-width: 1080px;
  margin: 0 auto;
}
.bench-card {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 24px 22px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--bg-subtle);
  text-align: left;
}
.bench-stat {
  font-family: var(--font-mono);
  font-size: 1.75rem;
  font-weight: 600;
  line-height: 1.1;
  color: var(--accent);
}
.bench-metric {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--text);
}
.bench-dataset {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--text-faint);
}
@media (max-width: 700px) { .bench-grid { grid-template-columns: 1fr; } }

.bench-note {
  max-width: 1080px;
  margin: 16px auto 0;
  font-family: var(--font-sans);
  font-size: var(--fs-xs);
  color: var(--text-faint);
  text-align: left;
}
.bench-invite {
  max-width: 640px;
  margin: 28px auto 20px;
  font-family: var(--font-sans);
  font-size: var(--fs-md);
  line-height: 1.5;
  color: var(--text-secondary);
  text-align: center;
}
.bench-actions { text-align: center; }

/* Benchmarks chart: recall vs. candidate-space size, with a recall@k toggle. */
.bench-chart { max-width: 560px; margin: 8px auto 36px; }
.bench-chart-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
  margin-bottom: 14px;
}
.bench-chart-cap { font-family: var(--font-mono); font-size: var(--fs-sm); color: var(--text); }
.bench-toggle {
  display: inline-flex;
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  overflow: hidden;
}
.bench-k {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--text-muted);
  background: transparent;
  padding: 6px 12px;
  cursor: pointer;
  transition: background var(--t-hover) var(--ease-out),
              color var(--t-hover) var(--ease-out);
}
.bench-k + .bench-k { border-left: 1px solid var(--border-strong); }
.bench-k:hover { color: var(--text); }
.bench-k.is-active { background: var(--accent); color: #fff; }

.bench-plot { width: 100%; }
.bench-svg { width: 100%; height: auto; display: block; }
.bench-grid-line { stroke: var(--border); stroke-width: 1; }
/* Axis text is bumped to --fs-sm because the SVG renders at ~half size. */
.bench-axis-label { font-family: var(--font-mono); font-size: var(--fs-sm); fill: var(--text-faint); }
.bench-axis-title { font-family: var(--font-mono); font-size: var(--fs-sm); fill: var(--text-muted); }

.bench-line { fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.bench-line--bgpt { stroke: var(--blue-bright); stroke-width: 3; }
.bench-line--seq { stroke: var(--purple-bright); }
.bench-line--twt { stroke: var(--orange-bright); }
.bench-line--gbt { stroke: var(--green-bright); }
.bench-line--pop { stroke: var(--text-faint); stroke-dasharray: 4 4; }
.bench-dot { fill: #fff; stroke-width: 2; }
.bench-dot--bgpt { stroke: var(--blue-bright); }
.bench-dot--seq { stroke: var(--purple-bright); }
.bench-dot--twt { stroke: var(--orange-bright); }
.bench-dot--gbt { stroke: var(--green-bright); }
.bench-dot--pop { stroke: var(--text-faint); }

.bench-legend {
  list-style: none;
  margin: 14px 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 8px 20px;
  justify-content: center;
}
.bench-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--text-muted);
}
.bench-swatch { width: 14px; height: 3px; border-radius: 2px; display: inline-block; }
.bench-swatch--bgpt { background: var(--blue-bright); }
.bench-swatch--seq { background: var(--purple-bright); }
.bench-swatch--twt { background: var(--orange-bright); }
.bench-swatch--gbt { background: var(--green-bright); }
.bench-swatch--pop { background: var(--text-faint); }

/* ===== Model detail modal ===== */
/* Standalone shell — deliberately NOT the signup .modal-card, whose 460px cap is
   defined later in this file and would win the cascade. Wide so the full paper
   summary + results fit without scrolling. */
.model-modal-overlay {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: rgba(17, 17, 17, 0.45);
  backdrop-filter: blur(2px);
  animation: mfade var(--t-state) var(--ease-out);
}
.model-modal-overlay[hidden] { display: none; }
.model-modal-card {
  position: relative;
  width: 100%;
  max-width: 760px;
  max-height: calc(100vh - 40px);
  overflow-y: auto;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 18px;
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.18);
  padding: 44px 48px;
  text-align: left;
  /* Same step as the overlay fade below it, so the scrim and the card arrive as
     one move (they used to be 0.2s vs 0.22s — close enough to look accidental,
     far enough apart that the scrim finished first). */
  animation: mpop var(--t-state) var(--ease-out);
}
@media (max-width: 560px) { .model-modal-card { padding: 28px 22px; } }
.model-modal-close {
  position: absolute;
  top: 16px;
  right: 18px;
  font-family: var(--font-mono);
  font-size: var(--fs-lg);
  line-height: 1;
  color: var(--text-faint);
  transition: color var(--t-hover) var(--ease-out);
}
.model-modal-close:hover { color: var(--text); }

.model-eyebrow {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 12px;
}
.model-title {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-lg);
  line-height: 1.3;
  color: var(--text);
  margin: 0 0 24px;
}
.model-section { margin-bottom: 24px; }
.model-subhead {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin: 0 0 10px;
}
.model-section p {
  font-family: var(--font-sans);
  font-size: var(--fs-base);
  line-height: 1.6;
  color: var(--text-secondary);
  margin: 0 0 12px;
}
.model-section p:last-child { margin-bottom: 0; }
.model-results {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.model-results li {
  font-family: var(--font-sans);
  font-size: var(--fs-base);
  line-height: 1.5;
  color: var(--text-secondary);
}
.model-stat { color: var(--accent); font-weight: 600; }
.model-modal-link {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: var(--fs-base);
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.model-placeholder {
  font-family: var(--font-sans);
  font-size: var(--fs-base);
  color: var(--text-muted);
  margin: 0;
}

/* ===== FAQ ===== */
.faq-section { max-width: 820px; margin: 0 auto; }
.faq-list { border-top: 1px solid var(--border); }

.faq-item { border-bottom: 1px solid var(--border); }

.faq-q {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  list-style: none;
  padding: 22px 4px;
  font-family: var(--font-mono);
  font-size: var(--fs-lg);
  color: var(--text);
  cursor: pointer;
}
.faq-q::-webkit-details-marker { display: none; }

.faq-q::after {
  content: '+';
  flex-shrink: 0;
  font-size: var(--fs-lg);
  font-weight: 300;
  line-height: 1;
  color: var(--text-muted);
  /* --t-open, not a step of its own: the marker turns for exactly as long as the
     answer takes to open, so the two read as one gesture rather than a fast tick
     followed by a slower panel. */
  transition: transform var(--t-open) var(--ease-out);
}
.faq-item[open] .faq-q::after { transform: rotate(45deg); }

.faq-a { padding: 0 4px 24px; }
.faq-a p {
  font-family: var(--font-sans);
  font-size: var(--fs-md);
  line-height: 1.65;
  color: var(--text-secondary);
  max-width: 68ch;
}
.faq-a a { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; }

/* --- Animated disclosure (driven by behaviorgpt-ui.js) ---
   Native <details> has no open/close animation, so the site's only real
   accordion used to snap while its marker eased — the one place the page most
   obviously broke its own pace. .js-faq is added by that script only when it
   takes over, so without JS (or under reduced motion) none of this applies and
   native <details name="faq"> keeps working exactly as before. */
.faq-list.js-faq .faq-a {
  height: 0;
  overflow: hidden;
  opacity: 0;
  /* The animated box cannot keep its own bottom padding: this is a border-box, so
     at height:0 that 24px would still hold the answer open by 24px. The inset
     moves to the content below, where it counts toward the scrollHeight JS
     measures. */
  padding-bottom: 0;
  /* Height is a box resizing, so it takes the size curve; the copy fades on the
     arrival curve. Both on --t-open, matching the marker above. */
  transition: height var(--t-open) var(--ease-io),
              opacity var(--t-open) var(--ease-out);
}
.faq-list.js-faq .faq-a > :last-child { padding-bottom: 24px; }

/* .is-open is set the instant a gesture starts, whereas [open] stays true for the
   whole length of a close (the element must remain rendered to animate shut). So
   in the JS path the marker follows .is-open — otherwise it would sit rotated and
   snap back only after the panel had finished closing. Equal specificity to the
   [open] reset above, and later in source, so it wins. */
.faq-list.js-faq .faq-item[open] .faq-q::after { transform: none; }
.faq-list.js-faq .faq-item.is-open .faq-q::after { transform: rotate(45deg); }
.faq-list.js-faq .faq-item.is-open .faq-a { opacity: 1; }

/* ===== Signup modal ===== */
.modal-overlay {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: rgba(17, 17, 17, 0.45);
  backdrop-filter: blur(2px);
  animation: mfade var(--t-state) var(--ease-out);
}
.modal-overlay[hidden] { display: none; }

@keyframes mfade { from { opacity: 0; } to { opacity: 1; } }

.modal-card {
  position: relative;
  width: 100%;
  max-width: 460px;
  max-height: calc(100vh - 40px);
  overflow-y: auto;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 18px;
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.18);
  padding: 40px;
  animation: mpop var(--t-state) var(--ease-out);
}

@keyframes mpop { from { opacity: 0; transform: translateY(8px) scale(.98); } to { opacity: 1; transform: none; } }

@media (max-width: 480px) { .modal-card { padding: 28px 22px; } }

/* The glyph is a 12x20 x — a target you have to aim at, and the one control
   that gets a visitor out of a modal. Give it a real 44px box (the card's own
   padding absorbs it) while the x stays optically where it was. */
.modal-close {
  position: absolute;
  top: 16px;
  right: 18px;
  font-family: var(--font-mono);
  font-size: var(--fs-lg);
  line-height: 1;
  color: var(--text-faint);
  transition: color var(--t-hover) var(--ease-out);
}
.modal-close:hover { color: var(--text); }

.modal-title {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-lg);
  text-align: center;
  color: var(--text);
  margin-bottom: 28px;
}

/* Below ~420px the centred title reaches the close box and the two used to
   overlap outright. Drop the title under the close rather than reserving side
   padding for it: at this width that padding forces "Sign up for BehaviorGPT"
   onto two ragged lines, which costs the same vertical space and reads worse. */
@media (max-width: 480px) {
  .modal-title { margin-top: 24px; }
}

.mrow {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
  margin-bottom: 18px;
}
@media (max-width: 420px) { .mrow { grid-template-columns: 1fr; } }

.mfield { display: flex; flex-direction: column; margin-bottom: 18px; }
.mrow .mfield { margin-bottom: 0; }

.mfield label {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--text);
  margin-bottom: 8px;
}

.mfield input,
.mfield select {
  width: 100%;
  font-family: var(--font-sans);
  font-size: var(--fs-sm);
  color: var(--text);
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 9px;
  padding: 12px 14px;
  transition: border-color var(--t-hover) var(--ease-out),
              box-shadow var(--t-hover) var(--ease-out);
}
.mfield input::placeholder { color: var(--text-faint); }
/* Safari on iOS zooms the whole page the moment focus lands in a field under
   16px, which throws the modal off-centre and leaves the visitor pinched in
   mid-signup with no way back. 16px is the threshold, so the fields take it on
   phones; the labels stay on the type scale. */
@media (max-width: 640px) {
  .mfield input,
  .mfield select { font-size: 1rem; }
}
.mfield input:focus,
.mfield select:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(47, 114, 230, 0.2);
}
.mfield input[aria-invalid="true"],
.mfield select[aria-invalid="true"] {
  border-color: var(--error);
  box-shadow: 0 0 0 3px rgba(213, 63, 48, 0.16);
}

/* Native select: strip the platform chrome and draw a caret so it matches
   the text inputs. */
.mfield select {
  appearance: none;
  -webkit-appearance: none;
  cursor: pointer;
  padding-right: 40px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23697586' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 14px center;
}
/* Placeholder option (empty value) reads as faint, like an input placeholder. */
.mfield select:invalid { color: var(--text-faint); }

.field-error { font-size: var(--fs-xs); color: var(--error); margin-top: 6px; }
.field-error[hidden] { display: none; }

.form-error { font-size: var(--fs-xs); color: var(--error); text-align: center; margin: 4px 0 -4px; }
.form-error[hidden] { display: none; }

.btn-continue {
  width: 100%;
  background: var(--black);
  color: #fff;
  border-radius: 9px;
  padding: 14px;
  font-family: var(--font-mono);
  font-size: var(--fs-base);
  font-weight: 600;
  margin-top: 4px;
  transition: background-color var(--t-hover) var(--ease-out);
}
.btn-continue:hover { background: #000; }

.modal-fineprint {
  margin: 14px 0 0;
  font-size: var(--fs-xs);
  line-height: 1.5;
  color: var(--text-faint);
  text-align: center;
}

/* Honeypot — kept in the DOM for bots, removed from view and the tab order
   for humans and assistive tech. Do not use display:none (some bots skip it). */
.hp-field {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* success state */
.modal-success { text-align: center; padding: 12px 0; }
.modal-success[hidden] { display: none; }
.success-check {
  width: 56px;
  height: 56px;
  margin: 4px auto 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--accent-soft);
  color: var(--accent);
}
.modal-success-sub {
  font-size: var(--fs-sm);
  line-height: 1.6;
  color: var(--text-muted);
  max-width: 34ch;
  margin: 0 auto 24px;
}

/* ===== Reduced motion: the remaining movement =====
   The section-local blocks above already cover reveals, the tree, the domain
   split and the spec cards. These are the pieces that were still moving for
   reduced-motion visitors: both modals arrived with a translate+scale pop, and
   every marker still spun.

   Colour and background transitions are deliberately left alone — they convey no
   movement, and stripping them makes hover states flicker rather than settle. The
   end states here are all preserved; only the travel between them is dropped, so
   a turned marker still reads as turned. */
@media (prefers-reduced-motion: reduce) {
  .modal-overlay,
  .modal-card,
  .model-modal-overlay,
  .model-modal-card { animation: none; }

  .btn-arrow,
  .usecase-marker,
  .faq-q::after { transition: none; }

  .btn-pill:hover .btn-arrow { transform: none; }
}
