/* Raindrop docs — shared theme.
   Served at /docs/_theme/theme.css by the docs package. Every section
   under /docs/* links this file via a <link rel="stylesheet">, so a
   theme change propagates to every page on the next refresh.

   Fonts are self-hosted under /_theme/fonts/ to avoid cross-origin issues.
   font-display: optional — the only policy that NEVER swaps mid-render: the
   browser gives the font a tiny (~100ms) block window and then commits to
   either Gotham or the fallback for the life of that paint. Combined with the
   <link rel="preload"> tags in every page <head> (Book/Medium/Bold fetched in
   parallel with this stylesheet instead of after it parses), Gotham is ready
   inside that window, so it renders on first paint with no flash of fallback
   text. Do NOT change this back to `swap` — that reintroduces the visible
   font swap after deploy (cold cache). */

@font-face { font-family: "Gotham"; src: url("/_theme/fonts/GothamHTF-Book.woff") format("woff"); font-weight: 400; font-display: optional; }
@font-face { font-family: "Gotham"; src: url("/_theme/fonts/GothamHTF-Medium.woff") format("woff"); font-weight: 500; font-display: optional; }
@font-face { font-family: "Gotham"; src: url("/_theme/fonts/GothamHTF-Bold.woff") format("woff"); font-weight: 700; font-display: optional; }
@font-face { font-family: "Gotham"; src: url("/_theme/fonts/GothamHTF-Black.woff") format("woff"); font-weight: 900; font-display: optional; }

:root {
  color-scheme: dark;
  --rd-blue-100: #1a3d8f;
  --rd-blue-200: #0a1f4a;
  --rd-blue-300: #04122c;
  --rd-cyan:     #4dd0e1;
  --rd-violet:   #6a5cff;
  --rd-sky:      #34a1d5;
  --bg:          #04122c;
  --bg-2:        #0a1f4a;
  --panel:       #0f2858;
  --panel-2:     #16315f;
  --border:      rgba(77, 208, 225, 0.18);
  --border-2:    rgba(255, 255, 255, 0.08);
  --text:        #e6ecf5;
  --text-dim:    #9aa9c2;
  --text-mute:   #6b7a96;
  --code-bg:     #04122c;
  --good:        #4ddb96;
  --warn:        #ffd285;
  --hdr-h:       56px;
}

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

html { scroll-behavior: smooth; }

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

.nav-toggle--bar, .nav-toggle--close, .nav-scrim { display: none; }
@media (max-width: 820px) {
  .nav-toggle--bar { display: inline-flex; }
  .nav-toggle--close { display: inline-flex; }
  .nav-scrim { display: block; }
}

* { box-sizing: border-box; min-width: 0; }
html, body { margin: 0; padding: 0; }
body { max-width: 100vw; }
body {
  font-family: "Gotham", "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
  background: linear-gradient(180deg, var(--rd-blue-200) 0%, var(--rd-blue-300) 100%);
  background-attachment: fixed;
  color: var(--text);
  font-size: 15.5px;
  line-height: 1.7;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  font-feature-settings: "kern", "liga", "calt";
}

:focus { outline: none; }
:focus-visible {
  outline: 2px solid var(--rd-cyan);
  outline-offset: 2px;
  border-radius: 4px;
}

a { color: var(--rd-cyan); text-decoration: none; }
a:hover { color: #7ee3ef; text-decoration: underline; }

header.top {
  position: sticky; top: 0; z-index: 30;
  /* Match the homepage glass — tinted, blurred, faint shadow.
     Same recipe across every page so the header reads as one
     consistent chrome. */
  background: rgba(4, 18, 44, 0.55);
  backdrop-filter: saturate(140%) blur(18px);
  -webkit-backdrop-filter: saturate(140%) blur(18px);
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  box-shadow: 0 4px 24px rgba(0, 0, 0, 0.18);
  padding: 12px 24px;
  display: flex; align-items: center; gap: 18px;
}
header.top .brand { display: flex; align-items: center; gap: 12px; }
header.top img { height: 22px; width: auto; }
header.top .crumb {
  color: var(--text-dim); font-size: 13px; font-weight: 500;
  letter-spacing: 0.04em; text-transform: uppercase;
}
header.top .right { display: flex; gap: 20px; align-items: center; }
header.top .right a {
  font-size: 13px;
  font-weight: 500;
  color: var(--text-dim);
  padding: 6px 2px;
  position: relative;
  transition: color 0.15s;
}
header.top .right a:hover {
  color: var(--text);
  text-decoration: none;
}
header.top .right a[aria-current="page"] {
  color: var(--text);
}
header.top .right a[aria-current="page"]::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -2px;
  height: 2px;
  border-radius: 2px;
  background: linear-gradient(90deg, var(--rd-cyan), var(--rd-violet));
}

/* Login link — pure text, no pill. Bright white text anchored by a
   gradient underline + a small arrow that slides on hover. Soft text
   glow at rest reads as "this is the CTA" without any shape. */
header.top .right a.nav-cta {
  position: relative;
  color: #ffffff;
  font-weight: 600;
  letter-spacing: 0.01em;
  padding-right: 16px;
  text-shadow: 0 0 12px rgba(140, 120, 255, 0.35);
  transition: text-shadow 0.25s ease;
}
/* gradient underline — always visible, sits below the word only */
header.top .right a.nav-cta::before {
  content: "";
  position: absolute;
  left: 0;
  right: 16px;
  bottom: 2px;
  height: 1.5px;
  border-radius: 2px;
  background: linear-gradient(90deg, #4dd0e1, #6a5cff, #b06aff);
  background-size: 200% 100%;
  background-position: 0% 50%;
  transition: background-position 0.6s ease, height 0.2s ease,
              box-shadow 0.25s ease;
}
/* arrow — overrides legacy ::after suppression */
header.top .right a.nav-cta::after {
  content: "→";
  display: inline-block !important;
  position: static;
  margin-left: 4px;
  background: none !important;
  height: auto;
  width: auto;
  color: #4dd0e1;
  font-weight: 700;
  transition: transform 0.2s ease, color 0.2s ease,
              text-shadow 0.25s ease;
}
header.top .right a.nav-cta:hover {
  text-decoration: none;
  text-shadow:
    0 0 14px rgba(140, 120, 255, 0.65),
    0 0 28px rgba(120, 200, 255, 0.30);
}
header.top .right a.nav-cta:hover::before {
  background-position: 100% 50%;
  height: 2px;
  box-shadow: 0 0 10px rgba(140, 120, 255, 0.55);
}
header.top .right a.nav-cta:hover::after {
  transform: translateX(3px);
  color: #a5ecf5;
  text-shadow: 0 0 10px rgba(77, 208, 225, 0.65);
}
@media (prefers-reduced-motion: reduce) {
  header.top .right a.nav-cta,
  header.top .right a.nav-cta::before,
  header.top .right a.nav-cta::after { transition: none; }
}

.search {
  position: relative;
  flex: 1 1 420px;
  max-width: 560px;
  margin: 0 auto;
}
.search-input-wrap {
  position: relative;
  display: flex;
  align-items: center;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid var(--border-2);
  border-radius: 10px;
  transition: border-color 0.15s, background 0.15s;
}
.search-input-wrap:focus-within {
  border-color: var(--rd-violet);
  background: rgba(106, 92, 255, 0.06);
  box-shadow: 0 0 0 4px rgba(106, 92, 255, 0.10);
}
.search-input-wrap svg.icon {
  position: absolute; left: 12px; width: 16px; height: 16px;
  color: var(--text-mute); pointer-events: none;
}
.search-input {
  width: 100%;
  background: transparent;
  border: none;
  padding: 10px 56px 10px 38px;
  font: inherit;
  font-size: 14px;
  color: var(--text);
  outline: none;
}
.search-input::placeholder { color: var(--text-mute); }
.search-kbd {
  position: absolute; right: 8px;
  display: inline-flex; align-items: center; gap: 2px;
  font-size: 11px; font-weight: 600; color: var(--text-mute);
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid var(--border-2);
  border-radius: 4px;
  padding: 2px 6px;
  pointer-events: none;
}
.search-results {
  position: absolute;
  top: calc(100% + 8px);
  left: 0; right: 0;
  background: rgba(10, 31, 74, 0.97);
  backdrop-filter: saturate(140%) blur(14px);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: 0 16px 40px rgba(0, 0, 0, 0.4);
  max-height: min(70vh, 540px);
  overflow-y: auto;
  display: none;
  padding: 6px;
}
.search-results.open { display: block; }
.search-results .sr-section {
  font-size: 10px; font-weight: 700; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--text-mute);
  padding: 10px 12px 6px;
}
.search-results .sr-item {
  display: block;
  padding: 8px 12px;
  border-radius: 8px;
  text-decoration: none;
  color: var(--text);
  cursor: pointer;
}
.search-results .sr-item:hover,
.search-results .sr-item.active {
  background: linear-gradient(90deg, rgba(106, 92, 255, 0.14) 0%, rgba(77, 208, 225, 0.06) 100%);
  text-decoration: none;
}
.search-results .sr-row {
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
}
.search-results .sr-title {
  font-size: 14px;
  color: var(--text);
  font-weight: 600;
}
.search-results .sr-sub {
  font-family: "SF Mono", Menlo, monospace;
  font-size: 11px;
  color: #b3a8ff;
  background: rgba(106, 92, 255, 0.10);
  border: 1px solid rgba(106, 92, 255, 0.20);
  border-radius: 3px;
  padding: 1px 5px;
}
/* Single understated tag — kind label, not action color codes. The
   color-coded Read/Create/Update variants were cluttering the dropdown.
   When we want disambiguation later, do it with iconography, not color. */
.search-results .sr-tag {
  font-size: 10px; font-weight: 600; letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 1px 6px;
  border-radius: 3px;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 255, 255, 0.06);
  color: var(--text-dim);
}
.search-results .sr-snippet {
  font-size: 12px; color: var(--text-dim);
  margin-top: 3px;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
  line-height: 1.5;
}

/* "Ask" affordance — injected by theme.js into every search box so the user
   can always force the chat/RAG path regardless of how the query reads.
   Sits where the ⌘K hint was; the hint hides when the button is present. */
.search-input-wrap:has(.search-ask) .search-kbd { display: none; }
.search-input-wrap:has(.search-ask) .search-input { padding-right: 86px; }
.search-ask {
  position: absolute; right: 6px;
  display: inline-flex; align-items: center; gap: 5px;
  font: inherit; font-size: 12px; font-weight: 600;
  color: #d3ddf0;
  background: linear-gradient(90deg, rgba(106, 92, 255, 0.22), rgba(77, 208, 225, 0.14));
  border: 1px solid rgba(106, 92, 255, 0.40);
  border-radius: 8px;
  padding: 5px 10px;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s, transform 0.15s;
}
.search-ask svg { width: 13px; height: 13px; }
.search-ask:hover {
  background: linear-gradient(90deg, rgba(106, 92, 255, 0.34), rgba(77, 208, 225, 0.22));
  border-color: rgba(106, 92, 255, 0.60);
  transform: translateY(-1px);
}

/* Injected RAG answer card in the results list (link-intent path). Tinted so
   it reads as distinct from plain link hits; snippet clamps to 3 lines with
   a trailing … (truncation happens in JS). */
