/* ===================================================================
   TradingVox: global stylesheet, loaded on every page after tokens.css.
   Section map: Reset → Chrome (progress/cursor/grain) → Nav → Buttons →
   Hero → Marquee → Reveal → Stats → How-it-works → Demo widget → Orb →
   Ecosystem → Features → Tiers → CTA → Footer → Standalone auth pages (split product canvas) →
   Responsive.
   Page-specific layers (content.css, pricing.css) load after this file
   and are scoped to their own class prefixes so they never fight this one.
   =================================================================== */

/* ===== Reset ===== */
* { box-sizing: border-box; }
html { scroll-behavior: auto; }
html, body { margin: 0; padding: 0; }
body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: var(--fs-md);
  font-weight: var(--fw-body);
  line-height: 1.55;
  overflow-x: hidden;
  position: relative;
}
h1, h2, h3, p, ul, figure { margin: 0; }
img { max-width: 100%; display: block; }
a { color: inherit; }
button { font: inherit; }
/* Every component that toggles visibility via the `hidden` attribute
   (feature-card filtering, the Vox-mode preview panels, FAQ search, empty
   states) needs this to actually work: `hidden`'s UA-stylesheet
   `display:none` loses to ANY author rule that sets `display` on the same
   element (e.g. `.feature-card { display: flex }`, `.feat-mode-transcript
   { display: flex }`) regardless of selector order, because author rules
   always beat UA rules at equal specificity. That silently broke both the
   Features catalogue filter and the Vox-mode preview (all three sample
   panels rendering stacked instead of one at a time) — found 2026-09-10.
   One global !important rule here is the fix that can't be re-broken by a
   future component adding its own `display`; also makes the one-off
   `.mode-tab[hidden]` rule below redundant (kept only so a diff explains
   why it's no longer needed). */
[hidden] { display: none !important; }

/* Screen-reader-only text: stays in the accessibility tree (and works as an
   aria-describedby target) while taking no visual space. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

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

* { scrollbar-color: var(--border-strong) transparent; scrollbar-width: thin; }
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 4px; }
::-webkit-scrollbar-thumb:hover { background: var(--accent-dim); }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto !important; }
  *, *::before, *::after { animation-duration: 0.001ms !important; animation-iteration-count: 1 !important; transition-duration: 0.001ms !important; scroll-behavior: auto !important; }
}
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}

.container { max-width: var(--container-max); margin: 0 auto; padding: 0 24px; }
.container-wide { max-width: var(--container-wide); margin: 0 auto; padding: 0 24px; }

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

/* ===== Icon system ===== */
/* Standard 24x24 stroke-based line icons (Feather/Lucide-style), inlined as
   SVG so they render pixel-identical across OS/browsers, no emoji, whose
   glyph and color vary by platform and look inconsistent on a fintech UI. */
.icon {
  width: 1em; height: 1em; display: inline-block; vertical-align: -0.15em; flex-shrink: 0;
  stroke: currentColor; fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round;
}
.icon-play, .icon-filled { fill: currentColor; stroke: none; }
.icon-spin { animation: iconSpin 1.1s linear infinite; }
@keyframes iconSpin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .icon-spin { animation: none; } }

.skip-link {
  position: fixed;
  top: -60px; left: 16px;
  z-index: 100;
  background: var(--voice);
  color: var(--text-on-accent);
  font-weight: var(--fw-strong);
  font-size: var(--fs-xs);
  padding: 10px 18px;
  border-radius: var(--radius-sm);
  transition: top var(--dur-2) var(--ease-out);
}
.skip-link:focus { top: 16px; }

/* ===== Ambient chrome: grain, progress bar, cursor glow ===== */
body::before {
  content: '';
  position: fixed;
  inset: 0;
  background-image: var(--noise);
  opacity: 0.035;
  mix-blend-mode: overlay;
  pointer-events: none;
  z-index: 2;
}

.scroll-progress {
  position: fixed;
  top: 0; left: 0;
  height: 2px;
  width: 0%;
  background: linear-gradient(90deg, var(--voice), var(--accent-strong));
  box-shadow: 0 0 12px var(--voice-glow);
  z-index: var(--z-progress);
  transition: width 80ms linear;
}

.cursor-glow {
  position: fixed;
  top: 0; left: 0;
  width: 360px; height: 360px;
  margin: -180px 0 0 -180px;
  border-radius: 50%;
  background: radial-gradient(circle, var(--accent-soft) 0%, rgba(155,107,255,0) 70%);
  pointer-events: none;
  z-index: var(--z-cursor);
  opacity: 0;
  transform: translate3d(-999px, -999px, 0);
  transition: opacity var(--dur-3) var(--ease-out);
  will-change: transform;
}
/* Restraint pass: dialed back from full opacity — a hint of ambient chrome
   following the cursor, not a decorative wash. */
.cursor-glow.is-active { opacity: 0.55; }
@media (hover: none), (pointer: coarse), (prefers-reduced-motion: reduce) {
  .cursor-glow { display: none; }
}

/* ===== Top bar ===== */
/* Redesigned to read as an app-grade product header (Linear/Vercel/OpenAI
   register): flat surface instead of a saturated glow-glass, tight
   typography, pill hover states instead of animated underlines, and a
   solid (not gradient/shine) CTA. Deliberately restrained — see the
   "avoid gradients/glow/large shadows" brief this replaced. */
.topbar {
  position: sticky;
  top: 0;
  z-index: var(--z-nav);
  background: rgba(11, 9, 24, 0.82);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--border-hair);
  transition: background var(--dur-3) var(--ease-out), border-color var(--dur-3) var(--ease-out);
}
body[data-scrolled="true"] .topbar {
  background: rgba(9, 7, 20, 0.96);
  border-bottom-color: var(--border);
}
.topbar-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  padding: 16px 40px;
}
/* The full desktop row (brand + 5 links + Log in/account + CTA) needs
   ~1,000px, so it only turns on at 1024px (below, the burger menu takes
   over) and trims its side padding until there's room to spare. */
@media (max-width: 1080px) { .topbar-inner { padding: 16px 24px; } }
@media (max-width: 640px) { .topbar-inner { padding: 14px 16px; } }
.brand {
  display: flex;
  align-items: center;
  gap: 14px;
  font-family: var(--font-display);
  font-size: var(--fs-xl);
  font-weight: var(--fw-emphasis);
  letter-spacing: var(--ls-tight);
}
.brand a { display: flex; align-items: center; gap: 14px; text-decoration: none; color: inherit; }
.brand-mark {
  width: 44px;
  height: 44px;
  flex-shrink: 0;
  filter: drop-shadow(0 0 8px var(--voice-glow));
}
/* Two-tone wordmark (FedEx/PayPal-style split of the compound name): "Vox"
   in the mark's gold so the text and the sound-wave bars read as one logo.
   Solid, not gradient-clipped text: at wordmark size the mark's two golds
   are indistinguishable, and a plain colour survives email clients,
   forced-colors mode and text selection. */
.brand-vox { color: var(--voice); }
/* Header-only override: tighter, flatter brand mark for the app-grade nav
   redesign — .brand/.brand-mark above stay untouched for the footer, which
   reuses the same classes at the original (bolder, glowing) treatment. */
.topbar .brand {
  gap: 12px;
  font-size: var(--fs-lead);
  font-weight: var(--fw-strong);
  letter-spacing: var(--ls-tight);
}
.topbar .brand { flex-shrink: 0; }
.topbar .brand a { gap: 12px; white-space: nowrap; }
.topbar .brand-mark {
  width: 32px;
  height: 32px;
  filter: none;
}
@keyframes dotPulse {
  0%, 100% { box-shadow: 0 0 8px var(--voice-glow); }
  50% { box-shadow: 0 0 18px var(--voice-glow); }
}
.eco-tag {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  color: var(--text-faint);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 4px 10px;
  margin-left: 6px;
  white-space: nowrap;
}
/* Decorative, so it's the first thing to go: it only fits beside the full
   nav on wide screens (hid below 720px before, which overflowed 720–1150). */
@media (max-width: 1279px) { .eco-tag { display: none; } }

.nav-links { display: none; align-items: center; gap: 2px; font-size: var(--fs-sm); font-weight: var(--fw-body); color: var(--text-muted); }
.nav-links a { text-decoration: none; color: inherit; }
.nav-links > a {
  padding: 8px 14px; border-radius: 8px; white-space: nowrap;
  transition: color var(--dur-1) ease, background var(--dur-1) ease;
}
.nav-links > a:hover { color: var(--text); background: var(--bg-elevated); }
.nav-links > a.is-active { color: var(--text); background: var(--bg-elevated); }
@media (min-width: 1024px) { .nav-links { display: flex; } }

.nav-cta-group { display: flex; align-items: center; gap: 14px; }
.nav-login-link { display: none; white-space: nowrap; font-size: var(--fs-sm); font-weight: var(--fw-body); color: var(--text-muted); text-decoration: none; transition: color var(--dur-1) ease; }
.nav-login-link:hover { color: var(--text); }
.nav-cta { display: none; }
@media (min-width: 720px) { .nav-cta { display: inline-flex; } .nav-login-link { display: inline; } }

/* Solid, flat CTA — overrides .btn-primary's gradient/shine-sweep for the
   header only (higher selector specificity beats it without touching the
   shared .btn-primary rule other pages' CTAs still use). */
.topbar .nav-cta.btn-primary {
  background: var(--voice);
  color: var(--text-on-accent);
  font-weight: var(--fw-emphasis);
  font-size: var(--fs-sm);
  padding: 10px 20px;
  border-radius: 8px;
  box-shadow: none;
  white-space: nowrap;
}
.topbar .nav-cta.btn-primary::before { content: none; }
.topbar .nav-cta.btn-primary:hover { background: var(--voice-strong); box-shadow: none; }

.nav-burger {
  display: inline-flex; align-items: center; justify-content: center;
  width: 38px; height: 38px; border-radius: var(--radius-sm);
  border: 1px solid var(--border); background: transparent; color: var(--text-muted); cursor: pointer;
  transition: background var(--dur-1) ease, border-color var(--dur-1) ease, color var(--dur-1) ease;
}
.nav-burger:hover { background: var(--bg-elevated); border-color: var(--border-strong); color: var(--text); }
@media (min-width: 1024px) { .nav-burger { display: none; } }

.mobile-menu {
  display: grid; grid-template-rows: 0fr;
  transition: grid-template-rows var(--dur-3) var(--ease-out);
  border-bottom: 1px solid transparent;
  background: rgba(9, 7, 20, 0.96);
  backdrop-filter: blur(14px);
}
.mobile-menu.is-open { grid-template-rows: 1fr; border-bottom-color: var(--border); }
.mobile-menu-inner { overflow: hidden; }
.mobile-menu-links { display: flex; flex-direction: column; padding: 8px 16px 20px; }
.mobile-menu-links a { padding: 14px 12px; border-radius: 8px; font-size: var(--fs-sm); font-weight: var(--fw-body); color: var(--text-muted); text-decoration: none; border-bottom: 1px solid var(--border-hair); transition: color var(--dur-1) ease, background var(--dur-1) ease; }
.mobile-menu-links a:hover { color: var(--text); background: var(--bg-elevated); }
/* The header CTA is hidden below 720px, so the menu carries it there. */
.mobile-menu-links .mobile-menu-cta {
  justify-content: center; margin-top: var(--sp-4); padding: 14px 26px;
  border-bottom: 0; color: var(--text-on-accent); font-weight: var(--fw-strong);
}
.mobile-menu-links .mobile-menu-cta:hover { color: var(--text-on-accent); background: linear-gradient(135deg, var(--voice), var(--voice-light)); }
@media (min-width: 720px) { .mobile-menu-links .mobile-menu-cta { display: none; } }
@media (min-width: 1024px) { .mobile-menu { display: none; } }

/* ===== Mega-nav dropdowns ===== */
.nav-item {
  position: relative; display: inline-flex; align-items: center; gap: 4px; white-space: nowrap;
  padding: 8px 14px; border-radius: 8px; cursor: pointer;
  transition: background var(--dur-1) ease;
}
.nav-item:hover, .nav-item:focus-within { background: var(--bg-elevated); }
.nav-item:hover > a, .nav-item:focus-within > a { color: var(--text); }
.nav-item .caret { font-size: var(--fs-3xs); color: var(--text-faint); transition: transform var(--dur-1) ease; }
.nav-item:hover .caret, .nav-item:focus-within .caret { transform: rotate(180deg); color: var(--text-muted); }
/* ── The dropdown-closes-on-the-way-in bug (reported 2026-09-10) ──
   `.nav-dropdown` used to be the visible card itself, positioned with a
   real `top: calc(100% + 12px)` gap below the trigger. That gap was empty
   page background belonging to no element, so moving the cursor from the
   trigger down toward the panel crossed genuinely dead space: `.nav-item`
   lost `:hover` a frame before the pointer reached the card, and the menu
   closed on the way in — worse the wider/farther the target inside the
   panel.
   Fixed the way Vercel/Linear/GitHub-style mega-menus actually do it, not
   by shrinking the visual gap or guessing a hover-bridge width: split the
   hit-testable region from the visible card. `.nav-dropdown` is now an
   invisible outer box that starts flush at the trigger's bottom edge
   (`top: 100%`, zero real gap) and reaches down through its own
   `padding-top`; `.nav-dropdown-panel` inside it is the actual visible
   card, offset by that padding so it still LOOKS like a 12px gap. Because
   the outer box is one continuous rectangle from the trigger's edge
   through the padding into the panel, there is no y-range left where the
   cursor can be at a dead x/y with nothing under it — the invisible
   padding closes the gap the previous fixed-height gap left open,
   regardless of which direction inside the panel the cursor is heading. */
.nav-dropdown {
  position: absolute; top: 100%; left: 50%; transform: translateX(-50%);
  padding-top: 12px;
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity var(--dur-2) var(--ease-out), visibility var(--dur-2);
  z-index: var(--z-dropdown);
}
.nav-item:hover .nav-dropdown, .nav-item:focus-within .nav-dropdown {
  opacity: 1; visibility: visible; pointer-events: auto;
}
.nav-dropdown-panel {
  min-width: 560px; background: var(--bg-elevated); border: 1px solid var(--border);
  /* Big floating panel, same radius/shadow pair as .hero-visual-frame —
     was a one-off 12px + hand-picked rgba shadow that didn't match any
     token (marketing-design-system hard rule 2: tokens only). */
  border-radius: var(--radius-lg); box-shadow: var(--shadow-lift); padding: var(--sp-5);
  display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--sp-3);
  transform: translateY(6px) scale(0.98);
  transition: transform var(--dur-2) var(--ease-out);
}
.nav-item:hover .nav-dropdown-panel, .nav-item:focus-within .nav-dropdown-panel {
  transform: translateY(0) scale(1);
}
/* Generic card-hover language (border-color + a slight lift), the same
   feedback every other card on the site gives, plus its own icon and tag
   accents on top — a flat background swap read as static/non-interactive. */
.nav-drop-link {
  display: flex; align-items: flex-start; gap: var(--sp-3); padding: 10px 12px;
  border: 1px solid transparent; border-radius: var(--radius-md); text-decoration: none;
  transition: background var(--dur-1) ease, border-color var(--dur-2) ease, transform var(--dur-2) var(--ease-out);
}
.nav-drop-link:hover, .nav-drop-link:focus-visible {
  background: var(--bg-card); border-color: var(--border-strong); transform: translateY(-1px);
}
.nav-drop-icon {
  flex-shrink: 0; width: 40px; height: 40px; border-radius: var(--radius-md); margin-top: 1px;
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-display); font-weight: var(--fw-display); font-size: var(--fs-xs); letter-spacing: var(--ls-tight);
  background: var(--accent-soft); color: var(--accent-strong);
  overflow: hidden; transition: transform var(--dur-2) var(--ease-spring);
}
.nav-drop-icon.is-hub { background: var(--voice-dim); color: var(--voice); }
.nav-drop-icon .icon { width: 20px; height: 20px; }
.nav-drop-link:hover .nav-drop-icon { transform: scale(1.08); }
.nav-drop-text { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.nav-drop-link .tag { font-family: var(--font-mono); font-size: var(--fs-2xs); letter-spacing: var(--ls-wide); text-transform: uppercase; color: var(--accent-strong); }
/* "You are here" is a you/current-page signal, not a category label like
   the rest — gold (--voice), the same "this one's you/selected" meaning
   .eco-card.is-you and the ecosystem orbit's own popover already use for
   TradingVox. Was rendering in the same violet as every other tag. */
.nav-drop-link .tag--you { color: var(--voice); }
.nav-drop-link strong { font-size: var(--fs-md); color: var(--text); font-weight: var(--fw-strong); }
.nav-drop-link span.desc { font-size: var(--fs-body-sm); line-height: 1.4; color: var(--text-muted); }
@media (prefers-reduced-motion: reduce) {
  .nav-drop-link:hover, .nav-drop-link:focus-visible, .nav-drop-link:hover .nav-drop-icon { transform: none; }
  .nav-item:hover .nav-dropdown-panel, .nav-item:focus-within .nav-dropdown-panel { transform: none; }
}
@media (max-width: 1023px) { .nav-dropdown { display: none; } }

/* Grouped variant: multiple labeled columns instead of a flat 2-col grid,
   for dropdowns with enough items (8+) that an ungrouped grid stops being
   scannable. */
.nav-dropdown-panel.is-grouped { display: flex; gap: var(--sp-7); min-width: 700px; align-items: flex-start; }
.nav-dropdown-group { display: flex; flex-direction: column; gap: 4px; flex: 1; min-width: 0; }
.nav-dropdown-heading {
  font-family: var(--font-mono); font-size: var(--fs-2xs); letter-spacing: var(--ls-wide); text-transform: uppercase;
  color: var(--text-faint); padding: 4px 14px 12px;
}

/* ===== Buttons ===== */
.btn {
  position: relative; display: inline-flex; align-items: center; gap: 8px;
  border-radius: var(--radius-sm); padding: 14px 26px; font-size: var(--fs-body); font-weight: var(--fw-strong);
  letter-spacing: var(--ls-tight);
  font-family: var(--font-body); border: 1px solid transparent; cursor: pointer; text-decoration: none;
  isolation: isolate; overflow: hidden;
  transition: transform var(--dur-2) var(--ease-spring), box-shadow var(--dur-2) var(--ease-out), border-color var(--dur-2) var(--ease-out), background var(--dur-2) var(--ease-out);
}
.btn:active { transform: scale(0.97); }
.btn-primary { background: linear-gradient(135deg, var(--voice), var(--voice-light)); color: var(--text-on-accent); }
.btn-primary::before {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(120deg, transparent 20%, rgba(255,255,255,0.55) 50%, transparent 80%);
  transform: translateX(-120%); z-index: -1;
}
.btn-primary:hover { box-shadow: 0 10px 30px rgba(255, 181, 71, 0.4); }
.btn-primary:hover::before { transform: translateX(120%); transition: transform 0.7s var(--ease-out); }
.btn-ghost { background: transparent; border-color: var(--border-strong); color: var(--text); }
.btn-ghost:hover { background: rgba(155, 107, 255, 0.08); border-color: var(--accent-strong); }
.btn-sm { padding: 8px 16px; font-size: var(--fs-label); }
@media (prefers-reduced-motion: reduce) { .btn { transition: none; } .btn-primary::before { display: none; } }

/* ===== Section shell ===== */
section { padding: var(--sp-9) 0; position: relative; }
/* .topbar is `position: sticky` (see ===== Top bar =====) — without this,
   jumping to an in-page anchor (nav's "Live Demo" link, the hero's "Try the
   voice demo" CTA, both -> #demo) scrolls the target flush to the viewport
   top, and the sticky nav then re-docks directly over the first ~70px of
   its content instead of sitting above it. Applied to every section with an
   id, not just #demo, since any of them could become a link target. */
section[id] { scroll-margin-top: 84px; }
.section-head { text-align: center; max-width: 640px; margin: 0 auto 48px; }
.section-head .eyebrow-mono { font-family: var(--font-mono); font-size: var(--fs-label); color: var(--data); letter-spacing: var(--ls-wide); text-transform: uppercase; }
/* Source-coloured variants so a section head can carry the same colour as
   the cards under it (EZPZ data = --accent, Finn = --voice; EZRA keeps the
   default --data) — same mapping as .feature-card--ezpz/--ezra/--finn. */
.section-head .eyebrow-mono--accent { color: var(--accent); }
.section-head .eyebrow-mono--voice { color: var(--voice); }
.section-head h2 { font-family: var(--font-display); font-weight: var(--fw-display); font-size: var(--fs-h2); margin: 10px 0 12px; letter-spacing: var(--ls-tight-lg); line-height: 1.05; }
.section-head p { color: var(--text); font-size: var(--fs-lead); line-height: 1.5; }

/* ===== Scroll reveal ===== */
.reveal { opacity: 0; transform: translateY(28px); transition: opacity var(--dur-4) var(--ease-out-expo), transform var(--dur-4) var(--ease-out-expo); transition-delay: var(--reveal-delay, 0ms); }
.reveal.is-visible { opacity: 1; transform: translateY(0); }
@media (prefers-reduced-motion: reduce) { .reveal { opacity: 1; transform: none; transition: none; } }

/* ===== Hero (home + section-hero variants share the ambient bg) ===== */
/* Tight top padding (2026-10-14): the headline and the command deck + tour
   must both be on screen at 1080p without scrolling. */
.hero { padding: var(--sp-6) 0 var(--sp-8); overflow: hidden; }
.hero-bg { position: absolute; inset: -10% -10% auto -10%; height: 900px; pointer-events: none; z-index: 0; }
.hero-blob { position: absolute; border-radius: 50%; filter: blur(70px); mix-blend-mode: screen; opacity: 0.68; will-change: transform; }
.hero-blob.b1 { width: 560px; height: 560px; top: -120px; left: 8%; background: radial-gradient(circle, var(--accent) 0%, transparent 70%); animation: driftA 22s var(--ease-in-out) infinite alternate; }
.hero-blob.b2 { width: 480px; height: 480px; top: 40px; right: 6%; background: radial-gradient(circle, var(--voice) 0%, transparent 70%); opacity: 0.55; animation: driftB 26s var(--ease-in-out) infinite alternate; }
.hero-blob.b3 { width: 380px; height: 380px; top: 260px; left: 42%; background: radial-gradient(circle, var(--data) 0%, transparent 70%); opacity: 0.35; animation: driftA 30s var(--ease-in-out) infinite alternate-reverse; }
@keyframes driftA { from { transform: translate(0, 0) scale(1); } to { transform: translate(40px, 60px) scale(1.08); } }
@keyframes driftB { from { transform: translate(0, 0) scale(1); } to { transform: translate(-50px, 30px) scale(0.94); } }
@media (prefers-reduced-motion: reduce) { .hero-blob, .eyebrow .pulse-dot, .hero-visual-orb { animation: none; } }
.hero-grid-fade {
  position: absolute; inset: 0;
  background:
    linear-gradient(var(--border-hair) 1px, transparent 1px) 0 0 / 64px 64px,
    linear-gradient(90deg, var(--border-hair) 1px, transparent 1px) 0 0 / 64px 64px;
  -webkit-mask-image: radial-gradient(ellipse 60% 50% at 50% 20%, #000 30%, transparent 75%);
  mask-image: radial-gradient(ellipse 60% 50% at 50% 20%, #000 30%, transparent 75%);
  pointer-events: none;
}

/* Pointer-reactive ambience (2026-10-14). interactions.js's [data-pointer-field]
   hook sets --pointer-x/--pointer-y (-1..1) and --pointer-mx/--pointer-my (%)
   on the hero. The blobs lean toward the cursor through the standalone
   `translate` property, which composes with their drift `transform` animation
   instead of replacing it, and the grid's visible patch follows the cursor.
   Defaults keep the static look on touch, reduced motion, or no JS. */
.hero[data-pointer-field] .hero-blob { transition: translate var(--dur-4) var(--ease-out); }
.hero[data-pointer-field] .hero-blob.b1 { translate: calc(var(--pointer-x, 0) * var(--hero-parallax)) calc(var(--pointer-y, 0) * var(--hero-parallax)); }
.hero[data-pointer-field] .hero-blob.b2 { translate: calc(var(--pointer-x, 0) * var(--hero-parallax) * -0.8) calc(var(--pointer-y, 0) * var(--hero-parallax) * 0.6); }
.hero[data-pointer-field] .hero-blob.b3 { translate: calc(var(--pointer-x, 0) * var(--hero-parallax) * 0.5) calc(var(--pointer-y, 0) * var(--hero-parallax) * -0.5); }
.hero[data-pointer-field] .hero-grid-fade {
  -webkit-mask-image: radial-gradient(ellipse 60% 50% at var(--pointer-mx, 50%) var(--pointer-my, 20%), #000 30%, transparent 75%);
  mask-image: radial-gradient(ellipse 60% 50% at var(--pointer-mx, 50%) var(--pointer-my, 20%), #000 30%, transparent 75%);
}
@media (prefers-reduced-motion: reduce) { .hero[data-pointer-field] .hero-blob { translate: none; transition: none; } }

/* 3D voice field (2026-10-14): a perspective particle sea drawn by
   hero-field.js. Sits above the blobs (screen-blended so the colours fuse)
   and below the content; fades out at the top so the headline stays clean,
   and shows through the glass of the prompt bar and tour frame. */
.hero-field {
  position: absolute; inset: 0; width: 100%; height: 100%; z-index: 0;
  pointer-events: none; mix-blend-mode: screen; opacity: 0;
  transition: opacity calc(var(--dur-4) * 3) var(--ease-out);
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 26%, #000 82%, transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 0%, #000 26%, #000 82%, transparent 100%);
}
.hero-field.is-ready { opacity: 1; }

/* The tour frame floats in 3D, leaning gently toward the cursor (same
   pointer vars as the blobs above). Desktop split layout only. */
@media (min-width: 1080px) {
  .hero[data-pointer-field] .hero-tour-visual {
    transform: perspective(1600px) rotateY(calc(var(--pointer-x, 0) * var(--hero-tilt))) rotateX(calc(var(--pointer-y, 0) * var(--hero-tilt) * -0.6));
    transition: transform var(--dur-4) var(--ease-out);
  }
}
@media (prefers-reduced-motion: reduce) { .hero[data-pointer-field] .hero-tour-visual { transform: none; transition: none; } }

.hero > .container { position: relative; z-index: 1; }

/* ---- Headline: top and centered, its own full-width row above the
   split grid below (not part of either column). ---- */
.hero-headline { text-align: center; margin: 0 auto var(--sp-6); }
.hero-headline .eyebrow { margin-bottom: var(--sp-4); }

/* ---- Bento split below the headline: copy left, live voice-demo card
   right (≥1080px). Stacks to a single left-aligned column below that. ---- */
.hero-grid { display: grid; grid-template-columns: 1fr; gap: 56px; align-items: center; }
.hero-copy .hero-ctas { justify-content: flex-start; }
.hero-showcase { position: relative; width: 100%; max-width: 560px; margin: 0 auto; display: flex; flex-direction: column; align-items: center; }
.hero-showcase .hero-visual { max-width: none; margin: 0; width: 100%; }
.hero-showcase-badge {
  display: inline-flex; align-items: center; gap: 7px;
  margin-bottom: 14px; padding: 5px 14px;
  background: var(--bg-glass); border: 1px solid rgba(61,220,151,0.35); border-radius: 999px;
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  font-family: var(--font-mono); font-size: var(--fs-2xs); letter-spacing: var(--ls-wide); color: var(--data);
}
.hero-showcase-badge-dot {
  width: 6px; height: 6px; border-radius: 50%; background: var(--data); flex-shrink: 0;
  box-shadow: 0 0 0 0 rgba(61,220,151,0.5);
  animation: badgeDotPulse 2s ease-in-out infinite;
}
@keyframes badgeDotPulse {
  0%   { box-shadow: 0 0 0 0 rgba(61,220,151,0.5); }
  70%  { box-shadow: 0 0 0 7px rgba(61,220,151,0); }
  100% { box-shadow: 0 0 0 0 rgba(61,220,151,0); }
}
@media (prefers-reduced-motion: reduce) { .hero-showcase-badge-dot { animation: none; box-shadow: none; } }
@media (min-width: 1080px) {
  .hero-grid { grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr); gap: 40px; }
  .hero-showcase { margin: 0 0 0 auto; }
  .hero-grid--tour { grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr); align-items: start; } /* the tour needs the room; top-aligned so the deck isn't pushed down */
}
.eyebrow {
  font-family: var(--font-mono); font-size: var(--fs-label); letter-spacing: var(--ls-wide); color: var(--voice);
  text-transform: uppercase; display: inline-flex; align-items: center; gap: 8px;
  border: 1px solid rgba(255, 181, 71, 0.35); background: var(--voice-dim);
  padding: 6px 14px; border-radius: 999px; margin-bottom: 28px;
}
.eyebrow .pulse-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--voice); box-shadow: 0 0 8px var(--voice); animation: dotPulse 2s ease-in-out infinite; }
.hero h1 { font-family: var(--font-display); font-weight: var(--fw-display); font-size: var(--fs-h1); line-height: 0.98; margin: 0 0 var(--sp-4); letter-spacing: var(--ls-tight-xl); text-shadow: 0 0 60px rgba(155,107,255,0.18), 0 0 120px rgba(155,107,255,0.07); text-wrap: balance; }
.hero h1 em {
  font-style: normal;
  background: linear-gradient(102deg, var(--accent-strong) 0%, var(--voice) 45%, var(--accent) 100%);
  -webkit-background-clip: text; background-clip: text; color: transparent;
  background-size: 250% auto; animation: gradientShift 4s ease-in-out infinite;
}
@keyframes gradientShift { 0%, 100% { background-position: 0% center; } 50% { background-position: 100% center; } }
@media (prefers-reduced-motion: reduce) { .hero h1 em { animation: none; } }
.hero-ctas { display: flex; gap: 14px; justify-content: center; flex-wrap: wrap; }

/* ===== Home hero: command deck + framed tour (2026-09-24) =====
   Left: a voice prompt bar, the tour's chapter list, CTAs and count-up stats.
   Right: the product tour inside the glass device frame, with a light beam
   running round its border. tour.js keeps both halves in sync by setting
   .hero[data-tour="idle|playing|paused|done"] and, on each .hero-chapter,
   .is-current plus --progress (0–1, how far that chapter has played). Every
   "alive" effect keys off data-tour="playing" (stable for a whole chapter),
   never the per-word speaking flag, so nothing restarts between words. */
.hero-lead { max-width: 640px; margin: 0 auto; font-size: var(--fs-lead); line-height: 1.55; color: var(--text-muted); text-wrap: balance; }
.hero-copy { display: flex; flex-direction: column; gap: var(--sp-6); min-width: 0; }

/* Prompt bar: what you'd say to Vox, typed out (interactions.js), plus a
   waveform that comes alive while the tour is playing. Links to the live demo. */
.hero-prompt {
  display: flex; align-items: center; gap: var(--sp-4);
  padding: var(--sp-3) var(--sp-5) var(--sp-3) var(--sp-3);
  border: 1px solid var(--border-strong); border-radius: var(--radius-pill);
  background: var(--bg-glass); backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  box-shadow: var(--shadow-card); color: var(--text); text-decoration: none;
  transition: border-color var(--dur-2) var(--ease-out), box-shadow var(--dur-3) var(--ease-out), transform var(--dur-2) var(--ease-out);
}
.hero-prompt:hover { border-color: var(--border-voice); transform: translateY(-2px); }
.hero[data-tour="playing"] .hero-prompt { border-color: var(--border-voice); box-shadow: var(--shadow-card), var(--shadow-glow-voice); }
.hero-prompt-mic {
  flex: none; display: grid; place-items: center; width: 48px; height: 48px; border-radius: 50%;
  background: linear-gradient(135deg, var(--voice), var(--voice-light)); color: var(--text-on-accent);
  box-shadow: 0 0 0 6px var(--voice-dim);
}
.hero-prompt-mic .icon { width: 20px; height: 20px; }
.hero[data-tour="playing"] .hero-prompt-mic { animation: heroMicPulse 1.6s var(--ease-in-out) infinite; }
@keyframes heroMicPulse { 50% { box-shadow: 0 0 0 11px var(--voice-dim); } }
.hero-prompt-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.hero-prompt-label { font-family: var(--font-mono); font-size: var(--fs-2xs); letter-spacing: var(--ls-wide); text-transform: uppercase; color: var(--voice); }
.hero-prompt-label-live, .hero[data-tour="playing"] .hero-prompt-label-idle { display: none; }
.hero[data-tour="playing"] .hero-prompt-label-live { display: inline; }
.hero-prompt .hero-typewriter-line { display: block; font-size: var(--fs-md); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.hero-prompt-wave { flex: none; display: flex; align-items: center; gap: 3px; height: 26px; }
.hero-prompt-wave i {
  width: 3px; height: 100%; border-radius: var(--radius-pill); background: var(--text-faint);
  transform: scaleY(0.25); animation: heroWaveIdle 2.4s var(--ease-in-out) infinite;
}
.hero-prompt-wave i:nth-child(2n) { animation-delay: -0.6s; }
.hero-prompt-wave i:nth-child(3n) { animation-delay: -1.2s; }
.hero[data-tour="playing"] .hero-prompt-wave i { background: var(--voice); animation: heroWave 0.9s var(--ease-in-out) infinite; }
.hero[data-tour="playing"] .hero-prompt-wave i:nth-child(2n) { animation-delay: -0.3s; }
.hero[data-tour="playing"] .hero-prompt-wave i:nth-child(3n) { animation-delay: -0.55s; }
@keyframes heroWaveIdle { 50% { transform: scaleY(0.45); } }
@keyframes heroWave { 0%, 100% { transform: scaleY(0.25); } 50% { transform: scaleY(1); } }

/* Chapter list: one row per tour scene (TOUR_SCENES' chapter + prompt).
   Tapping one plays it with sound; the playing row fills along its bottom. */
.hero-chapters { display: flex; flex-direction: column; gap: var(--sp-2); }
.hero-chapters-label { margin: 0 0 var(--sp-1); font-family: var(--font-mono); font-size: var(--fs-2xs); letter-spacing: var(--ls-wide); text-transform: uppercase; color: var(--text-faint); }
.hero-chapter {
  --chapter-color: var(--accent); --progress: 0;
  position: relative; overflow: hidden; display: flex; align-items: center; gap: var(--sp-4);
  width: 100%; padding: var(--sp-3) var(--sp-4); text-align: left; cursor: pointer;
  border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--bg-card);
  color: var(--text); font: inherit;
  transition: border-color var(--dur-2) var(--ease-out), background var(--dur-2) var(--ease-out), transform var(--dur-2) var(--ease-out);
}
.hero-chapter--ask { --chapter-color: var(--accent); }       /* EZPZ data */
.hero-chapter--chart { --chapter-color: var(--data); }       /* the live chart */
.hero-chapter--finn { --chapter-color: var(--voice); }       /* Finn / TradingView */
.hero-chapter--plans { --chapter-color: var(--text-muted); }
.hero-chapter:hover { border-color: var(--border-strong); transform: translateX(4px); }
.hero-chapter.is-current { border-color: var(--chapter-color); background: var(--bg-elevated); }
.hero-chapter-num { flex: none; font-family: var(--font-mono); font-size: var(--fs-2xs); font-weight: var(--fw-strong); letter-spacing: var(--ls-wide); color: var(--chapter-color); }
.hero-chapter-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.hero-chapter-title { font-family: var(--font-display); font-weight: var(--fw-strong); font-size: var(--fs-sm); letter-spacing: var(--ls-tight); }
.hero-chapter-quote { font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.hero-chapter-play {
  flex: none; display: grid; place-items: center; width: 32px; height: 32px; border-radius: 50%;
  border: 1px solid var(--border-strong); color: var(--text-muted);
  transition: border-color var(--dur-2) var(--ease-out), color var(--dur-2) var(--ease-out);
}
.hero-chapter-play-icon { width: 12px; height: 12px; }
.hero-chapter:hover .hero-chapter-play, .hero-chapter.is-current .hero-chapter-play { border-color: var(--chapter-color); color: var(--chapter-color); }
.hero-chapter-eq { display: none; align-items: flex-end; gap: 2px; height: 12px; }
.hero-chapter-eq i { width: 2px; height: 100%; border-radius: var(--radius-pill); background: var(--chapter-color); transform-origin: bottom; animation: heroWave 0.8s var(--ease-in-out) infinite; }
.hero-chapter-eq i:nth-child(2) { animation-delay: -0.25s; }
.hero-chapter-eq i:nth-child(3) { animation-delay: -0.5s; }
.hero[data-tour="playing"] .hero-chapter.is-current .hero-chapter-play-icon { display: none; }
.hero[data-tour="playing"] .hero-chapter.is-current .hero-chapter-eq { display: flex; }
.hero-chapter-progress {
  position: absolute; left: 0; right: 0; bottom: 0; height: 2px;
  background: var(--chapter-color); transform-origin: left; transform: scaleX(var(--progress));
}
.hero-chapter:focus-visible { outline: 2px solid var(--voice); outline-offset: 3px; }

/* Stats (count up on reveal via [data-count]). */
.hero-stats { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sp-4); margin: 0; padding-top: var(--sp-5); border-top: 1px solid var(--border); }
.hero-stat { display: flex; flex-direction: column-reverse; justify-content: flex-end; gap: var(--sp-1); }
.hero-stat-num { margin: 0; font-family: var(--font-display); font-weight: var(--fw-display); font-size: var(--fs-h3); line-height: 1.1; letter-spacing: var(--ls-normal); font-variant-numeric: tabular-nums; color: var(--text); }
.hero-stat-label { font-family: var(--font-mono); font-size: var(--fs-2xs); letter-spacing: var(--ls-wide); text-transform: uppercase; color: var(--text-faint); }

/* The tour, framed: shared glass device frame + a light beam on its border. */
.hero-tour { width: 100%; min-width: 0; scroll-margin-top: 84px; }
/* Doubled class so this beats the generic `.hero-visual { margin: 56px auto 0 }`
   further down; without it the tour frame sat 56px below the top-aligned deck. */
.hero-visual.hero-tour-visual { max-width: none; margin: 0; width: 100%; isolation: isolate; }
.hero-tour-frame { padding: var(--sp-4); transition: box-shadow var(--dur-3) var(--ease-out); }
.hero[data-tour="playing"] .hero-tour-frame { box-shadow: var(--shadow-glow-voice), var(--shadow-lift); }
.hero-tour-frame .hero-visual-topline { margin-bottom: var(--sp-3); }
.hero-tour-frame .tour-player { width: 100%; }
@property --hero-beam-angle { syntax: '<angle>'; inherits: false; initial-value: 0deg; }
.hero-tour-frame::before {
  content: ''; position: absolute; inset: -1px; padding: 1px; border-radius: inherit; pointer-events: none;
  background: conic-gradient(from var(--hero-beam-angle), transparent 0deg 240deg, var(--accent-strong) 290deg, var(--voice) 335deg, transparent 360deg);
  -webkit-mask: linear-gradient(black 0 0) content-box, linear-gradient(black 0 0); -webkit-mask-composite: xor;
  mask: linear-gradient(black 0 0) content-box exclude, linear-gradient(black 0 0);
  animation: heroBeam 7s linear infinite;
}
@keyframes heroBeam { to { --hero-beam-angle: 360deg; } }
.hero-tour-status { display: inline-flex; align-items: center; gap: var(--sp-2); font-family: var(--font-mono); font-size: var(--fs-2xs); letter-spacing: var(--ls-wide); text-transform: uppercase; color: var(--text-faint); transition: color var(--dur-2); }
.hero-tour-status-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--text-faint); }
.hero[data-tour="playing"] .hero-tour-status { color: var(--voice); }
.hero[data-tour="playing"] .hero-tour-status-dot { background: var(--voice); box-shadow: 0 0 8px var(--voice); animation: dotPulse 2s ease-in-out infinite; }

