/* ============================================================
   CLAOS — landing v2
   Concept: "Chaos, tamed." Night hero (agents working) →
   daylight sheet (you review) → night close (set it running).
   No frameworks. Animations are transform/opacity only.
   ============================================================ */

/* ----------------------------------------------------------
   1. Tokens
   ---------------------------------------------------------- */
:root {
  /* Brand */
  --green: #1db954;          /* Organic Intel green — fills, accents on dark */
  --green-bright: #3ddc78;   /* small text on dark (9:1 on night) */
  --green-deep: #0e7a36;     /* text/icon accent on light (5.6:1 on white) */
  --green-soft: rgba(29, 185, 84, 0.12);
  --green-glow: rgba(29, 185, 84, 0.45);

  /* Day palette */
  --paper: #ffffff;
  --surface: #f4f6f5;
  --ink: #141815;
  --ink-2: #525b55;                  /* muted text on light, 6.9:1 */
  --ink-faint: rgba(20, 24, 21, 0.45);
  --line: rgba(20, 24, 21, 0.1);

  /* Night palette (green-cast near-black) */
  --night: #0b100d;
  --night-2: #101712;
  --snow: #f4f6f5;
  --snow-2: #aab5ad;                 /* muted text on dark, 9:1 */
  --night-line: rgba(244, 246, 245, 0.14);

  /* Type — Comfortaa carries the brand voice, Jakarta carries the reading */
  --font-display: "Comfortaa", "Trebuchet MS", system-ui, sans-serif;
  --font-body: "Plus Jakarta Sans", system-ui, -apple-system, "Segoe UI", sans-serif;

  --fs-hero: clamp(2.4rem, 1.05rem + 4.7vw, 4.3rem);
  --fs-h2: clamp(1.9rem, 1.2rem + 2.9vw, 3.25rem);
  --fs-h3: 1.2rem;
  --fs-lead: clamp(1.05rem, 0.97rem + 0.4vw, 1.25rem);
  --fs-small: 0.875rem;
  --fs-micro: 0.75rem;

  /* Rhythm */
  --wrap: 72rem;
  --pad: clamp(1.25rem, 4vw, 2.5rem);
  --space-section: clamp(4.5rem, 3vw + 3rem, 7.5rem);
  --radius-sheet: clamp(20px, 4vw, 34px);

  /* Surfaces */
  --r-md: 14px;
  --r-lg: 22px;
  --shadow-card: 0 1px 2px rgba(15, 23, 17, 0.04), 0 14px 34px -16px rgba(15, 23, 17, 0.16);
  --shadow-card-hover: 0 2px 4px rgba(15, 23, 17, 0.05), 0 22px 44px -16px rgba(15, 23, 17, 0.22);

  /* Motion */
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  --t-reveal: 0.7s;

  color-scheme: light;
}

/* ----------------------------------------------------------
   2. Reset & base
   ---------------------------------------------------------- */
*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
}

html {
  scroll-padding-top: 5.5rem;
  overflow-x: hidden;
  overflow-x: clip;
}

@media (prefers-reduced-motion: no-preference) {
  html {
    scroll-behavior: smooth;
  }
}

body {
  font-family: var(--font-body);
  font-size: 1rem;
  line-height: 1.6;
  background: var(--night); /* overscroll above hero / below footer stays night */
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
  overflow-x: clip;
}

img {
  display: block;
  max-width: 100%;
  height: auto;
}

a {
  color: inherit;
}

h1,
h2,
h3,
p {
  margin: 0;
  overflow-wrap: break-word;
}

::selection {
  background: var(--green);
  color: #08130c;
}

:focus-visible {
  outline: 2px solid var(--green);
  outline-offset: 3px;
  border-radius: 4px;
}

.sheet :focus-visible {
  outline-color: var(--green-deep);
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: fixed;
  top: 1rem;
  left: 1rem;
  z-index: 300;
  padding: 0.7rem 1.2rem;
  border-radius: 999px;
  background: var(--ink);
  color: var(--paper);
  font-weight: 700;
  font-size: var(--fs-small);
  text-decoration: none;
  transform: translateY(-250%);
  transition: transform 0.25s var(--ease-out);
}

.skip-link:focus,
.skip-link:focus-visible {
  transform: none;
}

.wrap {
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--pad);
}

/* ----------------------------------------------------------
   3. Reveal system (IntersectionObserver adds .is-in / .hero-go)
   Hidden states are scoped to html.js so no-JS visitors see
   everything. Hover lift uses `translate` so it composes with
   the reveal's `transform` without fighting the transition.
   ---------------------------------------------------------- */
html.js [data-reveal] {
  opacity: 0;
  transform: translateY(26px);
  transition:
    opacity var(--t-reveal) var(--ease-out) var(--d, 0ms),
    transform var(--t-reveal) var(--ease-out) var(--d, 0ms),
    translate 0.3s var(--ease-out),
    box-shadow 0.3s var(--ease-out),
    border-color 0.3s var(--ease-out);
}

html.js [data-reveal].is-in {
  opacity: 1;
  transform: none;
}

html.js [data-intro] {
  opacity: 0;
  transform: translateY(20px);
  transition:
    opacity 0.8s var(--ease-out) var(--d, 0ms),
    transform 0.8s var(--ease-out) var(--d, 0ms);
}

html.js.hero-go [data-intro] {
  opacity: 1;
  transform: none;
}

/* ----------------------------------------------------------
   4. Shared atoms
   ---------------------------------------------------------- */
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--green-bright);
}

.eyebrow.on-light {
  color: var(--green-deep);
}

.eyebrow-dot {
  width: 0.45rem;
  height: 0.45rem;
  border-radius: 50%;
  background: currentColor;
  flex: none;
}

/* ── Acronym unfurl — the eyebrow loads as "CLAOS" then grows into the words ──
   Each initial's trailing letters (and the inter-word spaces) live in an
   inline-grid whose single column animates 0fr → 1fr, so the capitals never move
   while their words unfurl out of them. Default is fully-expanded (no-JS / SEO
   safe); html.js collapses it to "CLAOS"; .hero-go unfurls it once after intro. */
.eb-acro {
  white-space: nowrap;
}

.eb-x {
  display: inline-grid;
  grid-template-columns: 1fr;
  vertical-align: baseline;
}

.eb-x > span {
  overflow: hidden;
  white-space: pre; /* keep the single-space wrappers intact when expanded */
}

html.js .eb-x {
  grid-template-columns: 0fr;
}

html.js .eb-x > span {
  opacity: 0;
}

html.js.hero-go .eb-x {
  grid-template-columns: 1fr;
  transition: grid-template-columns 0.55s var(--ease-out);
  transition-delay: calc(1100ms + var(--i, 0) * 75ms);
}

html.js.hero-go .eb-x > span {
  opacity: 1;
  transition: opacity 0.5s var(--ease-out);
  transition-delay: calc(1140ms + var(--i, 0) * 75ms);
}

@media (prefers-reduced-motion: reduce) {
  html.js .eb-x {
    grid-template-columns: 1fr;
  }
  html.js .eb-x > span {
    opacity: 1;
  }
  html.js.hero-go .eb-x,
  html.js.hero-go .eb-x > span {
    transition: none;
  }
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  height: 3rem;
  padding: 0 1.45rem;
  border: 1px solid transparent;
  border-radius: 999px;
  font-family: var(--font-body);
  font-size: 0.95rem;
  font-weight: 700;
  letter-spacing: 0.01em;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition:
    translate 0.2s var(--ease-out),
    scale 0.2s var(--ease-out),
    background-color 0.2s var(--ease-out),
    border-color 0.2s var(--ease-out),
    box-shadow 0.2s var(--ease-out);
}

.btn:hover {
  translate: 0 -2px;
}

.btn:active {
  translate: 0 0;
  scale: 0.985;
}

.btn-primary {
  background: var(--green);
  color: #08130c; /* ink-on-green: 7.2:1 */
  box-shadow: 0 10px 28px -12px var(--green-glow);
}

.btn-primary:hover {
  background: #27c862;
  box-shadow: 0 14px 32px -12px var(--green-glow);
}

.btn-arrow {
  transition: transform 0.2s var(--ease-out);
}

.btn-primary:hover .btn-arrow {
  transform: translateX(3px);
}

.btn-ghost {
  border-color: var(--night-line);
  color: var(--snow);
  background: rgba(244, 246, 245, 0.02);
}

.btn-ghost:hover {
  background: rgba(244, 246, 245, 0.08);
  border-color: rgba(244, 246, 245, 0.3);
}

/* Secondary button for LIGHT surfaces (e.g. non-featured pricing cards) */
.btn-ghost-dark {
  border-color: var(--line);
  color: var(--ink);
  background: var(--paper);
}

.btn-ghost-dark:hover {
  background: var(--surface);
  border-color: rgba(20, 24, 21, 0.28);
}

.btn-sm {
  height: 2.4rem;
  padding: 0 1.05rem;
  font-size: 0.85rem;
}

.pulse-dot {
  position: relative;
  display: inline-block;
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: var(--green);
  flex: none;
}

.pulse-dot::after {
  content: "";
  position: absolute;
  inset: -3px;
  border-radius: 50%;
  border: 1px solid var(--green);
  animation: pulse-ring 2.4s var(--ease-out) infinite;
}

@keyframes pulse-ring {
  from {
    transform: scale(0.55);
    opacity: 0.9;
  }
  to {
    transform: scale(1.7);
    opacity: 0;
  }
}

/* Brand lockup (header + footer) */
.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  text-decoration: none;
}

.brand-mark {
  width: 26px;
  height: 26px;
  margin-right: -0.13rem; /* nudge the mark slightly closer to the "Claos" wordmark */
  filter: invert(1); /* black mark → white on night surfaces */
  transition: filter 0.35s;
}

.brand-word {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.18rem;
  letter-spacing: 0.01em;
  color: var(--snow);
  transition: color 0.35s;
}

.brand-beta {
  align-self: flex-start;
  margin: 0.18rem 0 0 -0.15rem;
  font-size: 0.55rem;
  font-weight: 800;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--green-bright);
}

/* ----------------------------------------------------------
   5. Header — floating glass pill
   ---------------------------------------------------------- */
.site-head {
  --hfg: var(--snow);
  --hfg2: var(--snow-2);
  --hbg-hover: rgba(244, 246, 245, 0.08);
  position: fixed;
  inset-inline: 0;
  top: 0;
  z-index: 100;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 0.8rem var(--pad) 0;
  pointer-events: none;
}

/* When the support chat is open on mobile it is a fullscreen overlay; hide the
   floating nav pill underneath it (the panel is fixed inset-0, but .site-head's
   z-index 100 would otherwise peek above it). Toggled by SupportChatWidget via
   html.support-chat-open. Higher specificity than `.site-head` above, so this
   wins without !important. Desktop keeps the header (panel is a corner card). */
@media (max-width: 767px) {
  html.support-chat-open .site-head {
    display: none;
  }
}

.head-pill {
  pointer-events: auto;
  display: flex;
  align-items: center;
  gap: 0.3rem;
  max-width: 100%;
  padding: 0.4rem 0.45rem 0.4rem 0.9rem;
  border: 1px solid var(--night-line);
  border-radius: 999px;
  background: rgba(11, 16, 13, 0.62);
  -webkit-backdrop-filter: blur(16px) saturate(1.5);
  backdrop-filter: blur(16px) saturate(1.5);
  transition: background-color 0.35s, border-color 0.35s, box-shadow 0.35s;
}

.site-head.on-light {
  --hfg: var(--ink);
  --hfg2: var(--ink-2);
  --hbg-hover: rgba(20, 24, 21, 0.06);
}

.site-head.on-light .head-pill {
  background: rgba(255, 255, 255, 0.82);
  border-color: var(--line);
  box-shadow: 0 12px 32px -18px rgba(15, 23, 17, 0.4);
}

.site-head.on-light .brand-mark {
  filter: none;
}

.site-head.on-light .brand-word {
  color: var(--ink);
}

.head-nav {
  display: none;
  align-items: center;
  gap: 0.15rem;
  margin-left: 0.5rem;
}

