/* =============================================================
   Agent Cohort - Marketing site, "Mission Console" design system
   Hand-written, framework-free. v2 redesign.

   Visual language: an instrument panel for developers. The app's
   own Cool Slate dark theme (deep navy ink, cyan accent) with cool
   porcelain paper sections for editorial contrast; editorial serif
   headlines (Instrument Serif) over a geometric UI face (Space
   Grotesk), and mono micro-labels (JetBrains Mono). Hairline
   rules, crosshair ticks, and section indices give the page the
   feel of a technical drawing; the product mock supplies the
   proof.

   Token contract: the token NAMES are unchanged from v1 so the
   ported functional blocks (app mock, pricing dynamics, waitlist
   modal, consent banner, prelaunch) inherit the new theme
   automatically. The app mock re-pins the original Cool Slate
   values in its own scope further down, so the product shot
   stays product-accurate.
   ============================================================= */

:root {
  /* Surfaces - Cool Slate ink (matches the app) */
  --bg:           #0a0a0f;
  --bg-2:         #0e0e15;
  --surface:      #14141c;
  --surface-2:    #1a1a23;
  --surface-3:    #21212c;
  --border:       #24242f;
  --border-2:     #2e2e3a;
  --border-soft:  rgba(255, 255, 255, 0.06);

  /* Text - cool slate */
  --text:         #ecedf2;
  --text-2:       #b6b8c4;
  --text-3:       #888a98;
  --text-muted:   #5d5f6c;

  /* Accent - Cool Slate cyan (the app default palette) */
  --accent:       #5cc1d4;
  --accent-2:     #7adff2;
  --accent-soft:  rgba(92, 193, 212, 0.12);
  --accent-glow:  rgba(92, 193, 212, 0.35);

  /* Secondary accents for chips / status */
  --orange:       #e89968;
  --green:        #7ab36a;
  --amber:        #d9a050;
  --red:          #d77780;
  --blue:         #82a8d8;

  /* Type */
  --font-display: 'Instrument Serif', Georgia, 'Times New Roman', serif;
  --font-sans: 'Space Grotesk', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI Variable', 'Segoe UI', system-ui, sans-serif;
  --font-mono: 'JetBrains Mono', 'Cascadia Code', 'Fira Code', Consolas, ui-monospace, monospace;
  --font-brand: 'Raffishly', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;

  /* Layout */
  --container: 1240px;
  --radius: 6px;
  --radius-lg: 10px;
  --radius-sm: 4px;

  /* Easing */
  --ease: cubic-bezier(0.2, 0.8, 0.2, 1);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);

  /* Hairline + label colors derived from the theme */
  --hairline: rgba(236, 237, 242, 0.10);
  --hairline-strong: rgba(236, 237, 242, 0.18);
  --label: var(--text-3);
}

/* Raised-slate theme: the contrast sections. A clearly lifted slate
   band (a few steps lighter than the page ground, still firmly dark)
   instead of a light "paper" slice, so the whole site stays in the
   app's dark family. Re-maps the same token names so every component
   that reads tokens adapts when placed inside a .theme-paper section;
   the class name is kept from the paper era to avoid markup churn. */
.theme-paper {
  --bg:           #16161f;
  --bg-2:         #1a1a24;
  --surface:      #1d1d28;
  --surface-2:    #232330;
  --surface-3:    #2a2a38;
  --border:       #30303e;
  --border-2:     #3c3c4c;
  --border-soft:  rgba(255, 255, 255, 0.07);

  --text:         #ecedf2;
  --text-2:       #b6b8c4;
  --text-3:       #8e90a0;
  --text-muted:   #636576;

  --accent:       #5cc1d4;
  --accent-2:     #7adff2;
  --accent-soft:  rgba(92, 193, 212, 0.12);
  --accent-glow:  rgba(92, 193, 212, 0.35);

  --hairline: rgba(236, 237, 242, 0.10);
  --hairline-strong: rgba(236, 237, 242, 0.20);

  background: var(--bg);
  color: var(--text);
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  /* Own stacking context so glows from neighbouring sections (e.g. the
     tour frame's blurred halo) cannot bleed over the slate band. */
  position: relative;
  z-index: 1;
}

/* ====== Self-hosted faces ====== */

/* Brand wordmark - same Raffishly OTF the dock app ships. Commercial
   license covers web distribution as part of the same paid product. */
@font-face {
  font-family: 'Raffishly';
  src: url('fonts/Raffishly.otf') format('opentype');
  font-weight: normal;
  font-style: normal;
  font-display: swap;
}

/* Instrument Serif - OFL. Display headlines only. */
@font-face {
  font-family: 'Instrument Serif';
  src: url('fonts/InstrumentSerif-Regular.latin.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Instrument Serif';
  src: url('fonts/InstrumentSerif-Italic.latin.woff2') format('woff2');
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}

/* Space Grotesk variable - OFL. Body + UI face. */
@font-face {
  font-family: 'Space Grotesk';
  src: url('fonts/SpaceGrotesk-Variable.latin.woff2') format('woff2');
  font-weight: 300 700;
  font-style: normal;
  font-display: swap;
}

/* JetBrains Mono variable - OFL. Labels, readouts, code. */
@font-face {
  font-family: 'JetBrains Mono';
  src: url('fonts/JetBrainsMono-Variable.latin.woff2') format('woff2');
  font-weight: 100 800;
  font-style: normal;
  font-display: swap;
}

/* ====== Reset / base ====== */

* { box-sizing: border-box; }

/* Restore the HTML `hidden` attribute's effect across the site.
   Without this rule, any element with an explicit `display:` (flex,
   grid, inline-block, etc.) overrides the user-agent default
   `display: none` that `hidden` sets. */
[hidden] { display: none !important; }

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

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: 16px;
  font-weight: 400;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

img, svg { display: block; max-width: 100%; }

a {
  color: var(--accent);
  text-decoration: none;
  transition: color 0.15s var(--ease);
}
a:hover { color: var(--accent-2); }

::selection {
  background: var(--accent);
  color: #0a1518;
}

code {
  font-family: var(--font-mono);
  font-size: 0.9em;
  background: var(--accent-soft);
  padding: 0.1em 0.4em;
  border-radius: var(--radius-sm);
  color: var(--text);
  border: 1px solid var(--border-soft);
}

pre {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 13px;
  line-height: 1.65;
  overflow-x: auto;
}

pre code {
  background: none;
  border: none;
  padding: 0;
  border-radius: 0;
  color: inherit;
  font-size: inherit;
}

h1, h2 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 400;
  letter-spacing: -0.01em;
  color: var(--text);
  line-height: 1.04;
  text-wrap: balance;
}
h3, h4 {
  margin: 0;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--text);
  line-height: 1.25;
  text-wrap: balance;
}

h1 { font-size: clamp(3rem, 7.5vw, 5.6rem); }
h2 { font-size: clamp(2.1rem, 4.4vw, 3.4rem); }
h3 { font-size: 1.1rem; }
h4 {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--text-3);
}

/* Serif italic accent inside display headlines. The class name is
   inherited from v1 (where it was a gradient) so existing markup
   keeps working; the treatment is now an italic accent stroke. */
.grad {
  font-style: italic;
  color: var(--accent);
}

p { margin: 0; color: var(--text-2); text-wrap: pretty; }

small { color: var(--text-3); }

.container {
  width: 100%;
  max-width: var(--container);
  margin: 0 auto;
  /* Longhand so `class="container X"` rules never wipe vertical padding. */
  padding-left: 28px;
  padding-right: 28px;
}

/* ====== Skip link ====== */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 300;
  padding: 12px 18px;
  background: var(--accent);
  color: #0a1518;
  font-family: var(--font-mono);
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  border-radius: 0 0 var(--radius) 0;
}
.skip-link:focus {
  left: 0;
  color: #0a1518;
}

/* ====== Focus visibility ====== */
a:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible,
summary:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* ====== Mono micro-labels (the system voice) ====== */
.mlabel {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.18em;
  color: var(--label);
}

/* Eyebrow: section voice line. `//` prefix painted by CSS so copy
   stays clean for screen readers. */
.eyebrow {
  display: inline-flex;
  align-items: baseline;
  gap: 10px;
  font-family: var(--font-mono);
  font-size: 11.5px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  color: var(--text-3);
}
.eyebrow::before {
  content: '//';
  color: var(--accent);
  letter-spacing: 0;
}

/* ====== Section heads ====== */
.section-head {
  position: relative;
  margin-bottom: clamp(36px, 5vw, 64px);
  max-width: 720px;
}
.section-head .eyebrow { margin-bottom: 18px; }
.section-head h2 { margin-bottom: 16px; }
.section-head p {
  font-size: clamp(15px, 1.3vw, 17px);
  color: var(--text-2);
  max-width: 560px;
}

.section-head-center {
  margin-left: auto;
  margin-right: auto;
  text-align: center;
}
.section-head-center p { margin-left: auto; margin-right: auto; }

.section-head-row {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 32px;
  max-width: none;
}
.section-head-row > div { max-width: 720px; }

/* ====== Hairlines + ticks ====== */
.hairline { border: 0; border-top: 1px solid var(--hairline); margin: 0; }

/* Full-bleed section divider with center crosshair. */
.rule-x {
  position: relative;
  height: 1px;
  background: var(--hairline);
}
.rule-x::after {
  content: '+';
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--accent);
  background: var(--bg);
  padding: 0 10px;
}

/* Corner brackets: four L-corners painted with background strips.
   Used on framed panels and hover states. */
.brackets { position: relative; }
.brackets::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image:
    linear-gradient(var(--accent), var(--accent)),
    linear-gradient(var(--accent), var(--accent)),
    linear-gradient(var(--accent), var(--accent)),
    linear-gradient(var(--accent), var(--accent)),
    linear-gradient(var(--accent), var(--accent)),
    linear-gradient(var(--accent), var(--accent)),
    linear-gradient(var(--accent), var(--accent)),
    linear-gradient(var(--accent), var(--accent));
  background-repeat: no-repeat;
  background-size: 16px 1px, 1px 16px, 16px 1px, 1px 16px, 16px 1px, 1px 16px, 16px 1px, 1px 16px;
  background-position:
    left top, left top,
    right top, right top,
    left bottom, left bottom,
    right bottom, right bottom;
  opacity: 0.9;
}

/* ====== Buttons ====== */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 14px 24px;
  font-family: var(--font-mono);
  font-size: 12.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  line-height: 1;
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.18s var(--ease), color 0.18s var(--ease),
              border-color 0.18s var(--ease), box-shadow 0.18s var(--ease),
              transform 0.18s var(--ease);
}
.btn:active { transform: translateY(1px); }
.btn svg { flex-shrink: 0; }

.btn-primary {
  background: var(--accent);
  color: #0a1518;
  border-color: var(--accent);
  box-shadow: 0 0 0 0 var(--accent-glow);
}
.btn-primary:hover {
  background: var(--accent-2);
  border-color: var(--accent-2);
  color: #0a1518;
  box-shadow: 0 0 28px 0 var(--accent-glow);
}

.btn-ghost {
  background: transparent;
  color: var(--text);
  border-color: var(--border-2);
}
.btn-ghost:hover {
  color: var(--accent);
  border-color: var(--accent);
  background: var(--accent-soft);
}

/* Arrow links */
.link-arrow {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--accent);
}
.link-arrow svg { transition: transform 0.18s var(--ease); }
.link-arrow:hover svg { transform: translateX(4px); }

/* Status dot (inherited name from v1 markup) */
.dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 8px var(--accent-glow);
  flex-shrink: 0;
}

/* ====== Scroll reveals ======
   reveal.js adds `rv-enabled` to <html> only when JS runs AND the
   user has not requested reduced motion; without it everything is
   fully visible (no-JS safe). */
html.rv-enabled [data-rv] {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity 0.7s var(--ease-out), transform 0.7s var(--ease-out);
  transition-delay: calc(var(--rv-delay, 0) * 90ms);
}
html.rv-enabled [data-rv].rv-in {
  opacity: 1;
  transform: none;
}

/* ====== Ticker (marquee strip) ======
   Markup ships the item run twice (second copy aria-hidden) so the
   loop is seamless without JS cloning. */
.ticker {
  overflow: hidden;
  position: relative;
}
.ticker-track {
  display: flex;
  width: max-content;
  animation: ticker-roll 36s linear infinite;
}
.ticker:hover .ticker-track { animation-play-state: paused; }
@keyframes ticker-roll {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

/* ====== Grain (dark sections only, very subtle) ====== */
.grain { position: relative; }
.grain::before {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  opacity: 0.05;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}


/* =============================================================
   SITE CHROME: header / nav / footer
   ============================================================= */

/* ====== Header ====== */
.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: rgba(12, 10, 6, 0.72);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid transparent;
  transition: border-color 0.25s var(--ease), background 0.25s var(--ease);
}
.site-header.is-scrolled {
  border-bottom-color: var(--hairline);
  background: rgba(12, 10, 6, 0.86);
}

.nav-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  height: 68px;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  color: var(--text);
}
.brand:hover { color: var(--text); }

/* Brand logo mark (cohort triangles). */
.brand-mark {
  display: block;
  width: 26px;
  height: 26px;
  flex: none;
  object-fit: contain;
  filter: drop-shadow(0 0 7px var(--accent-glow));
  transition: filter 0.25s var(--ease), transform 0.25s var(--ease);
}
.brand:hover .brand-mark {
  filter: drop-shadow(0 0 11px var(--accent-glow));
  transform: scale(1.04);
}

/* Header wordmark: the modern UI face for clarity at nav size. The
   Raffishly script stays reserved for display moments (footer brand,
   footer watermark). */
.brand-name {
  font-family: var(--font-sans);
  font-size: 20px;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--text);
}

.primary-nav {
  display: flex;
  align-items: center;
  gap: 30px;
}
.primary-nav a {
  font-family: var(--font-mono);
  font-size: 11.5px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--text-3);
  transition: color 0.15s var(--ease);
}
.primary-nav a:hover { color: var(--accent); }

.primary-nav .nav-signin {
  color: var(--text);
  border: 1px solid var(--border-2);
  border-radius: var(--radius-sm);
  padding: 9px 16px;
  transition: color 0.15s var(--ease), border-color 0.15s var(--ease), background 0.15s var(--ease);
}
.primary-nav .nav-signin:hover {
  color: var(--accent);
  border-color: var(--accent);
  background: var(--accent-soft);
}

.nav-github { display: inline-flex; color: var(--text-3); }
.nav-github:hover { color: var(--text); }

/* Hamburger */
.nav-toggle {
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 44px;
  height: 44px;
  padding: 10px;
  background: none;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  cursor: pointer;
}
.nav-toggle span {
  display: block;
  height: 1.5px;
  width: 100%;
  background: var(--text);
  transition: transform 0.25s var(--ease), opacity 0.2s var(--ease);
}
body.nav-open .nav-toggle span:nth-child(1) { transform: translateY(6.5px) rotate(45deg); }
body.nav-open .nav-toggle span:nth-child(2) { opacity: 0; }
body.nav-open .nav-toggle span:nth-child(3) { transform: translateY(-6.5px) rotate(-45deg); }

/* Mobile nav: drop-down console sheet */
.mobile-nav {
  display: none;
  flex-direction: column;
  border-top: 1px solid var(--hairline);
  background: var(--bg-2);
  padding: 10px 28px 26px;
}
body.nav-open .mobile-nav { display: flex; }
.mobile-nav a {
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--text-2);
  padding: 15px 0;
  border-bottom: 1px solid var(--hairline);
}
.mobile-nav a:last-child { border-bottom: none; }
.mobile-nav a:hover { color: var(--accent); }
.mobile-nav a::before {
  content: '> ';
  color: var(--accent);
}

/* ====== Footer ====== */
.site-footer {
  position: relative;
  border-top: 1px solid var(--hairline);
  background: var(--bg-2);
  padding: clamp(48px, 7vw, 88px) 0 36px;
  overflow: hidden;
}

.footer-grid {
  display: grid;
  grid-template-columns: 2fr 1fr 1fr 1fr 1fr;
  gap: 44px;
  position: relative;
  z-index: 1;
}

.footer-brand .brand-mark { margin-bottom: 14px; }
.footer-brand .brand-name {
  font-family: var(--font-brand);
  font-size: 26px;
  font-weight: 400;
  letter-spacing: 0.01em;
  display: block;
  margin-bottom: 10px;
}
.footer-tag {
  font-size: 13.5px;
  color: var(--text-3);
  max-width: 240px;
  font-style: italic;
  font-family: var(--font-display);
  font-size: 16px;
  line-height: 1.4;
}

.footer-col { display: flex; flex-direction: column; gap: 12px; }
.footer-col h4 { margin-bottom: 6px; }
.footer-col a {
  font-size: 13.5px;
  color: var(--text-2);
  width: fit-content;
}
.footer-col a:hover { color: var(--accent); }

.footer-bottom {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  flex-wrap: wrap;
  margin-top: clamp(40px, 6vw, 72px);
  padding-top: 22px;
  border-top: 1px solid var(--hairline);
  position: relative;
  z-index: 1;
}
.footer-bottom small {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.06em;
  color: var(--text-muted);
}
.footer-built::before {
  content: '+ ';
  color: var(--accent);
}

/* Oversized watermark wordmark behind the footer grid. */
.footer-wm {
  position: absolute;
  right: -1%;
  bottom: -30px;
  font-family: var(--font-brand);
  font-size: clamp(90px, 14vw, 200px);
  line-height: 1;
  color: var(--text);
  opacity: 0.035;
  pointer-events: none;
  user-select: none;
  white-space: nowrap;
}


/* =============================================================
   HOME PAGE SECTIONS
   ============================================================= */

/* ====== Hero ====== */
.hero {
  position: relative;
  padding: clamp(48px, 7vw, 96px) 0 clamp(56px, 8vw, 96px);
  overflow: hidden;
}

/* Layered backdrop: two accent radials, faint concentric radar rings
   emanating from behind the cockpit, and sparse registration "+"
   marks. Deliberately NOT the stock square line-grid. All decorative. */
.hero-bg {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  background:
    radial-gradient(1000px 520px at 50% 110%, rgba(92, 193, 212, 0.10), transparent 70%),
    radial-gradient(700px 380px at 12% -8%, rgba(122, 223, 242, 0.05), transparent 70%);
}
.hero-bg::after {
  content: '';
  position: absolute;
  inset: 0;
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='260' height='260'%3E%3Cpath d='M130 123v14M123 130h14' stroke='%23ecedf2' stroke-opacity='0.16' stroke-width='1'/%3E%3C/svg%3E"),
    repeating-radial-gradient(circle at 50% 96%,
      transparent 0,
      transparent 159px,
      rgba(236, 237, 242, 0.05) 159px,
      rgba(236, 237, 242, 0.05) 160px);
  background-size: 260px 260px, auto;
  background-position: 36px 22px, 0 0;
  mask-image: radial-gradient(ellipse 90% 80% at 50% 55%, black, transparent 80%);
  -webkit-mask-image: radial-gradient(ellipse 90% 80% at 50% 55%, black, transparent 80%);
}
.hero-stack {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(44px, 6vw, 72px);
}

.hero-copy {
  max-width: 880px;
  text-align: center;
  min-width: 0;
}

.hero-copy .eyebrow {
  margin-bottom: 26px;
  justify-content: center;
}

.hero-title {
  margin-bottom: 26px;
  font-size: clamp(3.1rem, 8vw, 6.2rem);
}
.hero-title .grad { display: block; }

.hero-sub {
  font-size: clamp(15.5px, 1.5vw, 18px);
  color: var(--text-2);
  margin-bottom: 34px;
  max-width: 600px;
  margin-left: auto;
  margin-right: auto;
}

.cta-row {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 14px;
  margin-bottom: 34px;
}

/* Mono readout chips */
.hero-meta {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 12px 26px;
}
.hero-meta li {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  color: var(--text-3);
  font-family: var(--font-mono);
  font-size: 11.5px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.12em;
}

/* ====== Hero visual: framed product cockpit ====== */
.hero-visual {
  position: relative;
  perspective: 2000px;
  width: 100%;
  max-width: 1120px;
  margin: 0 auto;
}

/* Figure label row above the mock - technical drawing caption. */
.visual-caption {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 12px;
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: var(--text-muted);
}
.visual-caption .vc-live {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  color: var(--text-3);
}
.visual-caption .vc-live::before {
  content: '';
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 10px var(--accent-glow);
  animation: vc-pulse 2.4s ease-in-out infinite;
}
@keyframes vc-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.35; }
}

/* Bracket frame floats just outside the mock. */
.hero-visual .visual-frame {
  position: absolute;
  inset: -14px;
  pointer-events: none;
  z-index: 2;
}

/* Accent landing-glow under the cockpit. */
.hero-visual::after {
  content: '';
  position: absolute;
  left: 8%;
  right: 8%;
  bottom: -34px;
  height: 70px;
  background: radial-gradient(ellipse at 50% 0%, var(--accent-glow), transparent 70%);
  opacity: 0.55;
  pointer-events: none;
}

/* ====== Supports ticker ====== */
.strip {
  border-top: 1px solid var(--hairline);
  border-bottom: 1px solid var(--hairline);
  background: var(--bg-2);
  padding: 0;
}
.strip-row {
  display: flex;
  align-items: stretch;
  gap: 0;
  padding: 0;
}
.strip-label {
  display: flex;
  align-items: center;
  flex-shrink: 0;
  padding: 18px 28px 18px 0;
  margin-right: 28px;
  border-right: 1px solid var(--hairline);
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  color: var(--text-3);
  white-space: nowrap;
}
.strip .ticker { flex: 1; min-width: 0; align-self: center; }
.strip-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  align-items: center;
  flex-shrink: 0;
}
.strip-list li {
  display: inline-flex;
  align-items: center;
  white-space: nowrap;
  font-family: var(--font-mono);
  font-size: 12.5px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: var(--text-2);
  padding-right: 18px;
}
.strip-list li::after {
  content: '+';
  margin-left: 18px;
  color: var(--accent);
  font-size: 13px;
}

/* ====== Generic dark section rhythm ====== */
.tour { padding: clamp(64px, 9vw, 120px) 0 clamp(48px, 7vw, 88px); }

/* ====== Why (paper editorial) ====== */
.why-section {
  padding: clamp(64px, 9vw, 120px) 0;
  border-top: 1px solid var(--hairline);
}

.why-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0;
  border-top: 1px solid var(--hairline-strong);
}

.why-card {
  position: relative;
  padding: 34px 30px 38px 0;
  margin-right: 30px;
  border-right: 1px solid var(--hairline);
}
.why-card:last-child { border-right: none; margin-right: 0; }

.why-num {
  display: block;
  font-family: var(--font-display);
  font-style: italic;
  font-size: 44px;
  line-height: 1;
  color: var(--accent);
  margin-bottom: 20px;
}

.why-card h3 {
  font-size: 20px;
  margin-bottom: 12px;
}
.why-card p {
  font-size: 14.5px;
  line-height: 1.65;
  color: var(--text-2);
}

.why-icon {
  position: absolute;
  top: 38px;
  right: 30px;
  color: var(--text-3);
  opacity: 0.7;
}

/* ====== Features bento ====== */
.features { padding: clamp(64px, 9vw, 120px) 0; }

.bento {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: 14px;
}

.cohort-card {
  position: relative;
  grid-column: span 4;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: 0;
  min-height: 218px;
  padding: 24px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  transition: border-color 0.22s var(--ease), background 0.22s var(--ease),
              transform 0.22s var(--ease);
}
.cohort-card:hover {
  border-color: var(--border-2);
  background: var(--surface-2);
  transform: translateY(-3px);
}

/* Corner brackets appear on hover. */
.cohort-card::after {
  content: '';
  position: absolute;
  inset: 8px;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.22s var(--ease);
  background-image:
    linear-gradient(var(--card-accent, var(--accent)), var(--card-accent, var(--accent))),
    linear-gradient(var(--card-accent, var(--accent)), var(--card-accent, var(--accent))),
    linear-gradient(var(--card-accent, var(--accent)), var(--card-accent, var(--accent))),
    linear-gradient(var(--card-accent, var(--accent)), var(--card-accent, var(--accent))),
    linear-gradient(var(--card-accent, var(--accent)), var(--card-accent, var(--accent))),
    linear-gradient(var(--card-accent, var(--accent)), var(--card-accent, var(--accent))),
    linear-gradient(var(--card-accent, var(--accent)), var(--card-accent, var(--accent))),
    linear-gradient(var(--card-accent, var(--accent)), var(--card-accent, var(--accent)));
  background-repeat: no-repeat;
  background-size: 12px 1px, 1px 12px, 12px 1px, 1px 12px, 12px 1px, 1px 12px, 12px 1px, 1px 12px;
  background-position:
    left top, left top, right top, right top,
    left bottom, left bottom, right bottom, right bottom;
}
.cohort-card:hover::after { opacity: 1; }

/* Two featured tiles up top. */
.cohort-card--wide { grid-column: span 7; min-height: 250px; }
.cohort-card--mid  { grid-column: span 5; min-height: 250px; }
.cohort-card--bar {
  grid-column: span 12;
  min-height: 0;
  flex-direction: row;
  /* Base cards justify flex-end for the column layout; in a row that
     shoves the copy to the right edge. Anchor the bar left instead. */
  justify-content: flex-start;
  align-items: center;
  gap: 20px;
  /* Right padding clears the absolutely-positioned [09] index. */
  padding: 20px 88px 20px 24px;
}
.cohort-card--bar .cohort-card__icon { position: static; flex-shrink: 0; }
.cohort-card--bar .cohort-card__text {
  display: flex;
  align-items: baseline;
  gap: 8px 18px;
  flex-wrap: wrap;
}
.cohort-card--bar .cohort-card__text h3 { white-space: nowrap; }
.cohort-card--bar .cohort-card__text p { max-width: none; flex: 1 1 480px; }

.cohort-card__no {
  position: absolute;
  top: 18px;
  right: 20px;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.14em;
  color: var(--text-muted);
}
.cohort-card__no::before { content: '['; color: var(--card-accent, var(--accent)); margin-right: 3px; }
.cohort-card__no::after  { content: ']'; color: var(--card-accent, var(--accent)); margin-left: 3px; }

.cohort-card__icon {
  position: absolute;
  top: 20px;
  left: 22px;
  width: 22px;
  height: 22px;
  color: var(--card-accent, var(--accent));
  opacity: 0.9;
}
.cohort-card__icon svg { width: 22px; height: 22px; }

/* Oversized ghost watermark icon. */
.cohort-card__wm {
  position: absolute;
  right: -26px;
  bottom: -30px;
  width: 150px;
  height: 150px;
  color: var(--card-accent, var(--accent));
  opacity: 0.05;
  pointer-events: none;
  transition: opacity 0.22s var(--ease), transform 0.22s var(--ease);
}
.cohort-card__wm svg { width: 150px; height: 150px; }
.cohort-card:hover .cohort-card__wm { opacity: 0.1; transform: rotate(-4deg); }

.cohort-card__text h3 { font-size: 16.5px; margin-bottom: 8px; }
.cohort-card__text p { font-size: 13.5px; line-height: 1.6; color: var(--text-2); max-width: 420px; }
.cohort-card--bar .cohort-card__text h3 { margin-bottom: 0; }

/* Subdued per-card accent hues tuned for the warm ink ground. */
.cohort-card[data-accent="cyan"]   { --card-accent: #5cc1d4; }
.cohort-card[data-accent="lime"]   { --card-accent: #a9c082; }
.cohort-card[data-accent="blue"]   { --card-accent: #82a8d8; }
.cohort-card[data-accent="violet"] { --card-accent: #a695d6; }
.cohort-card[data-accent="teal"]   { --card-accent: #6dbcab; }
.cohort-card[data-accent="green"]  { --card-accent: #7ab36a; }
.cohort-card[data-accent="amber"]  { --card-accent: #d9a050; }
.cohort-card[data-accent="orange"] { --card-accent: #e89968; }
.cohort-card[data-accent="pink"]   { --card-accent: #d489a4; }

/* ====== Plugins preview (paper) ====== */
.plugins-preview {
  padding: clamp(64px, 9vw, 120px) 0;
}

.plugin-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 14px;
}

.plugin-card {
  position: relative;
  padding: 22px 20px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  transition: border-color 0.2s var(--ease), transform 0.2s var(--ease),
              box-shadow 0.2s var(--ease);
}
.plugin-card:hover {
  border-color: var(--accent);
  transform: translateY(-3px);
  box-shadow: 0 14px 30px -18px rgba(10, 14, 24, 0.35);
}

.plugin-icon {
  width: 34px;
  height: 34px;
  display: grid;
  place-items: center;
  margin-bottom: 14px;
  color: var(--accent);
  background: var(--accent-soft);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}
.plugin-icon svg { width: 17px; height: 17px; }

.plugin-card-head {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 6px;
}
.plugin-card-head h3 { font-size: 15px; }

.plugin-card p {
  font-size: 13px;
  line-height: 1.55;
  color: var(--text-2);
}

.plugin-badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-family: var(--font-mono);
  font-size: 9px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  padding: 3px 7px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border-2);
  color: var(--text-3);
}
.plugin-badge.experimental {
  color: var(--orange);
  border-color: currentColor;
}

.plugin-preview-fallback { font-size: 14px; }

/* Build-your-own call-out: framed hairline strip. */
.plugin-byo {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 32px;
  margin-top: 44px;
  padding: 26px 28px;
  border: 1px dashed var(--border-2);
  border-radius: var(--radius);
}
.plugin-byo h3 { font-size: 17px; margin-bottom: 6px; }
.plugin-byo p { font-size: 13.5px; max-width: 560px; }
.plugin-byo .link-arrow { flex-shrink: 0; }

/* ====== Pricing ====== */
.pricing {
  position: relative;
  padding: clamp(64px, 9vw, 120px) 0;
  border-top: 1px solid var(--hairline);
}

.pricing-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 14px;
  align-items: stretch;
}

.plan {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: 30px 28px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  transition: border-color 0.2s var(--ease);
}
.plan:hover { border-color: var(--border-2); }

.plan-feature {
  border-color: var(--accent);
  background:
    linear-gradient(180deg, var(--accent-soft), transparent 36%),
    var(--surface);
  box-shadow: 0 18px 56px -30px var(--accent-glow);
}
.plan-feature:hover { border-color: var(--accent-2); }

.plan-head { margin-bottom: 20px; }

.plan-badge {
  position: absolute;
  top: -11px;
  left: 24px;
  display: inline-flex;
  padding: 4px 10px;
  background: var(--accent);
  color: #0a1518;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  border-radius: var(--radius-sm);
}

.plan-name {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 30px;
  margin-bottom: 4px;
}
.plan-tagline {
  font-size: 13px;
  color: var(--text-3);
  margin-bottom: 18px;
}

.plan-price {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 7px;
}
.plan-price-regular { display: inline-flex; align-items: baseline; gap: 7px; }
.plan-price-amount {
  font-family: var(--font-display);
  font-size: 42px;
  line-height: 1;
  color: var(--text);
}
.plan-price-period {
  font-family: var(--font-mono);
  font-size: 11.5px;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--text-3);
}
.plan-meta {
  margin-top: 10px;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.plan-features {
  list-style: none;
  margin: 0 0 26px;
  padding: 20px 0 0;
  border-top: 1px solid var(--hairline);
  display: flex;
  flex-direction: column;
  gap: 11px;
  flex: 1;
}
.plan-features li {
  display: flex;
  gap: 10px;
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--text-2);
}
.check {
  color: var(--accent);
  font-family: var(--font-mono);
  font-size: 12px;
  flex-shrink: 0;
  line-height: 1.7;
}
.coming {
  color: var(--text-muted);
  font-size: 12px;
}

.plan-cta { width: 100%; }

/* ====== Waitlist offer card ====== */
.waitlist { margin-top: 44px; }
.waitlist-card {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 32px;
  padding: 30px 32px;
  background:
    linear-gradient(120deg, var(--accent-soft), transparent 55%),
    var(--surface);
  border: 1px solid var(--accent);
  border-radius: var(--radius);
  position: relative;
  overflow: hidden;
}
.waitlist-card h3 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 26px;
  margin: 12px 0 8px;
}
.waitlist-card p { font-size: 14px; max-width: 520px; }
.waitlist-card .btn { flex-shrink: 0; }

/* ====== Closer ====== */
.closer {
  position: relative;
  padding: clamp(80px, 11vw, 150px) 0;
  border-top: 1px solid var(--hairline);
  overflow: hidden;
}
.closer::before {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(800px 400px at 50% 120%, var(--accent-soft), transparent 70%);
}

.closer-grid {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 34px;
}
.closer-grid h2 {
  font-size: clamp(2.4rem, 5.6vw, 4.4rem);
  max-width: 820px;
  margin-bottom: 16px;
}
.closer-grid p {
  max-width: 560px;
  margin: 0 auto;
  font-size: 15.5px;
}
.closer-cta {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 14px;
}


/* =============================================================
   SECONDARY PAGES (plugins / mission / download / enterprise / 404)
   ============================================================= */

/* ====== Shared page hero ====== */
.page-hero {
  position: relative;
  padding: clamp(56px, 8vw, 110px) 0 clamp(44px, 6vw, 80px);
  overflow: hidden;
}
.page-hero .hero-bg {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  background: radial-gradient(820px 420px at 18% -12%, rgba(92, 193, 212, 0.08), transparent 70%);
}
.page-hero .hero-bg::after {
  content: '';
  position: absolute;
  inset: 0;
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='260' height='260'%3E%3Cpath d='M130 123v14M123 130h14' stroke='%23ecedf2' stroke-opacity='0.16' stroke-width='1'/%3E%3C/svg%3E");
  background-size: 260px 260px;
  background-position: 36px 22px;
  mask-image: radial-gradient(ellipse 80% 80% at 30% 0%, black, transparent 80%);
  -webkit-mask-image: radial-gradient(ellipse 80% 80% at 30% 0%, black, transparent 80%);
}
.page-hero .container { position: relative; z-index: 1; }
.page-hero .eyebrow { margin-bottom: 22px; }
.page-hero h1 {
  font-size: clamp(2.7rem, 6.4vw, 4.8rem);
  max-width: 880px;
  margin-bottom: 22px;
}
.page-hero-sub {
  font-size: clamp(15px, 1.4vw, 17.5px);
  color: var(--text-2);
  max-width: 620px;
  margin-bottom: 30px;
}
.page-hero-meta {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 12px 26px;
}
.page-hero-meta li {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  color: var(--text-3);
  font-family: var(--font-mono);
  font-size: 11.5px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.12em;
}

/* ====== Plugins: how it works ====== */
.how { padding: clamp(56px, 8vw, 100px) 0; }

.how-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 14px;
  margin-bottom: 40px;
}
.how-card {
  position: relative;
  padding: 26px 24px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
.how-step {
  font-family: var(--font-display);
  font-style: italic;
  font-size: 36px;
  line-height: 1;
  color: var(--accent);
  margin-bottom: 16px;
}
.how-card h3 { font-size: 16.5px; margin-bottom: 8px; }
.how-card p { font-size: 13.5px; line-height: 1.6; }
.how-card .muted { color: var(--text-muted); font-weight: 400; font-size: 13px; }

/* Code blocks: terminal readouts. */
.code-block {
  margin-top: 18px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg-2);
  overflow: hidden;
}
.code-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 10px 16px;
  border-bottom: 1px solid var(--border);
  background: var(--surface);
}
.code-tab {
  font-family: var(--font-mono);
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-3);
}
.code-tab::before { content: '$ '; color: var(--accent); }
.copy-btn {
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--text-3);
  background: none;
  border: 1px solid var(--border-2);
  border-radius: var(--radius-sm);
  padding: 5px 12px;
  cursor: pointer;
  transition: color 0.15s var(--ease), border-color 0.15s var(--ease);
}
.copy-btn:hover { color: var(--accent); border-color: var(--accent); }
.copy-btn.is-copied { color: var(--green); border-color: var(--green); }
.code-block pre { padding: 18px 20px; }

