

/* ------------------------------------------------------------------ */
/* Brand faces, served from this origin.                               */
/* The privacy page tells a visitor the analytics cookie is the full   */
/* list of what leaves their browser. Loading the faces from Google    */
/* Fonts contradicted that: fonts.googleapis.com and fonts.gstatic.com */
/* both saw the visitor's IP and user agent before any consent choice  */
/* existed. Both families are SIL Open Font License 1.1, so the files  */
/* ship with the site instead (public/fonts/, subsets and unicode      */
/* ranges exactly as Google served them, so a Latin-only reader still  */
/* downloads only the Latin subset).                                   */
/* ------------------------------------------------------------------ */

/* Michroma - SIL OFL 1.1 */
@font-face {
  font-family: 'Michroma';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/michroma-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308,
    U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113,
    U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Michroma';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/michroma-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304,
    U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* Space Grotesk - SIL OFL 1.1. One variable file per subset covers the
   300-700 range the site uses. */
@font-face {
  font-family: 'Space Grotesk';
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url('/fonts/space-grotesk-vietnamese.woff2') format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0,
    U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}

@font-face {
  font-family: 'Space Grotesk';
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url('/fonts/space-grotesk-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308,
    U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113,
    U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Space Grotesk';
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url('/fonts/space-grotesk-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304,
    U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* deslop-ignore-file 02 06 09 10 32 - brand-kit wordmark clip, metallic CTA ramp (brand treatment), real link underlines, informative micro-labels, confirmed brand face (BRAND-GUIDELINES.md) */
/* ------------------------------------------------------------------ */
/* Agent Chakra brand tokens. Source: infra/branding/brand-kit/        */
/* BRAND-GUIDELINES.md (confirmed 2026-07-21). Dark is the brand       */
/* default; a first-class light theme derives from the same system.    */
/* Themes are driven by [data-theme] on <html>, stamped pre-paint by   */
/* the inline script in Base.astro (localStorage, else OS preference). */
/* Token naming is semantic (role-based), never per-section.           */
/* ------------------------------------------------------------------ */



:root {
  /* ---- Semantic color tokens: DARK (brand default) ---- */
  color-scheme: dark;

  --bg-ground: #030508; /* Obsidian Void */
  --bg-surface: #090d14; /* cards, elevated panels */
  --bg-raised: rgba(9, 13, 20, 0.8); /* success cards, overlays */
  --bg-input: rgba(3, 5, 8, 0.65);

  --text-primary: #cbd5e1; /* Chrome Platinum: body copy */
  --text-strong: #e2e8f0; /* headings, leads */
  --text-max: #f1f5f9; /* hover/max emphasis */
  /* Measured on this ground: AA compresses the muted ramp, so secondary sits
     high enough to stay a visible tier above faint (5.9 vs 4.6 on surface). */
  --text-secondary: #92a1b6; /* muted slate, AA on ground and card surface */
  --text-faint: #6c7d92; /* placeholders, legal fine print */

  --accent: #24a1de; /* Signal Cyan: THE accent */
  --accent-text: #24a1de; /* accent used as text/link color */
  --accent-ink: #04121c; /* text on accent fills */

  --border-hair: rgba(255, 255, 255, 0.04);
  --border-soft: rgba(255, 255, 255, 0.07);
  --border-accent: rgba(36, 161, 222, 0.18);
  --btn-edge: rgba(255, 255, 255, 0.12);

  --marker-mute: #334155; /* inactive dots, bullets, chevrons */
  --icon-mute: #94a3b8; /* line icons */

  --selection-bg: rgba(36, 161, 222, 0.32);
  --selection-text: #f1f5f9;

  /* Metallic wordmark gradient stops (brand kit chrome shine) */
  --wm-edge: #475569;
  --wm-mid: #cbd5e1;
  --wm-peak: #ffffff;

  /* Logomark "chrome liquid" stroke gradient stops */
  --chrome-lo: #334155;
  --chrome-hi: #e2e8f0;
  --chrome-mid: #64748b;

  /* CTA plate: the accent rendered as metal, in the wordmark's own vocabulary
     (edge -> mid -> peak -> mid -> edge, swept by background-position). Every
     stop is measured against --accent-ink: the darkest one, --cta-edge, is
     4.73:1, so the label holds AA anywhere under the sweep. One ramp for both
     themes, because the plate is an accent fill on both. */
  --cta-edge: #1b87bd;
  --cta-mid: #24a1de;
  --cta-peak: #8ed7f7;

  /* Raised-plate relief: light caught on the top bevel, ink on the bottom, a
     contact shadow, and an accent cast on the ground. Held in tokens because
     :focus-visible has to re-append the relief (see the focus rule). */
  --cta-relief:
    inset 0 1px 0 rgba(255, 255, 255, 0.5), inset 0 -1px 0 rgba(4, 18, 28, 0.28),
    0 1px 2px rgba(2, 8, 20, 0.3), 0 10px 22px -12px color-mix(in srgb, var(--accent) 75%, transparent);
  --cta-relief-hover:
    inset 0 1px 0 rgba(255, 255, 255, 0.6), inset 0 -1px 0 rgba(4, 18, 28, 0.28),
    0 1px 2px rgba(2, 8, 20, 0.32), 0 14px 30px -12px color-mix(in srgb, var(--accent) 90%, transparent);
  --cta-relief-pressed:
    inset 0 2px 4px rgba(4, 18, 28, 0.42), inset 0 -1px 0 rgba(255, 255, 255, 0.14);

  /* ---- Legacy aliases (older component styles reference these) ---- */
  --bg-void: var(--bg-ground);
  --surface-card: var(--bg-surface);
  --text-main: var(--text-primary);
  /* Legacy accent alias points at the TEXT-safe accent: identical to the pure
     accent on dark, darkened for AA contrast on light. Fills and glows use
     var(--accent) directly. */
  --signal-cyan: var(--accent-text);
  --text-muted: var(--text-secondary);
  --border-glow: var(--border-accent);
  --border-mute: var(--border-hair);

  /* Motion tokens (emil-design-eng / animation-systems skills) */
  --ease-out-strong: cubic-bezier(0.23, 1, 0.32, 1);
  --ease-in-out-strong: cubic-bezier(0.77, 0, 0.175, 1);
  /* Recipe-name aliases (K12 round 2b research §b-5): same curves, the names
     the shared recipes use. New code may use either; they never diverge. */
  --ease-out: var(--ease-out-strong);
  --ease-in-out: var(--ease-in-out-strong);
  --dur-micro: 160ms;
  --dur-ui: 220ms;

  /* Card treatment (K12 round 2b research §b-1/b-2). Dark grounds swallow
     drop shadows, so dark cards read by a 1px lit top edge plus a soft
     ambient; light theme overrides this with a layered shadow ramp. */
  --card-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.06),
    0 8px 24px rgba(0, 0, 0, 0.35);

  /* Focus ring (research §b-7): box-shadow, never outline.
     Two solid rings, not one translucent one. The old single 60% cyan ring
     measured 3.09:1 on the ground and 1.00:1 around an accent-filled button,
     which is the element people tab to most. The inner ground-colored ring
     separates the indicator from whatever the control is painted in, so the
     outer ring is always measured against the page: solid cyan is 7.02:1 on
     the ground and 6.70:1 on a card. */
  --focus-ring:
    0 0 0 2px var(--bg-ground),
    0 0 0 4px var(--accent);

  /* Header hairline: only visible once the bar gains its scrolled backdrop. */
  --header-hairline: rgba(255, 255, 255, 0.06);

  /* Fluid type scale */
  --text-hero: clamp(2.4rem, 1.2rem + 5.2vw, 4.6rem);
  --text-h2: clamp(1.7rem, 1.05rem + 2.4vw, 2.7rem);
  --text-h3: clamp(1.15rem, 1rem + 0.7vw, 1.45rem);
  --text-body: clamp(1rem, 0.95rem + 0.2vw, 1.09rem);
}

/* ---- Semantic color tokens: LIGHT ---- */
html[data-theme='light'] {
  color-scheme: light;

  --bg-ground: #f7f9fb;
  --bg-surface: #ffffff;
  --bg-raised: #ffffff;
  --bg-input: #ffffff;

  --text-primary: #334155;
  --text-strong: #0b1220; /* ink */
  --text-max: #030508;
  --text-secondary: #5b6675; /* muted, AA on ground and card */
  --text-faint: #64748b; /* AA on the light ground */

  --accent: #24a1de; /* Signal Cyan stays THE accent */
  --accent-text: #0f77b4; /* darkened cyan for AA text/links on light */
  --accent-ink: #04121c;

  --border-hair: #e2e8f0; /* hairline */
  --border-soft: #d6dee8;
  --border-accent: rgba(36, 161, 222, 0.38);
  --btn-edge: rgba(4, 18, 28, 0.1);

  --marker-mute: #94a3b8;
  --icon-mute: #64748b;

  --selection-bg: rgba(36, 161, 222, 0.25);
  --selection-text: #0b1220;

  /* Wordmark: darker chrome so the metallic treatment stays legible */
  --wm-edge: #0b1220;
  --wm-mid: #475569;
  --wm-peak: #8fa3b8;

  /* Logomark chrome, darkened for a light ground */
  --chrome-lo: #64748b;
  --chrome-hi: #1e293b;
  --chrome-mid: #475569;

  /* The CTA plate keeps its ramp on both themes (it is an accent fill on
     both), but the cast under it thins out: a deep shadow that reads as
     depth on the void reads as grime on white. */
  --cta-relief:
    inset 0 1px 0 rgba(255, 255, 255, 0.55), inset 0 -1px 0 rgba(4, 18, 28, 0.22),
    0 1px 2px rgba(2, 8, 20, 0.14), 0 10px 20px -14px color-mix(in srgb, var(--accent) 60%, transparent);
  --cta-relief-hover:
    inset 0 1px 0 rgba(255, 255, 255, 0.62), inset 0 -1px 0 rgba(4, 18, 28, 0.22),
    0 1px 2px rgba(2, 8, 20, 0.16), 0 14px 26px -14px color-mix(in srgb, var(--accent) 72%, transparent);

  /* Light surfaces carry depth by a layered ramp: each layer roughly doubles
     offset and blur, all low alpha (research §b-2). */
  --card-shadow:
    0 1px 2px rgba(2, 8, 20, 0.06),
    0 2px 8px rgba(2, 8, 20, 0.06),
    0 12px 32px rgba(2, 8, 20, 0.08);

  /* No alpha of --accent can reach 3:1 on this ground (solid #24a1de measures
     2.75), so the light ring uses the darkened cyan instead: solid #0f77b4 is
     4.61:1 on the ground and 4.86:1 on a card. */
  --focus-ring:
    0 0 0 2px var(--bg-ground),
    0 0 0 4px var(--accent-text);

  --header-hairline: rgba(2, 8, 20, 0.08);
}

html {
  background: var(--bg-ground);
  color: var(--text-primary);
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  scroll-behavior: smooth;
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
}

/* Horizontal-scroll regression guard: the page never scrolls sideways.
   Applied to both html and body; individual offenders are also fixed at
   the source (transform reveals, absolute rails, wide embeds). */
html,
body {
  overflow-x: clip;
}

body {
  font-size: var(--text-body);
  line-height: 1.65;
}

/* Anchor targets land clear of the sticky header (menu links target section
   and heading ids). */
section[id],
h2[id] {
  scroll-margin-top: 5.5rem;
}

/* Grain overlay (research §b-3): a static feTurbulence tile kills banding and
   the flat-vector look on the dark ground. Pure CSS background, no canvas, no
   script; position fixed so scrolling never repaints it. Dark theme only: the
   light ground needs no help and must not pick up visible noise. */
html:not([data-theme='light']) body::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 90;
  pointer-events: none;
  opacity: 0.04;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 160px 160px;
}

/* Media and wide content can never force the page wider than the viewport. */
img,
svg,
video,
iframe {
  max-width: 100%;
}

pre,
table {
  max-width: 100%;
  overflow-x: auto;
}

::selection {
  background: var(--selection-bg);
  color: var(--selection-text);
}

/* Focus rings via box-shadow, never outline (outline ignores radius;
   research §b-7). :where() keeps specificity at zero so any component-level
   focus treatment (e.g. the waitlist input) still wins. */
:where(a, button, summary, [role='button']):focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
  border-radius: 6px;
}

/* ---------------- Display / wordmark ---------------- */

.wordmark {
  font-family: 'Michroma', sans-serif;
  text-transform: uppercase;
  letter-spacing: 0.32em;
  /* Metallic logotype gradient with slow shine (brand kit). The stops are
     theme tokens: chrome-platinum on dark, darker chrome on light. */
  background-image: linear-gradient(
    100deg,
    var(--wm-edge) 0%,
    var(--wm-mid) 30%,
    var(--wm-peak) 50%,
    var(--wm-mid) 70%,
    var(--wm-edge) 100%
  );
  background-size: 220% 100%;
  background-clip: text;
  -webkit-background-clip: text;
  color: transparent;
}

@media (prefers-reduced-motion: no-preference) {
  /* .wordmark-still opts out: the header is chrome, not stage (K12 2b). */
  .wordmark:not(.wordmark-still) {
    animation: wordmark-shine 8s linear infinite;
  }

  /* Paused by motion.js when scrolled out of view. */
  .wordmark.is-offscreen {
    animation-play-state: paused;
  }
}

@keyframes wordmark-shine {
  from {
    background-position: 200% 0;
  }
  to {
    background-position: -20% 0;
  }
}

.numeral {
  font-family: 'Michroma', sans-serif;
  text-transform: uppercase;
  letter-spacing: 0.22em;
  color: var(--text-secondary);
  font-size: 0.72rem;
}

/* Logomark SVG chrome gradient: stop colors follow the theme. */
.lm-stop-lo {
  stop-color: var(--chrome-lo);
}
.lm-stop-hi {
  stop-color: var(--chrome-hi);
}
.lm-stop-mid {
  stop-color: var(--chrome-mid);
}

/* ---------------- Section primitives ---------------- */

.section {
  max-width: 72rem;
  margin-inline: auto;
  padding-inline: clamp(1.25rem, 4vw, 2.5rem);
  padding-block: clamp(3.5rem, 8vw, 6.5rem);
}

/* Phones read the same ladder with less dead air (r16, V2 6.1/6.8). */
@media (max-width: 47.99rem) {
  .section {
    padding-block: clamp(2.4rem, 9vw, 3.2rem);
  }
}

.section-narrow {
  max-width: 52rem;
}

.eyebrow {
  font-size: 0.88rem;
  font-weight: 500;
  letter-spacing: 0.02em;
  color: var(--text-secondary);
}

/* Michroma micro-label: quiet wayfinding above each act of the narrative.
   A short cyan tick anchors it; the label itself stays almost silent. */
.section-label {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  font-family: 'Michroma', sans-serif;
  font-size: 0.7rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin-bottom: 1.4rem;
}

.section-label::before {
  content: '';
  width: 1.4rem;
  height: 1.5px;
  background: var(--accent);
  flex-shrink: 0;
}

/* Pull-quote treatment for the turn-line and closing-line moments: a short
   cyan rule above, larger light type. Scale and space, not decoration. */
.pull-quote {
  position: relative;
  padding-top: 1.3rem;
  font-size: clamp(1.15rem, 1rem + 0.8vw, 1.45rem);
  font-weight: 300;
  line-height: 1.5;
  color: var(--text-strong);
}

.pull-quote::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  width: 2.6rem;
  height: 1.5px;
  background: var(--accent);
}