.head-nav a,
.head-login {
  padding: 0.45rem 0.8rem;
  border-radius: 999px;
  font-size: 0.875rem;
  font-weight: 600;
  text-decoration: none;
  color: var(--hfg2);
  transition: color 0.2s, background-color 0.2s;
}

.head-nav a:hover,
.head-login:hover {
  color: var(--hfg);
  background: var(--hbg-hover);
}

.head-actions {
  display: none;
  align-items: center;
  gap: 0.35rem;
  margin-left: 0.5rem;
}

.menu-btn {
  display: grid;
  place-items: center;
  gap: 5px;
  width: 2.4rem;
  height: 2.4rem;
  margin-left: 0.25rem;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: transparent;
  cursor: pointer;
}

.menu-line {
  display: block;
  width: 1.05rem;
  height: 2px;
  border-radius: 2px;
  background: var(--hfg);
  transition: transform 0.3s var(--ease-out);
}

.menu-btn[aria-expanded="true"] .menu-line:first-child {
  transform: translateY(3.5px) rotate(45deg);
}

.menu-btn[aria-expanded="true"] .menu-line:last-child {
  transform: translateY(-3.5px) rotate(-45deg);
}

/* author display would beat the UA's [hidden] rule — restate it */
.mobile-menu[hidden] {
  display: none;
}

.mobile-menu {
  pointer-events: auto;
  width: min(100%, 24rem);
  margin-top: 0.6rem;
  padding: 0.6rem;
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  border: 1px solid var(--night-line);
  border-radius: 20px;
  background: rgba(13, 18, 15, 0.94);
  -webkit-backdrop-filter: blur(18px);
  backdrop-filter: blur(18px);
  opacity: 0;
  transform: translateY(-8px) scale(0.98);
  transition: opacity 0.28s var(--ease-out), transform 0.28s var(--ease-out);
}

.site-head.on-light .mobile-menu {
  background: rgba(255, 255, 255, 0.95);
  border-color: var(--line);
}

.mobile-menu.open {
  opacity: 1;
  transform: none;
}

.mobile-menu a {
  padding: 0.8rem 1rem;
  border-radius: 14px;
  font-size: 1rem;
  font-weight: 600;
  text-decoration: none;
  color: var(--hfg);
}

.mobile-menu a:hover {
  background: var(--hbg-hover);
}

.mobile-menu .btn {
  margin-top: 0.3rem;
  justify-content: center;
  color: #08130c;
}

.mobile-menu-split {
  height: 1px;
  margin: 0.4rem 0.5rem;
  background: var(--night-line);
}

.site-head.on-light .mobile-menu-split {
  background: var(--line);
}

@media (min-width: 480px) {
  .head-actions {
    display: flex;
  }

  .head-actions .head-login {
    display: none;
  }
}

@media (min-width: 880px) {
  .head-nav {
    display: flex;
  }

  .head-actions .head-login {
    display: inline-block;
  }

  .menu-btn,
  .mobile-menu {
    display: none;
  }
}

/* ----------------------------------------------------------
   6. Hero — the night shift
   ---------------------------------------------------------- */
.hero {
  /* Pinned: the hero stays fixed in the viewport while the daylight sheet
     (z-index 3, opaque) slides up and covers it on scroll — "reveal" effect.
     Sits at the bottom of the stacking order so every later section paints
     over it. */
  position: sticky;
  top: 0;
  z-index: 0;
  display: flex;
  align-items: center;
  /* Just under one viewport so a sliver of the next section (the browser
     chrome) peeks at the bottom — an invitation to scroll. The --peek value
     is how much of the sheet shows at rest. Grows for tall content on short
     screens (min-height won't clip like a fixed height). */
  --peek: 58px;
  min-height: min(calc(100vh - var(--peek)), 1100px);
  min-height: min(calc(100svh - var(--peek)), 1100px);
  padding: 5.5rem 0 4rem;
  background: var(--night);
  color: var(--snow);
  overflow: hidden;
  color-scheme: dark;
}

/* A no-JS / reduced-motion-agnostic safety: if sticky isn't supported the
   hero simply scrolls normally (graceful degradation, no broken layout). */

/* Faint dot-grid — a quiet nod to v1's particle field */
.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: radial-gradient(rgba(244, 246, 245, 0.06) 1px, transparent 1.4px);
  background-size: 30px 30px;
  -webkit-mask-image: radial-gradient(80% 80% at 62% 42%, black 25%, transparent 78%);
  mask-image: radial-gradient(80% 80% at 62% 42%, black 25%, transparent 78%);
}

/* Grid dots twinkle like a starfield. V2Motion scatters <i> dots onto the grid
   intersections (the 30px module + 15px so they land on the dot centres) inside
   .hero-stars; each carries randomised --tw-* timing so they shimmer
   independently. Masked like the static grid so they fade toward the edges, and
   stacked (DOM order) behind the orbit canvas + copy. Reduced motion / no-JS →
   no dots, the static .hero::before grid still shows. */
.hero-stars {
  position: absolute;
  inset: 0;
  pointer-events: none;
  -webkit-mask-image: radial-gradient(80% 80% at 62% 42%, black 25%, transparent 78%);
  mask-image: radial-gradient(80% 80% at 62% 42%, black 25%, transparent 78%);
}

/* Canvas dot-grid glow + cursor hover (V2HeroDots). Overlays the static
   `.hero::before` / `.cta-band::before` grid on the dark sections — green dots
   glow near the cursor and twinkle ambiently. pointer-events:none so it never
   blocks the CTAs (it reads the cursor from the parent section). Masked per
   section to fade at the edges like the static grid. */
/* A sizing wrapper (plain div) stretches to the section like the old
   `.hero-stars`; the <canvas> fills it. A bare canvas as a flex child of the
   sticky hero collapses the layout — the div doesn't. */
.hero-dots-wrap {
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.hero-dots {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}
.hero .hero-dots-wrap {
  -webkit-mask-image: radial-gradient(80% 80% at 62% 42%, black 25%, transparent 78%);
  mask-image: radial-gradient(80% 80% at 62% 42%, black 25%, transparent 78%);
}
.cta-band .hero-dots-wrap {
  -webkit-mask-image: radial-gradient(70% 90% at 50% 30%, black 20%, transparent 75%);
  mask-image: radial-gradient(70% 90% at 50% 30%, black 20%, transparent 75%);
}
.page-banner .hero-dots-wrap {
  -webkit-mask-image: radial-gradient(78% 80% at 72% 42%, black 18%, transparent 80%);
  mask-image: radial-gradient(78% 80% at 72% 42%, black 18%, transparent 80%);
}

.hero-stars i {
  position: absolute;
  width: 4px;
  height: 4px;
  margin: -2px 0 0 -2px; /* centre the dot on its grid intersection */
  border-radius: 50%;
  background: var(--green); /* brand-green twinkle, echoing the orbit nodes */
  opacity: 0.24; /* clearly visible at rest; brightens further as it twinkles */
  transform: scale(0.5);
  animation: hero-twinkle var(--tw-dur, 5s) ease-in-out var(--tw-delay, 0s) infinite;
}

@keyframes hero-twinkle {
  0%, 100% {
    opacity: 0.24;
    transform: scale(0.5);
  }
  50% {
    opacity: var(--tw-peak, 0.9);
    transform: scale(1);
  }
}

@media (prefers-reduced-motion: reduce) {
  .hero-stars i {
    animation: none;
    opacity: 0.24;
  }
}

/* Spark layer — V2Motion launches a glowing dot from a twinkle star to the
   agent feed (Web Animations API), then prepends a feed row on impact. Above the
   copy (z:3) so the spark stays visible until it lands on the panel's top edge.
   Unmasked, so it reads cleanly all the way across. */
.hero-sparks {
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
}

.hero-spark {
  position: absolute;
  top: 0;
  left: 0;
  width: 7px;
  height: 7px;
  margin: -3.5px;
  border-radius: 50%;
  background: var(--green-bright, var(--green));
  box-shadow:
    0 0 8px 2px var(--green-glow),
    0 0 18px 5px rgba(29, 185, 84, 0.4);
  /* offset-rotate banks the comet along the Motion-Path curve (path set in JS)
     so the tail follows the arc; it's a no-op for the fallback translate flight. */
  offset-rotate: auto;
  will-change: offset-distance, transform, opacity;
}

/* trailing comet tail. With Motion Path the element auto-rotates along the curve
   (offset-rotate:auto), so the tail trails on its local axis with --a left at 0;
   the fallback flight instead sets --a to the straight launch→dot angle. */
.hero-spark::before {
  content: "";
  position: absolute;
  top: 50%;
  right: 50%;
  width: 30px;
  height: 2px;
  transform-origin: right center;
  transform: rotate(var(--a, 0deg));
  background: linear-gradient(to left, var(--green), transparent);
  border-radius: 2px;
}

@media (prefers-reduced-motion: reduce) {
  .hero-sparks {
    display: none;
  }
}

.hero-inner {
  position: relative;
  z-index: 2;
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--pad);
  display: grid;
  grid-template-columns: 1fr;
  gap: 3.5rem;
  align-items: center;
  /* Recede: as the daylight sheet rises over the pinned hero, the hero
     content scales down + fades, giving depth — the concept recedes as the
     product arrives. --hero-progress (0→1) is set by script.js on scroll;
     transform/opacity only, so it composites. Default 0 = no change, so
     no-JS / reduced-motion leaves the hero untouched. */
  transform: scale(calc(1 - var(--hero-progress, 0) * 0.05));
  transform-origin: 50% 42%;
  opacity: calc(1 - var(--hero-progress, 0) * 0.5);
}

/* grid items must be allowed to shrink below their nowrap min-content
   (the ticker rows ellipsize instead of widening the column) */
.hero-inner > * {
  min-width: 0;
}

.hero-title {
  margin-top: 1.3rem;
  font-family: var(--font-display);
  font-size: var(--fs-hero);
  font-weight: 700;
  line-height: 1.08;
  letter-spacing: -0.015em;
  text-wrap: balance;
}

.hero-title .accent {
  display: block;
  color: var(--green);
}

.hero-lead {
  max-width: 33rem;
  margin-top: 1.4rem;
  font-size: var(--fs-lead);
  line-height: 1.65;
  color: var(--snow-2);
}

.hero-ctas {
  display: flex;
  flex-wrap: wrap;
  gap: 0.8rem;
  margin-top: 2.1rem;
}

.hero-ctas.centered {
  justify-content: center;
}

.hero-note {
  margin-top: 1rem;
  font-size: var(--fs-small);
  color: var(--snow-2);
}

/* ── Live agent feed — the hero's right-side centrepiece ───────────────────── */
.agent-feed {
  position: relative;
  width: 100%;
  max-width: 31rem;
  padding: 1rem 1.15rem 0.95rem;
  border: 1px solid var(--night-line);
  border-radius: var(--r-lg);
  background: rgba(16, 23, 18, 0.6);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  box-shadow: 0 34px 90px -46px rgba(0, 0, 0, 0.8);
}

/* landing flash — opacity-only overlay ring, never repaints the box */
.agent-feed::after {
  content: "";
  position: absolute;
  inset: -1px;
  border: 1px solid rgba(29, 185, 84, 0.6);
  border-radius: var(--r-lg);
  opacity: 0;
  pointer-events: none;
}

.agent-feed.landed::after {
  animation: feed-land 0.7s var(--ease-out);
}

@keyframes feed-land {
  20% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}

.feed-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding-bottom: 0.85rem;
  border-bottom: 1px solid var(--night-line);
}

.feed-title {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--snow-2);
}

.feed-live {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  flex: none;
  font-size: var(--fs-micro);
  letter-spacing: 0.02em;
  color: var(--snow-2);
}

.feed-live-dot {
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: var(--green-bright);
  box-shadow: 0 0 0 3px rgba(29, 185, 84, 0.16);
}

html.js .feed-live-dot {
  animation: feed-live-pulse 2.4s ease-in-out infinite;
}

@keyframes feed-live-pulse {
  0%,
  100% {
    box-shadow: 0 0 0 2px rgba(29, 185, 84, 0.05);
  }
  50% {
    box-shadow: 0 0 0 4px rgba(29, 185, 84, 0.22);
  }
}