.search-results .sr-item.sr-ask {
  border: 1px solid rgba(106, 92, 255, 0.30);
  background: linear-gradient(135deg, rgba(106, 92, 255, 0.10), rgba(77, 208, 225, 0.04));
  margin-bottom: 4px;
}
.search-results .sr-tag-ask {
  color: #d8d2ff;
  background: rgba(106, 92, 255, 0.18);
  border-color: rgba(106, 92, 255, 0.40);
}
.search-results .sr-ask .sr-snippet { -webkit-line-clamp: 3; }
.search-results .sr-ask-cont {
  margin-top: 6px; font-size: 11.5px; font-weight: 600;
  color: var(--rd-cyan);
}
.search-results .sr-ask-close {
  margin-left: auto; background: none; border: none; cursor: pointer;
  color: rgba(230, 236, 245, 0.40); font-size: 13px; line-height: 1;
  padding: 2px 5px; border-radius: 4px; flex-shrink: 0;
  transition: color .15s, background .15s;
}
.search-results .sr-ask-close:hover { color: #fff; background: rgba(255, 255, 255, 0.08); }
/* Highlights inside results. Two paths:
   - `.sr-mark`  — legacy static-index highlight class (theme.js)
   - `mark`      — Typesense returns these wrapping matched terms
   Both render the same understated violet underline-on-tint so the eye
   tracks the matched terms without yellow shouting from the page. */
.search-results .sr-mark,
.search-results mark {
  background: rgba(106, 92, 255, 0.22);
  color: #d8d2ff;
  border-radius: 2px;
  padding: 0 2px;
  text-decoration: underline;
  text-decoration-color: rgba(179, 168, 255, 0.6);
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
}
.search-results .sr-empty {
  padding: 18px 14px; color: var(--text-mute); font-size: 13px; text-align: center;
}
.search-results .sr-scope-note {
  padding: 8px 14px 2px;
  font-size: 11.5px;
  color: rgba(77, 208, 225, 0.7);
  border-bottom: 1px solid var(--border-2);
  line-height: 1.45;
}
.search-results .sr-hint {
  padding: 8px 12px;
  border-top: 1px solid var(--border-2);
  color: var(--text-mute);
  font-size: 11px;
  display: flex; gap: 12px;
  margin-top: 4px;
}
.search-results .sr-hint kbd {
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid var(--border-2);
  border-radius: 3px;
  padding: 1px 5px;
  font-family: "SF Mono", Menlo, monospace;
  font-size: 10px;
  color: var(--text-dim);
}

.layout {
  display: grid;
  grid-template-columns: 230px minmax(0, 1fr);
  max-width: 1280px;
  margin: 0 auto;
  gap: 0;
  align-items: start;
}
@media (min-width: 1180px) {
  .layout {
    grid-template-columns: 220px minmax(0, 1fr) 380px;
    max-width: 1520px;
  }
}
@media (min-width: 1440px) {
  .layout {
    grid-template-columns: 220px minmax(0, 1fr) 440px;
    max-width: 1720px;
  }
}

nav.side {
  position: sticky;
  top: 60px;
  height: calc(100vh - 60px);
  overflow-y: auto;
  overflow-x: hidden;
  padding: 22px 14px 48px 20px;
  border-right: 1px solid var(--border-2);
  font-size: 14px;
  scrollbar-width: thin;
  scrollbar-color: rgba(255,255,255,0.08) transparent;
}
nav.side::-webkit-scrollbar { width: 6px; }
nav.side::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.08); border-radius: 3px; }
nav.side h4 {
  margin: 18px 0 10px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--rd-cyan);
  padding: 0 10px;
}
nav.side ul { list-style: none; margin: 0; padding: 0; }
nav.side li { margin: 0; }
nav.side a {
  display: block;
  padding: 6px 10px;
  border-radius: 6px;
  color: var(--text-dim);
  font-weight: 400;
  line-height: 1.35;
}
nav.side a:hover { background: rgba(77, 208, 225, 0.08); color: var(--text); text-decoration: none; }

/* Group: top-level section like "Sourcing Events".
   Sticky to the top of the nav scroll container so the section label
   stays visible while you scroll through that section's tool list. */
nav.side .group-head {
  position: sticky;
  top: 0;
  z-index: 5;
  display: flex; align-items: center; gap: 10px;
  margin: 22px 0 8px;
  padding: 8px 10px;
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: 0.02em;
  text-transform: none;
  color: var(--text);
  border-radius: 8px;
  background: linear-gradient(180deg, rgba(15, 40, 88, 0.95), rgba(10, 31, 74, 0.92));
  backdrop-filter: saturate(140%) blur(10px);
  -webkit-backdrop-filter: saturate(140%) blur(10px);
  border: 1px solid rgba(77, 208, 225, 0.18);
  box-shadow: 0 6px 14px -8px rgba(0, 0, 0, 0.5);
}
nav.side .group-head:hover {
  background: linear-gradient(180deg, rgba(77, 208, 225, 0.12), rgba(77, 208, 225, 0.04));
  border-color: rgba(77, 208, 225, 0.22);
  color: var(--text);
}
nav.side .group-head .dot {
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--rd-cyan);
  flex: 0 0 7px;
  box-shadow: 0 0 0 3px rgba(77, 208, 225, 0.14);
}
/* First group after the section header doesn't need the big top margin */
nav.side h4 + .group-head { margin-top: 4px; }

/* Subsection: CRUD label like "Read & query", "Create", "Update" */
nav.side .sub-head {
  margin: 12px 0 4px;
  padding: 0 12px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--rd-cyan);
  opacity: 0.75;
  display: flex;
  align-items: center;
  gap: 8px;
}
nav.side .sub-head::after {
  content: "";
  flex: 1;
  height: 1px;
  background: linear-gradient(90deg, rgba(77, 208, 225, 0.18), transparent);
}
/* First subsection in a group sits tighter against the group header */
nav.side .group-head + .sub-head { margin-top: 6px; }

/* Tool entries: clearly indented under their CRUD subsection */
nav.side .sub-head + ul {
  padding-left: 10px;
  margin: 0 0 4px 14px;
  border-left: 1px solid rgba(77, 208, 225, 0.12);
}
nav.side .tool-link { margin: 0; }
nav.side .tool-link a {
  padding: 5px 10px 5px 14px;
  font-size: 13.5px;
  color: var(--text-dim);
  position: relative;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  border-radius: 6px;
}
nav.side .tool-link a::before {
  content: "";
  position: absolute;
  left: 4px;
  top: 50%;
  transform: translateY(-50%);
  width: 4px; height: 4px;
  border-radius: 50%;
  background: var(--text-mute);
  opacity: 0.4;
  transition: opacity 120ms ease, background 120ms ease, transform 120ms ease;
}
nav.side .tool-link a:hover {
  color: var(--rd-cyan);
  background: rgba(77, 208, 225, 0.08);
}
nav.side .tool-link a:hover::before {
  background: var(--rd-cyan);
  opacity: 1;
  transform: translateY(-50%) scale(1.4);
}

/* Subcategory label inside a domain group */
nav.side .nav-subgroup-item {
  list-style: none;
  margin: 10px 0 2px;
  padding: 0;
}
nav.side .nav-subgroup {
  display: block;
  padding: 0 10px;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: rgba(77, 208, 225, 0.55);
  pointer-events: none;
  user-select: none;
}
nav.side .subgroup-items {
  margin: 0 0 4px;
  padding: 0;
}
nav.side .subgroup-items .tool-link a {
  padding-left: 18px;  /* extra indent for grouped topics */
  padding-top: 4px;
  padding-bottom: 4px;
}

/* Active-link highlight */
nav.side .tool-link a.active,
nav.side .tool-link a[aria-current] {
  background: rgba(77, 208, 225, 0.12);
  color: var(--text);
}
nav.side .tool-link a.active::before,
nav.side .tool-link a[aria-current]::before {
  background: var(--rd-cyan);
  opacity: 1;
}

main {
  padding: 44px 56px 96px;
  min-width: 0;
  max-width: 980px;
}
@media (min-width: 1180px) {
  main { padding: 44px 40px 96px 48px; max-width: none; }
}

.hero {
  padding: 44px 40px 36px;
  background:
    radial-gradient(800px 240px at 0% 0%, rgba(106, 92, 255, 0.14), transparent 60%),
    radial-gradient(640px 240px at 100% 100%, rgba(77, 208, 225, 0.10), transparent 60%),
    linear-gradient(180deg, rgba(15, 40, 88, 0.55), rgba(15, 40, 88, 0.30));
  border: 1px solid var(--border);
  border-radius: 16px;
  margin-bottom: 44px;
}
.hero .kicker {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--rd-cyan);
  margin-bottom: 14px;
}
.hero h1 {
  margin: 0 0 14px;
  font-size: 40px;
  font-weight: 700;
  letter-spacing: -0.025em;
  line-height: 1.1;
  color: #fff;
  max-width: 22ch;
}
.hero p {
  margin: 0;
  color: var(--text-dim);
  font-size: 17px;
  line-height: 1.6;
  max-width: 64ch;
}
.hero .stats {
  display: flex;
  gap: 32px;
  margin-top: 28px;
  flex-wrap: wrap;
  padding-top: 24px;
  border-top: 1px solid var(--border-2);
}
.hero .stat { display: flex; flex-direction: column; gap: 2px; }
.hero .stat .v {
  font-size: 22px;
  font-weight: 700;
  color: #fff;
  letter-spacing: -0.01em;
  font-feature-settings: "tnum";
}
.hero .stat .l {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--text-mute);
  font-weight: 600;
}

/* ── Animated chat mockup ─────────────────────────────────────────
   Full-width glassy panel below the hero stats. JS picks a random
   thread from the embedded JSON pool, types each user prompt,
   reveals a tool-call chip, then streams the agent reply. Repeats
   forever. Design aim: iPhone-warm bubbles + ChatGPT mono tool
   chips + Claude-cream agent accents. As the user scrolls past the
   hero, theme.js sets --chatdemo-scale on this element from 1.0 to
   ~0.78 so the panel gently recedes while still playing in-flow. */
/* ── Chatdemo: chat → branched flow morph ─────────────────────────
   The same DOM nodes do double duty. On page load the chat is at
   natural height, clean iMessage style (no tool chip, no chrome
   tilt). When the user scrolls into the dedicated scroll scene
   below it, those same user/tool/reply elements branch off from
   the chat: the panel chrome (bar, background, borders) dissolves;
   the bubbles fly to absolute positions in a horizontal flow
   USER → ROUTER → TOOL → REPLY; connector lines draw between them
   to reveal the agent mechanism.

   Driver: --chatdemo-progress (0 = chat view, 1 = branched flow).
   Set by theme.js based on scroll position inside .chatdemo-scene.
   Disabled in prefers-reduced-motion and below 768px (the flow
   doesn't fit on small screens — those just see the clean chat). */

/* === View A: natural chat panel === ───────────────────────────────
   On page load the chat sits at its content's natural height — no
   sticky pin yet, no oversized stage. The scroll scene below the
   panel is what kicks in once the user actually starts scrolling
   through this section. */
.chatdemo {
  --cream-100: #f6e7d0;
  --cream-200: #f4cfa5;
  --cream-300: #e9b487;

  position: relative;
  /* Width: own up to 760px; the .chatdemo-pin flex centers us. */
  width: 100%;
  margin: 0;
  border-radius: 22px;
  overflow: hidden;
  background:
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.025 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>"),
    radial-gradient(140% 100% at 0% 0%, rgba(106, 92, 255, 0.10), transparent 55%),
    radial-gradient(120% 100% at 100% 100%, rgba(244, 199, 156, 0.08), transparent 55%),
    linear-gradient(
      160deg,
      rgba(255, 255, 255, 0.07) 0%,
      rgba(255, 255, 255, 0.02) 45%,
      rgba(255, 255, 255, 0.015) 70%,
      rgba(255, 255, 255, 0.05) 100%
    );
  backdrop-filter: blur(34px) saturate(150%);
  -webkit-backdrop-filter: blur(34px) saturate(150%);
  border: 1px solid rgba(255, 255, 255, 0.14);
  box-shadow:
    0 30px 60px -22px rgba(0, 0, 0, 0.55),
    0 12px 24px -12px rgba(0, 0, 0, 0.35),
    inset 0 1px 0 rgba(255, 255, 255, 0.16),
    inset 0 0 80px rgba(255, 255, 255, 0.03);
  isolation: isolate;
  max-width: 760px;
}