/* Syntax token palette (warm console). */
.tok-key { color: var(--accent-2); }
.tok-str { color: #d9a050; }
.tok-num { color: #e89968; }
.tok-kw  { color: #a695d6; }
.tok-fn  { color: #7ab36a; }
.tok-id  { color: var(--text-2); }
.tok-pun { color: var(--text-3); }

/* ====== Plugins: built-ins catalog (paper) ====== */
.builtins { padding: clamp(56px, 8vw, 100px) 0; }

.builtin-list {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
}
.builtin {
  display: flex;
  gap: 18px;
  padding: 24px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  transition: border-color 0.2s var(--ease), transform 0.2s var(--ease),
              box-shadow 0.2s var(--ease);
}
.builtin:hover {
  border-color: var(--accent);
  transform: translateY(-2px);
  box-shadow: 0 14px 30px -18px rgba(10, 14, 24, 0.3);
}
.builtin-id { flex-shrink: 0; }
.builtin-tag {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--accent);
  border: 1px solid var(--border-2);
  border-radius: var(--radius-sm);
  padding: 4px 8px;
  background: var(--accent-soft);
}
.builtin-head {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 6px;
}
.builtin-head h3 { font-size: 16px; }
.builtin-body p { font-size: 13.5px; line-height: 1.6; }
.builtin-meta {
  list-style: none;
  margin: 12px 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 6px 14px;
}
.builtin-meta li {
  font-family: var(--font-mono);
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-3);
}
.builtin-meta li::before { content: '+ '; color: var(--accent); }
.builtin-cta { margin-top: 14px; }
.builtin-link {
  font-family: var(--font-mono);
  font-size: 11.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.1em;
}
.builtin-fallback { font-size: 14px; }

/* ====== Plugins: trust model ====== */
.trust {
  padding: clamp(56px, 8vw, 100px) 0;
  border-top: 1px solid var(--hairline);
}
.trust-grid {
  display: grid;
  grid-template-columns: 1fr 1.6fr;
  gap: 56px;
  align-items: start;
}
.trust-grid .eyebrow { margin-bottom: 18px; }
.trust-grid h2 { font-size: clamp(1.9rem, 3.4vw, 2.7rem); }
.trust-points {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0;
  border-top: 1px solid var(--hairline-strong);
}
.trust-point {
  padding: 24px 24px 28px 0;
  border-bottom: 1px solid var(--hairline);
}
.trust-point:nth-child(odd) { border-right: 1px solid var(--hairline); }
.trust-point:nth-child(even) { padding-left: 24px; padding-right: 0; }
.trust-point:nth-last-child(-n+2) { border-bottom: none; }
.trust-point h3 { font-size: 15.5px; margin-bottom: 8px; }
.trust-point h3::before {
  content: '+ ';
  color: var(--accent);
  font-family: var(--font-mono);
}
.trust-point p { font-size: 13.5px; line-height: 1.6; }

/* ====== Mission ====== */
.mission-why { padding: clamp(56px, 8vw, 100px) 0 clamp(40px, 6vw, 72px); }

.prose {
  max-width: 720px;
  display: flex;
  flex-direction: column;
  gap: 20px;
}
.prose p {
  font-size: clamp(15.5px, 1.4vw, 17.5px);
  line-height: 1.75;
  color: var(--text-2);
}
.prose-emphasis {
  font-family: var(--font-display);
  font-style: italic;
  font-size: clamp(20px, 2.4vw, 28px) !important;
  line-height: 1.4 !important;
  color: var(--text) !important;
  border-left: 2px solid var(--accent);
  padding-left: 22px;
  margin-top: 8px;
}

/* Manifesto: paper ledger of tenets. */
.manifesto { padding: clamp(64px, 9vw, 120px) 0; }

.tenet-list {
  list-style: none;
  margin: 0;
  padding: 0;
  counter-reset: tenet;
  border-top: 1px solid var(--hairline-strong);
}
.tenet {
  display: grid;
  grid-template-columns: 120px 1fr;
  gap: 28px;
  padding: 30px 0;
  border-bottom: 1px solid var(--hairline);
}
.tenet-num {
  font-family: var(--font-display);
  font-style: italic;
  font-size: 44px;
  line-height: 1;
  color: var(--accent);
}
.tenet-body h3 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(20px, 2.4vw, 27px);
  margin-bottom: 10px;
}
.tenet-body p {
  font-size: 15px;
  line-height: 1.7;
  max-width: 640px;
}

.vision { padding: clamp(56px, 8vw, 100px) 0; }

/* ====== Download ====== */
.download-page { padding: clamp(56px, 8vw, 100px) 0 clamp(48px, 7vw, 80px); position: relative; }
.download-page .section-head h1 {
  font-size: clamp(2.6rem, 5.6vw, 4.2rem);
  margin-bottom: 16px;
}
.download-page .section-head { max-width: 760px; }

.download-prelaunch {
  max-width: 560px;
  margin: 0 auto 48px;
  text-align: center;
  padding: 34px 30px;
  background:
    linear-gradient(160deg, var(--accent-soft), transparent 60%),
    var(--surface);
  border: 1px solid var(--accent);
  border-radius: var(--radius);
}
.download-prelaunch h3 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 26px;
  margin-bottom: 10px;
}
.download-prelaunch p { font-size: 14.5px; margin-bottom: 20px; }

.download-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 14px;
  margin-bottom: 26px;
}
.download-card {
  display: flex;
  align-items: center;
  gap: 18px;
  padding: 24px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--text);
  transition: border-color 0.2s var(--ease), transform 0.2s var(--ease),
              box-shadow 0.2s var(--ease);
}
.download-card:hover {
  color: var(--text);
  border-color: var(--accent);
  transform: translateY(-3px);
  box-shadow: 0 18px 44px -26px var(--accent-glow);
}
.download-os {
  width: 52px;
  height: 52px;
  display: grid;
  place-items: center;
  flex-shrink: 0;
  color: var(--accent);
  background: var(--accent-soft);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}
.download-text { flex: 1; min-width: 0; }
.download-os-name { font-weight: 600; font-size: 16px; }
.download-meta {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.04em;
  color: var(--text-3);
  margin-top: 4px;
}
.download-arrow {
  font-family: var(--font-mono);
  font-size: 18px;
  color: var(--text-3);
  transition: color 0.2s var(--ease), transform 0.2s var(--ease);
}
.download-card:hover .download-arrow { color: var(--accent); transform: translateY(3px); }

.download-note {
  text-align: center;
  font-size: 13.5px;
  color: var(--text-3);
}

/* ====== Enterprise hero tweak ====== */
.enterprise-form-section { padding-top: 8px; }

/* ====== 404 ====== */
.not-found {
  position: relative;
  padding: clamp(90px, 14vw, 170px) 0;
  overflow: hidden;
  text-align: center;
}
.not-found .hero-bg {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(700px 380px at 50% 120%, rgba(92, 193, 212, 0.10), transparent 70%);
}
.not-found .hero-bg::after {
  content: '';
  position: absolute;
  inset: 0;
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='260' height='260'%3E%3Cpath d='M130 123v14M123 130h14' stroke='%23ecedf2' stroke-opacity='0.16' stroke-width='1'/%3E%3C/svg%3E"),
    repeating-radial-gradient(circle at 50% 50%,
      transparent 0,
      transparent 139px,
      rgba(236, 237, 242, 0.05) 139px,
      rgba(236, 237, 242, 0.05) 140px);
  background-size: 260px 260px, auto;
  background-position: 36px 22px, 0 0;
  mask-image: radial-gradient(ellipse 70% 70% at 50% 50%, black, transparent 80%);
  -webkit-mask-image: radial-gradient(ellipse 70% 70% at 50% 50%, black, transparent 80%);
}
.not-found-inner {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0;
}
.not-found .eyebrow { margin-bottom: 22px; }
.not-found-title { margin-bottom: 18px; }
.not-found-sub {
  max-width: 460px;
  margin-bottom: 30px;
  font-size: 15px;
}
.not-found .cta-row { margin-bottom: 0; }

/* ====== Page responsive ====== */
@media (max-width: 980px) {
  .how-grid { grid-template-columns: 1fr; }
  .builtin-list { grid-template-columns: 1fr; }
  .trust-grid { grid-template-columns: 1fr; gap: 32px; }
  .tenet { grid-template-columns: 72px 1fr; gap: 18px; }
}

@media (max-width: 720px) {
  .trust-points { grid-template-columns: 1fr; }
  .trust-point,
  .trust-point:nth-child(even) { padding-left: 0; padding-right: 0; border-right: none; }
  .trust-point:nth-child(odd) { border-right: none; }
  .trust-point:nth-last-child(-n+2) { border-bottom: 1px solid var(--hairline); }
  .trust-point:last-child { border-bottom: none; }
  .tenet { grid-template-columns: 1fr; gap: 10px; padding: 24px 0; }
  .tenet-num { font-size: 32px; }
  .builtin { flex-direction: column; gap: 12px; }
}


/* =============================================================
   PRODUCT PALETTE SCOPE
   The app mock + its demos mirror the real Agent Cohort UI, so
   they keep the app's Cool Slate palette regardless of the site
   theme. Token names match the global set; values are the v1
   originals, re-pinned for the mock subtree only.
   ============================================================= */
.app-mock {
  /* Surfaces */
  --bg:           #0a0a0f;
  --bg-2:         #0e0e15;
  --surface:      #14141c;
  --surface-2:    #1a1a23;
  --surface-3:    #21212c;
  --border:       #24242f;
  --border-2:     #2e2e3a;
  --border-soft:  rgba(255, 255, 255, 0.06);

  /* Text */
  --text:         #ecedf2;
  --text-2:       #b6b8c4;
  --text-3:       #888a98;
  --text-muted:   #5d5f6c;

  /* Accent - Cool Slate (the app's default palette) */
  --accent:       #5cc1d4;
  --accent-2:     #7adff2;
  --accent-soft:  rgba(92, 193, 212, 0.12);
  --accent-glow:  rgba(92, 193, 212, 0.35);

  /* Secondary accents for chips / status */
  --orange:       #e89968;
  --green:        #7ab36a;
  --amber:        #d9a050;
  --red:          #d77780;
  --blue:         #82a8d8;

  /* The app's own type + geometry */
  --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI Variable', 'Segoe UI', system-ui, sans-serif;
  --radius: 12px;
  --radius-lg: 16px;
  --radius-sm: 8px;
}



/* ============ PORTED FROM v1: app mock + hero demos (lines 549-5096) ============ */
/* =============================================================
   App mock (hero visual) - mirrors the real Agent Cohort UI
   so the marketing surface looks like the product. Structure:
   .am-header (project chip + agent picker + plugin toolbar +
   search + window controls), .am-grid (1 large focused term +
   2 stacked terms), .am-statusbar.
   ============================================================= */

.app-mock {
  position: relative;
  border-radius: 12px;
  overflow: hidden;
  background: var(--bg-2);
  border: 1px solid var(--border);
  box-shadow:
    0 30px 80px -20px rgba(0, 0, 0, 0.7),
    0 0 0 1px rgba(255, 255, 255, 0.03),
    0 18px 60px -28px var(--accent-glow);
  transform: rotate3d(0, 1, 0, -1.5deg) rotate3d(1, 0, 0, 0.5deg);
  transform-origin: center;
  transition: transform 0.4s var(--ease);
  font-family: var(--font-sans);
}
.app-mock:hover { transform: rotate3d(0, 1, 0, 0deg); }

/* ---- Header ---- */
.am-header {
  position: relative;
  height: 40px;
  padding: 0 0 0 10px;
  display: flex;
  align-items: center;
  gap: 7px;
  background: var(--surface);
  flex-shrink: 0;
}
.am-header::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0; height: 1px;
  background: linear-gradient(90deg, transparent 0%, var(--accent) 18%, var(--accent) 82%, transparent 100%);
  opacity: 0.55;
}
.am-icon {
  width: 22px; height: 22px;
  border-radius: 6px;
  flex-shrink: 0;
  object-fit: cover;
  /* Source PNG already paints its own dark backdrop + accent peaks; the
     subtle outer ring + glow keep parity with the production AppLogo
     (.dock-header-app-icon-glow) without competing with the artwork. */
  box-shadow:
    0 0 0 1px rgba(255, 255, 255, 0.08),
    0 1px 2px rgba(0, 0, 0, 0.45),
    0 0 14px -2px var(--accent-glow);
  user-select: none;
  -webkit-user-drag: none;
}
.am-divider {
  width: 1px; height: 20px;
  background: var(--border);
  margin: 0 1px;
  flex-shrink: 0;
}

/* New-terminal "+" button. Mirrors `.dock-header-btn-primary` in the
   production DockShell.css: accent-tinted background + inset accent
   border, ~28px-tall pill. The terminal-spawn demo (assets/script.js)
   animates a pulse ring around this button when the cursor clicks it. */
.am-add-term {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 22px;
  padding: 0;
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  color: var(--accent);
  border: none;
  border-radius: 6px;
  cursor: default;
  flex-shrink: 0;
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 35%, transparent);
  /* Block native focus rings - this button is visual-only in the
     marketing surface; it never receives keyboard focus. */
  outline: none;
}
.am-add-term:focus-visible {
  /* Decorative; should never actually focus, but be safe. */
  outline: none;
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 60%, transparent),
              0 0 0 2px color-mix(in srgb, var(--accent) 35%, transparent);
}

.am-project {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 26px;
  padding: 0 10px 0 9px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 7px;
  font-size: 12px;
  color: var(--text);
  flex-shrink: 0;
}
.am-accent-dot {
  width: 9px; height: 9px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.25) inset, 0 0 8px var(--accent-glow);
}
.am-project-name { font-weight: 500; }
.am-project-sub { color: var(--text-3); font-size: 11px; }
.am-chev { width: 10px; height: 10px; color: var(--text-3); margin-left: 1px; }