.feed-list {
  position: relative;
  height: 12.6rem; /* exactly 4 rows — landed rows never shift the page */
  margin: 0.7rem 0 0;
  padding: 0;
  list-style: none;
  overflow: hidden;
}

/* fade the bottom edge so the last row dissolves rather than hard-cuts */
.feed-list::after {
  content: "";
  position: absolute;
  inset: auto 0 0;
  height: 1.6rem;
  pointer-events: none;
  background: linear-gradient(to bottom, transparent, rgba(16, 23, 18, 0.9));
}

.feed-row {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  height: 3.15rem;
  border-radius: 8px;
}

html.js .feed-list li.tick-in {
  animation: tick-in 0.55s var(--ease-out);
}

@keyframes tick-in {
  from {
    opacity: 0;
    transform: translateY(-10px);
  }
}

/* per-agent accent — set on the row so the monogram, working dots and the
   land-flash all share it. Greens/teals + one warm (Atlas). */
.feed-row[data-agent="Scout"] {
  --mono: #34d27a;
}
.feed-row[data-agent="Quill"] {
  --mono: #22bcc0;
}
.feed-row[data-agent="Atlas"] {
  --mono: #e3a346;
}
.feed-row[data-agent="Scribe"] {
  --mono: #7fd06a;
}

.feed-mono {
  display: grid;
  place-items: center;
  flex: none;
  width: 1.95rem;
  height: 1.95rem;
  border-radius: 9px;
  font-size: 0.66rem;
  font-weight: 800;
  letter-spacing: 0.01em;
  color: var(--mono, var(--green-bright));
  background: color-mix(in srgb, var(--mono, var(--green)) 15%, transparent);
  border: 1px solid color-mix(in srgb, var(--mono, var(--green)) 32%, transparent);
}

.feed-body {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
}

.feed-agent {
  font-size: 0.84rem;
  font-weight: 700;
  color: var(--snow);
}

.feed-task {
  min-width: 0;
  font-size: 0.78rem;
  line-height: 1.35;
  color: var(--snow-2);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.feed-meta {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  flex: none;
  margin-left: auto;
}

.feed-time {
  font-size: 0.68rem;
  color: rgba(170, 181, 173, 0.6);
}

/* green check on completed rows (CSS-drawn tick) */
.feed-check {
  display: grid;
  place-items: center;
  flex: none;
  width: 1rem;
  height: 1rem;
  border-radius: 50%;
  background: color-mix(in srgb, var(--green) 18%, transparent);
}
.feed-check::before {
  content: "";
  width: 0.34rem;
  height: 0.18rem;
  border: 1.6px solid var(--green-bright);
  border-top: 0;
  border-right: 0;
  transform: translateY(-1px) rotate(-45deg);
}

/* animated "working" dots in the agent's colour */
.feed-dots {
  display: inline-flex;
  align-items: center;
  gap: 3px;
}
.feed-dots i {
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--mono, var(--green-bright));
  opacity: 0.3;
}
html.js .feed-row.working .feed-dots i {
  animation: feed-dot-bounce 1.1s ease-in-out infinite;
}
.feed-dots i:nth-child(2) {
  animation-delay: 0.15s;
}
.feed-dots i:nth-child(3) {
  animation-delay: 0.3s;
}

@keyframes feed-dot-bounce {
  0%,
  80%,
  100% {
    opacity: 0.25;
    transform: translateY(0);
  }
  40% {
    opacity: 1;
    transform: translateY(-3px);
  }
}

/* ── working ↔ done state toggles ─────────────────────────────────────────── */
.feed-row .feed-dots {
  display: none;
}
.feed-row.working .feed-dots {
  display: inline-flex;
}
.feed-row.working .feed-time,
.feed-row.working .feed-check {
  display: none;
}

/* live treatments on the working row */
html.js .feed-row.working .feed-mono {
  animation: feed-mono-pulse 1.9s ease-in-out infinite;
}
/* Contained pulse — brightens the chip + an INSET glow (no outward ring, which
   the feed-list's overflow:hidden would clip at the panel edge). */
@keyframes feed-mono-pulse {
  0%,
  100% {
    background: color-mix(in srgb, var(--mono) 14%, transparent);
    box-shadow: inset 0 0 0 0 color-mix(in srgb, var(--mono) 0%, transparent);
  }
  50% {
    background: color-mix(in srgb, var(--mono) 30%, transparent);
    box-shadow: inset 0 0 9px 0 color-mix(in srgb, var(--mono) 42%, transparent);
  }
}
html.js .feed-row.working .feed-task {
  color: transparent;
  background: linear-gradient(
    90deg,
    var(--snow-2) 35%,
    var(--snow) 50%,
    var(--snow-2) 65%
  );
  background-size: 220% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  animation: feed-shimmer 1.7s linear infinite;
}
@keyframes feed-shimmer {
  to {
    background-position: -220% 0;
  }
}

/* land-flash when a working row resolves to done, in the agent's colour */
html.js .feed-row.just-landed {
  animation: feed-row-flash 0.9s var(--ease-out);
}
@keyframes feed-row-flash {
  0% {
    background: color-mix(in srgb, var(--mono) 24%, transparent);
  }
  100% {
    background: color-mix(in srgb, var(--mono) 0%, transparent);
  }
}

.feed-foot {
  margin-top: 0.55rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--night-line);
  font-size: var(--fs-small);
  color: var(--snow-2);
}

.feed-foot-num {
  display: inline-block;
  margin-right: 0.25rem;
  font-weight: 800;
  color: var(--green-bright);
}

/* the live "N working" count — drifts 2–5 so the header feels alive */
.feed-live-num {
  display: inline-block;
  font-weight: 700;
  color: var(--snow);
}

html.js .feed-foot-num.bumped,
html.js .feed-live-num.bumped {
  animation: feed-num-bump 0.5s var(--ease-out);
}
@keyframes feed-num-bump {
  30% {
    transform: translateY(-2px) scale(1.18);
  }
}

/* reduced motion: the feed stays legible + static (no shimmer/pulse/bounce) */
@media (prefers-reduced-motion: reduce) {
  .feed-row.working .feed-task {
    color: var(--snow-2);
    background: none;
    -webkit-background-clip: border-box;
    background-clip: border-box;
    animation: none;
  }
  .feed-row.working .feed-mono,
  .feed-row.working .feed-dots i,
  .feed-row.just-landed,
  .feed-foot-num.bumped,
  .feed-live-num.bumped {
    animation: none;
  }
}

/* The agent feed sits centred in the right column of the hero grid. */
.hero-stage {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 0;
}

@media (min-width: 980px) {
  .hero-inner {
    grid-template-columns: 1.05fr 0.95fr;
    gap: 2rem;
  }

  /* lift the feed so its top locks closer to the headline's first line rather
     than floating at the dead-centre of the taller copy column */
  .hero-stage {
    margin-top: clamp(-4.5rem, -4vw, -2.5rem);
  }
}

/* ----------------------------------------------------------
   7. The day sheet — light content rises over the night hero
   ---------------------------------------------------------- */
.sheet {
  position: relative;
  z-index: 3;
  margin-top: -34px;
  /* ends at stats now — the pinned .voices section (a sibling in <main>)
     continues the white surface and supplies the bottom spacing */
  padding-bottom: 0;
  background: var(--paper);
  border-radius: var(--radius-sheet) var(--radius-sheet) 0 0;
  box-shadow: 0 -20px 60px -32px rgba(0, 0, 0, 0.55);
  /* NOTE: no overflow:hidden here — it would break the sticky pin used for
     the closing reveal. The demo's rounded top is clipped on .demo-os itself. */
}

.section-title {
  margin-top: 1rem;
  font-family: var(--font-display);
  font-size: var(--fs-h2);
  font-weight: 700;
  line-height: 1.12;
  letter-spacing: -0.01em;
  color: var(--ink);
  text-wrap: balance;
}

.section-title.centered {
  text-align: center;
  margin-inline: auto;
  max-width: 22ch;
}

.section-lead {
  max-width: 36rem;
  margin-top: 1.1rem;
  font-size: var(--fs-lead);
  line-height: 1.65;
  color: var(--ink-2);
}

/* ----------------------------------------------------------
   8. Features — they work / document / report
   ---------------------------------------------------------- */
.features {
  padding-top: calc(var(--space-section) + 12px);
}

.card-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 1.1rem;
  margin-top: 3rem;
}

@media (min-width: 900px) {
  .card-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

.feature-card {
  display: flex;
  flex-direction: column;
  padding: 1.5rem 1.5rem 1.25rem;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-card);
}

.feature-card:hover {
  translate: 0 -5px;
  border-color: rgba(29, 185, 84, 0.4);
  box-shadow: var(--shadow-card-hover);
}

.card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 1.1rem;
}

.card-icon {
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  border-radius: 13px;
  background: var(--green-soft);
  color: var(--green-deep);
}

.card-num {
  font-size: 0.8rem;
  font-weight: 800;
  letter-spacing: 0.1em;
  color: var(--ink-faint);
}

.feature-card h3 {
  font-size: var(--fs-h3);
  font-weight: 700;
  color: var(--ink);
}

.feature-card > p {
  margin-top: 0.55rem;
  font-size: 0.95rem;
  line-height: 1.6;
  color: var(--ink-2);
}

/* Mockups — tiny product fictions, CSS only */
.mock {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 0.5rem;
  min-height: 9.75rem;
  margin-top: 1.4rem;
  padding: 0.85rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
}

/* Mock animations only run while the card is on screen */
html.js .mock .chip-cycle span,
html.js .mock .m-line,
html.js .mock .m-badge {
  animation-play-state: paused;
}

html.js .feature-card.is-in .mock .chip-cycle span,
html.js .feature-card.is-in .mock .m-line,
html.js .feature-card.is-in .mock .m-badge {
  animation-play-state: running;
}

.m-row {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.45rem 0.6rem;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 10px;
}

.m-ava {
  display: grid;
  place-items: center;
  width: 1.7rem;
  height: 1.7rem;
  border-radius: 50%;
  flex: none;
  font-size: 0.68rem;
  font-weight: 800;
  background: var(--green-soft);
  color: var(--green-deep);
}

.m-ava.a2 {
  background: rgba(20, 24, 21, 0.08);
  color: var(--ink);
}

.m-ava.a3 {
  background: var(--ink);
  color: var(--paper);
}

.m-id {
  display: flex;
  flex-direction: column;
  line-height: 1.2;
  min-width: 0;
}

.m-id strong {
  font-size: 0.74rem;
  font-weight: 700;
  color: var(--ink);
}

.m-id em {
  font-style: normal;
  font-size: 0.62rem;
  color: var(--ink-2);
}

.m-chip {
  margin-left: auto;
  padding: 0.22rem 0.55rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  font-size: 0.62rem;
  font-weight: 700;
  white-space: nowrap;
  background: var(--surface);
  color: var(--ink-2);
}

.m-chip.chip-live {
  display: inline-flex;
  align-items: center;
  gap: 0.32rem;
  background: var(--green-soft);
  border-color: transparent;
  color: var(--green-deep);
}

.m-chip.chip-live .pulse-dot {
  width: 0.38rem;
  height: 0.38rem;
}

.m-chip.chip-cycle {
  display: grid;
  min-width: 4.4rem;
  text-align: center;
}

.chip-cycle span {
  grid-area: 1 / 1;
  opacity: 0;
  animation: chip-fade 7.2s infinite;
}

.chip-cycle .c-r {
  animation-delay: 2.4s;
}

.chip-cycle .c-d {
  animation-delay: 4.8s;
  color: var(--green-deep);
}

@keyframes chip-fade {
  0% {
    opacity: 0;
    transform: translateY(3px);
  }
  7%,
  30% {
    opacity: 1;
    transform: none;
  }
  37%,
  100% {
    opacity: 0;
    transform: none;
  }
}

.m-doc-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  margin-bottom: 0.3rem;
}

.m-doc-title {
  font-size: 0.78rem;
  font-weight: 700;
  color: var(--ink);
}

.m-badge {
  padding: 0.2rem 0.55rem;
  border-radius: 999px;
  font-size: 0.62rem;
  font-weight: 700;
  background: var(--green-soft);
  color: var(--green-deep);
  opacity: 0;
  animation: badge-pop 9s infinite;
}