/* In view A the tool chip + result row are hidden so the chat
   reads as clean iMessage. They re-emerge during the branch-out
   transform (the JS reveals them as it moves them). */
.chatdemo .chatdemo-turn--tool {
  /* While the morph is unwired, keep the chat view clean — no
     tool chip rows in the stream. The static flow diagram below
     surfaces the tool calls instead. */
  display: none;
}

/* === View B: branched flow === ───────────────────────────────────
   When the JS flips the .chatdemo into branching mode it:
     1. Adds .is-branching to the chat panel (transition phase)
     2. Lifts the visible turn's user, tool, reply children out of
        their .chatdemo-turn parents into a flat .chatdemo-flow
        container, each with .chatdemo-flow-node class
     3. Each node gets inline left/top/width/height for the target
        position (computed by JS based on stage width)
     4. The panel chrome (.chatdemo-bar, .chatdemo-stream gradient)
        fades out via --chatdemo-progress

   Progress drives the panel chrome fade; the bubble flight is a
   per-element CSS transition between the saved chat-position and
   the computed flow-position. */

/* ── Chat morph: vertical flow inserts inside the chat ─────────────
   .chatmorph is a tall scroll region; its .chatmorph-pin is sticky
   so the chat stays in view while the user scrolls through it. The
   chat itself doesn't fade or move — instead, theme.js injects a
   .morphinsert between the latest user bubble and latest reply
   bubble. As --chatdemo-progress climbs, the insert grows vertical
   space, revealing Router + Tool blocks with arrows between user and
   reply. The chat rotation pauses so the morphed turn stays put. */
.chatmorph {
  --chatdemo-progress: 0;
  position: relative;
  /* Scroll fuel — the morph plays over this distance. 120vh gives a
     20vh runway after subtracting the viewport (height - vh), which is
     enough to reveal all four morphinsert nodes (clamp thresholds at
     0.05/0.18/0.32/0.45) without dragging the scroll experience. */
  height: 120vh;
  margin-top: 36px;
  /* No overflow:hidden — it would short-circuit position:sticky on
     .chatmorph-pin (the sticky element stops tracking page scroll if
     an ancestor establishes a clipping/scroll context) and the chat's
     title bar would tuck under the page header.top instead of pinning
     below it. */
}
.chatmorph-pin {
  position: sticky;
  /* Clear the sticky header.top (~54px tall: 12px padding + ~30px
     content + 12px padding + 1px border) with a 22px breathing band
     above the chat's title bar so the chat panel never tucks under the
     page header. */
  top: 76px;
  /* Center the chat horizontally while it's pinned. The .chatscroll-hint
     sibling is position:fixed so it doesn't participate in this flow. */
  display: flex;
  justify-content: center;
}

/* Scroll-down hint — fixed to the bottom-center of the viewport so it
   sits at the bottom of the screen on page load (no matter where the
   user is in the chatmorph runway). The outer element owns the
   positioning + centering transform; the inner element owns the
   bobbing keyframe, so the two transforms don't fight each other.
   Fades out the moment .chatdemo flips to .is-morphing (chat begins
   its height-expand transition). */
.chatscroll-hint {
  position: fixed;
  bottom: 32px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 12;
  pointer-events: none;
  user-select: none;
  transition: opacity 240ms ease;
  will-change: opacity;
}
.chatscroll-hint-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  color: rgba(246, 231, 208, 0.65);
  animation: chatscrollHintBob 1.6s ease-in-out infinite;
}
.chatscroll-hint-label {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--text-mute);
}
.chatscroll-hint-arrow {
  width: 18px;
  height: 26px;
  display: block;
  color: rgba(246, 231, 208, 0.75);
}
@keyframes chatscrollHintBob {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(6px); }
}
/* Once the chat begins expanding (.is-morphing engaged), the hint
   has served its purpose — fade out cleanly. The outer keeps its
   translateX(-50%) centering; only opacity changes. */
.chatdemo.is-morphing ~ .chatscroll-hint {
  opacity: 0;
}
@media (prefers-reduced-motion: reduce) {
  .chatscroll-hint-inner { animation: none; }
}
.chatmorph-pin > .chatdemo {
  /* Inside the pin, the chat just keeps its natural styling but
     gets to grow taller as the morphinsert expands inside its
     stream. */
  margin: 0;
}

/* When morph is engaged, give the stream extra padding-bottom for the
   inserted flow content. Height is no longer overridden here — the
   base .chatdemo-stream rule interpolates height directly off
   --chatdemo-progress so the expansion is smooth and scroll-driven. */
.chatdemo.is-morphing .chatdemo-stream {
  padding-bottom: 36px;
}

/* The morphinsert appears AFTER each chat turn — one per user
   bubble and one per reply bubble. The --left and --right modifier
   classes pin alignment + slide direction to the matching bubble's
   side, so each chart visually drops out of the bubble above it. */
.morphinsert {
  display: flex;
  flex-direction: column;
  /* 6px between arrow and flow-box node mirrors the .chatdemo-turn's
     6px bubble→child gap, so the arrow has even visual breathing
     room above (turn gap) and below (this gap) it. */
  gap: 6px;
  width: 100%;
  /* Generous cap so tall pretty-printed JSON results (8-10 lines) fit
     without clipping the bottom of the result node. The internal
     overflow:hidden is for the grow-in animation; .morphinsert-args
     below has its own max-height with overflow:auto for runaway sizes. */
  max-height: calc(540px * var(--chatdemo-progress));
  overflow: hidden;
  margin-top: 0;
  /* Same flex-shrink:0 reasoning as .chatdemo-turn — without it the
     stream's flex layout would squish these flow boxes when many turns
     accumulate, instead of letting the stream scroll. */
  flex-shrink: 0;
  transition: max-height 320ms cubic-bezier(0.22, 1, 0.36, 1);
  /* Per-attach fade-in — when a chart is appended mid-engagement
     (because its message just finished streaming), it eases in over
     400ms instead of snapping into existence. */
  animation: morphinsertEnter 420ms cubic-bezier(0.22, 1, 0.36, 1) both;
}
@keyframes morphinsertEnter {
  0%   { opacity: 0; transform: translateY(-4px); }
  100% { opacity: 1; transform: translateY(0); }
}
.morphinsert--left  { align-items: flex-start; }
.morphinsert--right { align-items: flex-end; }
.morphinsert-arrow {
  width: 16px;
  height: 28px;
  margin-top: -2px;
  color: rgba(246, 231, 208, 0.60);
  opacity: var(--morph-p, 0);
  transition: opacity 280ms ease, transform 280ms cubic-bezier(0.22, 1, 0.36, 1);
}
/* Sit closer to the bubble's tucked corner — only a small inset
   from the panel edge so the arrow visually drops out of the
   bubble's tail. */
.morphinsert--left  .morphinsert-arrow { margin-left:  12px; transform: translateX(calc(-18px * (1 - var(--morph-p, 0)))); }
.morphinsert--right .morphinsert-arrow { margin-right: 12px; transform: translateX(calc( 18px * (1 - var(--morph-p, 0)))); }
.morphinsert-arrow svg { width: 100%; height: 100%; display: block; }

.morphinsert-node {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 12px 16px;
  border-radius: 14px;
  min-width: 220px;
  max-width: 78%;
  opacity: var(--morph-p, 0);
  transition: opacity 280ms ease, transform 280ms cubic-bezier(0.22, 1, 0.36, 1);
}
.morphinsert--left  .morphinsert-node { align-items: flex-start; text-align: left;  transform: translateX(calc(-40px * (1 - var(--morph-p, 0)))); }
.morphinsert--right .morphinsert-node { align-items: flex-end;   text-align: right; transform: translateX(calc( 40px * (1 - var(--morph-p, 0)))); }
.morphinsert-node--tool {
  background: rgba(0, 0, 0, 0.34);
  border: 1px solid rgba(246, 231, 208, 0.18);
}
.morphinsert-node--result {
  background: linear-gradient(180deg, rgba(77, 219, 150, 0.14), rgba(77, 219, 150, 0.04));
  border: 1px solid rgba(77, 219, 150, 0.30);
}
.morphinsert-label {
  display: block;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  opacity: 0.85;
  margin-bottom: 2px;
}
.morphinsert-node--tool   .morphinsert-label { color: var(--cream-200); }
.morphinsert-node--result .morphinsert-label { color: var(--good); }
.morphinsert-body {
  display: block;
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
  word-break: break-word;
}
.morphinsert-node--tool   .morphinsert-body { color: var(--cream-100); }
.morphinsert-args {
  display: block;
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 11px;
  color: var(--text-mute);
  background: rgba(0, 0, 0, 0.30);
  border: 1px solid rgba(255, 255, 255, 0.04);
  border-radius: 6px;
  padding: 6px 9px;
  margin-top: 6px;
  white-space: pre-wrap;
  word-break: break-word;
  max-width: 100%;
  max-height: 280px;
  overflow: auto;
}

/* Per-child stagger — 4 children (arrow, router, arrow, tool).
   Each child's local --morph-p ramps over its own slice of the
   parent --chatdemo-progress, so they appear in sequence:
   arrow drops in → router slides in from left → second arrow →
   tool slides in from left. */
.morphinsert > :nth-child(1) { --morph-p: clamp(0, calc((var(--chatdemo-progress) - 0.05) * 4), 1); }
.morphinsert > :nth-child(2) { --morph-p: clamp(0, calc((var(--chatdemo-progress) - 0.18) * 4), 1); }
.morphinsert > :nth-child(3) { --morph-p: clamp(0, calc((var(--chatdemo-progress) - 0.32) * 4), 1); }
.morphinsert > :nth-child(4) { --morph-p: clamp(0, calc((var(--chatdemo-progress) - 0.45) * 4), 1); }

/* The chat panel transforms based on whether the JS has handed it
   off into the stage (.is-branching). In the default position it
   sits above the scene at natural height. When the scroll driver
   commits to the morph, the JS clones the .chatdemo's bounding
   rect into the stage and the panel chrome fades out around the
   bubbles which fly to their new homes. */
.chatdemo.is-branching {
  /* Panel chrome dissolves as progress increases. */
  background: linear-gradient(
    160deg,
    rgba(255, 255, 255, calc(0.07 * (1 - var(--chatdemo-progress)))) 0%,
    rgba(255, 255, 255, calc(0.02 * (1 - var(--chatdemo-progress)))) 100%
  );
  border-color: rgba(255, 255, 255, calc(0.14 * (1 - var(--chatdemo-progress))));
  box-shadow:
    0 calc(30px * (1 - var(--chatdemo-progress))) calc(60px * (1 - var(--chatdemo-progress)))
      -22px rgba(0, 0, 0, calc(0.55 * (1 - var(--chatdemo-progress)))),
    inset 0 1px 0 rgba(255, 255, 255, calc(0.16 * (1 - var(--chatdemo-progress))));
  backdrop-filter: blur(calc(34px * (1 - var(--chatdemo-progress)))) saturate(150%);
  -webkit-backdrop-filter: blur(calc(34px * (1 - var(--chatdemo-progress)))) saturate(150%);
  transition: background 280ms ease, border-color 280ms ease,
              box-shadow 280ms ease, backdrop-filter 280ms ease;
}
.chatdemo.is-branching .chatdemo-bar {
  opacity: calc(1 - var(--chatdemo-progress));
  transition: opacity 220ms ease;
}
.chatdemo.is-branching .chatdemo-stream {
  /* Hide the standard scrolling stream behind the branched flow —
     the stream's children get re-parented into the flow container. */
  opacity: calc(1 - var(--chatdemo-progress));
  pointer-events: none;
}

