/* 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 hardcode the la.raindrop.com CDN path (deployed by the
   auth0-login pipeline). Not templated here because the theme file
   itself is static. */

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

: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;
  background: rgba(4, 18, 44, 0.88);
  backdrop-filter: saturate(140%) blur(10px);
  border-bottom: 1px solid var(--border);
  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));
}

.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;
}
/* 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-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);
}

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;
}

.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; }

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; }
  .search-input { padding: 9px 50px 9px 34px; font-size: 13px; }
  .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; }

  .search-results { max-height: 60vh; border-radius: 10px; }
  .search-results .sr-snippet { -webkit-line-clamp: 2; }
}

@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; }
}