@media (max-width: 1079px) {
  .hero-copy { width: 100%; max-width: 640px; margin: 0 auto; } /* stacked above the tour: keep rows a readable width */
}
@media (max-width: 560px) {
  .hero-prompt { gap: var(--sp-3); padding-right: var(--sp-4); }
  .hero-prompt-mic { width: 40px; height: 40px; }
  .hero-prompt .hero-typewriter-line { font-size: var(--fs-sm); }
  .hero-prompt-wave { display: none; }
  .hero-stat-num { font-size: var(--fs-h4); }
  .hero-tour-frame { padding: var(--sp-2); }
  .hero-tour-frame .hero-visual-label { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .hero-prompt-wave i, .hero-prompt-mic, .hero-chapter-eq i, .hero-tour-status-dot, .hero-tour-frame::before { animation: none !important; }
  .hero-prompt:hover, .hero-chapter:hover { transform: none; }
}

/* ---- "Try saying" typewriter — a live-looking example of what you'd
   actually say to Vox, cycling through one line per capability (Ask/Draw/
   Research/Control) so it doubles as a feature teaser, not just texture.
   Typing logic lives in interactions.js, guarded on #heroTypewriterText so
   it's inert on every other page. ---- */
.hero-typewriter {
  display: inline-flex; align-items: center; gap: 10px; flex-wrap: wrap; max-width: 100%;
  margin: 0 0 30px; padding: 11px 18px;
  background: var(--bg-glass); border: 1px solid var(--border-strong); border-radius: 999px;
  backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
}
.hero-typewriter-label {
  font-family: var(--font-mono); font-size: var(--fs-2xs); letter-spacing: var(--ls-wide); text-transform: uppercase;
  color: var(--voice); flex-shrink: 0;
}
.hero-typewriter-line { margin: 0; min-height: 20px; font-family: var(--font-display); font-weight: var(--fw-strong); font-size: var(--fs-sm); color: var(--text); }
.hero-typewriter-cursor {
  display: inline-block; width: 2px; height: 16px; margin-left: 1px; vertical-align: -3px;
  background: var(--voice); animation: heroTypeCursor 0.9s steps(1) infinite;
}
@keyframes heroTypeCursor { 0%, 49% { opacity: 1; } 50%, 100% { opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .hero-typewriter-cursor { animation: none; } }

/* ---- Hero visual mockup (illustrative, not a real screenshot) ---- */
.hero-visual { position: relative; max-width: 640px; margin: 56px auto 0; }
.hero-visual-frame {
  position: relative; background: var(--bg-glass);
  backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);
  border: 1px solid var(--border-strong); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-glow), var(--shadow-lift); padding: 22px 24px; text-align: left;
}
.hero-visual-frame--voice {
  text-align: center; padding-top: 26px;
  border-color: rgba(155, 107, 255, 0.28);
  animation: heroCardGlow 3.5s ease-in-out infinite alternate;
}
@keyframes heroCardGlow {
  from { box-shadow: 0 0 0 1px rgba(155,107,255,0.14), 0 18px 50px -12px rgba(155,107,255,0.25), 0 28px 70px -18px rgba(4,2,18,0.75); }
  to   { box-shadow: 0 0 0 1px rgba(155,107,255,0.45), 0 18px 50px -12px rgba(155,107,255,0.55), 0 0 80px rgba(155,107,255,0.2), 0 28px 70px -18px rgba(4,2,18,0.75); }
}
@media (prefers-reduced-motion: reduce) { .hero-visual-frame--voice { animation: none !important; border-color: var(--border-strong); } }
.hero-visual-topline { display: flex; align-items: center; justify-content: space-between; margin-bottom: 16px; text-align: left; }
.hero-visual-dots { display: flex; gap: 6px; }
.hero-visual-dots span { width: 8px; height: 8px; border-radius: 50%; background: var(--border-strong); }
.hero-visual-label { font-family: var(--font-mono); font-size: var(--fs-2xs); letter-spacing: var(--ls-wide); text-transform: uppercase; color: var(--text-faint); transition: color var(--dur-2) ease; }

/* ---- Hero orb trigger — tap to hear a real answer. Reuses #demo's real
   .orb-wrap/.orb/.orb-ring component (same data-state colors/animations,
   see .orb-wrap[data-state=...] rules below) at hero scale, so this isn't
   a lookalike mockup — it's the actual "speaking" indicator the live
   product shows, sized up as the hero's focal point. ---- */
.hero-orb-trigger {
  display: flex; flex-direction: column; align-items: center; gap: 14px;
  background: none; border: none; padding: 8px 0 22px; margin: 0 auto 22px; cursor: pointer; width: 100%;
  border-bottom: 1px dashed var(--border);
}
.hero-orb-wrap.hero-orb-wrap { width: 176px; height: 176px; }
.hero-orb-wrap.hero-orb-wrap .orb { width: 128px; height: 128px; }
/* Both the icon and the eq bars are absolutely centered on top of each
   other — without this, .orb's flex row lays them out side by side (even
   though only one is visible at a time, opacity:0 still occupies flex
   space), which shoves the visible one off-center. */
.hero-orb-play-icon {
  position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
  width: 30px; height: 30px; fill: var(--voice);
  transition: opacity var(--dur-2) ease, transform var(--dur-2) ease;
}
.hero-orb-trigger:hover .hero-orb-play-icon { transform: translate(-50%, -50%) scale(1.08); }
.hero-orb-wrap[data-state="speaking"] .hero-orb-play-icon { opacity: 0; transform: translate(-50%, -50%) scale(0.7); }
.hero-orb-eq {
  position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
  display: flex; align-items: center; justify-content: center; gap: 3px; height: 30px; width: 42px;
  opacity: 0; transition: opacity var(--dur-2) ease;
}
.hero-orb-wrap[data-state="speaking"] .hero-orb-eq { opacity: 1; }
/* Idle/no-JS fallback is this canned keyframe loop. When real audio is
   playing, interactions.js drives an AnalyserNode off the actual <audio>
   element and sets bar heights + animation:none inline per frame — same
   bars, real amplitude instead of a canned pulse. See startWaveform(). */
.hero-orb-eq i { width: 3px; height: 8px; border-radius: 2px; background: var(--voice); display: block; animation: heroOrbEq 1s ease-in-out infinite; }
.hero-orb-eq i:nth-child(1) { animation-delay: -0.9s; }
.hero-orb-eq i:nth-child(2) { animation-delay: -0.6s; }
.hero-orb-eq i:nth-child(3) { animation-delay: -0.3s; }
.hero-orb-eq i:nth-child(4) { animation-delay: -0.7s; }
.hero-orb-eq i:nth-child(5) { animation-delay: -0.4s; }
.hero-orb-eq i:nth-child(6) { animation-delay: -0.15s; }
.hero-orb-eq i:nth-child(7) { animation-delay: -0.55s; }
@keyframes heroOrbEq { 0%, 100% { height: 7px; } 50% { height: 26px; } }
@media (prefers-reduced-motion: reduce) { .hero-orb-eq i { animation: none; height: 16px; } }
.hero-orb-hint { font-family: var(--font-mono); font-size: var(--fs-2xs); letter-spacing: var(--ls-wide); color: var(--text-faint); transition: color var(--dur-2) ease; }
.hero-orb-wrap[data-state="speaking"] ~ .hero-orb-hint { color: var(--voice); }

/* Base .hero-qa* rules — shared with coming_soon.html's own hero mockup
   (its .hero-visual-body/.hero-visual-orb pairing below), left-aligned
   next to a small fixed orb. Do not change alignment/spacing here; the
   redesigned centered layout for home.html's voice-first hero is scoped
   under .hero-visual-frame--voice below instead, so the two pages don't
   fight over the same class names. */
.hero-qa { display: flex; flex-direction: column; gap: 12px; min-width: 0; }
/* Slides stack in one grid cell instead of position:absolute, so the track
   grows to the tallest answer — an absolute slide in an 84px box ran over
   the dots and ticker pills whenever an answer wrapped past ~3 lines
   (every phone, and long answers on desktop). */
.hero-qa-track { position: relative; display: grid; min-height: 84px; }
.hero-qa-slide {
  grid-area: 1 / 1; display: flex; flex-direction: column; gap: 7px;
  opacity: 0; transform: translateY(8px); pointer-events: none;
  transition: opacity var(--dur-3) var(--ease-out), transform var(--dur-3) var(--ease-out);
}
.hero-qa-slide.is-active { opacity: 1; transform: translateY(0); pointer-events: auto; }
.hero-qa-q {
  font-family: var(--font-mono); font-size: var(--fs-2xs); letter-spacing: var(--ls-wide); color: var(--text-faint);
  text-transform: uppercase;
}
.hero-qa-a { font-family: var(--font-display); font-weight: var(--fw-strong); font-size: var(--fs-md); line-height: 1.28; color: var(--text); }
/* Which real, admin-registered Studio Beta voice narrated this specific
   clip (HeroVoiceDemo.voice) — shown only when a row actually sets one. */
.hero-qa-voice { font-family: var(--font-mono); font-size: var(--fs-2xs); letter-spacing: var(--ls-wide); color: var(--text-faint); }
/* Dots are real buttons — tap any one to jump straight to that example
   instead of waiting for the ~3.4s auto-rotation (see interactions.js). */
.hero-qa-dots { display: flex; gap: 6px; justify-content: center; }
.hero-qa-dot {
  width: 6px; height: 6px; padding: 7px; margin: -7px; border-radius: 50%; border: none; background: none; cursor: pointer;
  position: relative; -webkit-tap-highlight-color: transparent;
}
.hero-qa-dot::before {
  content: ''; position: absolute; inset: 7px; border-radius: 50%; background: var(--border-strong);
  transition: background var(--dur-2) ease, transform var(--dur-2) ease;
}
.hero-qa-dot:hover::before { background: var(--text-faint); }
.hero-qa-dot.is-active::before { background: var(--voice); transform: scale(1.3); }
.hero-qa-dot:focus-visible { outline: 2px solid var(--voice); outline-offset: 3px; border-radius: 50%; }
@media (prefers-reduced-motion: reduce) { .hero-qa-slide { transition: none; } }
@media (max-width: 480px) { .hero-qa-a { font-size: var(--fs-body); } }

.hero-visual-body { display: grid; grid-template-columns: auto 1fr; gap: 20px; align-items: center; }
.hero-visual-orb {
  width: 64px; height: 64px; border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, var(--bg-orb-glow), var(--bg-card) 70%);
  border: 1px solid var(--voice); box-shadow: 0 0 30px rgba(255, 181, 71, 0.35);
  flex-shrink: 0; animation: heroOrbPulse 2.4s ease-in-out infinite;
}
@keyframes heroOrbPulse { 0%, 100% { box-shadow: 0 0 20px rgba(255,181,71,0.28); } 50% { box-shadow: 0 0 38px rgba(255,181,71,0.5); } }

/* ---- home.html's voice-first hero only: center the Q&A caption under the
   big orb instead of the left-aligned-next-to-a-small-orb base layout
   above. ---- */
.hero-visual-frame--voice .hero-qa { align-items: center; text-align: center; }
.hero-visual-frame--voice .hero-qa-track { width: 100%; }
.hero-visual-frame--voice .hero-qa-slide { align-items: center; }
.hero-visual-frame--voice .hero-qa-a { max-width: 480px; }
.hero-visual-frame--voice .hero-qa-dots { margin-top: 2px; }
@media (max-width: 480px) {
  .hero-orb-wrap.hero-orb-wrap { width: 140px; height: 140px; }
  .hero-orb-wrap.hero-orb-wrap .orb { width: 100px; height: 100px; }
}
.hero-visual-ticker { margin-top: 18px; display: flex; gap: 10px; flex-wrap: wrap; border-top: 1px dashed var(--border); padding-top: 14px; }
.hero-visual-frame--voice .hero-visual-ticker { justify-content: center; }
.hero-visual-ticker span {
  font-family: var(--font-mono); font-size: var(--fs-2xs); padding: 4px 10px; border-radius: 999px;
  border: 1px solid var(--border-strong); color: var(--text-muted); transition: color var(--dur-2) ease, border-color var(--dur-2) ease;
}
.hero-visual-ticker span.up { color: var(--data); border-color: rgba(61, 220, 151, 0.4); }
.hero-visual-ticker span.down { color: var(--data-down); border-color: rgba(255, 107, 122, 0.4); }
.hero-visual-glow {
  position: absolute; inset: -6px; border-radius: var(--radius-lg);
  background: linear-gradient(135deg, rgba(155, 107, 255, 0.45), rgba(255, 181, 71, 0.3), rgba(61,220,151,0.15));
  filter: blur(32px); z-index: -1;
  animation: visualGlowPulse 4s ease-in-out infinite alternate;
}
@keyframes visualGlowPulse { from { opacity: 0.65; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .hero-visual-glow { animation: none; } }

/* Real integrations this specific answer drew on — not decorative, ties
   the sample back to actual connected products (TradingView's real
   charting_library is embedded at #chart; Finn/EZRA are real EZPZ
   ecosystem services, see .logo-strip below). */
.hero-visual-connected {
  margin: 14px 0 0; display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 8px;
  font-family: var(--font-mono); font-size: var(--fs-2xs); letter-spacing: var(--ls-wide); color: var(--text-faint);
}
.hero-visual-connected-chip {
  display: inline-flex; align-items: center; gap: 6px; color: var(--text-muted);
  border: 1px solid var(--border); border-radius: 999px; padding: 3px 10px;
}
.hero-visual-connected-chip::before { content: ''; width: 5px; height: 5px; border-radius: 50%; background: var(--accent); }

/* ===== Hero capability showcase — the 4 things Vox actually does
   (project-documents/VOX_USE_CASES.md §2-§5), so a first-time visitor
   isn't left thinking Vox only answers spoken questions. Each card gets
   its own brand color (existing tokens, none new) instead of one flat
   --bg-card gray for all four — --accent for Ask, --voice for Draw
   (matches the trendline it draws), --data for Research, --tier-free for
   Control, so the row reads as 4 distinct capabilities at a glance. ===== */
.hero-capabilities { max-width: 1080px; margin: 56px auto 0; }
.hero-capabilities-label {
  text-align: center; font-family: var(--font-mono); font-size: var(--fs-2xs); letter-spacing: var(--ls-wide);
  text-transform: uppercase; color: var(--text-faint); margin: 0 0 24px;
}
.hero-cap-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 18px; }
/* Same mousemove spotlight+tilt mechanism as .feature-card (interactions.js
   SPOTLIGHT_SELECTOR/TILT_SELECTOR sets --mx/--my and a live rotateX/rotateY
   — real 3D response to the cursor, not a canned hover snap). */