/* Flow container — hidden by default. When the morph engages, JS
   adds .is-active which promotes it to a viewport-wide fixed
   overlay so the lifted bubbles + connector lines can take up as
   much horizontal room as they need. Pointer-events stay off so
   it doesn't block scroll/clicks on the rest of the page. */
.chatdemo-flow {
  display: none;
}
.chatdemo-flow.is-active {
  display: block;
  position: fixed;
  inset: 0;
  width: 100vw;
  height: 100vh;
  pointer-events: none;
  z-index: 50;
}
.chatdemo-flow .chatdemo-flow-svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  overflow: visible;
}
.chatdemo-flow-svg path {
  fill: none;
  stroke: rgba(246, 231, 208, 0.50);
  stroke-width: 1.5;
  stroke-dasharray: 5 5;
  stroke-linecap: round;
  /* Lines draw in alongside progress. */
  stroke-dashoffset: calc(260px * (1 - var(--chatdemo-progress)));
  transition: stroke-dashoffset 320ms ease;
}
.chatdemo-flow-svg .arrow-head {
  fill: rgba(246, 231, 208, 0.75);
  opacity: var(--chatdemo-progress);
  transition: opacity 280ms ease;
}

/* Lifted nodes — the SAME .chatdemo-bubble--user etc elements the
   chat created, re-parented into the fixed-overlay .chatdemo-flow
   with inline geometry (in viewport pixel coordinates). They keep
   their bubble styling so the "this is the original message"
   reading survives the trip. */
.chatdemo-flow .chatdemo-flow-node {
  position: absolute;
  max-width: none;
  margin: 0;
  border-radius: 14px;
  transition:
    left 580ms cubic-bezier(0.22, 1, 0.36, 1),
    top 580ms cubic-bezier(0.22, 1, 0.36, 1),
    width 580ms cubic-bezier(0.22, 1, 0.36, 1),
    border-radius 320ms ease,
    opacity 320ms ease;
}
.chatdemo-flow .chatdemo-flow-label {
  position: absolute;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-mute);
  opacity: calc(var(--chatdemo-progress) * var(--chatdemo-progress));
  transition: opacity 320ms ease;
  pointer-events: none;
}
.chatdemo-flow-label--user   { color: var(--rd-cyan); }
.chatdemo-flow-label--router { color: #b2a8ff; }
.chatdemo-flow-label--tool   { color: var(--cream-200); }
.chatdemo-flow-label--reply  { color: var(--cream-200); }

.chatdemo-flow-node--router {
  padding: 10px 14px;
  background: rgba(106, 92, 255, 0.16);
  border: 1px solid rgba(106, 92, 255, 0.40);
  color: #d4cdff;
  font-size: 12.5px;
  font-weight: 600;
  text-align: center;
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
}


/* Window-chrome bar — traffic lights, app title, "connected" indicator. */
.chatdemo-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px 18px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0.01));
}
.chatdemo-dot {
  width: 10px; height: 10px; border-radius: 50%;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.2);
}
.chatdemo-dot--r { background: #ff5f57; }
.chatdemo-dot--y { background: #febc2e; }
.chatdemo-dot--g { background: #28c840; }
.chatdemo-title {
  margin-left: 10px;
  font-size: 12px;
  color: var(--text-dim);
  font-weight: 500;
  letter-spacing: 0.01em;
}
.chatdemo-status {
  margin-left: auto;
  display: flex; align-items: center; gap: 6px;
  font-size: 11px;
  color: var(--good);
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.chatdemo-pulse {
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--good);
  box-shadow: 0 0 0 3px rgba(77, 219, 150, 0.18);
  animation: chatdemoPulse 1.8s ease-in-out infinite;
}
@keyframes chatdemoPulse {
  0%, 100% { box-shadow: 0 0 0 3px rgba(77, 219, 150, 0.18); }
  50%      { box-shadow: 0 0 0 6px rgba(77, 219, 150, 0.06); }
}
.chatdemo-stream {
  padding: 26px 26px 32px;
  /* Height interpolates directly off --chatdemo-progress (set by
     theme.js as the user scrolls into .chatmorph). Collapsed at
     progress=0 (480px — taller initial panel reads better above the
     fold), fully expanded at progress=1 (100vh - 184px). Because
     progress moves smoothly with every scroll event, the panel
     slides down gradually instead of snapping at a threshold. */
  height: calc(480px + (100vh - 664px) * var(--chatdemo-progress, 0));
  overflow-y: auto;
  scroll-behavior: smooth;
  display: flex;
  flex-direction: column;
  gap: 18px;
  scrollbar-width: thin;
  scrollbar-color: rgba(255, 255, 255, 0.10) transparent;
  /* Top fade keeps old turns dissolving out of view rather than
     hard-clipping at the scroll edge. */
  mask-image: linear-gradient(180deg, transparent 0, #000 32px, #000 100%);
  -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 32px, #000 100%);
}
.chatdemo-stream::-webkit-scrollbar { width: 6px; }
.chatdemo-stream::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.10); border-radius: 3px; }

/* Chat turns ───────────────────────────────────────────────────── */
.chatdemo-turn {
  display: flex;
  flex-direction: column;
  gap: 6px;
  /* The stream is a flex column with overflow:auto. Without flex-shrink:0
     here, flexbox would compress every turn (and the morphinsert flow
     boxes between them) when total content exceeds the stream height,
     instead of letting the stream scroll. Keep natural heights; the
     overflow:auto on the stream handles the rest. */
  flex-shrink: 0;
  opacity: 0;
  animation: chatdemoFadeIn 0.42s cubic-bezier(0.22, 1, 0.36, 1) forwards;
}
.chatdemo-turn--user { align-items: flex-end; }
.chatdemo-turn--tool { align-items: flex-start; }
.chatdemo-turn--reply { align-items: flex-start; }

@keyframes chatdemoFadeIn {
  from { opacity: 0; transform: translateY(8px) scale(0.985); }
  to   { opacity: 1; transform: translateY(0)   scale(1); }
}

/* User bubble — iMessage-blue tint, right-aligned, tail tucked
   into the bottom-right corner. */
.chatdemo-bubble--user {
  position: relative;
  max-width: 78%;
  padding: 11px 15px;
  border-radius: 20px 20px 6px 20px;
  background: linear-gradient(180deg, rgba(77, 208, 225, 0.26), rgba(52, 161, 213, 0.18));
  border: 1px solid rgba(120, 220, 235, 0.30);
  color: #fff;
  font-size: 14.5px;
  line-height: 1.5;
  letter-spacing: -0.005em;
  box-shadow:
    0 6px 14px -6px rgba(52, 161, 213, 0.45),
    inset 0 1px 0 rgba(255, 255, 255, 0.18);
}
.chatdemo-caret {
  display: inline-block;
  width: 2px;
  height: 1em;
  margin-left: 1px;
  background: rgba(255, 255, 255, 0.85);
  vertical-align: -2px;
  animation: chatdemoCaret 0.9s steps(2) infinite;
}
@keyframes chatdemoCaret {
  50% { opacity: 0; }
}

/* Tool-call chip — ChatGPT-style mono pill that slides in. */
.chatdemo-tool {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 6px 13px 6px 10px;
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.32);
  border: 1px solid rgba(255, 255, 255, 0.07);
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-feature-settings: "calt" 0;
  font-size: 12px;
  color: var(--text-dim);
  letter-spacing: -0.01em;
  transform: translateX(-6px);
  animation: chatdemoSlideIn 0.42s cubic-bezier(0.22, 1, 0.36, 1) forwards;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04);
}
/* Inline SVG glyph — a stylized parens/brackets mark that reads
   instantly as "function / tool call" without needing a label. */
.chatdemo-tool .chatdemo-tool-icon {
  width: 13px; height: 13px;
  flex: 0 0 13px;
  fill: var(--cream-200);
  opacity: 0.95;
  filter: drop-shadow(0 0 4px rgba(244, 199, 156, 0.35));
}
.chatdemo-tool code {
  color: var(--cream-100);
  background: transparent;
  padding: 0;
  font-weight: 600;
}
.chatdemo-tool .chatdemo-tool-args { color: var(--text-mute); }
@keyframes chatdemoSlideIn {
  from { transform: translateX(-6px); opacity: 0; }
  to   { transform: translateX(0); opacity: 1; }
}

/* Tool result peek — small monospace card below the chip. */
.chatdemo-result {
  margin-top: 6px;
  padding: 9px 13px;
  border-radius: 10px;
  background: rgba(0, 0, 0, 0.24);
  border: 1px solid rgba(255, 255, 255, 0.05);
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-feature-settings: "calt" 0;
  font-size: 11.5px;
  line-height: 1.55;
  color: var(--text-mute);
  max-width: 80%;
}
.chatdemo-result {
  display: flex;
  align-items: flex-start;
  gap: 8px;
}
.chatdemo-result .chatdemo-result-arrow {
  width: 12px; height: 12px;
  flex: 0 0 12px;
  color: var(--cream-200);
  margin-top: 3px;
  opacity: 0.85;
}
.chatdemo-result .chatdemo-result-text { flex: 1 1 auto; min-width: 0; word-break: break-word; }

/* Agent reply bubble — warm cream-tinted, left-aligned, tail tucked
   into the bottom-left. Slight serif feature settings give it the
   Claude-warm reading texture against the user bubble's tight sans. */
.chatdemo-bubble--reply {
  position: relative;
  max-width: 78%;
  padding: 12px 16px;
  border-radius: 20px 20px 20px 6px;
  background:
    linear-gradient(180deg, rgba(246, 231, 208, 0.10), rgba(244, 199, 156, 0.04));
  border: 1px solid rgba(246, 231, 208, 0.16);
  color: var(--text);
  font-size: 14.5px;
  line-height: 1.6;
  letter-spacing: -0.003em;
  box-shadow:
    0 6px 16px -8px rgba(0, 0, 0, 0.50),
    inset 0 1px 0 rgba(246, 231, 208, 0.08);
}

/* Reduced motion: no fixed-pin morph — collapse the scrollroom and
   show the chat as a static flat panel. */
@media (prefers-reduced-motion: reduce) {
  .chatdemo-scrollroom { display: none; }
  .chatdemo.is-pinned { position: relative; top: auto; left: auto; transform: none; }
  .chatdemo-flow { display: none !important; }
  .chatdemo-turn { animation: none; opacity: 1; }
  .chatdemo-tool { animation: none; transform: none; opacity: 1; }
  .chatdemo-caret { animation: none; opacity: 0; }
  .chatdemo-pulse { animation: none; }
}

/* Mobile: horizontal flow doesn't fit. Drop the morph; chat is
   a static flat panel. */
@media (max-width: 768px) {
  .chatdemo-scrollroom { display: none; }
  .chatdemo.is-pinned { position: relative; top: auto; left: auto; transform: none; }
  .chatdemo-flow { display: none !important; }
}

section { margin: 56px 0; scroll-margin-top: calc(var(--hdr-h) + 24px); }
section:first-of-type { margin-top: 32px; }
section p { margin: 0 0 14px; max-width: 68ch; }
section p + p { margin-top: -2px; }
h2 {
  font-size: 24px;
  font-weight: 700;
  margin: 0 0 18px;
  color: #fff;
  letter-spacing: -0.015em;
  line-height: 1.25;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--border-2);
}
h3 {
  font-size: 18px;
  font-weight: 600;
  margin: 32px 0 10px;
  color: #fff;
  letter-spacing: -0.005em;
  line-height: 1.3;
}
h4 {
  font-size: 14px;
  font-weight: 600;
  margin: 20px 0 8px;
  color: var(--text);
}
p {
  color: var(--text-dim);
  max-width: 68ch;
}