.eyebrow .tick {
  color: var(--accent-text);
}

h1,
h2,
h3 {
  font-weight: 500;
  letter-spacing: -0.015em;
  line-height: 1.12;
  color: var(--text-strong);
  text-wrap: balance;
}

.prose-muted {
  color: var(--text-secondary);
}

a {
  transition: color var(--dur-micro) ease;
}

/* ---------------- Buttons ---------------- */

/* One primary-button language for the whole site. A flat accent rectangle is
   what every framework ships; this is a struck metal plate in the brand's own
   vocabulary, lit by the same slow sweep that runs across the wordmark. .btn is
   the hand-written version and factory-form's .ff-btn is the one the form stack
   builds at runtime, so both carry the identical treatment: a primary button
   should not change character depending on which file drew it. */
.btn,
factory-form .ff-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  flex: 0 0 auto;
  width: auto;
  font: inherit;
  font-weight: 500;
  font-size: 0.95rem;
  padding: 0.72rem 1.4rem;
  border-radius: 8px;
  cursor: pointer;
  color: var(--accent-ink);
  /* A hair of light above the glyphs, on the same axis as the top bevel, so
     the label reads as struck into the plate rather than laid on it. */
  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.18);
  border: 1px solid color-mix(in srgb, var(--accent-ink) 32%, transparent);
  box-shadow: var(--cta-relief);
  /* Solid fallback under the ramp: if background-image is dropped, the button
     is still an accent fill with legible ink, never a transparent box. */
  background-color: var(--accent);
  /* Two layers: a fixed vertical bevel wash, then the horizontal metal ramp
     the shine travels. Only the ramp's position ever moves. */
  background-image:
    linear-gradient(
      180deg,
      rgba(255, 255, 255, 0.26) 0%,
      rgba(255, 255, 255, 0) 48%,
      rgba(4, 18, 28, 0.16) 100%
    ),
    linear-gradient(
      100deg,
      var(--cta-edge) 0%,
      var(--cta-mid) 30%,
      var(--cta-peak) 50%,
      var(--cta-mid) 70%,
      var(--cta-edge) 100%
    );
  background-size:
    100% 100%,
    220% 100%;
  background-position:
    0 0,
    50% 0;
  background-repeat: no-repeat;
  transition:
    transform var(--dur-micro) var(--ease-out-strong),
    box-shadow var(--dur-micro) ease;
}