/* Agent picker */
.am-agents {
  display: inline-flex;
  gap: 2px;
  padding: 3px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 7px;
  flex-shrink: 0;
}
.am-agent {
  height: 20px;
  padding: 0 9px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  color: var(--text-2);
  border-radius: 4px;
}
.am-agent.active {
  background: var(--bg-2);
  color: var(--text);
  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25), inset 0 0 0 1px rgba(255, 255, 255, 0.03);
}
.am-agent-icon {
  width: 10px; height: 10px;
  border-radius: 2px;
  flex-shrink: 0;
}
.am-agent-icon.claude { background: linear-gradient(135deg, #e89968, #c97144); }
.am-agent-icon.codex  { background: linear-gradient(135deg, #25d491, #128a5b); }
.am-agent-icon.shell  { background: linear-gradient(135deg, #888, #555); }

/* Plugin toolbar */
.am-plugins {
  display: inline-flex;
  align-items: center;
  gap: 1px;
  height: 28px;
  padding: 1px;
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: 7px;
  flex-shrink: 0;
}
.am-plugin {
  position: relative;
  width: 24px; height: 24px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--text-3);
  border-radius: 5px;
}
.am-plugin svg {
  width: 13px; height: 13px;
  stroke-width: 1.5;
}
.am-plugin.active {
  background: var(--accent-soft);
  color: var(--accent);
}
.am-plugin-count {
  position: absolute;
  top: -2px; right: -2px;
  min-width: 13px; height: 12px;
  padding: 0 3px;
  background: var(--accent);
  color: #0a1518;
  font-family: var(--font-sans);
  font-size: 9px;
  font-weight: 700;
  line-height: 1;
  border-radius: 7px;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 0 0 1.5px var(--bg-2);
}
.am-plugin-dot {
  position: absolute;
  top: 4px; right: 4px;
  width: 5px; height: 5px;
  border-radius: 50%;
  box-shadow: 0 0 0 1.5px var(--bg-2);
}
.am-plugin-dot.ok { background: var(--green); }

.am-spacer { flex: 1; min-width: 6px; }

/* Terminal Spaces strip - mirrors src/renderer/.../SpacesStrip.css.
   Recessed dark "track" with pill-style tabs. */
.am-spaces {
  display: inline-flex;
  align-items: center;
  flex: 1 1 auto;
  min-width: 0;
  height: 28px;
  margin: 0 4px;
  padding: 2px 4px;
  gap: 2px;
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: 7px;
  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.25);
  overflow: hidden;
}
.am-space {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: 20px;
  padding: 0 8px 0 10px;
  border-radius: 4px;
  font-size: 10.5px;
  font-weight: 500;
  color: var(--text-3);
  white-space: nowrap;
  flex-shrink: 0;
}
.am-space.active {
  background: var(--surface-2);
  color: var(--text);
  box-shadow: inset 2px 0 0 0 var(--accent);
}
.am-space-default { padding-right: 14px; }
.am-space-dot {
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--green);
  box-shadow: 0 0 4px rgba(122, 179, 106, 0.55);
}
.am-space-icon { font-size: 11px; line-height: 1; }
.am-space-name { font-size: 10.5px; }
.am-space-add {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  border-radius: 4px;
  color: var(--text-3);
  font-size: 14px;
  font-weight: 400;
  flex-shrink: 0;
}

.am-search {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 26px;
  padding: 0 9px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 6px;
  color: var(--text-3);
  font-size: 11.5px;
  flex-shrink: 0;
}
.am-search svg { width: 11px; height: 11px; }
.am-search-text { display: inline-block; }
.am-kbd {
  margin-left: 2px;
  font-size: 10px;
  font-family: var(--font-mono);
  color: var(--text-3);
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: 3px;
  padding: 1px 5px;
}

.am-win-controls { display: flex; align-self: stretch; margin-left: 4px; flex-shrink: 0; }
.am-win-btn {
  width: 38px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-3);
}
.am-win-btn svg { width: 9px; height: 9px; }

/* ---- Terminal grid ---- */
.am-grid {
  display: grid;
  grid-template-columns: 1.4fr 1fr;
  grid-template-rows: 1fr 1fr;
  gap: 6px;
  padding: 6px;
  background: var(--bg-2);
  height: 360px;
}
.am-term-large { grid-row: 1 / 3; }

.am-term {
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 7px;
  overflow: hidden;
  position: relative;
}
.am-term.focused {
  border-color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent), 0 8px 24px rgba(0, 0, 0, 0.35);
}

/* Small mode - matches the app's compact terminal header tier */
.am-term-header {
  height: 22px;
  padding: 0 8px;
  display: flex;
  align-items: center;
  gap: 6px;
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
  font-size: 10.5px;
  flex-shrink: 0;
}
.am-agent-badge {
  width: 12px; height: 12px;
  border-radius: 2px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 8px;
  font-weight: 700;
  color: white;
  flex-shrink: 0;
  letter-spacing: -0.02em;
  font-family: var(--font-sans);
}
.am-agent-badge.claude { background: linear-gradient(135deg, #e89968, #c97144); }
.am-agent-badge.codex  { background: linear-gradient(135deg, #25d491, #128a5b); }
.am-agent-badge.shell  { background: linear-gradient(135deg, #777, #444); }

.am-term-title { color: var(--text); font-weight: 500; }
.am-term-meta { color: var(--text-3); font-size: 10px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.am-term-spacer { flex: 1; }
.am-term-status {
  width: 7px; height: 7px;
  border-radius: 50%;
  flex-shrink: 0;
}
.am-term-status.idle { background: var(--text-muted); }
.am-term-status.active {
  background: var(--green);
  box-shadow: 0 0 0 3px rgba(122, 179, 106, 0.18);
  animation: am-pulse 1.6s ease-in-out infinite;
}
.am-term-status.attention { background: var(--amber); box-shadow: 0 0 0 3px rgba(217, 160, 80, 0.18); }

@keyframes am-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.55; }
}

.am-term-body {
  flex: 1;
  padding: 10px 12px;
  background: #0a0c0f;
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1.6;
  color: #cfd6dc;
  overflow: hidden;
  white-space: pre-wrap;
  word-break: break-word;
}
.am-term-body .am-accent { color: var(--accent); }
.am-term-body .am-path   { color: #82a8d8; }
.am-term-body .am-ok     { color: var(--green); }
.am-term-body .am-err    { color: var(--red); }
.am-term-body .am-warn   { color: var(--amber); }
.am-term-body .am-dim    { color: #6b6b6b; }
.am-term-body .am-hl     { color: #f0e0c2; }
.am-term-body .am-key    { color: #c49bd6; }
.am-term-body .am-str    { color: #98c379; }
.am-cursor {
  display: inline-block;
  width: 6px; height: 13px;
  background: var(--accent);
  vertical-align: -2px;
  animation: am-blink 1.1s steps(2, start) infinite;
}
@keyframes am-blink { 50% { opacity: 0; } }

/* ---- Status bar ---- */
.am-statusbar {
  height: 24px;
  padding: 0 12px;
  display: flex;
  align-items: center;
  gap: 16px;
  background: var(--surface);
  border-top: 1px solid var(--border);
  font-size: 10.5px;
  color: var(--text-3);
  flex-shrink: 0;
}
.am-status-item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  white-space: nowrap;
}
.am-status-item svg { width: 10px; height: 10px; }
.am-status-ok svg { color: var(--green); }
.am-status-dot {
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 6px var(--accent-glow);
}
.am-status-spacer { flex: 1; }

/* Randomize toggle. Sits at the right edge of the statusbar; flips
   the orchestrator's order between "sequence" and "random" via the
   public CohortHero.configure() API. JS sets aria-pressed + a state
   class to reveal the correct icon. */
.am-shuffle-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 18px;
  padding: 0;
  margin-left: 2px;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 4px;
  color: var(--text-3);
  cursor: pointer;
  outline: none;
  transition: color 100ms ease, background-color 100ms ease, border-color 100ms ease;
  position: relative;
}
.am-shuffle-toggle:hover {
  color: var(--text-2);
  background: color-mix(in srgb, var(--text-3) 12%, transparent);
}
.am-shuffle-toggle:focus-visible {
  border-color: var(--accent);
  color: var(--text);
}
/* When randomize is ON, light the toggle accent + show the shuffle
   icon (and hide the sequence one). Default (off) shows sequence. */
.am-shuffle-toggle[aria-pressed="true"] {
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  border-color: color-mix(in srgb, var(--accent) 30%, transparent);
}
.am-shuffle-toggle .am-shuffle-icon { display: none; }
.am-shuffle-toggle .am-sequence-icon { display: inline-block; }
.am-shuffle-toggle[aria-pressed="true"] .am-shuffle-icon { display: inline-block; }
.am-shuffle-toggle[aria-pressed="true"] .am-sequence-icon { display: none; }

/* =============================================================
   App-mock animation system - "hero demos"
   -----------------------------------------------------------------
   The hero mock plays a registry of demos one at a time. Each demo
   is a self-contained overlay markup + CSS scope + JS hook:

     - HTML: <div class="am-demo am-demo-<id>" data-demo-id="<id>" ...>
             inside .app-mock. Multiple demos can coexist as siblings.

     - CSS: animations gated on `.am-demo-<id>.is-playing X` for
             elements INSIDE the demo wrapper, and on
             `.app-mock[data-active-demo="<id>"].is-anim-playing X`
             for effects that fire on elements OUTSIDE the wrapper
             (e.g. the focused terminal flash for the browser-plugin
             demo). Per-demo timing tokens live on the wrapper rule
             so designers can retune one demo without touching the
             others.

     - JS: register with `CohortHero.register('<id>', { duration,
             onMeasure, onPlay })`. The orchestrator handles initial
             delay, ordering (sequence / random / shuffle), pausing
             on visibility / IO / breakpoint / motion changes, and
             cycle teardown.

   The first demo is "browser-plugin" - it mirrors
   shared/plugins/browser/renderer/BrowserPanel.tsx so the marketing
   surface and the product read as one product.

   Accessibility:
   - aria-hidden="true" on every demo wrapper (decorative).
   - prefers-reduced-motion: reduce hides all demos.
   ============================================================= */

/* ─── Demo base (applies to every registered demo) ─────────────── */

.am-demo {
  position: absolute;
  pointer-events: none;
  font-family: var(--font-sans);
  opacity: 0;
  visibility: hidden;
  /* `transition` smooths the orchestrator's activate/deactivate
     state switches. CSS keyframes inside the demo handle the
     in-cycle animation; this transition is only for the wrapper. */
  transition: opacity 200ms var(--ease);
  /* Above the static terminals but below any popovers / tooltips. */
  z-index: 4;
}

/* Orchestrator toggles `.is-active` to bring the demo on-screen
   for its turn. Sibling demos stay hidden + measurable. */
.am-demo.is-active {
  opacity: 1;
  visibility: visible;
}

/* ─── Browser-plugin demo wrapper ──────────────────────────────── */

.am-demo-browser-plugin {
  /* Docks to the right half of the mock, between the header bottom
     and the statusbar top. The runtime header/statusbar heights
     are 40px and 24px (see .am-header / .am-statusbar). */
  top: 40px;
  right: 0;
  bottom: 24px;
  width: 58%;
  min-width: 320px;
  max-width: 640px;

  /* ─ Timing tokens (this demo only) ─
     Cycle = full play including panel-in, inspector flow, modal,
     terminal inject, panel-out, and rest. JS reads `--anim-cycle`
     to know how long to hold before the next demo. */
  --anim-cycle: 17s;

  --anim-panel-in-delay: 0.0s;
  --anim-panel-in-dur: 0.55s;

  --anim-url-type-delay: 0.85s;
  --anim-url-type-dur: 1.4s;

  --anim-load-delay: 2.30s;
  --anim-load-dur: 0.85s;

  --anim-page-delay: 2.65s;
  --anim-page-dur: 0.45s;

  --anim-cursor-to-inspect-delay: 3.05s;
  --anim-inspect-pulse-delay: 3.45s;
  --anim-inspect-active-delay: 3.80s;

  --anim-cursor-to-page-delay: 4.00s;
  --anim-hover-delay: 4.55s;
  --anim-hover-dur: 0.55s;

  --anim-select-delay: 5.10s;

  --anim-modal-delay: 5.45s;
  --anim-modal-dur: 0.42s;

  --anim-modal-type-delay: 5.95s;
  --anim-modal-type-dur: 2.3s;

  --anim-send-pulse-delay: 8.35s;
  --anim-send-click-delay: 8.85s;
  --anim-modal-out-delay: 9.05s;
  --anim-modal-out-dur: 0.45s;

  /* Panel slides back out 500ms after the inspector modal finishes
     closing so the eye gets a brief pause on the dock chrome and
     the receiving terminal before the overlay retracts. */
  --anim-panel-out-delay: 10.0s;
  --anim-panel-out-dur: 0.55s;

  --anim-inject-delay: 9.45s;
  --anim-inject-dur: 2.0s;

  --anim-rest-delay: 11.6s;
  --anim-rest-dur: 5.4s;

  /* Colour tokens borrowed from the product's inspector overlay so
     the hover indicator + selection box read identically to the
     real browser plugin (shared/plugins/browser/electron/inspector-script.ts). */
  --anim-hover-color: #da7756;
  --anim-hover-bg: rgba(218, 119, 86, 0.10);
  --anim-select-color: #2f6df0;
  --anim-select-bg: rgba(47, 109, 240, 0.10);

  /* CTA rect (in wrapper-relative percentages) - written by the JS
     controller after measuring .am-anim-page-cta.primary. Defaults
     here are conservative starting values so the boxes render
     somewhere reasonable even before the first measurement lands. */
  --anim-cta-left: 5%;
  --anim-cta-top: 50%;
  --anim-cta-width: 18%;
  --anim-cta-height: 9%;
  /* Cursor target inside the CTA - biased to the upper-left so the
     cursor's tip (top-left of the SVG) visibly lands inside the
     button. Re-derived from the CTA rect on each measurement. */
  --anim-cta-cursor-x: 8%;
  --anim-cta-cursor-y: 53%;

  /* Cursor target on the modal's "Send to Agent" button. Written
     by JS AFTER modal-in completes (the modal has a scale +
     translate animation that shifts the button's measured rect
     until it settles, so an early measure would land low). The
     defaults here are tuned to land near the button at a typical
     panel size; JS overrides them on every cycle. */
  --anim-send-cursor-x: 80%;
  --anim-send-cursor-y: 75%;
}

/* ─── Cursor pointer ───────────────────────────────────────────── */

.am-anim-cursor {
  position: absolute;
  /* Panel-relative anchor at top-left. The SVG arrow's tip is at
     its own (0, 0), so `top` / `left` directly correspond to where
     the visible cursor tip lands on the panel. */
  top: 2%;
  left: 102%;
  width: 14px;
  height: 16px;
  display: inline-flex;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.6));
  opacity: 0;
  z-index: 8;
}
.am-demo-browser-plugin.is-playing .am-anim-cursor {
  animation: am-anim-cursor-path var(--anim-cycle) linear forwards;
}

/* ─── Panel (slides in from right) ─────────────────────────────── */

.am-anim-panel {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border-left: 1px solid var(--border);
  box-shadow:
    -8px 0 22px -10px rgba(0, 0, 0, 0.55),
    -2px 0 0 0 color-mix(in srgb, var(--accent) 14%, transparent);
  overflow: hidden;
  pointer-events: none;
  transform: translateX(100%);
  opacity: 0.6;
}
/* Two-stage animation: panel-in (delay 0) docks the panel; panel-out
   (delay ~10s) slides it back out 500ms after the modal closes.
   Both use animation-fill-mode: forwards so the panel holds the
   docked state in between. CSS cascades the later animation in the
   list over the earlier one once both are at their "to" frame -
   panel-out therefore wins from 10s onward. */
.am-demo-browser-plugin.is-playing .am-anim-panel {
  animation:
    am-anim-panel-in  var(--anim-panel-in-dur)  var(--ease) var(--anim-panel-in-delay)  forwards,
    am-anim-panel-out var(--anim-panel-out-dur) var(--ease) var(--anim-panel-out-delay) forwards;
}

@keyframes am-anim-panel-in {
  0%   { transform: translateX(100%); opacity: 0.5; }
  60%  { opacity: 1; }
  100% { transform: translateX(0); opacity: 1; }
}

@keyframes am-anim-panel-out {
  0%   { transform: translateX(0);    opacity: 1; }
  35%  { opacity: 1; }
  100% { transform: translateX(105%); opacity: 0.5; }
}

/* ─── Toolbar ──────────────────────────────────────────────────── */

.am-anim-toolbar {
  display: flex;
  align-items: center;
  gap: 3px;
  padding: 5px 7px;
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
  min-height: 30px;
  box-sizing: border-box;
  flex-shrink: 0;
}

.am-anim-nav-group,
.am-anim-action-group {
  display: inline-flex;
  align-items: center;
  gap: 1px;
}

.am-anim-icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  padding: 0;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 4px;
  color: var(--text-3);
  cursor: default;
  position: relative;
  flex-shrink: 0;
}

.am-anim-inspect-btn { position: relative; }

.am-anim-inspect-pulse {
  position: absolute;
  inset: -3px;
  border-radius: 6px;
  border: 2px solid var(--accent);
  opacity: 0;
  pointer-events: none;
}
.am-demo-browser-plugin.is-playing .am-anim-inspect-pulse {
  animation: am-anim-pulse-out 0.95s var(--ease) var(--anim-inspect-pulse-delay) 2 forwards;
}

/* Inspect button switches to "is-active" tint after the click. */
.am-demo-browser-plugin.is-playing .am-anim-inspect-btn {
  animation: am-anim-inspect-activate 0.25s var(--ease) var(--anim-inspect-active-delay) forwards;
}

@keyframes am-anim-pulse-out {
  0%   { opacity: 0.85; transform: scale(1); }
  100% { opacity: 0; transform: scale(2.1); }
}

@keyframes am-anim-inspect-activate {
  to {
    background: color-mix(in srgb, var(--accent) 18%, transparent);
    color: var(--accent);
    border-color: color-mix(in srgb, var(--accent) 45%, transparent);
  }
}

/* ─── URL bar ──────────────────────────────────────────────────── */

.am-anim-urlbar {
  flex: 1;
  height: 22px;
  padding: 0 9px;
  background: var(--bg-2);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 11px;
  display: flex;
  align-items: center;
  font-family: var(--font-mono);
  font-size: 10.5px;
  position: relative;
  min-width: 0;
  overflow: hidden;
}

.am-demo-browser-plugin.is-playing .am-anim-urlbar {
  animation: am-anim-urlbar-focus 0.3s var(--ease) calc(var(--anim-url-type-delay) - 0.15s) forwards;
}

@keyframes am-anim-urlbar-focus {
  to {
    border-color: var(--accent);
    background: var(--surface);
  }
}

.am-anim-url-text {
  white-space: pre;
  color: var(--text);
}

.am-anim-url-placeholder {
  position: absolute;
  left: 9px;
  color: var(--text-muted);
  font-style: normal;
  pointer-events: none;
}
.am-demo-browser-plugin.is-playing .am-anim-url-placeholder {
  /* Hide the placeholder as soon as URL typing begins. */
  animation: am-anim-fade-out 0.1s linear calc(var(--anim-url-type-delay) - 0.05s) forwards;
}

.am-anim-url-caret {
  display: inline-block;
  width: 1px;
  height: 12px;
  margin-left: 1px;
  background: var(--accent);
  opacity: 0;
}
.am-demo-browser-plugin.is-playing .am-anim-url-caret {
  animation:
    am-anim-fade-in 0.1s linear calc(var(--anim-url-type-delay) - 0.1s) forwards,
    am-anim-caret-blink 1.05s steps(2, start) calc(var(--anim-url-type-delay) - 0.1s) infinite,
    am-anim-fade-out 0.15s linear calc(var(--anim-load-delay) - 0.05s) forwards;
}

@keyframes am-anim-caret-blink {
  50% { opacity: 0; }
}

/* ─── Tab strip ────────────────────────────────────────────────── */

.am-anim-tabstrip {
  display: flex;
  align-items: center;
  gap: 1px;
  height: 18px;
  padding: 0 6px;
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}

.am-anim-tab {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: 100%;
  padding: 0 8px;
  font-size: 10px;
  color: var(--text-2);
  border-radius: 0;
  position: relative;
}
.am-anim-tab.is-active { color: var(--text); background: var(--bg-2); }
.am-anim-tab.is-active::after {
  content: '';
  position: absolute;
  left: 6px; right: 6px; bottom: 0;
  height: 1.5px;
  background: var(--accent);
  border-radius: 1px;
}
.am-anim-favicon {
  width: 9px; height: 9px;
  border-radius: 2px;
  background: linear-gradient(135deg, var(--text-3), var(--accent));
  opacity: 0.5;
  flex-shrink: 0;
}
.am-anim-tab-title { font-size: 10px; white-space: nowrap; }

.am-anim-tab-new {
  width: 14px; height: 14px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 3px;
  color: var(--text-3);
  font-size: 11px;
  line-height: 1;
  margin-left: 2px;
}

/* ─── Loading bar ──────────────────────────────────────────────── */

.am-anim-loadbar {
  position: absolute;
  left: 0;
  top: 48px;  /* below toolbar(30) + tabstrip(18) */
  height: 1.5px;
  width: 0;
  background: linear-gradient(90deg, transparent, var(--accent) 30%, var(--accent-2) 70%, transparent);
  box-shadow: 0 0 6px var(--accent-glow);
  opacity: 0;
  z-index: 6;
}
.am-demo-browser-plugin.is-playing .am-anim-loadbar {
  animation: am-anim-loadbar var(--anim-load-dur) var(--ease) var(--anim-load-delay) forwards;
}

@keyframes am-anim-loadbar {
  0%   { width: 0;   opacity: 0; }
  10%  { opacity: 1; }
  85%  { opacity: 1; }
  100% { width: 100%; opacity: 0; }
}

/* ─── Host (fake page area) ────────────────────────────────────── */

.am-anim-host {
  flex: 1;
  position: relative;
  background: var(--bg);
  overflow: hidden;
}

/* Empty-state placeholder (before navigation completes). */
.am-anim-host-blank {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  color: var(--text-3);
}
.am-anim-host-pulse {
  width: 36px; height: 36px;
  border-radius: 50%;
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 35%, transparent);
  animation: am-anim-blank-pulse 2.4s ease-in-out infinite;
}
.am-anim-host-blank-title { font-size: 12px; font-weight: 600; color: var(--text-2); }
.am-anim-host-blank-sub { font-size: 10.5px; color: var(--text-3); }

.am-demo-browser-plugin.is-playing .am-anim-host-blank {
  animation: am-anim-fade-out 0.25s var(--ease) calc(var(--anim-page-delay) - 0.15s) forwards;
}

@keyframes am-anim-blank-pulse {
  0%, 100% { transform: scale(0.95); opacity: 0.85; }
  50%      { transform: scale(1.05); opacity: 1; }
}

/* ─── Fake page ────────────────────────────────────────────────── */

.am-anim-page {
  position: absolute;
  inset: 0;
  padding: 16px 18px;
  background:
    radial-gradient(circle at 18% 0%, color-mix(in srgb, var(--accent-2) 9%, transparent), transparent 38%),
    radial-gradient(circle at 88% 110%, color-mix(in srgb, var(--accent) 8%, transparent), transparent 42%),
    var(--bg);
  opacity: 0;
  /* Opacity-only fade-in - no translate. JS measures .am-anim-page-cta.primary
     to anchor the hover/select boxes; a transform here would shift the measured
     rect during the fade and the highlight would land off-target. */
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.am-demo-browser-plugin.is-playing .am-anim-page {
  animation: am-anim-page-in var(--anim-page-dur) var(--ease) var(--anim-page-delay) forwards;
}

@keyframes am-anim-page-in {
  to { opacity: 1; }
}

.am-anim-page-eyebrow {
  font-size: 9px;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--accent);
}

.am-anim-page-title {
  margin: 0;
  font-size: 18px;
  font-weight: 700;
  line-height: 1.18;
  letter-spacing: -0.02em;
  color: var(--text);
}

.am-anim-page-title-grad {
  background: linear-gradient(90deg, var(--accent), var(--accent-2));
  -webkit-background-clip: text;
          background-clip: text;
  color: transparent;
}

.am-anim-page-sub {
  margin: 0;
  font-size: 10.5px;
  line-height: 1.45;
  color: var(--text-2);
}

.am-anim-page-ctas {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 2px;
}

.am-anim-page-cta {
  display: inline-flex;
  align-items: center;
  height: 22px;
  padding: 0 12px;
  border-radius: 4px;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: -0.005em;
}
.am-anim-page-cta.primary {
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
  color: #0a1518;
  box-shadow: 0 4px 14px -6px var(--accent-glow);
}
.am-anim-page-cta.ghost {
  border: 1px solid var(--border-2);
  color: var(--text-2);
}

.am-anim-page-cards {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
  margin-top: auto;
}

.am-anim-page-card {
  height: 38px;
  background: linear-gradient(180deg, var(--surface) 0%, var(--bg-2) 100%);
  border: 1px solid var(--border);
  border-radius: 6px;
  position: relative;
  overflow: hidden;
}
.am-anim-page-card::before {
  content: '';
  position: absolute;
  top: 6px; left: 8px;
  width: 28%;
  height: 4px;
  background: var(--accent-soft);
  border-radius: 3px;
}
.am-anim-page-card::after {
  content: '';
  position: absolute;
  top: 16px; left: 8px;
  right: 8px;
  height: 3px;
  background: var(--border-2);
  border-radius: 2px;
}

/* ─── Inspector hover + selection boxes (over the fake page) ─────
 *
 * Both boxes are panel-relative children (NOT host-relative) so they
 * share the cursor's coordinate system. Their rect is pinned to the
 * actual .am-anim-page-cta.primary element by the JS controller via
 * the --anim-cta-* custom properties - the highlight therefore always
 * lands on the CTA even when font loading / viewport changes shift
 * the page layout.
 *
 * Only opacity is animated by keyframes. The visual reads as "the
 * cursor enters the page area, lands on the CTA, sees a hover (orange)
 * indicator, then the user clicks and the selection (blue) commits".
 * Since they live at the same panel-relative position, this reads as
 * "the hover commits to a selection" rather than two separate boxes.
 */

.am-anim-hover-box,
.am-anim-select-box {
  position: absolute;
  pointer-events: none;
  opacity: 0;
  border-radius: 3px;
  left: var(--anim-cta-left);
  top: var(--anim-cta-top);
  width: var(--anim-cta-width);
  height: var(--anim-cta-height);
  /* Above the page content but below the modal (z 5) so the
     selection stays visible after submit fires. */
  z-index: 3;
}

.am-anim-hover-box {
  border: 1.8px solid var(--anim-hover-color);
  background: var(--anim-hover-bg);
}
.am-demo-browser-plugin.is-playing .am-anim-hover-box {
  animation: am-anim-hover-fade var(--anim-hover-dur) var(--ease) var(--anim-hover-delay) forwards;
}

@keyframes am-anim-hover-fade {
  0%   { opacity: 0; }
  25%  { opacity: 0.95; }
  75%  { opacity: 0.95; }
  100% { opacity: 0; }
}

.am-anim-select-box {
  border: 1.8px solid var(--anim-select-color);
  background: var(--anim-select-bg);
  /* `transform` is animated for the commit pop; keep the position
     untouched so the CTA pin stays accurate. */
  transform: scale(0.85);
}
.am-anim-select-badge {
  position: absolute;
  top: -8px;
  left: -8px;
  min-width: 16px;
  height: 14px;
  padding: 0 4px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--anim-select-color);
  color: #fff;
  font-family: var(--font-sans);
  font-size: 9px;
  font-weight: 700;
  line-height: 1;
  border-radius: 7px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.35);
}
.am-demo-browser-plugin.is-playing .am-anim-select-box {
  animation: am-anim-select 0.4s var(--ease) var(--anim-select-delay) forwards;
}

@keyframes am-anim-select {
  0%   { opacity: 0; transform: scale(0.85); }
  60%  { opacity: 1; transform: scale(1.04); }
  100% { opacity: 1; transform: scale(1); }
}

/* ─── Inspector submit modal ───────────────────────────────────── */

.am-anim-modal {
  position: absolute;
  /* Anchored top-center within the host so it covers most of the
     panel without escaping the dock chrome. */
  left: 50%;
  top: 52%;
  width: 86%;
  max-width: 460px;
  transform: translate(-50%, calc(-50% + 12px)) scale(0.92);
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border-2);
  border-radius: 8px;
  box-shadow: 0 16px 40px -12px rgba(0, 0, 0, 0.7);
  opacity: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  font-family: var(--font-sans);
  z-index: 5;
}

.am-demo-browser-plugin.is-playing .am-anim-modal {
  animation:
    am-anim-modal-in var(--anim-modal-dur) var(--ease) var(--anim-modal-delay) forwards,
    am-anim-modal-out 0.45s var(--ease) var(--anim-modal-out-delay) forwards;
}

@keyframes am-anim-modal-in {
  to { opacity: 1; transform: translate(-50%, -50%) scale(1); }
}

@keyframes am-anim-modal-out {
  to { opacity: 0; transform: translate(-50%, calc(-50% - 8px)) scale(0.96); }
}

.am-anim-modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 7px 10px;
  border-bottom: 1px solid var(--border);
  font-size: 11px;
  font-weight: 600;
  color: var(--text);
}
.am-anim-modal-hint { font-size: 9.5px; font-weight: 400; color: var(--text-3); }

.am-anim-modal-body {
  padding: 9px 10px;
  display: flex;
  flex-direction: column;
  gap: 7px;
}

.am-anim-modal-shot {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 12px 16px;
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: 5px;
}

.am-anim-modal-shot-btn {
  display: inline-flex;
  align-items: center;
  height: 18px;
  padding: 0 10px;
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
  color: #0a1518;
  border-radius: 4px;
  font-size: 9.5px;
  font-weight: 600;
}

.am-anim-modal-chips {
  display: flex;
  gap: 4px;
  flex-wrap: wrap;
}

.am-anim-chip {
  font-family: var(--font-mono);
  font-size: 9.5px;
  padding: 1px 7px;
  border-radius: 999px;
  background: var(--bg-2);
  color: var(--text);
  border: 1px solid var(--border);
}

.am-anim-modal-meta {
  font-size: 9.5px;
  color: var(--text-3);
}

.am-anim-modal-textarea {
  position: relative;
  min-height: 38px;
  padding: 6px 8px;
  background: var(--bg-2);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 5px;
  font-family: var(--font-sans);
  font-size: 10px;
  line-height: 1.45;
  white-space: pre-wrap;
  word-break: break-word;
}

.am-anim-modal-text { white-space: pre-wrap; }

.am-anim-modal-caret {
  display: inline-block;
  width: 1px;
  height: 11px;
  margin-left: 1px;
  background: var(--accent);
  vertical-align: -2px;
  opacity: 0;
}
.am-demo-browser-plugin.is-playing .am-anim-modal-caret {
  animation:
    am-anim-fade-in 0.1s linear calc(var(--anim-modal-type-delay) - 0.05s) forwards,
    am-anim-caret-blink 1.05s steps(2, start) var(--anim-modal-type-delay) infinite,
    am-anim-fade-out 0.15s linear calc(var(--anim-send-pulse-delay) - 0.05s) forwards;
}

.am-anim-modal-footer {
  display: flex;
  justify-content: flex-end;
  gap: 6px;
  padding: 7px 10px;
  border-top: 1px solid var(--border);
  background: color-mix(in srgb, var(--bg-2) 60%, transparent);
}

.am-anim-modal-btn {
  padding: 4px 12px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 4px;
  font-size: 10px;
  font-weight: 500;
  position: relative;
}

.am-anim-modal-btn.primary {
  background: var(--accent);
  color: #0a1518;
  border-color: var(--accent);
}

/* Send button gets a soft pulse before the click, then a brief flash on click. */
.am-demo-browser-plugin.is-playing .am-anim-modal-btn.primary {
  animation:
    am-anim-send-pulse 0.4s var(--ease) var(--anim-send-pulse-delay) 2 alternate,
    am-anim-send-flash 0.18s var(--ease) var(--anim-send-click-delay) forwards;
}

@keyframes am-anim-send-pulse {
  to { box-shadow: 0 0 0 4px color-mix(in srgb, var(--accent) 30%, transparent); }
}

@keyframes am-anim-send-flash {
  to { filter: brightness(1.4); }
}

/* ─── Cursor path (one keyframes chain covering the whole demo) ─
 *
 * All values are PANEL-RELATIVE percentages so the cursor scales
 * with the panel and aligns with every other panel-positioned
 * element (URL bar, inspect button, hover/select boxes, modal).
 *
 * The CTA stop uses --anim-cta-cursor-{x,y} which the JS controller
 * derives from the actual rendered position of
 * .am-anim-page-cta.primary - that way the cursor lands inside the
 * CTA even if font loading or viewport changes shift the layout.
 * Modern browsers smoothly interpolate between var-resolved
 * percentages because the vars are registered as @property below;
 * older browsers fall back to discrete interpolation (the cursor
 * snaps between stops, which is still acceptable for a marketing
 * vignette).
 */

@keyframes am-anim-cursor-path {
  /* 0-3% : panel slides in; cursor parked off the right edge. */
  0%   { opacity: 0; top: 2%; left: 102%; }
  3%   { opacity: 0; top: 2%; left: 102%; }

  /* Cursor enters and lands on the URL bar (toolbar middle band, ~5% of panel height). */
  5%   { opacity: 1; top: 5%; left: 55%; }
  14%  { opacity: 1; top: 5%; left: 60%; }

  /* Cursor moves to the inspect button (right side of the toolbar). */
  17%  { top: 5%; left: 90%; }
  21%  { top: 5%; left: 90%; }
  22%  { top: 6.5%; left: 90%; } /* press wiggle - cursor sinks slightly on click */
  23%  { top: 5%; left: 90%; }

  /* Cursor enters the page area, landing on the primary CTA.
     The (x, y) target comes from JS-measured CTA rect. */
  27%  { top: var(--anim-cta-cursor-y); left: var(--anim-cta-cursor-x); }
  30%  { top: var(--anim-cta-cursor-y); left: var(--anim-cta-cursor-x); }
  31%  { top: calc(var(--anim-cta-cursor-y) + 1.5%); left: var(--anim-cta-cursor-x); } /* click press */
  32%  { top: var(--anim-cta-cursor-y); left: var(--anim-cta-cursor-x); }

  /* Modal opens. Cursor moves to the textarea (middle of the modal body). */
  35%  { top: 68%; left: 50%; }

  /* Cursor hangs near the textarea during the modal-typing window. */
  50%  { top: 68%; left: 50%; }

  /* Cursor moves to the Send button (lower-right of the modal footer).
     Coordinates come from JS measurement (--anim-send-cursor-{x,y})
     so the cursor lands ON the actual rendered button instead of a
     hardcoded percentage that drifts with modal/panel sizing. */
  53%  { top: var(--anim-send-cursor-y); left: var(--anim-send-cursor-x); }
  54%  { top: calc(var(--anim-send-cursor-y) + 1.5%); left: var(--anim-send-cursor-x); } /* send click press */
  55%  { top: var(--anim-send-cursor-y); left: var(--anim-send-cursor-x); }

  /* Cursor drifts down and fades BEFORE the panel slides out (~58.8%
     of the 17s cycle = 10s). Leaving the cursor visible past that
     point would strand it floating over the revealed terminals once
     the overlay retracts. */
  57%   { opacity: 1; top: 90%; left: 82%; }
  58.5% { opacity: 0; top: 95%; left: 90%; }
  100%  { opacity: 0; top: 95%; left: 90%; }
}

/* Register the CTA cursor vars so cross-keyframe interpolation
   produces a smooth move instead of a discrete snap. Supported
   in Chromium 85+, Safari 16.4+, Firefox 128+ (mid-2024). Older
   browsers ignore @property and fall back to discrete behaviour
   without erroring. */
@property --anim-cta-cursor-x {
  syntax: '<percentage>';
  inherits: true;
  initial-value: 8%;
}
@property --anim-cta-cursor-y {
  syntax: '<percentage>';
  inherits: true;
  initial-value: 53%;
}
@property --anim-send-cursor-x {
  syntax: '<percentage>';
  inherits: true;
  initial-value: 80%;
}
@property --anim-send-cursor-y {
  syntax: '<percentage>';
  inherits: true;
  initial-value: 75%;
}

/* ─── Terminal injection (left focused term picks up the prompt) ─ */

.am-term-inject {
  display: inline-block;
  opacity: 0;
  /* Pre-allocates layout space so the existing prompt above doesn't
     reflow when the inject content fades in. */
  max-height: 0;
  overflow: hidden;
  transition: opacity 0s, max-height 0s;
  will-change: opacity, max-height;
}

/* Demo-specific effect on an element OUTSIDE .am-demo-browser-plugin
   (the inject content lives inside the focused Claude terminal's body).
   Gated on the orchestrator's `data-active-demo` attribute + the global
   `is-anim-playing` class so only the browser-plugin demo lights it up.

   Note: timing values are hardcoded here (not `var(--anim-inject-*)`)
   because those custom properties are scoped to the demo wrapper, which
   is a SIBLING of .am-grid (where this element lives) - so the var
   would resolve to its unset initial value and the animation would run
   with duration 0. Keep these numbers in sync with the matching
   `--anim-inject-*` tokens on `.am-demo-browser-plugin`. */
.app-mock[data-active-demo="browser-plugin"].is-anim-playing .am-term-inject {
  animation: am-anim-term-inject 2s var(--ease) 9.45s forwards;
}

@keyframes am-anim-term-inject {
  0%   { opacity: 0; max-height: 0; }
  40%  { opacity: 1; max-height: 14em; }
  100% { opacity: 1; max-height: 14em; }
}

/* Hide the original prompt-cursor while the inject is streaming, so
   the visual reads as "prompt was submitted, now agent is working".
   Timing hardcoded - see the .am-term-inject rule above for why. */
.app-mock[data-active-demo="browser-plugin"].is-anim-playing .am-cursor-base {
  animation: am-anim-fade-out 0.2s var(--ease) 9.35s forwards;
}

.am-anim-inject-chip {
  display: inline-block;
  padding: 0 5px;
  margin-right: 4px;
  background: color-mix(in srgb, var(--accent) 18%, transparent);
  color: var(--accent);
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 600;
  border-radius: 3px;
  vertical-align: 1px;
}

/* ─── Shared helpers ───────────────────────────────────────────── */

@keyframes am-anim-fade-in {
  to { opacity: 1; }
}
@keyframes am-anim-fade-out {
  to { opacity: 0; }
}

/* When the focused term receives the inject, paint a soft accent
   pulse on its border so the eye is drawn to where the agent is
   working. */
.app-mock[data-active-demo="browser-plugin"].is-anim-playing .am-term-large.focused {
  animation: am-anim-term-receive 1.2s var(--ease) 9.35s forwards;
}

@keyframes am-anim-term-receive {
  0%   { box-shadow: 0 0 0 1px var(--accent), 0 8px 24px rgba(0, 0, 0, 0.35); }
  35%  { box-shadow: 0 0 0 2px var(--accent), 0 8px 36px var(--accent-glow), 0 0 24px var(--accent-glow); }
  100% { box-shadow: 0 0 0 1px var(--accent), 0 8px 24px rgba(0, 0, 0, 0.35); }
}

/* =============================================================
   Demo: terminal-spawn -> command -> close-shell
   -----------------------------------------------------------------
   Walks the new-terminal flow: cursor lands on the static `+`
   button in the header, pulse + modal in, agent picked, "Start
   Claude" click, modal out, the 4th terminal spawns into the grid,
   command typed + submitted, then the shell terminal closes and
   the grid returns to 2 right-column rows.

   Wrapper covers the full .app-mock minus the statusbar so the
   cursor can reach both the header (the `+`) and the grid (the
   terminals). Effects on elements outside the wrapper (the +
   pulse, the spawned terminal reveal, the shell close fade, the
   grid reflow) are gated on
   `.app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="..."]`
   so the orchestrator drives multi-stage state via a single attr.
   ============================================================= */

.am-demo-terminal-spawn {
  /* Covers everything except the statusbar so the cursor can reach
     the header's + button AND the grid's terminals. */
  top: 0;
  left: 0;
  right: 0;
  bottom: 24px;  /* leave the statusbar visible */
  font-family: var(--font-sans);

  /* ─ Master cycle + per-stage timing tokens ─ */
  --anim-cycle: 14s;

  /* Stage 1: cursor enters and lands on the + button. */
  --anim-cursor-to-add-delay: 0.0s;

  /* Stage 2: + button click pulse. */
  --anim-add-pulse-delay: 0.55s;
  --anim-add-pulse-dur: 0.85s;

  /* Stage 3: new-terminal modal slides in (centered). */
  --anim-modal-in-delay: 0.75s;
  --anim-modal-in-dur: 0.40s;

  /* Stage 4: cursor moves to the Claude agent option, then Start. */
  --anim-cursor-to-claude-delay: 1.40s;
  --anim-cursor-to-start-delay: 2.40s;

  /* Stage 5: Start click pulse. */
  --anim-start-pulse-delay: 2.65s;
  --anim-start-pulse-dur: 0.45s;

  /* Stage 6: modal slides back out. */
  --anim-modal-out-delay: 3.10s;
  --anim-modal-out-dur: 0.40s;

  /* Stage 7: 4th terminal slides into the grid (grid reflows
     to 3 right-column rows). */
  --anim-spawn-delay: 3.30s;
  --anim-spawn-dur: 0.55s;

  /* Stage 8: cursor moves to the new terminal, types a command. */
  --anim-cursor-to-new-delay: 4.10s;
  --anim-cmd-type-delay: 4.60s;
  --anim-cmd-type-dur: 2.10s;

  /* Stage 9: command output streams into the new terminal. */
  --anim-cmd-output-delay: 6.80s;
  --anim-cmd-output-dur: 1.20s;

  /* Stage 10: cursor moves to the shell terminal's close button. */
  --anim-cursor-to-close-delay: 8.20s;

  /* Stage 11: close click pulse. */
  --anim-close-pulse-delay: 8.65s;
  --anim-close-pulse-dur: 0.55s;

  /* Stage 12: shell terminal fades out, grid reflows to 2 rows.
     The fade starts immediately on the cursor click (no perceptible
     gap between the click press and the terminal beginning to
     disappear) - production terminals close synchronously on the
     close-button click, so any delay reads as broken to viewers. */
  --anim-shell-fade-delay: 8.70s;
  --anim-shell-fade-dur: 0.50s;
  --anim-grid-reflow-delay: 9.20s;
  --anim-grid-reflow-dur: 0.45s;

  /* Stage 13: cursor drifts off, then the cycle holds on the final
     state until the orchestrator hands off to the next demo. */
  --anim-cursor-exit-delay: 9.80s;

  /* Position tokens written by JS (so the cursor lands on the
     actual rendered buttons, not hardcoded percentages). The
     fallback values here position the cursor reasonably even
     before the first measurement. */
  --anim-add-cursor-x: 32%;
  --anim-add-cursor-y: 4%;
  --anim-claude-cursor-x: 38%;
  --anim-claude-cursor-y: 42%;
  --anim-start-cursor-x: 56%;
  --anim-start-cursor-y: 65%;
  --anim-new-cursor-x: 78%;
  --anim-new-cursor-y: 82%;
  --anim-close-cursor-x: 88%;
  --anim-close-cursor-y: 60%;

  /* Position tokens for pulse rings - centered on their targets. */
  --anim-add-pulse-x: 33%;
  --anim-add-pulse-y: 5%;
  --anim-close-pulse-x: 89%;
  --anim-close-pulse-y: 61%;

  /* Popover anchor (top-left, where the new-agent picker drops from
     the + button). JS writes these from the rendered + button rect
     - bottom-start alignment with a 4px gap to match production. */
  --anim-spawn-popover-x: 32%;
  --anim-spawn-popover-y: 11%;
}

@property --anim-add-cursor-x      { syntax: '<percentage>'; inherits: true; initial-value: 32%; }
@property --anim-add-cursor-y      { syntax: '<percentage>'; inherits: true; initial-value: 4%; }
@property --anim-claude-cursor-x   { syntax: '<percentage>'; inherits: true; initial-value: 38%; }
@property --anim-claude-cursor-y   { syntax: '<percentage>'; inherits: true; initial-value: 42%; }
@property --anim-start-cursor-x    { syntax: '<percentage>'; inherits: true; initial-value: 56%; }
@property --anim-start-cursor-y    { syntax: '<percentage>'; inherits: true; initial-value: 65%; }
@property --anim-new-cursor-x      { syntax: '<percentage>'; inherits: true; initial-value: 78%; }
@property --anim-new-cursor-y      { syntax: '<percentage>'; inherits: true; initial-value: 82%; }
@property --anim-close-cursor-x    { syntax: '<percentage>'; inherits: true; initial-value: 88%; }
@property --anim-close-cursor-y    { syntax: '<percentage>'; inherits: true; initial-value: 60%; }

/* ─── Cursor (terminal-spawn) ──────────────────────────────────── */

.am-demo-terminal-spawn .am-anim-cursor {
  position: absolute;
  top: 5%;
  left: 110%;
  width: 14px;
  height: 16px;
  display: inline-flex;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.6));
  opacity: 0;
  z-index: 8;
}

.am-demo-terminal-spawn.is-playing .am-anim-cursor {
  animation: am-spawn-cursor-path var(--anim-cycle) linear forwards;
}

@keyframes am-spawn-cursor-path {
  /* Cursor offscreen-right; wait briefly so the user notices the
     demo has begun (the + button is highlighted to draw the eye). */
  0%   { opacity: 0; top: 5%; left: 110%; }
  2%   { opacity: 0; top: 5%; left: 105%; }

  /* Enter and land on the + button (data-driven cursor target). */
  3.5% { opacity: 1; top: var(--anim-add-cursor-y); left: var(--anim-add-cursor-x); }
  5%   { top: var(--anim-add-cursor-y); left: var(--anim-add-cursor-x); }
  5.5% { top: calc(var(--anim-add-cursor-y) + 1.5%); left: var(--anim-add-cursor-x); } /* click press */
  6%   { top: var(--anim-add-cursor-y); left: var(--anim-add-cursor-x); }

  /* Modal opens. Cursor moves to the Claude agent option. */
  10%  { top: var(--anim-claude-cursor-y); left: var(--anim-claude-cursor-x); }
  12%  { top: var(--anim-claude-cursor-y); left: var(--anim-claude-cursor-x); }
  12.5%{ top: calc(var(--anim-claude-cursor-y) + 1.5%); left: var(--anim-claude-cursor-x); } /* click */
  13%  { top: var(--anim-claude-cursor-y); left: var(--anim-claude-cursor-x); }

  /* Move to "Start Claude" button. */
  18%  { top: var(--anim-start-cursor-y); left: var(--anim-start-cursor-x); }
  19.5%{ top: calc(var(--anim-start-cursor-y) + 1.5%); left: var(--anim-start-cursor-x); } /* click */
  20%  { top: var(--anim-start-cursor-y); left: var(--anim-start-cursor-x); }

  /* Modal exits. Cursor moves to the new terminal that spawns in. */
  29%  { top: var(--anim-new-cursor-y); left: var(--anim-new-cursor-x); }

  /* Cursor parks near the terminal during command typing. */
  50%  { top: var(--anim-new-cursor-y); left: var(--anim-new-cursor-x); }

  /* Cursor moves to the shell terminal's close button. */
  60%  { top: var(--anim-close-cursor-y); left: var(--anim-close-cursor-x); }
  62%  { top: var(--anim-close-cursor-y); left: var(--anim-close-cursor-x); }
  62.5%{ top: calc(var(--anim-close-cursor-y) + 1.5%); left: var(--anim-close-cursor-x); } /* click */
  63%  { top: var(--anim-close-cursor-y); left: var(--anim-close-cursor-x); }

  /* Cursor drifts down and fades. */
  73%  { opacity: 1; top: calc(var(--anim-close-cursor-y) + 6%); left: calc(var(--anim-close-cursor-x) + 4%); }
  77%  { opacity: 0; top: calc(var(--anim-close-cursor-y) + 9%); left: calc(var(--anim-close-cursor-x) + 6%); }
  100% { opacity: 0; top: calc(var(--anim-close-cursor-y) + 9%); left: calc(var(--anim-close-cursor-x) + 6%); }
}

/* ─── + button pulse (the static .am-add-term in the header) ───── */

.am-spawn-add-pulse {
  position: absolute;
  left: var(--anim-add-pulse-x);
  top: var(--anim-add-pulse-y);
  width: 26px;
  height: 22px;
  transform: translate(-50%, -50%);
  border: 2px solid var(--accent);
  border-radius: 6px;
  opacity: 0;
  pointer-events: none;
  z-index: 7;
}

.am-demo-terminal-spawn.is-playing .am-spawn-add-pulse {
  animation: am-spawn-pulse-out var(--anim-add-pulse-dur) var(--ease) var(--anim-add-pulse-delay) 2 forwards;
}

@keyframes am-spawn-pulse-out {
  0%   { opacity: 0.85; transform: translate(-50%, -50%) scale(1); }
  100% { opacity: 0;    transform: translate(-50%, -50%) scale(1.8); }
}

/* The static `+` button itself flashes when clicked so the eye
   reads "the orchestrator pressed it". */
.app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="add-click"] .am-add-term,
.app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="modal-open"] .am-add-term,
.app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="agent-select"] .am-add-term,
.app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="start-click"] .am-add-term {
  background: color-mix(in srgb, var(--accent) 28%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 60%, transparent);
}

/* ─── New-terminal modal ───────────────────────────────────────── */

/* New-agent picker: a compact popover anchored under the + button,
   mirroring the production AgentPickerPopover.tsx (280px wide,
   bottom-start anchor, 4px gap below the button). The marketing
   version drops the keyboard shortcut column and "Default" badge -
   the demo runs without input. JS writes the anchor position into
   --anim-spawn-popover-{x,y} based on the rendered + button rect,
   so the popover always tracks the button across viewport sizes. */
.am-spawn-modal {
  position: absolute;
  left: var(--anim-spawn-popover-x, 32%);
  top:  var(--anim-spawn-popover-y, 11%);
  width: 240px;
  /* Pixel-cap to keep proportions readable even on a narrow .app-mock. */
  max-width: 70%;
  transform-origin: top left;
  transform: translate(0, -4px) scale(0.96);
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border-2);
  border-radius: 7px;
  box-shadow: 0 14px 32px -10px rgba(0, 0, 0, 0.65);
  opacity: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  z-index: 5;
}

.am-demo-terminal-spawn.is-playing .am-spawn-modal {
  animation:
    am-spawn-modal-in  var(--anim-modal-in-dur)  var(--ease) var(--anim-modal-in-delay)  forwards,
    am-spawn-modal-out var(--anim-modal-out-dur) var(--ease) var(--anim-modal-out-delay) forwards;
}

@keyframes am-spawn-modal-in {
  to { opacity: 1; transform: translate(0, 0) scale(1); }
}

@keyframes am-spawn-modal-out {
  to { opacity: 0; transform: translate(0, -4px) scale(0.97); }
}

.am-spawn-modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 6px 10px;
  border-bottom: 1px solid var(--border);
  font-size: 11px;
  font-weight: 600;
}

.am-spawn-modal-title { color: var(--text); }

.am-spawn-provider-chip {
  display: inline-flex;
  align-items: center;
  height: 15px;
  padding: 0 7px;
  border-radius: 8px;
  font-size: 9px;
  font-weight: 600;
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent) 28%, transparent);
}

.am-spawn-modal-body {
  padding: 6px 8px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.am-spawn-modal-label {
  font-size: 9px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-3);
  font-weight: 600;
  padding: 0 2px;
}

.am-spawn-agents {
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.am-spawn-agent {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 5px 8px;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 5px;
  cursor: default;
  transition: background-color 120ms ease, border-color 120ms ease;
}

.am-spawn-agent .am-agent-badge {
  width: 16px;
  height: 16px;
  font-size: 9px;
  flex-shrink: 0;
}

.am-spawn-agent-info {
  display: flex;
  flex-direction: column;
  gap: 0;
  min-width: 0;
  flex: 1;
}

.am-spawn-agent-name {
  font-size: 10.5px;
  font-weight: 500;
  color: var(--text);
}

.am-spawn-agent-meta {
  font-size: 9px;
  color: var(--text-3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.am-spawn-agent-check {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 13px;
  height: 13px;
  border-radius: 50%;
  background: var(--accent);
  color: #0a1518;
  opacity: 0;
  flex-shrink: 0;
}
.am-spawn-agent-check svg { width: 9px; height: 9px; }

/* Default-selected Claude option has the check visible from the
   start (so the popover reads as "Claude is the current default"). */
.am-spawn-agent.is-selected .am-spawn-agent-check { opacity: 1; }

.am-spawn-agent.is-selected {
  background: color-mix(in srgb, var(--accent) 10%, transparent);
  border-color: color-mix(in srgb, var(--accent) 28%, transparent);
}

.am-spawn-modal-footer {
  display: flex;
  justify-content: flex-end;
  gap: 5px;
  padding: 6px 8px;
  border-top: 1px solid var(--border);
  background: color-mix(in srgb, var(--bg-2) 60%, transparent);
}

.am-spawn-modal-btn {
  padding: 3px 10px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 4px;
  font-size: 10px;
  font-weight: 500;
  position: relative;
}

.am-spawn-modal-btn.primary {
  background: var(--accent);
  color: #0a1518;
  border-color: var(--accent);
}

/* Start-Claude pulse + flash, mirroring the browser-plugin Send btn. */
.am-demo-terminal-spawn.is-playing .am-spawn-modal-btn.primary {
  animation:
    am-spawn-start-pulse var(--anim-start-pulse-dur) var(--ease) var(--anim-start-pulse-delay) 2 alternate;
}

@keyframes am-spawn-start-pulse {
  to { box-shadow: 0 0 0 4px color-mix(in srgb, var(--accent) 30%, transparent); }
}

/* ─── 4th terminal: spawn in / out ─────────────────────────────── */

/* Hidden by default. The terminal-spawn demo reveals it; other
   demos keep it out of layout entirely. */
.am-term-new { display: none; }

/* Phase-driven grid layout. The 4-terminal "spawning" phase puts
   the new terminal UNDERNEATH claude in the left column (claude
   shrinks to a single row); codex stays top-right, shell stays
   bottom-right. After "closed" (shell removed), codex stretches
   to span both right-column rows so the layout reads as a clean
   3-terminal grid with claude+new on the left and codex on the
   right - new terminal stays anchored under claude throughout. */

.app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="spawning"]        .am-term-large,
.app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="settled"]         .am-term-large,
.app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="cursor-to-close"] .am-term-large,
.app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="close-click"]     .am-term-large,
.app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="closing"]         .am-term-large,
.app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="closed"]          .am-term-large {
  grid-row: 1;
  grid-column: 1;
}