.group-section { scroll-margin-top: calc(var(--hdr-h) + 16px); }
.group-header {
  position: sticky;
  top: calc(var(--hdr-h) + 8px);
  z-index: 20;
  margin: 56px 0 12px;
  padding: 14px 20px;
  border-radius: 18px;
  background: linear-gradient(
    155deg,
    rgba(255, 255, 255, 0.10) 0%,
    rgba(255, 255, 255, 0.04) 45%,
    rgba(255, 255, 255, 0.02) 70%,
    rgba(255, 255, 255, 0.07) 100%
  );
  backdrop-filter: blur(20px) saturate(140%);
  -webkit-backdrop-filter: blur(20px) saturate(140%);
  border: 1px solid rgba(255, 255, 255, 0.14);
  box-shadow:
    0 16px 32px -16px rgba(0, 0, 0, 0.5),
    inset 0 1px 0 rgba(255, 255, 255, 0.14);
  display: flex; align-items: center; gap: 14px;
  flex-wrap: wrap;
}
.group-header::before {
  content: "";
  width: 4px; height: 22px;
  border-radius: 2px;
  background: linear-gradient(180deg, var(--rd-cyan), var(--rd-violet));
  flex: 0 0 4px;
}
.group-header h2 {
  margin: 0; padding: 0; border: none;
  font-size: 20px;
}
.group-header .group-meta {
  margin-left: auto;
  font-size: 12px;
  color: var(--text-mute);
  font-weight: 500;
  letter-spacing: 0.04em;
}
.group-header .group-meta strong { color: var(--text-dim); font-weight: 600; }
.group-desc {
  color: var(--text-dim);
  margin: 12px 0 0;
  font-size: 15px;
}

/* UI Guide topic blocks: one per how-to topic on the consolidated /ui page.
   The id lives on this wrapper so a side-nav jump lands with the heading
   clear of the sticky header. A hairline between consecutive topics gives
   the page rhythm so a long feature doesn't read as one undifferentiated
   wall of headings + paragraphs. */
.ui-topic {
  scroll-margin-top: calc(var(--hdr-h) + 16px);
  margin-top: 26px;
}
.ui-topic:first-of-type { margin-top: 16px; }
.ui-topic + .ui-topic { margin-top: 0; padding-top: 26px; border-top: 1px solid var(--border-2); }
.ui-topic h3 { margin: 0 0 12px; }

/* ── UI Guide prose ───────────────────────────────────────────────────
   Rendered from the light Markdown Gemini emits (renderProse in
   cmd/uigen/prose.go). Gives statuses, options, and steps real structure
   instead of a flat run-on paragraph of literal asterisks. */
.ui-topic > p { color: var(--text-dim); max-width: 68ch; margin: 0 0 14px; }
.ui-topic > p:last-child { margin-bottom: 0; }
.ui-topic strong { color: #fff; font-weight: 600; }
.ui-topic .prose-list strong,
.ui-topic .prose-steps strong { color: #fff; }

/* Plain bullet list — a small gradient dot per item. */
.ui-topic .prose-list {
  list-style: none;
  margin: 14px 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 9px;
  max-width: 68ch;
}
.ui-topic .prose-list li {
  position: relative;
  padding-left: 22px;
  color: var(--text-dim);
  line-height: 1.6;
}
.ui-topic .prose-list li::before {
  content: "";
  position: absolute;
  left: 4px;
  top: 0.66em;
  width: 6px; height: 6px;
  border-radius: 50%;
  background: linear-gradient(180deg, var(--rd-cyan), var(--rd-violet));
}

/* Labeled "definition" list — the status / option legend (each item is
   "**Term**: description"). Framed glassy panel, one row per term: a cyan
   marker, a bold term, a dim description. Turns the boring run-on into a
   scannable legend — the fix for the "Reverse Auction Statuses" wall. */
.ui-topic .prose-dl {
  list-style: none;
  margin: 16px 0;
  padding: 0;
  max-width: 74ch;
  border: 1px solid var(--border-2);
  border-radius: 12px;
  background: linear-gradient(180deg, rgba(15, 40, 88, 0.34), rgba(15, 40, 88, 0.16));
  overflow: hidden;
}
.ui-topic .prose-dl li {
  position: relative;
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: baseline;
  gap: 4px 14px;
  padding: 12px 18px 12px 32px;
  border-bottom: 1px solid var(--border-2);
  line-height: 1.55;
  transition: background 0.15s;
}
.ui-topic .prose-dl li:last-child { border-bottom: none; }
.ui-topic .prose-dl li:hover { background: rgba(77, 208, 225, 0.05); }
.ui-topic .prose-dl li::before {
  content: "";
  position: absolute;
  left: 15px;
  top: 1.05em;
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--rd-cyan);
  box-shadow: 0 0 0 3px rgba(77, 208, 225, 0.14);
}
.ui-topic .prose-dl .dl-term {
  color: #fff;
  font-weight: 600;
  letter-spacing: -0.005em;
  white-space: nowrap;
}
.ui-topic .prose-dl .dl-desc { color: var(--text-dim); }
@media (max-width: 560px) {
  .ui-topic .prose-dl li { grid-template-columns: 1fr; gap: 3px; padding-left: 32px; }
}

/* Numbered step list — circular gradient counters, like the rail's
   composition steps. */
.ui-topic .prose-steps {
  list-style: none;
  counter-reset: prose-step;
  margin: 16px 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 11px;
  max-width: 70ch;
}
.ui-topic .prose-steps li {
  counter-increment: prose-step;
  position: relative;
  padding-left: 40px;
  min-height: 26px;
  color: var(--text-dim);
  line-height: 1.6;
}
.ui-topic .prose-steps li::before {
  content: counter(prose-step);
  position: absolute;
  left: 0;
  top: -1px;
  width: 26px; height: 26px;
  border-radius: 50%;
  background: linear-gradient(180deg, var(--rd-cyan), var(--rd-violet));
  color: #04122c;
  font-size: 12px;
  font-weight: 700;
  font-feature-settings: "tnum";
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 4px 12px -4px rgba(77, 208, 225, 0.5);
}

.subsection {
  margin: 28px 0 10px;
  padding: 0;
  display: flex; align-items: center; gap: 10px;
  scroll-margin-top: calc(var(--hdr-h) + 16px);
}
.subsection h3 {
  margin: 0;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text);
}
.subsection .sub-rule {
  flex: 1;
  height: 1px;
  background: linear-gradient(to right, var(--border-2) 0%, transparent 100%);
}
.subsection .sub-count {
  font-size: 11px;
  color: var(--text-mute);
  font-weight: 600;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid var(--border-2);
  border-radius: 10px;
  padding: 1px 8px;
}

code, pre {
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, "Roboto Mono", monospace;
  font-size: 0.875em;
  font-feature-settings: "calt" 0;
}
code {
  background: rgba(77, 208, 225, 0.10);
  border: 1px solid rgba(77, 208, 225, 0.22);
  padding: 1.5px 6px;
  border-radius: 4px;
  color: var(--rd-cyan);
  white-space: nowrap;
}
pre {
  background: rgba(0, 0, 0, 0.28);
  border: 1px solid var(--border-2);
  border-radius: 10px;
  padding: 16px 18px;
  overflow-x: auto;
  color: var(--text);
  line-height: 1.6;
  font-size: 13px;
}
pre code {
  background: transparent;
  border: none;
  padding: 0;
  color: inherit;
  white-space: pre;
}

/* Endpoint card — a glassy URL-pill with a copy-to-clipboard button.
   Used in the Introduction and Getting started sections. The label
   and URL row are stacked inside a single pebble so the unit reads
   as one component (label + URL + action) rather than three loose
   pieces of text. Visual language matches the auth0-login glass. */
.endpoint-card {
  position: relative;
  margin: 18px 0 22px;
  padding: 14px 16px 16px;
  border-radius: 14px;
  background: linear-gradient(
    155deg,
    rgba(255, 255, 255, 0.07) 0%,
    rgba(255, 255, 255, 0.03) 50%,
    rgba(255, 255, 255, 0.05) 100%
  );
  backdrop-filter: blur(18px) saturate(140%);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
  border: 1px solid rgba(255, 255, 255, 0.12);
  box-shadow:
    0 12px 28px -14px rgba(0, 0, 0, 0.45),
    inset 0 1px 0 rgba(255, 255, 255, 0.10);
  max-width: 640px;
}
.endpoint-label {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--rd-cyan);
  margin: 0 0 8px;
}
.endpoint-row {
  display: flex;
  align-items: center;
  gap: 12px;
}
.endpoint-url {
  flex: 1 1 auto;
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-feature-settings: "calt" 0;
  font-size: 14px;
  color: #fff;
  letter-spacing: 0;
  background: none;
  border: none;
  padding: 0;
  word-break: break-all;
  user-select: all;
}
.endpoint-copy {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  border-radius: 8px;
  background: rgba(77, 208, 225, 0.10);
  border: 1px solid rgba(77, 208, 225, 0.22);
  color: var(--rd-cyan);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.02em;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s, color 0.15s, transform 0.15s;
  font-family: inherit;
}
.endpoint-copy:hover {
  background: rgba(77, 208, 225, 0.18);
  border-color: rgba(77, 208, 225, 0.4);
  color: #7ee3ef;
}
.endpoint-copy:active { transform: scale(0.97); }
.endpoint-copy-icon {
  flex: 0 0 14px;
  width: 14px; height: 14px;
}
.endpoint-card[data-copied="1"] .endpoint-copy {
  background: rgba(77, 219, 150, 0.15);
  border-color: rgba(77, 219, 150, 0.4);
  color: var(--good);
}

.callout {
  padding: 14px 16px;
  border-radius: 8px;
  background: rgba(106, 92, 255, 0.08);
  border-left: 3px solid var(--rd-violet);
  color: var(--text-dim);
  margin: 14px 0;
  font-size: 14px;
}
.callout strong { color: var(--text); }