.hero-cap-card {
  position: relative; overflow: hidden; background: var(--bg-card); border: 1px solid var(--border-strong);
  border-radius: var(--radius-md); padding: 28px 28px 24px;
  display: flex; flex-direction: row; align-items: flex-start; gap: 22px;
  transform: perspective(900px) rotateX(0deg) rotateY(0deg); will-change: transform;
  box-shadow: 0 0 0 1px var(--cap-glow, transparent), 0 20px 40px -24px rgba(4, 2, 18, 0.75);
  transition: border-color var(--dur-2) ease, box-shadow var(--dur-2) ease, transform var(--dur-2) var(--ease-out);
}
.hero-cap-card::before {
  content: ''; position: absolute; inset: 0; opacity: 0; pointer-events: none;
  background: radial-gradient(320px circle at var(--mx, 30%) var(--my, 50%), var(--cap-glow, var(--voice-dim)), transparent 70%);
  transition: opacity var(--dur-2) ease;
}
.hero-cap-card::after {
  content: ''; position: absolute; top: 0; left: 0; right: 0; height: 2px;
  background: linear-gradient(90deg, transparent, var(--cap-color, var(--accent)), transparent);
  opacity: 0; transition: opacity var(--dur-3) var(--ease-out);
}
.hero-cap-card:hover::before, .hero-cap-card:focus-visible::before,
.hero-cap-card.is-active::before { opacity: 1; }
.hero-cap-card:hover::after, .hero-cap-card:focus-visible::after,
.hero-cap-card.is-active::after { opacity: 1; }
.hero-cap-card:hover, .hero-cap-card:focus-visible {
  border-color: var(--cap-color, var(--border-strong));
  box-shadow: 0 0 0 1px var(--cap-color, var(--border-strong)), 0 0 48px -8px var(--cap-glow, var(--accent-glow)), var(--shadow-card);
}
.hero-cap-card.is-active {
  border-color: var(--cap-color, var(--border-strong));
  box-shadow: 0 0 0 1px var(--cap-color, var(--border-strong)), 0 0 40px -6px var(--cap-glow, var(--accent-glow)), var(--shadow-card);
}
.hero-cap-card--ask { --cap-color: var(--accent); --cap-glow: var(--accent-soft); }
.hero-cap-card--draw { --cap-color: var(--voice); --cap-glow: var(--voice-dim); }
.hero-cap-card--research { --cap-color: var(--data); --cap-glow: var(--data-dim); }
.hero-cap-card--control { --cap-color: var(--tier-free); --cap-glow: rgba(13, 148, 136, 0.16); }

/* Icon column — square tinted area on the left */
.hero-cap-media {
  flex-shrink: 0; display: flex; flex-direction: column; align-items: center;
  justify-content: flex-start; gap: 10px;
  width: 88px; padding: 18px 12px 14px;
  background: var(--cap-glow, rgba(155,107,255,0.07));
  border: 1px solid var(--cap-glow, var(--border));
  border-radius: var(--radius-sm);
  transition: background var(--dur-2) ease, border-color var(--dur-2) ease;
}
.hero-cap-card:hover .hero-cap-media,
.hero-cap-card.is-active .hero-cap-media {
  background: var(--cap-glow, rgba(155,107,255,0.13));
  border-color: var(--cap-color, var(--accent));
}
.hero-cap-num {
  font-family: var(--font-mono); font-size: var(--fs-3xs); font-weight: var(--fw-strong); letter-spacing: var(--ls-wide);
  color: var(--cap-color, var(--accent)); opacity: 0.45;
  transition: opacity var(--dur-2) ease;
}
.hero-cap-card:hover .hero-cap-num,
.hero-cap-card.is-active .hero-cap-num { opacity: 1; }

/* Content column — tag, title, example, chips */
.hero-cap-body { flex: 1; min-width: 0; }
.hero-cap-tag {
  display: inline-flex; align-items: center; gap: 5px;
  font-family: var(--font-mono); font-size: var(--fs-2xs); font-weight: var(--fw-strong); letter-spacing: var(--ls-wide);
  text-transform: uppercase; color: var(--cap-color, var(--voice)); margin-bottom: 10px;
}
.hero-cap-tag::before {
  content: ''; display: inline-block; width: 5px; height: 5px; border-radius: 50%;
  background: var(--cap-color, var(--accent));
}
.hero-cap-title { font-family: var(--font-display); font-weight: var(--fw-strong); font-size: var(--fs-h4); line-height: 1.28; color: var(--text); margin: 0 0 14px; }
.hero-cap-example {
  font-family: var(--font-mono); font-size: var(--fs-xs); line-height: 1.55; color: var(--text);
  margin: 0; padding: 11px 14px; background: rgba(243,240,255,0.035); border-radius: 8px;
  border-left: 2px solid var(--cap-color, var(--accent));
}
.hero-cap-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 14px; }
.hero-cap-chip {
  font-family: var(--font-mono); font-size: var(--fs-2xs); font-weight: var(--fw-emphasis); letter-spacing: var(--ls-wide);
  padding: 4px 10px; border-radius: 999px;
  color: var(--cap-color, var(--accent));
  background: var(--cap-glow, rgba(155,107,255,0.1));
  border: 1px solid transparent;
  transition: border-color var(--dur-1) ease;
}
.hero-cap-card.is-active .hero-cap-chip,
.hero-cap-card:hover .hero-cap-chip { border-color: var(--cap-color, var(--accent)); }
.hero-cap-tv-badge {
  display: inline-flex; align-items: center; gap: 5px;
  margin-top: 14px; padding: 5px 12px;
  background: var(--bg-elevated); border: 1px solid var(--border-strong); border-radius: 999px;
  font-family: var(--font-mono); font-size: var(--fs-2xs); font-weight: var(--fw-emphasis); letter-spacing: var(--ls-wide); color: var(--text-muted);
}
.hero-cap-tv-badge svg { width: 14px; height: 14px; flex-shrink: 0; color: var(--text); } /* TradingView's mark is monochrome */

/* Icon strip — sized for the media column */
.hero-cap-icon { position: relative; display: block; width: 64px; height: 52px; color: var(--cap-color, var(--accent-strong)); }
.hero-cap-icon svg { width: 100%; height: 100%; overflow: visible; }

/* Draw: thin bars (same 3px width as Ask bars) + animated trendline. */
.hero-cap-chart rect { fill: var(--border-strong); opacity: 0.45; }
.hero-cap-trendline {
  fill: none; stroke: var(--cap-color, var(--voice)); stroke-width: 2.5; stroke-linecap: round;
  stroke-dasharray: 65; stroke-dashoffset: 65; animation: heroCapDraw 3.2s var(--ease-out) infinite;
}
@keyframes heroCapDraw {
  0% { stroke-dashoffset: 65; }
  35%, 75% { stroke-dashoffset: 0; }
  100% { stroke-dashoffset: 0; }
}

/* Ask: 5 symmetric thin bars (bell-curve heights), animated vertical scale. */
.hero-cap-wave .wave-bar { fill: var(--cap-color); transform-origin: center; transform-box: fill-box; animation: heroCapWave 1.4s ease-in-out infinite; }
.hero-cap-wave .wave-bar:nth-child(1) { animation-delay: -1.1s; }
.hero-cap-wave .wave-bar:nth-child(2) { animation-delay: -0.7s; }
.hero-cap-wave .wave-bar:nth-child(3) { animation-delay: -1.4s; }
.hero-cap-wave .wave-bar:nth-child(4) { animation-delay: -0.4s; }
.hero-cap-wave .wave-bar:nth-child(5) { animation-delay: -0.9s; }
@keyframes heroCapWave { 0%, 100% { transform: scaleY(0.45); } 50% { transform: scaleY(1); } }

/* Research: stroke-only magnifying glass + data lines inside.
   Same stroke weight (2.5px) as the Draw trendline — all icons now share one weight. */
.hero-cap-scan .scan-glass { fill: none; stroke: var(--cap-color); stroke-width: 2.5; stroke-linecap: round; animation: heroCapScan 3s ease-in-out infinite; }
.hero-cap-scan .scan-line { stroke: var(--border-strong); stroke-width: 1.5; stroke-linecap: round; fill: none; opacity: 0.65; }
@keyframes heroCapScan {
  0%, 100% { transform: translate(0, 0); }
  25% { transform: translate(-3px, 3px); }
  50% { transform: translate(-6px, -2px); }
  75% { transform: translate(-2px, -4px); }
}

/* Control: 3-track horizontal slider icon. Same stroke weight as the others.
   The active knob pulses to signal live control. */
.hero-cap-slider .slider-track { stroke: var(--cap-color); stroke-width: 2; stroke-linecap: round; fill: none; opacity: 0.35; }
.hero-cap-slider .slider-knob { fill: none; stroke: var(--cap-color); stroke-width: 2.5; }
.hero-cap-slider .slider-knob--active { fill: var(--cap-color); opacity: 0.85; animation: heroCapSliderPulse 2s ease-in-out infinite; }
@keyframes heroCapSliderPulse { 0%, 100% { opacity: 0.85; } 50% { opacity: 0.4; } }
@media (prefers-reduced-motion: reduce) {
  .hero-cap-card { transition: none; transform: none !important; }
  .hero-cap-trendline { animation: none; stroke-dashoffset: 0; }
  .hero-cap-wave .wave-bar { animation: none; transform: scaleY(0.75); }
  .hero-cap-scan .scan-glass { animation: none; }
  .hero-cap-slider .slider-knob--active { animation: none; opacity: 1; }
}
/* Two columns leave the text only ~120–185px beside the icon column on a
   tablet; go single-column at 860 (was 640). */
@media (max-width: 860px) { .hero-cap-grid { grid-template-columns: 1fr; } }
@media (max-width: 640px) {
  .hero-cap-card { padding: 20px 18px 18px; gap: 16px; }
  .hero-cap-media { width: 72px; padding: 14px 10px 12px; }
  .hero-cap-icon { width: 52px; height: 42px; }
  .hero-cap-title { font-size: var(--fs-body); }
}


/* ===== Marquee logo strip ===== */
.logo-strip { padding: 40px 0; border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); }
.logo-strip-label { text-align: center; font-family: var(--font-mono); font-size: var(--fs-2xs); letter-spacing: var(--ls-wide); text-transform: uppercase; color: var(--text-faint); margin: 0 0 22px; }
.logo-row { display: flex; align-items: center; justify-content: center; gap: 20px; flex-wrap: wrap; }
.logo-chip {
  display: flex; align-items: center; gap: 8px; font-family: var(--font-display); font-weight: var(--fw-emphasis);
  font-size: var(--fs-sm); color: var(--text-muted); padding: 10px 18px; border: 1px solid var(--border);
  border-radius: var(--radius-pill); transition: color var(--dur-1) ease, border-color var(--dur-1) ease; white-space: nowrap;
}
.logo-chip:hover { color: var(--text); border-color: var(--border-strong); }
.logo-chip .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--accent); }

/* ===== How it works =====
   A real 3-step pipeline (ask -> Vox routes to whichever ecosystem piece
   actually has the answer -> spoken back), not three unconnected feature
   blurbs — the arrow connectors plus the step-example quotes on 1 and 3
   are the same real exchange threaded through, and step 2's routes list
   is the actual EZPZ-direct/EZRA/Finn split (project-documents/
   VOX_USE_CASES.md §1-§5), not a generic "smart backend" claim. */
.steps-grid { display: flex; flex-direction: column; gap: 14px; position: relative; }
@media (min-width: 860px) { .steps-grid { flex-direction: row; align-items: stretch; gap: 0; } }
.step-card {
  background: var(--bg-elevated); border: 1px solid var(--border); border-radius: var(--radius-md);
  padding: 28px 24px; position: relative; transition: border-color var(--dur-2) ease, transform var(--dur-2) ease;
  display: flex; flex-direction: column;
}
@media (min-width: 860px) { .step-card { flex: 1 1 0; } }
.step-card:hover { border-color: var(--border-strong); transform: translateY(-3px); }
.step-num {
  font-family: var(--font-mono); font-size: var(--fs-label); color: var(--voice); border: 1px solid rgba(255,181,71,0.35);
  background: var(--voice-dim); width: 30px; height: 30px; border-radius: 50%; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center; margin-bottom: 16px; font-weight: var(--fw-strong);
}
.step-card h3 { font-family: var(--font-display); font-weight: var(--fw-strong); font-size: var(--fs-h3); margin: 0 0 10px; letter-spacing: var(--ls-tight-lg); }
.step-card p { font-size: var(--fs-sm); line-height: 1.5; color: var(--text); margin: 0; }

/* Connector between steps: a down-arrow when stacked on mobile, a
   right-arrow in the row on desktop — makes this read as one pipeline
   instead of three separate cards competing for attention. */
.step-arrow { display: flex; align-items: center; justify-content: center; color: var(--text-faint); flex-shrink: 0; }
.step-arrow .icon { width: 20px; height: 20px; transform: rotate(90deg); }
@media (min-width: 860px) { .step-arrow { width: 44px; } .step-arrow .icon { transform: none; } }

/* Real quoted exchange on steps 1 and 3 — the same question/answer pair,
   not two unrelated examples, so the loop actually closes. */
.step-card p.step-example {
  margin-top: 14px; padding: 10px 14px; background: var(--bg-card); border: 1px solid var(--border-hair);
  border-radius: var(--radius-sm); font-family: var(--font-mono); font-size: var(--fs-xs); line-height: 1.5;
  color: var(--text);
}

/* Step 2's real routing split, meaning-coded to match this site's other
   ecosystem-routing colors (hero-cap-card): live market data = --data
   (green), EZRA's reasoning = --accent (brand/AI), Finn's real TradingView
   control = --tier-free (teal), so the same concept reads the same color
   everywhere on the page. */
.step-routes { list-style: none; margin: 16px 0 0; padding: 0; display: flex; flex-direction: column; gap: 9px; }
.step-route { display: flex; align-items: center; gap: 9px; font-size: var(--fs-label); }
.step-route-dot { width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0; }
.step-route--data .step-route-dot { background: var(--data); box-shadow: 0 0 6px var(--data-dim); }
.step-route--research .step-route-dot { background: var(--accent); box-shadow: 0 0 6px var(--accent-soft); }
.step-route--control .step-route-dot { background: var(--tier-free); box-shadow: 0 0 6px rgba(13, 148, 136, 0.35); }
.step-route-tag { color: var(--text-muted); flex: 1; }
.step-route-via { font-family: var(--font-mono); font-size: var(--fs-2xs); font-weight: var(--fw-strong); letter-spacing: var(--ls-wide); color: var(--text-muted); white-space: nowrap; }

/* ===== Modern Mode Selector (redesigned 2026-09-02) ===== */
/* Clean, centered tabs with professional styling */

.demo-mode-selector {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  margin: 28px 0 32px;
}

.mode-tabs-container {
  display: flex;
  justify-content: center;
  width: 100%;
}

.mode-tabs {
  display: inline-flex;
  align-items: center;
  gap: 0;
  background: var(--bg-sunken);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 6px;
  box-shadow: inset 0 1px 2px rgba(4, 2, 18, 0.15);
}

.mode-tab {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 10px 20px;
  border: none;
  border-radius: 8px;
  background: transparent;
  color: var(--text-muted);
  font-family: var(--font-body);
  font-size: var(--fs-body-sm);
  font-weight: var(--fw-emphasis);
  cursor: pointer;
  outline: none;
  white-space: nowrap;
  transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}

/* .mode-tab[hidden] no longer needs its own override — superseded by the
   global [hidden] rule in the Reset section above (2026-09-10). */

.mode-tab:hover {
  color: var(--text);
  background: rgba(243, 240, 255, 0.06);
}

.mode-tab.active {
  background: var(--data);
  color: var(--text-on-data);
  box-shadow: 0 2px 8px rgba(61, 220, 151, 0.3);
}

.mode-tab.active:hover {
  background: var(--data-strong);
  box-shadow: 0 3px 10px rgba(61, 220, 151, 0.4);
}

.mode-tab:focus-visible {
  outline: 2px solid var(--accent-strong);
  outline-offset: 2px;
}

/* Usage multiplier on a premium voice tab (Studio, "3x") — the model-picker
   convention of labelling options that use more of a plan's allowance. */
.mode-tab-meter {
  display: inline-flex;
  align-items: center;
  margin-left: var(--sp-2);
  padding: 1px var(--sp-1);
  border-radius: var(--radius-pill);
  background: var(--voice-dim);
  color: var(--voice);
  font-family: var(--font-mono);
  font-size: var(--fs-3xs);
  font-weight: var(--fw-strong);
  letter-spacing: var(--ls-normal);
  font-variant-numeric: tabular-nums;
  line-height: 1.4;
}

.mode-tab.active .mode-tab-meter {
  background: var(--bg-sunken);
}

/* Connection status */
.live-status {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  font-weight: var(--fw-body);
  color: var(--text-muted);
  padding: 8px 16px;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  box-shadow: 0 1px 3px rgba(4, 2, 18, 0.1);
}

.live-status-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--text-faint);
  flex-shrink: 0;
}

.live-status-dot.is-connecting {
  background: var(--voice);
  animation: dotPulse 1.3s ease-in-out infinite;
}

.live-status-dot.is-connected {
  background: var(--data);
  box-shadow: 0 0 8px var(--data);
}

.live-status-dot.is-error {
  background: var(--data-down);
}

@media (prefers-reduced-motion: reduce) {
  .live-status-dot.is-connecting {
    animation: none;
  }
}

/* Auth panel */
.auth-panel {
  display: flex;
  justify-content: center;
  margin-bottom: 20px;
}

.auth-link {
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  color: var(--text-faint);
  text-decoration: none;
  border-bottom: 1px dashed var(--border-strong);
  transition: all var(--dur-1) ease;
}

.auth-link:hover {
  color: var(--voice);
  border-bottom-color: var(--voice);
}

/* Connect button */
.live-connect-btn {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 12px 24px;
  border: none;
  border-radius: var(--radius-pill);
  cursor: pointer;
  background: linear-gradient(135deg, var(--data) 0%, var(--data-strong) 100%);
  color: var(--text-on-data);
  font-family: var(--font-body);
  font-weight: var(--fw-strong);
  font-size: var(--fs-body-sm);
  box-shadow: 0 4px 12px rgba(61, 220, 151, 0.3);
  transition: all 0.2s ease;
}

.live-connect-btn:hover {
  transform: translateY(-1px);
  box-shadow: 0 6px 16px rgba(61, 220, 151, 0.4);
}

.live-connect-btn:active {
  transform: translateY(0);
}

.live-connect-btn:focus-visible {
  box-shadow: 0 0 0 3px var(--data-dim), 0 4px 12px rgba(61, 220, 151, 0.3);
}

.live-connect-btn:disabled {
  cursor: wait;
  opacity: 0.75;
  transform: none;
}

.live-connect-icon {
  display: flex;
  width: 18px;
  height: 18px;
  flex-shrink: 0;
}

.live-connect-icon .icon {
  width: 18px;
  height: 18px;
}

.live-connect-btn.is-connecting .live-connect-icon .icon {
  animation: iconSpin 1.1s linear infinite;
}

/* Responsive adjustments */
@media (max-width: 768px) {
  .mode-tabs {
    padding: 5px;
    border-radius: 10px;
  }
  
  .mode-tab {
    padding: 8px 16px;
    font-size: var(--fs-xs);
  }
}

@media (max-width: 640px) {
  .mode-tabs {
    width: 100%;
    max-width: 100%;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    -ms-overflow-style: none;
  }
  
  .mode-tabs::-webkit-scrollbar {
    display: none;
  }
  
  .mode-tab {
    padding: 8px 14px;
    font-size: var(--fs-xs);
  }
}

@media (max-width: 480px) {
  .demo-mode-selector {
    margin: 20px 0 24px;
  }
  
  .mode-tab {
    padding: 7px 12px;
    font-size: var(--fs-label);
  }
}

/* ===== Standalone auth pages (login/signup/forgot/reset/verify) ===== */
/* Split product-canvas + form. Shared chrome lives in auth_base.html.
   Form fields here are `.auth-field`; `.form-field` below is the contact
   page's (and any other marketing form's) language — do not merge them. */
.auth-msg { font-family: var(--font-mono); font-size: var(--fs-label); color: var(--text-faint); text-align: center; margin-top: 14px; min-height: 16px; line-height: 1.6; }
.auth-msg a { color: var(--voice); }

.auth-split-body {
  min-height: 100vh;
  min-height: 100dvh;
  display: grid;
  grid-template-columns: minmax(420px, 1fr) minmax(440px, 1fr);
}
@media (max-width: 1080px) { .auth-split-body { grid-template-columns: 380px 1fr; } }
@media (max-width: 860px)  { .auth-split-body { grid-template-columns: 1fr; } }

.auth-brand-panel {
  background: var(--bg-sunken);
  display: flex; flex-direction: column;
  justify-content: space-between;
  padding: var(--sp-7) var(--sp-6);
  position: relative; overflow: hidden;
  border-right: 1px solid var(--border);
}
@media (max-width: 1080px) { .auth-brand-panel { padding: var(--sp-6) var(--sp-5); } }
@media (max-width: 860px)  { .auth-brand-panel { display: none; } }

.auth-brand-blob {
  position: absolute; border-radius: 50%;
  filter: blur(90px); pointer-events: none;
}
.auth-brand-blob.b1 {
  width: 420px; height: 420px;
  background: radial-gradient(ellipse, var(--accent-soft) 0%, transparent 70%);
  top: -100px; left: -100px;
  animation: blobDrift 14s var(--ease-in-out) infinite;
}
.auth-brand-blob.b2 {
  width: 320px; height: 320px;
  background: radial-gradient(ellipse, var(--voice-dim) 0%, transparent 70%);
  bottom: -60px; right: -60px;
  animation: blobDrift 18s var(--ease-in-out) infinite reverse;
}
@keyframes blobDrift {
  0%,100% { transform: translate(0,0) scale(1); }
  33%      { transform: translate(28px,-36px) scale(1.07); }
  66%      { transform: translate(-18px,28px) scale(0.94); }
}
@media (prefers-reduced-motion: reduce) { .auth-brand-blob { animation: none; } }

.auth-brand-logo {
  display: flex; align-items: center; gap: var(--sp-3);
  font-family: var(--font-display); font-weight: var(--fw-strong); font-size: var(--fs-h4);
  color: var(--text); text-decoration: none; position: relative; z-index: 1;
}
.auth-brand-logo img { width: 30px; height: 30px; }

.auth-brand-content {
  flex: 1; display: flex; flex-direction: column;
  justify-content: center; gap: var(--sp-6); position: relative; z-index: 1;
}
.auth-brand-content .eyebrow { margin-bottom: 0; align-self: flex-start; }

.auth-brand-headline {
  font-family: var(--font-display); font-size: var(--fs-h3);
  font-weight: var(--fw-display); line-height: 1.18; letter-spacing: var(--ls-tight-lg); color: var(--text);
}
.auth-brand-headline span {
  background: linear-gradient(135deg, var(--voice), var(--accent-strong));
  -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text;
}

.auth-brand-visual { position: relative; isolation: isolate; }
.auth-brand-visual .hero-visual-frame {
  box-shadow: var(--shadow-lift);
  padding: var(--sp-4) var(--sp-5);
}
.auth-brand-transcript { display: flex; flex-direction: column; gap: var(--sp-3); }
.auth-brand-visual .t-line { max-width: 100%; }
.auth-brand-visual .t-line.ai .txt { font-size: var(--fs-sm); }

.auth-brand-footer { position: relative; z-index: 1; font-family: var(--font-mono); font-size: var(--fs-2xs); color: var(--text-faint); }

.auth-form-panel {
  display: flex; flex-direction: column; justify-content: center; align-items: center;
  padding: var(--sp-7) var(--sp-6); background: var(--bg); position: relative;
  overflow-x: hidden; overflow-y: auto;
}
/* Fill the panel instead of the default 900px-tall box: that height made
   the panel's own overflow-y scroll into empty background on any screen
   shorter than ~820px (a second, blank scrollbar on login/verify). */
.auth-form-panel .hero-bg { z-index: 0; inset: 0; height: auto; overflow: hidden; }
.auth-form-panel .hero-blob { opacity: 0.28; }
@media (max-width: 860px) { .auth-form-panel { padding: var(--sp-6) var(--sp-4); justify-content: flex-start; } }

.auth-switch {
  position: absolute; top: var(--sp-5); right: var(--sp-5);
  z-index: 2; margin: 0;
  font-size: var(--fs-sm); color: var(--text-faint);
}
.auth-switch a {
  color: var(--text); font-weight: var(--fw-emphasis); text-decoration: none;
  border-bottom: 1px solid var(--border-strong);
  transition: color var(--dur-1) ease, border-color var(--dur-1) ease;
}
.auth-switch a:hover { color: var(--voice); border-bottom-color: var(--voice); }
@media (max-width: 860px) {
  .auth-switch { position: static; text-align: center; margin: 0 0 var(--sp-4); }
}

.auth-mobile-bar {
  display: none; align-items: center; justify-content: center;
  margin-bottom: var(--sp-6); text-decoration: none;
  font-family: var(--font-display); font-weight: var(--fw-strong); font-size: var(--fs-h4);
  color: var(--text); gap: var(--sp-3); position: relative; z-index: 2;
}
.auth-mobile-bar img { width: 28px; height: 28px; }
@media (max-width: 860px) { .auth-mobile-bar { display: flex; } }

.auth-form-card { width: 100%; max-width: 400px; position: relative; z-index: 2; }
.auth-form-card.is-status { text-align: center; }
.auth-form-card.is-status .btn { margin-top: var(--sp-5); }
/* h2 = a second pane on the same page (login's MFA step, signup's check-inbox
   step, the OPRA wizard's steps), styled as that pane's title. */
.auth-form-card h1, .auth-form-card h2 {
  font-family: var(--font-display); font-weight: var(--fw-display); font-size: var(--fs-xl);
  letter-spacing: var(--ls-tight); margin: 0 0 var(--sp-2); color: var(--text);
}
.auth-form-card .auth-form-sub {
  font-size: var(--fs-sm); color: var(--text-muted); margin: 0 0 var(--sp-6); line-height: 1.55;
}
/* Signup stacks two of these (the standalone-account note, then the "what
   happens next" step note). Two full --sp-6 gaps read as two unrelated
   paragraphs; collapsing the first keeps them as one intro block. */
.auth-form-card .auth-form-sub + .auth-form-sub { margin-top: calc(var(--sp-6) * -1 + var(--sp-2)); }
.auth-form-card .auth-form-sub a { color: var(--voice); text-decoration: underline; }

@keyframes cardShake {
  0%,100% { transform: translateX(0); }
  18%     { transform: translateX(-8px); }
  36%     { transform: translateX(8px); }
  54%     { transform: translateX(-5px); }
  72%     { transform: translateX(4px); }
  88%     { transform: translateX(-2px); }
}
.auth-form-card.is-error { animation: cardShake 0.46s var(--ease-out) both; }
@media (prefers-reduced-motion: reduce) { .auth-form-card.is-error { animation: none; } }

.auth-status-icon {
  width: 56px; height: 56px; margin: 0 auto var(--sp-5);
  display: grid; place-items: center;
  border-radius: var(--radius-md);
  background: var(--accent-soft); color: var(--accent);
}
.auth-status-icon .icon { width: 24px; height: 24px; }
.auth-status-icon.is-ok { background: var(--data-dim); color: var(--data); }
.auth-status-icon.is-fail { background: var(--data-down-dim); color: var(--data-down); }