.app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="spawning"]        .am-term-new,
.app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="settled"]         .am-term-new,
.app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="cursor-to-close"] .am-term-new,
.app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="close-click"]     .am-term-new,
.app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="closing"]         .am-term-new,
.app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="closed"]          .am-term-new {
  display: flex;
  grid-row: 2;
  grid-column: 1;
  animation: am-spawn-term-in var(--anim-spawn-dur) var(--ease) both;
}

.app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="spawning"]        .am-term[data-am-term="codex"],
.app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="settled"]         .am-term[data-am-term="codex"],
.app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="cursor-to-close"] .am-term[data-am-term="codex"],
.app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="close-click"]     .am-term[data-am-term="codex"],
.app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="closing"]         .am-term[data-am-term="codex"] {
  grid-row: 1;
  grid-column: 2;
}

.app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="spawning"]        .am-term-shell,
.app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="settled"]         .am-term-shell,
.app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="cursor-to-close"] .am-term-shell,
.app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="close-click"]     .am-term-shell,
.app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="closing"]         .am-term-shell {
  grid-row: 2;
  grid-column: 2;
}

/* After close, codex stretches to span both right-column rows. */
.app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="closed"] .am-term[data-am-term="codex"] {
  grid-row: 1 / -1;
  grid-column: 2;
}

@keyframes am-spawn-term-in {
  0%   { opacity: 0; transform: translateY(6px) scale(0.95); }
  100% { opacity: 1; transform: translateY(0)    scale(1); }
}

/* Smooth the grid-row template change. CSS Grid template
   interpolation lands in Chrome 117+, Firefox 119+, Safari 17.4+;
   older browsers snap rather than animating, still functional. */
.am-grid {
  transition: grid-template-rows var(--anim-grid-reflow-dur, 0.55s) var(--ease);
}

/* Shell terminal fade-out during phase "closing". */
.app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="closing"] .am-term-shell {
  animation: am-spawn-shell-fade var(--anim-shell-fade-dur) var(--ease) forwards;
}

@keyframes am-spawn-shell-fade {
  0%   { opacity: 1; transform: scale(1); }
  100% { opacity: 0; transform: scale(0.95); }
}

/* Phase "closed": shell hidden entirely (removed from grid flow).
   Grid stays at 1fr 1fr / 1.4fr 1fr; claude + new occupy the left
   column rows; codex stretches across both right-column rows
   (rule above), so the layout reads as a tidy 3-terminal grid
   with new still anchored under claude. */
.app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="closed"] .am-term-shell {
  display: none;
}
.app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="closed"] .am-grid {
  grid-template-rows: 1fr 1fr;
}

/* ─── Close button on shell terminal (decorative until demo plays) ─ */

.am-term-close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 14px;
  height: 14px;
  padding: 0;
  background: transparent;
  border: none;
  color: var(--text-3);
  border-radius: 3px;
  cursor: default;
  opacity: 0;
  transition: opacity 120ms ease, background-color 120ms ease;
  margin-right: 2px;
}

/* Show the close button when the terminal-spawn demo is in a phase
   where the user is about to click it. Keeps the static state
   uncluttered (matches the production UI's hover-reveal behaviour). */
.app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="cursor-to-close"] .am-term-shell .am-term-close,
.app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="close-click"]     .am-term-shell .am-term-close,
.app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="closing"]         .am-term-shell .am-term-close {
  opacity: 0.9;
  background: color-mix(in srgb, var(--text-3) 18%, transparent);
}

/* ─── Pulse ring on the shell close button ─────────────────────── */

.am-spawn-close-pulse {
  position: absolute;
  left: var(--anim-close-pulse-x);
  top: var(--anim-close-pulse-y);
  width: 18px;
  height: 18px;
  transform: translate(-50%, -50%);
  border: 2px solid var(--red);
  border-radius: 50%;
  opacity: 0;
  pointer-events: none;
  z-index: 7;
}

.am-demo-terminal-spawn.is-playing .am-spawn-close-pulse {
  animation: am-spawn-close-pulse var(--anim-close-pulse-dur) var(--ease) var(--anim-close-pulse-delay) 2 forwards;
}

@keyframes am-spawn-close-pulse {
  0%   { opacity: 0.85; transform: translate(-50%, -50%) scale(1); }
  100% { opacity: 0;    transform: translate(-50%, -50%) scale(2); }
}

/* ─── New terminal: command typing + output streaming ──────────── */

.am-anim-spawn-cmd { white-space: pre; }

.am-anim-spawn-output {
  display: inline-block;
  white-space: pre-wrap;
  opacity: 0;
  max-height: 0;
  overflow: hidden;
}

/* Timing hardcoded - --anim-cmd-* are scoped to .am-demo-terminal-spawn
   which is a sibling of .am-grid. See .am-term-inject rule above. */
.app-mock[data-active-demo="terminal-spawn"].is-anim-playing .am-anim-spawn-output {
  animation: am-spawn-output-reveal 1.2s var(--ease) 6.8s forwards;
}

@keyframes am-spawn-output-reveal {
  0%   { opacity: 0; max-height: 0; }
  50%  { opacity: 1; max-height: 10em; }
  100% { opacity: 1; max-height: 10em; }
}

/* Hide the in-terminal blinking cursor inside the new terminal
   until typing starts; reveal it during the typing window so the
   text reads as actively being entered. */
.am-cursor-new {
  opacity: 0;
}
.app-mock[data-active-demo="terminal-spawn"].is-anim-playing .am-cursor-new {
  /* Hardcoded delays - --anim-cmd-* vars don't cascade to this element. */
  animation:
    am-spawn-cursor-show 0.1s linear 4.6s forwards,
    am-spawn-cursor-hide 0.1s linear 6.8s forwards;
}
@keyframes am-spawn-cursor-show { to { opacity: 1; } }
@keyframes am-spawn-cursor-hide { to { opacity: 0; } }

/* The new terminal gets the focused-ring treatment after spawn so
   it visually reads as "newly active". */
.app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="settled"] .am-term-new,
.app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="cursor-to-close"] .am-term-new,
.app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="close-click"] .am-term-new,
.app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="closing"] .am-term-new,
.app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="closed"] .am-term-new {
  border-color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent), 0 8px 24px rgba(0, 0, 0, 0.35);
}

/* =============================================================
   Demo: git-manager quick view
   -----------------------------------------------------------------
   Hover-driven popover from the Git plugin pin in the header.
   Mirrors shared/plugins/git-manager/renderer/GitManagerQuickView.tsx:
   320px-wide popover with branch summary, unstaged + staged file
   lists, commit message textarea, and Pull/Push/Commit action row.

   Flow walks through staging two files, typing a commit message,
   committing (staged section clears, ahead becomes 1, Push button
   appears), then pushing (ahead returns to 0).

   Phase progression on .app-mock[data-gm-phase=...]:
       hover -> qv-open -> stage1 -> stage2 -> message-typed
       -> committed -> pushed -> rest
   ============================================================= */

.am-demo-git-manager {
  /* Covers everything except the statusbar so the cursor can reach
     both the Git pin (in header) and the popover content below it. */
  top: 0;
  left: 0;
  right: 0;
  bottom: 24px;
  font-family: var(--font-sans);

  /* ─ Master cycle + per-stage timing tokens ─ */
  --anim-cycle: 13s;

  --anim-gm-hover-delay: 0.40s;
  --anim-gm-qv-in-delay: 0.65s;
  --anim-gm-qv-in-dur: 0.20s;

  --anim-gm-stage1-cursor-delay: 1.60s;
  --anim-gm-stage1-click-delay: 1.85s;
  --anim-gm-stage1-phase: 2.00s;

  --anim-gm-stage2-cursor-delay: 2.45s;
  --anim-gm-stage2-click-delay: 2.70s;
  --anim-gm-stage2-phase: 2.85s;

  --anim-gm-msg-cursor-delay: 3.25s;
  --anim-gm-msg-type-delay: 3.55s;
  --anim-gm-msg-type-dur: 2.10s;
  --anim-gm-msg-phase: 5.70s;

  --anim-gm-commit-cursor-delay: 5.95s;
  --anim-gm-commit-click-delay: 6.20s;
  --anim-gm-commit-phase: 6.30s;

  --anim-gm-push-cursor-delay: 6.75s;
  --anim-gm-push-click-delay: 7.05s;
  --anim-gm-push-phase: 7.20s;

  --anim-gm-rest-delay: 7.60s;
  --anim-gm-qv-out-delay: 11.30s;
  --anim-gm-qv-out-dur: 0.20s;

  /* Position tokens written by JS each cycle. Defaults are
     conservative starting values used only on the very first paint. */
  --anim-gm-popover-x: 60%;
  --anim-gm-popover-y: 11%;
  --anim-gm-cursor-x: 70%;
  --anim-gm-cursor-y: 5%;
  --anim-gm-stage-cursor-x: 90%;
  --anim-gm-stage-cursor-y: 30%;
  --anim-gm-msg-cursor-x: 75%;
  --anim-gm-msg-cursor-y: 60%;
  --anim-gm-commit-cursor-x: 92%;
  --anim-gm-commit-cursor-y: 75%;
  --anim-gm-push-cursor-x: 78%;
  --anim-gm-push-cursor-y: 75%;
}

@property --anim-gm-cursor-x        { syntax: '<percentage>'; inherits: true; initial-value: 70%; }
@property --anim-gm-cursor-y        { syntax: '<percentage>'; inherits: true; initial-value: 5%; }
@property --anim-gm-stage-cursor-x  { syntax: '<percentage>'; inherits: true; initial-value: 90%; }
@property --anim-gm-stage-cursor-y  { syntax: '<percentage>'; inherits: true; initial-value: 30%; }
@property --anim-gm-msg-cursor-x    { syntax: '<percentage>'; inherits: true; initial-value: 75%; }
@property --anim-gm-msg-cursor-y    { syntax: '<percentage>'; inherits: true; initial-value: 60%; }
@property --anim-gm-commit-cursor-x { syntax: '<percentage>'; inherits: true; initial-value: 92%; }
@property --anim-gm-commit-cursor-y { syntax: '<percentage>'; inherits: true; initial-value: 75%; }
@property --anim-gm-push-cursor-x   { syntax: '<percentage>'; inherits: true; initial-value: 78%; }
@property --anim-gm-push-cursor-y   { syntax: '<percentage>'; inherits: true; initial-value: 75%; }

/* ─── Cursor (git-manager) ─────────────────────────────────────── */

.am-demo-git-manager .am-anim-cursor {
  position: absolute;
  top: 5%;
  left: 110%;
  width: 14px;
  height: 16px;
  display: inline-flex;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.6));
  opacity: 0;
  z-index: 8;
}

.am-demo-git-manager.is-playing .am-anim-cursor {
  animation: am-gm-cursor-path var(--anim-cycle) linear forwards;
}

@keyframes am-gm-cursor-path {
  /* 0-3% : cursor offscreen-right; user notices the static state. */
  0%   { opacity: 0; top: 5%; left: 110%; }
  2%   { opacity: 0; top: 5%; left: 105%; }

  /* Cursor enters and lands on the Git plugin pin. */
  4%   { opacity: 1; top: var(--anim-gm-cursor-y); left: var(--anim-gm-cursor-x); }
  6%   { top: var(--anim-gm-cursor-y); left: var(--anim-gm-cursor-x); }
  /* Hover hold while the 150ms hover-intent runs in production. */
  12%  { top: var(--anim-gm-cursor-y); left: var(--anim-gm-cursor-x); }

  /* Cursor drops to the first file's stage button. */
  14%  { top: var(--anim-gm-stage-cursor-y); left: var(--anim-gm-stage-cursor-x); }
  15.5%{ top: calc(var(--anim-gm-stage-cursor-y) + 1.2%); left: var(--anim-gm-stage-cursor-x); } /* click press */
  16.5%{ top: var(--anim-gm-stage-cursor-y); left: var(--anim-gm-stage-cursor-x); }
  /* Stage1 phase applies at ~15.5% so the file slides up. Cursor
     stays parked because file 2 shifts up to the same row. */
  19%  { top: var(--anim-gm-stage-cursor-y); left: var(--anim-gm-stage-cursor-x); }
  20.5%{ top: calc(var(--anim-gm-stage-cursor-y) + 1.2%); left: var(--anim-gm-stage-cursor-x); } /* second click */
  21.5%{ top: var(--anim-gm-stage-cursor-y); left: var(--anim-gm-stage-cursor-x); }

  /* Cursor drops to the commit message textarea. */
  25%  { top: var(--anim-gm-msg-cursor-y); left: var(--anim-gm-msg-cursor-x); }
  /* Hold during typing. */
  44%  { top: var(--anim-gm-msg-cursor-y); left: var(--anim-gm-msg-cursor-x); }

  /* Move to Commit button. */
  46%  { top: var(--anim-gm-commit-cursor-y); left: var(--anim-gm-commit-cursor-x); }
  47.5%{ top: calc(var(--anim-gm-commit-cursor-y) + 1.2%); left: var(--anim-gm-commit-cursor-x); } /* click */
  48.5%{ top: var(--anim-gm-commit-cursor-y); left: var(--anim-gm-commit-cursor-x); }

  /* Move to Push button (which has just appeared because ahead > 0). */
  52%  { top: var(--anim-gm-push-cursor-y); left: var(--anim-gm-push-cursor-x); }
  54%  { top: calc(var(--anim-gm-push-cursor-y) + 1.2%); left: var(--anim-gm-push-cursor-x); } /* click */
  55%  { top: var(--anim-gm-push-cursor-y); left: var(--anim-gm-push-cursor-x); }

  /* Hold then drift away. */
  85%  { opacity: 1; top: calc(var(--anim-gm-push-cursor-y) + 5%); left: calc(var(--anim-gm-push-cursor-x) + 3%); }
  90%  { opacity: 0; top: calc(var(--anim-gm-push-cursor-y) + 8%); left: calc(var(--anim-gm-push-cursor-x) + 5%); }
  100% { opacity: 0; top: calc(var(--anim-gm-push-cursor-y) + 8%); left: calc(var(--anim-gm-push-cursor-x) + 5%); }
}

/* Pulse on the Git plugin pin while the cursor is hovering it. */
.app-mock[data-active-demo="git-manager"][data-gm-phase="hover"] .am-plugin[data-am-plugin="git"],
.app-mock[data-active-demo="git-manager"][data-gm-phase="qv-open"] .am-plugin[data-am-plugin="git"],
.app-mock[data-active-demo="git-manager"][data-gm-phase="stage1"] .am-plugin[data-am-plugin="git"],
.app-mock[data-active-demo="git-manager"][data-gm-phase="stage2"] .am-plugin[data-am-plugin="git"],
.app-mock[data-active-demo="git-manager"][data-gm-phase="typing"] .am-plugin[data-am-plugin="git"],
.app-mock[data-active-demo="git-manager"][data-gm-phase="committed"] .am-plugin[data-am-plugin="git"],
.app-mock[data-active-demo="git-manager"][data-gm-phase="pushed"] .am-plugin[data-am-plugin="git"] {
  background: color-mix(in srgb, var(--accent) 18%, transparent);
  color: var(--accent);
}

/* ─── Quick-view popover ───────────────────────────────────────── */

.am-gm-qv {
  position: absolute;
  /* LEFT-edge anchored (no horizontal translate). The JS controller
     computes the left edge as `pin_center - half_popover_width` so
     the popover is visually centered on the pin, but the layout box
     matches the visual position - critical because the cursor
     measurement uses offsetLeft (transform-independent) and would
     otherwise be off by half_popover_width with translate(-50%, ...). */
  left: var(--anim-gm-popover-x);
  top:  var(--anim-gm-popover-y);
  width: 320px;
  max-width: 78%;
  transform-origin: top center;
  transform: translate(0, -4px) scale(0.96);
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border-2);
  border-radius: 8px;
  box-shadow: 0 16px 36px -10px rgba(0, 0, 0, 0.7);
  opacity: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 8px;
  font-family: var(--font-sans);
  font-size: 10.5px;
  overflow: hidden;
  z-index: 5;
}

.am-demo-git-manager.is-playing .am-gm-qv {
  animation:
    am-gm-qv-in  var(--anim-gm-qv-in-dur)  var(--ease) var(--anim-gm-qv-in-delay)  forwards,
    am-gm-qv-out var(--anim-gm-qv-out-dur) var(--ease) var(--anim-gm-qv-out-delay) forwards;
}

@keyframes am-gm-qv-in  { to { opacity: 1; transform: translate(0, 0) scale(1); } }
@keyframes am-gm-qv-out { to { opacity: 0; transform: translate(0, -4px) scale(0.96); } }

/* Summary row */
.am-gm-qv-summary {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 5px 8px;
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: 5px;
  font-size: 11px;
}
.am-gm-qv-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--amber);
  flex-shrink: 0;
}
/* Branch turns "clean" (green) after the commit + push sequence. */
.app-mock[data-active-demo="git-manager"][data-gm-phase="pushed"] .am-gm-qv-dot,
.app-mock[data-active-demo="git-manager"][data-gm-phase="rest"]   .am-gm-qv-dot {
  background: var(--green);
}
.am-gm-qv-branch {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  color: var(--text);
  font-weight: 500;
}
.am-gm-qv-branch-name { font-weight: 600; }
.am-gm-qv-meta {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  color: var(--text-3);
  font-size: 10px;
}

/* Ahead indicator: hidden by default, visible after commit. */
.am-gm-qv-ahead {
  display: none;
  align-items: center;
  gap: 2px;
  color: var(--accent);
  font-weight: 600;
}
.app-mock[data-active-demo="git-manager"][data-gm-phase="committed"] .am-gm-qv-ahead {
  display: inline-flex;
}

/* "N changed" indicator. Updates copy by phase. */
.am-gm-qv-changed { color: var(--text-3); }
.app-mock[data-active-demo="git-manager"][data-gm-phase="stage1"]    .am-gm-qv-changed::after,
.app-mock[data-active-demo="git-manager"][data-gm-phase="stage2"]    .am-gm-qv-changed::after,
.app-mock[data-active-demo="git-manager"][data-gm-phase="typing"]    .am-gm-qv-changed::after,
.app-mock[data-active-demo="git-manager"][data-gm-phase="committed"] .am-gm-qv-changed::after,
.app-mock[data-active-demo="git-manager"][data-gm-phase="pushed"]    .am-gm-qv-changed::after,
.app-mock[data-active-demo="git-manager"][data-gm-phase="rest"]      .am-gm-qv-changed::after {
  /* Reset the original "3 changed" text via phase-specific overrides below. */
  content: '';
}
/* The base text "3 changed" is replaced by phase-aware copy via JS, see qvChanged binding. */

/* Section labels */
.am-gm-qv-section-label {
  font-size: 9px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-3);
  font-weight: 600;
  padding: 0 2px;
}

/* Staged section is hidden by default (no staged files initially). */
.am-gm-qv-section-staged,
.am-gm-qv-files-staged { display: none; }
.app-mock[data-active-demo="git-manager"][data-gm-phase="stage1"] .am-gm-qv-section-staged,
.app-mock[data-active-demo="git-manager"][data-gm-phase="stage1"] .am-gm-qv-files-staged,
.app-mock[data-active-demo="git-manager"][data-gm-phase="stage2"] .am-gm-qv-section-staged,
.app-mock[data-active-demo="git-manager"][data-gm-phase="stage2"] .am-gm-qv-files-staged,
.app-mock[data-active-demo="git-manager"][data-gm-phase="typing"] .am-gm-qv-section-staged,
.app-mock[data-active-demo="git-manager"][data-gm-phase="typing"] .am-gm-qv-files-staged {
  display: block;
}
.am-gm-qv-files-staged { display: none; }
.app-mock[data-active-demo="git-manager"][data-gm-phase="stage1"] .am-gm-qv-files-staged,
.app-mock[data-active-demo="git-manager"][data-gm-phase="stage2"] .am-gm-qv-files-staged,
.app-mock[data-active-demo="git-manager"][data-gm-phase="typing"] .am-gm-qv-files-staged {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

/* File rows */
.am-gm-qv-files {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.am-gm-qv-file {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 4px 6px;
  background: var(--bg-2);
  border: 1px solid transparent;
  border-radius: 4px;
  font-family: var(--font-mono);
  font-size: 10px;
  min-width: 0;
}
.am-gm-qv-file:hover {
  background: color-mix(in srgb, var(--bg-2) 60%, var(--surface-2) 40%);
}

.am-gm-qv-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 14px;
  height: 14px;
  font-family: var(--font-sans);
  font-size: 9px;
  font-weight: 700;
  border-radius: 3px;
  flex-shrink: 0;
}
.am-gm-qv-badge-M { color: var(--amber);  background: color-mix(in srgb, var(--amber) 22%, transparent); }
.am-gm-qv-badge-A { color: var(--green);  background: color-mix(in srgb, var(--green) 22%, transparent); }
.am-gm-qv-badge-D { color: var(--red);    background: color-mix(in srgb, var(--red) 22%, transparent); }

.am-gm-qv-path {
  flex: 1;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--text-2);
}

.am-gm-qv-stats {
  font-size: 9.5px;
  color: var(--text-3);
  font-family: var(--font-mono);
  flex-shrink: 0;
}
.am-gm-qv-add { color: var(--green); }
.am-gm-qv-del { color: var(--red); }

.am-gm-qv-row-btn {
  width: 16px;
  height: 16px;
  padding: 0;
  background: transparent;
  border: 1px solid var(--border-2);
  border-radius: 3px;
  color: var(--text-2);
  font-family: var(--font-sans);
  font-size: 11px;
  line-height: 1;
  cursor: default;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  outline: none;
}

/* Phase-driven file visibility. Each file has TWO DOM entries (one
   in unstaged, one in staged); we toggle which is rendered. */
.am-gm-qv-files-unstaged [data-am-gm-file="1"] { display: flex; }
.app-mock[data-active-demo="git-manager"][data-gm-phase="stage1"]    .am-gm-qv-files-unstaged [data-am-gm-file="1"],
.app-mock[data-active-demo="git-manager"][data-gm-phase="stage2"]    .am-gm-qv-files-unstaged [data-am-gm-file="1"],
.app-mock[data-active-demo="git-manager"][data-gm-phase="typing"]    .am-gm-qv-files-unstaged [data-am-gm-file="1"],
.app-mock[data-active-demo="git-manager"][data-gm-phase="committed"] .am-gm-qv-files-unstaged [data-am-gm-file="1"],
.app-mock[data-active-demo="git-manager"][data-gm-phase="pushed"]    .am-gm-qv-files-unstaged [data-am-gm-file="1"],
.app-mock[data-active-demo="git-manager"][data-gm-phase="rest"]      .am-gm-qv-files-unstaged [data-am-gm-file="1"] {
  display: none;
}

.am-gm-qv-files-unstaged [data-am-gm-file="2"] { display: flex; }
.app-mock[data-active-demo="git-manager"][data-gm-phase="stage2"]    .am-gm-qv-files-unstaged [data-am-gm-file="2"],
.app-mock[data-active-demo="git-manager"][data-gm-phase="typing"]    .am-gm-qv-files-unstaged [data-am-gm-file="2"],
.app-mock[data-active-demo="git-manager"][data-gm-phase="committed"] .am-gm-qv-files-unstaged [data-am-gm-file="2"],
.app-mock[data-active-demo="git-manager"][data-gm-phase="pushed"]    .am-gm-qv-files-unstaged [data-am-gm-file="2"],
.app-mock[data-active-demo="git-manager"][data-gm-phase="rest"]      .am-gm-qv-files-unstaged [data-am-gm-file="2"] {
  display: none;
}

/* Staged section copies: visible only between stage and commit. */
.app-mock[data-active-demo="git-manager"][data-gm-phase="stage1"] .am-gm-qv-files-staged [data-am-gm-file="1"],
.app-mock[data-active-demo="git-manager"][data-gm-phase="stage2"] .am-gm-qv-files-staged [data-am-gm-file="1"],
.app-mock[data-active-demo="git-manager"][data-gm-phase="typing"] .am-gm-qv-files-staged [data-am-gm-file="1"] {
  display: flex;
}
.app-mock[data-active-demo="git-manager"][data-gm-phase="stage2"] .am-gm-qv-files-staged [data-am-gm-file="2"],
.app-mock[data-active-demo="git-manager"][data-gm-phase="typing"] .am-gm-qv-files-staged [data-am-gm-file="2"] {
  display: flex;
}
/* Hide the staged children by default (no phase). */
.am-gm-qv-files-staged [data-am-gm-file] { display: none; }

/* Commit message input */
.am-gm-qv-message {
  position: relative;
  width: 100%;
  min-height: 36px;
  padding: 6px 8px;
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: 5px;
  font-family: var(--font-sans);
  font-size: 11px;
  line-height: 1.4;
  color: var(--text);
  white-space: pre-wrap;
  opacity: 0.6;
  transition: opacity 120ms ease, border-color 120ms ease;
  box-sizing: border-box;
}
.am-gm-qv-message-placeholder {
  position: absolute;
  left: 8px;
  top: 6px;
  color: var(--text-muted);
  font-size: 11px;
  pointer-events: none;
}
.am-gm-qv-message-text { white-space: pre-wrap; }
.am-gm-qv-message-caret {
  display: inline-block;
  width: 1px;
  height: 11px;
  margin-left: 1px;
  background: var(--accent);
  vertical-align: -1px;
  opacity: 0;
}
/* Once a file is staged, the textarea becomes "enabled" (full opacity). */
.app-mock[data-active-demo="git-manager"][data-gm-phase="stage1"] .am-gm-qv-message,
.app-mock[data-active-demo="git-manager"][data-gm-phase="stage2"] .am-gm-qv-message,
.app-mock[data-active-demo="git-manager"][data-gm-phase="typing"] .am-gm-qv-message {
  opacity: 1;
  border-color: var(--border-2);
}
/* Replace placeholder text once the input is enabled. */
.app-mock[data-active-demo="git-manager"][data-gm-phase="stage1"] .am-gm-qv-message-placeholder,
.app-mock[data-active-demo="git-manager"][data-gm-phase="stage2"] .am-gm-qv-message-placeholder {
  content: 'Commit message…';
}
.app-mock[data-active-demo="git-manager"][data-gm-phase="stage1"] .am-gm-qv-message-placeholder::before,
.app-mock[data-active-demo="git-manager"][data-gm-phase="stage2"] .am-gm-qv-message-placeholder::before {
  content: 'Commit message…';
}
/* Hide the placeholder the instant any text is typed into the
 * message field, regardless of which phase is active. The previous
 * rule gated on data-gm-phase="typing", but the orchestrator sets
 * that phase AFTER the typing completes (~msgPhase) - so during
 * the actual typing window the placeholder stayed visible underneath
 * the growing text. Using `:has(.am-gm-qv-message-text:not(:empty))`
 * makes the rule reactive to real content. */
.am-gm-qv-message:has(.am-gm-qv-message-text:not(:empty)) .am-gm-qv-message-placeholder {
  display: none;
}

/* Belt-and-braces phase hide so the placeholder stays gone after
 * the message is cleared on commit (when the text span becomes
 * empty again). */
.app-mock[data-active-demo="git-manager"][data-gm-phase="committed"] .am-gm-qv-message-placeholder,
.app-mock[data-active-demo="git-manager"][data-gm-phase="pushed"]    .am-gm-qv-message-placeholder,
.app-mock[data-active-demo="git-manager"][data-gm-phase="rest"]      .am-gm-qv-message-placeholder {
  display: none;
}
/* Caret blink while typing window is active. */
.am-demo-git-manager.is-playing .am-gm-qv-message-caret {
  animation:
    am-gm-msg-caret-show 0.1s linear var(--anim-gm-msg-type-delay) forwards,
    am-gm-msg-caret-blink 1.05s steps(2, start) calc(var(--anim-gm-msg-type-delay) + 0.05s) infinite,
    am-gm-msg-caret-hide 0.1s linear var(--anim-gm-commit-click-delay) forwards;
}
@keyframes am-gm-msg-caret-show  { to { opacity: 1; } }
@keyframes am-gm-msg-caret-hide  { to { opacity: 0; } }
@keyframes am-gm-msg-caret-blink { 50% { opacity: 0; } }

/* Clear typed text after commit. */
.app-mock[data-active-demo="git-manager"][data-gm-phase="committed"] .am-gm-qv-message-text,
.app-mock[data-active-demo="git-manager"][data-gm-phase="pushed"]    .am-gm-qv-message-text,
.app-mock[data-active-demo="git-manager"][data-gm-phase="rest"]      .am-gm-qv-message-text {
  display: none;
}

/* Action row */
.am-gm-qv-inline-actions {
  display: flex;
  gap: 5px;
}

.am-gm-qv-action {
  flex: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 24px;
  padding: 0 8px;
  border-radius: 4px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  color: var(--text);
  font-size: 11px;
  font-weight: 500;
  cursor: default;
  position: relative;
}
.am-gm-qv-action.primary {
  background: var(--accent);
  color: #0a1518;
  border-color: var(--accent);
  font-weight: 600;
  opacity: 0.55;
}
/* Commit enabled when a file is staged + message exists. */
.app-mock[data-active-demo="git-manager"][data-gm-phase="typing"] .am-gm-qv-action.primary {
  opacity: 1;
}

/* Push button hidden until ahead > 0 (after commit). */
.am-gm-qv-action-push { display: none; }
.app-mock[data-active-demo="git-manager"][data-gm-phase="committed"] .am-gm-qv-action-push {
  display: inline-flex;
}

/* Commit click pulse. */
.am-demo-git-manager.is-playing .am-gm-qv-action.primary {
  animation: am-gm-commit-pulse 0.40s var(--ease) var(--anim-gm-commit-click-delay) 2 alternate;
}
@keyframes am-gm-commit-pulse {
  to { box-shadow: 0 0 0 4px color-mix(in srgb, var(--accent) 30%, transparent); }
}

/* Push click pulse. */
.am-demo-git-manager.is-playing .am-gm-qv-action-push {
  animation: am-gm-push-pulse 0.40s var(--ease) var(--anim-gm-push-click-delay) 2 alternate;
}
@keyframes am-gm-push-pulse {
  to { box-shadow: 0 0 0 4px color-mix(in srgb, var(--accent) 25%, transparent); }
}

/* Mobile: narrower popover so it fits inside the .app-mock. */
@media (max-width: 720px) {
  .am-gm-qv {
    width: 260px;
    max-width: 84%;
    font-size: 10px;
  }
  .am-gm-qv-path { font-size: 9.5px; }
  .am-gm-qv-stats { font-size: 9px; }
}

/* =============================================================
   Demo: voice plugin recording -> transcribing -> inject
   -----------------------------------------------------------------
   Mirrors the PySide6 voice indicator (overlay_qt.py). Pill at the
   bottom-center of the app-mock with a red recording dot, three-
   layered waveform bars, an `m:ss` timer ticking up, and an
   `Alt+Q` hotkey hint. Transitions to a transcribing state (red
   dot -> orange spinner, timer freezes), then exits and reveals
   transcribed text at the focused Claude terminal's prompt.

   Phase progression on .app-mock[data-voice-phase=...]:
       recording -> transcribing -> exited -> injecting -> settled
   ============================================================= */

.am-demo-voice {
  /* Covers the .app-mock (statusbar visible at the bottom). The
     indicator anchors to bottom-center via CSS; no header
     interaction needed. */
  top: 0;
  left: 0;
  right: 0;
  bottom: 24px;
  font-family: var(--font-sans);

  /* Master cycle + per-stage timing tokens. */
  --anim-cycle: 11s;
  --anim-voice-in-delay: 0.30s;
  --anim-voice-in-dur: 0.30s;
  --anim-voice-record-start: 0.55s;
  --anim-voice-record-dur: 3.00s;
  --anim-voice-transcribe-start: 3.55s;
  --anim-voice-transcribe-dur: 0.80s;
  --anim-voice-out-delay: 4.35s;
  --anim-voice-out-dur: 0.20s;
  --anim-voice-inject-delay: 4.70s;
  --anim-voice-inject-dur: 1.70s;
  --anim-voice-rest-delay: 6.50s;

  /* Production overlay colour tokens (overlay_qt.py defaults). */
  --voice-bg:      #131a25;
  --voice-border:  #2a3245;
  --voice-text:    #e6ecf5;
  --voice-muted:   #8a93a8;
  --voice-error:   #e85c66;   /* recording */
  --voice-warning: #e8a85c;   /* transcribing */
  --voice-accent:  #5cc1d4;   /* idle wave */
}

/* ─── Indicator pill ──────────────────────────────────────────── */

.am-voice-indicator {
  position: absolute;
  bottom: 8px;
  left: 50%;
  transform: translateX(-50%) scale(0.4);
  transform-origin: bottom center;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 7px 13px;
  background: var(--voice-bg);
  border: 1px solid var(--voice-border);
  border-radius: 13px;
  color: var(--voice-text);
  font-size: 10px;
  /* Three-pass shadow approximates the QPainter halo on the
   * production overlay (8px contact + 16px + 24px). */
  box-shadow:
    0 2px 8px  rgba(0, 0, 0, 0.50),
    0 6px 16px rgba(0, 0, 0, 0.35),
    0 14px 32px rgba(0, 0, 0, 0.25);
  opacity: 0;
  z-index: 9;
  pointer-events: none;
}