@media (prefers-reduced-motion: no-preference) {
  /* Same mechanism and period as the wordmark: the brand has one shine, and
     the CTA is the second place it appears. */
  .btn,
  factory-form .ff-btn {
    animation: cta-shine 8s linear infinite;
  }

  /* Paused by motion.js on the same observer that pauses .wordmark. */
  .btn.is-offscreen,
  factory-form .ff-btn.is-offscreen {
    animation-play-state: paused;
  }
}

@keyframes cta-shine {
  from {
    background-position:
      0 0,
      200% 0;
  }
  to {
    background-position:
      0 0,
      -20% 0;
  }
}

@media (hover: hover) and (pointer: fine) {
  /* Hover accelerates the metal instead of raising brightness: brightness on a
     gradient flattens it toward white, which is the opposite of the effect. */
  .btn:hover,
  factory-form .ff-btn:hover {
    animation-duration: 2.6s;
    box-shadow: var(--cta-relief-hover);
    transform: none;
  }
}

/* Press sinks the plate into its own shadow. A raised object that scales does
   not read as pressed; one that drops a pixel and loses its cast does. */
.btn:active,
factory-form .ff-btn:active {
  transform: translateY(1px);
  box-shadow: var(--cta-relief-pressed);
}

/* The global :focus-visible rule sets box-shadow outright, which would erase
   the relief. Re-append it, ring first so the ring paints over the cast, and
   restate the 8px radius the global rule would otherwise pull down to 6px. */