@keyframes badge-pop {
  0%,
  52% {
    opacity: 0;
    transform: scale(0.92);
  }
  58%,
  92% {
    opacity: 1;
    transform: none;
  }
  100% {
    opacity: 0;
  }
}

.m-line {
  display: block;
  height: 0.5rem;
  border-radius: 4px;
  background: rgba(20, 24, 21, 0.1);
  transform-origin: left center;
  animation: line-grow 9s var(--ease-out) infinite;
}

.m-line:nth-of-type(2) {
  animation-delay: 0.5s;
}

.m-line:nth-of-type(3) {
  animation-delay: 1s;
}

.m-line:nth-of-type(4) {
  animation-delay: 1.5s;
}

@keyframes line-grow {
  0% {
    transform: scaleX(0);
  }
  9%,
  88% {
    transform: scaleX(1);
  }
  96%,
  100% {
    transform: scaleX(0);
  }
}

.w92 {
  width: 92%;
}

.w100 {
  width: 100%;
}

.w78 {
  width: 78%;
}

.w55 {
  width: 55%;
}

.m-msg {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0.6rem;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 10px;
}

html.js .mock-inbox .m-msg {
  opacity: 0;
  transform: translateX(18px);
  transition: opacity 0.55s var(--ease-out), transform 0.55s var(--ease-out);
}

html.js .feature-card.is-in .mock-inbox .m-msg {
  opacity: 1;
  transform: none;
}

html.js .mock-inbox .m-msg:nth-child(1) {
  transition-delay: 0.25s;
}

html.js .mock-inbox .m-msg:nth-child(2) {
  transition-delay: 0.42s;
}

html.js .mock-inbox .m-msg:nth-child(3) {
  transition-delay: 0.59s;
}

.m-dot {
  width: 0.45rem;
  height: 0.45rem;
  border-radius: 50%;
  background: var(--green);
  flex: none;
}

.m-dot.read {
  background: rgba(20, 24, 21, 0.18);
}

.m-msg-body {
  min-width: 0;
  font-size: 0.68rem;
  color: var(--ink-2);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.m-msg-body strong {
  font-weight: 700;
  color: var(--ink);
}

.m-time {
  margin-left: auto;
  flex: none;
  font-size: 0.6rem;
  color: var(--ink-faint);
}

/* ----------------------------------------------------------
   9. How it works — three steps, dino footprints between
   ---------------------------------------------------------- */
.how {
  margin-top: var(--space-section);
  padding-block: var(--space-section);
  background: var(--surface);
}

.steps {
  display: grid;
  grid-template-columns: 1fr;
  gap: 3.2rem;
  margin: 3rem 0 0;
  padding: 0;
  list-style: none;
}

.step {
  position: relative;
}

.step-num {
  display: grid;
  place-items: center;
  width: 2.6rem;
  height: 2.6rem;
  border-radius: 50%;
  background: var(--ink);
  color: var(--paper);
  font-family: var(--font-display);
  font-size: 1.05rem;
  font-weight: 700;
}

.step h3 {
  margin-top: 1.1rem;
  font-size: var(--fs-h3);
  font-weight: 700;
  color: var(--ink);
}

.step p {
  max-width: 34ch;
  margin-top: 0.5rem;
  font-size: 0.95rem;
  line-height: 1.6;
  color: var(--ink-2);
}

/* Footprint trail — walks into each next step.
   Toes point down the page on stacked layouts, rightward on desktop. */
.trail {
  --fp-rot: 180deg;
  display: flex;
  gap: 0.4rem;
  margin-bottom: 1rem;
}

.fp {
  width: 13px;
  height: 13px;
  fill: currentColor;
  color: var(--green-deep);
  transform: rotate(var(--fp-rot));
}

.fp:nth-child(odd) {
  translate: 0 3px;
}

html.js .trail .fp {
  opacity: 0;
  transform: rotate(var(--fp-rot)) scale(0.5);
  transition: opacity 0.4s var(--ease-out), transform 0.4s var(--ease-spring);
}

html.js .step.is-in .trail .fp {
  opacity: 0.6;
  transform: rotate(var(--fp-rot)) scale(1);
}

html.js .step.is-in .trail .fp:nth-child(1) {
  transition-delay: 0.35s;
}

html.js .step.is-in .trail .fp:nth-child(2) {
  transition-delay: 0.5s;
}

html.js .step.is-in .trail .fp:nth-child(3) {
  transition-delay: 0.65s;
}

html.js .step.is-in .trail .fp:nth-child(4) {
  transition-delay: 0.8s;
}

@media (min-width: 900px) {
  .steps {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 4rem;
  }

  .trail {
    --fp-rot: 90deg;
    position: absolute;
    top: 0.55rem;
    left: -4rem;
    width: 4rem;
    justify-content: center;
    gap: 0.3rem;
    margin: 0;
  }

  .fp {
    width: 12px;
    height: 12px;
  }
}

/* ----------------------------------------------------------
   10. Stats — ghost numbers
   ---------------------------------------------------------- */
.stats {
  padding-top: var(--space-section);
}

.stats-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 2.6rem;
  text-align: center;
}

@media (min-width: 760px) {
  .stats-grid {
    grid-template-columns: repeat(3, 1fr);
    gap: 1.5rem;
  }
}

.stat-num {
  font-family: var(--font-display);
  font-size: clamp(4.2rem, 8.5vw, 6.6rem);
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--ink);
  opacity: 0.08;
  font-variant-numeric: tabular-nums;
  user-select: none;
}

.stat-label {
  position: relative;
  /* The label tucks under the giant ghosted number; a smaller negative pull
     keeps the overlap look but leaves a touch more breathing room below it. */
  margin-top: -0.4rem;
  font-size: 0.85rem;
  font-weight: 800;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink);
}

.stat-desc {
  margin-top: 0.5rem;
  font-size: 0.9rem;
  color: var(--ink-2);
}

/* ----------------------------------------------------------
   11. Voices
   ---------------------------------------------------------- */
.voices {
  padding-top: var(--space-section);
  /* generous breathing room below the testimonials before the CTA's −36 overlap
     (which then lands on white, not on a testimonial card) */
  padding-bottom: clamp(5rem, 3rem + 4vw, 7rem);
  /* Opaque white so the pinned hero behind it never shows through, and so it
     reads as one continuous daylight surface with the sheet above. z-index 3
     (matching the sheet, not below it) so the sheet's downward box-shadow bleed
     doesn't paint a faint grey seam across this section's top. */
  position: relative;
  z-index: 3;
  background: var(--paper);
}

/* Pin the testimonials so the dark CTA (z:4) rises up and over them — the
   mirror of the hero reveal. The home testimonials are a single short marquee
   row (viewport-bounded), so the slide-over works at every width, mobile
   included (the "top section slides over fine but the last one doesn't on
   mobile" fix). Two rules:
     - prefers-reduced-motion: no-preference — pin at all widths. Under reduced
       motion the marquee instead wraps to a tall multi-row block; pinning a
       section taller than the viewport traps the scroll, so it stays relative
       there (graceful, motion-free).
     - min-width: 900px — keep pinning on desktop regardless of motion, matching
       the prior behavior (the desktop row stays short). */
@media (prefers-reduced-motion: no-preference) {
  .voices {
    position: sticky;
    top: 0;
  }
}
@media (min-width: 900px) {
  .voices {
    position: sticky;
    top: 0;
  }
}

/* ── Inner-page closing slide-over (.pin-tail) ───────────────────────────────
   The mirror of the top reveal, and the inner-page twin of .voices: a short,
   static closing section is lifted OUT of the .sheet to sit between the sheet
   and the .cta-band, so it pins in the page flow while the dark .cta-band (z:4,
   margin-top:-36px) rises and covers it. Opaque paper bg continues the daylight
   surface seamlessly from the sheet above; the section above it (last one still
   in the sheet) supplies the top gap, so no padding-top here. Only applied to
   pages whose closing block is short — pinning tall/interactive content would
   freeze it awkwardly under the rising CTA. Pins only ≥900px, like .voices. */
.pin-tail {
  position: relative;
  /* z-index 3 (matching the sheet, NOT below it) so the sheet's downward
     box-shadow bleed doesn't paint a faint grey seam across this white section's
     top — the pin-tail (later in DOM) covers it. */
  z-index: 3;
  /* flow-root → a block formatting context that CONTAINS the closing block's
     first-child top margin (e.g. .section-title's 1rem). Without it that margin
     collapses out the top of this section, leaving a transparent strip above the
     white that reveals the pinned dark banner behind it. The margin still spaces
     the heading — just inside the white now. */
  display: flow-root;
  padding-top: 0;
  padding-bottom: clamp(5rem, 3rem + 4vw, 7rem);
  background: var(--paper);
}

@media (min-width: 900px) {
  .pin-tail {
    position: sticky;
    top: 0;
  }
}

/* Home pricing section — each home section provides its own top padding for the
   vertical rhythm; the added pricing section had none, so it butted against the
   features grid above it. */
#pricing {
  padding-top: var(--space-section);
}

.quote-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.1rem;
  margin-top: 3rem;
}

@media (min-width: 900px) {
  .quote-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

.quote {
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
  padding: 1.7rem;
  background: var(--surface);
  border-radius: var(--r-lg);
}

.quote blockquote {
  font-size: 1rem;
  line-height: 1.7;
  color: var(--ink);
}

.quote blockquote::before {
  content: "\201C";
  display: block;
  font-family: var(--font-display);
  font-size: 2.6rem;
  line-height: 0.6;
  margin-bottom: 0.7rem;
  color: var(--green-deep);
  opacity: 0.55;
}

.quote figcaption {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  margin-top: auto;
}

.quote-ava {
  display: grid;
  place-items: center;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 50%;
  flex: none;
  font-size: 0.78rem;
  font-weight: 800;
  background: var(--green-soft);
  color: var(--green-deep);
}

.quote-ava.v2 {
  background: rgba(20, 24, 21, 0.08);
  color: var(--ink);
}

.quote-ava.v3 {
  background: var(--ink);
  color: var(--paper);
}

.quote-who {
  display: flex;
  flex-direction: column;
  font-size: 0.8rem;
  line-height: 1.45;
  color: var(--ink-2);
}

.quote-who strong {
  font-size: 0.875rem;
  color: var(--ink);
}

/* ----------------------------------------------------------
   12. CTA band — night again
   ---------------------------------------------------------- */
.cta-band {
  position: relative;
  z-index: 4;
  margin-top: -36px;
  /* Full-screen close: guarantees the band is taller than the pinned voices
     section so it always fully covers it as it slides over (the covering
     element must be ≥ what it covers). Also a stronger final beat. Content is
     centred in the viewport-tall band. */
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: calc(var(--space-section) + 16px) 0 var(--space-section);
  background: var(--night);
  color: var(--snow);
  border-radius: var(--radius-sheet) var(--radius-sheet) 0 0;
  overflow: hidden;
  color-scheme: dark;
}

/* The CTA (z:4, opaque) slides up over the pinned .voices section (z:2) as you
   reach the bottom — the mirror of the sheet covering the hero. No sticky on
   the CTA itself; it covers by z-index + normal flow while voices holds. */

/* Closing emerge — the REVERSE of the hero recede. As the sheet uncovers the
   pinned CTA (--cta-progress 0→1, set by script.js), the closing content grows
   from slightly smaller and fades in, instead of shrinking and fading out.
   JS-and-motion only: no-JS or reduced motion shows it full-size from the start. */
@media (prefers-reduced-motion: no-preference) {
  html.js .cta-inner {
    transform: scale(calc(0.92 + var(--cta-progress, 0) * 0.08));
    opacity: calc(0.25 + var(--cta-progress, 0) * 0.75);
    transform-origin: 50% 50%;
    will-change: transform, opacity;
  }

  html.js .cta-dino {
    opacity: calc(0.15 + var(--cta-progress, 0) * 0.85);
  }
}

.cta-band::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: radial-gradient(rgba(244, 246, 245, 0.055) 1px, transparent 1.4px);
  background-size: 30px 30px;
  -webkit-mask-image: radial-gradient(70% 90% at 50% 30%, black 20%, transparent 75%);
  mask-image: radial-gradient(70% 90% at 50% 30%, black 20%, transparent 75%);
}