/* Pop-in (elastic-out) + shrink-out (scale-shrink). */
.am-demo-voice.is-playing .am-voice-indicator {
  animation:
    am-voice-pop-in  var(--anim-voice-in-dur)  cubic-bezier(0.34, 1.56, 0.64, 1) var(--anim-voice-in-delay) forwards,
    am-voice-pop-out var(--anim-voice-out-dur) cubic-bezier(0.55, 0, 0.7, 0.2) var(--anim-voice-out-delay) forwards;
}

@keyframes am-voice-pop-in  { to { opacity: 1; transform: translateX(-50%) scale(1); } }
@keyframes am-voice-pop-out { to { opacity: 0; transform: translateX(-50%) scale(0.4); } }

/* ─── Status indicator: red dot (recording) / orange spinner ─── */

.am-voice-status {
  position: relative;
  width: 14px;
  height: 14px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.am-voice-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--voice-error);
  box-shadow: 0 0 0 0 color-mix(in srgb, var(--voice-error) 60%, transparent);
  animation: am-voice-dot-pulse 1.4s ease-in-out infinite;
}
@keyframes am-voice-dot-pulse {
  0%, 100% { transform: scale(0.92); box-shadow: 0 0 0 0 color-mix(in srgb, var(--voice-error) 55%, transparent); }
  50%      { transform: scale(1.08); box-shadow: 0 0 0 6px color-mix(in srgb, var(--voice-error) 0%,  transparent); }
}

.am-voice-spinner {
  position: absolute;
  inset: 0;
  display: none;
  align-items: center;
  justify-content: center;
  color: var(--voice-warning);
}
.am-voice-spinner svg { animation: am-voice-spinner-rot 0.9s linear infinite; }
@keyframes am-voice-spinner-rot { to { transform: rotate(360deg); } }

/* Phase switch: hide red dot, show spinner. */
.app-mock[data-active-demo="voice"][data-voice-phase="transcribing"] .am-voice-dot {
  display: none;
}
.app-mock[data-active-demo="voice"][data-voice-phase="transcribing"] .am-voice-spinner {
  display: inline-flex;
}

/* ─── Waveform bars ────────────────────────────────────────────── */

.am-voice-waveform {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  height: 18px;
  flex-shrink: 0;
}

.am-voice-bar {
  width: 2px;
  border-radius: 1px;
  background: var(--voice-error);
  height: 3px;
}

/* Recording state: bars bounce with varied amplitudes/delays so
 * the wave doesn't feel mechanical. Production uses three overlapping
 * sine waves; this 16-bar approximation reads similarly at the
 * marketing scale. */
.am-demo-voice.is-playing .am-voice-bar {
  animation: am-voice-bar-bounce 0.70s ease-in-out infinite;
}

/* Per-bar variation: alternating phase + amplitudes so the wave has
 * a natural-feeling envelope (mid bars taller, edges shorter). */
.am-voice-bar:nth-child(1)  { animation-delay: -0.05s; animation-duration: 0.62s; --amp-h: 5px; }
.am-voice-bar:nth-child(2)  { animation-delay: -0.18s; animation-duration: 0.78s; --amp-h: 9px; }
.am-voice-bar:nth-child(3)  { animation-delay: -0.32s; animation-duration: 0.55s; --amp-h: 13px; }
.am-voice-bar:nth-child(4)  { animation-delay:  0.00s; animation-duration: 0.70s; --amp-h: 11px; }
.am-voice-bar:nth-child(5)  { animation-delay: -0.10s; animation-duration: 0.82s; --amp-h: 15px; }
.am-voice-bar:nth-child(6)  { animation-delay: -0.25s; animation-duration: 0.60s; --amp-h: 17px; }
.am-voice-bar:nth-child(7)  { animation-delay: -0.05s; animation-duration: 0.74s; --amp-h: 16px; }
.am-voice-bar:nth-child(8)  { animation-delay: -0.15s; animation-duration: 0.66s; --amp-h: 17px; }
.am-voice-bar:nth-child(9)  { animation-delay: -0.22s; animation-duration: 0.78s; --amp-h: 16px; }
.am-voice-bar:nth-child(10) { animation-delay: -0.08s; animation-duration: 0.58s; --amp-h: 15px; }
.am-voice-bar:nth-child(11) { animation-delay: -0.30s; animation-duration: 0.72s; --amp-h: 13px; }
.am-voice-bar:nth-child(12) { animation-delay: -0.12s; animation-duration: 0.64s; --amp-h: 12px; }
.am-voice-bar:nth-child(13) { animation-delay: -0.04s; animation-duration: 0.80s; --amp-h: 10px; }
.am-voice-bar:nth-child(14) { animation-delay: -0.20s; animation-duration: 0.56s; --amp-h: 9px; }
.am-voice-bar:nth-child(15) { animation-delay: -0.28s; animation-duration: 0.70s; --amp-h: 7px; }
.am-voice-bar:nth-child(16) { animation-delay: -0.06s; animation-duration: 0.66s; --amp-h: 5px; }

@keyframes am-voice-bar-bounce {
  0%, 100% { height: 3px; }
  50%      { height: var(--amp-h, 12px); }
}

/* Transcribing state: bars switch to idle accent colour and a
 * subtler oscillation (matches the production "soft sine, ~30%
 * amplitude" idle pulse). */
.app-mock[data-active-demo="voice"][data-voice-phase="transcribing"] .am-voice-bar {
  background: var(--voice-warning);
  animation: am-voice-bar-idle 1.4s ease-in-out infinite;
}
@keyframes am-voice-bar-idle {
  0%, 100% { height: 3px; opacity: 0.55; }
  50%      { height: calc(var(--amp-h, 12px) * 0.35); opacity: 0.85; }
}

/* ─── Timer + hotkey ───────────────────────────────────────────── */

.am-voice-meta {
  display: inline-flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 1px;
  flex-shrink: 0;
}

.am-voice-timer {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  color: var(--voice-text);
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}

.am-voice-hotkey {
  font-family: var(--font-mono);
  font-size: 8.5px;
  color: var(--voice-muted);
  line-height: 1.1;
  letter-spacing: 0.02em;
}

/* ─── Inject content in the focused Claude terminal ───────────── */

.am-voice-inject {
  /* Block-level so the inject sits on its own line below the previous
     prompt, irrespective of `white-space: pre-wrap` in the parent
     terminal body. Margin-top creates a visible gap without relying
     on literal newlines in the HTML (which would render as text and
     interact badly with the typing animation). */
  display: block;
  margin-top: 1em;
  opacity: 0;
  max-height: 0;
  overflow: hidden;
  white-space: nowrap;  /* keep the prompt + transcript on one line */
}

/* Reveal the inject during the voice demo. Hardcoded delay/dur
 * because the timing tokens live on .am-demo-voice (a sibling of
 * .am-grid, where this element lives) and CSS vars don't cascade
 * laterally. Keep these in sync with --anim-voice-inject-*. */
.app-mock[data-active-demo="voice"].is-anim-playing .am-voice-inject {
  animation: am-voice-inject-reveal 1.7s var(--ease) 4.7s forwards;
}
@keyframes am-voice-inject-reveal {
  0%   { opacity: 0; max-height: 0; }
  35%  { opacity: 1; max-height: 6em; }
  100% { opacity: 1; max-height: 6em; }
}

/* Hide the original prompt's blinking cursor while the voice
 * inject is appearing - reads as "the voice replaced the prompt". */
.app-mock[data-active-demo="voice"].is-anim-playing .am-cursor-base {
  animation: am-anim-fade-out 0.2s var(--ease) 4.6s forwards;
}

.am-cursor-voice-end {
  /* Standard blinking-cursor styling; uses the global @keyframes
   * am-blink from the static cursor rules. */
  opacity: 0;
}
.app-mock[data-active-demo="voice"].is-anim-playing .am-cursor-voice-end {
  animation: am-voice-end-cursor-show 0.1s linear 5.4s forwards;
}
@keyframes am-voice-end-cursor-show { to { opacity: 1; } }

/* Focused-terminal glow during the voice demo - matches the
 * browser-plugin "term-receive" treatment for visual consistency. */
.app-mock[data-active-demo="voice"].is-anim-playing .am-term-large.focused {
  animation: am-anim-term-receive 1.0s var(--ease) 4.7s forwards;
}

/* Mobile adjustments: pill scales down slightly so it doesn't
 * dominate a narrow .app-mock. */
@media (max-width: 720px) {
  .am-voice-indicator {
    padding: 6px 11px;
    gap: 8px;
    font-size: 9.5px;
  }
  .am-voice-waveform { height: 16px; }
  .am-voice-bar { width: 1.5px; }
  .am-voice-timer { font-size: 10px; }
  .am-voice-hotkey { font-size: 8px; }
}

/* =============================================================
   Demo: workspace-plugin
   -----------------------------------------------------------------
   Demonstrates the full enable-a-plugin -> dock-its-panel flow:

     cursor + Ctrl+, kbd chip  -> Settings modal in (Plugins tab)
                               -> cursor lands on Workspace toggle
                               -> click pulse + toggle flips on
                               -> Settings modal out
                               -> Workspace pin slides into header
                                  plugin row with glow pulse
                               -> cursor moves to the new pin -> click
                               -> Workspace side panel slides in
                                  from the right (between header +
                                  statusbar) and tree rows cascade in
                               -> cursor drops to the filter input,
                                  types "comp"; matching rows stay
                                  opaque, non-matching rows dim

   Wrapper covers the full .app-mock minus the statusbar so the
   cursor can reach both the new header pin AND the docked panel.

   Effects on elements OUTSIDE the wrapper - the workspace pin in
   the header plugin row and the focused-terminal dim - are gated on
   `.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="..."]`
   so the orchestrator drives multi-stage state via a single attr.

   All timing tokens are scoped to .am-demo-workspace-plugin so a
   designer can retune any single beat without touching JS.
   ============================================================= */

.am-demo-workspace-plugin {
  /* Same geometry as terminal-spawn: full mock minus the statusbar. */
  top: 0;
  left: 0;
  right: 0;
  bottom: 24px;
  font-family: var(--font-sans);
  color: var(--text);

  /* ─ Master cycle + per-stage timing tokens ─ */
  --anim-cycle: 22s;

  /* Stage 1: cursor enters from off-mock; kbd chip pops as a brief
     blip that signals "Ctrl + , was pressed", then fades just before
     the settings modal slides in (so the modal owns the focus). */
  --anim-wsp-cursor-enter-delay: 0.20s;
  --anim-wsp-kbd-chip-in-delay: 0.30s;
  --anim-wsp-kbd-chip-in-dur: 0.20s;
  --anim-wsp-kbd-chip-out-delay: 0.65s;
  --anim-wsp-kbd-chip-out-dur: 0.25s;

  /* Stage 2: settings modal slides in (centered). */
  --anim-wsp-settings-in-delay: 0.85s;
  --anim-wsp-settings-in-dur: 0.45s;

  /* Stage 3: cursor lands on the target toggle. */
  --anim-wsp-cursor-to-toggle-delay: 2.10s;

  /* Stage 4: click pulse + toggle flip-on. */
  --anim-wsp-toggle-pulse-delay: 2.55s;
  --anim-wsp-toggle-pulse-dur: 0.65s;
  --anim-wsp-toggle-flip-delay: 2.65s;
  --anim-wsp-toggle-flip-dur: 0.30s;

  /* Stage 5: settings modal slides back out. */
  --anim-wsp-settings-out-delay: 3.40s;
  --anim-wsp-settings-out-dur: 0.45s;

  /* Stage 6: workspace pin appears in the header plugin row with a
     glow + slide-in. The pin's `display` is toggled to inline-flex
     here so it actually claims layout; the orchestrator JS flips
     `data-wsp-phase` to drive the reveal across stages. */
  --anim-wsp-pin-reveal-delay: 3.85s;
  --anim-wsp-pin-reveal-dur: 0.55s;

  /* Stage 7: cursor moves to the new pin. */
  --anim-wsp-cursor-to-pin-delay: 4.60s;

  /* Stage 8: pin click pulse. */
  --anim-wsp-pin-pulse-delay: 5.15s;
  --anim-wsp-pin-pulse-dur: 0.55s;

  /* Stage 9: workspace side panel slides in from the right. */
  --anim-wsp-panel-in-delay: 5.40s;
  --anim-wsp-panel-in-dur: 0.55s;

  /* Stage 10: tree rows cascade in (per-row CSS delay handles the stagger). */
  --anim-wsp-tree-cascade-delay: 6.05s;

  /* Stage 11: cursor moves to the filter input. */
  --anim-wsp-cursor-to-filter-delay: 8.10s;

  /* Stage 12: filter typing. */
  --anim-wsp-filter-type-delay: 8.60s;
  --anim-wsp-filter-type-dur: 1.10s;
  --anim-wsp-filter-applied-delay: 10.0s;

  /* Stage 13: cursor descends to a matching tree row + double-click. */
  --anim-wsp-cursor-to-file-delay: 11.6s;
  --anim-wsp-file-dblclick-1-delay: 12.0s;
  --anim-wsp-file-dblclick-2-delay: 12.20s;
  --anim-wsp-file-dblclick-pulse-dur: 0.50s;

  /* Stage 14: editor overlay slides in over the terminal grid. */
  --anim-wsp-editor-in-delay: 12.5s;
  --anim-wsp-editor-in-dur: 0.55s;

  /* Stage 15: cursor moves into the editor body, types an edit. */
  --anim-wsp-cursor-to-edit-delay: 13.4s;
  --anim-wsp-edit-type-delay: 13.9s;
  --anim-wsp-edit-type-dur: 1.40s;

  /* Stage 16: cursor moves to the tab; tab is grabbed. */
  --anim-wsp-cursor-to-tab-delay: 15.6s;
  --anim-wsp-tab-grab-delay: 16.0s;

  /* Stage 17: tab is dragged away; once past the drag-distance threshold
     the docked editor swaps for a floating undocked window. */
  --anim-wsp-tab-drag-delay: 16.2s;
  --anim-wsp-undock-delay: 17.2s;
  --anim-wsp-undock-dur: 0.55s;

  /* Stage 18: cursor drift + cycle hold. */
  --anim-wsp-cursor-exit-delay: 19.5s;

  /* Cursor / pulse anchor positions (in wrapper-relative percentages).
     JS writes these on every cycle by measuring the rendered targets
     - the fallbacks below place the cursor / pulses reasonably
     before the first measurement lands. */
  --anim-wsp-cursor-enter-x: 110%;
  --anim-wsp-cursor-enter-y: 8%;
  --anim-wsp-toggle-cursor-x: 56%;
  --anim-wsp-toggle-cursor-y: 48%;
  --anim-wsp-pin-cursor-x: 60%;
  --anim-wsp-pin-cursor-y: 6%;
  --anim-wsp-filter-cursor-x: 76%;
  --anim-wsp-filter-cursor-y: 14%;
  --anim-wsp-toggle-pulse-x: 56%;
  --anim-wsp-toggle-pulse-y: 48%;
  --anim-wsp-pin-pulse-x: 60%;
  --anim-wsp-pin-pulse-y: 6%;

  /* Editor-flow cursor targets (JS-written; fallbacks placed inside the
     left workspace panel + docked editor area on the right). */
  --anim-wsp-file-cursor-x: 18%;
  --anim-wsp-file-cursor-y: 48%;
  --anim-wsp-file-pulse-x: 19%;
  --anim-wsp-file-pulse-y: 49%;
  --anim-wsp-edit-cursor-x: 70%;
  --anim-wsp-edit-cursor-y: 55%;
  --anim-wsp-tab-cursor-x: 56%;
  --anim-wsp-tab-cursor-y: 16%;
  /* Final drag-out target for the cursor: down and left of the tab
     bar so the drag distance exceeds the undock threshold AND the
     resulting floating window lands mostly inside the mock (not
     extending off the bottom-right edge). The floating window's
     transform offsets a fraction up + left from this point so the
     cursor lands on its titlebar after the drop. */
  --anim-wsp-drag-end-x: 44%;
  --anim-wsp-drag-end-y: 42%;

  /* Reusable colour token: enabled-toggle accent matches the rest of
     the marketing surface (var(--accent) is the cyan brand colour). */
  --anim-wsp-toggle-on: var(--accent);
  --anim-wsp-toggle-on-bg: color-mix(in srgb, var(--accent) 70%, transparent);
}

/* @property declarations let the cursor animation pick up live
   updates to these custom properties (e.g. when the window resizes
   mid-cycle and the orchestrator re-runs onMeasure). Without these
   the browser treats var() values as opaque strings, so a JS write
   doesn't propagate to running animations. Match the syntax to the
   underlying value type so the engine can interpolate too. */
@property --anim-wsp-toggle-cursor-x { syntax: '<percentage>'; inherits: true; initial-value: 56%; }
@property --anim-wsp-toggle-cursor-y { syntax: '<percentage>'; inherits: true; initial-value: 48%; }
@property --anim-wsp-pin-cursor-x    { syntax: '<percentage>'; inherits: true; initial-value: 60%; }
@property --anim-wsp-pin-cursor-y    { syntax: '<percentage>'; inherits: true; initial-value: 6%; }
@property --anim-wsp-filter-cursor-x { syntax: '<percentage>'; inherits: true; initial-value: 76%; }
@property --anim-wsp-filter-cursor-y { syntax: '<percentage>'; inherits: true; initial-value: 14%; }
@property --anim-wsp-toggle-pulse-x  { syntax: '<percentage>'; inherits: true; initial-value: 56%; }
@property --anim-wsp-toggle-pulse-y  { syntax: '<percentage>'; inherits: true; initial-value: 48%; }
@property --anim-wsp-pin-pulse-x     { syntax: '<percentage>'; inherits: true; initial-value: 60%; }
@property --anim-wsp-pin-pulse-y     { syntax: '<percentage>'; inherits: true; initial-value: 6%; }
@property --anim-wsp-file-cursor-x   { syntax: '<percentage>'; inherits: true; initial-value: 18%; }
@property --anim-wsp-file-cursor-y   { syntax: '<percentage>'; inherits: true; initial-value: 48%; }
@property --anim-wsp-file-pulse-x    { syntax: '<percentage>'; inherits: true; initial-value: 19%; }
@property --anim-wsp-file-pulse-y    { syntax: '<percentage>'; inherits: true; initial-value: 49%; }
@property --anim-wsp-edit-cursor-x   { syntax: '<percentage>'; inherits: true; initial-value: 70%; }
@property --anim-wsp-edit-cursor-y   { syntax: '<percentage>'; inherits: true; initial-value: 55%; }
@property --anim-wsp-tab-cursor-x    { syntax: '<percentage>'; inherits: true; initial-value: 56%; }
@property --anim-wsp-tab-cursor-y    { syntax: '<percentage>'; inherits: true; initial-value: 16%; }
@property --anim-wsp-drag-end-x      { syntax: '<percentage>'; inherits: true; initial-value: 75%; }
@property --anim-wsp-drag-end-y      { syntax: '<percentage>'; inherits: true; initial-value: 72%; }

/* ─── Cursor (workspace-plugin) ────────────────────────────────── */

.am-demo-workspace-plugin .am-anim-cursor {
  position: absolute;
  top: 8%;
  left: 110%;
  width: 14px;
  height: 16px;
  display: inline-flex;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.6));
  opacity: 0;
  z-index: 9;
}

.am-demo-workspace-plugin.is-playing .am-anim-cursor {
  animation: am-wsp-cursor-path var(--anim-cycle) linear forwards;
}

@keyframes am-wsp-cursor-path {
  /* Each percentage is mapped to seconds via `--anim-cycle = 22s`
     (1% = 220ms). The phase machine fires JS-driven attribute
     transitions at the timestamps in parentheses below; the cursor
     keyframes are positioned so the visual click-press lands a
     fraction BEFORE each phase transition that depends on it, which
     reads as cause-and-effect in the eye. */

  /* Cursor offscreen-right. Brief hold so the eye registers the
     keyboard chip + modal animation before tracking the cursor. */
  0%    { opacity: 0; top: var(--anim-wsp-cursor-enter-y); left: var(--anim-wsp-cursor-enter-x); }
  1.0%  { opacity: 0; top: var(--anim-wsp-cursor-enter-y); left: var(--anim-wsp-cursor-enter-x); }

  /* ~2.10s (9.5%): land on the target toggle. Pulse 2.55s (11.6%);
     flip 2.65s (12.0%). Press at 11.7% lands between them. */
  9.5%  { opacity: 1; top: var(--anim-wsp-toggle-cursor-y);  left: var(--anim-wsp-toggle-cursor-x); }
  11.2% { opacity: 1; top: var(--anim-wsp-toggle-cursor-y);  left: var(--anim-wsp-toggle-cursor-x); }
  11.7% { opacity: 1; top: calc(var(--anim-wsp-toggle-cursor-y) + 1.5%); left: var(--anim-wsp-toggle-cursor-x); }  /* press */
  12.3% { opacity: 1; top: var(--anim-wsp-toggle-cursor-y);  left: var(--anim-wsp-toggle-cursor-x); }                /* release */

  /* Brief hold while the toggle flips + settings modal closes. */
  17.5% { opacity: 1; top: var(--anim-wsp-toggle-cursor-y);  left: var(--anim-wsp-toggle-cursor-x); }

  /* ~5.04s (22.9%): arrive at the newly-revealed pin in the header.
     Pulse 5.15s (23.4%); panel-in 5.40s (24.5%). Press at 24.1%
     lands between pulse and panel-in. */
  22.9% { opacity: 1; top: var(--anim-wsp-pin-cursor-y);    left: var(--anim-wsp-pin-cursor-x); }
  23.7% { opacity: 1; top: var(--anim-wsp-pin-cursor-y);    left: var(--anim-wsp-pin-cursor-x); }
  24.1% { opacity: 1; top: calc(var(--anim-wsp-pin-cursor-y) + 1.6%); left: var(--anim-wsp-pin-cursor-x); }  /* press */
  24.7% { opacity: 1; top: var(--anim-wsp-pin-cursor-y);    left: var(--anim-wsp-pin-cursor-x); }              /* release */

  /* Brief hold while the panel slides in. */
  32.0% { opacity: 1; top: var(--anim-wsp-pin-cursor-y);    left: var(--anim-wsp-pin-cursor-x); }

  /* ~8.48s (38.5%): drop to the filter input. Phase `filtering` 8.52s
     (38.7%); typing begins 8.60s (39.1%). Press at 38.8% lands just
     before typing starts. */
  38.5% { opacity: 1; top: var(--anim-wsp-filter-cursor-y); left: var(--anim-wsp-filter-cursor-x); }
  38.8% { opacity: 1; top: calc(var(--anim-wsp-filter-cursor-y) + 1%); left: var(--anim-wsp-filter-cursor-x); }  /* press */
  39.1% { opacity: 1; top: var(--anim-wsp-filter-cursor-y); left: var(--anim-wsp-filter-cursor-x); }              /* release */

  /* Hold while typing. */
  50.0% { opacity: 1; top: var(--anim-wsp-filter-cursor-y); left: var(--anim-wsp-filter-cursor-x); }

  /* ~11.6s (52.7%): descend to the matching tree row.
     Double-click pulses 12.0s (54.5%) + 12.20s (55.5%); editor opens
     12.5s (56.8%). Two press-release pairs read as a double-click. */
  52.7% { opacity: 1; top: var(--anim-wsp-file-cursor-y);   left: var(--anim-wsp-file-cursor-x); }
  54.3% { opacity: 1; top: var(--anim-wsp-file-cursor-y);   left: var(--anim-wsp-file-cursor-x); }
  54.7% { opacity: 1; top: calc(var(--anim-wsp-file-cursor-y) + 0.8%); left: var(--anim-wsp-file-cursor-x); }  /* press 1 */
  55.0% { opacity: 1; top: var(--anim-wsp-file-cursor-y);   left: var(--anim-wsp-file-cursor-x); }              /* release 1 */
  55.3% { opacity: 1; top: calc(var(--anim-wsp-file-cursor-y) + 0.8%); left: var(--anim-wsp-file-cursor-x); }  /* press 2 */
  55.6% { opacity: 1; top: var(--anim-wsp-file-cursor-y);   left: var(--anim-wsp-file-cursor-x); }              /* release 2 */

  /* Hold while the editor overlay slides in (~12.5-13.1s = 56.8-59.5%). */
  60.0% { opacity: 1; top: var(--anim-wsp-file-cursor-y);   left: var(--anim-wsp-file-cursor-x); }

  /* ~13.4s (60.9%): move into the editor body. Click into the target
     line at 14.4s-ish so typing (14.5s = 65.9%) starts immediately
     after the press. */
  60.9% { opacity: 1; top: var(--anim-wsp-edit-cursor-y);   left: var(--anim-wsp-edit-cursor-x); }
  63.0% { opacity: 1; top: var(--anim-wsp-edit-cursor-y);   left: var(--anim-wsp-edit-cursor-x); }
  63.3% { opacity: 1; top: calc(var(--anim-wsp-edit-cursor-y) + 0.8%); left: var(--anim-wsp-edit-cursor-x); }  /* press */
  63.7% { opacity: 1; top: var(--anim-wsp-edit-cursor-y);   left: var(--anim-wsp-edit-cursor-x); }              /* release */

  /* Hold while typing fake edits (~13.9-15.3s = 63.2-69.5%). */
  70.0% { opacity: 1; top: var(--anim-wsp-edit-cursor-y);   left: var(--anim-wsp-edit-cursor-x); }

  /* ~15.6s (70.9%): move up to the editor tab. Grab/press at 16.0s
     (72.7%) so the drag (16.2s = 73.6%) starts immediately after
     the press registers. */
  70.9% { opacity: 1; top: var(--anim-wsp-tab-cursor-y);    left: var(--anim-wsp-tab-cursor-x); }
  72.3% { opacity: 1; top: var(--anim-wsp-tab-cursor-y);    left: var(--anim-wsp-tab-cursor-x); }
  72.7% { opacity: 1; top: calc(var(--anim-wsp-tab-cursor-y) + 0.6%); left: var(--anim-wsp-tab-cursor-x); }  /* press */

  /* Drag motion: cursor sweeps down + right to the drag-end target,
     dragging the tab ghost with it. Undock at 17.2s (78.2%) - by
     then the cursor is well past the drag-distance threshold. */
  73.6% { opacity: 1; top: var(--anim-wsp-tab-cursor-y);    left: var(--anim-wsp-tab-cursor-x); }              /* drag begins */
  78.0% { opacity: 1; top: var(--anim-wsp-drag-end-y);      left: var(--anim-wsp-drag-end-x); }              /* mid-drag */
  82.0% { opacity: 1; top: var(--anim-wsp-drag-end-y);      left: var(--anim-wsp-drag-end-x); }              /* settled at drop */

  /* Hold while the floating window settles into place. */
  87.0% { opacity: 1; top: var(--anim-wsp-drag-end-y);      left: var(--anim-wsp-drag-end-x); }

  /* Cursor drifts down + fades. */
  92.0% { opacity: 1; top: calc(var(--anim-wsp-drag-end-y) + 5%); left: calc(var(--anim-wsp-drag-end-x) + 4%); }
  96.0% { opacity: 0; top: calc(var(--anim-wsp-drag-end-y) + 8%); left: calc(var(--anim-wsp-drag-end-x) + 6%); }
  100%  { opacity: 0; top: calc(var(--anim-wsp-drag-end-y) + 8%); left: calc(var(--anim-wsp-drag-end-x) + 6%); }
}

/* ─── Keyboard shortcut chip ───────────────────────────────────── */

/* Brief affordance that pops just below the header to signal "Ctrl +
   , was pressed to open Settings". Centered horizontally so it
   doesn't overlap the static window controls / search trigger in the
   top-right of the header. Same look as the static `.am-kbd` in the
   search trigger so it reads as the same widget. */
.am-wsp-kbd-chip {
  position: absolute;
  top: 48px;
  left: 50%;
  padding: 5px 10px;
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: 5px;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--text);
  box-shadow: 0 4px 14px -4px rgba(0, 0, 0, 0.55), 0 0 0 1px color-mix(in srgb, var(--accent) 26%, transparent);
  opacity: 0;
  transform: translate(-50%, -6px) scale(0.95);
  pointer-events: none;
  z-index: 12;
  white-space: nowrap;
}

.am-demo-workspace-plugin.is-playing .am-wsp-kbd-chip {
  animation:
    am-wsp-kbd-in  var(--anim-wsp-kbd-chip-in-dur)  var(--ease) var(--anim-wsp-kbd-chip-in-delay)  forwards,
    am-wsp-kbd-out var(--anim-wsp-kbd-chip-out-dur) var(--ease) var(--anim-wsp-kbd-chip-out-delay) forwards;
}

@keyframes am-wsp-kbd-in {
  to { opacity: 1; transform: translate(-50%, 0) scale(1); }
}
@keyframes am-wsp-kbd-out {
  to { opacity: 0; transform: translate(-50%, -6px) scale(0.96); }
}

/* ─── Settings backdrop ────────────────────────────────────────── */

.am-wsp-settings-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(7, 11, 16, 0.55);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
  opacity: 0;
  z-index: 5;
}

.am-demo-workspace-plugin.is-playing .am-wsp-settings-backdrop {
  animation:
    am-wsp-fade-in  var(--anim-wsp-settings-in-dur)  var(--ease) var(--anim-wsp-settings-in-delay)  forwards,
    am-wsp-fade-out var(--anim-wsp-settings-out-dur) var(--ease) var(--anim-wsp-settings-out-delay) forwards;
}

@keyframes am-wsp-fade-in  { to { opacity: 1; } }
@keyframes am-wsp-fade-out { to { opacity: 0; } }

/* ─── Settings modal ───────────────────────────────────────────── */

.am-wsp-settings {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 86%;
  max-width: 520px;
  max-height: 78%;
  background: var(--surface);
  border: 1px solid var(--border-2);
  border-radius: 10px;
  box-shadow: 0 24px 60px -16px rgba(0, 0, 0, 0.7);
  overflow: hidden;
  opacity: 0;
  transform: translate(-50%, -45%) scale(0.96);
  display: flex;
  flex-direction: column;
  z-index: 6;
}

.am-demo-workspace-plugin.is-playing .am-wsp-settings {
  animation:
    am-wsp-settings-in  var(--anim-wsp-settings-in-dur)  var(--ease) var(--anim-wsp-settings-in-delay)  forwards,
    am-wsp-settings-out var(--anim-wsp-settings-out-dur) var(--ease) var(--anim-wsp-settings-out-delay) forwards;
}

@keyframes am-wsp-settings-in {
  to { opacity: 1; transform: translate(-50%, -50%) scale(1); }
}
@keyframes am-wsp-settings-out {
  to { opacity: 0; transform: translate(-50%, -45%) scale(0.97); }
}

.am-wsp-settings-header {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  border-bottom: 1px solid var(--border);
  background: var(--bg-2);
  flex-shrink: 0;
}
.am-wsp-settings-title {
  font-size: 12px;
  font-weight: 600;
  color: var(--text);
}
.am-wsp-settings-search {
  flex: 1;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 8px;
  height: 19px;
  border: 1px solid var(--border);
  border-radius: 5px;
  background: var(--bg-3, var(--bg-2));
  color: var(--text-3);
  font-size: 10px;
  max-width: 220px;
}
.am-wsp-settings-search svg { stroke: currentColor; opacity: 0.75; }
.am-wsp-settings-close {
  width: 18px;
  height: 18px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 4px;
  color: var(--text-3);
  background: transparent;
}

.am-wsp-settings-body {
  display: flex;
  flex: 1;
  min-height: 0;
}

/* Sidebar tabs */
.am-wsp-settings-tabs {
  width: 124px;
  min-width: 90px;
  flex-shrink: 0;
  border-right: 1px solid var(--border);
  background: var(--bg-2);
  padding: 6px 4px;
  display: flex;
  flex-direction: column;
  gap: 1px;
  overflow-y: auto;
}
.am-wsp-tab {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 8px;
  font-size: 10px;
  color: var(--text-2);
  border-radius: 4px;
  white-space: nowrap;
}
.am-wsp-tab-dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.55;
  flex-shrink: 0;
}
.am-wsp-tab.is-active {
  color: var(--text);
  background: color-mix(in srgb, var(--accent) 18%, transparent);
  box-shadow: inset 2px 0 0 var(--accent);
}
.am-wsp-tab.is-active .am-wsp-tab-dot {
  background: var(--accent);
  opacity: 1;
}