.btn:focus-visible,
factory-form .ff-btn:focus-visible {
  border-radius: 8px;
  box-shadow: var(--focus-ring), var(--cta-relief);
}

factory-form .ff-btn:disabled {
  opacity: 0.6;
  cursor: default;
  animation: none;
}

/* ---------------- Theme toggle (header) ---------------- */

.theme-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 8px;
  border: 1px solid var(--border-soft);
  background: transparent;
  color: var(--text-secondary);
  cursor: pointer;
  transition:
    color var(--dur-micro) ease,
    border-color var(--dur-micro) ease,
    transform var(--dur-micro) var(--ease-out-strong);
}

@media (hover: hover) and (pointer: fine) {
  .theme-toggle:hover {
    color: var(--text-strong);
    border-color: var(--border-accent);
  }
}

.theme-toggle:active {
  transform: scale(0.94);
}

.theme-toggle svg {
  width: 1.05rem;
  height: 1.05rem;
}

/* Show the icon of the theme you would switch TO. */
.theme-toggle .icon-sun {
  display: block;
}
.theme-toggle .icon-moon {
  display: none;
}
html[data-theme='light'] .theme-toggle .icon-sun {
  display: none;
}
html[data-theme='light'] .theme-toggle .icon-moon {
  display: block;
}