/* Twinkle field — V2Motion scatters <i> dots on the band's 30px grid, the same
   starfield as the hero, behind the centred copy. Masked to match the ::before
   grid so the twinkle fades exactly where the static dots do. Reuses
   @keyframes hero-twinkle + the --tw-* var contract. No spark layer — the CTA
   has no agent-feed panel to shoot into. */
.cta-stars {
  position: absolute;
  inset: 0;
  pointer-events: none;
  -webkit-mask-image: radial-gradient(70% 90% at 50% 30%, black 20%, transparent 75%);
  mask-image: radial-gradient(70% 90% at 50% 30%, black 20%, transparent 75%);
}

.cta-stars i {
  position: absolute;
  width: 4px;
  height: 4px;
  margin: -2px 0 0 -2px;
  border-radius: 50%;
  background: var(--green);
  opacity: 0.24;
  transform: scale(0.5);
  animation: hero-twinkle var(--tw-dur, 5s) ease-in-out var(--tw-delay, 0s) infinite;
}

@media (prefers-reduced-motion: reduce) {
  .cta-stars i {
    animation: none;
    opacity: 0.24;
  }
}

.cta-inner {
  position: relative;
  text-align: center;
}

.cta-title {
  font-family: var(--font-display);
  font-size: clamp(2.1rem, 1.1rem + 4.2vw, 4rem);
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: -0.015em;
  text-wrap: balance;
}

.cta-title .accent {
  display: block;
  color: var(--green);
}

.cta-sub {
  margin-top: 1.2rem;
  font-size: var(--fs-lead);
  color: var(--snow-2);
}

.cta-band .hero-ctas {
  margin-top: 2.3rem;
}

/* The dino sleeps until morning */
.cta-dino {
  position: relative;
  display: flex;
  justify-content: center;
  margin-top: 3.6rem;
}

.cta-dino img {
  width: 76px;
  height: 76px;
  filter: invert(1);
  opacity: 0.92;
}

.zzz {
  position: absolute;
  top: -1rem;
  left: calc(50% + 2.4rem);
  display: flex;
}

.zzz i {
  position: absolute;
  font-family: var(--font-display);
  font-style: normal;
  font-weight: 700;
  color: var(--green-bright);
  opacity: 0;
  animation: float-z 3.6s ease-in-out infinite;
}

.zzz i:nth-child(1) {
  font-size: 0.8rem;
}

.zzz i:nth-child(2) {
  font-size: 1rem;
  animation-delay: 1.2s;
}

.zzz i:nth-child(3) {
  font-size: 1.2rem;
  animation-delay: 2.4s;
}

@keyframes float-z {
  0% {
    opacity: 0;
    transform: translate(0, 6px) scale(0.7);
  }
  25% {
    opacity: 0.95;
  }
  70% {
    opacity: 0;
    transform: translate(14px, -20px) scale(1.2);
  }
  100% {
    opacity: 0;
    transform: translate(14px, -20px) scale(1.2);
  }
}

/* ----------------------------------------------------------
   13. Footer
   ---------------------------------------------------------- */
.site-foot {
  padding: 3.5rem 0 2.5rem;
  background: var(--night);
  color: var(--snow);
  border-top: 1px solid var(--night-line);
  color-scheme: dark;
}

.foot-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 2.5rem;
}

@media (min-width: 540px) {
  .foot-grid {
    grid-template-columns: 1fr 1fr;
  }
}

@media (min-width: 880px) {
  .foot-grid {
    grid-template-columns: 2.2fr 1fr 1fr 1fr;
    gap: 2rem;
  }
}

.foot-tag {
  max-width: 24rem;
  margin-top: 1.1rem;
  font-size: 0.9rem;
  line-height: 1.65;
  color: var(--snow-2);
}

.foot-col {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.6rem;
}

.foot-col h3 {
  margin-bottom: 0.35rem;
  font-size: 0.72rem;
  font-weight: 800;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--snow-2);
}

.foot-col a {
  font-size: 0.9rem;
  color: var(--snow);
  opacity: 0.82;
  text-decoration: none;
}

.foot-col a:hover {
  opacity: 1;
  text-decoration: underline;
  text-underline-offset: 3px;
}

.foot-legal {
  margin-top: 3rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--night-line);
  font-size: 0.8rem;
  color: var(--snow-2);
}

/* ----------------------------------------------------------
   14. Reduced motion — static final states everywhere
   ---------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  html.js [data-reveal],
  html.js [data-intro],
  html.js .mock-inbox .m-msg,
  html.js .trail .fp {
    opacity: 1;
    transform: none;
    transition: none;
  }

  html.js .trail .fp {
    opacity: 0.6;
    transform: rotate(var(--fp-rot));
  }

  .pulse-dot::after,
  .zzz i,
  .chip-cycle span,
  .m-line,
  .m-badge,
  .feed-list li.tick-in,
  .agent-feed.landed::after {
    animation: none;
  }

  /* Freeze mockups at their "finished" frame */
  .chip-cycle span {
    opacity: 0;
  }

  .chip-cycle .c-d {
    opacity: 1;
  }

  .m-badge {
    opacity: 1;
  }

  .m-line {
    transform: none;
  }

  .zzz i {
    opacity: 0.7;
    transform: translate(4px, -6px);
  }

  .zzz i:nth-child(2) {
    transform: translate(10px, -12px);
  }

  .zzz i:nth-child(3) {
    transform: translate(17px, -19px);
  }

  .btn:hover,
  .feature-card:hover {
    translate: 0 0;
  }
}

/* ============================================================
   SHARED INNER-PAGE KIT — used by pricing / merch / affiliates /
   careers / help / terms / privacy / dpa. Same night→day→night
   rhythm as home: compact dark .page-banner → light .sheet →
   dark .cta-band → dark footer. Built from the same tokens.
   ============================================================ */

/* ---------- 15. Page banner (compact night hero) ---------- */
.page-banner {
  /* Pinned like the home hero: the banner holds at the top while the daylight
     .sheet (z:3, margin-top:-34px) rises and covers it — the same night→day
     slide-over as the landing, in a compact form. Sits at the bottom of the
     stacking order so every later (opaque) section paints over it. */
  position: sticky;
  top: 0;
  z-index: 0;
  padding: clamp(7rem, 6rem + 4vw, 9rem) 0 clamp(3.5rem, 2.5rem + 3vw, 5rem);
  background: var(--night);
  color: var(--snow);
  overflow: hidden;
  color-scheme: dark;
}

.page-banner::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: radial-gradient(rgba(244, 246, 245, 0.06) 1px, transparent 1.4px);
  background-size: 30px 30px;
  -webkit-mask-image: radial-gradient(78% 80% at 72% 42%, black 18%, transparent 80%);
  mask-image: radial-gradient(78% 80% at 72% 42%, black 18%, transparent 80%);
}

.page-banner .wrap {
  position: relative;
  z-index: 2;
}

/* Ambient twinkle field — replaces the old decorative orbit echo. The hero's
   starfield, scattered by V2Motion across the banner's 30px grid and masked to
   match .page-banner::before (upper-right), so the twinkle sits where the orbit
   used to be and the left-aligned copy stays clear. Reuses @keyframes
   hero-twinkle + the --tw-* var contract. */
.banner-stars {
  position: absolute;
  inset: 0;
  pointer-events: none;
  -webkit-mask-image: radial-gradient(78% 80% at 72% 42%, black 18%, transparent 80%);
  mask-image: radial-gradient(78% 80% at 72% 42%, black 18%, transparent 80%);
}

.banner-stars i {
  position: absolute;
  width: 4px;
  height: 4px;
  margin: -2px 0 0 -2px;
  border-radius: 50%;
  background: var(--green);
  opacity: 0.24;
  transform: scale(0.5);
  animation: hero-twinkle var(--tw-dur, 5s) ease-in-out var(--tw-delay, 0s) infinite;
}

@media (prefers-reduced-motion: reduce) {
  .banner-stars i {
    animation: none;
    opacity: 0.24;
  }
}

.breadcrumb {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.8rem;
  color: var(--snow-2);
}

.breadcrumb a {
  color: var(--snow-2);
  text-decoration: none;
}

.breadcrumb a:hover {
  color: var(--snow);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.breadcrumb .sep {
  opacity: 0.45;
}

.breadcrumb [aria-current] {
  color: var(--snow);
}

.page-title {
  margin-top: 1.1rem;
  max-width: 20ch;
  font-family: var(--font-display);
  font-size: clamp(2.1rem, 1.3rem + 2.7vw, 3.2rem);
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: -0.012em;
  color: var(--snow);
  text-wrap: balance;
}

.page-title .accent {
  color: var(--green);
}

.page-lead {
  max-width: 46ch;
  margin-top: 1.1rem;
  font-size: var(--fs-lead);
  line-height: 1.6;
  color: var(--snow-2);
}

.page-date {
  margin-top: 0.9rem;
  font-size: 0.85rem;
  color: var(--snow-2);
}

/* small inline availability / status line on a banner */
.page-status {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 1.2rem;
  padding: 0.35rem 0.8rem;
  border: 1px solid var(--night-line);
  border-radius: 999px;
  font-size: 0.8rem;
  color: var(--snow-2);
}

/* Inner-page section rhythm. SCOPED to `.page-banner + .sheet` so the home
   page (which has `.hero + .sheet` and styles its sections via named classes
   like .features/.how) is never touched. Inner pages use the bare .section
   class, which otherwise carries no vertical padding.
   - every section gets full vertical padding,
   - the first breathes under the banner overlap,
   - consecutive sections drop their top so gaps never double. */
.page-banner + .sheet .section {
  padding-block: var(--space-section);
}

.page-banner + .sheet .section:first-child {
  padding-top: calc(var(--space-section) - 4px);
}

.page-banner + .sheet .section + .section {
  padding-top: 0;
}

/* ---------- 16. Tiles (help categories, affiliate benefits) ---------- */
.tile-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 1rem;
  margin-top: 2.75rem;
}

@media (min-width: 660px) {
  .tile-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 980px) {
  .tile-grid.cols-3 {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

.tile {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding: 1.4rem;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-card);
  text-decoration: none;
  color: inherit;
}

a.tile:hover {
  translate: 0 -4px;
  border-color: rgba(29, 185, 84, 0.4);
  box-shadow: var(--shadow-card-hover);
}

.tile h3 {
  font-size: 1.05rem;
  font-weight: 700;
  color: var(--ink);
}

.tile p {
  font-size: 0.9rem;
  line-height: 1.55;
  color: var(--ink-2);
}

.tile-more {
  margin-top: auto;
  padding-top: 0.3rem;
  font-size: 0.8rem;
  font-weight: 700;
  color: var(--green-deep);
}

.tile[hidden] {
  display: none;
}

/* ---------- 17. Prose + legal layout ---------- */
.legal-wrap {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 2.5rem;
  margin-top: 2.5rem;
}

@media (min-width: 940px) {
  .legal-wrap {
    grid-template-columns: 15rem minmax(0, 1fr);
    gap: 4rem;
  }
}

.toc {
  min-width: 0;
}

.toc h2 {
  font-size: 0.72rem;
  font-weight: 800;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-2);
}

.toc ol {
  list-style: none;
  margin: 0.9rem 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}

.toc a {
  display: block;
  padding: 0.15rem 0;
  font-size: 0.85rem;
  line-height: 1.4;
  color: var(--ink-2);
  text-decoration: none;
  border-left: 2px solid transparent;
  padding-left: 0.8rem;
  margin-left: -0.8rem;
  transition: color 0.2s, border-color 0.2s;
}

.toc a:hover {
  color: var(--ink);
}

.toc a.active {
  color: var(--green-deep);
  border-color: var(--green-deep);
  font-weight: 600;
}

@media (min-width: 940px) {
  .toc {
    position: sticky;
    top: 6rem;
    align-self: start;
    max-height: calc(100vh - 8rem);
    overflow-y: auto;
  }
}

.prose {
  max-width: 70ch;
  color: var(--ink-2);
}