/* Auth form fields — Linear-style labelled inputs, not the contact .form-field */
.auth-fields { display: flex; flex-direction: column; gap: var(--sp-4); }
.auth-field { display: flex; flex-direction: column; gap: var(--sp-2); }
.auth-field > label, .auth-field-row label {
  font-size: var(--fs-label); font-weight: var(--fw-emphasis);
  color: var(--text-muted); font-family: var(--font-body);
}
.auth-optional { font-weight: var(--fw-body); color: var(--text-faint); }
.auth-field-row {
  display: flex; justify-content: space-between; align-items: baseline; gap: var(--sp-3);
}
.auth-field-link {
  font-size: var(--fs-label); color: var(--text-faint); text-decoration: none;
  transition: color var(--dur-1) ease;
}
.auth-field-link:hover { color: var(--voice); }
.auth-input-wrap { position: relative; }
.auth-field input {
  width: 100%; font-family: var(--font-body); font-size: var(--fs-sm);
  letter-spacing: var(--ls-normal);
  background: var(--bg-elevated); border: 1px solid var(--border-strong);
  color: var(--text); border-radius: var(--radius-md);
  padding: var(--sp-3) var(--sp-4);
  transition: border-color var(--dur-1) ease, box-shadow var(--dur-1) ease, background var(--dur-1) ease;
}
.auth-field input:focus {
  outline: none; border-color: var(--accent);
  background: var(--bg-card);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.auth-field input::placeholder { color: var(--text-faint); }
.auth-field input.has-toggle { padding-right: 44px; }
.auth-field input:disabled { opacity: 0.6; cursor: not-allowed; }
.auth-field.is-invalid input { border-color: var(--data-down); box-shadow: 0 0 0 3px var(--data-down-dim); }
.auth-code-input {
  font-family: var(--font-mono); font-size: var(--fs-lg);
  letter-spacing: var(--ls-otp); text-align: center;
}

.auth-meter {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--sp-1);
  margin-top: var(--sp-1);
}
.auth-meter span {
  height: 3px; border-radius: var(--radius-pill); background: var(--border);
  transition: background var(--dur-2) ease;
}
.auth-meter[data-strength="1"] span:nth-child(1) { background: var(--data-down); }
.auth-meter[data-strength="2"] span:nth-child(-n+2) { background: var(--voice); }
.auth-meter[data-strength="3"] span:nth-child(-n+3) { background: var(--voice); }
.auth-meter[data-strength="4"] span { background: var(--data); }

/* Contact (and any other marketing form) — keep this language separate from auth */
.form-fields { display: flex; flex-direction: column; gap: 16px; }
.form-field { display: flex; flex-direction: column; gap: 6px; }
.form-field label { font-size: var(--fs-label); font-weight: var(--fw-emphasis); color: var(--text-muted); font-family: var(--font-body); }
.form-field .input-wrap { position: relative; }
.form-field input, .form-field textarea, .form-field select {
  width: 100%; font-family: var(--font-body); font-size: var(--fs-body-sm);
  background: var(--bg-elevated); border: 1px solid var(--border-strong);
  color: var(--text); border-radius: var(--radius-sm); padding: 11px 14px;
  transition: border-color var(--dur-1) ease, box-shadow var(--dur-1) ease;
  box-sizing: border-box;
}
.form-field input:focus, .form-field textarea:focus, .form-field select:focus {
  border-color: var(--accent); outline: none; box-shadow: 0 0 0 3px var(--accent-soft);
}
.form-field input::placeholder, .form-field textarea::placeholder { color: var(--text-faint); font-size: var(--fs-body-sm); }
.form-field input.has-toggle { padding-right: 42px; }
.form-field textarea { resize: vertical; min-height: 96px; font-family: inherit; }

/* Honeypot: off-screen rather than display:none (some bots skip hidden
   fields), aria-hidden so screen-reader users never encounter it. Any
   non-empty value here means a bot filled every input — the receiving view
   silently no-ops instead of erroring (contact.html / ContactMessageView). */
.hp-field { position: absolute; left: -9999px; top: -9999px; opacity: 0; pointer-events: none; }

.pw-toggle {
  position: absolute; right: 12px; top: 50%; transform: translateY(-50%);
  background: none; border: none; cursor: pointer; color: var(--text-faint);
  padding: 4px; display: flex; align-items: center;
  transition: color var(--dur-1) ease; z-index: 1;
}
.pw-toggle:hover { color: var(--accent-strong); }
.pw-toggle .icon, .pw-toggle svg { width: 16px; height: 16px; }

/* ── EZPZ / staking settings card (#ezpz on account_security) ── */
/* Link to the "Connect your EZPZ account" help guide, wherever linking is mentioned
   (Settings EZPZ card, Pricing add-on). Gold, the link colour prose pages use. */
.ezpz-guide-link { color: var(--voice); text-decoration: underline; text-decoration-color: var(--voice-dim); text-underline-offset: 2px; white-space: nowrap; }
.ezpz-guide-link:hover { text-decoration-color: var(--voice); }
.ezpz-hint {
  margin: var(--sp-3) 0 0;
  font-size: var(--fs-label);
  color: var(--text-faint);
  line-height: 1.6;
}
.ezpz-divider {
  height: 1px;
  margin: var(--sp-5) 0 var(--sp-4);
  background: var(--border-hair);
}
/* The card stacks several one-off action rows; this keeps their buttons from
   colliding without giving each block its own bespoke spacing rule. */
#ezpz .sbtn + .sbtn { margin-left: var(--sp-2); }
#ezpz .sf-row + .sbtn { margin-top: var(--sp-3); }

.auth-check-field { display: flex; flex-direction: column; gap: var(--sp-1); }
.auth-check {
  display: flex; align-items: flex-start; gap: var(--sp-2);
  font-size: var(--fs-body-sm); color: var(--text-muted); cursor: pointer;
  line-height: 1.5; font-weight: var(--fw-body);
}
.auth-check input[type="checkbox"] {
  width: 16px; height: 16px; margin: 2px 0 0; flex-shrink: 0;
  accent-color: var(--accent); cursor: pointer;
}
.auth-check strong { color: var(--text); font-weight: var(--fw-emphasis); }
.auth-check-hint {
  margin: 0 0 0 var(--sp-4);
  font-size: var(--fs-label); color: var(--text-faint); line-height: 1.5;
}
/* "optional" beside a field label (signup's Name field) */
.auth-label-opt { margin-left: var(--sp-2); font-weight: 400; color: var(--text-faint); }
.auth-ezpz-fields { display: flex; flex-direction: column; gap: var(--sp-3); }

/* Full-width loading modifier for `.btn.btn-primary` (auth + contact) */
.auth-submit { width: 100%; justify-content: center; margin-top: var(--sp-2); }
.auth-submit:disabled { opacity: 0.5; cursor: not-allowed; }
.btn-spinner {
  display: none; width: 16px; height: 16px; flex-shrink: 0;
  border: 2px solid var(--voice-dim);
  border-top-color: var(--text-on-accent);
  border-radius: 50%;
  animation: btnSpin 0.72s linear infinite;
}
.btn-text { transition: opacity var(--dur-1) ease; }
@keyframes btnSpin { to { transform: rotate(360deg); } }
.auth-submit.is-loading { pointer-events: none; }
.auth-submit.is-loading .btn-text { opacity: 0; max-width: 0; overflow: hidden; margin: 0; }
.auth-submit.is-loading .btn-spinner { display: block; }

.auth-status-msg {
  font-family: var(--font-mono); font-size: var(--fs-label); min-height: 18px;
  line-height: 1.6; margin-top: var(--sp-4); text-align: center;
  color: var(--text-faint); border-radius: var(--radius-sm);
  transition: color var(--dur-2) ease, background var(--dur-2) ease, border-color var(--dur-2) ease;
}
.auth-status-msg:not(:empty) { padding: 10px 14px; background: var(--bg-sunken); border: 1px solid var(--border); }
.auth-status-msg.is-error { color: var(--data-down); border-color: var(--data-down-dim); background: var(--data-down-dim); }
.auth-status-msg a { color: var(--voice); text-decoration: underline; }

.auth-form-links {
  text-align: center; font-size: var(--fs-xs); color: var(--text-faint); margin-top: var(--sp-5);
}
.auth-form-links a {
  color: var(--accent-strong); text-decoration: none; font-weight: var(--fw-emphasis);
  transition: color var(--dur-1) ease;
}
.auth-form-links a:hover { color: var(--voice); }

/* ── Onboarding (rebuilt 2026-09-23) ──────────────────────────────────────
   One progress strip across the whole join flow — Account -> Verify email ->
   Agreement -> Plan — rendered by _onboard_steps.html on signup, verify and
   the OPRA step, and moved client-side by auth.js's setOnboardStep(). Four
   thin bars with a mono label under each (Stripe/Vercel checkout pattern):
   done = --data, current = --voice, upcoming = --border. */
.onboard-steps {
  list-style: none; margin: 0 0 var(--sp-6); padding: 0;
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--sp-2);
}
.onboard-step {
  display: flex; flex-direction: column; gap: var(--sp-2); min-width: 0;
  font-family: var(--font-mono); font-size: var(--fs-2xs); letter-spacing: var(--ls-wide);
  text-transform: uppercase; color: var(--text-faint);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  transition: color var(--dur-2) ease;
}
/* At 320–385px "Verify email" was cut to "Verify e…"; let labels wrap. */
@media (max-width: 480px) { .onboard-step { white-space: normal; overflow: visible; line-height: 1.3; } }
.onboard-step::before {
  content: ""; display: block; height: 3px; border-radius: var(--radius-pill);
  background: var(--border); transition: background var(--dur-3) var(--ease-out);
}
.onboard-step.is-done { color: var(--text-muted); }
.onboard-step.is-done::before { background: var(--data); }
.onboard-step.is-current { color: var(--text); }
.onboard-step.is-current::before { background: linear-gradient(90deg, var(--voice), var(--voice-light)); }
@media (prefers-reduced-motion: reduce) { .onboard-step, .onboard-step::before { transition: none; } }

/* Wide card: the OPRA agreement step, which holds a document, not a short form. */
.auth-form-card.is-wide { max-width: 600px; }

/* A pane title that JS focuses on step change (so screen readers announce the
   new step) — a heading, not a control, so it takes no focus ring. */
.auth-form-card [tabindex="-1"]:focus { outline: none; }

/* Inline text button: a secondary action inside a sentence ("send it again",
   "use a different email"). A real <button>, styled as a link. */
.auth-text-btn {
  background: none; border: 0; padding: 0; font: inherit; cursor: pointer;
  color: var(--accent-strong); font-weight: var(--fw-emphasis);
  text-decoration: underline; text-decoration-color: var(--border-strong); text-underline-offset: 3px;
  transition: color var(--dur-1) ease;
}
.auth-text-btn:hover { color: var(--voice); }
.auth-text-btn:disabled { color: var(--text-faint); cursor: default; text-decoration: none; }
.auth-text-btn:focus-visible { outline: 2px solid var(--voice); outline-offset: 2px; border-radius: var(--radius-sm); }

.auth-ezpz-note { margin: 0 0 0 var(--sp-4); font-size: var(--fs-label); color: var(--text-faint); line-height: 1.5; }

/* Consent line under the signup button. */
.auth-legal { margin: 0; text-align: center; font-size: var(--fs-label); color: var(--text-faint); line-height: 1.5; }
.auth-legal a { color: var(--text-muted); text-decoration: underline; text-decoration-color: var(--border-strong); text-underline-offset: 2px; }
.auth-legal a:hover { color: var(--voice); }

/* Check-your-inbox pane (signup step 2). */
.auth-inbox { text-align: center; }
.auth-inbox .auth-status-icon { background: var(--voice-dim); color: var(--voice); }
.auth-inbox-email { color: var(--text); font-weight: var(--fw-emphasis); overflow-wrap: anywhere; }
.auth-inbox-open { width: 100%; justify-content: center; gap: var(--sp-2); }
.auth-inbox-open .icon { width: 16px; height: 16px; }
.auth-inbox-help {
  list-style: none; margin: var(--sp-5) 0 0; padding: var(--sp-4) 0 0;
  border-top: 1px solid var(--border-hair);
  display: flex; flex-direction: column; gap: var(--sp-2);
  font-size: var(--fs-xs); color: var(--text-faint); line-height: 1.6;
}
.auth-inbox-wait { font-family: var(--font-mono); letter-spacing: var(--ls-normal); font-variant-numeric: tabular-nums; }

/* Verify / status pages: stacked full-width actions under the message. */
.auth-status-actions { display: flex; flex-direction: column; gap: var(--sp-3); margin-top: var(--sp-5); }
.auth-status-actions .btn { width: 100%; justify-content: center; }
.auth-form-card.is-status .auth-status-actions .btn { margin-top: 0; }
.auth-status-resend { text-align: left; margin-top: var(--sp-5); }

/* ===== Settings / Profile page ===== */
/* Account dropdown — main nav + settings page both use .topbar with this component */
.nav-user-wrap { position: relative; }
.nav-user-btn {
  display: flex; align-items: center; gap: 8px;
  background: none; border: 1px solid var(--border); border-radius: var(--radius-sm);
  padding: 5px 10px 5px 6px; cursor: pointer;
  font-family: var(--font-body); font-size: var(--fs-xs); color: var(--text-muted);
  transition: border-color var(--dur-1) ease, background var(--dur-1) ease;
  line-height: 1;
}
.nav-user-btn:hover { border-color: var(--border-strong); background: var(--bg-elevated); }
.nav-user-avatar {
  width: 24px; height: 24px; border-radius: 50%;
  background: linear-gradient(135deg, var(--accent-dim), var(--accent));
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-display); font-weight: var(--fw-strong); font-size: var(--fs-2xs); color: var(--text); flex-shrink: 0;
}
.nav-user-name {
  max-width: 110px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--fs-xs);
}
.nav-user-caret { opacity: 0.4; flex-shrink: 0; }
/* Avatar only on phones: with the name the button (~180px) plus brand and
   burger overflowed the topbar below ~430px when logged in. */
@media (max-width: 480px) { .nav-user-name { display: none; } .nav-user-btn { padding: 5px 8px 5px 6px; } }
.nav-user-dropdown {
  position: absolute; top: calc(100% + 8px); right: 0;
  background: var(--bg-card); border: 1px solid var(--border); border-radius: 10px;
  min-width: 218px; padding: 6px 0;
  box-shadow: 0 12px 28px rgba(4, 2, 18, 0.45); z-index: 600;
  opacity: 0; pointer-events: none; transform: translateY(-6px);
  transition: opacity var(--dur-1) ease, transform var(--dur-1) ease;
}
.nav-user-dropdown.is-open {
  opacity: 1; pointer-events: auto; transform: translateY(0);
}
.nav-dropdown-email {
  padding: 10px 16px 8px; font-size: var(--fs-label); color: var(--text-faint);
  font-family: var(--font-mono); border-bottom: 1px solid var(--border-hair);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.nav-dropdown-item {
  display: flex; align-items: center; gap: 10px; padding: 9px 16px;
  font-size: var(--fs-body-sm); font-weight: var(--fw-body); color: var(--text-muted);
  text-decoration: none; background: none; border: none; width: 100%;
  text-align: left; cursor: pointer; font-family: var(--font-body);
  transition: background var(--dur-1) ease, color var(--dur-1) ease;
}
.nav-dropdown-item:hover { background: var(--bg-elevated); color: var(--text); }
.nav-dropdown-item svg { width: 14px; height: 14px; flex-shrink: 0; opacity: 0.6; }
.nav-dropdown-item.is-danger:hover { color: var(--data-down); background: rgba(255,107,122,0.08); }
.nav-dropdown-divider { height: 1px; background: var(--border-hair); margin: 4px 0; }

.settings-layout {
  display: grid; grid-template-columns: 208px 1fr;
  max-width: var(--container-max); width: 100%; margin: 0 auto; padding: 40px 28px; gap: 36px;
}
@media (max-width: 720px) { .settings-layout { grid-template-columns: 1fr; padding: 20px 16px; gap: 24px; } }

/* Sticky sidebar — top offset matches the shared topbar height (64px) */
@media (min-width: 720px) {
  .settings-sidebar { position: sticky; top: 80px; align-self: start; }
  .settings-layout .scard { scroll-margin-top: 88px; }
}
.settings-sidebar { display: flex; flex-direction: column; gap: 2px; }
.settings-sidebar-label {
  font-family: var(--font-mono); font-size: var(--fs-3xs); font-weight: var(--fw-emphasis);
  text-transform: uppercase; letter-spacing: var(--ls-wide); color: var(--text-faint);
  padding: 0 10px; margin-bottom: 4px; margin-top: 16px;
}
.settings-sidebar-label:first-child { margin-top: 0; }
.settings-nav-btn {
  display: flex; align-items: center; gap: 9px; padding: 8px 10px;
  border-radius: var(--radius-sm); font-family: var(--font-body); font-size: var(--fs-body-sm);
  font-weight: var(--fw-body); color: var(--text-muted); text-decoration: none; cursor: pointer;
  border: none; background: none; width: 100%; text-align: left;
  transition: background var(--dur-1) ease, color var(--dur-1) ease;
}
.settings-nav-btn:hover { background: var(--bg-elevated); color: var(--text); }
.settings-nav-btn.active { background: var(--accent-soft); color: var(--accent-strong); }
.settings-nav-btn svg { width: 15px; height: 15px; flex-shrink: 0; stroke-width: 2.2; }

.settings-main { display: flex; flex-direction: column; gap: 20px; }

/* Profile hero card */
.profile-hero {
  background: var(--bg-card); border: 1px solid var(--border);
  border-radius: var(--radius-md); padding: 24px;
  display: flex; align-items: center; gap: 18px;
}
.profile-hero-avatar {
  width: 54px; height: 54px; border-radius: 50%;
  background: linear-gradient(135deg, var(--accent-dim), var(--accent));
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-display); font-weight: var(--fw-display); font-size: var(--fs-h3); color: var(--text);
  flex-shrink: 0; box-shadow: 0 0 0 3px var(--accent-soft);
}
.profile-hero-info { flex: 1; min-width: 0; }
.profile-hero-name {
  font-family: var(--font-display); font-size: var(--fs-h4); font-weight: var(--fw-strong);
  margin: 0 0 2px; color: var(--text);
}
.profile-hero-email { font-size: var(--fs-xs); color: var(--text-faint); margin: 0 0 10px; }
.profile-hero-name, .profile-hero-email { overflow-wrap: anywhere; } /* long emails on phones */
.profile-hero-badges { display: flex; gap: 7px; flex-wrap: wrap; }
.pbadge {
  display: inline-flex; align-items: center; gap: 4px;
  font-family: var(--font-mono); font-size: var(--fs-3xs); font-weight: var(--fw-emphasis);
  padding: 3px 9px; border-radius: var(--radius-pill);
  text-transform: uppercase; letter-spacing: var(--ls-wide);
}
.pbadge.standard { background: var(--bg-elevated); color: var(--text-muted); border: 1px solid var(--border-strong); }
.pbadge.pro { background: var(--accent-soft); color: var(--accent-strong); border: 1px solid rgba(155,107,255,0.3); }
.pbadge.elite { background: var(--voice-dim); color: var(--voice-strong); border: 1px solid rgba(255,181,71,0.3); }
.pbadge.verified { background: var(--data-dim); color: var(--data); border: 1px solid rgba(61,220,151,0.3); }
.pbadge svg { width: 10px; height: 10px; stroke-width: 2.5; }

/* Settings card */
.scard {
  background: var(--bg-card); border: 1px solid var(--border);
  border-radius: var(--radius-md); overflow: hidden;
}
.scard-head {
  padding: 18px 22px 14px; border-bottom: 1px solid var(--border-hair);
}
.scard-head h2 {
  font-family: var(--font-display); font-size: var(--fs-sm); font-weight: var(--fw-strong);
  margin: 0 0 3px; color: var(--text);
}
.scard-head p { font-size: var(--fs-sm); color: var(--text-faint); margin: 0; line-height: 1.5; }
.scard-body { padding: 20px 22px; display: flex; flex-direction: column; gap: 16px; }
.scard-body form { margin: 0; display: flex; flex-direction: column; gap: 16px; width: 100%; }
.scard-foot {
  padding: 14px 22px; border-top: 1px solid var(--border-hair);
  background: var(--bg-sunken); display: flex; align-items: center;
  justify-content: space-between; gap: 12px;
}
.scard-foot-msg {
  font-family: var(--font-mono); font-size: var(--fs-label); color: var(--text-faint); flex: 1;
  transition: color var(--dur-2) ease;
}
.scard-foot-msg.ok { color: var(--data); }
.scard-foot-msg.err { color: var(--data-down); }

/* Settings form rows */
.sf-row { display: flex; flex-direction: column; gap: 5px; }
.sf-row label { font-size: var(--fs-label); font-weight: var(--fw-emphasis); color: var(--text-muted); }
.sf-row .sf-hint { font-size: var(--fs-label); color: var(--text-faint); line-height: 1.4; }
.sf-row .input-wrap { position: relative; }
.sf-row input {
  width: 100%; max-width: 480px; font-family: var(--font-body); font-size: var(--fs-body-sm);
  background: var(--bg-elevated); border: 1px solid var(--border-strong);
  color: var(--text); border-radius: var(--radius-sm); padding: 10px 14px;
  transition: border-color var(--dur-1) ease, box-shadow var(--dur-1) ease;
  box-sizing: border-box;
}
.sf-row input:focus { border-color: var(--accent); outline: none; box-shadow: 0 0 0 3px var(--accent-soft); }
.sf-row input::placeholder { color: var(--text-faint); font-size: var(--fs-xs); }
.sf-row input.has-toggle { padding-right: 42px; }

/* Settings buttons */
.sbtn {
  font-family: var(--font-body); font-size: var(--fs-xs); font-weight: var(--fw-emphasis);
  padding: 8px 16px; border-radius: var(--radius-sm); border: none;
  cursor: pointer; white-space: nowrap;
  transition: opacity var(--dur-1) ease, transform var(--dur-1) ease;
}
.sbtn:hover { opacity: 0.85; transform: translateY(-1px); }
.sbtn:active { transform: translateY(0); }
.sbtn:disabled { opacity: 0.4; cursor: not-allowed; transform: none; }
.sbtn.primary { background: var(--accent); color: var(--text); }
.sbtn.secondary { background: var(--bg-elevated); color: var(--text-muted); border: 1px solid var(--border-strong); }
.sbtn.danger { background: var(--data-down-dim); color: var(--data-down); border: 1px solid rgba(255,107,122,0.25); }

/* 2FA status indicator */
.mfa-row {
  display: flex; align-items: center; gap: 14px;
  padding: 14px 16px; background: var(--bg-elevated);
  border-radius: var(--radius-sm); border: 1px solid var(--border);
}
.mfa-row-icon {
  width: 34px; height: 34px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center; flex-shrink: 0;
}
.mfa-row-icon.on { background: var(--data-dim); color: var(--data); }
.mfa-row-icon.off { background: var(--bg-card); color: var(--text-faint); border: 1px solid var(--border-strong); }
.mfa-row-icon svg { width: 16px; height: 16px; stroke-width: 2.2; }
.mfa-row-text strong { font-size: var(--fs-body-sm); font-weight: var(--fw-emphasis); color: var(--text); display: block; }
.mfa-row-text span { font-size: var(--fs-label); color: var(--text-faint); }

/* QR / backup code areas */
.mfa-qr-wrap {
  text-align: center; padding: 20px;
  background: var(--bg-elevated); border-radius: var(--radius-sm); border: 1px solid var(--border);
}
.mfa-qr-wrap img { width: 176px; height: 176px; border-radius: 8px; display: block; margin: 0 auto 12px; }
.mfa-secret-mono {
  font-family: var(--font-mono); font-size: var(--fs-label); color: var(--text-muted);
  background: var(--bg-card); border: 1px solid var(--border);
  border-radius: var(--radius-sm); padding: 8px 12px;
  word-break: break-all; text-align: center;
}
.backup-grid {
  display: grid; grid-template-columns: 1fr 1fr; gap: 8px;
}
.backup-cell {
  font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--text);
  background: var(--bg-elevated); border: 1px solid var(--border);
  border-radius: var(--radius-sm); padding: 8px 12px; text-align: center; letter-spacing: var(--ls-wide);
}

/* Usage meters (account_security.html's "Usage this period" card) */
.usage-meter { display: flex; flex-direction: column; gap: 7px; }
.usage-meter-head { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; }
.usage-meter-label { font-size: var(--fs-label); font-weight: var(--fw-emphasis); color: var(--text-muted); }
.usage-meter-value {
  font-family: var(--font-mono); font-size: var(--fs-label); color: var(--text-faint);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* "1,234,567 of 2,000,000 tokens (62%)" doesn't fit beside the label on a
   phone — wrap it under instead of cutting the numbers off. */
@media (max-width: 560px) { .usage-meter-head { flex-wrap: wrap; } .usage-meter-value { white-space: normal; } }
.usage-bar-track { height: 8px; border-radius: var(--radius-pill); background: var(--bg-elevated); overflow: hidden; }
.usage-bar-fill {
  height: 100%; width: 0%; border-radius: var(--radius-pill);
  background: linear-gradient(90deg, var(--accent), var(--accent-strong));
  transition: width var(--dur-3) var(--ease-out), background var(--dur-2) ease;
}
.usage-bar-fill--voice { background: linear-gradient(90deg, var(--voice), var(--voice-strong)); }
.usage-bar-fill.is-warning { background: linear-gradient(90deg, var(--voice), var(--voice-strong)); }
.usage-bar-fill.is-danger { background: linear-gradient(90deg, var(--data-down), #FF8A96); }

/* Credit section (account_security.html's dedicated "Credit balance" card,
   added 2026-09-09 — self-service top-up, a master "use my credit"
   switch, and an auto-reload toggle, same pattern Anthropic Console/
   OpenAI billing use) */
.scard-head-row { display: flex; align-items: flex-start; justify-content: space-between; gap: 14px; }
.credit-balance-row { display: flex; align-items: baseline; gap: 8px; }
.credit-balance-amount { font-family: var(--font-mono); font-size: var(--fs-xl); font-weight: var(--fw-strong); color: var(--data); }
.credit-balance-label { font-size: var(--fs-label); color: var(--text-faint); }
.credit-divider { height: 1px; background: var(--border-hair); }
.credit-section-label { font-size: var(--fs-label); font-weight: var(--fw-emphasis); color: var(--text-muted); margin: 0 0 8px; }

.credit-topup-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.credit-topup-group { display: flex; gap: 6px; flex-wrap: wrap; }
.credit-topup-btn {
  font-family: var(--font-mono); font-size: var(--fs-label); font-weight: var(--fw-strong);
  padding: 6px 12px; border-radius: var(--radius-pill);
  border: 1px solid var(--border-strong); background: var(--bg-elevated); color: var(--text-muted);
  cursor: pointer; transition: border-color var(--dur-1) ease, color var(--dur-1) ease, background var(--dur-1) ease, transform var(--dur-1) ease;
}
.credit-topup-btn:hover { border-color: var(--accent-strong); color: var(--accent-strong); background: var(--accent-soft); transform: translateY(-1px); }
.credit-topup-btn:active { transform: translateY(0); }
.credit-topup-btn:disabled { opacity: 0.4; cursor: not-allowed; transform: none; }
.credit-topup-btn--custom { background: var(--accent-soft); border-color: var(--accent); color: var(--accent-strong); }
.credit-topup-custom { display: flex; align-items: center; gap: 4px; }
.credit-topup-custom-prefix { font-family: var(--font-mono); font-size: var(--fs-label); color: var(--text-faint); }
.credit-topup-custom-input {
  width: 60px; font-family: var(--font-mono); font-size: var(--fs-label);
  background: var(--bg-elevated); border: 1px solid var(--border-strong); color: var(--text);
  border-radius: var(--radius-sm); padding: 5px 8px;
  -moz-appearance: textfield;
}
.credit-topup-custom-input::-webkit-outer-spin-button, .credit-topup-custom-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.credit-topup-custom-input:focus { border-color: var(--accent); outline: none; box-shadow: 0 0 0 3px var(--accent-soft); }

.credit-autoreload-head { display: flex; align-items: center; justify-content: space-between; }
.credit-autoreload-config {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  font-size: var(--fs-label); color: var(--text-muted); margin-top: 12px;
}
.credit-inline-input-wrap { display: inline-flex; align-items: center; gap: 2px; font-family: var(--font-mono); color: var(--text); }
.credit-inline-input {
  width: 52px; font-family: var(--font-mono); font-size: var(--fs-label);
  background: var(--bg-elevated); border: 1px solid var(--border-strong); color: var(--text);
  border-radius: var(--radius-sm); padding: 4px 6px;
  -moz-appearance: textfield;
}
.credit-inline-input::-webkit-outer-spin-button, .credit-inline-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.credit-inline-input:focus { border-color: var(--accent); outline: none; box-shadow: 0 0 0 3px var(--accent-soft); }

/* Toggle switch — reused for both the "use my credit" and "auto-reload"
   master switches. A real <input type="checkbox"> under the hood (kept
   accessible/focusable/labelable), visually hidden, driving sibling
   .tvx-toggle-track/-thumb via :checked. */
.tvx-toggle { position: relative; display: inline-flex; align-items: center; cursor: pointer; flex-shrink: 0; }
.tvx-toggle input {
  position: absolute; opacity: 0; width: 1px; height: 1px; margin: -1px; overflow: hidden;
}
.tvx-toggle-track {
  width: 38px; height: 22px; border-radius: var(--radius-pill);
  background: var(--bg-elevated); border: 1px solid var(--border-strong);
  transition: background var(--dur-2) ease, border-color var(--dur-2) ease;
  position: relative; display: inline-block;
}
.tvx-toggle-thumb {
  position: absolute; top: 2px; left: 2px; width: 16px; height: 16px; border-radius: 50%;
  background: var(--text-faint);
  transition: transform var(--dur-2) var(--ease-out), background var(--dur-2) ease;
}
.tvx-toggle input:checked + .tvx-toggle-track { background: var(--accent-soft); border-color: var(--accent); }
.tvx-toggle input:checked + .tvx-toggle-track .tvx-toggle-thumb { transform: translateX(16px); background: var(--accent-strong); }
.tvx-toggle input:focus-visible + .tvx-toggle-track { outline: 2px solid var(--voice); outline-offset: 2px; }
.tvx-toggle input:disabled + .tvx-toggle-track { opacity: 0.5; cursor: not-allowed; }

@keyframes fade-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: translateY(0); } }
.scard { animation: fade-in 0.2s ease; }

/* ===== Voice demo widget ===== */
/* Modern Demo Shell (redesigned 2026-09-02) - Enhanced UI with depth and polish */
.demo-shell {
  position: relative;
  background: var(--bg-glass);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  box-shadow: 
    0 8px 32px rgba(4, 2, 18, 0.3),
    0 2px 8px rgba(4, 2, 18, 0.2),
    inset 0 1px 0 rgba(255, 255, 255, 0.05);
  padding: 40px;
  display: grid;
  grid-template-columns: 1fr;
  gap: 32px;
  overflow: hidden;
}

.demo-shell::before {
  content: '';
  position: absolute;
  inset: -1px;
  border-radius: var(--radius-xl);
  padding: 1px;
  z-index: -1;
  background: linear-gradient(135deg, 
    rgba(99, 102, 241, 0.2) 0%, 
    transparent 20%,
    transparent 40%,
    rgba(255, 181, 71, 0.15) 60%,
    transparent 80%
  );
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
}

.demo-shell::after {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 1px;
  background: linear-gradient(90deg, 
    transparent, 
    rgba(255, 255, 255, 0.1), 
    transparent
  );
}

@media (min-width: 900px) {
  .demo-shell {
    grid-template-columns: 320px 1fr;
    padding: 44px;
  }
}

/* Enhanced Voice Column */
.demo-voice-column,
.orb-col {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 20px;
}

.voice-orb-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  width: 100%;
}