/* ---------------- Long-form pages (manifesto, privacy, terms) -------- */

.page-prose h1 {
  font-size: var(--text-h2);
  margin-bottom: 0.6rem;
}

.page-prose .page-updated {
  font-size: 0.85rem;
  color: var(--text-secondary);
  margin-bottom: 2.4rem;
}

.page-prose h2 {
  font-size: 1.25rem;
  margin: 2.4rem 0 0.7rem;
}

.page-prose h3 {
  font-size: 1.02rem;
  margin: 1.6rem 0 0.5rem;
}

.page-prose p {
  color: var(--text-primary);
  margin-bottom: 1rem;
  max-width: 46rem;
}

.page-prose .lede {
  font-size: clamp(1.08rem, 1rem + 0.5vw, 1.3rem);
  font-weight: 300;
  line-height: 1.6;
  color: var(--text-strong);
}

.page-prose ul,
.page-prose ol {
  margin: 0 0 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  max-width: 46rem;
}

.page-prose li {
  color: var(--text-primary);
  padding-left: 1.15rem;
  position: relative;
}

.page-prose li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.62em;
  width: 0.4rem;
  height: 1.5px;
  background: var(--accent);
}

.page-prose a {
  color: var(--accent-text);
  text-decoration: underline;
  text-underline-offset: 0.15em;
}