ul.features {
  list-style: none;
  padding: 0;
  margin: 8px 0 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
ul.features li {
  padding: 14px 0;
  border-bottom: 1px solid var(--border-2);
  color: var(--text-dim);
  line-height: 1.6;
  max-width: 68ch;
}
ul.features li:last-child { border-bottom: none; }
ul.features li strong {
  color: #fff;
  font-weight: 600;
  display: block;
  margin-bottom: 4px;
  font-size: 15px;
  letter-spacing: -0.005em;
}

.action-dot {
  display: inline-block;
  width: 9px; height: 9px;
  border-radius: 50%;
  background: var(--rd-violet);
  box-shadow: 0 0 0 3px rgba(106, 92, 255, 0.18);
}
.action-dot[data-action="Read"]   { background: var(--good);    box-shadow: 0 0 0 3px rgba(77, 219, 150, 0.18); }
.action-dot[data-action="Create"] { background: var(--rd-cyan); box-shadow: 0 0 0 3px rgba(77, 208, 225, 0.18); }
.action-dot[data-action="Update"] { background: #ffd285;        box-shadow: 0 0 0 3px rgba(255, 210, 133, 0.18); }

.tool-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 12px;
}
.tool {
  position: relative;
  border: 1px solid var(--border-2);
  background: linear-gradient(180deg, rgba(15, 40, 88, 0.55) 0%, rgba(15, 40, 88, 0.30) 100%);
  border-radius: 12px;
  padding: 22px 24px;
  scroll-margin-top: calc(var(--hdr-h) + 24px);
  transition: border-color 0.15s, transform 0.15s;
}
.tool:hover {
  border-color: var(--border);
  transform: translateY(-1px);
}
.tool::before {
  content: "";
  position: absolute;
  left: 0; top: 14px; bottom: 14px;
  width: 3px;
  border-radius: 0 2px 2px 0;
  background: var(--rd-violet);
}
.tool[data-action="Read"]::before   { background: var(--good); }
.tool[data-action="Create"]::before { background: var(--rd-cyan); }
.tool[data-action="Update"]::before { background: #ffd285; }
.tool.search-hit {
  border-color: var(--rd-cyan);
  box-shadow: 0 0 0 3px rgba(77, 208, 225, 0.12);
}

/* Tool header: single row, baseline-aligned.
   Order: human title → snake_case identifier → badge → anchor.
   The identifier sits next to the title so the visual hierarchy reads
   as "Business User · add_sourcing_event_business_user · Write" on
   one line instead of three stacked rows. */
.tool-head {
  display: flex;
  align-items: baseline;
  gap: 12px;
  flex-wrap: wrap;
  row-gap: 6px;
}
.tool-head h4.ttitle {
  margin: 0;
  color: #fff;
  font-size: 17px;
  font-weight: 600;
  letter-spacing: -0.012em;
  line-height: 1.3;
}
.tool-head .tname {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 12px;
  color: var(--text-mute);
  font-feature-settings: "calt" 0;
  font-weight: 400;
  /* No chip background here — the title is the primary signal; the
     identifier is secondary metadata, styled like a subtle annotation. */
}
.tool:hover .tool-head .tname { color: var(--rd-cyan); }
.tool-head .anchor-link {
  margin-left: auto;
  font-size: 14px;
  color: var(--text-mute);
  opacity: 0;
  transition: opacity 0.15s;
  text-decoration: none;
}
.tool:hover .anchor-link { opacity: 1; }
.tool-head .anchor-link:hover { color: var(--rd-cyan); }
.badge {
  display: inline-block; padding: 2px 8px;
  font-size: 10px; font-weight: 700; letter-spacing: 0.06em;
  text-transform: uppercase; border-radius: 4px;
  background: rgba(77, 219, 150, 0.12); color: var(--good);
  border: 1px solid rgba(77, 219, 150, 0.3);
}
.badge.write {
  background: rgba(255, 196, 92, 0.12);
  color: #ffd285;
  border-color: rgba(255, 196, 92, 0.3);
}
.tool p.desc {
  color: var(--text-dim);
  margin: 12px 0 0;
  font-size: 14.5px;
  line-height: 1.6;
  max-width: 64ch;
}

.group-intro {
  color: var(--text-dim);
  margin: 0 0 18px;
  font-size: 15px;
}

@media (min-width: 1180px) {
  .tool .prompts { display: none; }
}
.prompts {
  margin-top: 12px;
  padding-top: 10px;
  border-top: 1px solid var(--border-2);
}
.prompts-label {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-mute);
  margin-bottom: 6px;
}
.prompts-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.prompts-list li {
  padding: 4px 0;
  color: var(--text);
  font-size: 13.5px;
  line-height: 1.45;
  font-style: italic;
}
.prompts-list li::before,
.prompts-list li::after {
  font-size: 18px;
  line-height: 1;
  font-style: normal;
  color: var(--rd-cyan);
  vertical-align: -2px;
}
.prompts-list li::before { content: "\201C"; margin-right: 4px; }
.prompts-list li::after  { content: "\201D"; margin-left: 2px; }

/* "Touches" chip row on tool cards. Hidden for now: most MCP tools
   touch enough tables that the list is more noise than signal. The
   eino-side template still emits the markup; flip back to flex when
   we want it again. */
.related-tables {
  display: none;
}
.related-tables--enabled {
  margin-top: 10px;
  padding-top: 8px;
  border-top: 1px dashed var(--border-2);
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px 8px;
}
.related-tables__label {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-mute);
}
.related-tables__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.related-tables__chip {
  display: inline-block;
  font-family: "SF Mono", Menlo, monospace;
  font-size: 11px;
  line-height: 1.4;
  color: var(--text-dim);
  background: rgba(77, 208, 225, 0.07);
  border: 1px solid rgba(77, 208, 225, 0.18);
  border-radius: 4px;
  padding: 1px 7px;
  text-decoration: none;
  transition: background 0.12s, color 0.12s, border-color 0.12s;
}
.related-tables__chip:hover,
.related-tables__chip:focus-visible {
  color: #fff;
  background: rgba(77, 208, 225, 0.14);
  border-color: rgba(77, 208, 225, 0.42);
  text-decoration: none;
}

/* Accepted-values block on an MCP tool card — lists an enum param's allowed
   values (with their UI label as a tooltip) so a reader sees the lifecycle
   states a tool can drive. */
.enum-param {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px;
  margin-top: 8px;
}
.enum-param__name {
  font-size: 11px;
  color: var(--text-mute);
}
.enum-param__name code {
  font-family: "SF Mono", Menlo, monospace;
  color: var(--text-dim);
}
.enum-param__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}
.enum-param__chip {
  font-family: "SF Mono", Menlo, monospace;
  font-size: 10.5px;
  line-height: 1.5;
  color: #9fe9bd;
  background: rgba(127, 224, 166, 0.07);
  border: 1px solid rgba(127, 224, 166, 0.18);
  border-radius: 4px;
  padding: 1px 6px;
  cursor: default;
}

aside.rail {
  display: none;
}
@media (min-width: 1180px) {
  aside.rail {
    display: block;
    position: sticky;
    top: calc(var(--hdr-h) + 24px);
    align-self: start;
    padding: 24px 28px 24px 12px;
    /* The rail is its own positioning container for .rail-compose,
       which is absolutely anchored to the bottom of this box. Removing
       overflow:auto so the compose card can hang at the bottom without
       being clipped or pushed by sibling content above. */
    height: calc(100vh - var(--hdr-h) - 32px);
    scrollbar-width: thin;
    scrollbar-color: rgba(255,255,255,0.08) transparent;
  }
}
aside.rail::-webkit-scrollbar { width: 6px; }
aside.rail::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.08); border-radius: 3px; }

.rail-card[hidden],
.rail-compose[hidden] { display: none; }

/* Rail-card and compose-card each get their own fade-in keyframe with
   a slightly different motion + delay, so they don't enter together
   like a single popup. Compose appears first (broader-context cue);
   rail-card joins 180ms later (per-tool detail). Modern feel:
   simultaneous opacity / translateY / scale / blur transitions with a
   cubic-bezier that has a soft overshoot. */
.rail-compose:not([hidden]):not([data-exiting]) {
  animation: railEnterCompose 0.5s cubic-bezier(0.16, 1, 0.3, 1) both;
}
.rail-card:not([hidden]):not([data-exiting]) {
  animation: railEnterCard 0.5s cubic-bezier(0.16, 1, 0.3, 1) 0.18s both;
}
/* Exit fades. JS sets data-exiting before flipping hidden, so this
   plays the reverse of the entrance — opacity 1→0, slight upward
   drift, light blur — over the duration matched in JS (460ms for
   compose, 320ms for the rail-card). Easing is symmetric to the
   entrance so it feels like the same curve in reverse. */
.rail-compose[data-exiting] {
  animation: railExitCompose 0.46s cubic-bezier(0.4, 0, 0.6, 1) both;
}
.rail-card[data-exiting] {
  animation: railExitCard 0.32s cubic-bezier(0.4, 0, 0.6, 1) both;
}
@keyframes railExitCompose {
  from {
    opacity: 1;
    transform: translateY(0) scale(1);
    filter: blur(0);
  }
  to {
    opacity: 0;
    transform: translateY(-8px) scale(0.985);
    filter: blur(5px);
  }
}
@keyframes railExitCard {
  from {
    opacity: 1;
    transform: translateY(0) scale(1);
    filter: blur(0);
  }
  to {
    opacity: 0;
    transform: translateY(-6px) scale(0.99);
    filter: blur(3px);
  }
}
@keyframes railEnterCompose {
  from {
    opacity: 0;
    transform: translateY(14px) scale(0.985);
    filter: blur(6px);
  }
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
    filter: blur(0);
  }
}
@keyframes railEnterCard {
  from {
    opacity: 0;
    transform: translateY(10px) scale(0.99);
    filter: blur(4px);
  }
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
    filter: blur(0);
  }
}
@media (prefers-reduced-motion: reduce) {
  .rail-card:not([hidden]),
  .rail-compose:not([hidden]),
  .rail-card[data-exiting],
  .rail-compose[data-exiting] { animation: none; }
}
.rail-card {
  border: 1px solid var(--border-2);
  background: linear-gradient(180deg, rgba(15, 40, 88, 0.50), rgba(15, 40, 88, 0.22));
  border-radius: 14px;
  padding: 22px 24px 24px;
  transition: opacity 0.18s ease;
}
.rail-label {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--rd-cyan);
  margin: 0 0 4px;
}
.rail-name {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 12px;
  color: var(--text-mute);
  margin: 0 0 18px;
  word-break: break-all;
  font-feature-settings: "calt" 0;
}
.rail-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.rail-list li {
  padding: 4px 0;
  color: #fff;
  font-size: 17px;
  line-height: 1.45;
  font-weight: 500;
  letter-spacing: -0.005em;
}
.rail-list li::before,
.rail-list li::after {
  font-size: 28px;
  line-height: 1;
  font-weight: 700;
  font-style: normal;
  color: var(--rd-cyan);
  vertical-align: -6px;
}
.rail-list li::before { content: "\201C"; margin-right: 4px; }
.rail-list li::after  { content: "\201D"; margin-left: 2px; }

/* Composition card — anchored to the bottom of the rail via absolute
   positioning so it is completely independent of the rail-card above.
   The rail itself is a sticky positioning container with a fixed
   height (viewport - header), so this card sits at the bottom of the
   visible rail no matter what the dynamic Try-saying card does.
   Content is rewritten per-group by the tracker in theme.js. Visual
   language matches the auth0-login pebble. */