/* Enhanced orb styling */
.orb-wrap {
  position: relative;
  width: 180px;
  height: 180px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.orb {
  width: 120px;
  height: 120px;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, var(--bg-orb-glow), var(--bg-card) 70%);
  border: 2px solid var(--border-strong);
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  box-shadow: 
    0 8px 24px rgba(4, 2, 18, 0.2),
    inset 0 2px 8px rgba(255, 255, 255, 0.1),
    inset 0 -2px 8px rgba(4, 2, 18, 0.1);
  transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}

.orb-ring {
  position: absolute;
  inset: -16px;
  border-radius: 50%;
  border: 2px solid rgba(255, 181, 71, 0);
  transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}

.orb-wrap[data-state="idle"] .orb {
  box-shadow: 
    0 4px 16px rgba(4, 2, 18, 0.15),
    inset 0 2px 8px rgba(255, 255, 255, 0.08);
}

.orb-wrap[data-state="listening"] .orb-ring {
  border-color: rgba(62, 217, 160, 0.5);
  animation: pulseRing 1.6s ease-out infinite;
  box-shadow: 0 0 20px rgba(62, 217, 160, 0.3);
}

.orb-wrap[data-state="listening"] .orb {
  border-color: var(--data);
  box-shadow: 
    0 0 30px rgba(62, 217, 160, 0.4),
    0 8px 24px rgba(4, 2, 18, 0.2);
}

.orb-wrap[data-state="thinking"] .orb {
  border-color: var(--border-strong);
  animation: thinkTilt 2.4s ease-in-out infinite;
  box-shadow: 0 4px 16px rgba(4, 2, 18, 0.2);
}

.orb-wrap[data-state="speaking"] .orb {
  border-color: var(--voice);
  box-shadow: 
    0 0 40px rgba(255, 181, 71, 0.45),
    0 8px 32px rgba(255, 181, 71, 0.25),
    inset 0 2px 8px rgba(255, 255, 255, 0.15);
  animation: speakGlow 1.1s ease-in-out infinite;
}

.orb-wrap[data-state="speaking"] .orb-ring {
  border-color: rgba(255, 181, 71, 0.4);
  box-shadow: 0 0 30px rgba(255, 181, 71, 0.5);
}

.orb-wrap[data-state="error"] .orb {
  border-color: var(--data-down);
  background: radial-gradient(circle at 35% 30%, var(--data-down-deep), var(--bg-card) 70%);
  box-shadow: 0 0 30px rgba(239, 68, 68, 0.3);
}

.orb-col { display: flex; flex-direction: column; align-items: center; gap: 18px; }
.orb-wrap { position: relative; width: 160px; height: 160px; display: flex; align-items: center; justify-content: center; }
.orb {
  width: 108px; height: 108px; border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, var(--bg-orb-glow), var(--bg-card) 70%);
  border: 1px solid var(--border-strong); position: relative;
  display: flex; align-items: center; justify-content: center; overflow: hidden;
  transition: box-shadow 0.4s ease, border-color 0.4s ease, transform 0.3s ease;
}
.orb-ring { position: absolute; inset: -14px; border-radius: 50%; border: 1px solid rgba(255, 181, 71, 0); transition: border-color 0.4s ease; }

.orb-wrap[data-state="listening"] .orb-ring { border-color: rgba(62, 217, 160, 0.55); animation: pulseRing 1.6s ease-out infinite; }
.orb-wrap[data-state="listening"] .orb { border-color: var(--data); }
.orb-wrap[data-state="thinking"] .orb { border-color: var(--border-strong); animation: thinkTilt 2.4s ease-in-out infinite; }
.orb-wrap[data-state="speaking"] .orb {
  border-color: var(--voice); box-shadow: 0 0 0 0 rgba(255, 181, 71, 0.5), 0 0 40px rgba(255, 181, 71, 0.35);
  animation: speakGlow 1.1s ease-in-out infinite;
}
.orb-wrap[data-state="speaking"] .orb-ring { border-color: rgba(255, 181, 71, 0.5); }
.orb-wrap[data-state="error"] .orb { border-color: var(--data-down); background: radial-gradient(circle at 35% 30%, var(--data-down-deep), var(--bg-card) 70%); }

@keyframes pulseRing { 0% { transform: scale(0.92); opacity: 0.9; } 70% { transform: scale(1.14); opacity: 0; } 100% { opacity: 0; } }
@keyframes speakGlow { 0%, 100% { box-shadow: 0 0 0 0 rgba(255, 181, 71, 0.45), 0 0 30px rgba(255, 181, 71, 0.3); } 50% { box-shadow: 0 0 0 10px rgba(255, 181, 71, 0), 0 0 50px rgba(255, 181, 71, 0.5); } }
@keyframes thinkTilt { 0%, 100% { transform: rotate(0deg); } 50% { transform: rotate(6deg); } }

/* Enhanced status indicator */
.orb-status {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 8px 16px;
  background: var(--bg-sunken);
  border-radius: var(--radius-pill);
  border: 1px solid var(--border);
}

.status-indicator {
  display: flex;
  align-items: center;
  gap: 10px;
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  font-weight: var(--fw-emphasis);
  letter-spacing: var(--ls-wide);
  text-transform: uppercase;
  color: var(--text-muted);
}

.orb-status .dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--text-faint);
  position: relative;
}

.orb-status .dot::after {
  content: '';
  position: absolute;
  inset: -2px;
  border-radius: 50%;
  border: 1px solid currentColor;
  opacity: 0.3;
}

.orb-wrap[data-state="listening"] ~ .orb-status .dot { 
  background: var(--data);
  box-shadow: 0 0 8px var(--data);
}
.orb-wrap[data-state="speaking"] ~ .orb-status .dot { 
  background: var(--voice);
  box-shadow: 0 0 8px var(--voice);
}
.orb-wrap[data-state="error"] ~ .orb-status .dot { 
  background: var(--data-down);
  box-shadow: 0 0 8px var(--data-down);
}

/* Enhanced waveform with brand identity */
.waveform {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 8px;
}

.waveform .bar {
  width: 10px;
  border-radius: 6px;
  background: var(--text-faint);
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  transform-origin: center;
  position: relative;
}

.waveform .bar::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 6px;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.2) 0%, transparent 100%);
  opacity: 0;
  transition: opacity 0.3s ease;
}

.waveform .bar:nth-child(1),
.waveform .bar:nth-child(5) { height: 24px; }
.waveform .bar:nth-child(2),
.waveform .bar:nth-child(4) { height: 16px; }
.waveform .bar:nth-child(3) { height: 8px; }

.waveform.active .bar {
  background: linear-gradient(180deg, var(--voice-strong) 0%, var(--voice) 100%);
  animation: barPulse 0.9s ease-in-out infinite;
}

.waveform.active .bar::after {
  opacity: 1;
}

.waveform.active .bar:nth-child(1) { animation-delay: 0s; }
.waveform.active .bar:nth-child(2) { animation-delay: 0.12s; }
.waveform.active .bar:nth-child(3) { animation-delay: 0.24s; }
.waveform.active .bar:nth-child(4) { animation-delay: 0.36s; }
.waveform.active .bar:nth-child(5) { animation-delay: 0.48s; }

.eco-orbit-hub .bar { background: var(--voice); }
.eco-orbit-hub .waveform { transform: scale(0.82); }

@keyframes barPulse {
  0%, 100% { transform: scaleY(1); }
  50% { transform: scaleY(1.8); }
}

@media (prefers-reduced-motion: reduce) {
  .waveform.active .bar,
  .orb-wrap .orb,
  .orb-wrap .orb-ring {
    animation: none !important;
  }
}

/* Modern Mic Controls */
.mic-controls,
.mic-actions {
  display: flex;
  flex-direction: column;
  gap: 12px;
  width: 100%;
}

.mic-btn {
  position: relative;
  width: 100%;
  min-height: 56px;
  border-radius: var(--radius-md);
  padding: 10px 18px;
  background: var(--bg-card);
  border: 2px solid var(--border);
  color: var(--text);
  font-family: var(--font-body);
  font-weight: var(--fw-emphasis);
  font-size: var(--fs-sm);
  letter-spacing: var(--ls-tight);
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 14px;
  text-align: left;
  transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
  touch-action: none;
  user-select: none;
  outline: none;
  overflow: hidden;
}

.mic-btn::before {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(135deg, rgba(255, 255, 255, 0.1) 0%, transparent 50%);
  opacity: 0;
  transition: opacity 0.25s ease;
}

.mic-btn:hover {
  border-color: var(--border-strong);
  transform: translateY(-2px);
  box-shadow: 0 4px 12px rgba(4, 2, 18, 0.15);
}

.mic-btn:hover::before {
  opacity: 1;
}

.mic-btn:focus-visible {
  border-color: var(--voice);
  box-shadow: 0 0 0 3px var(--voice-dim);
}

.mic-btn-icon {
  width: 40px;
  height: 40px;
  border-radius: 12px;
  flex-shrink: 0;
  background: var(--voice-dim);
  color: var(--voice);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
  position: relative;
}

.mic-btn-icon::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 12px;
  background: linear-gradient(135deg, rgba(255, 255, 255, 0.15) 0%, transparent 100%);
  opacity: 0;
  transition: opacity 0.25s ease;
}

.mic-btn:hover .mic-btn-icon::after {
  opacity: 1;
}

.mic-btn-icon .icon {
  width: 18px;
  height: 18px;
  position: relative;
  z-index: 1;
}

.mic-btn-label {
  flex: 1;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  position: relative;
  z-index: 1;
}

.mic-btn.is-listening {
  border-color: var(--data);
  background: var(--data-dim);
  box-shadow: 0 0 20px rgba(62, 217, 160, 0.2);
}

.mic-btn.is-listening .mic-btn-icon {
  background: rgba(61, 220, 151, 0.25);
  color: var(--data);
}

.mic-btn.is-convo-active {
  border-color: var(--voice);
  background: var(--voice-dim);
  box-shadow: 0 0 20px rgba(255, 181, 71, 0.2);
}

.mic-btn.is-convo-active .mic-btn-icon {
  background: rgba(255, 181, 71, 0.3);
  color: var(--voice);
}

.mic-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
  transform: none !important;
}

.mic-hint {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--fs-label);
  color: var(--text-faint);
  text-align: center;
  padding: 8px 12px;
  background: var(--bg-sunken);
  border-radius: var(--radius-sm);
  border: 1px solid var(--border-hair);
}

/* Usage-rate notice at the top of a voice panel (Studio). Spans both demo
   columns; the detail list opens inline (data-disclosure, interactions.js)
   rather than as a floating tooltip, since .demo-shell clips overflow. */
.usage-callout {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: start;
  gap: var(--sp-3) var(--sp-4);
  padding: var(--sp-4) var(--sp-5);
  background: var(--voice-dim);
  border: 1px solid var(--border-voice);
  border-radius: var(--radius-md);
}

.usage-callout-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: var(--radius-sm);
  background: var(--bg-sunken);
  color: var(--voice);
}

.usage-callout-icon .icon {
  width: 20px;
  height: 20px;
}

.usage-callout-body {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
  min-width: 0;
}

.usage-callout-title {
  margin: 0;
  color: var(--text);
  font-size: var(--fs-body-sm);
  font-weight: var(--fw-strong);
  letter-spacing: var(--ls-tight);
}

.usage-callout-text {
  margin: 0;
  color: var(--text-muted);
  font-size: var(--fs-body-sm);
}

.usage-callout-rate {
  color: var(--voice);
  font-family: var(--font-mono);
  font-weight: var(--fw-strong);
  letter-spacing: var(--ls-normal);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.usage-callout-detail {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  margin-top: var(--sp-3);
}

.usage-callout-list {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  margin: 0;
  padding: var(--sp-3) var(--sp-4);
  list-style: none;
  background: var(--bg-sunken);
  border: 1px solid var(--border-hair);
  border-radius: var(--radius-sm);
  font-size: var(--fs-body-sm);
  color: var(--text-muted);
}

.usage-callout-list li {
  display: flex;
  justify-content: space-between;
  gap: var(--sp-4);
}

.usage-callout-link {
  color: var(--voice);
  font-weight: var(--fw-emphasis);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.usage-callout-link:hover {
  color: var(--voice-strong);
}

.usage-callout-toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--border-voice);
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--voice);
  font-family: var(--font-body);
  font-size: var(--fs-label);
  font-weight: var(--fw-emphasis);
  white-space: nowrap;
  cursor: pointer;
  transition: background var(--dur-2) var(--ease-out), border-color var(--dur-2) var(--ease-out);
}

.usage-callout-toggle:hover {
  background: var(--voice-dim);
  border-color: var(--voice);
}

.usage-callout-link:focus-visible,
.usage-callout-toggle:focus-visible {
  outline: 2px solid var(--accent-strong);
  outline-offset: 2px;
}

.usage-callout-toggle .icon {
  width: 14px;
  height: 14px;
  transition: transform var(--dur-2) var(--ease-out);
}

.usage-callout-toggle[aria-expanded="true"] .icon {
  transform: rotate(180deg);
}

@media (prefers-reduced-motion: reduce) {
  .usage-callout-toggle,
  .usage-callout-toggle .icon {
    transition: none;
  }
}

@media (max-width: 640px) {
  .usage-callout {
    grid-template-columns: auto 1fr;
    padding: var(--sp-4);
  }

  .usage-callout-toggle {
    grid-column: 1 / -1;
    justify-self: start;
  }

  .usage-callout-list li {
    flex-direction: column;
    gap: 0;
  }
}

/* Enhanced conversation row */
.mic-convo-row {
  display: flex;
  gap: 12px;
}

.mic-convo-row .mic-btn {
  flex: 1;
  min-width: 0;
}

.mute-btn {
  flex-shrink: 0;
  width: 56px;
  min-height: 56px;
  border-radius: var(--radius-md);
  background: var(--bg-card);
  border: 2px solid var(--border);
  color: var(--text-muted);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  outline: none;
  transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}

.mute-btn:hover {
  border-color: var(--border-strong);
  color: var(--text);
  transform: translateY(-2px);
}

.mute-btn:focus-visible {
  border-color: var(--voice);
  box-shadow: 0 0 0 3px var(--voice-dim);
}

.mute-btn .icon {
  width: 18px;
  height: 18px;
}

.mute-btn .icon-muted {
  display: none;
}

.mute-btn.is-muted {
  border-color: var(--data-down);
  background: var(--data-down-dim);
  color: var(--data-down);
}

.mute-btn.is-muted .icon-unmuted {
  display: none;
}

.mute-btn.is-muted .icon-muted {
  display: block;
}

/* Enhanced stop speaking button */
.stop-speak-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 10px 20px;
  border-radius: var(--radius-pill);
  background: linear-gradient(135deg, var(--voice) 0%, var(--voice-strong) 100%);
  border: none;
  color: var(--text-on-accent);
  font-family: var(--font-body);
  font-size: var(--fs-xs);
  font-weight: var(--fw-emphasis);
  cursor: pointer;
  outline: none;
  animation: stopBtnIn 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
  box-shadow: 0 4px 12px rgba(255, 181, 71, 0.3);
}

.stop-speak-btn:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 16px rgba(255, 181, 71, 0.4);
}

.stop-speak-btn:focus-visible {
  box-shadow: 0 0 0 3px var(--voice-dim), 0 4px 12px rgba(255, 181, 71, 0.3);
}

.stop-speak-icon {
  display: flex;
  width: 16px;
  height: 16px;
  flex-shrink: 0;
}

.stop-speak-icon .icon {
  width: 16px;
  height: 16px;
}

@keyframes stopBtnIn {
  from { 
    opacity: 0;
    transform: translateY(-8px);
  }
  to { 
    opacity: 1;
    transform: translateY(0);
  }
}

@media (prefers-reduced-motion: reduce) {
  .stop-speak-btn {
    animation: none;
  }
}

/* Enhanced Demo Main Area */
.demo-main {
  display: flex;
  flex-direction: column;
  gap: 20px;
  min-width: 0;
}

.demo-quick-actions {
  margin-bottom: 4px;
}

.demo-quick-actions::before {
  content: 'Try asking';
  display: block;
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  font-weight: var(--fw-emphasis);
  letter-spacing: var(--ls-wide);
  text-transform: uppercase;
  color: var(--text-faint);
  margin-bottom: 10px;
}

.chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

.chip {
  position: relative;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  font-weight: var(--fw-body);
  background: var(--bg-card);
  border: 2px solid var(--border);
  color: var(--text-muted);
  padding: 10px 16px;
  border-radius: 999px;
  cursor: pointer;
  transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
  outline: none;
  overflow: hidden;
}

.chip::before {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(135deg, var(--voice-dim) 0%, transparent 100%);
  opacity: 0;
  transition: opacity 0.25s ease;
}

.chip:hover {
  color: var(--text);
  border-color: var(--voice);
  transform: translateY(-2px);
  box-shadow: 0 4px 12px rgba(255, 181, 71, 0.2);
}

.chip:hover::before {
  opacity: 0.5;
}

.chip:focus-visible {
  border-color: var(--voice);
  box-shadow: 0 0 0 3px var(--voice-dim);
}

.chip:active {
  transform: translateY(0);
}

/* Enhanced Transcript Container */
.demo-transcript-container {
  position: relative;
}

.transcript {
  position: relative;
  background:
    radial-gradient(ellipse 90% 40% at 50% 0%, rgba(255, 181, 71, 0.05), transparent 65%),
    var(--bg-card);
  border: 2px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 24px;
  min-height: 320px;
  max-height: 480px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 18px;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04);
  transition: border-color 0.25s ease, box-shadow 0.25s ease;
}

.transcript:focus-within {
  border-color: var(--accent-strong);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04), 0 0 0 3px var(--accent-soft);
}

/* Chat bubbles — each .t-line is a column (label above bubble); .who
   carries a colored dot so user/AI turns are distinguishable at a glance
   even with color-blindness (the label text is the accessible fallback),
   .txt is the actual bubble surface. */
.t-line {
  max-width: 82%;
  display: flex;
  flex-direction: column;
  gap: 5px;
  position: relative;
}

.t-line .who {
  font-family: var(--font-mono);
  font-size: var(--fs-3xs);
  font-weight: var(--fw-strong);
  letter-spacing: var(--ls-wide);
  text-transform: uppercase;
  color: var(--text-faint);
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 0 2px;
}

.t-line .who::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--text-faint);
  flex-shrink: 0;
}

.t-line .txt {
  display: block;
  overflow-wrap: anywhere; /* a long URL/ticker list must not widen the bubble */
  padding: 13px 17px;
  border-radius: 18px;
  line-height: 1.5;
}

.t-line.user { align-self: flex-end; align-items: flex-end; }
.t-line.user .who { color: var(--accent-strong); flex-direction: row-reverse; }
.t-line.user .who::before { background: var(--accent-strong); box-shadow: 0 0 6px var(--accent-glow); }
.t-line.user .txt {
  font-family: var(--font-body); font-weight: var(--fw-emphasis); font-size: var(--fs-body);
  color: var(--text-on-accent);
  background: linear-gradient(135deg, var(--accent-strong), var(--accent-dim));
  border-bottom-right-radius: 5px;
  box-shadow: 0 6px 16px rgba(155, 107, 255, 0.25);
}

.t-line.ai { align-self: flex-start; align-items: flex-start; }
.t-line.ai .who { color: var(--voice); }
.t-line.ai .who::before { background: var(--voice); box-shadow: 0 0 6px var(--voice-glow); }
.t-line.ai .txt {
  font-family: var(--font-display); font-weight: var(--fw-emphasis); font-size: var(--fs-lg); line-height: 1.4;
  color: var(--text);
  background: var(--bg-elevated);
  border: 1px solid var(--border-hair);
  border-bottom-left-radius: 5px;
  box-shadow: 0 6px 16px rgba(4, 2, 18, 0.3);
}
.t-line.ai .txt .locked-tag {
  font-family: var(--font-mono); font-size: var(--fs-3xs); color: var(--ecosystem-elite); border: 1px solid rgba(245, 158, 11, 0.4);
  border-radius: 999px; padding: 2px 8px; margin-left: 8px; vertical-align: middle; text-transform: uppercase;
}

/* Compliance disclaimer (compliance_notice) — deliberately NOT styled like
   .t-line.ai/.user: this isn't part of the conversation, it's a fixed,
   code-enforced legal notice, and should read as a quiet automated aside,
   not something either party said. Centered, small, mono, bounded by
   dashed rules top/bottom so it visually separates itself from the
   conversation flow above and below it without needing a heavier card
   treatment (unlike .preview-limit-card, this repeats every few minutes —
   it needs to stay unobtrusive, not keep demanding attention). */
.t-line.system {
  align-self: center; text-align: center; max-width: 86%;
  padding: 10px 4px; border-top: 1px dashed var(--border); border-bottom: 1px dashed var(--border);
}
.t-line.system .who { color: var(--text-faint); }
.t-line.system .txt {
  display: block; font-family: var(--font-mono); font-size: var(--fs-label); line-height: 1.6; color: var(--text-faint);
}
.t-empty {
  margin: auto; text-align: center; max-width: 340px;
  display: flex; flex-direction: column; align-items: center; gap: 6px;
}
.t-empty-icon {
  width: 56px; height: 56px; margin-bottom: 8px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: radial-gradient(circle at 35% 30%, var(--voice-dim), transparent 70%), var(--bg-elevated);
  border: 1px solid var(--border);
  animation: tEmptyPulse 3s var(--ease-in-out) infinite;
}
.t-empty-icon .icon { width: 24px; height: 24px; color: var(--voice); }
.t-empty strong { font-family: var(--font-display); font-weight: var(--fw-strong); font-size: var(--fs-md); color: var(--text-muted); }
.t-empty span { color: var(--text-faint); font-size: var(--fs-body-sm); line-height: 1.55; }
@keyframes tEmptyPulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(255, 181, 71, 0.12); }
  50% { box-shadow: 0 0 0 8px rgba(255, 181, 71, 0); }
}
@media (prefers-reduced-motion: reduce) { .t-empty-icon { animation: none; } }

/* Preview-limit-reached upgrade card — deliberately NOT a plain .t-line
   error bubble (a "⚠" chat message reads as a bug/system failure, not the
   expected end of a free trial). A self-contained card instead: warm
   gradient (brand voice/accent, not --data-down red — this isn't a
   failure), a clear headline, and a direct CTA to the tier comparison
   further down the same page. */
.preview-limit-card {
  display: flex; gap: 16px; align-items: flex-start; align-self: center; width: 100%;
  background: linear-gradient(135deg, var(--voice-dim), var(--accent-soft));
  border: 1px solid rgba(255, 181, 71, 0.35); border-radius: var(--radius-md);
  padding: 22px 24px; animation: stopBtnIn var(--dur-3) var(--ease-out);
}
/* Icon above the text on phones — beside it, the copy got an ~84–180px
   column and wrapped a word or two per line. */
@media (max-width: 480px) { .preview-limit-card { flex-direction: column; padding: var(--sp-4); gap: var(--sp-3); } }
.preview-limit-icon {
  width: 42px; height: 42px; border-radius: 12px; flex-shrink: 0;
  background: var(--bg-card); border: 1px solid rgba(255, 181, 71, 0.4); color: var(--voice);
  display: flex; align-items: center; justify-content: center;
}
.preview-limit-icon .icon { width: 20px; height: 20px; }
.preview-limit-body { min-width: 0; }
.preview-limit-title { font-family: var(--font-display); font-weight: var(--fw-strong); font-size: var(--fs-h4); color: var(--text); margin: 2px 0 6px; }
.preview-limit-text { font-family: var(--font-body); font-size: var(--fs-sm); line-height: 1.55; color: var(--text-muted); margin: 0 0 16px; }
.preview-limit-actions { display: flex; gap: 10px; flex-wrap: wrap; }
@media (prefers-reduced-motion: reduce) { .preview-limit-card { animation: none; } }

/* ===== Product tour (#tour, 2026-09-23) =====
   A video-like player: four animated scenes narrated by Vox (tour.js,
   script in apps/marketing/tour.py). Every visual that reacts to a spoken
   word starts hidden and gains .is-on when tour.js fires its [data-cue];
   the scene root also gains .cue-<name> for "swap A for B" effects. */