@media (hover: hover) and (pointer: fine) {
  .page-prose a:hover {
    color: var(--text-strong);
  }
}

.page-prose blockquote {
  border-left: 1.5px solid var(--accent);
  padding-left: clamp(1rem, 3vw, 1.6rem);
  margin: 1.6rem 0;
  font-size: clamp(1.05rem, 1rem + 0.4vw, 1.25rem);
  font-weight: 300;
  color: var(--text-strong);
  max-width: 44rem;
}

.page-prose strong {
  color: var(--text-strong);
  font-weight: 500;
}

/* ---------------- Motion foundation ---------------- */
/* Elements opted into JS reveals are hidden only when the motion system
   has actually booted (html.has-motion). No-JS and reduced-motion users
   always see static content.
   opacity, never visibility: a visibility:hidden element cannot take focus,
   which took every control below the hero out of the tab order until it was
   scrolled into view. Transparent-but-present keeps focus order intact, and
   the browser's scroll-into-view on focus fires the reveal. */

html.has-motion [data-reveal],
html.has-motion [data-reveal-item],
html.has-motion [data-hero-seq] {
  opacity: 0;
}

@media (prefers-reduced-motion: reduce) {
  html.has-motion [data-reveal],
  html.has-motion [data-reveal-item],
  html.has-motion [data-hero-seq] {
    opacity: 1;
  }
}

/* ---------------- factory-form brand theme ---------------- */
/* The component ships theme-adaptive defaults; these host tokens pin it
   to the Agent Chakra semantic palette (both themes). */

factory-form {
  display: block;
  /* Host tokens win over the component's adaptive fallbacks. */
  --brand-color: var(--accent);
  --white-color: var(--accent-ink);
  --primary-text-color: var(--text-strong);
  --secondary-text-color: var(--text-secondary);
  --muted-text-color: var(--text-faint);
  --divider-color: var(--border-soft);
  --background-elevated-color: var(--bg-input);
}

factory-form .ff-form {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.6rem;
}

factory-form .ff-field {
  flex: 1 1 260px;
  margin: 0;
  order: 1;
  min-width: 0;
}