.rail-compose {
  position: absolute;
  left: 12px;
  right: 28px;
  bottom: 24px;
  padding: 20px 22px 22px;
  border-radius: 18px;
  background: linear-gradient(
    155deg,
    rgba(255, 255, 255, 0.08) 0%,
    rgba(255, 255, 255, 0.03) 45%,
    rgba(255, 255, 255, 0.02) 70%,
    rgba(255, 255, 255, 0.06) 100%
  );
  backdrop-filter: blur(24px) saturate(140%);
  -webkit-backdrop-filter: blur(24px) saturate(140%);
  border: 1px solid rgba(255, 255, 255, 0.14);
  box-shadow:
    0 16px 32px -16px rgba(0, 0, 0, 0.5),
    inset 0 1px 0 rgba(255, 255, 255, 0.14);
}
.rail-compose-eyebrow {
  margin: 0 0 6px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--rd-cyan);
}
.rail-compose-title {
  margin: 0 0 8px;
  font-size: 20px;
  font-weight: 700;
  color: var(--text);
  letter-spacing: -0.005em;
}
.rail-compose-lede {
  margin: 0 0 18px;
  font-size: 14.5px;
  line-height: 1.55;
  color: var(--text-dim);
}
.rail-compose-list {
  counter-reset: compose;
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.rail-compose-list li {
  counter-increment: compose;
  position: relative;
  padding: 12px 12px 12px 36px;
  border-radius: 12px;
  background: rgba(0, 0, 0, 0.18);
  border: 1px solid rgba(255, 255, 255, 0.06);
  display: flex;
  flex-direction: column;
  gap: 6px;
  transition: background 0.18s ease, border-color 0.18s ease;
}
.rail-compose-list li:hover {
  background: rgba(0, 0, 0, 0.28);
  border-color: rgba(77, 208, 225, 0.20);
}
.rail-compose-list li::before {
  content: counter(compose);
  position: absolute;
  left: 10px;
  top: 12px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: linear-gradient(180deg, var(--rd-cyan), var(--rd-violet));
  color: #04122c;
  font-size: 11px;
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.rail-compose-step {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--rd-cyan);
}
.rail-compose-prompt {
  font-size: 15px;
  line-height: 1.5;
  color: var(--text);
  font-style: italic;
}
.rail-compose-prompt::before { content: "\201C"; color: var(--rd-cyan); font-style: normal; margin-right: 2px; }
.rail-compose-prompt::after  { content: "\201D"; color: var(--rd-cyan); font-style: normal; margin-left: 2px; }
/* The tool chain is reference metadata — useful but not the headline.
   Hidden by default (height collapses to 0 with a fade) and revealed
   on hover of the example, on keyboard focus, or when the example
   contains a focused link. */
.rail-compose-chain {
  font-size: 11.5px;
  line-height: 1.55;
  color: var(--text-mute);
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-feature-settings: "calt" 0;
  word-break: break-word;
  max-height: 0;
  opacity: 0;
  overflow: hidden;
  transition: max-height 0.25s ease, opacity 0.2s ease, margin-top 0.25s ease;
  margin-top: 0;
}
.rail-compose-list li:hover .rail-compose-chain,
.rail-compose-list li:focus-within .rail-compose-chain {
  max-height: 200px;
  opacity: 1;
  margin-top: 2px;
}
.rail-compose-chain code {
  background: rgba(77, 208, 225, 0.10);
  color: var(--rd-cyan);
  padding: 1px 5px;
  border-radius: 3px;
  font-size: 11px;
}
.rail-compose-hint {
  margin: 18px 0 0;
  padding-top: 16px;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  font-size: 13px;
  line-height: 1.55;
  color: var(--text-dim);
}

footer.bottom {
  border-top: 1px solid var(--border-2);
  padding: 28px 56px 40px;
  margin-top: 60px;
  color: var(--text-mute);
  font-size: 13px;
  max-width: 920px;
}
footer.bottom .row { display: flex; justify-content: space-between; gap: 24px; flex-wrap: wrap; }

@media (max-width: 1179px) {
  main { padding: 32px 36px 80px; }
  .hero { padding: 28px 28px 24px; }
  .hero h1 { font-size: 28px; }
}

@media (max-width: 820px) {
  header.top { padding: 10px 14px; gap: 10px; }
  header.top .crumb { display: none; }
  header.top .right { display: none; }
  .search { flex-basis: auto; max-width: none; margin: 0; }
  /* 16px font on input is mandatory — anything smaller triggers iOS
     Safari auto-zoom on focus, which leaves the page zoomed in even
     after blur. Padding stays compact so the header doesn't grow. */
  .search-input { padding: 10px 14px 10px 34px; font-size: 16px; }
  .search-kbd { display: none; }

  .layout { grid-template-columns: 1fr; }
  main { padding: 20px 16px 60px; }

  nav.side {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    width: min(82vw, 320px);
    height: 100dvh;
    padding: calc(var(--hdr-h) + 14px) 16px 24px 18px;
    background: rgba(4, 18, 44, 0.96);
    backdrop-filter: saturate(140%) blur(14px);
    border-right: 1px solid var(--border);
    box-shadow: 18px 0 32px rgba(0, 0, 0, 0.35);
    overflow-y: auto;
    transform: translateX(-100%);
    transition: transform 0.22s ease;
    z-index: 25;
    visibility: hidden;
  }
  nav.side[data-collapsed="false"] {
    transform: translateX(0);
    visibility: visible;
  }

  .nav-scrim {
    position: fixed;
    inset: 0;
    background: rgba(4, 18, 44, 0.55);
    backdrop-filter: blur(2px);
    z-index: 24;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.22s ease;
  }
  .nav-scrim[data-visible="true"] {
    opacity: 1;
    pointer-events: auto;
  }
  body.nav-open { overflow: hidden; }

  .nav-toggle {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: transparent;
    border: 1px solid var(--border-2);
    color: var(--text);
    font: inherit;
    font-size: 12px;
    font-weight: 600;
    padding: 6px 10px;
    border-radius: 6px;
    cursor: pointer;
  }
  .nav-toggle .chev {
    width: 14px; height: 14px;
    color: var(--text-mute);
  }
  .nav-toggle .chev-down { display: none; }
  nav.side .nav-toggle {
    margin-bottom: 8px;
  }

  main { padding: 20px 16px 60px; }
  .hero { padding: 22px 20px 20px; margin-bottom: 24px; border-radius: 12px; }
  .hero h1 { font-size: 22px; line-height: 1.2; }
  .hero p { font-size: 14px; }
  .hero .stats { gap: 18px; margin-top: 16px; }
  .hero .stat .v { font-size: 18px; }
  .hero .stat .l { font-size: 10px; }

  section { margin: 32px 0; }
  h2 { font-size: 18px; }

  .group-header { margin-top: 36px; padding-bottom: 10px; }
  .group-header h2 { font-size: 17px; }
  .group-header::before { height: 18px; }
  .group-header .group-meta { font-size: 11px; }

  .tool { padding: 14px 14px; border-radius: 10px; }
  .tool::before { top: 12px; bottom: 12px; }
  .tool-head h4.ttitle { font-size: 15px; }
  .tool-head .tname { font-size: 11px; }
  .badge { font-size: 9px; padding: 1px 6px; }
  .tool p.desc { font-size: 13px; }

  footer.bottom { padding: 20px 16px 28px; }
  footer.bottom .row { flex-direction: column; gap: 6px; }

  /* Dropdown grows to fill most of the viewport (the on-screen
     keyboard already eats ~40%). Items get fatter tap targets, the
     keyboard hint row hides — touch users don't use ↑↓/↵/esc. */
  .search-results {
    max-height: 70dvh;
    border-radius: 10px;
    padding: 4px;
    /* Pull the dropdown flush with the header on phones so it reads
       as a panel attached to the input, not a floating menu. */
    top: calc(100% + 4px);
  }
  .search-results .sr-item { padding: 12px 12px; border-radius: 8px; }
  .search-results .sr-row { gap: 6px; }
  .search-results .sr-title { font-size: 15px; }
  .search-results .sr-snippet { -webkit-line-clamp: 2; font-size: 12.5px; }
  .search-results .sr-hint { display: none; }
}

@media (max-width: 480px) {
  /* Below ~480px the header gets cramped; let the search dropdown
     ignore the header padding and span edge-to-edge so the snippets
     have room to breathe. The input itself stays in the header. */
  header.top .search-results {
    position: fixed;
    top: var(--hdr-h);
    left: 8px;
    right: 8px;
    max-height: calc(100dvh - var(--hdr-h) - 16px);
  }
}

@media (max-width: 480px) {
  main { padding: 16px 12px 48px; }
  .hero { padding: 18px 16px 16px; }
  .hero h1 { font-size: 20px; }
  .tool-head { gap: 6px; }
  .tool-head .anchor-link { display: none; }
}

/* ── Gated-content lockout ────────────────────────────────────────── */
/* Full-bleed lava + glass-card screen, rendered by theme.js's vault
   IIFE when a section page is requested without (or with the wrong)
   access key in the URL fragment. Visually mirrors the homepage:
   five colored blobs drifting under an SVG goo filter, with a
   centered glass card containing the lock message.
   All selectors are namespaced under .vault-locked-page so the
   styles only activate when the IIFE has flipped the body class —
   no risk of colliding with the homepage's identical-looking
   (separately-scoped) lava + glass on / itself. */

.vault-locked-page {
  /* Override theme.css's default body background with the dark radial
     the lava blobs sit against. */
  background: radial-gradient(ellipse 120% 80% at 50% 30%,
              #0a1f4a 0%, #04122c 100%) #04122c;
  background-attachment: fixed;
  min-height: 100vh;
  overflow-x: hidden;
}

/* @property registrations let the browser interpolate rim hotspot
   positions continuously across the keyframes — without them the
   rim highlights jump between snapshots. */
@property --vlock-rim-a-x { syntax: "<percentage>"; inherits: false; initial-value: 0%;   }
@property --vlock-rim-a-y { syntax: "<percentage>"; inherits: false; initial-value: 0%;   }
@property --vlock-rim-b-x { syntax: "<percentage>"; inherits: false; initial-value: 100%; }
@property --vlock-rim-b-y { syntax: "<percentage>"; inherits: false; initial-value: 100%; }
@property --vlock-rim-c-x { syntax: "<percentage>"; inherits: false; initial-value: 100%; }
@property --vlock-rim-c-y { syntax: "<percentage>"; inherits: false; initial-value: 0%;   }
@property --vlock-rim-d-x { syntax: "<percentage>"; inherits: false; initial-value: 0%;   }
@property --vlock-rim-d-y { syntax: "<percentage>"; inherits: false; initial-value: 100%; }
@property --vlock-rim-e-x { syntax: "<percentage>"; inherits: false; initial-value: 100%; }
@property --vlock-rim-e-y { syntax: "<percentage>"; inherits: false; initial-value: 50%;  }

/* Lava layer — fixed behind everything, parallax-driven by --mx/--my
   that the vault IIFE writes on document.documentElement from mousemove. */
.vault-bg {
  position: fixed; inset: 0; z-index: 0;
  pointer-events: none;
  opacity: 0.78;
  filter: url(#vault-lava-goo) blur(28px);
  transform: translate3d(calc(var(--mx, 0) * -16px), calc(var(--my, 0) * -10px), 0);
  transition: transform 320ms cubic-bezier(.2,.8,.2,1);
}
.vault-bg--no-goo { filter: none; }
.vault-bg__blob {
  position: absolute;
  border-radius: 50%;
  mix-blend-mode: screen;
}
.vault-bg--no-goo .vault-bg__blob { filter: blur(32px); }
.vault-bg__blob--a {
  width: 460px; height: 460px; top: -120px; left: -120px;
  background: radial-gradient(circle at 35% 35%, #4dd0e1, #1e88a8 70%);
  animation: vlock-bobA 72s ease-in-out infinite, vlock-morphA 18s ease-in-out infinite;
}
.vault-bg__blob--b {
  width: 520px; height: 520px; bottom: -160px; right: -160px;
  background: radial-gradient(circle at 60% 40%, #6a5cff, #3a2da8 70%);
  animation: vlock-bobB 96s ease-in-out infinite, vlock-morphB 22s ease-in-out infinite;
}
.vault-bg__blob--c {
  width: 380px; height: 380px; top: -100px; right: -80px;
  background: radial-gradient(circle at 40% 50%, #34a1d5, #1a5c80 70%);
  animation: vlock-bobC 84s ease-in-out infinite, vlock-morphC 20s ease-in-out infinite;
}
.vault-bg__blob--d {
  width: 340px; height: 340px; bottom: -100px; left: -80px;
  background: radial-gradient(circle at 50% 35%, #5dc4ff, #1d6da8 70%);
  animation: vlock-bobD 66s ease-in-out infinite, vlock-morphD 16s ease-in-out infinite;
}
.vault-bg__blob--e {
  width: 240px; height: 240px; top: 60%; right: -80px;
  background: radial-gradient(circle at 50% 50%, #8a76ff, #4a3acc 70%);
  animation: vlock-bobE 104s ease-in-out infinite, vlock-morphE 24s ease-in-out infinite;
}
@keyframes vlock-bobA { 0%,100% { transform: translate(0,0);     } 33% { transform: translate(140px, 180px);   } 66% { transform: translate(260px, 60px);   } }
@keyframes vlock-bobB { 0%,100% { transform: translate(0,0);     } 40% { transform: translate(-180px, -140px); } 70% { transform: translate(-80px, -300px); } }
@keyframes vlock-bobC { 0%,100% { transform: translate(0,0);     } 35% { transform: translate(-160px, 220px);  } 70% { transform: translate(-40px, 80px);   } }
@keyframes vlock-bobD { 0%,100% { transform: translate(0,0);     } 45% { transform: translate(220px, -180px);  } 75% { transform: translate(120px, -40px);  } }
@keyframes vlock-bobE { 0%,100% { transform: translate(0,0);     } 50% { transform: translate(-90px, -320px);  } }
@keyframes vlock-morphA { 0%,100% { border-radius: 50%; } 50% { border-radius: 60% 40% 55% 45% / 50% 60% 40% 50%; } }
@keyframes vlock-morphB { 0%,100% { border-radius: 50%; } 50% { border-radius: 45% 55% 50% 50% / 55% 45% 60% 40%; } }
@keyframes vlock-morphC { 0%,100% { border-radius: 50%; } 50% { border-radius: 55% 45% 60% 40% / 45% 55% 45% 55%; } }
@keyframes vlock-morphD { 0%,100% { border-radius: 50%; } 50% { border-radius: 50% 50% 45% 55% / 60% 40% 50% 50%; } }
@keyframes vlock-morphE { 0%,100% { border-radius: 50%; } 50% { border-radius: 55% 45% 50% 50% / 50% 55% 45% 55%; } }

/* Main stage — the section page's <main> is the natural slot for
   the card, but we don't want its existing padding/maxwidth, so the
   IIFE puts the card in a sibling .vault-locked-stage that takes
   over. Height roughly matches the homepage hero (95vh) so the
   card sits in the same visual position. */
.vault-locked-stage {
  position: relative;
  z-index: 10;
  min-height: 95vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 48px 24px 64px;
}

/* The glass card itself. Same recipe as .home-card on the homepage —
   noise + layered linear-gradient + heavy backdrop blur + multi-layer
   inset/outset shadows. Smaller max-width than the hero card because
   the lockout message is shorter. */
.vault-card {
  position: relative;
  z-index: 3;
  width: 100%;
  max-width: 520px;
  padding: 44px 40px 36px;
  border-radius: 28px;
  isolation: isolate;
  text-align: center;
  color: rgba(255, 255, 255, 0.95);
  background:
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.03 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>"),
    linear-gradient(155deg,
      rgba(255, 255, 255, 0.13) 0%,
      rgba(255, 255, 255, 0.04) 45%,
      rgba(255, 255, 255, 0.02) 70%,
      rgba(255, 255, 255, 0.08) 100%);
  backdrop-filter: blur(48px) saturate(125%) brightness(104%);
  -webkit-backdrop-filter: blur(48px) saturate(125%) brightness(104%);
  border: 1px solid rgba(255, 255, 255, 0.18);
  box-shadow:
    0 50px 100px -24px rgba(0, 0, 0, 0.55),
    0 16px 32px -10px rgba(0, 0, 0, 0.35),
    inset 0 1px 0 rgba(255, 255, 255, 0.16),
    inset 0 -2px 8px rgba(0, 0, 0, 0.14),
    inset 0 0 60px rgba(255, 255, 255, 0.05);
  transform: translate3d(calc(var(--mx, 0) * 4px), calc(var(--my, 0) * 4px), 0);
  transition: transform 320ms cubic-bezier(.2,.8,.2,1), box-shadow 480ms cubic-bezier(.22,1,.36,1);
  animation: vlock-cardIn 540ms cubic-bezier(.22,1,.36,1) both;
}
@keyframes vlock-cardIn {
  from { transform: translateY(12px) scale(0.97); opacity: 0; }
  to   { transform: translateY(0) scale(1); opacity: 1; }
}
/* Top-edge sheen so the upper curve of the glass catches some light. */
.vault-card::before {
  content: "";
  position: absolute; inset: -1px;
  border-radius: inherit;
  background: radial-gradient(ellipse 120% 60% at 50% -10%,
              rgba(255, 255, 255, 0.13) 0%,
              rgba(255, 255, 255, 0.04) 35%,
              rgba(255, 255, 255, 0) 60%);
  pointer-events: none;
  z-index: 1;
}
.vault-card > * { position: relative; z-index: 2; }

/* Rim highlights — five bright spots orbiting the card border, each
   synced to its corresponding blob's bob cycle. Drawn as a 2px ring
   via mask-composite: exclude so the highlight only paints on the
   actual border, not over the card body. */
.vault-card::after {
  content: "";
  position: absolute; inset: 0;
  border-radius: inherit;
  padding: 2px;
  background:
    radial-gradient(circle 240px at var(--vlock-rim-a-x, 0%)   var(--vlock-rim-a-y, 0%),
      rgba(77, 208, 225, 1)   0%, rgba(120, 220, 235, 0.8) 14%,
      rgba(160, 230, 240, 0.4) 32%, transparent 65%),
    radial-gradient(circle 240px at var(--vlock-rim-b-x, 100%) var(--vlock-rim-b-y, 100%),
      rgba(106, 92, 255, 0.95) 0%, rgba(150, 135, 255, 0.75) 14%,
      rgba(185, 175, 255, 0.4) 32%, transparent 65%),
    radial-gradient(circle 220px at var(--vlock-rim-c-x, 100%) var(--vlock-rim-c-y, 0%),
      rgba(52, 161, 213, 0.95) 0%, rgba(110, 190, 225, 0.75) 14%,
      rgba(155, 210, 235, 0.4) 32%, transparent 65%),
    radial-gradient(circle 220px at var(--vlock-rim-d-x, 0%)   var(--vlock-rim-d-y, 100%),
      rgba(93, 196, 255, 0.95) 0%, rgba(140, 215, 255, 0.75) 14%,
      rgba(175, 225, 250, 0.4) 32%, transparent 65%),
    radial-gradient(circle 200px at var(--vlock-rim-e-x, 100%) var(--vlock-rim-e-y, 50%),
      rgba(138, 118, 255, 0.9) 0%, rgba(170, 155, 255, 0.7) 14%,
      rgba(195, 185, 255, 0.35) 32%, transparent 65%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
  pointer-events: none;
  z-index: 3;
  animation:
    vlock-rimA 42s ease-in-out infinite,
    vlock-rimB 56s ease-in-out infinite,
    vlock-rimC 49s ease-in-out infinite,
    vlock-rimD 38s ease-in-out infinite,
    vlock-rimE 64s ease-in-out infinite;
}
@keyframes vlock-rimA { 0%,100% { --vlock-rim-a-x: 0%;   --vlock-rim-a-y: 0%;   } 50% { --vlock-rim-a-x: 18%; --vlock-rim-a-y: 24%; } }
@keyframes vlock-rimB { 0%,100% { --vlock-rim-b-x: 100%; --vlock-rim-b-y: 100%; } 50% { --vlock-rim-b-x: 78%; --vlock-rim-b-y: 80%; } }
@keyframes vlock-rimC { 0%,100% { --vlock-rim-c-x: 100%; --vlock-rim-c-y: 0%;   } 50% { --vlock-rim-c-x: 82%; --vlock-rim-c-y: 28%; } }
@keyframes vlock-rimD { 0%,100% { --vlock-rim-d-x: 0%;   --vlock-rim-d-y: 100%; } 50% { --vlock-rim-d-x: 22%; --vlock-rim-d-y: 72%; } }
@keyframes vlock-rimE { 0%,100% { --vlock-rim-e-x: 100%; --vlock-rim-e-y: 50%; } 50% { --vlock-rim-e-x: 78%; --vlock-rim-e-y: 30%; } }

/* Card content — icon, title, body, CTA. */
.vault-card__icon {
  width: 56px; height: 56px;
  margin: 0 auto 18px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.14);
  display: flex;
  align-items: center;
  justify-content: center;
  color: rgba(255, 255, 255, 0.92);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.12);
}
.vault-card__icon svg {
  width: 24px; height: 24px;
}
.vault-card__title {
  margin: 0 0 12px;
  font-size: 24px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: rgba(255, 255, 255, 0.96);
}
.vault-card__body {
  margin: 0 0 28px;
  font-size: 15px;
  line-height: 1.55;
  color: rgba(255, 255, 255, 0.72);
}
.vault-card__body strong {
  color: rgba(255, 255, 255, 0.92);
  font-weight: 600;
}
.vault-card__cta {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 10px 22px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.1);
  border: 1px solid rgba(255, 255, 255, 0.22);
  color: rgba(255, 255, 255, 0.96);
  font-size: 14px;
  font-weight: 500;
  text-decoration: none;
  transition: background 160ms ease, border-color 160ms ease, transform 160ms ease;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.12);
}
.vault-card__cta:hover {
  background: rgba(255, 255, 255, 0.18);
  border-color: rgba(255, 255, 255, 0.32);
  transform: translateY(-1px);
}
/* The offline "Retry now" CTA is a <button>, not an <a> — reset the UA
   chrome so it matches the link-styled CTA above. */
button.vault-card__cta {
  cursor: pointer;
  font-family: inherit;
  -webkit-appearance: none;
  appearance: none;
}

/* Busy state: the silent-refresh interstitial swaps the icon for a
   spinner. The container keeps the same 56px disc as the static icons. */
.vault-card__icon--busy {
  color: rgba(255, 255, 255, 0.92);
}
.vault-spinner {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  border: 2.5px solid rgba(255, 255, 255, 0.22);
  border-top-color: rgba(255, 255, 255, 0.92);
  animation: vlock-spin 0.7s linear infinite;
}
@keyframes vlock-spin {
  to { transform: rotate(360deg); }
}
@media (prefers-reduced-motion: reduce) {
  .vault-spinner { animation-duration: 1.6s; }
}

/* Header tinting when in the locked state — keep nav legible against
   the lava but lighter than the default near-opaque header bar. */
.vault-locked-page header.top {
  background: rgba(4, 18, 44, 0.55);
  backdrop-filter: saturate(140%) blur(18px);
  -webkit-backdrop-filter: saturate(140%) blur(18px);
}

/* Hide section-page chrome that survives a vault swap. nav.side and
   aside.rail are siblings of <main> (rendered by eino's mcpdocs +
   raindropapi templates) so the vault IIFE's main.innerHTML wipe
   doesn't touch them. Side-nav toggles + scrim are likewise outside
   <main>. All three would otherwise leak structure of the gated
   section even when the actual content is encrypted. */
.vault-locked-page nav.side,
.vault-locked-page aside.rail,
.vault-locked-page .nav-scrim,
.vault-locked-page .nav-toggle,
.vault-locked-page footer.bottom {
  display: none !important;
}

/* With nav.side and aside.rail hidden, the .layout grid still reserves
   their columns (220px / 380px), and <main> — the only remaining grid
   item — gets placed into the first column. That squishes the lockout
   card into a ~220px-wide strip on the left. Collapse the grid to a
   single column so <main> takes the full viewport width. */
.vault-locked-page .layout {
  grid-template-columns: 1fr;
  max-width: none;
}
.vault-locked-page main {
  padding: 0;
  max-width: none;
}

@media (max-width: 600px) {
  .vault-card { padding: 36px 28px 30px; }
  .vault-card__title { font-size: 20px; }
  .vault-card__body { font-size: 14px; }
}

@media (prefers-reduced-motion: reduce) {
  .vault-bg, .vault-bg__blob,
  .vault-card, .vault-card::after {
    animation: none !important;
    transition: none !important;
  }
  .vault-bg { transform: none; }
  .vault-card { transform: none; }
}