.tour-player { max-width: 1080px; margin: 0 auto; container: tour / inline-size; }

.tour-stage {
  position: relative; aspect-ratio: 16 / 9; overflow: hidden;
  border-radius: var(--radius-xl); border: 1px solid var(--border);
  background: radial-gradient(120% 90% at 20% 10%, var(--bg-elevated), var(--bg-card) 60%, var(--bg-sunken));
  box-shadow: var(--shadow-lift);
}
.tour-tag {
  position: absolute; top: var(--sp-4); right: var(--sp-5); z-index: 2;
  font-family: var(--font-mono); font-size: var(--fs-3xs); letter-spacing: var(--ls-wide);
  text-transform: uppercase; color: var(--text-faint);
}

.tour-scene {
  position: absolute; inset: var(--sp-6) var(--sp-7);
  display: grid; align-items: center; gap: var(--sp-6);
  animation: tourSceneIn var(--dur-3) var(--ease-out);
}
@keyframes tourSceneIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }

/* Everything a cue reveals: hidden until its word is spoken. */
.tour-stage [data-cue] { opacity: 0; transform: translateY(8px); transition: opacity var(--dur-3) var(--ease-out), transform var(--dur-3) var(--ease-out); }
.tour-stage [data-cue].is-on { opacity: 1; transform: none; }

/* Vox's face in every scene: the SAME orb the live demo uses (.orb-wrap /
   .orb / .waveform, shared), so the tour looks and moves like the real thing.
   tour.js flips data-state to "speaking" and lights the waveform on every word
   Vox says, exactly as voice-live.js does for a live answer. Only the size is
   tour-specific. */
.orb-wrap.tour-voice--sm { width: 64px; height: 64px; } /* same box as the Finn/TradingView badges, so the links line up; the ring overflows it */
.tour-voice--sm .orb { width: 60px; height: 60px; border-width: 1px; }
.tour-voice--sm .orb-ring { inset: -8px; }
.tour-voice--sm .waveform { transform: scale(0.55); }
/* Finn and TradingView sit in the same round badge as Vox, so the three read
   as one route. Finn's mark is the EZPZ logo its desktop app uses. */
.tour-logo {
  display: grid; place-items: center; width: 64px; height: 64px; border-radius: 50%; overflow: hidden;
  background: var(--bg-sunken); border: 1px solid var(--border-voice); box-shadow: var(--shadow-glow-voice);
}
.tour-logo img { display: block; width: 100%; height: 100%; object-fit: cover; }
.tour-logo--finn { background: var(--text-on-accent); } /* the EZPZ mark is drawn on black */
.tour-logo--tv { border-color: var(--border-strong); box-shadow: var(--shadow-card); color: var(--text); } /* TradingView's mark is monochrome */
.tour-logo--tv .icon { width: 30px; height: 30px; }

/* Scene 1 — just ask */
.tour-scene--ask { grid-template-columns: 1fr 1.25fr; }
.tour-ask-voice { display: flex; flex-direction: column; align-items: center; gap: var(--sp-5); }
.tour-bubble {
  margin: 0; padding: var(--sp-3) var(--sp-4); border-radius: var(--radius-lg);
  background: var(--accent-soft); border: 1px solid var(--border-accent);
  font-size: var(--fs-sm); font-weight: var(--fw-emphasis); color: var(--text);
}
.tour-cards { display: grid; gap: var(--sp-3); }
.tour-card {
  display: grid; grid-template-columns: 1fr auto; gap: 2px var(--sp-4); align-items: center;
  padding: var(--sp-3) var(--sp-4); border-radius: var(--radius-md);
  background: var(--bg-glass); border: 1px solid var(--border); border-left: 3px solid var(--border-strong);
}
.tour-card--accent { border-left-color: var(--accent); }
.tour-card--data { border-left-color: var(--data); }
.tour-card-kicker { grid-column: 1 / -1; font-family: var(--font-mono); font-size: var(--fs-2xs); letter-spacing: var(--ls-wide); color: var(--text-faint); text-transform: uppercase; }
.tour-card-value { font-family: var(--font-display); font-weight: var(--fw-strong); font-size: var(--fs-h4); color: var(--text); }
.tour-card-note { font-size: var(--fs-xs); color: var(--text-muted); }
.tour-bars { grid-column: 2; grid-row: 2 / 4; display: flex; align-items: flex-end; gap: 3px; height: 28px; }
.tour-bars i { width: 5px; border-radius: 2px; background: var(--accent); transform-origin: bottom; transform: scaleY(0.15); transition: transform var(--dur-4) var(--ease-out); }
.tour-bars i:nth-child(1) { height: 30%; } .tour-bars i:nth-child(2) { height: 55%; } .tour-bars i:nth-child(3) { height: 40%; }
.tour-bars i:nth-child(4) { height: 75%; } .tour-bars i:nth-child(5) { height: 60%; } .tour-bars i:nth-child(6) { height: 100%; }
.tour-card.is-on .tour-bars i { transform: scaleY(1); }
.tour-meter { grid-column: 2; grid-row: 2; width: 88px; height: 6px; border-radius: var(--radius-pill); background: var(--border); overflow: hidden; }
.tour-meter i { display: block; width: 72%; height: 100%; background: var(--data); transform-origin: left; transform: scaleX(0); transition: transform var(--dur-4) var(--ease-out); }
.tour-card.is-on .tour-meter i { transform: scaleX(1); }
.tour-source {
  justify-self: start; padding: var(--sp-1) var(--sp-3); border-radius: var(--radius-pill);
  border: 1px solid var(--border-voice); background: var(--voice-dim); color: var(--voice);
  font-family: var(--font-mono); font-size: var(--fs-2xs); letter-spacing: var(--ls-wide); text-transform: uppercase;
}

/* Windows: the site's chart (scene 2) and TradingView Desktop (scene 3). */
.tour-window { border-radius: var(--radius-lg); border: 1px solid var(--border); background: var(--bg-sunken); overflow: hidden; box-shadow: var(--shadow-card); }
.tour-window-bar { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-2) var(--sp-3); border-bottom: 1px solid var(--border-hair); }
.tour-dots { display: inline-flex; gap: 5px; }
.tour-dots i { width: 8px; height: 8px; border-radius: 50%; background: var(--border-strong); }
.tour-window-title { font-family: var(--font-mono); font-size: var(--fs-2xs); color: var(--text-faint); }
.tour-chart { position: relative; padding: var(--sp-3) var(--sp-4) var(--sp-4); }
.tour-chart-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--sp-2); }
.tour-sym { position: relative; display: inline-grid; font-family: var(--font-mono); font-size: var(--fs-sm); font-weight: var(--fw-strong); color: var(--text); }
.tour-sym > span { grid-area: 1 / 1; }
.tour-stage .tour-sym-to[data-cue]:not(.is-on) { transform: translateY(-8px); } /* the new ticker drops in from above */
.tour-scene.cue-symbol .tour-sym-from,
.tour-scene.cue-tv-symbol .tour-sym-from { opacity: 0; transition: opacity var(--dur-2); }
.tour-chip { padding: 2px var(--sp-2); border-radius: var(--radius-pill); border: 1px solid var(--border-accent); background: var(--accent-soft); color: var(--accent-strong); font-family: var(--font-mono); font-size: var(--fs-2xs); }
.tour-chip--voice { border-color: var(--border-voice); background: var(--voice-dim); color: var(--voice); }
.tour-candles { display: block; width: 100%; height: 190px; }
.tour-body.is-up { fill: var(--data); } .tour-body.is-down { fill: var(--data-down); }
.tour-wick.is-up { stroke: var(--data); } .tour-wick.is-down { stroke: var(--data-down); }
.tour-wick { stroke-width: 1; }
.tour-series--from, .tour-series--to { transition: opacity var(--dur-3); }
.tour-scene.cue-symbol .tour-series--from,
.tour-scene.cue-tv-symbol .tour-series--from { opacity: 0; }
.tour-stage .tour-series[data-cue] { transform: none; }
/* Lines draw themselves in rather than fading. */
.tour-level, .tour-ema, .tour-trend { fill: none; stroke-width: 2; stroke-dasharray: 600; stroke-dashoffset: 600; }
.tour-level { stroke: var(--voice); }
.tour-ema { stroke: var(--voice); stroke-width: 1.5; }
.tour-trend { stroke: var(--accent-strong); }
.tour-stage .tour-level.is-on, .tour-stage .tour-ema.is-on, .tour-stage .tour-trend.is-on { stroke-dashoffset: 0; transition: stroke-dashoffset 1.2s var(--ease-out), opacity var(--dur-2); }
.tour-level-label { position: absolute; right: var(--sp-4); top: var(--sp-7); font-family: var(--font-mono); font-size: var(--fs-2xs); color: var(--voice); }
.tour-rsi { display: block; width: 100%; height: 36px; margin-top: var(--sp-2); border-top: 1px solid var(--border-hair); }
.tour-rsi-band { stroke: var(--border); stroke-dasharray: 3 4; }
.tour-rsi-line { fill: none; stroke: var(--accent-strong); stroke-width: 1.5; }

/* Scene 2 — it drives your chart */
.tour-scene--chart { grid-template-columns: minmax(0, 760px); justify-content: center; }

/* Scene 3 — your TradingView, by voice */
/* Vox -> Finn -> the window, left to right: the last link leads into the chart. */
.tour-scene--finn { grid-template-columns: auto minmax(0, 1fr); column-gap: var(--sp-1); }
.tour-route { display: flex; align-items: center; gap: var(--sp-2); }
.tour-node { display: flex; flex-direction: column; align-items: center; gap: var(--sp-1); }
.tour-node--finn { gap: var(--sp-2); }
.tour-node-label { font-family: var(--font-mono); font-size: var(--fs-2xs); color: var(--text-faint); letter-spacing: var(--ls-wide); text-transform: uppercase; }
/* Lifted by the margin so the line meets the logos, not their labels. */
.tour-link {
  display: block; width: 44px; height: 2px; margin-bottom: var(--sp-5);
  background: linear-gradient(90deg, var(--accent), var(--voice)); border-radius: var(--radius-pill);
}
.tour-toast {
  position: absolute; right: var(--sp-4); bottom: var(--sp-4); display: inline-flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3); border-radius: var(--radius-md); background: var(--bg-elevated); border: 1px solid var(--border-voice);
  font-size: var(--fs-xs); color: var(--text);
}
.tour-toast .icon { width: 14px; height: 14px; color: var(--voice); }
.tour-window--tv { min-width: 0; } /* lets the window shrink inside the scene grid */
.tour-real { display: block; width: 100%; }
.tour-badge {
  position: absolute; left: 50%; bottom: calc(-1 * var(--sp-4)); translate: -50% 0;
  padding: var(--sp-1) var(--sp-4); border-radius: var(--radius-pill); background: var(--voice-dim); border: 1px solid var(--border-voice);
  color: var(--voice); font-family: var(--font-mono); font-size: var(--fs-2xs); letter-spacing: var(--ls-wide); text-transform: uppercase; white-space: nowrap;
}

/* Scene 4 — how you get it (prices rendered live from MembershipTier) */
.tour-scene--plans { grid-template-columns: 1fr; justify-items: center; align-content: center; }
.tour-plans { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-4); width: min(100%, 720px); }
.tour-plan { display: flex; flex-direction: column; gap: var(--sp-2); padding: var(--sp-5); border-radius: var(--radius-lg); background: var(--bg-glass); border: 1px solid var(--border); }
.tour-stage .tour-plan[data-cue].is-on { border-color: var(--border-accent); box-shadow: var(--shadow-card); }
.tour-stage .tour-plan--bundle[data-cue].is-on { border-color: var(--border-voice); }
.tour-plan-kicker { font-family: var(--font-mono); font-size: var(--fs-2xs); letter-spacing: var(--ls-wide); text-transform: uppercase; color: var(--text-faint); }
.tour-plan-title { font-family: var(--font-display); font-weight: var(--fw-strong); font-size: var(--fs-h4); letter-spacing: var(--ls-tight); color: var(--text); }
.tour-try { margin-top: var(--sp-5); }
.tour-plan-price { font-family: var(--font-mono); font-size: var(--fs-sm); letter-spacing: var(--ls-normal); color: var(--voice); }

/* Overlays: reduced-motion start, "tap for sound", the end card. */
.tour-start, .tour-sound-hint {
  position: absolute; z-index: 3; display: inline-flex; align-items: center; gap: var(--sp-2);
  border-radius: var(--radius-pill); cursor: pointer; font-family: var(--font-body); font-weight: var(--fw-strong);
}
.tour-start { position: static; padding: var(--sp-3) var(--sp-5); border: 0; background: linear-gradient(135deg, var(--voice), var(--voice-light)); color: var(--text-on-accent); font-size: var(--fs-sm); }

/* The cover: the stage's first frame, before the tour plays. */
.tour-cover {
  position: absolute; inset: 0; z-index: 3; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--sp-5); padding: var(--sp-6); text-align: center;
  background: radial-gradient(90% 70% at 50% 40%, var(--bg-elevated), var(--bg-sunken));
}
.tour-cover-route { display: flex; align-items: center; gap: var(--sp-4); }
.tour-cover-node { display: flex; flex-direction: column; align-items: center; gap: var(--sp-2); }
.tour-cover-link {
  display: block; width: 64px; height: 2px; margin-bottom: var(--sp-5); border-radius: var(--radius-pill);
  background: linear-gradient(90deg, var(--accent), var(--voice));
}
.tour-cover-title {
  margin: 0; max-width: 560px; font-family: var(--font-display); font-weight: var(--fw-display);
  font-size: var(--fs-h3); letter-spacing: var(--ls-tight-lg); color: var(--text);
}
.tour-sound-hint { right: var(--sp-4); bottom: var(--sp-4); padding: var(--sp-2) var(--sp-4); border: 1px solid var(--border-voice); background: var(--bg-overlay); color: var(--voice); font-size: var(--fs-xs); }
.tour-start .icon, .tour-sound-hint .icon { width: 16px; height: 16px; }
.tour-sound-hint:hover { border-color: var(--voice); }
.tour-end { position: absolute; inset: 0; z-index: 4; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--sp-4); background: var(--bg-overlay); }
.tour-end-title { margin: 0; font-family: var(--font-display); font-weight: var(--fw-display); font-size: var(--fs-h3); letter-spacing: var(--ls-tight-lg); color: var(--text); }

/* Captions: karaoke-style — dim until spoken, gold on the word being said. */
/* Vox's spoken words: same voice as .t-line.ai .txt / .hero-qa-a (display font, --text). */
.tour-caption {
  min-height: 2.9em; margin: var(--sp-4) auto 0; max-width: 820px; text-align: center;
  font-family: var(--font-display); font-weight: var(--fw-emphasis); font-size: var(--fs-lead); line-height: 1.45; letter-spacing: var(--ls-tight);
}
.tour-word { color: var(--text-muted); transition: color var(--dur-1); }
.tour-word.is-spoken { color: var(--text); }
.tour-word.is-now { color: var(--voice); }

/* Controls */
.tour-controls { display: flex; align-items: center; gap: var(--sp-4); margin-top: var(--sp-4); }
.tour-btn { flex: none; width: 40px; height: 40px; display: inline-grid; place-items: center; border-radius: 50%; border: 1px solid var(--border); background: var(--bg-card); color: var(--text); cursor: pointer; }
.tour-btn:hover { border-color: var(--border-strong); }
.tour-btn .icon { width: 16px; height: 16px; }
.tour-player.is-playing .icon-play, .tour-player:not(.is-playing) .icon-pause { display: none; }
.tour-player.has-sound .icon-muted, .tour-player:not(.has-sound) .icon-sound { display: none; }
.tour-chapters { flex: 1; display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--sp-3); }
.tour-chapter { display: flex; flex-direction: column; justify-content: center; gap: var(--sp-2); min-height: 32px; padding: 0; border: 0; background: none; cursor: pointer; text-align: left; } /* a real tap target, even when the label is hidden on mobile */
.tour-chapter-track { display: block; height: 3px; border-radius: var(--radius-pill); background: var(--border); overflow: hidden; }
.tour-chapter-fill { display: block; height: 100%; background: var(--voice); transform-origin: left; transform: scaleX(0); }
.tour-chapter-label { font-family: var(--font-mono); font-size: var(--fs-2xs); letter-spacing: var(--ls-wide); text-transform: uppercase; color: var(--text-faint); }
.tour-chapter.is-current .tour-chapter-label, .tour-chapter:hover .tour-chapter-label { color: var(--text); }
.tour-chapter:focus-visible, .tour-btn:focus-visible { outline: 2px solid var(--voice); outline-offset: 3px; }

/* Narrow players (phones, small tablets, and the hero's right column on
   desktop): a compact layout of its own, not the desktop stage squeezed.
   A container query on the player's own width, not the viewport, so it holds
   wherever the player sits; 812px = the old 860px viewport breakpoint minus
   the container's 24px gutters. Scenes start below the illustration tag (which moves to the
   left, clear of the orb), the "Just ask" orb sits beside its question rather
   above it, and the cards tighten so each scene fits a 375px frame without
   dead space. */
@container tour (max-width: 812px) {
  .tour-stage { aspect-ratio: auto; min-height: 500px; }
  .tour-tag { right: auto; left: var(--sp-4); top: var(--sp-3); }
  .tour-scene { inset: var(--sp-7) var(--sp-4) var(--sp-6); gap: var(--sp-4); }
  .tour-scene--ask, .tour-scene--finn { grid-template-columns: 1fr; align-content: center; }
  .tour-ask-voice { flex-direction: row; justify-content: center; gap: var(--sp-4); }
  .orb-wrap.tour-voice:not(.tour-voice--sm) { width: 64px; height: 64px; flex: none; }
  .tour-voice:not(.tour-voice--sm) .orb { width: 60px; height: 60px; border-width: 1px; }
  .tour-voice:not(.tour-voice--sm) .orb-ring { inset: -8px; }
  .tour-voice:not(.tour-voice--sm) .waveform { transform: scale(0.55); }
  .tour-bubble { font-size: var(--fs-xs); padding: var(--sp-2) var(--sp-3); }
  .tour-cards { gap: var(--sp-2); }
  .tour-card { padding: var(--sp-2) var(--sp-3); }
  .tour-card-value { font-size: var(--fs-md); }
  .tour-bars { height: 22px; }
  .tour-source { justify-self: center; }
  .tour-plan { padding: var(--sp-4); }
  .tour-plan-title { font-size: var(--fs-md); }
  .tour-cover .tour-logo { width: 56px; height: 56px; }
  .tour-cover-link { width: 28px; }
  .tour-cover-title { font-size: var(--fs-h4); }
  .tour-route { justify-content: center; }
  .tour-link { width: 32px; }
  .tour-route .tour-link:last-child { display: none; } /* the window sits below here, not beside */
  .tour-candles { height: 130px; }
  .tour-plans { grid-template-columns: 1fr; gap: var(--sp-3); }
  .tour-try { margin-top: var(--sp-3); }
  .tour-chapter-label { display: none; }
  .tour-caption { font-size: var(--fs-sm); }
}
@media (prefers-reduced-motion: reduce) {
  .tour-scene, .tour-stage [data-cue], .tour-bars i, .tour-meter i, .tour-word { animation: none; transition: none; }
  .tour-level, .tour-ema, .tour-trend { stroke-dashoffset: 0; }
}

/* ===== Live demo: the first impression (2026-09-23) =====
   The no-account "Talk to Vox" demo (apps/voice_sessions/demo.py). What a
   visitor sees is driven by body[data-audience], set by demo-experience.js:
   "visitor" (no account), "free" (signed in, no package), "member" (package).
   The .preview-limit-card above doubles as the demo's end card. */

/* The promise, stated before they click: time, no account, delayed data. */
.demo-offer {
  list-style: none; margin: calc(-1 * var(--sp-4)) auto var(--sp-6); padding: 0;
  display: flex; flex-wrap: wrap; justify-content: center; gap: var(--sp-2) var(--sp-5);
}
.demo-offer-item {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  font-family: var(--font-mono); font-size: var(--fs-2xs); letter-spacing: var(--ls-wide);
  text-transform: uppercase; color: var(--text-faint);
}
.demo-offer-item .icon { width: 14px; height: 14px; color: var(--voice); }

/* Countdown under the orb. Scale transform, not width, so it never reflows. */
.demo-timer { display: flex; flex-direction: column; align-items: center; gap: var(--sp-1); margin-top: var(--sp-2); }
.demo-timer-label {
  font-family: var(--font-mono); font-size: var(--fs-2xs); letter-spacing: var(--ls-normal);
  font-variant-numeric: tabular-nums; color: var(--text-faint);
}
.demo-timer-track { width: 120px; height: 3px; border-radius: var(--radius-pill); background: var(--border); overflow: hidden; }
.demo-timer-fill {
  display: block; width: 100%; height: 100%; background: var(--voice);
  transform-origin: left center; transition: transform var(--dur-2) linear;
}
.demo-timer.is-ending .demo-timer-label { color: var(--voice); }
@media (prefers-reduced-motion: reduce) { .demo-timer-fill { transition: none; } }

/* Where Turnstile appears — only if Cloudflare ever needs a click. */
.demo-turnstile:empty { display: none; }
.demo-turnstile { margin-top: var(--sp-3); display: flex; justify-content: center; }

/* What Vox is doing right now ("Putting NVDA on the chart…"). Quieter than a
   spoken line: it narrates, it doesn't talk. */
.t-activity {
  display: flex; align-items: center; gap: var(--sp-2); margin: var(--sp-1) 0 var(--sp-2);
  font-family: var(--font-mono); font-size: var(--fs-2xs); letter-spacing: var(--ls-normal); color: var(--text-faint);
  animation: tActivityIn var(--dur-2) var(--ease-out);
}
.t-activity-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--data); box-shadow: 0 0 6px var(--data); flex: none; }
@keyframes tActivityIn { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .t-activity { animation: none; } }

/* One clear action for a visitor: "Talk to Vox" (the same .mic-btn every tier
   uses — no special styling, so it matches Pro and Studio), no hold-to-talk to
   learn. The tier tabs stay visible: Pro and
   Studio carry a lock for visitors and free members, and tapping one explains
   what a plan unlocks (demo-experience.js). */
/* The demo's guest start (Turnstile + POST) is running: say so on the button. */
#startConvoBtn.is-connecting { cursor: progress; opacity: 0.72; }
.mode-tab-lock { display: none; margin-left: var(--sp-1); color: var(--text-faint); }
.mode-tab-lock .icon { width: 12px; height: 12px; }
body[data-audience="visitor"] .mode-tab-lock,
body[data-audience="free"] .mode-tab-lock { display: inline-flex; }
body[data-audience="visitor"] #micBtn,
body[data-audience="member"] .demo-offer { display: none; }

/* Settings are shown to everyone (2026-09-24 — they used to be hidden from
   visitors). A visitor or free member uses what the free preview offers and
   sees what a plan adds, locked (#planSettings), instead of not seeing it at
   all; a member with a package has the real controls and never sees it. The
   Integration sign-up card replaces the Finn/EZPZ rows a visitor can't use. */
body[data-audience="member"] .settings-section--locked,
body:not([data-audience="visitor"]) .settings-signup-card { display: none; }
.setting-plan-badge {
  display: inline-flex; align-items: center; gap: 4px; margin-left: auto; flex-shrink: 0;
  font-family: var(--font-mono); font-size: var(--fs-3xs); font-weight: var(--fw-emphasis);
  letter-spacing: var(--ls-wide); text-transform: uppercase;
  color: var(--voice); background: var(--voice-dim); border: 1px solid var(--border-voice);
  border-radius: var(--radius-pill); padding: 2px 8px;
}
.setting-plan-badge .icon { width: 10px; height: 10px; }
.setting-note { font-size: var(--fs-label); color: var(--text-faint); margin: 0; line-height: 1.4; }
.settings-section-foot { font-size: var(--fs-sm); color: var(--text-muted); margin: var(--sp-3) 0 0; }
.settings-section-foot a { color: var(--voice); font-weight: var(--fw-emphasis); }
.settings-section-foot a:hover { text-decoration: underline; }

/* Suggested prompts: the demo set works with no EZPZ account; members get
   the full set. */
body:not([data-audience="member"]) .chip[data-audience="member"],
body[data-audience="member"] .chip[data-audience="demo"] { display: none; }

.demo-input-area {
  position: relative;
}

/* Pill-shaped composer — input and send button share one bordered
   surface (like a modern chat app's message bar) instead of two
   separately-boxed controls, so focus reads as "this whole bar is
   active" rather than just the input. */
.ask-row {
  display: flex;
  gap: 8px;
  align-items: center;
  background: var(--bg-card);
  border: 2px solid var(--border);
  border-radius: var(--radius-pill);
  padding: 6px 6px 6px 22px;
  transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}

.ask-row:focus-within {
  border-color: var(--accent-strong);
  box-shadow: 0 0 0 3px var(--accent-soft);
  background: var(--bg-sunken);
}

.ask-row input {
  flex: 1;
  min-width: 0;
  background: transparent;
  border: none;
  color: var(--text);
  padding: 13px 0;
  font-size: var(--fs-sm);
  font-family: var(--font-body);
  font-weight: var(--fw-body);
  outline: none;
}

.ask-row input::placeholder {
  color: var(--text-faint);
  transition: opacity 0.25s ease;
}

.ask-row:focus-within input::placeholder {
  opacity: 0.6;
}

.ask-row button {
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  height: 44px;
  padding: 0 22px;
  border-radius: var(--radius-pill);
  font-size: var(--fs-sm);
  font-weight: var(--fw-strong);
}

.disclaimer { font-size: var(--fs-label); color: var(--text-faint); padding-top: 4px; }
.demo-disclaimer { max-width: 52rem; margin: 20px auto 0; text-align: center; }

/* ===== Settings panel v3 (redesigned 2026-09-01) =====
   A sectioned system, not a loose strip of same-sized fields: an outer
   panel (.settings-strip, the one real bordered card) containing themed
   .settings-section groups (Voice behavior / Voice & mode / Integration),
   each a small mono eyebrow + a .settings-grid of .setting-card tiles.
   Surface levels stay deliberately subtle — page bg → panel (bg-card) →
   card (a faint tint + hairline, not a second heavy border) — so nesting
   never reads as "a card inside a card". Every control (pill-group, select)
   is styled to fill its card's full width; combined with .settings-grid's
   auto-fit (not fixed-count) columns, a group can never be wider than its
   own column, so there's no fixed width to miscalculate and overflow. */
.settings-strip {
  display: flex; flex-direction: column; gap: var(--sp-5);
  background: var(--bg-card); border: 1px solid var(--border);
  border-radius: var(--radius-lg); padding: var(--sp-6);
}
.settings-strip-head { display: flex; flex-direction: column; gap: 3px; }
.settings-strip-head h3 {
  font-family: var(--font-display); font-weight: var(--fw-strong); font-size: var(--fs-md);
  color: var(--text); margin: 0; letter-spacing: var(--ls-tight);
}
.settings-strip-head p { font-size: var(--fs-sm); color: var(--text-faint); margin: 0; }