.prose > * + * {
  margin-top: 1.05rem;
}

.prose h2 {
  margin-top: 2.6rem;
  font-family: var(--font-display);
  font-size: 1.4rem;
  font-weight: 700;
  line-height: 1.25;
  color: var(--ink);
  scroll-margin-top: 6rem;
}

.prose h2:first-child {
  margin-top: 0;
}

.prose h3 {
  margin-top: 1.8rem;
  font-size: 1.05rem;
  font-weight: 700;
  color: var(--ink);
  scroll-margin-top: 6rem;
}

.prose p,
.prose li {
  font-size: 0.97rem;
  line-height: 1.72;
  color: var(--ink-2);
}

.prose strong {
  color: var(--ink);
  font-weight: 700;
}

.prose a {
  color: var(--green-deep);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.prose ul {
  margin-top: 0.8rem;
  padding-left: 1.1rem;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.prose li {
  padding-left: 0.3rem;
}

.prose li::marker {
  color: var(--green-deep);
}

.contact-card {
  margin-top: 1.4rem;
  padding: 1.3rem 1.5rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
}

.contact-card ul {
  list-style: none;
  margin: 0.5rem 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  font-size: 0.95rem;
  color: var(--ink-2);
}

.contact-card a {
  color: var(--green-deep);
}

/* responsive data table (DPA sub-processors) */
.table-scroll {
  margin-top: 1.1rem;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
}

.data-table {
  width: 100%;
  min-width: 34rem;
  border-collapse: collapse;
  font-size: 0.875rem;
}

.data-table th,
.data-table td {
  padding: 0.7rem 0.9rem;
  text-align: left;
  vertical-align: top;
  border-bottom: 1px solid var(--line);
}

.data-table th {
  font-weight: 700;
  color: var(--ink);
  background: var(--surface);
  position: sticky;
  top: 0;
}

.data-table td {
  color: var(--ink-2);
}

.data-table tr:last-child td {
  border-bottom: 0;
}

/* ---------- 18. FAQ (native <details>, no JS) ---------- */
.faq {
  margin-top: 2.75rem;
  border-top: 1px solid var(--line);
}

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

.faq summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.15rem 0;
  font-size: 1rem;
  font-weight: 600;
  color: var(--ink);
  cursor: pointer;
  list-style: none;
}

.faq summary::-webkit-details-marker {
  display: none;
}

.faq-plus {
  position: relative;
  flex: none;
  width: 1.1rem;
  height: 1.1rem;
}

.faq-plus::before,
.faq-plus::after {
  content: "";
  position: absolute;
  inset: 0;
  margin: auto;
  background: var(--ink-2);
  border-radius: 2px;
}

.faq-plus::before {
  width: 1.1rem;
  height: 2px;
}

.faq-plus::after {
  width: 2px;
  height: 1.1rem;
  transition: transform 0.3s var(--ease-out);
}

.faq details[open] .faq-plus::after {
  transform: rotate(90deg);
}

.faq-answer {
  padding: 0 0 1.2rem;
  max-width: 64ch;
  font-size: 0.95rem;
  line-height: 1.68;
  color: var(--ink-2);
}

.faq-answer a {
  color: var(--green-deep);
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* ---------- 19. Pricing ---------- */
.pricing-controls {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
  /* No top margin: the cards-section padding already supplies the lead-in gap,
     and the compare instance gets its gap from the intro's margin-bottom. */
  margin-top: 0;
}

/* the Monthly / Annual pill + save badge share one row under the sentence */
.billing-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 1rem;
}

/* inline-sentence audience selector — "Show me plans for [myself v]". One
   toggle button flips personal/team; the visible label swaps via .show-team,
   and it drives the same #pricing-plans state as the cards (no React state),
   so the cards + both compare matrices + every selector stay in lockstep. */
.plan-switch {
  font-size: var(--fs-lead);
  color: var(--ink-2);
  text-align: center;
}

.plan-switch button {
  border: 0;
  background: transparent;
  padding: 0 0 0.12rem;
  font: inherit;
  font-weight: 700;
  color: var(--ink);
  border-bottom: 2px solid var(--green-deep);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 0.28rem;
  transition: color 0.2s var(--ease-out);
}

.plan-switch button:hover {
  color: var(--green-deep);
}

.plan-switch button svg {
  color: var(--green-deep);
}

.plan-switch .lbl-team {
  display: none;
}

.pricing-plans.show-team .plan-switch .lbl-personal {
  display: none;
}

.pricing-plans.show-team .plan-switch .lbl-team {
  display: inline;
}

.seg {
  display: inline-flex;
  padding: 0.25rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 999px;
}

.seg button {
  border: 0;
  background: transparent;
  padding: 0.5rem 1.05rem;
  border-radius: 999px;
  font: inherit;
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--ink-2);
  cursor: pointer;
  transition: color 0.2s var(--ease-out), background-color 0.2s var(--ease-out);
}

.seg button[aria-pressed="true"] {
  background: var(--paper);
  color: var(--ink);
  box-shadow: var(--shadow-sm);
}

.save-badge {
  font-size: 0.72rem;
  font-weight: 800;
  letter-spacing: 0.03em;
  color: var(--green-deep);
  background: var(--green-soft);
  padding: 0.35rem 0.65rem;
  border-radius: 999px;
}

.tier-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 1rem;
  margin-top: 2.5rem;
}

@media (min-width: 720px) {
  .tier-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 1080px) {
  .tier-grid.cols-4 {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }

  .tier-grid.cols-3 {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

/* category switch — pure CSS via container class */
.pricing-plans:not(.show-team) .tier-grid.team {
  display: none;
}

.pricing-plans.show-team .tier-grid.personal {
  display: none;
}

/* Compare matrices span the full content width — unlike the cards they are NOT
   in the 2-column .tier-grid (which clipped them to half width). The audience
   toggle shows one set at a time, mirroring the .tier-grid swap above. */
.compare-set {
  margin-top: 1.5rem;
}

.pricing-plans:not(.show-team) .compare-set.team {
  display: none;
}

.pricing-plans.show-team .compare-set.personal {
  display: none;
}

.tier {
  display: flex;
  flex-direction: column;
  padding: 1.5rem;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-card);
}

.tier.featured {
  position: relative;
  border-color: var(--green);
  box-shadow: 0 0 0 1px var(--green), var(--shadow-card-hover);
}

.tier-badge {
  position: absolute;
  top: -0.7rem;
  left: 50%;
  translate: -50% 0;
  padding: 0.25rem 0.7rem;
  border-radius: 999px;
  background: var(--green);
  color: #08130c;
  font-size: 0.68rem;
  font-weight: 800;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

.tier h3 {
  font-family: var(--font-display);
  font-size: 1.25rem;
  font-weight: 700;
  color: var(--ink);
}

.tier .tier-desc {
  margin-top: 0.2rem;
  font-size: 0.85rem;
  color: var(--ink-2);
}

.tier .price {
  display: flex;
  align-items: baseline;
  gap: 0.3rem;
  margin-top: 1.1rem;
}

.tier .amt {
  font-family: var(--font-display);
  font-size: 2.3rem;
  font-weight: 700;
  line-height: 1;
  color: var(--ink);
}

.tier .per {
  font-size: 0.78rem;
  color: var(--ink-2);
}

.tier .note {
  margin-top: 0.3rem;
  min-height: 1rem;
  font-size: 0.75rem;
  color: var(--ink-faint);
}

.tier .btn {
  width: 100%;
  margin-top: 1.2rem;
}

.tier ul {
  list-style: none;
  margin: 1.2rem 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}

.tier li {
  display: flex;
  gap: 0.55rem;
  font-size: 0.85rem;
  line-height: 1.45;
  color: var(--ink-2);
}

.tier li svg {
  flex: none;
  margin-top: 0.15rem;
  color: var(--green-deep);
}

/* billing period swap — pure CSS */
.amt-a,
.note-a {
  display: none;
}

.period-annual .amt-m,
.period-annual .note-m {
  display: none;
}

.period-annual .amt-a,
.period-annual .note-a {
  display: inline;
}

/* ---------- 20. Merch (CSS/SVG product cards — no photos) ---------- */
.merch-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 1.2rem;
  margin-top: 2.75rem;
}

@media (min-width: 760px) {
  .merch-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

.merch-card {
  display: flex;
  flex-direction: column;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-card);
  overflow: hidden;
}

.merch-shot {
  position: relative;
  display: grid;
  place-items: center;
  aspect-ratio: 4 / 3;
  background: radial-gradient(circle at 50% 35%, #eef1ef, #e4e8e5);
  color: var(--ink);
}

.merch-shot svg {
  width: 56%;
  height: auto;
}

.sold-out {
  position: absolute;
  top: 0.8rem;
  right: 0.8rem;
  padding: 0.3rem 0.65rem;
  border-radius: 999px;
  background: rgba(20, 24, 21, 0.82);
  color: var(--snow);
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.03em;
}

.merch-body {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  padding: 1.2rem 1.3rem 1.4rem;
}

.merch-body h3 {
  font-size: 1.05rem;
  font-weight: 700;
  color: var(--ink);
}

.merch-body .merch-tag {
  font-size: 0.85rem;
  color: var(--ink-2);
}

.merch-body .merch-price {
  margin-top: 0.5rem;
  font-family: var(--font-display);
  font-size: 1.2rem;
  font-weight: 700;
  color: var(--ink);
}

.size-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-top: 0.8rem;
}

.size-chip {
  padding: 0.2rem 0.5rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  font-size: 0.72rem;
  color: var(--ink-faint);
  text-decoration: line-through;
}

/* ---------- 21. Empty state (careers) + notify form ---------- */
.empty-card {
  margin-top: 2.5rem;
  padding: clamp(2rem, 5vw, 3.5rem);
  border: 1.5px dashed var(--line);
  border-radius: var(--r-lg);
  text-align: center;
}

.empty-card p {
  max-width: 48ch;
  margin-inline: auto;
  color: var(--ink-2);
  line-height: 1.65;
}

.empty-card .empty-lead {
  font-family: var(--font-display);
  font-size: 1.2rem;
  font-weight: 700;
  color: var(--ink);
  margin-bottom: 0.6rem;
}

.empty-card a {
  color: var(--green-deep);
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 2px;
}

.notify {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  max-width: 28rem;
  margin-top: 1.5rem;
}

.notify input {
  flex: 1 1 12rem;
  min-width: 0;
  height: 3rem;
  padding: 0 1rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--paper);
  font: inherit;
  font-size: 0.95rem;
  color: var(--ink);
}

.notify input::placeholder {
  color: var(--ink-faint);
}

.notify input:focus-visible {
  outline: 2px solid var(--green-deep);
  outline-offset: 1px;
  border-color: transparent;
}

.notify .btn {
  flex: none;
}

/* centered narrow intro for simple pages */
.lede {
  max-width: 52rem;
}

.lede.center {
  margin-inline: auto;
  text-align: center;
}

/* ---------- 22. Inner-page reduced-motion + hover guards ---------- */
@media (prefers-reduced-motion: reduce) {
  a.tile:hover {
    translate: 0 0;
  }

  .faq details[open] .faq-plus::after,
  .toc a {
    transition: none;
  }
}

/* ============================================================
   23. HOME DEMO — the daylight sheet's OWN rounded top IS the
   browser: macOS chrome (traffic lights + claos.ai address bar) sits
   flush in the sheet's rounded top edge, the real <DemoAppShell> as
   the browser content, full-bleed to the section edges. The page
   literally "opens" claos.ai — and a white dino mascot stands on that
   top edge, its body over the dark hero (see v2-hero-dino), greeting
   the browser as it rises. Chips come alive on scroll.
   ============================================================ */
.demo-section {
  padding: 0; /* flush — the sheet's rounded top frames the browser */
  position: relative; /* anchors the ::after shadow-pool below the demo */
}

/* Soft shadow POOL under the demo — an elliptical radial glow strongest under the
   centre and fading to nothing toward the left/right edges and downward. Unlike a
   box-shadow (which on an edge-to-edge element is a full-width divider band), this
   tapers at the sides, so it reads as a floating window's shadow and dissolves
   smoothly into the page. pointer-events:none so it never blocks the content it
   overlaps below. */