/* Plugins panel content */
.am-wsp-settings-content {
  flex: 1;
  padding: 10px 12px 12px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-width: 0;
  overflow: hidden;
}
.am-wsp-settings-heading-title {
  display: block;
  font-size: 12px;
  font-weight: 600;
  color: var(--text);
}
.am-wsp-settings-heading-sub {
  display: block;
  font-size: 10px;
  color: var(--text-3);
  margin-top: 1px;
}
.am-wsp-plugin-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
  overflow: hidden;
}
.am-wsp-plugin-card {
  display: grid;
  grid-template-columns: 22px 1fr auto;
  align-items: center;
  gap: 8px;
  padding: 5px 8px;
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: 6px;
  min-width: 0;
}
.am-wsp-plugin-card.is-enabled {
  border-color: color-mix(in srgb, var(--accent) 32%, var(--border));
  background: color-mix(in srgb, var(--accent) 6%, var(--bg-2));
}
.am-wsp-plugin-card.am-wsp-plugin-target {
  /* Slight emphasis (subtle accent glow) so the eye is already drawn to
     the Workspace row when the modal opens - the cursor's destination
     reads as the "active" affordance even before it arrives. */
  border-color: color-mix(in srgb, var(--accent) 38%, var(--border));
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--accent) 14%, transparent);
}
.am-wsp-plugin-avatar {
  width: 22px;
  height: 22px;
  border-radius: 5px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 16%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent) 30%, transparent);
  flex-shrink: 0;
}
.am-wsp-plugin-avatar svg { width: 12px; height: 12px; }
.am-wsp-avatar-git { color: #f0883e; background: rgba(240, 136, 62, 0.12); border-color: rgba(240, 136, 62, 0.30); }
.am-wsp-avatar-voice { color: #c490e8; background: rgba(196, 144, 232, 0.12); border-color: rgba(196, 144, 232, 0.30); }
.am-wsp-avatar-memory { color: #6fbf73; background: rgba(111, 191, 115, 0.12); border-color: rgba(111, 191, 115, 0.30); }
.am-wsp-avatar-workspace { /* keep the accent default - Workspace is the demo's hero */ }
.am-wsp-plugin-info { min-width: 0; }
.am-wsp-plugin-name {
  display: block;
  font-size: 10.5px;
  font-weight: 600;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.am-wsp-plugin-desc {
  display: block;
  font-size: 9px;
  color: var(--text-3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Toggle switch (mirrors PluginPanel.tsx's plugin-hub-toggle). */
.am-wsp-toggle {
  position: relative;
  width: 24px;
  height: 13px;
  border-radius: 8px;
  background: var(--border);
  border: 1px solid color-mix(in srgb, var(--border) 60%, transparent);
  flex-shrink: 0;
  transition: background 200ms var(--ease), border-color 200ms var(--ease);
}
.am-wsp-toggle-track {
  position: absolute;
  top: 1px;
  left: 1px;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--text-3);
  transition: transform 220ms var(--ease), background 220ms var(--ease);
}
.am-wsp-toggle.is-on {
  background: var(--anim-wsp-toggle-on-bg);
  border-color: var(--anim-wsp-toggle-on);
}
.am-wsp-toggle.is-on .am-wsp-toggle-track {
  transform: translateX(11px);
  background: #fff;
  box-shadow: 0 0 6px color-mix(in srgb, var(--accent) 65%, transparent);
}

/* Target toggle flips on at toggle-flip-delay. The keyframe animates
   the background + thumb position via a `to`-only frame so the
   "from" state is the off-state declared on `.am-wsp-toggle`. */
.am-demo-workspace-plugin.is-playing .am-wsp-toggle[data-am-anim-el="targetToggle"] {
  animation: am-wsp-toggle-flip var(--anim-wsp-toggle-flip-dur) var(--ease) var(--anim-wsp-toggle-flip-delay) forwards;
}
.am-demo-workspace-plugin.is-playing .am-wsp-toggle[data-am-anim-el="targetToggle"] .am-wsp-toggle-track {
  animation: am-wsp-toggle-thumb var(--anim-wsp-toggle-flip-dur) var(--ease) var(--anim-wsp-toggle-flip-delay) forwards;
}

@keyframes am-wsp-toggle-flip {
  to {
    background: var(--anim-wsp-toggle-on-bg);
    border-color: var(--anim-wsp-toggle-on);
  }
}
@keyframes am-wsp-toggle-thumb {
  to {
    transform: translateX(11px);
    background: #fff;
    box-shadow: 0 0 6px color-mix(in srgb, var(--accent) 65%, transparent);
  }
}

/* Target card gets a subtle confirmation glow on enable. */
.am-demo-workspace-plugin.is-playing .am-wsp-plugin-card.am-wsp-plugin-target {
  animation: am-wsp-card-confirm 0.6s var(--ease) calc(var(--anim-wsp-toggle-flip-delay) + 0.1s) forwards;
}

@keyframes am-wsp-card-confirm {
  0%, 100% { background: color-mix(in srgb, var(--accent) 6%, var(--bg-2)); }
  40%      { background: color-mix(in srgb, var(--accent) 18%, var(--bg-2)); }
}

/* ─── Toggle click pulse ───────────────────────────────────────── */

.am-wsp-toggle-pulse {
  position: absolute;
  left: var(--anim-wsp-toggle-pulse-x);
  top: var(--anim-wsp-toggle-pulse-y);
  width: 28px;
  height: 17px;
  transform: translate(-50%, -50%);
  border: 2px solid var(--accent);
  border-radius: 10px;
  opacity: 0;
  pointer-events: none;
  z-index: 7;
}

.am-demo-workspace-plugin.is-playing .am-wsp-toggle-pulse {
  animation: am-wsp-pulse-out var(--anim-wsp-toggle-pulse-dur) var(--ease) var(--anim-wsp-toggle-pulse-delay) 1 forwards;
}

@keyframes am-wsp-pulse-out {
  0%   { opacity: 0.85; transform: translate(-50%, -50%) scale(1); }
  100% { opacity: 0;    transform: translate(-50%, -50%) scale(1.7); }
}

/* ─── Workspace pin reveal in the header plugin row ────────────── */

/* The new pin is hidden by default (display: none keeps it from claiming
   layout outside the demo) and only revealed during the workspace-plugin
   demo from the `pinned` phase onward. */
.am-plugin-workspace {
  display: none;
}

/* Reveal-only state: pin enters the header row as a NORMAL (inactive)
   pin - same styling as the dormant Tests/Memory/Voice pins. No
   accent background, no glow ring; just the default text-3 colour
   inherited from .am-plugin. This matches production behaviour:
   enabling a plugin pins its icon, but the "active" highlight only
   appears when the user actually opens that plugin's panel. */
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="pinned"] .am-plugin-workspace,
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="pin-click"] .am-plugin-workspace,
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="panel-open"] .am-plugin-workspace,
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="panel-settled"] .am-plugin-workspace,
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="filtering"] .am-plugin-workspace,
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="filtered"] .am-plugin-workspace,
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="dblclick"] .am-plugin-workspace,
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="editor-open"] .am-plugin-workspace,
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="editing"] .am-plugin-workspace,
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="tab-grab"] .am-plugin-workspace,
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="dragging"] .am-plugin-workspace,
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="undocked"] .am-plugin-workspace,
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="rest"] .am-plugin-workspace {
  display: inline-flex;
  /* Slide-in animation runs once on the attribute transition; the
     `forwards` fill keeps the pin docked for the rest of the cycle.
     No accent styling here - the pin reads as inactive on reveal. */
  animation: am-wsp-pin-in var(--anim-wsp-pin-reveal-dur) var(--ease) both;
}

/* Active highlight: only kicks in once the cursor has actually clicked
   the pin and the panel is opening / open. Mirrors the production
   `.am-plugin.active` rule (accent background + accent text). */
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="panel-open"] .am-plugin-workspace,
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="panel-settled"] .am-plugin-workspace,
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="filtering"] .am-plugin-workspace,
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="filtered"] .am-plugin-workspace,
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="dblclick"] .am-plugin-workspace,
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="editor-open"] .am-plugin-workspace,
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="editing"] .am-plugin-workspace,
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="tab-grab"] .am-plugin-workspace,
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="dragging"] .am-plugin-workspace,
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="undocked"] .am-plugin-workspace,
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="rest"] .am-plugin-workspace {
  background: var(--accent-soft);
  color: var(--accent);
  transition: background 220ms var(--ease), color 220ms var(--ease);
}

@keyframes am-wsp-pin-in {
  0%   { opacity: 0; transform: translateY(-4px) scale(0.6); }
  60%  { opacity: 1; transform: translateY(0)    scale(1.12); }
  100% { opacity: 1; transform: translateY(0)    scale(1); }
}

/* Pin click pulse ring (anchored on the rendered pin via JS-written vars). */
.am-wsp-pin-pulse {
  position: absolute;
  left: var(--anim-wsp-pin-pulse-x);
  top: var(--anim-wsp-pin-pulse-y);
  width: 24px;
  height: 24px;
  transform: translate(-50%, -50%);
  border: 2px solid var(--accent);
  border-radius: 8px;
  opacity: 0;
  pointer-events: none;
  z-index: 7;
}

.am-demo-workspace-plugin.is-playing .am-wsp-pin-pulse {
  animation: am-wsp-pulse-out var(--anim-wsp-pin-pulse-dur) var(--ease) var(--anim-wsp-pin-pulse-delay) 2 forwards;
}

/* ─── Workspace side panel ────────────────────────────────────── */

.am-wsp-panel {
  position: absolute;
  top: 40px;          /* below the header */
  left: 0;
  bottom: 0;          /* statusbar offset handled by the demo wrapper */
  width: 46%;
  min-width: 240px;
  max-width: 360px;
  background: var(--surface);
  border-right: 1px solid var(--border-2);
  box-shadow:
    8px 0 22px -10px rgba(0, 0, 0, 0.55),
    2px 0 0 0 color-mix(in srgb, var(--accent) 14%, transparent);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  opacity: 0.4;
  transform: translateX(-102%);
  z-index: 5;
}

.am-demo-workspace-plugin.is-playing .am-wsp-panel {
  animation: am-wsp-panel-in var(--anim-wsp-panel-in-dur) var(--ease) var(--anim-wsp-panel-in-delay) forwards;
}

@keyframes am-wsp-panel-in {
  0%   { opacity: 0.4; transform: translateX(-102%); }
  60%  { opacity: 1;   transform: translateX(0);     }
  100% { opacity: 1;   transform: translateX(0);     }
}

.am-wsp-panel-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 5px 9px;
  border-bottom: 1px solid var(--border);
  background: var(--bg-2);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--text);
  text-transform: uppercase;
  flex-shrink: 0;
}
.am-wsp-panel-close {
  width: 14px;
  height: 14px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--text-3);
  border-radius: 3px;
}

.am-wsp-panel-toolbar {
  display: flex;
  align-items: center;
  gap: 3px;
  padding: 5px 6px;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}

/* Filter input (purely visual span - character typing is JS-driven). */
.am-wsp-filter {
  position: relative;
  flex: 1;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 7px;
  height: 18px;
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: 4px;
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text);
  min-width: 0;
}
.am-wsp-filter svg { color: var(--text-3); flex-shrink: 0; }
.am-wsp-filter-text {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.am-wsp-filter-caret {
  display: inline-block;
  width: 1.5px;
  height: 9px;
  background: var(--accent);
  margin-left: 1px;
  opacity: 0;
  animation: am-blink 1s steps(1) infinite;
}
.am-wsp-filter-placeholder {
  position: absolute;
  left: 22px;
  color: var(--text-3);
  opacity: 0.5;
  pointer-events: none;
}

/* Focus + reveal caret once the cursor "clicks into" the filter input.
   Persists across every post-filter phase so the typed text never
   loses its placeholder-hidden / caret-visible state. */
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="filtering"] .am-wsp-filter,
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="filtered"] .am-wsp-filter,
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="dblclick"] .am-wsp-filter,
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="editor-open"] .am-wsp-filter,
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="editing"] .am-wsp-filter,
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="tab-grab"] .am-wsp-filter,
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="dragging"] .am-wsp-filter,
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="undocked"] .am-wsp-filter,
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="rest"] .am-wsp-filter {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 5%, var(--bg-2));
}
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="filtering"] .am-wsp-filter-caret {
  opacity: 1;
}
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="filtering"] .am-wsp-filter-placeholder,
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="filtered"] .am-wsp-filter-placeholder,
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="dblclick"] .am-wsp-filter-placeholder,
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="editor-open"] .am-wsp-filter-placeholder,
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="editing"] .am-wsp-filter-placeholder,
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="tab-grab"] .am-wsp-filter-placeholder,
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="dragging"] .am-wsp-filter-placeholder,
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="undocked"] .am-wsp-filter-placeholder,
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="rest"] .am-wsp-filter-placeholder {
  opacity: 0;
}

.am-wsp-panel-btn {
  width: 18px;
  height: 18px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--text-3);
  background: transparent;
  border: 0;
  border-radius: 3px;
  cursor: default;
  flex-shrink: 0;
  padding: 0;
}

.am-wsp-panel-tree {
  flex: 1;
  overflow: hidden;
  padding: 4px 0;
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-2);
}

.am-wsp-tree-row {
  display: flex;
  align-items: center;
  gap: 5px;
  padding: 2px 8px 2px calc(6px + (var(--depth) * 12px));
  white-space: nowrap;
  opacity: 0;
  transform: translateY(2px);
  transition: opacity 240ms var(--ease), background 200ms var(--ease);
}
.am-wsp-tree-row[data-depth="0"] { --depth: 0; }
.am-wsp-tree-row[data-depth="1"] { --depth: 1; }
.am-wsp-tree-row[data-depth="2"] { --depth: 2; }
.am-wsp-tree-row[data-depth="3"] { --depth: 3; }

.am-wsp-tree-arrow {
  display: inline-block;
  width: 8px;
  text-align: center;
  font-size: 8px;
  color: var(--text-3);
  flex-shrink: 0;
  transform-origin: center;
}
.am-wsp-tree-row[data-folder="open"] .am-wsp-tree-arrow { transform: rotate(90deg); }
.am-wsp-tree-arrow-spacer {
  display: inline-block;
  width: 8px;
  flex-shrink: 0;
}

.am-wsp-tree-dir { display: inline-flex; flex-shrink: 0; }
.am-wsp-tree-file {
  width: 11px;
  height: 11px;
  flex-shrink: 0;
  border-radius: 2px;
  position: relative;
  background:
    linear-gradient(135deg, transparent 0 60%, color-mix(in srgb, var(--text-3) 35%, transparent) 60% 100%),
    color-mix(in srgb, var(--text-3) 15%, transparent);
  border: 1px solid color-mix(in srgb, var(--text-3) 30%, transparent);
}
.am-wsp-tree-file[data-ext="tsx"],
.am-wsp-tree-file[data-ext="ts"]   { border-color: #3178c6; background-color: rgba(49, 120, 198, 0.12); }
.am-wsp-tree-file[data-ext="js"]   { border-color: #d1c358; background-color: rgba(209, 195, 88, 0.14); }
.am-wsp-tree-file[data-ext="json"] { border-color: #a8b577; background-color: rgba(168, 181, 119, 0.14); }
.am-wsp-tree-file[data-ext="md"]   { border-color: #2b80ec; background-color: rgba(43, 128, 236, 0.14); }

.am-wsp-tree-name {
  overflow: hidden;
  text-overflow: ellipsis;
  font-size: 10px;
}

/* Tree cascade: each row reveals with a staggered delay. The
   `--anim-wsp-tree-cascade-delay` token marks t=0 for the stagger.
   nth-child handles the per-row offset so JS doesn't need to
   touch each row individually. */
.am-demo-workspace-plugin.is-playing .am-wsp-tree-row {
  animation: am-wsp-tree-row-in 0.35s var(--ease) forwards;
  animation-delay: calc(var(--anim-wsp-tree-cascade-delay) + (var(--row-i, 0) * 0.06s));
}
.am-wsp-panel-tree .am-wsp-tree-row:nth-child(1)  { --row-i: 0; }
.am-wsp-panel-tree .am-wsp-tree-row:nth-child(2)  { --row-i: 1; }
.am-wsp-panel-tree .am-wsp-tree-row:nth-child(3)  { --row-i: 2; }
.am-wsp-panel-tree .am-wsp-tree-row:nth-child(4)  { --row-i: 3; }
.am-wsp-panel-tree .am-wsp-tree-row:nth-child(5)  { --row-i: 4; }
.am-wsp-panel-tree .am-wsp-tree-row:nth-child(6)  { --row-i: 5; }
.am-wsp-panel-tree .am-wsp-tree-row:nth-child(7)  { --row-i: 6; }
.am-wsp-panel-tree .am-wsp-tree-row:nth-child(8)  { --row-i: 7; }
.am-wsp-panel-tree .am-wsp-tree-row:nth-child(9)  { --row-i: 8; }
.am-wsp-panel-tree .am-wsp-tree-row:nth-child(10) { --row-i: 9; }
.am-wsp-panel-tree .am-wsp-tree-row:nth-child(11) { --row-i: 10; }
.am-wsp-panel-tree .am-wsp-tree-row:nth-child(12) { --row-i: 11; }
.am-wsp-panel-tree .am-wsp-tree-row:nth-child(13) { --row-i: 12; }
.am-wsp-panel-tree .am-wsp-tree-row:nth-child(14) { --row-i: 13; }

@keyframes am-wsp-tree-row-in {
  to { opacity: 1; transform: translateY(0); }
}

/* Filter applied: non-matching rows dim (kept rendered so the layout
   doesn't reflow under the cursor). The matching rows stay opaque and
   pick up a subtle accent background to read as "selected". */
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="filtered"] .am-wsp-tree-row:not([data-am-wsp-match]),
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="dblclick"] .am-wsp-tree-row:not([data-am-wsp-match]),
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="editor-open"] .am-wsp-tree-row:not([data-am-wsp-match]),
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="editing"] .am-wsp-tree-row:not([data-am-wsp-match]),
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="tab-grab"] .am-wsp-tree-row:not([data-am-wsp-match]),
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="dragging"] .am-wsp-tree-row:not([data-am-wsp-match]),
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="undocked"] .am-wsp-tree-row:not([data-am-wsp-match]),
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="rest"] .am-wsp-tree-row:not([data-am-wsp-match]) {
  opacity: 0.22;
}
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="filtered"] .am-wsp-tree-row[data-am-wsp-match],
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="dblclick"] .am-wsp-tree-row[data-am-wsp-match],
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="editor-open"] .am-wsp-tree-row[data-am-wsp-match],
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="editing"] .am-wsp-tree-row[data-am-wsp-match],
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="tab-grab"] .am-wsp-tree-row[data-am-wsp-match],
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="dragging"] .am-wsp-tree-row[data-am-wsp-match],
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="undocked"] .am-wsp-tree-row[data-am-wsp-match],
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="rest"] .am-wsp-tree-row[data-am-wsp-match] {
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  color: var(--text);
}

/* ─── File double-click pulse ────────────────────────────────────
   Anchored on the matching tree row the cursor lands on; two
   iterations read as a double-click. Position written by JS into
   --anim-wsp-file-pulse-{x,y} so it tracks whichever row was hit. */
.am-wsp-file-pulse {
  position: absolute;
  left: var(--anim-wsp-file-pulse-x);
  top: var(--anim-wsp-file-pulse-y);
  /* Width is JS-driven from the actual file-name span's rendered
     width so the ring always fits the name on every viewport size.
     The fallback (140px) covers `DockHeaderCompact.tsx` at the
     default font size. */
  width: var(--anim-wsp-file-pulse-w, 140px);
  height: 16px;
  transform: translate(-50%, -50%);
  border: 2px solid var(--accent);
  border-radius: 4px;
  opacity: 0;
  pointer-events: none;
  z-index: 7;
}

.am-demo-workspace-plugin.is-playing .am-wsp-file-pulse {
  animation:
    am-wsp-file-pulse-1 var(--anim-wsp-file-dblclick-pulse-dur) var(--ease) var(--anim-wsp-file-dblclick-1-delay) forwards,
    am-wsp-file-pulse-2 var(--anim-wsp-file-dblclick-pulse-dur) var(--ease) var(--anim-wsp-file-dblclick-2-delay) forwards;
}

@keyframes am-wsp-file-pulse-1 {
  0%   { opacity: 0.85; transform: translate(-50%, -50%) scale(1); }
  100% { opacity: 0;    transform: translate(-50%, -50%) scale(1.4); }
}
@keyframes am-wsp-file-pulse-2 {
  0%   { opacity: 0.85; transform: translate(-50%, -50%) scale(1); }
  100% { opacity: 0;    transform: translate(-50%, -50%) scale(1.4); }
}

/* ─── Docked editor overlay ──────────────────────────────────────
   Production mirror: EditorOverlay.tsx covers the full grid area
   with `inset: 0`. In the demo wrapper the grid sits to the right
   of the workspace panel (panel width: 46% / max 360px), so the
   editor overlay docks starting at the panel's right edge and
   extends to the right edge of the mock. The slide-in mirrors the
   production "paper shuffle" hand-off (subtle translate + opacity). */
.am-wsp-editor {
  position: absolute;
  top: 40px;                      /* below the header */
  left: max(46%, 0px);
  /* Width-derived left: workspace panel is min-width: 240px / max-width:
     360px / 46%, so the editor takes whatever remains. Using max() on
     left + right: 0 means the editor naturally fills the residual. */
  right: 0;
  bottom: 0;
  background: var(--surface);
  border-top: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  opacity: 0;
  transform: translate3d(-8px, 6px, 0) scale(0.99);
  z-index: 6;
  pointer-events: none;
}

/* Override left to honour the panel's max-width on wider viewports
   (so the editor doesn't leave a gap beside a 360px-capped panel). */
@media (min-width: 800px) {
  .am-wsp-editor {
    left: min(46%, 360px);
  }
}

.am-demo-workspace-plugin.is-playing .am-wsp-editor {
  animation:
    am-wsp-editor-in var(--anim-wsp-editor-in-dur) var(--ease) var(--anim-wsp-editor-in-delay) forwards,
    am-wsp-editor-out var(--anim-wsp-undock-dur) var(--ease) var(--anim-wsp-undock-delay) forwards;
}

@keyframes am-wsp-editor-in {
  0%   { opacity: 0; transform: translate3d(-8px, 6px, 0) scale(0.99); }
  100% { opacity: 1; transform: translate3d(0, 0, 0) scale(1); }
}

/* On undock: the docked overlay slides + tilts away (mirrors the
   paper-shuffle keyframe in global.css) and fades to 0 as the
   floating window fades in over it. */
@keyframes am-wsp-editor-out {
  0%   { opacity: 1; transform: translate3d(0, 0, 0) rotate(0deg); }
  100% { opacity: 0; transform: translate3d(14px, 18px, 0) rotate(0.8deg); }
}

/* Editor tab bar (mirrors .editor-tab-bar). */
.am-wsp-editor-tabbar {
  display: flex;
  align-items: stretch;
  height: 26px;
  background: var(--bg-2);
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
  overflow: hidden;
}
.am-wsp-editor-tabs {
  display: flex;
  align-items: stretch;
  flex: 1 1 0;
  min-width: 0;
}
.am-wsp-editor-tab {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 0 9px;
  height: 100%;
  font-size: 10px;
  color: var(--text-2);
  border-right: 1px solid var(--border);
  white-space: nowrap;
  font-family: var(--font-mono);
}
.am-wsp-editor-tab.is-active {
  color: var(--text);
  background: var(--surface);
  /* Accent underline matches the production `.editor-tab-active`. */
  box-shadow: inset 0 -2px 0 var(--accent);
}
.am-wsp-editor-tab-icon {
  width: 9px;
  height: 9px;
  border-radius: 1.5px;
  background:
    linear-gradient(135deg, transparent 0 60%, color-mix(in srgb, #3178c6 35%, transparent) 60% 100%),
    color-mix(in srgb, #3178c6 18%, transparent);
  border: 1px solid #3178c6;
  flex-shrink: 0;
}
.am-wsp-editor-tab-name { color: inherit; font-family: var(--font-mono); }
.am-wsp-editor-tab-dirty {
  color: var(--accent);
  font-size: 8px;
  opacity: 0;             /* hidden until typing makes the buffer dirty */
  transition: opacity 200ms var(--ease);
}
.am-wsp-editor-tab-close {
  font-size: 11px;
  color: var(--text-3);
  margin-left: 2px;
}
.am-wsp-editor-actions {
  display: inline-flex;
  align-items: center;
  gap: 1px;
  padding: 0 5px;
  flex-shrink: 0;
  background: var(--bg-2);
  box-shadow: -6px 0 6px -4px rgba(0, 0, 0, 0.35);
}
.am-wsp-editor-btn {
  width: 17px;
  height: 17px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--text-3);
  background: transparent;
  border: 0;
  border-radius: 3px;
  cursor: default;
  padding: 0;
}
.am-wsp-editor-close-all { color: var(--text-3); font-size: 14px; margin-left: 2px; padding: 0 4px; }

/* Editor body: gutter + code + minimap, mirrors Monaco's layout.
   Line-height stays tight (1.35) - matches the production Monaco
   default for the dock's font size and keeps the buffer reading as
   code instead of leaving each line floating in a band of whitespace. */
.am-wsp-editor-body {
  flex: 1;
  display: grid;
  grid-template-columns: 24px 1fr 24px;
  min-height: 0;
  background: var(--surface);
  font-family: var(--font-mono);
  font-size: 10.5px;
  line-height: 1.35;
  color: var(--text-2);
  overflow: hidden;
}
.am-wsp-editor-gutter {
  background: var(--bg-2);
  color: var(--text-3);
  font-size: 9.5px;
  text-align: right;
  padding: 4px 4px 0 0;
  display: flex;
  flex-direction: column;
  border-right: 1px solid var(--border);
  user-select: none;
  line-height: 1.35;
}
.am-wsp-editor-gutter span { display: block; line-height: 1.35; }
.am-wsp-editor-code {
  padding: 4px 8px;
  overflow: hidden;
  white-space: pre;
  position: relative;
}
.am-wsp-editor-line {
  display: block;
  /* Lock line-height per row so &nbsp; blank lines (used as visual
     separators in the buffer) don't pick up the parent line-height
     and balloon vertically - keeps the sample reading like code. */
  line-height: 1.35;
  min-height: 1.35em;
}
.am-wsp-editor-line-target {
  /* Subtle active-line highlight so the user reads it as the cursor's
     resting line. The accent shifts in once the cursor clicks the line
     (phase=editing); before that it's a faint background hint. */
  background: color-mix(in srgb, var(--accent) 5%, transparent);
  margin: 0 -8px;
  padding: 0 8px;
  transition: background 220ms var(--ease);
}
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="editing"] .am-wsp-editor-line-target,
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="dragging"] .am-wsp-editor-line-target,
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="undocked"] .am-wsp-editor-line-target {
  background: color-mix(in srgb, var(--accent) 12%, transparent);
}

/* Monaco-style syntax tokens (no real highlighting; just enough
   colour separation that the buffer reads as code). */
.am-wsp-kw   { color: #c678dd; }   /* keywords */
.am-wsp-str  { color: #98c379; }   /* strings */
.am-wsp-tok  { color: #61afef; }   /* identifiers */
.am-wsp-fn   { color: #61afef; }   /* function names */
.am-wsp-tag  { color: #e06c75; }   /* JSX tags */
.am-wsp-attr { color: #d19a66; }   /* attribute names */
.am-wsp-prop { color: #e5c07b; }   /* property access */
.am-wsp-ind  { color: transparent; user-select: text; }   /* indent spaces (preserved) */
.am-wsp-typed-new {
  color: var(--text);
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  border-radius: 2px;
  padding: 0 1px;
}

/* Editor caret (inline blinker inside the target line). */
.am-wsp-editor-caret {
  display: inline-block;
  width: 1.5px;
  height: 11px;
  background: var(--accent);
  margin: 0 1px;
  vertical-align: middle;
  opacity: 0;
}
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="editing"] .am-wsp-editor-caret,
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="tab-grab"] .am-wsp-editor-caret,
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="dragging"] .am-wsp-editor-caret {
  animation: am-blink 1s steps(1) infinite;
}

/* Minimap rail. Each <span> is a "compressed line" - widths drive
   the bar-chart silhouette that real Monaco minimaps render. */
.am-wsp-editor-minimap {
  background: var(--bg-2);
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 5px 3px;
  border-left: 1px solid var(--border);
}
.am-wsp-editor-minimap span {
  display: block;
  height: 3px;
  background: color-mix(in srgb, var(--text-3) 32%, transparent);
  border-radius: 1px;
}
/* Per-bar widths for the decorative minimap. Kept in CSS (not inline style=
   attributes) so the strict CSP style-src with no 'unsafe-inline' applies. */
.am-wsp-editor-minimap span:nth-child(1) { width: 56%; }
.am-wsp-editor-minimap span:nth-child(2) { width: 78%; }
.am-wsp-editor-minimap span:nth-child(3) { width: 64%; }
.am-wsp-editor-minimap span:nth-child(4) { width: 8%; }
.am-wsp-editor-minimap span:nth-child(5) { width: 72%; }
.am-wsp-editor-minimap span:nth-child(6) { width: 84%; }
.am-wsp-editor-minimap span:nth-child(7) { width: 90%; }
.am-wsp-editor-minimap span:nth-child(8) { width: 50%; }
.am-wsp-editor-minimap span:nth-child(9) { width: 56%; }
.am-wsp-editor-minimap span:nth-child(10) { width: 38%; }
.am-wsp-editor-minimap span:nth-child(11) { width: 14%; }

/* Dirty indicator: revealed once the typed-edit is in flight. */
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="editing"] .am-wsp-editor-tab-dirty,
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="tab-grab"] .am-wsp-editor-tab-dirty,
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="dragging"] .am-wsp-editor-tab-dirty,
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="undocked"] .am-wsp-editor-tab-dirty {
  opacity: 1;
}

/* ─── Tab ghost (drag preview) ───────────────────────────────────
   Appears only during the `tab-grab` + `dragging` phases. Visually
   mirrors the active editor tab (icon + name + dirty dot) and lifts
   slightly off the surface via shadow + scale so it reads as a
   detached drag preview. JS pins its position to the cursor's
   current target every frame. */
.am-wsp-tab-ghost {
  position: absolute;
  left: var(--anim-wsp-tab-cursor-x);
  top: var(--anim-wsp-tab-cursor-y);
  /* Anchor the ghost so the cursor sits over its left edge - this is
     where the production drag handle sits visually. */
  transform: translate(-12px, 4px) scale(0.96);
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 9px;
  height: 22px;
  background: var(--bg-2);
  border: 1px solid color-mix(in srgb, var(--accent) 40%, var(--border));
  border-radius: 4px;
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text);
  box-shadow: 0 10px 22px -10px rgba(0, 0, 0, 0.6), 0 0 0 1px color-mix(in srgb, var(--accent) 20%, transparent);
  opacity: 0;
  pointer-events: none;
  z-index: 11;
}

.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="tab-grab"] .am-wsp-tab-ghost,
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="dragging"] .am-wsp-tab-ghost {
  opacity: 1;
  /* Match the cursor's tab->drag-end sweep duration so the ghost and
     cursor arrive at the drop point together. The cursor keyframe
     moves from 73.6% to 78% of a 22s cycle = 0.97s; round to 1s. */
  transition: left 1s linear, top 1s linear, transform 1s var(--ease);
}

.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="dragging"] .am-wsp-tab-ghost {
  /* Once the drag truly begins (past the 20px-equivalent threshold)
     the ghost follows the cursor's drag-end target. The 1s transition
     above keeps the ghost glued to the cursor across the sweep. */
  left: var(--anim-wsp-drag-end-x);
  top: var(--anim-wsp-drag-end-y);
  transform: translate(-12px, 4px) scale(1) rotate(2deg);
}

/* ─── Floating undocked editor window ────────────────────────────
   Appears once the drag has crossed the undock threshold. Anchored
   near the drop point with rounded corners + dropdown shadow so it
   reads as a separate OS window, not part of the dock. Same chrome
   as the production detached editor: titlebar (file + project) +
   window-controls cluster, then tab bar, then body. */
.am-wsp-floating-editor {
  position: absolute;
  left: var(--anim-wsp-drag-end-x);
  top: var(--anim-wsp-drag-end-y);
  width: 50%;
  max-width: 320px;
  min-width: 220px;
  min-height: 150px;
  height: 56%;
  max-height: 210px;
  /* Anchor so the cursor lands near the floating window's titlebar.
     Translate -25%/-10% pulls the window up + left from the drop
     point so it sits comfortably inside the mock (vs. extending off
     the bottom-right when the drop was farther down + right). */
  transform: translate(-25%, -10%) scale(0.86);
  background: var(--surface);
  border: 1px solid var(--border-2);
  border-radius: 6px;
  box-shadow:
    0 22px 50px -16px rgba(0, 0, 0, 0.72),
    0 0 0 1px color-mix(in srgb, var(--accent) 18%, transparent);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  opacity: 0;
  pointer-events: none;
  z-index: 7;
}

.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="undocked"] .am-wsp-floating-editor,
.app-mock[data-active-demo="workspace-plugin"][data-wsp-phase="rest"] .am-wsp-floating-editor {
  animation: am-wsp-floating-in var(--anim-wsp-undock-dur) var(--ease) forwards;
}

@keyframes am-wsp-floating-in {
  0%   { opacity: 0; transform: translate(-25%, -10%) scale(0.86); }
  100% { opacity: 1; transform: translate(-25%, -10%) scale(1);    }
}