.settings-section { display: flex; flex-direction: column; gap: var(--sp-3); }
.settings-section + .settings-section { padding-top: var(--sp-5); border-top: 1px solid var(--border-hair); }
.settings-section-head {
  display: flex; align-items: center; justify-content: space-between; gap: 7px;
}
.settings-section-label {
  display: flex; align-items: center; gap: 8px;
  font-family: var(--font-mono); font-size: var(--fs-2xs); font-weight: var(--fw-emphasis); letter-spacing: var(--ls-wide);
  text-transform: uppercase; color: var(--text-faint);
}
.settings-section-icon-circle {
  width: 22px; height: 22px; border-radius: 7px; flex-shrink: 0;
  background: var(--accent-soft); color: var(--accent-strong);
  display: inline-flex; align-items: center; justify-content: center;
}
.settings-section-icon-circle .icon { width: 12px; height: 12px; }
.settings-section-toggle {
  flex-shrink: 0; width: 24px; height: 24px; border-radius: 7px;
  border: none; background: transparent; padding: 0;
  display: flex; align-items: center; justify-content: center;
  cursor: pointer; color: var(--text-faint);
  transition: background var(--dur-1) ease, color var(--dur-1) ease;
}
.settings-section-toggle:hover { background: rgba(243, 240, 255, 0.07); color: var(--text); }
.settings-section-toggle .icon { width: 14px; height: 14px; transition: transform 0.25s ease; }
.settings-section.is-collapsed .settings-section-toggle .icon { transform: rotate(-90deg); }

/* Animate collapse: grid-template-rows trick (no JS height measurement needed) */
.settings-section-body {
  display: grid; grid-template-rows: 1fr;
  transition: grid-template-rows 0.28s ease, opacity 0.22s ease;
  opacity: 1;
}
.settings-section-body > * { min-height: 0; overflow: hidden; }
.settings-section.is-collapsed .settings-section-body {
  grid-template-rows: 0fr; opacity: 0; pointer-events: none;
}

/* auto-fit + a real minmax (not a hardcoded 2-up) — column count follows
   whatever width .demo-main actually has, per tier's visible card count,
   without a breakpoint table to keep in sync. */
.settings-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(230px, 100%), 1fr)); gap: var(--sp-4); }

.setting-card {
  display: flex; flex-direction: column; gap: 12px; min-width: 0;
  background: rgba(255, 255, 255, 0.025); border: 1px solid var(--border-hair);
  border-radius: var(--radius-md); padding: 14px var(--sp-4);
}
/* Voice style's option text ("Expressive (slower, emotional)") is the one
   value in this panel long enough to actually need the room — full row
   guarantees it, rather than hoping a 2-up column happens to be wide enough. */
.setting-card--wide { grid-column: 1 / -1; }
.setting-card-head { display: flex; align-items: center; gap: 9px; }
.setting-card-icon {
  display: flex; align-items: center; justify-content: center; flex-shrink: 0;
  width: 26px; height: 26px; border-radius: 8px;
  background: var(--accent-soft); color: var(--accent-strong); font-size: var(--fs-body-sm);
}
.setting-card-label { font-family: var(--font-body); font-weight: var(--fw-strong); font-size: var(--fs-body-sm); color: var(--text); }

/* Segmented control: an inset track (not a flat strip) so the group reads
   as one physical toggle, same "carved-in" cue macOS/iOS segmented controls
   use — .pill.active then sits "raised" out of that groove via its own
   gradient+glow, which is the whole depth illusion. flex (not inline-flex)
   + each .pill at flex:1 so the control always fills its card's full
   width at equal, balanced proportions, matching whatever column width
   .settings-grid gives it. */
.pill-group {
  display: flex; width: 100%; gap: 3px; padding: 4px; background: var(--bg-sunken);
  border: 1px solid var(--border-hair); border-radius: 11px;
  box-shadow: inset 0 1px 3px rgba(4, 2, 18, 0.5);
}
.pill {
  flex: 1; text-align: center; font-family: var(--font-body); font-size: var(--fs-label); font-weight: var(--fw-emphasis);
  padding: 9px 8px; border-radius: 8px;
  border: 1px solid transparent; background: transparent; color: var(--text-muted); cursor: pointer;
  transition: background var(--dur-2) var(--ease-spring), color var(--dur-1) ease, box-shadow var(--dur-2) var(--ease-spring);
}
.pill:hover:not(.locked):not(.active) { color: var(--text); background: rgba(243, 240, 255, 0.06); }
.pill.active {
  background: linear-gradient(180deg, var(--voice-strong), var(--voice));
  color: var(--text-on-accent);
  box-shadow: 0 2px 8px -2px var(--voice-glow), inset 0 1px 0 rgba(255, 255, 255, 0.3);
}
.pill.locked { opacity: 0.5; cursor: not-allowed; position: relative; }
.pill .lock { margin-left: 5px; display: inline-flex; }
.pill .lock .icon { width: 10px; height: 10px; }
.pill:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--bg-sunken), 0 0 0 4px var(--accent-strong); position: relative; z-index: 1; }

/* Vox-mode selector: two clickable cards (icon + name + one-line desc) that
   replace both the old <select> (main panel) and the old 3-pill group
   (studio beta panel) — consistent across every tier, no "Default" option. */
.mode-card-group {
  display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-3);
}
.mode-card {
  display: flex; flex-direction: column; align-items: flex-start; gap: 9px;
  padding: 14px var(--sp-4);
  background: rgba(255, 255, 255, 0.025); border: 1px solid var(--border-hair);
  border-radius: var(--radius-md); cursor: pointer; text-align: left; width: 100%;
  transition: border-color 0.15s ease, background 0.15s ease, box-shadow 0.22s ease;
}
.mode-card:hover:not(.active) {
  border-color: var(--border-strong); background: rgba(255, 255, 255, 0.04);
}
.mode-card.active {
  border-color: var(--voice); background: rgba(255, 181, 71, 0.06);
  box-shadow: 0 0 0 1px var(--voice), 0 4px 20px -4px rgba(255, 181, 71, 0.28);
}
.mode-card:focus-visible {
  outline: none; box-shadow: 0 0 0 2px var(--bg-sunken), 0 0 0 4px var(--voice);
}
.mode-card-icon {
  width: 30px; height: 30px; border-radius: 8px; flex-shrink: 0;
  background: var(--accent-soft); color: var(--accent-strong);
  display: flex; align-items: center; justify-content: center;
  transition: background 0.15s ease, color 0.15s ease;
}
.mode-card.active .mode-card-icon { background: var(--voice-dim); color: var(--voice); }
.mode-card-icon .icon { width: 15px; height: 15px; }
.mode-card-name {
  font-family: var(--font-body); font-weight: var(--fw-strong); font-size: var(--fs-xs); color: var(--text);
  line-height: 1.2;
}
.mode-card-desc {
  font-size: var(--fs-label); color: var(--text-faint); line-height: 1.45; margin: 0;
}

/* Custom chevron via background-image (not a wrapper + JS dropdown — a
   plain <select> stays keyboard/screen-reader native for free) so it
   matches the rest of the control language instead of the browser's raw
   default arrow. #9992C4 below is --text-faint's literal value — CSS custom
   properties can't be referenced inside a data-URI. radius-md (not
   radius-pill, that's .pill-group's shape) so a dropdown reads differently
   from a segmented toggle at a glance, not just on close inspection. Full
   width, same as .pill-group, for the same "fills its card" reason. */
select.voice-select {
  appearance: none; -webkit-appearance: none; -moz-appearance: none; width: 100%;
  background-color: var(--bg-sunken);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6' fill='none'%3E%3Cpath d='M1 1L5 5L9 1' stroke='%239992C4' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 14px center;
  border: 1px solid var(--border); color: var(--text); border-radius: var(--radius-md);
  padding: 10px 36px 10px 14px; font-size: var(--fs-xs); font-family: var(--font-body); cursor: pointer;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03);
  transition: border-color var(--dur-1) ease, background-color var(--dur-1) ease;
}
select.voice-select:hover { border-color: var(--border-strong); background-color: var(--bg-elevated); }
select.voice-select:focus-visible { outline: none; border-color: var(--accent-strong); box-shadow: 0 0 0 3px var(--accent-soft); }
select.voice-select option { background: var(--bg-elevated); color: var(--text); }
select.voice-select option:disabled { color: var(--text-faint); }
select.voice-select.is-picker-active { display: none; }

/* Studio-only voice picker (added 2026-08-12) — #voiceSelect (above) stays the real,
   unchanged source of truth (still populated with every voice, still what setLiveVoice()
   reads) for every tier; this is a Studio-only visual replacement for it, needed because
   a plain <select> genuinely can't do search, and Studio's 97-voice library (vs. 6-30 for
   every other tier) isn't browsable without one — the ".voice-select stays a plain native
   element for keyboard/screen-reader support" reasoning above still holds for every tier
   that doesn't need search; this only opts out where the option count makes that
   trade-off unworkable. Reuses .nav-dropdown's panel language (bg-elevated/border-strong/
   radius-lg/shadow-lift) rather than inventing a new "modern panel" look. */
.voice-picker { position: relative; }
.voice-picker-trigger {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  width: 100%; appearance: none; background-color: var(--bg-sunken);
  border: 1px solid var(--border); color: var(--text); border-radius: var(--radius-md);
  padding: 10px 14px; font-size: var(--fs-xs); font-family: var(--font-body); cursor: pointer;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03);
  transition: border-color var(--dur-1) ease, background-color var(--dur-1) ease;
}
.voice-picker-trigger:hover { border-color: var(--border-strong); background-color: var(--bg-elevated); }
.voice-picker-trigger:focus-visible { outline: none; border-color: var(--accent-strong); box-shadow: 0 0 0 3px var(--accent-soft); }
.voice-picker-trigger .caret { font-size: var(--fs-3xs); color: var(--text-faint); transition: transform var(--dur-1) ease; flex-shrink: 0; }
.voice-picker.is-open .voice-picker-trigger .caret { transform: rotate(180deg); color: var(--accent-strong); }

.voice-picker-panel {
  /* position: fixed + appended to <body> by JS (buildStudioVoicePicker), not a
     descendant of .voice-picker — a real bug found interactively (2026-08-12):
     the generic `section { position: relative }` rule means #demo and its LATER
     sibling sections (#ecosystem/#features/#tiers/#cta) share one positioned-
     stacking order; being later in DOM order, they painted ABOVE #demo's entire
     subtree regardless of z-index set on anything nested inside #demo — this
     panel's z-index: 70 only ever won fights within #demo's own stacking
     context, never against a later sibling section entirely outside it. The
     panel was visually correct but silently unclickable. Portal'd to <body>
     (no positioned ancestor at all) to sidestep that fight rather than try to
     win it — top/right are set inline by JS from the trigger's real
     getBoundingClientRect() each time it opens, not fixed CSS values, since a
     fixed-position element has nothing to auto-anchor to anymore. */
  position: fixed; width: 320px; max-width: 90vw;
  background: var(--bg-elevated); border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-lift);
  opacity: 0; visibility: hidden; pointer-events: none; transform: translateY(4px);
  transition: opacity var(--dur-2) ease, transform var(--dur-2) ease, visibility var(--dur-2);
  z-index: var(--z-dropdown);
  display: flex; flex-direction: column; max-height: 420px;
}
/* Own class, not `.voice-picker.is-open .voice-picker-panel` — that descendant
   selector stopped matching once the panel moved out of .voice-picker (above). */
.voice-picker-panel.is-open {
  opacity: 1; visibility: visible; pointer-events: auto; transform: translateY(0);
}
.voice-picker-search-wrap { padding: 12px; border-bottom: 1px solid var(--border-hair); flex-shrink: 0; }
.voice-picker-search {
  width: 100%; background: var(--bg-sunken); border: 1px solid var(--border);
  border-radius: var(--radius-md); color: var(--text); font-size: var(--fs-xs);
  font-family: var(--font-mono); padding: 8px 12px;
}
.voice-picker-search:focus-visible { outline: none; border-color: var(--accent-strong); box-shadow: 0 0 0 3px var(--accent-soft); }
/* min-height: 0 is not optional here — a real bug, caught interactively (2026-08-12):
   without it, a flex child (.voice-picker-panel is display:flex/flex-direction:column
   above) defaults to min-height:auto, meaning "never shrink below my own content's
   natural height," so overflow-y:auto never actually engaged — the list just grew past
   the panel's max-height: 420px instead of clipping/scrolling, pushing the "show more"
   button (and most of the 97-voice expanded list) below the viewport with no way to
   reach it. This is why "show more" appeared broken/unresponsive: the button wasn't
   malfunctioning, it was rendering off-screen. min-height: 0 lets this flex child
   actually respect the parent's max-height and become the scrollable region it was
   already styled to be. */
.voice-picker-list { overflow-y: auto; min-height: 0; padding: 8px; }
.voice-picker-group-label {
  font-family: var(--font-mono); font-size: var(--fs-3xs); letter-spacing: var(--ls-wide); text-transform: uppercase;
  color: var(--text-faint); padding: 10px 10px 4px;
}
.voice-picker-group-label:first-child { padding-top: 4px; }
.voice-picker-option {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  width: 100%; text-align: left; background: none; border: none; color: var(--text);
  font-size: var(--fs-body-sm); padding: 8px 10px; border-radius: var(--radius-md); cursor: pointer;
  transition: background var(--dur-1) ease;
}
.voice-picker-option:hover { background: rgba(155, 107, 255, 0.1); }
.voice-picker-option.is-selected { background: var(--accent-soft); color: var(--accent-strong); font-weight: var(--fw-emphasis); }
.voice-picker-option .check { font-size: var(--fs-label); color: var(--accent-strong); visibility: hidden; }
.voice-picker-option.is-selected .check { visibility: visible; }
.voice-picker-more-toggle {
  width: 100%; text-align: center; background: none; border: none; border-top: 1px dashed var(--border);
  color: var(--accent-strong); font-family: var(--font-mono); font-size: var(--fs-2xs); letter-spacing: var(--ls-wide);
  padding: 10px; margin-top: 6px; cursor: pointer; transition: color var(--dur-1) ease;
}
.voice-picker-more-toggle:hover { color: var(--text); }
.voice-picker-empty { padding: 20px 10px; text-align: center; color: var(--text-faint); font-size: var(--fs-xs); }

/* Integration card: Finn is a connection to another app, not a preference
   toggle like the pill/select cards above — its own full-width surface
   (not squeezed into a .settings-grid cell) with a title/status/description
   on one side and the primary action on the other reads as "a connection",
   not "one more form field". Status uses a plain inline dot+label (not the
   nav's padded/bordered .live-status pill) on purpose — a second badge
   competing with .setting-card-icon chips for attention would be exactly
   the "huge badge" this is trying to avoid. */
/* .settings-signup-card: the visitor's stand-in for these rows (home.html) — its
   own class, since finn-link.js wires every .finn-link-group it finds. */
.finn-link-group, .ezpz-link-group, .settings-signup-card {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: var(--sp-3) var(--sp-5);
  background: rgba(255, 255, 255, 0.025); border: 1px solid var(--border-hair);
  border-radius: var(--radius-md); padding: var(--sp-4) var(--sp-5);
}
.finn-link-main { display: flex; flex-direction: column; gap: 4px; min-width: 220px; flex: 1 1 260px; }
.finn-link-title-row { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.finn-link-title { font-family: var(--font-body); font-weight: var(--fw-strong); font-size: var(--fs-body-sm); color: var(--text); }
.finn-link-desc { font-size: var(--fs-label); color: var(--text-faint); margin: 0; }
.finn-status-wrap {
  display: inline-flex; align-items: center; gap: 7px;
  font-family: var(--font-mono); font-size: var(--fs-label); color: var(--text-muted);
}
.finn-link-actions { display: flex; gap: 8px; flex-shrink: 0; }
/* "Link Finn" / "Re-link" — finn-link.js swaps this label with the live status (2026-09-22). */
.finn-link-btn-label { white-space: nowrap; }
/* Full-width row of its own once shown, not squeezed beside the actions —
   the code needs to stay legible/selectable at full size. Shared by both
   the Finn and EZPZ Account link panels — same "connection card" look. */
.finn-pairing-code, .ezpz-pairing-code { flex-basis: 100%; display: flex; flex-direction: column; gap: 8px; }
.finn-pairing-hint { display: flex; align-items: center; gap: 6px; font-size: var(--fs-label); color: var(--text-faint); margin: 0; line-height: 1.4; }
.finn-pairing-hint .icon { font-size: var(--fs-xs); flex-shrink: 0; color: var(--text-faint); }
.finn-pairing-code-row { display: flex; gap: 8px; max-width: 360px; }
.finn-pairing-code-value, .ezpz-pairing-code-value {
  flex: 1; min-width: 0; display: block; font-family: var(--font-mono); font-size: var(--fs-body-sm); letter-spacing: var(--ls-wide);
  background: var(--bg-sunken); border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
  padding: 9px 12px; color: var(--text); word-break: break-all;
}
.finn-copy-btn, .ezpz-copy-btn {
  display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0;
  width: 38px; background: var(--bg-sunken); border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm); color: var(--text-muted); cursor: pointer; font-size: var(--fs-sm);
  transition: color var(--dur-1) ease, border-color var(--dur-1) ease;
}
.finn-copy-btn:hover, .ezpz-copy-btn:hover { color: var(--text); border-color: var(--accent-strong); }
.finn-copy-btn:focus-visible, .ezpz-copy-btn:focus-visible { outline: none; border-color: var(--accent-strong); box-shadow: 0 0 0 3px var(--accent-soft); }
.finn-copy-btn.is-copied, .ezpz-copy-btn.is-copied { color: var(--data); border-color: var(--data); }

/* Chart target — always-visible setting card in Voice & Mode; disabled until Finn is linked */
.chart-target-finn-badge {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: var(--fs-3xs);
  font-weight: var(--fw-emphasis);
  letter-spacing: var(--ls-wide);
  text-transform: uppercase;
  color: var(--text-faint);
  background: var(--bg-sunken);
  border: 1px solid var(--border-hair);
  border-radius: 5px;
  padding: 2px 6px;
  flex-shrink: 0;
}
body.finn-linked .chart-target-finn-badge { display: none; }
.chart-target-finn-hint {
  font-size: var(--fs-2xs);
  color: var(--text-faint);
  margin: var(--sp-2) 0 0;
  line-height: 1.4;
  display: none;
}
body:not(.finn-linked) .chart-target-finn-hint { display: block; }
body:not(.finn-linked) #chartTargetPills .pill,
body:not(.finn-linked) [data-field="chart_target"] .pill {
  opacity: 0.38;
  pointer-events: none;
  cursor: not-allowed;
}

/* ===== Ecosystem orbit ===== */
/* Interactive overview on wide screens: TradingVox as the hub (the same orb
   used in the live demo, on purpose, it's the same product), the other 7
   products as satellites at the vertices of a regular heptagon. Each node is
   a real link; hover/focus popovers get their pitch text from `.eco-grid` via
   interactions.js so the HTML only carries one copy of each blurb (the grid
   is the <1024px fallback and the single content source for crawlers). */
.eco-orbit { display: none; position: relative; width: min(600px, 100%); aspect-ratio: 1; margin: 0 auto 64px; }
/* The orbit's descriptions open on hover only, so touch tablets (iPad
   landscape is 1024+) keep the card grid, which shows them inline. */
@media (min-width: 1024px) and (hover: hover) { .eco-orbit { display: block; } }
.eco-orbit-lines { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.eco-orbit-lines line {
  stroke: var(--accent); stroke-width: 0.3; stroke-dasharray: 1.5 2; opacity: 0.45;
  animation: ecoOrbitFlow 3.5s linear infinite;
}
@keyframes ecoOrbitFlow { to { stroke-dashoffset: -14; } }
@media (prefers-reduced-motion: reduce) { .eco-orbit-lines line { animation: none; } }

.eco-orbit-hub {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: 140px; height: 140px; display: flex; align-items: center; justify-content: center;
}
.eco-orbit-hub .orb { width: 92px; height: 92px; }
.eco-orbit-hub .orb-ring { inset: -14px; border-color: rgba(255, 181, 71, 0.4); animation: pulseRing 2.6s ease-out infinite; }
.eco-orbit-hub-label {
  position: absolute; bottom: -8px; left: 50%; transform: translateX(-50%);
  font-family: var(--font-mono); font-size: var(--fs-2xs); font-weight: var(--fw-body); letter-spacing: var(--ls-wide); text-transform: uppercase;
  color: var(--voice); white-space: nowrap; background: var(--bg); padding: 2px 10px; border-radius: 999px;
  border: 1px solid rgba(255, 181, 71, 0.35);
}

.eco-orbit-node { position: absolute; transform: translate(-50%, -50%); z-index: 1; }
.eco-orbit-node:hover, .eco-orbit-node:focus-within { z-index: 5; }
.eco-orbit-node-pill {
  display: flex; align-items: center; gap: 8px;
  background: var(--bg-elevated); border: 1px solid var(--border-strong); border-radius: 999px;
  padding: 7px 16px 7px 7px; font-family: var(--font-display); font-weight: var(--fw-strong); font-size: var(--fs-body-sm); color: var(--text);
  white-space: nowrap; box-shadow: var(--shadow-card); text-decoration: none;
  transition: transform var(--dur-2) var(--ease-spring), border-color var(--dur-2) ease, box-shadow var(--dur-2) ease;
}
.eco-orbit-node:hover .eco-orbit-node-pill, .eco-orbit-node:focus-within .eco-orbit-node-pill {
  transform: scale(1.1); border-color: var(--accent-strong); box-shadow: var(--shadow-glow);
}
.eco-orbit-node-icon {
  width: 24px; height: 24px; border-radius: 50%; flex-shrink: 0; overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  background: var(--accent-soft); color: var(--accent-strong); font-size: var(--fs-3xs); font-weight: var(--fw-display);
}
.eco-orbit-node-icon img { width: 100%; height: 100%; object-fit: cover; }

.eco-orbit-popover {
  position: absolute; top: 100%; left: 50%; margin-top: 14px; width: 230px;
  background: var(--bg-elevated); border: 1px solid var(--border-strong); border-radius: var(--radius-md);
  box-shadow: var(--shadow-lift); padding: 18px; text-align: left;
  opacity: 0; visibility: hidden; pointer-events: none;
  transform: translate(-50%, 6px); transition: opacity var(--dur-2) ease, transform var(--dur-2) ease, visibility var(--dur-2);
}
.eco-orbit-popover::before, .eco-orbit-popover::after {
  content: ''; position: absolute; bottom: 100%; left: 50%; transform: translateX(-50%); border: 7px solid transparent;
}
.eco-orbit-popover::before { border-bottom-color: var(--border-strong); }
.eco-orbit-popover::after { border-bottom-color: var(--bg-elevated); margin-bottom: -1px; }
.eco-orbit-node:hover .eco-orbit-popover, .eco-orbit-node:focus-within .eco-orbit-popover {
  opacity: 1; visibility: visible; pointer-events: auto; transform: translate(-50%, 0);
}
.eco-orbit-popover h4 { font-family: var(--font-display); font-weight: var(--fw-strong); font-size: var(--fs-body); margin: 0 0 6px; letter-spacing: var(--ls-tight); }
.eco-orbit-popover p { color: var(--text-muted); font-size: var(--fs-sm); line-height: 1.5; margin: 0 0 12px; }

/* ===== Ecosystem grid ===== */
/* A flat, growing roster of products, not one linear pipeline, so this is
   a wrapping card grid rather than an arrow-chain: it scales cleanly as
   the ecosystem adds more pieces instead of needing a redesign each time.
   Hidden at the .eco-orbit breakpoint above — it only exists as the
   <1024px fallback for the hover-driven orbit. */
.eco-grid { display: grid; grid-template-columns: 1fr; gap: 18px; justify-items: stretch; }
@media (min-width: 640px) { .eco-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 900px) { .eco-grid { grid-template-columns: repeat(4, 1fr); } }
@media (min-width: 1024px) and (hover: hover) { .eco-grid { display: none; } }
.eco-card {
  display: flex; flex-direction: column; background: var(--bg-elevated); border: 1px solid var(--border); border-radius: var(--radius-md);
  padding: 22px; position: relative; overflow: hidden; text-decoration: none;
  transition: border-color var(--dur-2) ease, transform var(--dur-2) ease;
}
.eco-card::before {
  content: ''; position: absolute; inset: 0; opacity: 0; pointer-events: none;
  background: radial-gradient(280px circle at var(--mx, 50%) var(--my, 0%), var(--accent-soft), transparent 70%);
  transition: opacity var(--dur-2) ease;
}
.eco-card:hover::before { opacity: 0.4; }
.eco-card:hover { border-color: var(--border-strong); transform: translateY(-2px); }
.eco-card.is-you { border-color: rgba(255, 181, 71, 0.45); box-shadow: 0 0 0 1px rgba(255, 181, 71, 0.15) inset; }

.eco-card-top { display: flex; align-items: flex-start; justify-content: space-between; margin-bottom: 16px; position: relative; z-index: 1; }
.eco-card-icon {
  width: 44px; height: 44px; border-radius: 12px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-display); font-weight: var(--fw-display); font-size: var(--fs-sm); letter-spacing: var(--ls-tight);
  background: var(--accent-soft); color: var(--accent-strong);
  overflow: hidden;
}
.eco-card.is-you .eco-card-icon { background: var(--voice-dim); color: var(--voice); }
.eco-card-icon img, .nav-drop-icon img { width: 100%; height: 100%; object-fit: cover; border-radius: inherit; }
.eco-card-status {
  display: inline-flex; align-items: center; gap: 5px; font-family: var(--font-mono); font-size: var(--fs-3xs);
  font-weight: var(--fw-emphasis); letter-spacing: var(--ls-wide); text-transform: uppercase; color: var(--data);
  border: 1px solid rgba(61, 220, 151, 0.35); background: var(--data-dim); border-radius: 999px; padding: 4px 10px;
}
.eco-card-status::before { content: ''; width: 5px; height: 5px; border-radius: 50%; background: var(--data); box-shadow: 0 0 6px var(--data); }
.eco-card.is-you .eco-card-status { color: var(--voice); border-color: rgba(255, 181, 71, 0.35); background: var(--voice-dim); }
.eco-card.is-you .eco-card-status::before { background: var(--voice); box-shadow: 0 0 6px var(--voice); }

.eco-card h3 { font-family: var(--font-display); font-weight: var(--fw-strong); font-size: var(--fs-h3); margin: 0 0 8px; letter-spacing: var(--ls-tight-lg); position: relative; z-index: 1; }
.eco-card p { color: var(--text-muted); font-size: var(--fs-sm); line-height: 1.5; margin: 0; flex: 1; position: relative; z-index: 1; }

.eco-card-cta {
  display: inline-flex; align-items: center; gap: 6px; margin-top: 18px;
  font-family: var(--font-display); font-weight: var(--fw-strong); font-size: var(--fs-body-sm); color: var(--accent-strong); position: relative; z-index: 1;
}
.eco-card.is-you .eco-card-cta { color: var(--voice); }
.eco-card-cta .icon { width: 15px; height: 15px; transition: transform var(--dur-2) var(--ease-out); }
.eco-card:hover .eco-card-cta .icon { transform: translate(3px, -3px); }

/* ===== Feature grid ===== */
/* Bento layout on wide screens: card 1 (the flagship) gets a 2x2 footprint,
   card 2 spans wide, cards 3-4 sit small underneath it. Visual hierarchy
   instead of four identical boxes competing for the same attention. Falls
   back to a plain wrapping grid below 900px, where a bento layout would
   just be four squashed, oddly-shaped cards. */
.feature-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 18px;
}
@media (max-width: 900px) { .feature-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .feature-grid { grid-template-columns: 1fr; } }

.feature-card {
  background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius-md);
  padding: 28px 26px 24px; position: relative; overflow: hidden; display: flex; flex-direction: column;
  transition: border-color var(--dur-2) ease, box-shadow var(--dur-2) ease, transform var(--dur-2) var(--ease-out);
  transform: perspective(800px) rotateX(0deg) rotateY(0deg); will-change: transform;
}
.feature-card::before {
  content: ''; position: absolute; inset: 0; opacity: 0; pointer-events: none;
  background: radial-gradient(280px circle at var(--mx, 50%) var(--my, 0%), var(--fc-glow, var(--voice-dim)), transparent 70%);
  transition: opacity var(--dur-2) ease;
}
.feature-card:hover::before { opacity: 0.4; }
.feature-card:hover {
  border-color: var(--fc-color, var(--border-strong));
  transform: perspective(800px) translateY(-2px);
}