.demo-section::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  top: 100%; /* begins exactly at the demo's bottom edge */
  height: 120px;
  pointer-events: none;
  background: radial-gradient(
    92% 120% at 50% 0%,
    rgba(15, 23, 17, 0.03) 0%,
    rgba(15, 23, 17, 0.014) 45%,
    transparent 82%
  );
}

/* Hidden while the demo is pinned full-screen (it owns the viewport; the section
   collapses) so the pool doesn't peek out behind the lock. */
html.demo-entering .demo-section::after,
html.demo-takeover .demo-section::after {
  display: none;
}

.demo-os {
  --demo-side: 240px;
  background: var(--paper);
  /* clips its own rounded top (matching the sheet) now that the sheet no
     longer uses overflow:hidden — keeps the browser flush in the rounded edge */
  border-radius: var(--radius-sheet) var(--radius-sheet) 0 0;
  overflow: hidden;
  /* No box-shadow here: on an edge-to-edge element it becomes a full-width
     horizontal band that reads as a divider line. The separation is instead a
     side-tapering radial glow on .demo-section::after below — softest at the
     edges, so it reads as a floating shadow pool, not a ruled line. */
}

/* browser chrome — traffic lights left, claos.ai address bar centered */
.demo-chrome {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  height: 46px;
  padding: 0 1.15rem;
  background: var(--surface);
  border-bottom: 1px solid var(--line);
}

.demo-lights {
  display: inline-flex;
  gap: 0.5rem;
  justify-self: start;
}

.demo-lights i {
  width: 0.72rem;
  height: 0.72rem;
  border-radius: 50%;
}

/* standard macOS window-control colors — UI chrome, not brand tokens */
.demo-lights .red {
  background: #ff5f57;
}
.demo-lights .yellow {
  background: #febc2e;
}
.demo-lights .green {
  background: #28c840;
}

.demo-address {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  justify-self: center;
  min-width: min(60vw, 16rem);
  padding: 0.32rem 1rem;
  border-radius: 999px;
  background: var(--paper);
  border: 1px solid var(--line);
  font-size: 0.75rem;
  color: var(--ink-2);
}

.demo-address svg {
  flex: none;
  color: var(--ink-faint);
}

.demo-body {
  /* Holds the real interactive <DemoAppShell> (v1 parity). Definite height so the
     app demo's full-height layout fills the browser frame. Sized so the whole
     demo-os (this body + 47px of chrome+border) fills exactly the viewport BELOW
     the fixed 66px header — i.e. 47 + 66 = 113px reserved — so when scrolled with
     the nav just above it, the browser's bottom meets the bottom of the screen. */
  height: clamp(560px, calc(100vh - 113px), 1280px);
}

/* ---- sidebar ---- */
.demo-side {
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
  width: var(--demo-side);
  flex: none;
  padding: 0.85rem 0.7rem;
  border-right: 1px solid var(--line);
  background: var(--surface);
}

.demo-ws {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.15rem 0.3rem;
}

.demo-ws-avatar {
  display: grid;
  place-items: center;
  width: 1.65rem;
  height: 1.65rem;
  flex: none;
  border-radius: 8px;
  background: var(--green);
  color: #08130c;
  font-size: 0.78rem;
  font-weight: 800;
}

.demo-ws-name {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--ink);
}

.demo-ws-switch {
  margin-left: auto;
  color: var(--ink-faint);
}

.demo-row {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.42rem 0.55rem;
  border-radius: 9px;
  font-size: 0.82rem;
  color: var(--ink-2);
}

.demo-row svg {
  flex: none;
  color: var(--ink-faint);
}

.demo-row.is-active {
  background: var(--green-soft);
  color: var(--green-deep);
  font-weight: 600;
}

.demo-row.is-active svg {
  color: var(--green-deep);
}

.demo-search {
  border: 1px solid var(--line);
  background: var(--paper);
  color: var(--ink-faint);
}

.demo-nav {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
}

.demo-group-label {
  padding: 0 0.55rem;
  margin-bottom: 0.3rem;
  font-size: 0.66rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.demo-group {
  display: flex;
  flex-direction: column;
}

.demo-empty {
  padding: 0 0.55rem;
  font-size: 0.74rem;
  color: var(--ink-faint);
}

.demo-side-foot {
  margin-top: auto;
}

/* ---- main panel ---- */
.demo-main {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-width: 0;
}

.demo-topbar {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.7rem 1.1rem;
  border-bottom: 1px solid var(--line);
}

.demo-crumb {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  min-width: 0;
  font-size: 0.8rem;
  color: var(--ink-faint);
}

.demo-crumb b {
  font-weight: 600;
  color: var(--ink);
}

.demo-crumb .demo-sep {
  opacity: 0.5;
}

.demo-top-actions {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  margin-left: auto;
}

.demo-top-actions svg {
  color: var(--ink-faint);
}

.demo-user {
  display: grid;
  place-items: center;
  width: 1.7rem;
  height: 1.7rem;
  border-radius: 50%;
  background: var(--green-soft);
  color: var(--green-deep);
  font-size: 0.68rem;
  font-weight: 800;
}

.demo-canvas {
  display: flex;
  flex-direction: column;
  flex: 1;
  padding: 1.4rem 1.2rem 2rem;
}

.demo-statline {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.4rem 1rem;
  font-size: 0.76rem;
  color: var(--ink-faint);
}

.demo-stat {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
}

.demo-stat svg {
  opacity: 0.8;
}

.demo-convo {
  width: 100%;
  max-width: 40rem;
  margin: clamp(1.5rem, 5vh, 3rem) auto 0;
}

.demo-bubble {
  position: relative;
  padding: 0.95rem 1.15rem;
  border-radius: 16px 16px 16px 4px;
  background: var(--surface);
  border: 1px solid var(--line);
  font-size: 0.95rem;
  line-height: 1.55;
  color: var(--ink);
}

.demo-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin-top: 1rem;
}

.demo-chip {
  padding: 0.55rem 1rem;
  border-radius: 999px;
  border: 1px solid rgba(29, 185, 84, 0.35);
  background: var(--green-soft);
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--green-deep);
}

@media (max-width: 760px) {
  .demo-side {
    display: none;
  }

  /* Tighten the hero on phones: lift the agent feed closer to the copy and clip
     the rows window to the two freshest rows (the rest age out exactly as on
     desktop), so the demo section comes into view sooner. The header + the
     "N tasks finished" footer stay, so it still reads as a live feed.

     The hero is min(100svh - --peek); its content intrinsically overflows a
     phone viewport, which eats the 58px browser-chrome peek. Reclaim ~120px of
     vertical rhythm here (padding + inter-element margins + feed chrome) so the
     demo browser's top edge crests into the first screen, not just the dino. */
  .hero {
    /* Bottom padding is a BUFFER: the daylight sheet rises ~40px over the hero's
       bottom edge for the reveal, so this keeps that overlap off the agent feed.
       The vertical space is reclaimed from margins + inline CTAs below instead. */
    padding: 5rem 0 3.75rem;
  }

  .hero-inner {
    gap: 1.05rem;
  }

  .hero-title {
    margin-top: 0.85rem;
    /* Trim the headline on phones (was up to 2.4rem) — a real mobile browser's
       bottom toolbar eats ~48–90px of the usable viewport, so the hero content
       has to be that much shorter for the browser mockup to still crest. */
    font-size: 2.05rem;
  }

  .hero-lead {
    margin-top: 0.85rem;
    font-size: 1rem;
    line-height: 1.42;
  }

  /* Sit the two CTAs on one row (was stacked, ~109px → ~52px) — the single
     biggest reclaim, and enough to keep the whole agent feed clear of the
     rising daylight sheet while the browser chrome still peeks. */
  .hero-ctas {
    margin-top: 1.35rem;
    flex-wrap: nowrap;
    gap: 0.6rem;
  }

  .hero-ctas .btn {
    flex: 1 1 0;
    min-width: 0;
    justify-content: center;
    padding-inline: 0.85rem;
    white-space: nowrap;
  }

  .hero-note {
    margin-top: 0.7rem;
  }

  .agent-feed {
    padding: 0.8rem 1rem 0.7rem;
  }

  .feed-foot {
    margin-top: 0.4rem;
    padding-top: 0.6rem;
  }

  .feed-list {
    height: 5.7rem; /* exactly 2 rows (was 12.6rem / 4), a touch tighter on phones */
  }

  .feed-list::after {
    height: 0.8rem; /* subtler bottom fade to match the shorter 2-row window */
  }

  /* Hold the floating support bubble back on the first mobile screen (so it
     doesn't cover the home demo's dino greeting); reveal it once the visitor
     scrolls past ~half a viewport. V2Motion toggles .support-shown on <html> — a
     plain :not() class (no :has()) so the toggle invalidates style reliably.
     Hidden from first paint, so there's no flash. */
  html [aria-label^="Open support chat"] {
    transition: opacity 0.3s ease, transform 0.3s ease;
  }

  html:not(.support-shown) [aria-label^="Open support chat"] {
    opacity: 0;
    transform: scale(0.85) translateY(10px);
    pointer-events: none;
  }

  .demo-body {
    min-height: clamp(380px, 70vh, 520px);
  }

  .demo-canvas {
    padding: 1.2rem 1rem 1.6rem;
  }
}

/* ============================================================
   24. SCROLL CHOREOGRAPHY — the demo "types to life" on reveal, and
   a finished-work particle hands off from the orbit into the browser.
   Hidden states scoped to html.js (no-JS shows the final frame);
   reduced motion jumps straight to the final frame.
   ============================================================ */

/* --- demo: typing indicator → greeting → chips --- */
.demo-typing {
  position: absolute;
  top: 1.05rem;
  left: 1.15rem;
  display: inline-flex;
  align-items: center;
  gap: 0.32rem;
  opacity: 0;
  transition: opacity 0.3s var(--ease-out);
}

.demo-typing i {
  width: 0.42rem;
  height: 0.42rem;
  border-radius: 50%;
  background: var(--ink-faint);
}

html.js .demo-greeting-text {
  opacity: 0;
  transition: opacity 0.45s var(--ease-out);
}

html.js .demo-chip {
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.4s var(--ease-out), transform 0.4s var(--ease-out);
}

/* armed: the demo is in view, assistant is "typing" */
html.js .demo-os.is-armed .demo-typing {
  opacity: 1;
}

html.js .demo-os.is-armed .demo-typing i {
  animation: demo-type 1.2s ease-in-out infinite;
}

.demo-typing i:nth-child(2) {
  animation-delay: 0.15s;
}
.demo-typing i:nth-child(3) {
  animation-delay: 0.3s;
}

@keyframes demo-type {
  0%, 60%, 100% {
    transform: translateY(0);
    opacity: 0.4;
  }
  30% {
    transform: translateY(-3px);
    opacity: 1;
  }
}

/* live: greeting "sent", typing gone, chips stagger in */
html.js .demo-os.is-live .demo-typing {
  opacity: 0;
}

html.js .demo-os.is-live .demo-greeting-text {
  opacity: 1;
}

html.js .demo-os.is-live .demo-chip {
  opacity: 1;
  transform: none;
}

html.js .demo-os.is-live .demo-chip:nth-child(1) {
  transition-delay: 0.45s;
}
html.js .demo-os.is-live .demo-chip:nth-child(2) {
  transition-delay: 0.55s;
}
html.js .demo-os.is-live .demo-chip:nth-child(3) {
  transition-delay: 0.65s;
}
html.js .demo-os.is-live .demo-chip:nth-child(4) {
  transition-delay: 0.75s;
}

@media (prefers-reduced-motion: reduce) {
  .demo-typing {
    display: none;
  }

  html.js .demo-greeting-text,
  html.js .demo-chip {
    opacity: 1;
    transform: none;
    transition: none;
  }

  .demo-typing i {
    animation: none;
  }
}

/* ============================================================
   25. PEEK INTERACTION — while the hero is at rest, the next
   section (the browser) peeks at the bottom. It bobs gently to
   signal "alive / more below"; hover lifts it to preview more;
   clicking it scrolls the section into view (wired in script.js).
   `.is-peeking` is toggled on .sheet by the scroll handler.
   ============================================================ */