.am-wsp-floating-titlebar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 4px 8px;
  height: 22px;
  background: var(--bg-2);
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}
.am-wsp-floating-title-group {
  display: inline-flex;
  align-items: baseline;
  gap: 8px;
  min-width: 0;
}
.am-wsp-floating-title {
  font-size: 10.5px;
  font-weight: 600;
  color: var(--text);
  white-space: nowrap;
}
.am-wsp-floating-project {
  font-size: 9.5px;
  color: var(--text-3);
  white-space: nowrap;
}
.am-wsp-floating-wincontrols {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.am-wsp-floating-wc {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--text-3);
  opacity: 0.65;
}
.am-wsp-floating-wc.close { background: #e06c75; opacity: 1; }

.am-wsp-floating-tabbar {
  display: flex;
  height: 20px;
  background: var(--bg-2);
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}
.am-wsp-floating-tab {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 0 8px;
  font-size: 9.5px;
  color: var(--text-2);
}
.am-wsp-floating-tab.is-active {
  color: var(--text);
  background: var(--surface);
  box-shadow: inset 0 -2px 0 var(--accent);
}
.am-wsp-floating-body {
  flex: 1;
  display: grid;
  grid-template-columns: 18px 1fr;
  min-height: 0;
  background: var(--surface);
  font-family: var(--font-mono);
  font-size: 9.5px;
  line-height: 1.35;
  color: var(--text-2);
  overflow: hidden;
}
.am-wsp-floating-body .am-wsp-editor-gutter {
  font-size: 8.5px;
  padding-top: 3px;
}
.am-wsp-typed-mirror {
  color: var(--text);
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  border-radius: 2px;
  padding: 0 1px;
}

/* ─── Reduced-motion + small-viewport opt-outs ─────────────────── */

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

/* ─── Tablet / mobile (<= 720px): adapt demos, don't hide ─────────
 *
 * The static mock already restructures at <= 720px (see the mobile
 * media block farther down in this file): grid goes single-column,
 * the 3rd terminal hides, spaces strip hides, etc. The animations
 * follow suit:
 *
 *   - browser-plugin's docked panel goes full-width (the right-half
 *     "dock" metaphor doesn't translate to a single-column mock).
 *   - both modals shrink so they fit narrower viewports.
 *   - terminal-spawn's mobile-time grid override keeps the shell +
 *     new terminals visible during the demo (the default mobile
 *     rule `.am-term:nth-child(n+3) { display: none }` would
 *     otherwise hide them, and the close-shell stage would have
 *     nothing to close).
 *
 * Because the cursor / box / pulse positions are all percentages of
 * the demo wrapper, they automatically scale with the new wrapper
 * size; the JS measurement pass on each cycle re-pins target rects
 * to the rendered elements, so there's nothing tablet-specific to
 * configure.
 */
@media (max-width: 720px) {
  /* Browser-plugin: panel covers the full grid area on mobile. */
  .am-demo-browser-plugin {
    width: 100%;
    min-width: 0;
    max-width: none;
  }

  /* Inspector modal: scale down to fit the narrower panel. */
  .am-anim-modal {
    width: 92%;
    max-width: 380px;
  }
  /* The inspector preview image strip cap was tuned for desktop;
   * shave a bit on mobile so the modal still fits inside the panel. */
  .am-anim-modal-shot { padding: 8px 12px; }

  /* New-agent popover: narrower so it doesn't overflow the mock's
     right edge when anchored under the + button on phone widths.
     The JS pos vars (--anim-spawn-popover-{x,y}) keep the anchor
     under the + button regardless of viewport. */
  .am-spawn-modal {
    width: 200px;
    max-width: 64%;
  }

  /* Terminal-spawn: the static mobile rule hides .am-term past the
   * 2nd child so only claude + codex render by default. While the
   * demo is active, keep the shell visible (so the close stage has
   * something to close) and reveal the new terminal during the
   * spawn phases. */
  .app-mock[data-active-demo="terminal-spawn"] .am-term-shell {
    display: flex;
  }
  .app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="spawning"]        .am-term-new,
  .app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="settled"]         .am-term-new,
  .app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="cursor-to-close"] .am-term-new,
  .app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="close-click"]     .am-term-new,
  .app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="closing"]         .am-term-new,
  .app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="closed"]          .am-term-new {
    display: flex;
  }

  /* Mobile grid is single-column with `height: auto`; the desktop's
   * explicit `grid-row` / `grid-column` placements (claude+new on the
   * left, codex+shell on the right) would inflate the grid into 2
   * columns again on mobile. Reset every demo-controlled placement so
   * the column flows naturally, and use `1.4fr 1fr ...` row sizing so
   * claude stays the dominant tile. */
  .app-mock[data-active-demo="terminal-spawn"] .am-term-large,
  .app-mock[data-active-demo="terminal-spawn"] .am-term-new,
  .app-mock[data-active-demo="terminal-spawn"] .am-term[data-am-term="codex"],
  .app-mock[data-active-demo="terminal-spawn"] .am-term-shell {
    grid-row: auto;
    grid-column: auto;
  }
  .app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="spawning"]        .am-grid,
  .app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="settled"]         .am-grid,
  .app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="cursor-to-close"] .am-grid,
  .app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="close-click"]     .am-grid,
  .app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="closing"]         .am-grid {
    grid-template-rows: 1.4fr 1fr 1fr 1fr;
  }
  .app-mock[data-active-demo="terminal-spawn"][data-spawn-phase="closed"] .am-grid {
    grid-template-rows: 1.4fr 1fr 1fr;
  }

  /* Workspace-plugin: settings modal + side panel shrink to fit. The
     percentage-based panel width caps below 360px on narrow screens,
     and the inner settings modal scales to ~94% so it still fits with
     room to breathe around the dimmed backdrop. */
  .am-wsp-settings {
    width: 94%;
    max-width: 440px;
    max-height: 82%;
  }
  .am-wsp-settings-tabs {
    width: 96px;
    min-width: 80px;
  }
  .am-wsp-tab { font-size: 9.5px; padding: 4px 6px; }
  .am-wsp-panel {
    width: 60%;
    max-width: none;
    min-width: 0;
  }
  .am-wsp-kbd-chip { font-size: 9px; padding: 3px 6px; }
}

/* ─── Very narrow phones (<= 380px): keep static mock only ─────────
 *
 * Below 380px the modals get cramped, the cursor sprite loses
 * legibility against the typography, and there isn't enough vertical
 * room to read the multi-step sequence. The static mock already
 * carries the marketing message at this size.
 */
@media (max-width: 380px) {
  .am-demo { display: none !important; }
}



/* ============ PORTED FROM v1: trial card (lines 5595-5687) ============ */
/* ===== Trial card (Solo pinned as a free trial) ===== */
/* The Solo card gains an accent ring + a "pinned" corner sticker so it
   reads as a trial offer placed on top of the plain Solo plan. */
.plan.is-trial {
  background: linear-gradient(180deg, rgba(92, 193, 212, 0.10) 0%, var(--surface) 60%);
  border-color: rgba(92, 193, 212, 0.45);
  box-shadow:
    0 0 0 1px rgba(92, 193, 212, 0.25),
    0 20px 54px -26px var(--accent-glow);
}
.plan-trial-pin {
  position: absolute;
  top: -10px;
  right: 16px;
  transform: rotate(5deg);
  padding: 5px 11px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: #0a1518;
  background: var(--accent);
  border: 1px solid rgba(255, 255, 255, 0.25);
  border-radius: 6px;
  box-shadow: 0 6px 16px -6px var(--accent-glow);
  user-select: none;
}
/* $0 is the hero during the trial; the regular price is struck through
   and shrunk beside it so the buyer still sees what they'll pay once
   the trial ends, and a subline restates it in plain words. */
.plan.is-trial .plan-price { flex-wrap: wrap; }
.plan-price-zero {
  font-family: var(--font-mono);
  font-size: 38px;
  font-weight: 700;
  color: var(--accent);
  letter-spacing: -0.02em;
  line-height: 1;
}
.plan-price-zero-for {
  color: var(--accent-2, var(--accent));
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  align-self: baseline;
}
.plan-price-regular {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
}
.plan.is-trial .plan-price-regular {
  text-decoration: line-through;
  text-decoration-color: var(--text-muted);
  opacity: 0.6;
}
.plan.is-trial .plan-price-amount { font-size: 17px; font-weight: 600; }
.plan.is-trial .plan-price-period { font-size: 12px; }
.plan-trial-after {
  color: var(--text-3);
  font-size: 12.5px;
  line-height: 1.5;
  margin: 8px 0 14px;
}
/* Subtle text-style controls (not primary buttons): themed via these
   classes so they never fall back to the platform button look. */
.plan-trial-skip,
.plan-trial-restore {
  appearance: none;
  -webkit-appearance: none;
  background: none;
  border: 0;
  width: 100%;
  margin-top: 10px;
  padding: 4px 0;
  font: inherit;
  font-size: 12px;
  text-align: center;
  cursor: pointer;
  transition: color 0.15s var(--ease);
}
.plan-trial-skip { color: var(--text-3); }
.plan-trial-skip:hover { color: var(--text); }
.plan-trial-restore { color: var(--accent); }
.plan-trial-restore:hover { color: var(--accent-2, var(--accent)); }
.plan-trial-skip:focus-visible,
.plan-trial-restore:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 4px;
}



/* ============ PORTED FROM v1: tiered pricing / seats / discount / period-toggle (lines 5688-5972) ============ */
/* ============================================================
   Tiered-pricing / seats / discount / period-toggle UI
   Added for the seat-quantity + yearly-period feature. Designed
   to inherit the existing dark theme tokens (--text, --text-2,
   --text-3, --border, --accent).
   ============================================================ */

.period-toggle {
  display: flex;
  width: max-content;
  align-items: center;
  gap: 4px;
  padding: 4px;
  margin: 0 auto 32px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
}
.period-toggle-btn {
  appearance: none;
  background: transparent;
  border: 0;
  color: var(--text-2);
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  padding: 8px 18px;
  border-radius: 7px;
  cursor: pointer;
  transition: background 120ms ease, color 120ms ease;
}
.period-toggle-btn:hover { color: var(--text); }
.period-toggle-btn.is-active {
  background: var(--text);
  color: var(--bg);
}
.period-toggle-btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}
.period-toggle-save {
  display: inline-block;
  margin-left: 6px;
  font-size: 9px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #5fc488;
}
.period-toggle-btn.is-active .period-toggle-save {
  color: #1f7a45;
}

/* Discount badge (above the price when plan.discount is set).
   Uses a lighter-than-token tint so the badge POPS against the dark
   card surface. --amber (#d9a050) is the closest existing token but
   too muted at this size — these brighter values are deliberately
   badge-specific. If a future design pass adds an --amber-bright
   token, swap to that and drop the literal hex. */
.plan-discount-badge {
  display: inline-block;
  margin-bottom: 8px;
  padding: 2px 8px;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: #ffe28a;
  background: rgba(255, 182, 60, 0.12);
  border: 1px solid rgba(255, 182, 60, 0.4);
  border-radius: 4px;
}

/* Post-launch waitlist-member note beside the period toggle. Hidden
   until loadPlans() sees an active waitlistDiscount offer (and hidden
   in prelaunch mode via data-prelaunch-hide - the offer card owns the
   messaging there). Same amber family as .plan-discount-badge so the
   promo surfaces read as one system. */
.pricing-offer-note {
  max-width: 560px;
  margin: 14px auto 4px;
  padding: 10px 16px;
  font-size: 13px;
  line-height: 1.55;
  text-align: center;
  color: var(--text-2);
  background: rgba(255, 182, 60, 0.06);
  border: 1px solid rgba(255, 182, 60, 0.22);
  border-radius: var(--radius-sm);
}
.pricing-offer-note-badge {
  display: inline-block;
  margin-right: 8px;
  padding: 2px 8px;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: #ffe28a;
  background: rgba(255, 182, 60, 0.12);
  border: 1px solid rgba(255, 182, 60, 0.4);
  border-radius: 999px;
}

/* Strikethrough "was" price next to the live amount. */
.plan-price-compare-at {
  font-family: var(--font-mono);
  font-size: 14px;
  color: var(--text-3);
  margin-left: 4px;
}

/* Live "save N%" indicator next to the per-seat price (updates as the
   user steps the seat count). */
.plan-price-savings {
  display: inline-block;
  margin-left: 8px;
  padding: 1px 6px;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: #5fc488;
  background: rgba(95, 196, 136, 0.12);
  border: 1px solid rgba(95, 196, 136, 0.35);
  border-radius: 3px;
}

.plan-stepper {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0 0 12px;
}
.plan-stepper .stepper-label {
  font-size: 12px;
  color: var(--text-3);
}
.plan-stepper .stepper-group {
  display: inline-flex;
  align-items: center;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  overflow: hidden;
}
.plan-stepper .stepper-btn {
  appearance: none;
  background: transparent;
  border: 0;
  color: var(--text-2);
  padding: 4px 10px;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: color 120ms ease, background 120ms ease;
}
.plan-stepper .stepper-btn:hover { color: var(--text); background: rgba(255,255,255,0.04); }
.plan-stepper .stepper-btn:disabled { opacity: 0.4; cursor: not-allowed; }
.plan-stepper .stepper-input {
  appearance: textfield;
  -moz-appearance: textfield;
  width: 48px;
  background: transparent;
  border: 0;
  color: var(--text);
  font-family: var(--font-mono);
  font-size: 13px;
  text-align: center;
  padding: 4px 0;
  font-variant-numeric: tabular-nums;
}
.plan-stepper .stepper-input::-webkit-inner-spin-button,
.plan-stepper .stepper-input::-webkit-outer-spin-button {
  -webkit-appearance: none;
  margin: 0;
}
.plan-stepper .stepper-input:focus { outline: 1px solid var(--accent); }
.plan-stepper .stepper-cap {
  font-size: 10px;
  color: var(--text-muted);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.plan-tier-summary {
  font-size: 12px;
  color: #5fc488;
  margin: 0 0 8px;
}
.plan-tier-summary strong {
  color: #7fd5a3;
  font-weight: 600;
}

.plan-tier-breakdown {
  margin: 0 0 16px;
}
.plan-tier-breakdown summary {
  font-size: 12px;
  color: var(--text-3);
  cursor: pointer;
  user-select: none;
  list-style: none;
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.plan-tier-breakdown summary::-webkit-details-marker { display: none; }
.plan-tier-breakdown summary::before {
  content: '▸';
  font-size: 10px;
  transition: transform 120ms ease;
}
.plan-tier-breakdown[open] summary::before {
  transform: rotate(90deg);
}
.plan-tier-breakdown summary:hover { color: var(--text-2); }
.plan-tier-table {
  width: 100%;
  margin-top: 8px;
  border-collapse: collapse;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
}
.plan-tier-table thead th {
  font-weight: 400;
  color: var(--text-muted);
  text-align: left;
  padding-bottom: 4px;
  border-bottom: 1px solid var(--border);
}
.plan-tier-table thead th:last-child { text-align: right; }
.plan-tier-table tbody th {
  font-weight: 400;
  color: var(--text-2);
  text-align: left;
  padding: 5px 0;
}
.plan-tier-table tbody td {
  color: var(--text);
  text-align: right;
  padding: 5px 0;
}
.plan-tier-table tbody tr + tr th,
.plan-tier-table tbody tr + tr td {
  border-top: 1px solid var(--border);
}

.waitlist { display: flex; justify-content: center; }
.waitlist-card {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding: 22px 26px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  width: 100%;
  max-width: 700px;
  flex-wrap: wrap;
}
.waitlist-card h3 { font-size: 15px; margin-bottom: 4px; }
.waitlist-card p { font-size: 13px; color: var(--text-3); }

/* Offer variant: subtle warm wash + accent border so the 30% off card
   reads as a premium promotional surface without becoming a billboard. */
.waitlist-card.waitlist-card-offer {
  padding: 26px 28px;
  background:
    radial-gradient(420px 220px at 0% 0%, rgba(255, 197, 110, 0.10), transparent 70%),
    radial-gradient(420px 220px at 100% 100%, rgba(92, 193, 212, 0.08), transparent 70%),
    var(--surface);
  border-color: rgba(255, 197, 110, 0.28);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.04),
    0 18px 48px -32px rgba(255, 175, 90, 0.35),
    0 8px 26px -22px rgba(0, 0, 0, 0.6);
}
.waitlist-card-copy {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
  min-width: 0;
  flex: 1 1 auto;
}
.waitlist-card-copy h3 { font-size: 17px; margin: 2px 0 2px; }
.waitlist-card-copy p { font-size: 13.5px; color: var(--text-2); max-width: 46ch; line-height: 1.5; }
.waitlist-card-cta { flex-shrink: 0; }

/* Mobile: stack the offer card. Breakpoint matches the nav-toggle so
   "mobile chrome shown" implies "card stacked" with no ambiguous middle
   range where the button squats beside the copy on one row. */
@media (max-width: 720px) {
  .waitlist-card.waitlist-card-offer {
    flex-direction: column;
    align-items: stretch;
    padding: 22px 20px;
    gap: 16px;
  }
  .waitlist-card-copy h3 { font-size: 16px; }
  .waitlist-card-copy p { font-size: 13px; max-width: none; }
  .waitlist-card-cta {
    width: 100%;
    justify-content: center;
    padding: 12px 16px;
    font-size: 14.5px;
  }
}

@media (max-width: 980px) {
  .pricing-grid { grid-template-columns: 1fr; }
}



/* ============ PORTED FROM v1: legal pages (lines 6471-6659) ============ */
/* =============================================================
   Legal pages (privacy.html, terms.html)
   Long-form, single-column policy copy. Extends `.prose` with
   heading, list, and emphasis support, and adds the TL;DR
   summary card + on-page table of contents that frame the body.
   ============================================================= */

/* `.legal-meta` is the small effective / last-updated line under
   the page-hero subtitle. Uses the muted text token so it sits
   below the eyebrow without competing for attention. */
.legal-meta {
  display: inline-flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 8px 12px;
  margin-top: 18px;
  font-size: 13px;
  color: var(--text-3);
}
.legal-meta strong { color: var(--text-2); font-weight: 600; }
.legal-meta time { font-variant-numeric: tabular-nums; }
.legal-meta-sep { color: var(--text-muted); }

/* Legal pages: pull the hero in tight against the summary card so the
   effective / last-updated line and the TL;DR read as one unit. */
.page-legal .page-hero {
  padding-bottom: clamp(18px, 2.5vw, 28px);
}

/* TL;DR card — plain-language summary at the top of each policy.
   Surface-tone card with a thin accent stripe so it reads as
   "guidance, not the contract". Bullets are 1.5 line-height for
   skim-ability. */
.legal-summary {
  padding-top: clamp(10px, 1.5vw, 16px);
  padding-bottom: clamp(8px, 2vw, 16px);
}
.legal-tldr {
  /* Left-aligned with the page copy (v1 centered the single column;
     v2 anchors everything to the container's left edge). */
  max-width: 820px;
  margin: 0;
  padding: 22px 24px 20px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius);
}
.legal-tldr-title {
  font-size: 13px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--accent);
  margin: 0 0 12px;
}
.legal-tldr-list {
  list-style: disc;
  padding-left: 20px;
  margin: 0 0 12px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.legal-tldr-list li {
  font-size: 14.5px;
  line-height: 1.6;
  color: var(--text-2);
}
.legal-tldr-list li strong { color: var(--text); font-weight: 600; }
.legal-tldr-note {
  margin: 8px 0 0;
  font-size: 12px;
  color: var(--text-muted);
  font-style: italic;
}

/* Table of contents. Single column on mobile, two columns on
   wider viewports so a 20-item ToC doesn't run a page long. */
.legal-toc {
  padding-top: clamp(20px, 3vw, 28px);
  padding-bottom: clamp(20px, 3vw, 28px);
}
.legal-toc-title {
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--text-3);
  margin: 0 0 12px;
}
.legal-toc-list {
  list-style: none;
  margin: 0;
  max-width: 880px;
  padding: 16px 18px;
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px 24px;
}
.legal-toc-list li {
  font-size: 14px;
  line-height: 1.5;
}
.legal-toc-list a {
  color: var(--text-2);
  text-decoration: none;
}
.legal-toc-list a:hover,
.legal-toc-list a:focus-visible {
  color: var(--accent);
}

/* Body container — caps width at 760px so lines stay readable. */
.legal-body {
  padding-top: clamp(20px, 3vw, 36px);
  padding-bottom: clamp(60px, 8vw, 100px);
}
.legal-body .prose {
  max-width: 760px;
}

/* Extend `.prose` so policy headings, lists, and inline emphasis
   read like a position paper rather than a wall of text. Only
   the elements legal pages actually use are styled here; we
   leave `.prose p` alone so mission.html keeps its existing
   typography. */
.legal-body .prose h2 {
  font-size: clamp(1.25rem, 2.4vw, 1.5rem);
  line-height: 1.3;
  color: var(--text);
  margin: 32px 0 12px;
  scroll-margin-top: 88px; /* clears the sticky site-header on anchor jumps */
}
.legal-body .prose h2:first-child { margin-top: 0; }
.legal-body .prose h3 {
  font-size: 1.05rem;
  line-height: 1.4;
  color: var(--text);
  margin: 22px 0 8px;
  scroll-margin-top: 88px;
}
.legal-body .prose ul,
.legal-body .prose ol {
  margin: 0;
  padding-left: 22px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  color: var(--text-2);
  font-size: 16px;
  line-height: 1.7;
}
.legal-body .prose ul ul,
.legal-body .prose ol ol,
.legal-body .prose ul ol,
.legal-body .prose ol ul {
  margin-top: 8px;
  padding-left: 22px;
}
.legal-body .prose li { color: var(--text-2); }
.legal-body .prose li strong { color: var(--text); font-weight: 600; }
.legal-body .prose p strong { color: var(--text); font-weight: 600; }
.legal-body .prose code {
  font-family: var(--font-mono);
  font-size: 0.88em;
  padding: 2px 6px;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  border: 1px solid var(--border-soft);
  color: var(--text);
}
.legal-body .prose a {
  color: var(--accent);
  text-decoration: underline;
  text-decoration-color: var(--accent-soft);
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
}
.legal-body .prose a:hover,
.legal-body .prose a:focus-visible {
  color: var(--accent-2);
  text-decoration-color: var(--accent-2);
}

@media (max-width: 720px) {
  .legal-toc-list { grid-template-columns: 1fr; }
  .legal-body .prose ul,
  .legal-body .prose ol { font-size: 15px; }
}



/* ============ PORTED FROM v1: enterprise contact form (lines 6932-7163) ============ */
/* =============================================================
   ENTERPRISE / CONTACT FORM
   ============================================================= */
.enterprise-form-section {
  padding: clamp(20px, 4vw, 40px) 24px clamp(60px, 10vw, 110px);
}

.enterprise-form-wrap {
  max-width: 760px;
  margin: 0 auto;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: clamp(20px, 4vw, 36px);
  box-shadow: 0 18px 60px -32px rgba(0, 0, 0, 0.55);
}

.enterprise-form {
  display: flex;
  flex-direction: column;
  gap: 18px;
}

.enterprise-form-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 18px;
}

.enterprise-form-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0; /* allow grid children to shrink under their content */
}
.enterprise-form-field-full {
  /* Spans the full width inside .enterprise-form (it lives outside a row). */
  width: 100%;
}
.enterprise-form-field-spacer {
  /* Holds the second column in a one-input row so the layout doesn't
     collapse from 2 columns to 1 mid-form. */
  display: block;
}

.enterprise-form-field label {
  font-size: 13px;
  font-weight: 500;
  color: var(--text-2);
  letter-spacing: 0.01em;
}
.enterprise-required {
  color: var(--accent);
  margin-left: 3px;
}
.enterprise-optional {
  color: var(--text-muted);
  font-weight: 400;
  font-size: 12px;
}

.enterprise-form-field input,
.enterprise-form-field textarea {
  width: 100%;
  background: var(--bg-2);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 10px 12px;
  font-family: var(--font-sans);
  font-size: 14px;
  line-height: 1.4;
  transition: border-color 0.15s var(--ease), background 0.15s var(--ease), box-shadow 0.15s var(--ease);
  /* Strip default UA appearance so the dark theme isn't broken by
     platform widget chrome on number/email/tel inputs. */
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: textfield;
}
.enterprise-form-field input::placeholder,
.enterprise-form-field textarea::placeholder {
  color: var(--text-muted);
}
.enterprise-form-field input:hover,
.enterprise-form-field textarea:hover {
  border-color: var(--border-2);
}
.enterprise-form-field input:focus,
.enterprise-form-field textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
  background: var(--surface);
}
.enterprise-form-field input[aria-invalid="true"],
.enterprise-form-field textarea[aria-invalid="true"] {
  border-color: var(--red);
  box-shadow: 0 0 0 3px rgba(215, 119, 128, 0.12);
}
.enterprise-form-field textarea {
  resize: vertical;
  min-height: 120px;
}
/* Spin-button neutralisation on number inputs so the field matches the
   visual weight of every other input. */
.enterprise-form-field input[type="number"]::-webkit-inner-spin-button,
.enterprise-form-field input[type="number"]::-webkit-outer-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

/* Honeypot wrapper: visually + a11y hidden. The `<div class="enterprise-hp">`
   markup carries `aria-hidden="true"` and `tabindex="-1"` on the input, but
   without an off-screen rule the unstyled "Website" input renders inline —
   real users see and try to fill it. Use the classic clipped-square trick so
   it stays in the layout/accessibility tree just enough for crawlers that
   ignore aria-hidden, while being invisible to humans and assistive tech. */
.enterprise-hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.enterprise-field-error {
  margin: 0;
  font-size: 12px;
  color: var(--red);
  line-height: 1.4;
}
.enterprise-field-meta {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 12px;
  margin-top: 2px;
}
.enterprise-usecase-counter {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.enterprise-usecase-counter.is-over {
  color: var(--red);
}

.enterprise-form-status {
  margin: 0;
  font-size: 13px;
  color: var(--text-2);
  min-height: 1.4em; /* Reserve vertical space so the form doesn't jump. */
}
.enterprise-form-status.is-error {
  color: var(--red);
}
.enterprise-form-status a {
  color: var(--accent);
}

.enterprise-form-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 16px;
  margin-top: 4px;
}
.enterprise-form-submit:disabled {
  opacity: 0.55;
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
}
.enterprise-form-note {
  margin: 0;
  font-size: 12px;
  color: var(--text-3);
  flex: 1 1 240px;
}
.enterprise-form-note a {
  color: var(--accent);
}

/* Success card (replaces the form on a 202). */
.enterprise-success {
  text-align: center;
  padding: 28px 20px 20px;
}
.enterprise-success h2 {
  margin: 0 0 12px;
  color: var(--text);
}
.enterprise-success p {
  max-width: 560px;
  margin: 0 auto 8px;
  color: var(--text-2);
}
.enterprise-success-id {
  font-size: 12px;
  color: var(--text-3);
  margin-top: 18px;
}
.enterprise-success-id code {
  margin-left: 6px;
}
.enterprise-success-note {
  font-size: 12px;
  color: var(--text-3);
  margin-top: 16px;
}

@media (max-width: 640px) {
  .enterprise-form-row {
    grid-template-columns: 1fr;
    gap: 14px;
  }
  .enterprise-form-field-spacer {
    display: none;
  }
  .enterprise-form-actions {
    flex-direction: column;
    align-items: stretch;
  }
  .enterprise-form-submit {
    width: 100%;
    justify-content: center;
  }
}



/* ============ PORTED FROM v1: launch banner (lines 7164-7301) ============ */
/* ====== Launch banner ======
   Pre-launch announcement strip pinned above the sticky site header.
   Stays in the DOM after dismissal (`is-dismissed` + display:none) so
   a future re-open from settings can show it again without a rebuild. */
.launch-banner {
  position: relative;
  z-index: 50; /* below modal (1000) but above page content */
  background:
    linear-gradient(90deg, rgba(92, 193, 212, 0.18), rgba(122, 223, 242, 0.12) 60%, rgba(92, 193, 212, 0.18));
  border-top: 1px solid rgba(92, 193, 212, 0.4);
  border-bottom: 1px solid var(--border);
  color: var(--text);
  font-size: 13px;
  line-height: 1.35;
}
.launch-banner.is-dismissed { display: none; }
.launch-banner-inner {
  max-width: 1200px;
  margin: 0 auto;
  padding: 9px 18px;
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}
.launch-banner-label {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}
.launch-banner-pulse {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 0 0 var(--accent-glow);
  animation: launch-banner-pulse 2.4s ease-in-out infinite;
  flex-shrink: 0;
}
@keyframes launch-banner-pulse {
  0%, 100% { box-shadow: 0 0 0 0 var(--accent-glow); }
  50%      { box-shadow: 0 0 0 7px rgba(92, 193, 212, 0); }
}
.launch-banner-eyebrow {
  text-transform: uppercase;
  letter-spacing: 0.1em;
  font-size: 11px;
  font-weight: 600;
  color: var(--accent-2);
  flex-shrink: 0;
}
.launch-banner-text {
  color: var(--text);
  flex: 1 1 200px;
  min-width: 0;
}
.launch-banner-cta {
  appearance: none;
  border: 1px solid rgba(255, 255, 255, 0.12);
  background: linear-gradient(180deg, var(--accent) 0%, #4ab3c8 100%);
  color: #0a1518;
  font: inherit;
  font-weight: 700;
  padding: 6px 15px;
  border-radius: 999px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  white-space: nowrap;
  flex-shrink: 0;
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.18) inset,
    0 8px 22px -12px var(--accent-glow);
  transition: transform 120ms ease, box-shadow 160ms ease, background-color 120ms ease;
}
.launch-banner-cta:hover {
  background: linear-gradient(180deg, var(--accent-2) 0%, var(--accent) 100%);
  transform: translateY(-1px);
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.24) inset,
    0 12px 28px -12px var(--accent-glow);
}
.launch-banner-cta:focus-visible {
  outline: 2px solid var(--accent-2);
  outline-offset: 2px;
}
.launch-banner-close {
  appearance: none;
  border: none;
  background: transparent;
  color: var(--text-3);
  cursor: pointer;
  padding: 4px;
  border-radius: 4px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.launch-banner-close:hover { color: var(--text); }
.launch-banner-close:focus-visible {
  outline: 2px solid var(--accent-2);
  outline-offset: 2px;
}

@media (max-width: 640px) {
  /* Phone layout: a labeled chip on top, the message, then a full-width
     primary CTA. The close button is pinned to the top-right corner, out of
     flow, so nothing wraps into a cramped pile. */
  .launch-banner-inner {
    position: relative;
    flex-direction: column;
    align-items: stretch;
    gap: 10px;
    padding: 13px 44px 14px 16px;
  }
  .launch-banner-eyebrow { font-size: 10.5px; }
  .launch-banner-text {
    flex: 0 0 auto;
    font-size: 13px;
    line-height: 1.45;
  }
  .launch-banner-cta {
    width: 100%;
    justify-content: center;
    padding: 11px 16px;
    font-size: 14px;
  }
  .launch-banner-close {
    position: absolute;
    top: 9px;
    right: 9px;
    padding: 8px;
  }
}



/* ============ PORTED FROM v1: discount badge (lines 7302-7382) ============ */
/* ====== Discount badge ======
   Reusable promotional chip used by the launch banner and the waitlist
   card. Warm amber gradient + soft shimmer reads as a "deal" marker that
   visually contrasts the site's cyan accent without breaking the palette.
   Sized for inline use; `discount-badge-lg` is the card-sized variant. */
.discount-badge {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 11px;
  border-radius: 999px;
  background:
    linear-gradient(135deg, rgba(255, 200, 110, 0.18) 0%, rgba(255, 165, 75, 0.10) 100%),
    rgba(20, 14, 6, 0.4);
  border: 1px solid rgba(255, 197, 110, 0.42);
  color: #ffd79c;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
  flex-shrink: 0;
  overflow: hidden;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.16),
    0 8px 22px -14px rgba(255, 175, 90, 0.55);
}
.discount-badge::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(110deg, transparent 30%, rgba(255, 230, 175, 0.22) 50%, transparent 70%);
  transform: translateX(-130%);
  animation: discount-badge-shimmer 5s ease-in-out infinite;
  pointer-events: none;
}
@keyframes discount-badge-shimmer {
  0%   { transform: translateX(-130%); }
  55%  { transform: translateX(130%); }
  100% { transform: translateX(130%); }
}
.discount-badge-text {
  position: relative;
  z-index: 1;
  display: inline-flex;
  align-items: baseline;
  gap: 4px;
}
.discount-badge-percent {
  color: #fff1d4;
  font-weight: 800;
  letter-spacing: 0.04em;
}

/* Larger variant for in-card placement (waitlist card hero). */
.discount-badge-lg {
  padding: 5px 14px;
  font-size: 11.5px;
  gap: 7px;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.18),
    0 10px 28px -16px rgba(255, 175, 90, 0.6);
}
.discount-badge-lg .discount-badge-percent { font-size: 13px; }

@media (prefers-reduced-motion: reduce) {
  .discount-badge::after { animation: none; }
}

@media (max-width: 640px) {
  /* Banner badge sits between the "Releasing soon" label and the message
     on phone layout. Self-align so the chip hugs the left edge instead of
     stretching to full row width when the banner becomes a column flex. */
  .launch-banner .discount-badge {
    align-self: flex-start;
    font-size: 10px;
    padding: 3px 10px;
  }
}



/* ============ PORTED FROM v1: waitlist modal (lines 7383-7655) ============ */
/* ====== Waitlist modal ======
   Dialog + overlay. Hidden by default (`hidden` attribute drives both
   display + a11y). Focus trap + Esc + backdrop-close handled in JS. */