/* Email + button share the first row; Turnstile and meta rows follow. */
factory-form .ff-form > .ff-btn {
  order: 2;
}

factory-form .cf-turnstile {
  order: 3;
  margin-top: 0.2rem;
  /* Reserve the widget's rendered height (65px, size=flexible) up front so
     nothing shifts when the iframe mounts, and no stray gap reads as broken. */
  min-height: 65px;
  overflow: clip;
  max-width: 100%;
}

/* The frame is drawn only once the widget is actually there. Bordering the
   empty reservation would show an unexplained empty box to anyone on a slow
   connection, or permanently to anyone whose network blocks the widget. */
factory-form .cf-turnstile:has(iframe) {
  border: 1px solid var(--border-hair);
  border-radius: 8px;
}

factory-form .ff-error {
  order: 4;
}

factory-form .ff-privacy {
  order: 5;
}

factory-form .ff-field.ff-hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

factory-form .ff-label {
  display: block;
  font-size: 0.78rem;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-secondary);
  margin-bottom: 0.4rem;
}


/* Phone widths: the stacked form reads as designed, not squeezed (r15, 6.3);
   controls keep real touch targets (r15, 6.7). */
@media (max-width: 47.99rem) {
  factory-form .ff-form {
    flex-direction: column;
    align-items: stretch;
  }

  factory-form .ff-form .btn {
    width: 100%;
    min-height: 2.9rem;
  }

  .theme-toggle {
    width: 2.75rem;
    height: 2.75rem;
  }
}

factory-form .ff-input {
  width: 100%;
  background: var(--bg-input);
  border: 1px solid var(--border-soft);
  border-radius: 8px;
  color: var(--text-strong);
  font: inherit;
  padding: 0.72rem 0.9rem;
  transition:
    border-color var(--dur-micro) ease,
    box-shadow var(--dur-micro) ease;
}

factory-form .ff-input::placeholder {
  color: var(--text-faint);
}

factory-form .ff-input:focus {
  outline: none;
  border-color: color-mix(in srgb, var(--accent) 55%, transparent);
  box-shadow: var(--focus-ring);
}

/* The waitlist button's own styling lives with .btn in the Buttons section:
   it is the same primary button, so it is defined once. What used to sit here
   was a private copy that drifted into a second, flatter template. */

factory-form .ff-error {
  flex-basis: 100%;
  margin: 0.15rem 0 0;
  font-size: 0.88rem;
  color: #e5484d;
}

html:not([data-theme='light']) factory-form .ff-error {
  color: #f0a8a8;
}

factory-form .ff-privacy {
  flex-basis: 100%;
  margin: 0.35rem 0 0;
  font-size: 0.85rem;
  font-weight: 300;
  color: var(--text-secondary);
}

factory-form .cf-turnstile {
  flex-basis: 100%;
}

factory-form .ff-success {
  align-items: flex-start;
  text-align: left;
  gap: 0;
  border: 1px solid var(--border-accent);
  background: var(--bg-raised);
  border-radius: 12px;
  padding: 1.4rem 1.5rem;
  box-shadow: var(--card-shadow);
}

factory-form .ff-success-icon {
  background: color-mix(in srgb, var(--accent) 10%, transparent);
  font-size: 1rem;
}

factory-form .ff-success-icon {
  width: 2rem;
  height: 2rem;
  display: grid;
  place-items: center;
  border-radius: 999px;
  border: 1px solid var(--border-accent);
  color: var(--accent-text);
  margin-bottom: 0.7rem;
}

factory-form .ff-success-title {
  font-size: 1.1rem;
  font-weight: 500;
  color: var(--text-strong);
  margin: 0 0 0.35rem;
}

factory-form .ff-success-body {
  margin: 0;
  color: var(--text-secondary);
  font-size: 0.95rem;
}

@media (prefers-reduced-motion: no-preference) {
  factory-form .ff-success:not([hidden]) {
    animation: ff-success-in 260ms var(--ease-out-strong);
  }
}

@keyframes ff-success-in {
  from {
    opacity: 0;
    transform: scale(0.97);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}