/* Source-specific color variables */
.feature-card--ezpz  { --fc-color: var(--accent);    --fc-glow: var(--accent-soft); }
.feature-card--ezra  { --fc-color: var(--data);      --fc-glow: var(--data-dim); }
.feature-card--finn  { --fc-color: var(--voice);     --fc-glow: var(--voice-dim); }

/* Source badge — sits at top of card */
.feature-source {
  display: inline-flex; align-items: center; gap: 5px;
  font-family: var(--font-mono); font-size: var(--fs-3xs); font-weight: var(--fw-strong); letter-spacing: var(--ls-wide);
  text-transform: uppercase; border-radius: 999px; padding: 3px 9px;
  margin-bottom: 18px; width: fit-content;
}
.feature-source::before {
  content: ''; display: inline-block; width: 5px; height: 5px; border-radius: 50%;
  background: currentColor; opacity: 0.9;
}
.feature-source--ezpz { color: var(--accent);  background: var(--accent-soft); }
.feature-source--ezra { color: var(--data);    background: var(--data-dim); }
.feature-source--finn { color: var(--voice);   background: var(--voice-dim); }

/* Icon badge */
.feature-icon {
  width: 44px; height: 44px; border-radius: 12px; display: flex; align-items: center;
  justify-content: center; margin-bottom: 16px;
  transition: transform var(--dur-2) var(--ease-spring);
}
.feature-icon .icon { width: 20px; height: 20px; }
.feature-card:hover .feature-icon { transform: scale(1.1) rotate(-4deg); }
.feature-icon--ezpz { background: var(--accent-soft); color: var(--accent); }
.feature-icon--ezra { background: var(--data-dim);    color: var(--data); }
.feature-icon--finn { background: var(--voice-dim);   color: var(--voice); }

.feature-card h3 { font-size: var(--fs-h4); font-weight: var(--fw-strong); margin: 0 0 10px; font-family: var(--font-display); letter-spacing: var(--ls-tight); line-height: 1.25; }
.feature-card p { font-size: var(--fs-sm); line-height: 1.55; color: var(--text); margin: 0 0 14px; }

/* Example ask — monospace quote at the bottom of each card */
.feature-ask {
  font-family: var(--font-mono); font-size: var(--fs-label); line-height: 1.5; color: var(--text);
  margin: auto 0 0; padding: 10px 12px;
  background: rgba(243, 240, 255, 0.04); border-radius: 7px;
  border-left: 2px solid var(--fc-color, var(--accent));
}
.tier-badge { display: inline-flex; font-family: var(--font-mono); font-size: var(--fs-3xs); font-weight: var(--fw-strong); letter-spacing: var(--ls-wide); padding: 3px 8px; border-radius: 4px; text-transform: uppercase; }
.tier-badge.premium { background: linear-gradient(135deg, var(--ecosystem-purple), var(--ecosystem-purple-light)); color: var(--text); }
/* Studio previously shared .premium (purple) with Pro, which made two
   visually distinct product tiers read as the same thing. Gold matches its
   card treatment (--voice) below and the studio-grade identity it has on
   the full /pricing page. */
.tier-badge.voice { background: linear-gradient(135deg, var(--voice), var(--voice-strong)); color: var(--text-on-accent); }
.tier-badge.elite { background: linear-gradient(135deg, var(--ecosystem-elite-strong), var(--ecosystem-elite)); color: var(--text); }
.tier-badge.free { background: linear-gradient(135deg, var(--tier-free), var(--tier-free-light)); color: var(--text); }
@media (prefers-reduced-motion: reduce) { .feature-card { transform: none !important; } }

/* ===== Voice tiers (home page teaser grid) =====
   auto-fit + justify-content: center means the grid hugs however many cards
   SHOW_STANDARD_TIER (apps/marketing/context_processors.py) leaves in the
   template — 2 cards center as a pair instead of leaving an empty third
   column, same fix as .pricing-grid in pricing.css. */
.tier-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 400px)); justify-content: center; gap: 18px; }
.tier-card { background: var(--bg-elevated); border: 1px solid var(--border); border-radius: var(--radius-md); padding: 26px; display: flex; flex-direction: column; gap: 12px; transition: transform var(--dur-2) ease, border-color var(--dur-2) ease; }
.tier-card:hover { transform: translateY(-3px); }
/* Restraint pass: was a continuously spinning conic-gradient border (the
   most decorative/atmospheric single effect on the site) — "featured" is
   real signal (recommended plan), so it keeps a distinct static border
   instead of losing the treatment outright. */
.tier-card.featured { position: relative; border-color: rgba(255,181,71,0.5); background: var(--bg-elevated); }
@property --spin-angle { syntax: '<angle>'; inherits: false; initial-value: 0deg; }
@keyframes spinBorder { to { --spin-angle: 360deg; } }
/* Studio's own static gold identity — distinct from Pro's spinning
   "featured" border rather than competing with it, matching .is-premium
   on the full /pricing page so the two pages read as one design system. */
.tier-card.premium { border-color: rgba(255, 181, 71, 0.35); background: linear-gradient(180deg, rgba(255, 181, 71, 0.07), transparent 45%), var(--bg-elevated); }
.tier-card.premium:hover { border-color: rgba(255, 181, 71, 0.55); }

.tier-card-head { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 10px; }
.tier-icon { width: 30px; height: 30px; flex-shrink: 0; border-radius: var(--radius-sm); display: flex; align-items: center; justify-content: center; }
.tier-icon .icon { width: 15px; height: 15px; }
.tier-icon--elite { background: rgba(245, 158, 11, 0.14); color: var(--ecosystem-elite); }
.tier-icon--accent { background: var(--accent-soft); color: var(--accent-strong); }
.tier-icon--voice { background: var(--voice-dim); color: var(--voice-strong); }
.tier-name { font-family: var(--font-display); font-weight: var(--fw-strong); font-size: var(--fs-h3); letter-spacing: var(--ls-tight-lg); }
.tier-price { font-family: var(--font-mono); color: var(--text); font-size: var(--fs-xs); }
/* Same short scannable cost stat as .pricing-savings-badge on /pricing —
   Studio's usage-based price alone doesn't convey "cheap in practice". */
.tier-savings-badge {
  display: inline-flex; align-items: center; gap: 6px; align-self: flex-start; white-space: nowrap;
  font-family: var(--font-mono); font-size: var(--fs-label); font-weight: var(--fw-strong); letter-spacing: var(--ls-wide);
  color: var(--voice-strong); background: var(--voice-dim); border: 1px solid rgba(255, 181, 71, 0.35);
  border-radius: var(--radius-pill); padding: 5px 12px; margin-top: -4px;
}
.tier-savings-badge .icon { width: 13px; height: 13px; stroke: var(--voice-strong); fill: none; stroke-width: 2.5; flex-shrink: 0; }
.tier-list { list-style: none; padding: 0; margin: 6px 0 0; display: flex; flex-direction: column; gap: 10px; }
/* The optional EZPZ AI & Data add-on under a home plan card (2026-09-23) —
   one quiet dashed line, the same recipe as the pricing card's add-on row. */
.tier-addon {
  margin: var(--sp-2) 0 0; padding: var(--sp-3) var(--sp-4);
  background: var(--bg-card); border: 1px dashed var(--border-strong); border-radius: var(--radius-md);
  font-size: var(--fs-label); color: var(--text-muted); line-height: 1.5;
}
.tier-addon strong { color: var(--voice-strong); font-weight: var(--fw-strong); }
.tier-list li { font-size: var(--fs-sm); color: var(--text); display: flex; gap: 8px; line-height: 1.4; }
.tier-list li .check { color: var(--data); flex-shrink: 0; }
.tier-list li .check .icon { width: 16px; height: 16px; margin-top: 2px; }

/* ===== CTA banner ===== */
.cta-banner {
  border-radius: var(--radius-xl); padding: 56px 32px; text-align: center; position: relative; overflow: hidden;
  background: linear-gradient(150deg, var(--bg-elevated), var(--bg-card));
  border: 1px solid var(--border-strong);
}
.cta-banner::before {
  content: ''; position: absolute; inset: -40% -10% auto -10%; height: 320px;
  background: radial-gradient(circle, var(--accent-soft) 0%, transparent 70%); pointer-events: none;
}
.cta-banner h2 { font-family: var(--font-display); font-weight: var(--fw-display); font-size: var(--fs-h2); letter-spacing: var(--ls-tight-lg); margin-bottom: 16px; position: relative; }
.cta-banner p { color: var(--text-muted); font-size: var(--fs-lead); line-height: 1.5; max-width: 460px; margin: 0 auto 30px; position: relative; }
.cta-banner .hero-ctas { position: relative; }
@media (max-width: 480px) { .cta-banner { padding: 40px 20px; } }

/* ===== Sub-nav: sticky in-page section strip (features, faq, legal pages) =====
   Sits just under the sticky .topbar (~76px tall from 720px up, where the
   header CTA sets its height; ~67–71px below that, set by the burger).
   interactions.js's scrollspy toggles .is-active on whichever link's
   target is in view ([data-scrollspy] on the <nav>). Anchor targets that
   follow a sub-nav get a bigger scroll margin so they clear both bars. */
.subnav {
  position: sticky; top: 76px; z-index: calc(var(--z-nav) - 1);
  background: var(--bg-overlay);
  backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  border-top: 1px solid var(--border-hair); border-bottom: 1px solid var(--border-hair);
}
@media (max-width: 719px) { .subnav { top: 66px; } }
.subnav-inner {
  display: flex; justify-content: flex-start; gap: 6px; padding-top: 10px; padding-bottom: 10px;
  overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch;
}
.subnav-inner::-webkit-scrollbar { display: none; }
/* Centred via auto margins, not justify-content: center — a centred row
   that overflows spills off the LEFT edge where it can't be scrolled to
   (Terms' 11 pills lost "Intro" at 768–1280px). Auto margins centre when
   there's room and collapse to left-aligned + scrollable when there isn't. */
.subnav-inner > :first-child { margin-left: auto; }
.subnav-inner > :last-child { margin-right: auto; }
.subnav a {
  display: inline-flex; align-items: center; gap: 8px; flex-shrink: 0;
  font-family: var(--font-mono); font-size: var(--fs-label); letter-spacing: var(--ls-wide); text-transform: uppercase;
  color: var(--text-faint); text-decoration: none; padding: 8px 14px; border-radius: var(--radius-pill);
  border: 1px solid transparent;
  transition: color var(--dur-1) ease, border-color var(--dur-1) ease, background var(--dur-1) ease;
}
.subnav a:hover { color: var(--text); background: var(--bg-glass); }
.subnav a.is-active { color: var(--text); border-color: var(--border-strong); background: var(--bg-glass); }
.subnav-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--text-faint); flex-shrink: 0; transition: box-shadow var(--dur-2) ease; }
.subnav-dot--accent { background: var(--accent); }
.subnav-dot--voice { background: var(--voice); }
.subnav-dot--data { background: var(--data); }
.subnav a.is-active .subnav-dot { box-shadow: 0 0 0 3px var(--border-hair); }
.subnav ~ [id], .subnav ~ * [id] { scroll-margin-top: 150px; }

/* ===== Search field: pill input with a leading icon (catalogue/FAQ filters) ===== */
.search-field { position: relative; display: block; width: 100%; max-width: 520px; }
.search-field .icon {
  position: absolute; left: 16px; top: 50%; transform: translateY(-50%);
  width: 16px; height: 16px; color: var(--text-faint); pointer-events: none;
}
.search-field input {
  width: 100%; padding: 12px 18px 12px 42px; border-radius: var(--radius-pill);
  border: 1px solid var(--border-strong); background: var(--bg-glass); color: var(--text);
  font-family: var(--font-body); font-size: var(--fs-sm); letter-spacing: var(--ls-normal);
  transition: border-color var(--dur-2) ease, box-shadow var(--dur-2) ease;
}
.search-field input::placeholder { color: var(--text-faint); }
.search-field input:focus { outline: none; border-color: var(--voice); box-shadow: 0 0 0 3px var(--voice-dim); }
.search-field input::-webkit-search-cancel-button { -webkit-appearance: none; }

/* ===== Accordion (FAQ page, pricing FAQ) =====
   One accordion for the whole site — moved here from content.css so the
   pricing page's "Common questions" uses the same component instead of
   its own divider-list variant. */
.faq-group-title {
  font-family: var(--font-mono); font-size: var(--fs-label); letter-spacing: var(--ls-wide); text-transform: uppercase;
  color: var(--data); margin: 40px 0 14px;
}
.faq-group-title:first-child { margin-top: 0; }
.faq-item {
  border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--bg-card);
  margin-bottom: 10px; overflow: hidden; transition: border-color var(--dur-2) ease;
}
.faq-item:hover { border-color: var(--border-strong); }
.faq-item summary {
  cursor: pointer; list-style: none; padding: 18px 20px; font-family: var(--font-body); font-weight: var(--fw-strong);
  font-size: var(--fs-md); color: var(--text); display: flex; align-items: center; justify-content: space-between; gap: 12px;
}
.faq-item summary::-webkit-details-marker { display: none; }
.faq-item summary::after {
  content: '+'; font-family: var(--font-mono); color: var(--text-faint); font-size: var(--fs-h4); flex-shrink: 0;
  transition: transform var(--dur-2) var(--ease-out), color var(--dur-2) ease;
}
.faq-item[open] { border-color: rgba(255,181,71,0.35); }
.faq-item[open] summary::after { transform: rotate(45deg); color: var(--voice); }
.faq-item .faq-answer { padding: 0 20px 20px; color: var(--text); font-size: var(--fs-sm); line-height: 1.65; }
.faq-item .faq-answer p + p, .faq-item .faq-answer ul { margin-top: 10px; }
@keyframes faqFadeIn { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: translateY(0); } }
.faq-item[open] .faq-answer { animation: faqFadeIn var(--dur-2) var(--ease-out) both; }
@media (prefers-reduced-motion: reduce) { .faq-item[open] .faq-answer { animation: none; } }

/* ===== Footer ===== */
footer {
  position: relative;
  padding: 64px 0 32px;
  background: var(--bg-sunken);
  color: var(--text-muted);
  font-size: var(--fs-sm);
}
footer::before {
  content: ''; position: absolute; top: 0; left: 0; right: 0; height: 1px;
  background: linear-gradient(90deg, transparent, var(--border-strong) 20%, var(--border-strong) 80%, transparent);
}

/* Brand (left) + nav (right) flex row */
.footer-main {
  display: flex;
  align-items: flex-start;
  gap: 64px;
  padding-bottom: 40px;
}
.footer-brand { flex: 0 0 240px; }
.footer-brand-desc {
  margin-top: 14px;
  line-height: 1.7;
  color: var(--text-muted);
  font-size: var(--fs-sm);
}

/* 3-column nav group */
.footer-nav {
  flex: 1;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 32px;
}
.footer-col h4 {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  letter-spacing: var(--ls-wide);
  text-transform: uppercase;
  color: var(--text-faint);
  margin-bottom: 16px;
}
.footer-col ul { list-style: none; padding: 0; display: flex; flex-direction: column; gap: 10px; }
/* Bigger tap targets on touch-size screens, same visual rhythm. */
@media (max-width: 860px) { .footer-col ul { gap: 0; } .footer-col a { padding: 7px 0; } }
.footer-col a {
  text-decoration: none;
  color: var(--text-muted);
  font-size: var(--fs-sm);
  display: inline-block;
  transition: color var(--dur-1) ease, transform var(--dur-2) var(--ease-out);
}
.footer-col a:hover { color: var(--text); transform: translateX(4px); }

/* Ecosystem horizontal belt */
.footer-eco-belt {
  display: flex;
  align-items: center;
  gap: 20px;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 14px 20px;
  margin-bottom: 24px;
}
.footer-eco-label {
  font-family: var(--font-mono);
  font-size: var(--fs-3xs);
  letter-spacing: var(--ls-wide);
  text-transform: uppercase;
  color: var(--text-faint);
  white-space: nowrap;
  flex-shrink: 0;
}
.footer-eco-pills { display: flex; flex-wrap: wrap; gap: 7px; }
.footer-eco-pill {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  font-weight: var(--fw-strong);
  letter-spacing: var(--ls-wide);
  color: var(--accent-strong);
  background: var(--accent-soft);
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  padding: 6px 12px;
  text-decoration: none;
  transition: background var(--dur-2) ease, border-color var(--dur-2) ease,
              color var(--dur-2) ease, transform var(--dur-2) var(--ease-spring);
}
.footer-eco-pill:hover {
  background: rgba(155, 107, 255, 0.22);
  border-color: var(--accent);
  color: var(--text);
  transform: translateY(-2px);
}

/* Disclosure callout */
.footer-disclosure {
  border-left: 2px solid var(--voice);
  background: var(--voice-dim);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  padding: 14px 18px;
  margin-bottom: 28px;
  font-size: var(--fs-xs);
  line-height: 1.65;
  color: var(--text-muted);
}
.footer-disclosure strong { color: var(--voice-strong); font-weight: var(--fw-emphasis); }

/* Bottom bar */
.footer-bottom {
  border-top: 1px solid var(--border);
  padding-top: 24px;
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.footer-copyright { font-size: var(--fs-xs); color: var(--text-faint); }

/* Footer responsive */
@media (max-width: 860px) {
  .footer-main { flex-direction: column; gap: 36px; }
  .footer-brand { flex: none; width: 100%; }
  .footer-eco-belt { flex-wrap: wrap; }
}
@media (max-width: 600px) {
  .footer-nav { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 380px) {
  .footer-nav { grid-template-columns: 1fr; }
}

/* ===== Responsive tweaks ===== */
@media (max-width: 640px) {
  .demo-shell { padding: 26px; }
  .hero { padding: var(--sp-5) 0 var(--sp-7); }
  section { padding: var(--sp-8) 0; }

  /* Voice demo widget (#demo) — .demo-shell already drops to a single
     column below 900px (see its own min-width:900px rule); everything
     below is the narrower tightening pass on top of that. */
  .mode-toggle { gap: 10px; margin: 4px 0 22px; }
  .mode-tabs { gap: 2px; padding: 3px; width: 100%; justify-content: center; }
  .mode-btn { padding: 8px 13px; font-size: var(--fs-label); }
  .live-status { padding: 6px 12px; }

  /* .settings-grid's auto-fit already collapses cards to one column once
     230px minmax no longer fits two across, so no forced column override
     is needed here — just reclaiming padding for the narrower screen. */
  .settings-strip { padding: var(--sp-4); gap: var(--sp-4); }
  .mode-card-group { grid-template-columns: 1fr; }
  .finn-link-group, .ezpz-link-group { flex-direction: column; align-items: stretch; padding: var(--sp-4); }
  .finn-link-actions { width: 100%; }
  .finn-link-actions button { flex: 1; }

  /* Ask row: input above button, not squeezed side by side — the button
     was shrinking to an unreadable sliver once the input claimed its
     minimum usable width on a narrow phone. Composer drops the pill
     radius here too, since a full-width pill with a stacked button
     inside it reads oddly at this width. */
  .ask-row { flex-direction: column; align-items: stretch; border-radius: var(--radius-md); padding: 10px; gap: 10px; }
  .ask-row input { padding: 8px 6px; }
  .ask-row button { width: 100%; justify-content: center; }

  .chip-row { gap: 6px; }
  .chip { font-size: var(--fs-label); padding: 7px 12px; }

  .orb-wrap { width: 132px; height: 132px; }
  .orb { width: 92px; height: 92px; }
}

@media (max-width: 400px) {
  /* Below ~400px even 2 tabs per row can be tight with "Scripted Preview"
     in the mix — let the segmented control wrap to as many rows as it
     needs rather than compressing text further. */
  .mode-tabs { flex-direction: column; align-items: stretch; }
  .mode-btn { justify-content: center; }
}

/* #chart — TradingView Advanced Charts widget (chart-widget.js). */
.tv-chart-shell { background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius-md); overflow: hidden; }
.tv-chart-container { width: 100%; height: 640px; }
.tv-chart-placeholder { display: flex; align-items: center; justify-content: center; height: 320px; color: var(--text-muted); font-size: var(--fs-sm); }

/* Feed label above the chart. Delayed market data has to say so, and the
   chart is now shown to signed-out visitors too (2026-09-23), so this is the
   one place the page states which feed the bars came from. Same pill
   vocabulary as .eco-card-status; amber (--ecosystem-elite, the Elite-gating
   colour) for delayed because real time is exactly what Elite unlocks. */
.tv-chart-status {
  display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap;
  padding: var(--sp-2) var(--sp-3); border-bottom: 1px solid var(--border);
}
.tv-chart-feed {
  display: inline-flex; align-items: center; gap: 5px; font-family: var(--font-mono); font-size: var(--fs-3xs);
  font-weight: var(--fw-emphasis); letter-spacing: var(--ls-wide); text-transform: uppercase;
  border-radius: var(--radius-pill); padding: 4px 10px;
  color: var(--ecosystem-elite); border: 1px solid var(--ecosystem-elite); background: var(--voice-dim);
}
.tv-chart-feed::before { content: ''; width: 5px; height: 5px; border-radius: 50%; background: var(--ecosystem-elite); }
.tv-chart-feed[data-feed="live"] {
  color: var(--data); border-color: var(--data); background: var(--data-dim);
}
.tv-chart-feed[data-feed="live"]::before { background: var(--data); box-shadow: 0 0 6px var(--data); }
.tv-chart-feed-note { font-size: var(--fs-2xs); color: var(--text-faint); }
.tv-chart-feed-link { font-size: var(--fs-2xs); color: var(--accent-strong); text-decoration: underline; }

/* Chart spotlight (chart-jump.js) — briefly draws the eye to the live chart
   after a member jumps here from the "Embedded" chart-target setting, or
   after a voice command actually touches the chart, so it doesn't just
   blend into the page below the fold. Reuses .tier-card.featured's spinning
   conic-gradient border for a consistent "pay attention here" motif. */
.tv-chart-shell.chart-spotlight {
  border-color: transparent;
  background: linear-gradient(var(--bg-card), var(--bg-card)) padding-box,
    conic-gradient(from var(--spin-angle, 0deg), var(--accent), var(--voice), var(--accent)) border-box;
  animation: spinBorder 1.6s linear 2, chartSpotlightGlow 1.6s ease-out 2;
}
@keyframes chartSpotlightGlow {
  0% { box-shadow: 0 0 0 0 var(--accent-glow); }
  35% { box-shadow: 0 0 44px 4px var(--accent-glow); }
  100% { box-shadow: 0 0 0 0 rgba(155, 107, 255, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .tv-chart-shell.chart-spotlight { animation: none; border-color: var(--accent-strong); }
}

/* "View chart" jump link next to the Chart target pills (Voice & mode
   settings) — members picking "Embedded" there have no other way to know
   which chart on the page that means. */
.chart-target-jump-link {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  width: fit-content;
  margin-top: var(--sp-2);
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  font-weight: var(--fw-emphasis);
  letter-spacing: var(--ls-wide);
  color: var(--accent-strong);
  text-decoration: none;
  cursor: pointer;
  transition: color var(--dur-1) ease, transform var(--dur-1) ease;
}
.chart-target-jump-link:hover { color: var(--accent); transform: translateX(2px); }
.chart-target-jump-link .icon { width: 11px; height: 11px; transition: transform var(--dur-1) ease; }
.chart-target-jump-link:hover .icon { transform: translateY(2px); }

@media (max-width: 900px) {
  .tv-chart-container { height: 480px; }
  .tv-chart-placeholder { height: 240px; }
}


/* ===== Enhanced Responsive Design for Demo Section ===== */
@media (max-width: 899px) {
  .demo-shell {
    grid-template-columns: 1fr;
    padding: 32px;
    gap: 28px;
  }
  
  .voice-orb-container {
    order: 1;
  }
  
  .demo-main {
    order: 2;
  }
  
  .orb-wrap {
    width: 160px;
    height: 160px;
  }
  
  .orb {
    width: 110px;
    height: 110px;
  }
  
  .orb-ring {
    inset: -14px;
  }
}

@media (max-width: 640px) {
  .demo-mode-selector {
    margin: 20px 0;
  }
  
  .demo-shell {
    padding: 24px;
    border-radius: var(--radius-lg);
  }
  
  .chip-row {
    gap: 8px;
  }
  
  .chip {
    padding: 8px 14px;
    font-size: var(--fs-label);
  }
  
  .mic-btn {
    min-height: 50px;
    padding: 8px 14px;
  }
  
  .mic-btn-icon {
    width: 36px;
    height: 36px;
  }
  
  .transcript {
    padding: 18px;
    min-height: 240px;
  }
  
  .ask-row {
    flex-direction: column;
    align-items: stretch;
    border-radius: var(--radius-md);
    padding: 10px;
    gap: 10px;
  }

  .ask-row input {
    padding: 8px 6px;
  }

  .ask-row button {
    width: 100%;
    justify-content: center;
  }
}

@media (max-width: 480px) {
  .demo-shell {
    padding: 20px;
    gap: 24px;
  }
  
  .orb-wrap {
    width: 140px;
    height: 140px;
  }
  
  .orb {
    width: 95px;
    height: 95px;
  }
  
  .orb-status {
    padding: 6px 12px;
  }
  
  .status-text {
    font-size: var(--fs-2xs);
  }
  
  .mic-controls,
  .mic-actions {
    gap: 10px;
  }
  
  .mute-btn {
    width: 50px;
    min-height: 50px;
  }
  
  .t-line.ai .txt {
    font-size: var(--fs-h4);
  }
  
  .t-line.user .txt {
    font-size: var(--fs-body-sm);
  }
}

/* Smooth scroll for transcript */
.transcript {
  scroll-behavior: smooth;
  -webkit-overflow-scrolling: touch;
}

/* Scrollbar styling for transcript */
.transcript::-webkit-scrollbar {
  width: 8px;
}

.transcript::-webkit-scrollbar-track {
  background: var(--bg-sunken);
  border-radius: 4px;
}

.transcript::-webkit-scrollbar-thumb {
  background: var(--border-strong);
  border-radius: 4px;
  transition: background 0.25s ease;
}

.transcript::-webkit-scrollbar-thumb:hover {
  background: var(--text-faint);
}

/* Animation for new messages */
@keyframes messageSlideIn {
  from {
    opacity: 0;
    transform: translateY(12px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.t-line {
  animation: messageSlideIn 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}

/* Focus styles for keyboard navigation */
.mode-btn:focus-visible,
.chip:focus-visible,
.mic-btn:focus-visible,
.mute-btn:focus-visible,
.stop-speak-btn:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px var(--accent-soft);
  z-index: 1;
}

/* Print styles */
@media print {
  .demo-shell {
    box-shadow: none;
    border: 1px solid #ccc;
    page-break-inside: avoid;
  }
  
  .mic-controls,
  .mic-actions,
  .stop-speak-btn {
    display: none;
  }
}

/* ===== Form fields on touch-size screens =====
   iOS Safari zooms the page in when a field under 16px is focused, and
   stays zoomed. Every text field on the site is 12–15px on desktop, so
   bump them to --fs-body (16px) on phone/tablet widths. Page layers that
   own their own field (stake_modal.css, opra.css) do the same there. */
@media (max-width: 860px) {
  .auth-field input, .form-field input, .form-field textarea, .form-field select,
  .sf-row input, .search-field input, .ask-row input,
  .credit-topup-custom-input, .credit-inline-input { font-size: var(--fs-body); }
}