.waitlist-modal {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
}
.waitlist-modal[hidden] { display: none; }
.waitlist-modal-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(5, 6, 10, 0.72);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  cursor: pointer;
}
.waitlist-modal-dialog {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 32px 28px 24px;
  width: 100%;
  max-width: 460px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(255, 255, 255, 0.02);
  animation: waitlist-modal-in 160ms cubic-bezier(.2,.8,.2,1);
}
@keyframes waitlist-modal-in {
  from { opacity: 0; transform: translateY(8px) scale(0.985); }
  to   { opacity: 1; transform: translateY(0)  scale(1); }
}
.waitlist-modal-close {
  position: absolute;
  top: 12px;
  right: 12px;
  appearance: none;
  border: none;
  background: transparent;
  color: var(--text-3);
  cursor: pointer;
  width: 32px;
  height: 32px;
  border-radius: 8px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.waitlist-modal-close:hover { color: var(--text); background: var(--surface-2); }
.waitlist-modal-close:focus-visible {
  outline: 2px solid var(--accent-2);
  outline-offset: 2px;
}
.waitlist-modal-title {
  font-size: 20px;
  margin: 0 0 6px;
  color: var(--text);
}
.waitlist-modal-sub {
  font-size: 13.5px;
  color: var(--text-2);
  margin: 0 0 22px;
}
.waitlist-form-field {
  margin-bottom: 14px;
}
.waitlist-form-field label {
  display: block;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-2);
  margin-bottom: 6px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.waitlist-form-field input[type="email"] {
  width: 100%;
  appearance: none;
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text);
  font: inherit;
  font-size: 14px;
  padding: 10px 12px;
  transition: border-color 120ms ease, box-shadow 120ms ease;
}
.waitlist-form-field input[type="email"]::placeholder { color: var(--text-muted); }
.waitlist-form-field input[type="email"]:hover { border-color: var(--border-2); }
.waitlist-form-field input[type="email"]:focus-visible {
  border-color: var(--accent);
  outline: none;
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.waitlist-form-field input[aria-invalid="true"] {
  border-color: #e85c66;
  box-shadow: 0 0 0 3px rgba(232, 92, 102, 0.18);
}
.waitlist-field-error {
  color: #e85c66;
  font-size: 12px;
  margin: 6px 0 0;
  line-height: 1.3;
}
.waitlist-hp {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}
.waitlist-turnstile {
  min-height: 0;
  margin: 10px 0 6px;
}
.waitlist-turnstile:empty { display: none; }
/* Consent row: the native checkbox is visually hidden but stays focusable
   and screen-reader-reachable; `.waitlist-consent-box` is the painted
   surface that mirrors its checked / focus state via sibling combinators. */
.waitlist-form-consent {
  margin: 14px 0 0;
}
.waitlist-consent-label {
  display: grid;
  grid-template-columns: auto 1fr;
  column-gap: 10px;
  align-items: start;
  cursor: pointer;
  user-select: none;
  font-size: 13px;
  line-height: 1.45;
  color: var(--text-2);
}
.waitlist-consent-checkbox {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}
.waitlist-consent-box {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 18px;
  height: 18px;
  margin-top: 1px;
  border: 1px solid var(--border-2);
  border-radius: var(--radius-sm);
  background: var(--bg-2);
  color: transparent;
  transition: background-color 120ms ease, border-color 120ms ease, box-shadow 120ms ease, color 120ms ease;
}
.waitlist-consent-box svg {
  width: 11px;
  height: 11px;
  transform: scale(0.6);
  opacity: 0;
  transition: transform 140ms cubic-bezier(.2,.8,.2,1), opacity 120ms ease;
}
.waitlist-consent-label:hover .waitlist-consent-box {
  border-color: var(--accent);
}
.waitlist-consent-checkbox:focus-visible + .waitlist-consent-box {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.waitlist-consent-checkbox:checked + .waitlist-consent-box {
  background: var(--accent);
  border-color: var(--accent);
  color: #0a0a0f;
}
.waitlist-consent-checkbox:checked + .waitlist-consent-box svg {
  opacity: 1;
  transform: scale(1);
}
.waitlist-consent-checkbox[aria-invalid="true"] + .waitlist-consent-box {
  border-color: #e85c66;
  box-shadow: 0 0 0 3px rgba(232, 92, 102, 0.18);
}
.waitlist-consent-text { display: block; }
.waitlist-consent-link {
  color: var(--accent);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
  white-space: nowrap;
}
.waitlist-consent-link:hover { color: var(--accent-2); }
.waitlist-consent-link:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 2px;
}
.waitlist-form-status {
  margin: 8px 0 0;
  min-height: 18px;
  font-size: 13px;
  color: var(--text-2);
}
.waitlist-form-status.is-error { color: #e85c66; }
.waitlist-form-actions {
  display: flex;
  gap: 10px;
  align-items: center;
  margin-top: 18px;
  flex-wrap: wrap;
}
.waitlist-form-submit { flex: 1 1 auto; justify-content: center; }
.waitlist-form-submit[disabled],
.waitlist-form-submit[aria-disabled="true"] { opacity: 0.55; cursor: not-allowed; }
.waitlist-form-note {
  margin: 14px 0 0;
  font-size: 11.5px;
  color: var(--text-3);
  line-height: 1.4;
}
.waitlist-form-success {
  text-align: center;
  padding: 6px 4px 8px;
}
.waitlist-form-success-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  background: var(--accent-soft);
  color: var(--accent);
  margin-bottom: 10px;
}
.waitlist-form-success h3 {
  font-size: 18px;
  margin: 0 0 4px;
  color: var(--text);
}
.waitlist-form-success p {
  font-size: 13px;
  color: var(--text-2);
  margin: 0 0 18px;
}

@media (max-width: 520px) {
  .waitlist-modal { padding: 14px; }
  .waitlist-modal-dialog { padding: 26px 20px 20px; }
  .waitlist-form-actions { flex-direction: column; align-items: stretch; }
  .waitlist-form-submit { width: 100%; }
  /* Consent row: extend the tap target across the full row by giving
     the label a comfortable min-height. The checkbox + text alignment
     stays correct because the grid layout already keys off `align-items: start`. */
  .waitlist-form-consent { margin-top: 12px; }
  .waitlist-consent-label {
    min-height: 44px;
    font-size: 13.5px;
    column-gap: 12px;
  }
  .waitlist-consent-box { width: 20px; height: 20px; margin-top: 2px; }
}



/* ============ PORTED FROM v1: video tour (lines 7742-7888) ============ */
/* ============================================================
   VIDEO TOUR  (home page "See it in action" section)
   Section rhythm mirrors .why; the frame mirrors the .app-mock
   treatment (border + accent-glow shadow). Self-contained.
   ============================================================ */
.tour {
  padding-top: clamp(72px, 9vw, 110px);
  padding-bottom: clamp(60px, 8vw, 100px);
}
.tour-frame {
  position: relative;
  max-width: 980px;
  margin: 0 auto;
  border-radius: var(--radius-lg);
  overflow: hidden;
  border: 1px solid var(--border);
  background: var(--bg-2);
  box-shadow:
    0 30px 80px -20px rgba(0, 0, 0, 0.7),
    0 0 0 1px rgba(255, 255, 255, 0.03),
    0 18px 60px -28px var(--accent-glow);
}
.tour-glow {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  border-radius: inherit;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06);
}
.tour-video {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  background: #000;
  object-fit: cover;
}
/* Responsive cut switch: landscape on desktop, portrait on mobile viewports.
   Only the visible <video> ever downloads (both are preload="none"). */
.tour-frame--portrait {
  display: none;
  max-width: 420px;
}
.tour-video--portrait {
  aspect-ratio: 9 / 16;
  max-height: 82vh;
  object-fit: contain;
}
@media (max-width: 760px) {
  .tour-frame--landscape {
    display: none;
  }
  .tour-frame--portrait {
    display: block;
  }
}
@media (max-width: 640px) {
  .tour-frame { border-radius: var(--radius); }
}

/* Custom centered play button. Hidden by default so the no-JS fallback is the
   native <video controls>; script.js adds .js-enhanced (revealing this button
   and stripping native controls until playback starts). It fades out once the
   video is playing (.is-playing) and returns on end as a replay affordance. */
.tour-play {
  position: absolute;
  inset: 0;
  margin: auto;
  z-index: 3;
  display: none;
  align-items: center;
  justify-content: center;
  width: clamp(64px, 8vw, 88px);
  height: clamp(64px, 8vw, 88px);
  padding: 0;
  border: 0;
  border-radius: 50%;
  cursor: pointer;
  color: #fff;
  background: rgba(12, 17, 25, 0.5);
  -webkit-backdrop-filter: blur(8px) saturate(120%);
  backdrop-filter: blur(8px) saturate(120%);
  box-shadow:
    0 10px 34px -8px rgba(0, 0, 0, 0.65),
    inset 0 0 0 1px rgba(255, 255, 255, 0.1),
    0 0 30px -6px var(--accent-glow);
  transition:
    transform 200ms cubic-bezier(0.16, 1, 0.3, 1),
    box-shadow 220ms ease,
    opacity 280ms ease;
}
.tour-frame.js-enhanced .tour-play {
  display: flex;
}
/* Thin accent ring that sits flush inside the button rim. */
.tour-play-ring {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 2px solid var(--accent);
  opacity: 0.85;
  transition: opacity 220ms ease, transform 220ms ease;
}
.tour-play-icon {
  position: relative;
  width: 38%;
  height: 38%;
  margin-left: 6%; /* optical centering of the play triangle */
  fill: currentColor;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.45));
}
.tour-play:hover,
.tour-play:focus-visible {
  transform: scale(1.07);
  background: rgba(16, 22, 32, 0.62);
  box-shadow:
    0 12px 40px -8px rgba(0, 0, 0, 0.7),
    inset 0 0 0 1px rgba(255, 255, 255, 0.16),
    0 0 46px -4px var(--accent-glow);
}
.tour-play:hover .tour-play-ring,
.tour-play:focus-visible .tour-play-ring {
  opacity: 1;
  transform: scale(1.04);
}
.tour-play:focus-visible {
  outline: 2px solid var(--accent-2);
  outline-offset: 4px;
}
.tour-play:active {
  transform: scale(0.97);
}
/* Once playback starts, dissolve the button (native controls take over). */
.tour-frame.is-playing .tour-play {
  opacity: 0;
  transform: scale(0.86);
  pointer-events: none;
}
@media (prefers-reduced-motion: reduce) {
  .tour-play,
  .tour-play-ring { transition: opacity 200ms ease; }
  .tour-play:hover,
  .tour-play:focus-visible { transform: none; }
  .tour-frame.is-playing .tour-play { transform: none; }
}




/* ============ PORTED FROM v1: cookie consent banner (lines 7889-8003) ============ */
/* ===== Cookie consent banner ===========================================
   Footer-attached, fixed to viewport bottom on mobile and sticky-style on
   desktop. Shown on first visit until the user picks Accept or Essential
   only; preference persists in localStorage under
   `agent-cohort:cookie-consent` ("all" | "essential").

   Accept = the script.js banner module injects the Google Fonts
   stylesheet into <head>. Essential = no font request fires; the site
   falls back to the system stack baked into `--font-sans`. */
.cookie-banner {
  position: fixed;
  left: 50%;
  bottom: 18px;
  width: calc(100% - 32px);
  max-width: 720px;
  z-index: 2147483600;
  background: var(--surface-2);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: 0 18px 60px rgba(0, 0, 0, 0.45), 0 2px 6px rgba(0, 0, 0, 0.25);
  font-size: 13.5px;
  line-height: 1.5;
  padding: 14px 16px;
  display: grid;
  grid-template-columns: 1fr;
  gap: 12px;
  align-items: center;
  opacity: 0;
  transform: translate(-50%, 12px);
  pointer-events: none;
  transition: opacity 220ms ease, transform 260ms cubic-bezier(.2, .8, .2, 1);
}
.cookie-banner[data-visible="true"] {
  opacity: 1;
  transform: translate(-50%, 0);
  pointer-events: auto;
}
.cookie-banner[hidden] { display: none !important; }
.cookie-banner-copy {
  color: var(--text-2);
  margin: 0;
}
.cookie-banner-copy strong {
  color: var(--text);
  font-weight: 600;
}
.cookie-banner-link {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-thickness: 1px;
}
.cookie-banner-link:hover { color: var(--accent-2); }
.cookie-banner-actions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  justify-content: stretch;
}
.cookie-banner-btn {
  appearance: none;
  border: 1px solid var(--border-2);
  background: var(--bg-2);
  color: var(--text);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  padding: 9px 14px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  flex: 1 1 auto;
  min-height: 38px;
  transition: background-color 120ms ease, border-color 120ms ease, color 120ms ease, box-shadow 120ms ease;
}
.cookie-banner-btn:hover {
  border-color: var(--accent);
  color: var(--accent);
}
.cookie-banner-btn:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.cookie-banner-btn.is-primary {
  background: var(--accent);
  border-color: var(--accent);
  color: #0a0a0f;
}
.cookie-banner-btn.is-primary:hover {
  background: var(--accent-2);
  border-color: var(--accent-2);
  color: #0a0a0f;
}
@media (min-width: 640px) {
  .cookie-banner {
    grid-template-columns: 1fr auto;
    gap: 18px;
    padding: 14px 18px;
  }
  .cookie-banner-actions { flex-wrap: nowrap; }
  .cookie-banner-btn { flex: 0 0 auto; }
}
@media (max-width: 420px) {
  .cookie-banner {
    bottom: 12px;
    width: calc(100% - 20px);
    padding: 12px 14px;
  }
  .cookie-banner-btn { width: 100%; }
}
@media (prefers-reduced-motion: reduce) {
  .cookie-banner { transition: none; }
}


/* =============================================================
   RESPONSIVE (v2 layout)
   ============================================================= */

@media (max-width: 1080px) {
  .bento { gap: 12px; }
  .cohort-card { grid-column: span 6; }
  .cohort-card--wide { grid-column: span 12; }
  .cohort-card--mid { grid-column: span 12; min-height: 200px; }
  .cohort-card--bar { grid-column: span 12; }
  .plugin-grid { grid-template-columns: repeat(3, 1fr); }
}

@media (max-width: 980px) {
  .hero-stack { gap: 38px; }

  /* App mock: drop the 3D tilt + compact the chrome at tablet width. */
  .app-mock { transform: none; }
  .am-grid { height: 300px; }
  .am-search-text { display: none; }
  .am-space-name { display: none; }
  .am-space.active .am-space-name { display: inline; }

  .why-grid { grid-template-columns: 1fr; border-top: none; }
  .why-card {
    border-right: none;
    margin-right: 0;
    padding: 26px 0;
    border-top: 1px solid var(--hairline);
  }
  .why-icon { top: 30px; right: 0; }

  .pricing-grid { grid-template-columns: 1fr; max-width: 560px; margin: 0 auto; }
  .footer-grid { grid-template-columns: 1fr 1fr; }
  .section-head-row { flex-direction: column; align-items: flex-start; }

  .download-grid { grid-template-columns: 1fr; }
  .closer-grid h2 { font-size: clamp(2rem, 7vw, 3rem); }
}

@media (max-width: 720px) {
  .primary-nav { display: none; }
  .nav-toggle { display: flex; }

  html { scroll-padding-top: 70px; }

  .hero { padding-top: 40px; }
  .hero-title { font-size: clamp(2.5rem, 11vw, 3.4rem); }
  .hero-sub { font-size: 15px; }

  .cta-row { gap: 10px; }
  .cta-row .btn { flex: 1 1 0; min-width: 150px; }

  .section-head { margin-bottom: 32px; }
  .section-head h2 { font-size: clamp(1.7rem, 7vw, 2.2rem); }

  .hero-meta { gap: 10px 18px; }
  .visual-caption { display: none; }

  .strip-label { padding: 14px 18px 14px 0; margin-right: 18px; font-size: 10px; }
  .strip-list li { font-size: 11.5px; }

  .bento { grid-template-columns: 1fr; }
  .cohort-card,
  .cohort-card--wide,
  .cohort-card--mid,
  .cohort-card--bar { grid-column: span 1; min-height: 0; padding: 22px 20px 24px; }
  .cohort-card--bar { flex-direction: column; align-items: flex-start; }
  .cohort-card__icon { position: static; margin-bottom: 36px; }
  .cohort-card__text p { max-width: none; }

  .plugin-grid { grid-template-columns: 1fr 1fr; }
  .plugin-byo { flex-direction: column; align-items: flex-start; gap: 14px; padding: 22px 20px; }

  .plan { padding: 24px 20px; }
  .plan-price-amount { font-size: 34px; }
  .waitlist-card { flex-direction: column; align-items: flex-start; gap: 16px; padding: 24px 20px; }
  .waitlist-card .btn { align-self: stretch; }
  .closer-cta { width: 100%; flex-direction: column; }
  .closer-cta .btn, .plan-cta { width: 100%; }

  .footer-grid { grid-template-columns: 1fr; gap: 26px; }
  .footer-bottom { flex-direction: column; align-items: flex-start; }
  .footer-wm { font-size: 80px; bottom: 56px; }

  .download-card { padding: 18px; gap: 14px; }

  /* App mock on phones: compact header, single-column grid showing the
     focused Claude term + one secondary so the visual stays informative
     without dominating the hero. (Ported from v1.) */
  .am-header { padding-left: 8px; gap: 5px; flex-wrap: nowrap; overflow: hidden; }
  .am-project-sub, .am-chev { display: none; }
  .am-search { display: none; }
  .am-divider { display: none; }
  .am-plugins .am-plugin:nth-child(n+4) { display: none; }
  .am-spaces { display: none; }
  .am-grid {
    grid-template-columns: 1fr;
    grid-template-rows: 1.4fr 1fr;
    height: auto;
    padding: 5px;
    gap: 5px;
  }
  .am-term-large { grid-row: auto; }
  .am-term:nth-child(n+3) { display: none; }
  .am-term-large .am-term-body { min-height: 180px; }
  .am-term-body { font-size: 10.5px; padding: 9px 10px; }
  .am-statusbar { gap: 10px; padding: 0 10px; font-size: 10px; }
  .am-statusbar .am-status-item:nth-child(n+4) { display: none; }

  pre { font-size: 12px; }
  .code-block pre { padding: 14px 16px; }
}

@media (max-width: 460px) {
  .container { padding-left: 18px; padding-right: 18px; }
  .nav-row { height: 60px; gap: 12px; }
  .btn { padding: 12px 16px; font-size: 11.5px; }
  .plugin-grid { grid-template-columns: 1fr; }
  .hero-title { letter-spacing: 0; }
}

/* ====== Motion preferences (v2 additions) ====== */
@media (prefers-reduced-motion: reduce) {
  .visual-caption .vc-live::before { animation: none; }
  .ticker { overflow-x: auto; }
  .ticker-track { animation: none; width: auto; }
  html.rv-enabled [data-rv] { opacity: 1; transform: none; transition: none; }
  .cohort-card:hover,
  .plugin-card:hover { transform: none; }
}



/* ============ PORTED FROM v1: small phones / iOS safe areas / touch / reduced motion (lines 6849-6931) ============ */
/* ====== Small phones (≤380px) ====== */
@media (max-width: 380px) {
  .container { padding-left: 16px; padding-right: 16px; }
  .nav-row { gap: 8px; }
  .brand-name { font-size: 16px; }
  .brand-mark { width: 22px; height: 22px; }

  .hero-title { font-size: 1.85rem; }
  .hero-sub { font-size: 14px; }
  .eyebrow { font-size: 11px; padding: 3px 8px; letter-spacing: 0.12em; }

  .nav-github span,
  .nav-github { padding: 7px 10px; font-size: 12.5px; }
  .btn { padding: 10px 14px; font-size: 12.5px; }

  .feature, .plugin-card, .why-card, .how-card, .builtin, .plan, .trust-point {
    padding: 20px 18px;
  }
  .plan-price-amount { font-size: 28px; }
  .plan-price-zero { font-size: 28px; }

  .am-header { padding-left: 6px; gap: 4px; }
  .am-project { padding: 0 8px 0 7px; font-size: 11px; }
  .am-plugins { padding: 0; }
  .am-plugins .am-plugin:nth-child(n+3) { display: none; }
  .am-term-body { font-size: 10px; }
  .am-term-meta { display: none; }

  .builtin { grid-template-columns: 1fr; gap: 12px; }
  .builtin-id { padding-top: 0; }
}

/* ====== iOS safe areas (notches, home indicators) ====== */
@supports (padding: max(0px)) {
  .site-header { padding-top: env(safe-area-inset-top); }
  .site-header .nav-row {
    padding-left: max(24px, env(safe-area-inset-left));
    padding-right: max(24px, env(safe-area-inset-right));
  }
  .site-footer { padding-bottom: max(24px, env(safe-area-inset-bottom)); }
}

/* ====== Touch hygiene ======
   - Eliminate iOS double-tap zoom delay on interactive elements.
   - Disable lift-on-hover transforms on touch devices (sticky hover state). */
.btn, .copy-btn, .nav-toggle, .nav-github,
.download-card, .plugin-card, .feature, .why-card, .how-card,
.builtin, .plan, .trust-point, a {
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}

@media (hover: none) {
  .download-card:hover,
  .plugin-card:hover,
  .feature:hover,
  .why-card:hover,
  .builtin:hover,
  .plan:hover,
  .how-card:hover,
  .trust-point:hover,
  .cohort-card:hover,
  .app-mock:hover {
    transform: none;
  }
  .download-card:hover .download-arrow,
  .link-arrow:hover svg { transform: none; }
}

/* Minimum tap target for primary actionable elements (≥ Apple HIG 44pt) */
.btn { min-height: 44px; }

/* ====== Reduced motion ====== */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  .app-mock { transform: none !important; }
}



/* ============ PORTED FROM v1: prelaunch mode (lines 7656-7735) ============ */
/* ====== Prelaunch mode ======
   Active when `<html data-prelaunch="true">` is set (production until
   the product ships - see assets/prelaunch.js for the flip switch).
   Hides pre-launch CTAs so the only path off the marketing site is
   the waitlist + enterprise contact. Per-element opt-in via:
     [data-prelaunch-hide]      - display:none.
     [data-prelaunch-disable]   - visible but unclickable + a11y.
   Plus blanket rules for nav chrome + pricing-grid that are
   structurally always hidden in this mode. */
html[data-prelaunch="true"] [data-prelaunch-hide] { display: none !important; }
/* Inverse: elements that ONLY render under prelaunch. Hidden by default. */
[data-prelaunch-show] { display: none; }
html[data-prelaunch="true"] [data-prelaunch-show] { display: inline-flex; }
/* Block-level variant: a panel/section that should render as a block. */
html[data-prelaunch="true"] [data-prelaunch-show].download-prelaunch {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  text-align: center;
  padding: 36px 26px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  max-width: 540px;
  margin: 0 auto;
}
.download-prelaunch h3 { font-size: 18px; margin: 0; color: var(--text); }
.download-prelaunch p { font-size: 14px; color: var(--text-2); margin: 0; }
html[data-prelaunch="true"] [data-prelaunch-disable] {
  pointer-events: none;
  opacity: 0.55;
  cursor: not-allowed;
  filter: saturate(0.6);
}
/* aria-disabled lift; the surrounding wrapper paints a "coming soon"
   strip on hero CTAs so the user understands why the buttons don't act. */
html[data-prelaunch="true"] [aria-disabled="true"] {
  pointer-events: none;
}
/* Header chrome: GitHub icon hidden (no functional release flow yet);
   sign-in stays visible but disabled (the sign-in app exists; we just
   don't want pre-launch traffic landing on it). */
html[data-prelaunch="true"] .nav-github {
  display: none !important;
}
html[data-prelaunch="true"] .nav-signin {
  pointer-events: none;
  opacity: 0.55;
  cursor: not-allowed;
  filter: saturate(0.6);
}
/* Header Download nav link sits inside .primary-nav + .mobile-nav and
   uses [data-prelaunch-disable] (set on each page's nav) for the same
   disabled treatment. Pricing-grid + per-period toggle are hidden
   in-block via the rule above. */
/* Catch-all: any download / releases link is HIDDEN under
   prelaunch unless marked `data-prelaunch-disable` (the header nav
   download link, sign-in, and the hero CTAs take that opt-out so
   they stay visible-but-grayed). Matches both the canonical clean
   URL (`href="download"`) and the legacy `.html` form so a stray
   link without the marker still gets caught. */
html[data-prelaunch="true"] a[href="download"]:not([data-prelaunch-disable]):not(.nav-signin),
html[data-prelaunch="true"] a[href="download.html"]:not([data-prelaunch-disable]):not(.nav-signin),
html[data-prelaunch="true"] a[href$="/download"]:not([data-prelaunch-disable]):not(.nav-signin),
html[data-prelaunch="true"] a[href^="https://github.com/BenDol/Agent-Cohort-Release/releases"]:not([data-prelaunch-disable]):not(.nav-github) {
  display: none !important;
}
/* Pricing block: hide the section header (eyebrow + tagline), the
   yearly/monthly toggle, and the card grid. The `.waitlist` block
   that lives inside the same <section class="pricing"> intentionally
   stays visible so the only call-to-action surfaces is "Join the waitlist". */
html[data-prelaunch="true"] .pricing > .container > .section-head,
html[data-prelaunch="true"] .pricing .period-toggle,
html[data-prelaunch="true"] .pricing .pricing-grid {
  display: none !important;
}
/* Tighten the waitlist card spacing now that nothing precedes it. */
html[data-prelaunch="true"] .pricing { padding-top: clamp(40px, 6vw, 64px); }

/* ====== Live mode: waitlist retired ======
   Once the site is live (prelaunch OFF - staging today, production when its
   host flag flips in assets/prelaunch.js), the pre-launch announcement
   banner and the waitlist offer card are hidden. They stay in the DOM and
   return the moment prelaunch is flipped back on, so the waitlist is
   dormant rather than deleted. Keyed on :not([data-prelaunch="true"]) so a
   no-JS visitor (attribute never set) also gets the live experience. */
html:not([data-prelaunch="true"]) #launch-banner,
html:not([data-prelaunch="true"]) #waitlist {
  display: none !important;
}

/* ====== Pricing visibility flag (see assets/prelaunch.js) ======
   When `<html data-pricing="hidden">`, every pricing surface is hidden:
   the index pricing section ([data-pricing-hide]) plus every nav/footer
   "Pricing" link and the download page's "See pricing" CTA (matched by
   href so no per-page markup edit is needed). A pricing link that must
   survive inside prose (the download page's "subscription" mention) opts
   out with [data-pricing-keep]. Purchasing isn't live yet; flip a host to
   shown in prelaunch.js once checkout is ready. CSS visibility only -
   billing routes are gated server-side. */
html[data-pricing="hidden"] [data-pricing-hide],
html[data-pricing="hidden"] a[href="#pricing"]:not([data-pricing-keep]),
html[data-pricing="hidden"] a[href="/#pricing"]:not([data-pricing-keep]) {
  display: none !important;
}

/* ====== Downloads visibility flag (see assets/prelaunch.js) ======
   When `<html data-downloads="hidden">`, every download entry point is
   hidden: the /download page grid + note ([data-downloads-hide]) and every
   nav "Download" link + hero/closer download CTA (matched by href). A brief
   "downloads paused" notice ([data-downloads-show]) takes their place on the
   download page. Keeps the staging test environment from handing out
   installers before the pre-production testing window closes; flip the host
   in prelaunch.js to re-enable. CSS visibility only. */
html[data-downloads="hidden"] [data-downloads-hide],
html[data-downloads="hidden"] a[href="download"]:not([data-downloads-keep]),
html[data-downloads="hidden"] a[href="download.html"]:not([data-downloads-keep]),
html[data-downloads="hidden"] a[href$="/download"]:not([data-downloads-keep]) {
  display: none !important;
}
/* Inverse: elements that render ONLY when downloads are hidden. */
[data-downloads-show] { display: none; }
html[data-downloads="hidden"] [data-downloads-show] { display: block; }
/* The paused-downloads notice reuses the .download-prelaunch card chrome
   (mirrors the prelaunch replacement box) but gated on data-downloads. */
html[data-downloads="hidden"] [data-downloads-show].download-prelaunch {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  text-align: center;
  padding: 36px 26px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  max-width: 540px;
  margin: 0 auto;
}

/* ====== UAT / public-testing banner (staging + dev) ======
   Injected by assets/prelaunch.js on the shared pre-production test
   environments (data-env staging|dev, or ?uat=on) to tell visitors this is a
   public testing build, not production. Normal-flow bar above the sticky
   header, matching the launch-banner placement. Amber is a deliberate
   non-prod caution signal, distinct from the site's cyan accent. */
.uat-banner {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 7px 16px;
  font-family: var(--font-mono, ui-monospace, "JetBrains Mono", monospace);
  font-size: 12.5px;
  line-height: 1.4;
  text-align: center;
  color: #0a0a0f;
  background: linear-gradient(90deg, #ffd15c, #ffb020);
  border-bottom: 1px solid rgba(0, 0, 0, 0.28);
}
.uat-banner strong { font-weight: 700; }
.uat-banner-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #0a0a0f;
  flex: 0 0 auto;
  animation: uat-pulse 2s ease-in-out infinite;
}
@keyframes uat-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.35; }
}
@media (prefers-reduced-motion: reduce) {
  .uat-banner-dot { animation: none; }
}

/* ====== Closed-beta report guide (see assets/prelaunch.js) ======
   The /download "how to report an issue" walkthrough for invited
   closed-beta testers. Renders ONLY under `<html data-beta="true">`
   (the staging hosts by default; `?beta=on` forces it for dev review
   and the deploy smoke suite). CSS visibility only. */
[data-beta-show] { display: none; }
html[data-beta="true"] [data-beta-show] { display: block; }

.beta-report {
  padding: clamp(48px, 7vw, 90px) 0;
  border-top: 1px solid var(--hairline);
}
.beta-report .section-head { margin-bottom: clamp(28px, 4vw, 44px); }
.beta-report-steps {
  list-style: none;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 18px;
  max-width: 880px;
  margin: 0 auto;
  padding: 0;
}
.beta-report-step {
  display: flex;
  flex-direction: column;
  gap: 18px;
  padding: 24px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
}
.beta-report-step-head {
  display: flex;
  align-items: flex-start;
  gap: 14px;
  text-align: left;
}
.beta-report-step-num {
  flex: 0 0 auto;
  width: 30px;
  height: 30px;
  display: grid;
  place-items: center;
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 600;
  color: var(--accent);
  background: var(--accent-soft);
  border: 1px solid var(--accent);
  border-radius: 50%;
}
.beta-report-step h3 { font-size: 16.5px; margin: 2px 0 6px; }
.beta-report-step-head p { font-size: 14px; color: var(--text-2); margin: 0; }
/* The two screenshots have very different aspect ratios (a wide top-bar
   crop and a tall sidebar crop), so each sits centred in a media well
   that stretches to fill its card and scales the image down to fit.
   The wrapping <a> opens the full-size PNG for a closer look. */
.beta-report-shot {
  flex: 1;
  display: grid;
  place-items: center;
  padding: 14px;
  background: var(--bg);
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  transition: border-color 0.2s var(--ease);
}
.beta-report-shot:hover,
.beta-report-shot:focus-visible { border-color: var(--accent); }
.beta-report-shot img {
  max-width: 100%;
  max-height: 480px;
  width: auto;
  height: auto;
  border-radius: 6px;
}
.beta-report-note {
  max-width: 640px;
  margin: 26px auto 0;
  text-align: center;
  font-size: 14px;
  color: var(--text-2);
}
@media (max-width: 860px) {
  .beta-report-steps { grid-template-columns: 1fr; }
  .beta-report-shot img { max-height: 420px; }
}


/* ============ PORTED FROM v1: print (lines 7736-7741) ============ */
/* ====== Print ====== */
@media print {
  .site-header, .site-footer, .hero-bg, .nav-toggle, .launch-banner, .waitlist-modal { display: none; }
  body { background: white; color: black; }
}


/* =============================================================
   POST-PORT OVERRIDES
   Fine-tuning applied after the ported v1 blocks so the carried
   components (banner, modal, consent, pricing dynamics) sit
   comfortably in the v2 design language.
   ============================================================= */

/* Reveal stagger for card grids (no inline styles allowed by CSP,
   so stagger is expressed per-grid here). */
html.rv-enabled .why-grid [data-rv]:nth-child(2),
html.rv-enabled .bento [data-rv]:nth-child(2) { transition-delay: 90ms; }
html.rv-enabled .why-grid [data-rv]:nth-child(3),
html.rv-enabled .bento [data-rv]:nth-child(3) { transition-delay: 180ms; }
html.rv-enabled .bento [data-rv]:nth-child(4) { transition-delay: 90ms; }
html.rv-enabled .bento [data-rv]:nth-child(5) { transition-delay: 180ms; }
html.rv-enabled .bento [data-rv]:nth-child(7) { transition-delay: 90ms; }
html.rv-enabled .bento [data-rv]:nth-child(8) { transition-delay: 180ms; }


/* =============================================================
   HERO BACKDROP VARIANTS (dev-only alternates)
   The shipped default (no attribute) is the radar-rings backdrop
   defined on .hero-bg above. These alternates are kept for design
   iteration and activate via <html data-hero-bg="contours|beams|
   constellation|horizon">, set by assets/js/_bg-preview.js on
   non-production hosts only (?herobg=<variant>).
   ============================================================= */

/* ---- Variant: topographic contours ---- */
html[data-hero-bg="contours"] .hero-bg::after {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='640' height='640'%3E%3Cg fill='none' stroke='%23ecedf2' stroke-opacity='0.055' stroke-width='1'%3E%3Cpath d='M120 320c-40-70 10-150 90-160s170 30 190 95-30 130-110 150S160 390 120 320z'/%3E%3Cpath d='M150 318c-30-55 15-118 80-126s140 24 156 76-26 104-92 120S178 372 150 318z'/%3E%3Cpath d='M182 315c-21-40 18-88 62-94s108 18 119 56-22 78-72 90-94-12-109-52z'/%3E%3Cpath d='M216 311c-13-26 18-58 44-62s74 12 81 37-16 52-50 60-65-9-75-35z'/%3E%3Cpath d='M470 540c-26-40 5-92 56-100s108 20 120 60-20 80-70 92-82-12-106-52z'/%3E%3Cpath d='M492 534c-18-28 8-64 42-70s78 14 86 42-15 56-50 64-62-8-78-36z'/%3E%3Cpath d='M516 528c-11-18 8-40 27-44s50 9 55 27-10 36-32 41-40-6-50-24z'/%3E%3Cpath d='M520 100c-16-26 6-58 36-64s70 13 78 38-13 51-45 58-56-7-69-32z'/%3E%3Cpath d='M540 96c-9-15 5-33 21-36s40 8 45 22-8 29-26 33-32-4-40-19z'/%3E%3C/g%3E%3C/svg%3E");
  background-size: 640px 640px;
  background-position: 0 0;
}

/* ---- Variant: cinematic light beams ---- */
html[data-hero-bg="beams"] .hero-bg::after {
  background-image:
    linear-gradient(112deg, transparent 30%, rgba(92, 193, 212, 0.09) 38%, transparent 46%),
    linear-gradient(112deg, transparent 55%, rgba(122, 223, 242, 0.05) 63%, transparent 70%),
    linear-gradient(68deg, transparent 64%, rgba(92, 193, 212, 0.07) 74%, transparent 84%);
  background-size: auto;
  background-position: 0 0;
  filter: blur(28px);
  mask-image: radial-gradient(ellipse 95% 90% at 50% 45%, black, transparent 85%);
  -webkit-mask-image: radial-gradient(ellipse 95% 90% at 50% 45%, black, transparent 85%);
}

/* ---- Variant: constellation (agent network) ---- */
html[data-hero-bg="constellation"] .hero-bg::after {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='560' height='560'%3E%3Cg stroke='%237adff2' stroke-opacity='0.07' stroke-width='1'%3E%3Cpath d='M84 96L210 168M210 168l122-52M210 168l36 150M438 388l-96-70M438 388l64 96'/%3E%3C/g%3E%3Cg fill='%23ecedf2'%3E%3Ccircle cx='84' cy='96' r='1.6' fill-opacity='0.34'/%3E%3Ccircle cx='210' cy='168' r='2' fill-opacity='0.42'/%3E%3Ccircle cx='332' cy='116' r='1.3' fill-opacity='0.25'/%3E%3Ccircle cx='246' cy='318' r='1.6' fill-opacity='0.3'/%3E%3Ccircle cx='438' cy='388' r='2' fill-opacity='0.4'/%3E%3Ccircle cx='342' cy='318' r='1.2' fill-opacity='0.22'/%3E%3Ccircle cx='502' cy='484' r='1.4' fill-opacity='0.26'/%3E%3Ccircle cx='120' cy='420' r='1.3' fill-opacity='0.24'/%3E%3Ccircle cx='480' cy='80' r='1.5' fill-opacity='0.3'/%3E%3Ccircle cx='40' cy='256' r='1.2' fill-opacity='0.2'/%3E%3C/g%3E%3C/svg%3E");
  background-size: 560px 560px;
  background-position: 0 0;
}

/* ---- Variant: horizon (vapor minimal) ---- */
html[data-hero-bg="horizon"] .hero-bg {
  background:
    radial-gradient(1100px 560px at 50% 118%, rgba(92, 193, 212, 0.16), transparent 72%),
    radial-gradient(420px 800px at 50% 100%, rgba(122, 223, 242, 0.05), transparent 75%);
}
html[data-hero-bg="horizon"] .hero-bg::after {
  background-image:
    linear-gradient(180deg, transparent calc(72% - 1px), rgba(122, 223, 242, 0.28) 72%, transparent calc(72% + 1px));
  background-size: auto;
  background-position: 0 0;
  mask-image: radial-gradient(ellipse 70% 100% at 50% 72%, black, transparent 78%);
  -webkit-mask-image: radial-gradient(ellipse 70% 100% at 50% 72%, black, transparent 78%);
}