/* Bob the WHOLE section. Driven by the `translate` property (not `transform`)
   so it composes with the hover-lift below — which uses `transform` — instead
   of the two fighting over one property. Result: the entire peeking section
   rises and settles as one unit, and hover lifts it on top while it bobs. */
@keyframes peek-bob {
  0%,
  100% {
    translate: 0 0;
  }
  50% {
    translate: 0 -7px;
  }
}

.sheet.is-peeking {
  cursor: pointer;
  animation: peek-bob 2.8s ease-in-out infinite;
  transition: transform 0.45s var(--ease-out);
}

/* hover the visible peek → lift the whole section to reveal more of the app */
.sheet.is-peeking:hover {
  transform: translateY(-44px);
}

@media (prefers-reduced-motion: reduce) {
  .sheet.is-peeking {
    animation: none;
  }

  .sheet.is-peeking:hover {
    transform: none;
  }
}

/* ── Lenis smooth scroll (required rules; v2 pages only) ───────────────────── */
html.lenis,
html.lenis body { height: auto; }
.lenis:not(.lenis-autoToggle).lenis-stopped { overflow: clip; }
.lenis [data-lenis-prevent],
.lenis [data-lenis-prevent-wheel],
.lenis [data-lenis-prevent-touch] { overscroll-behavior: contain; }
.lenis.lenis-smooth iframe { pointer-events: none; }

/* ── Voices carousel — one-row auto-scrolling marquee (3+ cards in view) ────── */
.voices-marquee {
  margin-top: clamp(2.5rem, 1.8rem + 2vw, 3.75rem);
  overflow: hidden;
  -webkit-mask-image: linear-gradient(to right, transparent, #000 6%, #000 94%, transparent);
  mask-image: linear-gradient(to right, transparent, #000 6%, #000 94%, transparent);
}
.voices-track {
  display: flex;
  width: max-content;
  animation: voices-scroll 40s linear infinite;
}
.voices-track > .quote {
  flex: 0 0 auto;
  width: min(23rem, 80vw);
  margin: 0 clamp(1rem, 2vw, 1.5rem) 0 0; /* margin (not gap) so the -50% loop tiles exactly */
}
.voices-marquee:hover .voices-track,
.voices-track:focus-within {
  animation-play-state: paused;
}
@keyframes voices-scroll {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}
@media (prefers-reduced-motion: reduce) {
  .voices-marquee { overflow: visible; -webkit-mask-image: none; mask-image: none; }
  .voices-track {
    animation: none;
    width: auto;
    flex-wrap: wrap;
    justify-content: center;
    gap: clamp(1rem, 2vw, 1.5rem);
  }
  .voices-track > .quote { margin: 0; }
  .voices-track > .quote[aria-hidden="true"] { display: none; }
}

/* ── Demo: undo this file's margin reset inside the embedded app ─────────────
   This stylesheet's `*{margin:0}` (section 2) is UNLAYERED, so it overrides
   Tailwind's margin utilities (which live in `@layer utilities`) on every node
   of the embedded <DemoAppShell> — silently killing `mx-auto` (so the chat
   column went flush-left instead of centred) and `space-y-*` gaps (so the
   greeting/chips spacing collapsed). Padding survives because the reset never
   touches it. `revert-layer` rolls margin back to the Tailwind layer, handing
   those nodes their normal values — so the demo renders exactly like the
   post-signup full-screen version. Scoped to .demo-body → the browser chrome,
   the rest of the marketing page, and the real product are all untouched. */
.demo-body *,
.demo-body *::before,
.demo-body *::after {
  margin: revert-layer;
}

/* ============================================================
   GHOST SCROLL RAIL — a thin progress thumb on the right edge. The
   native scrollbar is hidden on v2 (html.v2-day) because Lenis drives
   smooth scroll, so this replaces it with the app's ghost aesthetic.
   V2Motion sizes/positions the thumb off window.scrollY and toggles
   .is-scrolling. A neutral mid-grey reads on both the dark hero and the
   light daylight sheet. pointer-events:none — never hijacks the wheel.
   ============================================================ */
.v2-scrollrail {
  position: fixed;
  top: 0;
  right: 3px;
  width: 6px;
  height: 100vh;
  height: 100dvh;
  z-index: 90;
  /* Track is inert — only the thumb takes pointer events (below), so the rail
     never blocks clicks on the page beneath it. */
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.35s ease;
}

.v2-scrollrail.is-scrolling,
.v2-scrollrail.is-dragging {
  opacity: 1;
}

.v2-scrollrail-thumb {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 40px;
  border-radius: 9999px;
  background: rgba(145, 148, 156, 0.55);
  box-shadow: 0 0 0 0.5px rgba(0, 0, 0, 0.06);
  /* Grabbable like the app's native scrollbar — V2Motion drives drag-to-scroll. */
  pointer-events: auto;
  cursor: grab;
  will-change: transform;
  transition: background 0.15s ease;
}

/* Keep the visible thumb thin but give it a wider transparent grab zone so it's
   still easy to catch with the cursor (inherits the thumb's pointer-events). */
.v2-scrollrail-thumb::before {
  content: "";
  position: absolute;
  inset: -2px -9px;
}

.v2-scrollrail-thumb:hover {
  background: rgba(145, 148, 156, 0.78);
}

.v2-scrollrail.is-dragging .v2-scrollrail-thumb {
  background: rgba(145, 148, 156, 0.85);
  cursor: grabbing;
}

@media (prefers-reduced-motion: reduce) {
  .v2-scrollrail {
    transition: none;
  }
}

/* ============================================================
   DEMO SCROLL-TAKEOVER (home · desktop · motion-OK only)
   When V2Motion adds `.demo-takeover` to <html>, the demo browser
   pins full-viewport, the header slides away, and a dim layer
   recedes the rest of the page so it reads as stepping into the
   real app. Released by the Continue pill / Esc / on demo
   completion (V2Motion removes the class + restarts Lenis).

   The chrome (dim + pill) is display:none by default, so it costs
   nothing before engage, and on mobile / reduced motion (where
   V2Motion never adds the class) the section just renders inline
   as before. Lenis.stop() supplies the actual scroll-lock
   (.lenis-stopped → overflow:clip); these rules are the visuals.
   ============================================================ */
.demo-dim,
.demo-continue {
  display: none;
}

/* Two phases share these "entry" styles:
   • `.demo-entering` — added on click BEFORE the glide, while the demo is still
     peeking off-screen, so the header retracts and the demo pre-sizes to the full
     viewport invisibly. The glide then carries an already-full-size, header-less
     demo up to the very top.
   • `.demo-takeover` — added when the glide settles. It only flips the demo to
     position:fixed (a positionless, sizeless change), so the lock is seamless —
     no jump from "just below the header" to full screen. */

/* Header slides up + fades out so the demo glides into a clean viewport. The
   `.demo-immersive` case is the post-release, no-lock state: V2Motion toggles it
   by scroll coverage so scrolling back over the full-bleed demo also hides the
   nav (it slides back down when you scroll away). */
html.demo-entering .site-head,
html.demo-takeover .site-head,
html.demo-immersive .site-head {
  transform: translateY(-130%);
  opacity: 0;
  pointer-events: none;
  transition:
    transform 0.6s var(--ease-out),
    opacity 0.5s ease;
}

/* The sheet's peek-bob animates the `translate` property, which (like transform)
   establishes a containing block for fixed descendants — that would pin .demo-os
   to the sheet's box instead of the viewport. Neutralize every transform-family
   prop; engage also strips .is-peeking in JS so the higher-specificity
   `.is-peeking:hover` transform can't re-trap it. */
html.demo-entering .sheet,
html.demo-takeover .sheet {
  animation: none;
  translate: none;
  transform: none;
  transition: none;
}

/* Pre-size to the full viewport below the 46px chrome bar (overrides the in-flow
   clamp). Applied during `.demo-entering` while the demo is still below the fold,
   so the growth is invisible and the demo arrives at the top already full-size.
   dvh so mobile browser chrome doesn't clip it. */
html.demo-entering .demo-body,
html.demo-takeover .demo-body {
  height: calc(100vh - 46px);
  height: calc(100dvh - 46px);
}

/* Top corners stay rounded so it reads as an app window over the dimmed page. */
html.demo-entering .demo-os,
html.demo-takeover .demo-os {
  border-radius: var(--radius-sheet) var(--radius-sheet) 0 0;
  border-bottom: 0;
}

/* The lock: flip to fixed full-viewport. No size/position change vs the glided-in
   state (already top:0, full height), so there's nothing to animate — seamless. */
html.demo-takeover .demo-os {
  position: fixed;
  inset: 0;
  z-index: 90;
}

/* macOS traffic-light buttons double as an exit while the demo owns the screen. */
html.demo-takeover .demo-lights {
  cursor: pointer;
}

/* Post-release (no lock): once the takeover has been exited, the demo stays a
   full-viewport, full-bleed panel in normal flow — so scrolling back up to it
   reads like the full-screen experience, just freely scrollable. (Height + rounded
   top match the takeover; NOT position:fixed, so the page scrolls normally.) */
html.demo-released .demo-body {
  height: calc(100vh - 46px);
  height: calc(100dvh - 46px);
}

/* Released keeps the base closed-window frame (bottom border + soft shadow) — no
   override needed beyond the full-bleed height above. */

/* Dim/blur the rest of the page behind the pinned demo. */
html.demo-takeover .demo-dim {
  display: block;
  position: fixed;
  inset: 0;
  z-index: 80;
  background: rgba(8, 11, 9, 0.55);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
  animation: demo-dim-in 0.5s ease both;
}

@keyframes demo-dim-in {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

/* The always-visible escape: a Continue pill in the bottom-right corner — clear
   of the demo's centred chat composer (which it used to cover). */
html.demo-takeover .demo-continue {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  position: fixed;
  z-index: 95;
  right: clamp(1rem, 3vw, 2rem);
  bottom: clamp(1rem, 3vh, 2.25rem);
  padding: 0.62rem 1.15rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--paper);
  color: var(--ink);
  font: inherit;
  font-size: 0.85rem;
  font-weight: 600;
  cursor: pointer;
  box-shadow: 0 8px 24px -10px rgba(0, 0, 0, 0.4);
  animation: demo-continue-in 0.5s var(--ease-out) 0.25s both;
  transition:
    transform 0.2s var(--ease-out),
    box-shadow 0.2s,
    background-color 0.3s,
    color 0.3s;
}

html.demo-takeover .demo-continue:hover {
  transform: translateY(-2px);
  box-shadow: 0 12px 28px -10px rgba(0, 0, 0, 0.45);
}

html.demo-takeover .demo-continue svg {
  animation: demo-continue-bob 1.8s ease-in-out infinite;
}

@keyframes demo-continue-in {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes demo-continue-bob {
  0%,
  100% {
    transform: translateY(0);
  }
  50% {
    transform: translateY(3px);
  }
}

/* Once the demo finishes building the workspace, V2Motion adds `.demo-complete`
   (the scroll lock is already released by then) — turn the pill into a positive
   "you're done, carry on" affordance. */
html.demo-takeover.demo-complete .demo-continue {
  background: var(--green);
  border-color: transparent;
  color: #fff;
}

/* The demo's chat composer is centred (max-w-2xl). On wide screens the bottom-
   right Continue pill clears it, but below ~1140px the composer is wide enough to
   sit under the pill — so lift the pill above the composer there (rather than
   narrowing the shared composer, which the real app also uses). Placed AFTER the
   base `.demo-continue` bottom rule so it wins on equal specificity. */
@media (max-width: 1140px) {
  html.demo-takeover .demo-continue {
    bottom: 6.5rem;
  }
}

/* The floating support bubble + its proactive teaser would break the full-screen
   illusion — hide both while the demo owns the screen. */
html.demo-takeover [aria-label^="Open support chat"],
html.demo-takeover [data-proactive-trigger] {
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease;
}

@media (prefers-reduced-motion: reduce) {
  html.demo-takeover .site-head,
  html.demo-takeover .demo-os,
  html.demo-takeover .demo-dim,
  html.demo-takeover .demo-continue {
    animation: none;
  }
}
