/* ============================================================================
   theme.css — soft pastel-purple restyle, layered on top of app.css.
   Shift: acid-lime cyber-zine → boba.xyz lavender (sans-only, pills, rounding,
   blobs, no ticker/§-numbers). Overrides tokens + a few component rules; rest
   of app.css carries over so changes propagate site-wide. Roll back: remove
   the <link> in base.html.
   ============================================================================ */

:root {
  /* ─── Palette ──────────────────────────────────────────────────── */
  --ink:         #0F0F12;
  --ink-soft:    #131317;
  --surface-1:   #1A1A20;
  --surface-2:   #1E1E26;
  --surface-3:   #25252E;
  --border:      #2A2A33;
  --border-soft: #1F1F26;
  --border-hot:  #3A3A47;

  --paper:       #F5F5F7;
  --paper-soft:  #DCDCE0;
  --mute:        #8E8E94;
  --mute-soft:   #6A6A72;
  --faint:       #4A4A54;

  /* Primary accent — lavender. Replaces acid-lime everywhere via --acid
     (button bg, focus rings, brand/pill dots, section-rule num, etc.). */
  --acid:        #C4A9FF;
  --acid-dim:    #A88AEF;
  --acid-glow:   rgba(196, 169, 255, 0.22);

  /* Secondary accents — softened to pastel. */
  --magenta:     #F49AC2;
  --magenta-dim: #E07AAB;
  --cyan:        #8ED5DC;
  --amber:       #F4D58D;
  --rose:        #F0A8AC;
  --emerald:     #9DD5B5;

  /* ─── Typography — sans-only ──────────────────────────────────────
     Display face = Unbounded (self-hosted @font-face in app.css). Italic
     falls back to Inter so we stay sans-only (no Instrument Serif). Keep
     --font-mono for code/IDs. */
  --font-display:        "Unbounded", "Inter", "Hanken Grotesk", "Helvetica Neue", system-ui, -apple-system, sans-serif;
  --font-display-italic: "Inter", "Hanken Grotesk", "Helvetica Neue", system-ui, -apple-system, sans-serif;
  --font-body:           "Inter", "Hanken Grotesk", "Helvetica Neue", system-ui, -apple-system, sans-serif;

  /* ─── Generous rounding ─────────────────────────────────────────── */
  --radius-sm:  10px;
  --radius:     14px;
  --radius-lg:  20px;
  --radius-xl:  28px;

  /* ─── Atmospheric softening ─────────────────────────────────────── */
  --mesh-opacity:  0.72;
  --grain-opacity: 0.025;

  /* ─── Mobile / Telegram-WebView safe-area ─────────────────────────
     env(safe-area-inset-*) is 0 without a notch/home-indicator (desktop
     no-op); on notched iOS Safari / TG WebView it expands to system insets
     — a clean padding source for composer, footer, sticky bars. */
  --safe-top:    env(safe-area-inset-top,    0px);
  --safe-right:  env(safe-area-inset-right,  0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --safe-left:   env(safe-area-inset-left,   0px);
}

/* ─── Mobile touch hygiene ───────────────────────────────────────────
   Suppress WebKit's grey/blue tap-flash overlay (mobile-only; desktop
   ignores it). `touch-action: manipulation` on controls kills the 300ms
   double-tap-zoom click delay in mobile Safari while keeping page pinch-zoom
   — attached to buttons/links only, not scrollers. */
* { -webkit-tap-highlight-color: transparent; }
a, button, [role="button"], input, select, textarea, label {
  touch-action: manipulation;
}

/* ─── Mobile-render safeguards (don't trigger desktop fallback) ───────
   When one rogue child stretches past the viewport, mobile browsers
   auto-zoom-out the whole page ("show desktop site"). These four rules
   close common offenders without touching desktop (max-width:100% caps to
   PARENT, wider than these elements on desktop, so it never bites). */
html {
  /* Disable iOS landscape text auto-scaling: WebKit bumps fonts ~20%,
     breaking media-query thresholds (13px input → 16px → wrong rules). */
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  /* Restore iOS momentum scroll in pinned-height regions (chat feed). */
  -webkit-overflow-scrolling: touch;
}
html, body {
  /* Hard cap document width (belt-and-braces over app.css overflow-x):
     never exceed the viewport even with a negative margin / fixed-width
     SVG. hidden = fallback; clip refines on modern engines (no scroll ctx). */
  max-width: 100vw;
  overflow-x: hidden;
  overflow-x: clip;
}
/* Cap media: one full-bleed <img>/<pre> wider than its parent triggers
   "desktop scaling" of the whole document. */
img, svg, video, iframe, canvas, picture {
  max-width: 100%;
  height: auto;
}
/* iOS Safari auto-zooms (and won't undo) on focused inputs < 16px. Force
   16px on text inputs, mobile-only (@media keeps small desktop fields). */
@media (max-width: 880px) {
  input:not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="range"]),
  select,
  textarea {
    font-size: 16px;
  }
}

/* ─── Body background — soft amorphous blobs ────────────────────────
   Lavender/pink/cyan blobs, heavier blur + less saturation than the
   cyber-zine atmosphere. Animation removed: a 70px blur on a viewport-sized
   fixed pseudo forced Firefox to re-rasterise the layer every tick (Gecko
   won't GPU-composite large CSS-filter layers), burning CPU + ~30-80MB of
   bitmaps in long chats. Drift (4°/90s) was imperceptible; static lets
   Firefox cache the rasterise once. */
body::before {
  /* Three blobs, not four. The 4th (center wash, 0.04 alpha) was nearly
     invisible but cost one extra per-pixel stops-walk; Firefox SWGL
     profiles showed commitRadialGradientFromStops ~50 samples/thread, so
     4→3 trims that proportionally. Diagonal palette reads the same. */
  background:
    radial-gradient(58vw 50vw at 12% 14%, rgba(196, 169, 255, 0.10) 0%, transparent 64%),
    radial-gradient(44vw 44vw at 88% 22%, rgba(244, 154, 194, 0.075) 0%, transparent 64%),
    radial-gradient(60vw 50vw at 70% 92%, rgba(142, 213, 220, 0.06) 0%, transparent 64%) !important;
  /* Was blur(70px). Radii (44–60vw) already give diffuse edges from the
     gradient stops; the extra 20px kernel only added rasterise cost on
     every cache invalidation. 50px keeps the look, halves the pixel work. */
  filter: blur(50px) saturate(1.05) !important;
  animation: none !important;
}

/* Drop the grain pseudo (app.css body::after): at --grain-opacity 0.025
   it's invisible, yet mix-blend-mode:overlay makes Firefox re-composite an
   isolation group every paint frame (recomputes on scroll). The lavender
   mesh already gives texture; killing it stops per-frame backdrop work. */
body::after { display: none !important; }

/* ─── Hide editorial chrome ─────────────────────────────────────────
   Ticker gone; section-rule drops its §-number + rules → plain heading. */
.ticker { display: none !important; }

.section-rule {
  display: flex;
  gap: 12px;
  margin: 56px 0 22px;
  align-items: baseline;
  font-family: var(--font-body);
  font-size: 14px;
  letter-spacing: 0;
  text-transform: none;
}
.section-rule::before,
.section-rule::after { display: none !important; }
.section-rule__num { display: none; }
.section-rule__title {
  color: var(--paper);
  font-weight: 600;
  font-size: 18px;
  letter-spacing: -0.012em;
  text-transform: none;
}

/* ─── Buttons — pill-shaped, soft shadow on hover ──────────────────── */
.btn {
  height: 44px;
  padding: 0 22px;
  border-radius: 999px;
  font-weight: 500;
  letter-spacing: -0.005em;
}
.btn--sm { height: 36px; padding: 0 16px; border-radius: 999px; font-size: 13px; }

.btn--primary {
  background: var(--acid);
  color: #1A1A20;
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.10) inset;
}
.btn--primary:hover {
  background: var(--acid-dim);
  box-shadow: 0 6px 22px rgba(196, 169, 255, 0.28), 0 1px 0 rgba(255, 255, 255, 0.12) inset;
}

.btn--ghost {
  background: rgba(255, 255, 255, 0.04);
  border-color: transparent;
  color: var(--paper);
}
.btn--ghost:hover {
  background: rgba(255, 255, 255, 0.08);
  border-color: transparent;
}

/* Integration card — tabbed install snippets (replaces "Endpoints").
   Pill-segmented tabs, active gets lavender wash, hidden panels use [hidden].
   Geometry: inline-flex+nowrap keeps one strip (flex-wrap bled to 2 lines at
   ~80px); align-items:stretch equalises button heights; tab radius = container
   minus padding so the active pill sits flush (no half-moon of background). */
.integration__tabs {
  display: inline-flex;
  flex-wrap: nowrap;
  align-items: stretch;
  gap: 2px;
  padding: 3px;
  background: rgba(255, 255, 255, 0.025);
  border: 1px solid var(--border-soft);
  border-radius: 999px;
  margin-bottom: 14px;
}
.integration__tab {
  appearance: none;
  border: 0;
  background: transparent;
  color: var(--mute);
  padding: 7px 18px;
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.02em;
  line-height: 1.2;
  border-radius: 999px;
  cursor: pointer;
  transition: color 140ms ease, background 140ms ease, box-shadow 140ms ease;
  /* Reserve the 1px inset-ring width on every tab so the active pill
     doesn't nudge its neighbours when it gains the highlight below. */
  box-shadow: inset 0 0 0 1px transparent;
  white-space: nowrap;
}
.integration__tab:hover {
  color: var(--paper);
  background: rgba(255, 255, 255, 0.03);
}
.integration__tab--active {
  color: var(--paper);
  background: rgba(196, 169, 255, 0.18);
  font-weight: 600;
  /* INSET ring keeps the pill's outer size identical to inactive tabs;
     the old outset ring leaked into the gap and read as "bigger". */
  box-shadow: inset 0 0 0 1px rgba(196, 169, 255, 0.34);
}
.integration__tab:focus-visible {
  outline: 2px solid var(--acid);
  outline-offset: 2px;
}

/* ─── Narrow viewports / Telegram WebView ─────────────────────────────
   At ≤520px (in-bot WebView ~370px) the inline-flex pill bar overflowed
   the card (last tab clipped). Full-width flex + equal-share children size
   pills to the card; padding trimmed (7→6 / 18→8px) so "Claude Code" fits
   on one line at 320px. Same fix applied to the OS sub-picker. */
@media (max-width: 520px) {
  .integration__tabs,
  .integration__os {
    display: flex;
    width: 100%;
    flex-wrap: nowrap;
  }
  .integration__tab,
  .integration__os-tab {
    flex: 1 1 0;
    min-width: 0;
    padding-left: 8px;
    padding-right: 8px;
    text-align: center;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .integration__tab { padding-top: 6px; padding-bottom: 6px; font-size: 11.5px; }
  .integration__os-tab { padding-top: 4px; padding-bottom: 4px; font-size: 10.5px; }
}

.integration__hint {
  margin: 0 0 10px;
  font-size: 12.5px;
  color: var(--mute);
  line-height: 1.5;
}

/* OS sub-picker inside an integration panel — small pill tabs (Win/mac/
   Linux) that pick the install one-liner. Sits between hint and code. */
.integration__os {
  display: inline-flex;
  gap: 2px;
  padding: 3px;
  margin: 0 0 10px;
  background: rgba(255, 255, 255, 0.025);
  border: 1px solid var(--border-soft);
  border-radius: 999px;
}
.integration__os-tab {
  appearance: none;
  border: 0;
  background: transparent;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.02em;
  color: var(--mute);
  padding: 5px 12px;
  border-radius: 999px;
  cursor: pointer;
  transition: background 140ms, color 140ms;
}
.integration__os-tab:hover { color: var(--paper-soft); }
.integration__os-tab--active {
  background: rgba(196, 169, 255, 0.16);
  color: var(--acid);
}
/* One-line "then set X = Y" hint after .integration__code. Inline <code>
   chips reuse the global .code styling. */
.integration__sub {
  margin: 10px 0 0;
  font-size: 12px;
  line-height: 1.55;
  color: var(--paper-soft);
}
.integration__sub code {
  font-family: var(--font-mono);
  font-size: 11px;
  padding: 1px 6px;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid var(--border-soft);
  border-radius: 5px;
  color: var(--paper);
}
.integration__code {
  margin: 0;
  padding: 12px 14px;
  background: rgba(0, 0, 0, 0.30);
  border: 1px solid var(--border-soft);
  border-radius: 10px;
  font-family: var(--font-mono);
  font-size: 11.5px;
  line-height: 1.55;
  color: var(--paper-soft);
  white-space: pre-wrap;
  word-break: break-all;
  max-height: 180px;
  overflow-y: auto;
  scrollbar-width: thin;
}
.integration__code code { background: none; color: inherit; padding: 0; }
.integration__copy {
  margin-top: 10px;
  appearance: none;
  border: 1px solid var(--border-soft);
  background: rgba(255, 255, 255, 0.03);
  color: var(--paper);
  border-radius: 8px;
  padding: 7px 14px;
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  transition: background 140ms ease, border-color 140ms ease, color 140ms ease;
}
.integration__copy:hover {
  background: rgba(196, 169, 255, 0.10);
  border-color: rgba(196, 169, 255, 0.40);
}
.integration__copy.is-copied {
  color: var(--emerald);
  border-color: rgba(157, 213, 181, 0.50);
  background: rgba(157, 213, 181, 0.10);
}
.integration__more {
  display: inline-block;
  margin-top: 14px;
  font-family: var(--font-mono);
  font-size: 11.5px;
  color: var(--acid);
  text-decoration: none;
  letter-spacing: 0.02em;
}
.integration__more:hover { color: var(--paper); }

/* Setup page — long-form guide; per-tool sections with numbered steps +
   code blocks. Inherits .integration__code styling. */
.setup-section {
  padding: 24px 26px;
  margin-top: 22px;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
  background: rgba(255, 255, 255, 0.012);
}
.setup-section__title {
  font-family: var(--font-body);
  font-size: 18px;
  font-weight: 600;
  color: var(--paper);
  margin: 0 0 6px;
}
.setup-section__sub {
  margin: 0 0 18px;
  font-size: 13px;
  color: var(--mute);
}
.setup-step {
  display: grid;
  grid-template-columns: 28px minmax(0, 1fr);
  gap: 14px;
  align-items: start;
  margin-top: 14px;
}
.setup-step__num {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  border: 1px solid rgba(196, 169, 255, 0.40);
  color: var(--paper);
  background: rgba(196, 169, 255, 0.10);
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.setup-step__body { font-size: 13px; line-height: 1.6; color: var(--paper-soft); }
.setup-step__body p { margin: 0 0 8px; }
.setup-step__body code:not(.integration__code code) {
  font-family: var(--font-mono);
  font-size: 11.5px;
  padding: 1px 5px;
  border-radius: 4px;
  background: rgba(196, 169, 255, 0.10);
  color: var(--paper);
}

/* Setup page — top TOC chips linking each per-tool article. Flat doc keyed
   by #all / #cc / #codex / #opencode / #sdk anchors. */
.setup-toc {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 18px;
}
.setup-toc__chip {
  font-family: var(--font-mono);
  font-size: 11.5px;
  letter-spacing: 0.02em;
  color: var(--paper-soft);
  padding: 6px 12px;
  border: 1px solid var(--border-soft);
  border-radius: 999px;
  text-decoration: none;
  background: rgba(255, 255, 255, 0.02);
  transition: color 140ms, background 140ms, border-color 140ms;
}
.setup-toc__chip--active,
.setup-toc__chip--active:hover {
  color: var(--acid);
  background: rgba(196, 169, 255, 0.16);
  border-color: rgba(196, 169, 255, 0.55);
}
.setup-toc__chip:hover {
  color: var(--acid);
  background: rgba(196, 169, 255, 0.10);
  border-color: rgba(196, 169, 255, 0.36);
}

/* Setup page — OS picker (Win/mac/Linux) inside each tool's steps. Pure
   CSS: hidden radios + labels-as-tabs reveal the matching .setup-os__pane
   via `:checked ~` (no JS). The id-suffix trick ([id$="-win"] etc.) lets one
   rule cover every os-group (os-all-*, os-cc-*, os-codex-*, os-opencode-*). */
.setup-os { display: block; margin: 8px 0 0; }
.setup-os__radio {
  position: absolute;
  opacity: 0;
  pointer-events: none;
  width: 0;
  height: 0;
}
.setup-os__tabs {
  display: inline-flex;
  gap: 2px;
  padding: 3px;
  margin: 0 0 10px;
  background: rgba(255, 255, 255, 0.025);
  border: 1px solid var(--border-soft);
  border-radius: 999px;
}
.setup-os__tab {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.02em;
  color: var(--mute);
  padding: 5px 12px;
  border-radius: 999px;
  cursor: pointer;
  user-select: none;
  transition: background 140ms, color 140ms;
}
.setup-os__tab:hover { color: var(--paper-soft); }
.setup-os__pane { display: none; }
.setup-os__radio[id$="-win"]:checked ~ .setup-os__tabs label[for$="-win"],
.setup-os__radio[id$="-mac"]:checked ~ .setup-os__tabs label[for$="-mac"],
.setup-os__radio[id$="-linux"]:checked ~ .setup-os__tabs label[for$="-linux"] {
  background: rgba(196, 169, 255, 0.16);
  color: var(--acid);
}
.setup-os__radio[id$="-win"]:checked ~ .setup-os__pane[data-os="win"],
.setup-os__radio[id$="-mac"]:checked ~ .setup-os__pane[data-os="mac"],
.setup-os__radio[id$="-linux"]:checked ~ .setup-os__pane[data-os="linux"] {
  display: block;
}
.setup-os__radio:focus-visible ~ .setup-os__tabs {
  box-shadow: 0 0 0 2px rgba(196, 169, 255, 0.30);
  border-color: rgba(196, 169, 255, 0.45);
}
.setup-os__hint {
  margin: 0 0 6px;
  color: var(--mute);
  font-family: var(--font-mono);
  font-size: 11px;
}

/* Setup page — top-level "Automatic / Manual" toggle swapping the whole
   page body. Same radio-tab pattern as .setup-os but with large nav-sized
   pills. Nested .setup-os groups use their own radio names (os-cc-auto, …)
   so the suffix-selector scopes to the nearest .setup-os ancestor. */
.setup-mode { display: block; margin: 22px 0 0; }
.setup-mode__radio {
  position: absolute;
  opacity: 0;
  pointer-events: none;
  width: 0;
  height: 0;
}
.setup-mode__tabs {
  display: inline-flex;
  gap: 4px;
  padding: 5px;
  margin: 0 0 18px;
  background: rgba(255, 255, 255, 0.025);
  border: 1px solid var(--border-soft);
  border-radius: 999px;
}
.setup-mode__tab {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.02em;
  color: var(--mute);
  padding: 9px 18px;
  border-radius: 999px;
  cursor: pointer;
  user-select: none;
  transition: background 140ms, color 140ms;
}
.setup-mode__tab:hover { color: var(--paper-soft); }
.setup-mode__dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.55;
}
.setup-mode__pane { display: none; }
.setup-mode__radio[id$="-auto"]:checked ~ .setup-mode__tabs label[for$="-auto"],
.setup-mode__radio[id$="-manual"]:checked ~ .setup-mode__tabs label[for$="-manual"] {
  background: rgba(196, 169, 255, 0.16);
  color: var(--acid);
}
.setup-mode__radio[id$="-auto"]:checked ~ .setup-mode__pane[data-mode="auto"],
.setup-mode__radio[id$="-manual"]:checked ~ .setup-mode__pane[data-mode="manual"] {
  display: block;
}
.setup-mode__radio:focus-visible ~ .setup-mode__tabs {
  box-shadow: 0 0 0 2px rgba(196, 169, 255, 0.30);
  border-color: rgba(196, 169, 255, 0.45);
}
.setup-mode__lead {
  margin: 0 0 6px;
  font-size: 13.5px;
  line-height: 1.65;
  color: var(--paper-soft);
  max-width: 62ch;
}
.setup-mode__foot {
  margin: 22px 0 0;
  padding: 14px 18px;
  border: 1px dashed var(--border-soft);
  border-radius: var(--radius);
  background: rgba(255, 255, 255, 0.012);
  color: var(--mute);
  font-family: var(--font-mono);
  font-size: 11.5px;
  line-height: 1.6;
}

/* Setup section — optional header row with a "recommended" badge for the
   first Auto-pane card. Falls back to .setup-section__title flow if no
   head wrapper. */
.setup-section__head {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0 0 6px;
  flex-wrap: wrap;
}
.setup-section__head .setup-section__title { margin: 0; }
.setup-section__badge {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--acid);
  padding: 3px 9px;
  border-radius: 999px;
  background: rgba(196, 169, 255, 0.14);
  border: 1px solid rgba(196, 169, 255, 0.40);
}
.setup-section__after {
  margin: 14px 0 0;
  color: var(--mute);
  font-family: var(--font-mono);
  font-size: 11.5px;
}

/* Setup-step inline helpers — small print under a step's code block;
   kept tight so a long Manual guide doesn't feel like a wall. */
.setup-step__note {
  margin: 10px 0 0;
  font-size: 12px;
  color: var(--mute-soft);
  line-height: 1.6;
}
.setup-step__path {
  margin: 0 0 8px;
  font-size: 11.5px;
  color: var(--mute-soft);
}
.setup-step__list {
  margin: 8px 0;
  padding-left: 22px;
  color: var(--paper-soft);
  line-height: 1.7;
}

/* Chat-composer "Send" / "Generate image" — premium feel without touching
   the global .btn--primary. Brand gradient (lavender → magenta-peach) + hover
   glow so the conversation's primary action is unmistakeable. */
.btn--send {
  height: 38px;
  padding: 0 18px 0 16px;
  border-radius: 999px;
  font-size: 13.5px;
  font-weight: 600;
  letter-spacing: -0.005em;
  color: #1A1A20;
  background: linear-gradient(135deg, #D8C2FF 0%, #F49AC2 100%);
  border: 0;
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.35) inset,
    0 6px 18px -6px rgba(196, 169, 255, 0.55);
  transition:
    transform 140ms cubic-bezier(0.22, 1, 0.36, 1),
    box-shadow 200ms ease,
    filter 200ms ease;
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.btn--send:hover {
  transform: translateY(-1px);
  filter: brightness(1.05);
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.40) inset,
    0 12px 32px -8px rgba(196, 169, 255, 0.70),
    0 0 0 4px rgba(196, 169, 255, 0.12);
}
.btn--send:active {
  transform: translateY(0) scale(0.985);
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.30) inset,
    0 4px 10px -4px rgba(196, 169, 255, 0.55);
}
.btn--send:focus-visible {
  outline: 2px solid rgba(196, 169, 255, 0.65);
  outline-offset: 3px;
}
.btn--send svg {
  flex-shrink: 0;
  transform: translateX(-1px);
  transition: transform 180ms cubic-bezier(0.22, 1, 0.36, 1);
}
.btn--send:hover svg {
  transform: translateX(1px) rotate(-8deg);
}

.btn--magenta {
  background: var(--magenta);
  color: #1A1A20;
}
.btn--magenta:hover { background: var(--magenta-dim); }

.btn--danger-link {
  font-family: var(--font-body);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
}

/* ─── Cards — softer surface, no corner marks ──────────────────────── */
.card {
  background: var(--surface-1);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-lg);
  padding: 26px;
}
.card--marked::before,
.card--marked::after { display: none !important; }
.card--hero,
.card--magenta,
.card--emerald {
  background:
    radial-gradient(80% 100% at 0% 0%, rgba(196, 169, 255, 0.08) 0%, transparent 70%),
    var(--surface-1);
  border: 1px solid var(--border-soft);
}

/* ─── Brand — drop the italic serif, cat mascot mark ───────────────── */
.brand__name {
  font-family: var(--font-body);
  font-weight: 700;
  font-style: normal;
  font-size: 18px;
  letter-spacing: -0.012em;
  line-height: 1;
}
.brand__name .dot { color: var(--acid); }
.brand__name .ext {
  font-family: var(--font-body);
  font-weight: 500;
  font-style: normal;
  font-size: 14px;
  color: var(--mute);
  letter-spacing: 0;
}

/* Brand mark — rounded lavender plate (the constant identity) holding the
   mascot, which fills most of it. */
.brand__mark {
  width: 40px;
  height: 40px;
  background: var(--acid);
  border-color: transparent;
  border-radius: 11px;
  color: #FFFFFF;
}
.brand__mark svg,
.brand__mark img {
  width: 36px;
  height: 36px;
  object-fit: contain;
  display: block;
}
.brand__mark svg path,
.brand__mark svg ellipse {
  stroke: none;
}

/* ─── Site header — softer translucent ─────────────────────────────── */
.site-header {
  /* Alpha walked up (0.78→0.88→0.94) as backdrop-filter was reduced then
     killed: the frosted glass re-sampled per scroll frame, and those pixels
     included the body::before blur(50px) mesh — nested blur that bottlenecked
     landing scroll. At 0.94 the bar is near-opaque so the lost blur is
     invisible. -webkit prefix dropped (no sampler => no need). */
  background: rgba(15, 15, 18, 0.94);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  border-bottom: 1px solid var(--border-soft);
}
.site-header__inner { height: 64px; }

/* ─── Hamburger drawer (mobile only) ─────────────────────────────────
   Pure-CSS off-canvas nav. Three elements (hidden on desktop):
   #mobile-nav-toggle (checkbox = open-state), .mobile-nav-btn (burger
   <label>), .mobile-nav-overlay (click-to-close <label>). At ≤880px the
   button+overlay show and .nav becomes a fixed drawer sliding in via
   translateX. Checkbox is a sibling of .nav, so `:checked ~ .nav` flips its
   transform — no JS, CSP-safe. */
.mobile-nav-toggle  { position: absolute; opacity: 0; pointer-events: none; }
.mobile-nav-btn     { display: none; }
.mobile-nav-overlay { display: none; }

@media (max-width: 880px) {
  .site-header__inner {
    position: relative;
    height: 56px;
    gap: 8px;
    padding: 0 16px;
  }

  /* Burger button — three bars in a 44×44 hit area; margin-left:auto
     pins it to the row's right edge regardless of nav-item count. */
  .mobile-nav-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    margin-left: auto;
    border-radius: 12px;
    cursor: pointer;
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid var(--border-soft);
    transition: background 160ms ease, border-color 160ms ease;
    z-index: 110;
  }
  .mobile-nav-btn:hover,
  .mobile-nav-btn:focus-within { background: rgba(255, 255, 255, 0.08); border-color: var(--border-hot); }

  .mobile-nav-btn__bars {
    display: inline-flex;
    flex-direction: column;
    gap: 4px;
    width: 18px;
  }
  .mobile-nav-btn__bars > span {
    display: block;
    width: 100%;
    height: 2px;
    background: var(--paper);
    border-radius: 2px;
    transition: transform 200ms ease, opacity 160ms ease;
    transform-origin: center;
  }
  /* Animate burger → ✕ when drawer opens. */
  .mobile-nav-toggle:checked ~ .mobile-nav-btn .mobile-nav-btn__bars > span:nth-child(1) {
    transform: translateY(6px) rotate(45deg);
  }
  .mobile-nav-toggle:checked ~ .mobile-nav-btn .mobile-nav-btn__bars > span:nth-child(2) {
    opacity: 0;
  }
  .mobile-nav-toggle:checked ~ .mobile-nav-btn .mobile-nav-btn__bars > span:nth-child(3) {
    transform: translateY(-6px) rotate(-45deg);
  }

  /* Click-to-close overlay behind the drawer. opacity 0 + pointer-events
     none when closed so it doesn't catch taps. */
  .mobile-nav-overlay {
    display: block;
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.55);
    backdrop-filter: blur(2px);
    -webkit-backdrop-filter: blur(2px);
    opacity: 0;
    pointer-events: none;
    transition: opacity 220ms ease;
    z-index: 99;
  }
  .mobile-nav-toggle:checked ~ .mobile-nav-overlay {
    opacity: 1;
    pointer-events: auto;
  }

  /* The drawer itself — off-canvas right, slides in. .nav flips from row
     to full-height column. */
  .nav {
    position: fixed;
    top: 0;
    right: 0;
    width: min(82vw, 320px);
    height: 100dvh;
    flex-direction: column;
    align-items: stretch;
    justify-content: flex-start;
    gap: 6px;
    padding: 76px 20px max(24px, var(--safe-bottom));
    background: var(--ink-soft);
    border-left: 1px solid var(--border-soft);
    box-shadow: -16px 0 40px rgba(0, 0, 0, 0.4);
    transform: translateX(100%);
    transition: transform 260ms cubic-bezier(0.4, 0, 0.2, 1);
    z-index: 100;
    overflow-y: auto;
  }
  .mobile-nav-toggle:checked ~ .nav {
    transform: translateX(0);
  }

  /* Drawer nav links → full-width rows, bigger touch targets; active keeps
     its lavender wash. */
  .nav__link {
    display: flex;
    align-items: center;
    width: 100%;
    height: 44px;
    padding: 0 14px;
    font-size: 15px;
    border-radius: 10px;
  }
  .nav__sep {
    display: block;
    height: 1px;
    width: 100%;
    margin: 8px 0;
    background: var(--border-soft);
  }
  /* CTA "Get a key" sits at the bottom of the drawer with breathing room. */
  .nav__link--cta {
    margin-top: 8px;
    justify-content: center;
    font-weight: 600;
  }

  /* Lang switch — keep it compact at the bottom of the drawer. */
  .lang-switch {
    margin-top: auto;
    align-self: center;
  }

  /* Stop the body from scrolling when the drawer is open. */
  .mobile-nav-toggle:checked ~ .nav,
  .mobile-nav-toggle:checked ~ .mobile-nav-overlay { /* nothing extra; here for selector clarity */ }
}
html:has(.mobile-nav-toggle:checked) { overflow: hidden; }

/* ─── Nav — pill links, lavender active ────────────────────────────── */
.nav__link {
  border-radius: 999px;
  padding: 0 14px;
  font-weight: 500;
}
.nav__link:hover { background: rgba(255, 255, 255, 0.05); }
.nav__link--active {
  background: rgba(196, 169, 255, 0.12);
  color: var(--acid);
}
.nav__link--cta {
  background: var(--acid);
  color: #1A1A20;
  border-radius: 999px;
  padding: 0 16px;
}
.nav__link--cta:hover { background: var(--acid-dim); color: #1A1A20; }

/* Telegram-support link — nav lavender palette + inline paper-plane icon
   so it reads as an offsite action. */
.nav__link--support {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.nav__link--support svg {
  flex-shrink: 0;
  margin-top: -1px;
  opacity: 0.75;
  transition: opacity 160ms ease;
}
.nav__link--support:hover svg { opacity: 1; }

.nav__user {
  font-family: var(--font-body);
  font-weight: 500;
}

/* Lang switch — pill segmented control matching the nav pills. Overrides
   app.css's sharp 6px rect + loud solid-acid active state that made the
   toggle read louder than everything else in the header. */
.lang-switch {
  border-color: var(--border-soft);
  border-radius: 999px;
  height: 32px;
  padding: 2px;
  margin-left: 6px;
  align-items: stretch;
}
.lang-switch__btn {
  display: inline-flex;
  align-items: center;
  border-radius: 999px;
  padding: 0 10px;
  cursor: pointer;
  transition: background 160ms, color 160ms;
}
.lang-switch__btn--active {
  background: rgba(196, 169, 255, 0.12);
  color: var(--acid);
}
.lang-switch__btn:not(.lang-switch__btn--active):hover {
  background: rgba(255, 255, 255, 0.04);
  color: var(--paper);
}

/* ─── Models block — collapsible model list in a provider card.
   Pure <details>/<summary>, no JS. Closed by default (5-15 bindings each
   would over-stretch the page). Chevron flips on [open] via a sibling rule. */
.models-block > summary {
  list-style: none;
  cursor: pointer;
  user-select: none;
  padding: 4px 0;
}
.models-block > summary::-webkit-details-marker,
.models-block > summary::marker { display: none; }
.models-block__chev {
  display: inline-block;
  margin-right: 6px;
  color: var(--mute);
  transition: transform 120ms ease;
  font-family: var(--font-mono);
}
.models-block[open] > summary .models-block__chev { transform: rotate(90deg); }
.models-block > summary:hover .eyebrow { color: var(--paper); }

/* ─── Action menu — per-row dropdown for admin tables ──────────────
   Native <details>/<summary> for JS-free open/close (CSP-safe). Trigger
   looks like a .btn--ghost (disclosure triangle stripped); floating panel
   sits below-right, above the table via z-index. */
.actions-menu {
  display: inline-block;
  position: relative;
}
.actions-menu > summary {
  list-style: none;
  cursor: pointer;
  user-select: none;
}
.actions-menu > summary::-webkit-details-marker,
.actions-menu > summary::marker { display: none; }
.actions-menu[open] > summary {
  background: rgba(196, 169, 255, 0.10);
  color: var(--acid);
}
.actions-menu__panel {
  /* position:fixed — base.html JS sets top/left from the trigger's
     getBoundingClientRect() on open (and on scroll/resize while open).
     Fixed sidesteps every clip we hit: data-wrap rounding, cell overflow,
     sticky header, z-index battles. Today's usages (admin_users/_models)
     sit outside any .reveal wrapper, so the transform-containing-block
     hazard doesn't apply. z-index:100 keeps it above .site-header (30). */
  position: fixed;
  min-width: 200px;
  background: var(--surface-1);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
  padding: 4px;
  box-shadow: 0 12px 28px rgba(0, 0, 0, 0.5);
  z-index: 100;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.actions-menu__item {
  appearance: none;
  -webkit-appearance: none;
  border: 0;
  background: transparent;
  text-align: left;
  width: 100%;
  padding: 9px 12px;
  font-family: var(--font-mono);
  font-size: 12.5px;
  color: var(--paper-soft);
  cursor: pointer;
  border-radius: 6px;
  transition: background 140ms, color 140ms;
}
.actions-menu__item:hover {
  background: rgba(255, 255, 255, 0.04);
  color: var(--paper);
}
.actions-menu__item--danger { color: var(--rose); }
.actions-menu__item--danger:hover {
  background: rgba(248, 113, 113, 0.08);
  color: var(--rose);
}
.actions-menu form.inline { margin: 0; }

/* ─── Profile menu — header avatar dropdown ───────────────────────────
   Reuses the actions-menu portal logic on a different trigger: pill with
   avatar + login + chevron. csp-safe-init.js portals .actions-menu__panel
   into <body> while open so it rides above the sticky header. Mobile
   (≤720px) collapses the trigger to just the avatar bubble. */
.profile-menu > summary.profile-menu__btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 4px 10px 4px 4px;
  border-radius: 999px;
  border: 1px solid var(--border-soft);
  color: var(--paper-soft);
  background: transparent;
  font-family: var(--font-mono);
  font-size: 12.5px;
  line-height: 1;
  transition: background 140ms ease, border-color 140ms ease, color 140ms ease;
}
.profile-menu > summary.profile-menu__btn:hover {
  background: rgba(255, 255, 255, 0.04);
  border-color: var(--border);
  color: var(--paper);
}
/* Override: the .actions-menu[open] > summary lavender bg is meant for
   square admin-row buttons and looks wrong on this pill. */
.profile-menu[open] > summary.profile-menu__btn {
  background: rgba(196, 169, 255, 0.10);
  border-color: rgba(196, 169, 255, 0.32);
  color: var(--acid);
}

.profile-menu__avatar {
  width: 26px;
  height: 26px;
  border-radius: 999px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: rgba(196, 169, 255, 0.16);
  color: var(--acid);
  font-weight: 600;
  font-size: 12px;
  flex-shrink: 0;
  text-transform: uppercase;
  letter-spacing: 0;
}

.profile-menu__login {
  max-width: 140px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.profile-menu__caret {
  flex-shrink: 0;
  color: var(--mute);
  transition: transform 160ms ease, color 160ms ease;
}
.profile-menu[open] > summary.profile-menu__btn .profile-menu__caret {
  transform: rotate(-180deg);
  color: var(--acid);
}

/* Dropdown body. Drop the base .actions-menu__panel 4px padding so the
   identity header card bleeds to the edges and its separator looks clean. */
.profile-menu__panel {
  min-width: 244px;
  padding: 0;
  overflow: hidden;
  border-radius: 12px;
}

/* Identity header — Stripe-style account card at the top of the dropdown.
   Without it the trigger said "admin" then jumped straight to action links
   with no continuity. Gradient mirrors the trigger's [open] tint so they
   read as the same surface. */
.profile-menu__header {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 14px;
  background: linear-gradient(180deg, rgba(196, 169, 255, 0.08), transparent 90%);
  border-bottom: 1px solid var(--border-soft);
}
.profile-menu__avatar--lg {
  width: 36px;
  height: 36px;
  font-size: 14px;
}
.profile-menu__identity {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
  overflow: hidden;
}
.profile-menu__identity-name {
  font-family: var(--font-mono);
  font-size: 13.5px;
  color: var(--paper);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.profile-menu__identity-role {
  font-family: var(--font-mono);
  font-size: 10.5px;
  color: var(--mute);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* Item groups. The panel is portaled into <body> on open, stripping its
   .profile-menu ancestor — so anchor items would lay out inline. Pin every
   selector here to a class that travels with the portaled element
   (.profile-menu__panel / .profile-menu__items) so styles survive the move. */
.profile-menu__items {
  display: flex;
  flex-direction: column;
  padding: 4px;
}

/* Anchor reset — the UA `a { text-decoration: underline }` wins over
   .actions-menu__item (which never sets it). Force link states to tokens. */
.profile-menu__panel a.actions-menu__item,
.profile-menu__panel a.actions-menu__item:link,
.profile-menu__panel a.actions-menu__item:visited {
  text-decoration: none;
  color: var(--paper-soft);
  font-family: var(--font-mono);
  display: block;
}
.profile-menu__panel a.actions-menu__item:hover,
.profile-menu__panel a.actions-menu__item:focus,
.profile-menu__panel a.actions-menu__item:focus-visible {
  text-decoration: none;
  color: var(--paper);
  outline: none;
}

/* Items breathe more here than in admin tables (no cell heights to match).
   Selector pinned to the portaled root. */
.profile-menu__panel .actions-menu__item {
  padding: 10px 14px;
  font-size: 13px;
  border-radius: 8px;
}

.profile-menu__sep {
  border: 0;
  border-top: 1px solid var(--border-soft);
  margin: 0;
  height: 0;
}

@media (max-width: 720px) {
  .profile-menu__login { display: none; }
  .profile-menu > summary.profile-menu__btn { padding: 3px; }
}

/* ─── Auth tabs — CSS-only segmented control on /login ──────────────
   Two hidden radios drive `:checked ~ panel` to flip the visible form (no
   JS, CSP-safe). Labels look like paired pill nav-buttons; active borrows
   the lavender soft-tint (.nav__link--active, .actions-menu). */
.auth-tabs__radio {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}
.auth-tabs {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 4px;
  margin-top: 22px;
  padding: 4px;
  background: rgba(255, 255, 255, 0.02);
  border: 1px solid var(--border-soft);
  border-radius: 999px;
}
.auth-tabs__btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 10px 16px;
  font-family: var(--font-body);
  font-size: 13.5px;
  font-weight: 500;
  color: var(--mute);
  background: transparent;
  border-radius: 999px;
  cursor: pointer;
  user-select: none;
  transition: background 160ms, color 160ms;
}
.auth-tabs__btn:hover {
  color: var(--paper-soft);
}
.auth-tabs__btn svg {
  flex-shrink: 0;
  opacity: 0.7;
  transition: opacity 160ms;
}
#auth-tab-email:checked ~ .auth-tabs .auth-tabs__btn--email,
#auth-tab-password:checked ~ .auth-tabs .auth-tabs__btn--password {
  background: rgba(196, 169, 255, 0.14);
  color: var(--acid);
}
#auth-tab-email:checked ~ .auth-tabs .auth-tabs__btn--email svg,
#auth-tab-password:checked ~ .auth-tabs .auth-tabs__btn--password svg {
  opacity: 1;
}

.auth-tabs__panel {
  display: none;
  margin-top: 22px;
}
#auth-tab-email:checked ~ .auth-tabs__panel--email,
#auth-tab-password:checked ~ .auth-tabs__panel--password {
  display: block;
}

/* "Sent to {email}" header replacing the email-entry form after the
   magic-link POST. Dashed-rule envelope, lavender accent on the <code> addr. */
.auth-card__sent {
  padding: 14px 16px;
  background: rgba(196, 169, 255, 0.06);
  border: 1px solid rgba(196, 169, 255, 0.18);
  border-radius: var(--radius);
}
/* Inline hint below an input — small, mute, mono. */
.auth-card__hint {
  margin: 8px 0 0;
  font-family: var(--font-mono);
  font-size: 11.5px;
  color: var(--mute);
  line-height: 1.5;
}

/* Big 6-digit code input — centered, wide-spaced mono so it reads as a
   one-time-code field. autocomplete="one-time-code" auto-fills on iOS/Android. */
.code-input {
  text-align: center;
  font-size: 22px;
  font-weight: 600;
  letter-spacing: 0.28em;
  padding: 14px 12px;
}
.code-input::placeholder {
  color: var(--mute-soft);
  letter-spacing: 0.28em;
}

/* ─── Footer — minimal, single-row ─────────────────────────────────── */
.site-footer {
  /* `auto` keeps app.css's sticky-footer behaviour (body flex col + main
     flex:1): footer hugs the viewport bottom on short pages, collapses to 0
     on long ones. Gap above is owned by padding-top so it survives both. */
  margin-top: auto;
  /* Bottom padding folds in the iOS home-indicator inset; desktop
     --safe-bottom is 0px so the footer keeps its 28px. */
  padding: 80px 28px calc(28px + var(--safe-bottom));
  border-top: 1px solid var(--border-soft);
  font-family: var(--font-body);
  font-size: 13px;
  color: var(--mute);
}

/* ─── In Telegram WebView ─────────────────────────────────────────────
   In a TG WebApp sheet (TG provides its own close/back chrome, sheet height
   is precious): hide the public footer, tighten the header, widen .shell to
   the safe edges. Gated on body.in-tg (set by tg-webapp.js), so PC +
   standalone mobile stay untouched. */
.in-tg .site-footer { display: none !important; }
.in-tg .site-header {
  /* Tighten the header (TG already shows the page title) — frees ~36px,
     which matters on short Android sheets. */
  padding-top: max(8px, var(--safe-top)) !important;
  padding-bottom: 8px !important;
}
.in-tg main > .shell {
  padding-left:  max(16px, var(--safe-left));
  padding-right: max(16px, var(--safe-right));
}
.in-tg .ticker { display: none !important; }
.site-footer__inner {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
}
.site-footer__cols,
.site-footer__heading,
.site-footer__list { display: none !important; }
.site-footer__inner > div:first-child > div:last-child {
  color: var(--mute);
  font-family: var(--font-body);
}
.site-footer__legal {
  display: inline-flex;
  align-items: center;
  gap: 18px;
  font-family: var(--font-body);
  font-size: 13px;
  color: var(--mute);
}
.site-footer__legal a {
  color: var(--mute);
  text-decoration: none;
  transition: color 160ms ease;
}
.site-footer__legal a:hover { color: var(--paper); }

/* ─── Inputs — softer ──────────────────────────────────────────────── */
.input {
  height: 46px;
  border-radius: var(--radius);
  background: rgba(255, 255, 255, 0.025);
  border: 1px solid var(--border-soft);
  font-family: var(--font-body);
  font-size: 14.5px;
}
.input:focus {
  border-color: var(--acid);
  background: rgba(196, 169, 255, 0.04);
  box-shadow: 0 0 0 4px var(--acid-glow);
}

.field-label {
  font-family: var(--font-body);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  color: var(--mute);
}
.field-label::before { display: none; }

/* ─── Eyebrow — less aggressive ────────────────────────────────────── */
.eyebrow {
  font-family: var(--font-body);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.02em;
  text-transform: none;
  color: var(--mute);
}

/* ─── Pills / chips / tags ─────────────────────────────────────────── */
.pill {
  font-family: var(--font-body);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  padding: 6px 12px;
}
.chip {
  font-family: var(--font-body);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
}
.tag {
  font-family: var(--font-body);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  padding: 4px 10px;
}
.tag--image { background: rgba(244, 154, 194, 0.10); color: var(--magenta); border-color: rgba(244, 154, 194, 0.30); }
.tag--ok    { background: rgba(157, 213, 181, 0.12); color: var(--emerald); border-color: rgba(157, 213, 181, 0.30); }

/* ─── Hero title — drop the giant serif italic ─────────────────────── */
.hero__title {
  font-family: var(--font-body);
  font-weight: 700;
  font-style: normal;
  font-size: clamp(42px, 8vw, 88px);
  line-height: 1.05;
  letter-spacing: -0.028em;
}
.hero__title .it { font-style: normal; }
.hero__title .em {
  color: var(--acid);
  position: relative;
}
.hero__title .em::after { display: none; }
.hero__lede {
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.6;
}

.hero__num { display: none; }   /* hide editorial "§ 01 / GATEWAY" label */
.hero__stat-label { font-family: var(--font-body); font-weight: 500; font-size: 12px; letter-spacing: 0; text-transform: none; }

/* Hero stat numbers — 700→500 so they feel reportive, not brutalist
   (matches boba's light-display stat weight). */
.hero__stat-value {
  font-family: var(--font-body);
  font-weight: 500;
  font-style: normal;
  font-size: 32px;
  letter-spacing: -0.022em;
  color: var(--paper);
}
.hero__stat-value .small {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 13px;
  color: var(--mute);
}

/* Stats strip — softer card shell instead of edge-only borders. */
.hero__stats {
  margin-top: 48px;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-lg);
  background: var(--surface-1);
  overflow: hidden;
}
.hero__stat {
  border-right: 1px solid var(--border-soft);
}
.hero__stat:last-child { border-right: none; }

/* Pulsing dot before the leftmost stat (live latency) signals the number
   is measured live, not build-time. Updates every 5min via live_stats. */
.hero__stat-label {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.hero__stat-dot {
  display: inline-block;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--emerald);
  box-shadow: 0 0 0 0 rgba(157, 213, 181, 0.55);
  animation: hero-stat-dot-pulse 2.2s ease-out infinite;
}
@keyframes hero-stat-dot-pulse {
  0%   { box-shadow: 0 0 0 0 rgba(157, 213, 181, 0.55); }
  70%  { box-shadow: 0 0 0 7px rgba(157, 213, 181, 0); }
  100% { box-shadow: 0 0 0 0 rgba(157, 213, 181, 0); }
}
.hero__stat-pending {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 18px;
  color: var(--mute);
  letter-spacing: -0.005em;
}

/* ─── Landing hero — boba-mode centering + cat mascot card ──────────
   `.hero--boba` (index only) makes a centered flex-column with the mascot
   above the title. Inner pages keep the default left-aligned hero. */
.hero--boba {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding-top: 56px;
}
.hero--boba .hero__top {
  justify-content: center;
  margin-bottom: 22px;
}
.hero--boba .hero__title {
  text-align: center;
  max-width: 14ch;
}
.hero--boba .hero__lede {
  text-align: center;
  margin-left: auto;
  margin-right: auto;
}
.hero--boba .hero__cta {
  justify-content: center;
}
.hero--boba .hero__stats {
  width: 100%;
}

/* Referral teaser under the CTA. Brand lavender, but outline + tinted bg
   (not solid fill) so it steps below the CTA while staying on-brand. */
.hero__bonus-wrap {
  margin-top: 18px;
  text-align: center;
}
.hero__bonus {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 8px 16px;
  border-radius: 999px;
  background: rgba(196, 169, 255, 0.08);
  border: 1px solid rgba(196, 169, 255, 0.28);
  color: var(--acid);
  font-size: 13.5px;
  font-weight: 500;
  text-decoration: none;
  transition: background 160ms ease, border-color 160ms ease, transform 160ms ease;
}
.hero__bonus:hover {
  background: rgba(196, 169, 255, 0.14);
  border-color: rgba(196, 169, 255, 0.45);
  transform: translateY(-1px);
}
.hero__bonus-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--acid);
  flex-shrink: 0;
}

.hero__mascot {
  width: 96px;
  height: 96px;
  margin-bottom: 28px;
  border-radius: 22px;
  background: var(--acid);
  display: grid;
  place-items: center;
  box-shadow:
    0 18px 60px -16px rgba(196, 169, 255, 0.45),
    0 4px 14px -6px rgba(196, 169, 255, 0.30);
  transition: transform 0.3s var(--ease-out);
}
.hero__mascot:hover {
  transform: rotate(-3deg) translateY(-2px);
}
.hero__mascot svg,
.hero__mascot img {
  width: 80px;
  height: 80px;
  object-fit: contain;
  display: block;
}

/* ─── Invites grid — two columns on desktop, stack on mobile ──────── */
.invites-grid {
  display: grid;
  grid-template-columns: 1.5fr 1fr;
  gap: 28px;
}
@media (max-width: 720px) {
  .invites-grid {
    grid-template-columns: 1fr;
    gap: 18px;
  }
  /* Stat sidebar (two cards) is the desktop right column; on mobile it
     goes 2-col then 1-col below. */
  .invites-grid > div:last-child {
    grid-template-columns: 1fr 1fr;
    display: grid;
    gap: 12px !important;
  }
}
@media (max-width: 480px) {
  .invites-grid > div:last-child {
    grid-template-columns: 1fr;
  }
}

/* Mobile copybox — the referral link wrapped letter-by-letter into a thin
   column (grid vs long URL fighting for width). Stack vertically: full-width
   link box over full-width copy button. */
@media (max-width: 480px) {
  .copybox {
    flex-direction: column;
    align-items: stretch;
  }
  .copybox .text {
    word-break: break-all;
    overflow-wrap: anywhere;
    font-size: 12px;
  }
  .copybox .btn { width: 100%; }
}

/* ─── Page headings — keep big but lose the editorial italic ──────── */
.page-h1 {
  font-family: var(--font-body) !important;
  font-style: normal !important;
  font-weight: 700;
  letter-spacing: -0.025em;
  /* Long Russian compounds at 56px clipped the right edge. clamp drops to
     28px on narrow phones; hyphens lets the browser split where a clip
     would be worse. */
  font-size: clamp(28px, 9vw, 56px);
  line-height: 1.04;
  word-break: break-word;
  overflow-wrap: anywhere;
  hyphens: auto;
}
.page-sub {
  font-family: var(--font-body);
  color: var(--paper-soft);
  /* Same overflow safety for sub-headlines (clipped at the same width). */
  overflow-wrap: anywhere;
  word-break: break-word;
}

/* `.it` is the emphasis mark across hero/page/numcard headings, once italic
   Instrument Serif. Drop the italic, tint lavender — still reads as accent. */
.it {
  font-style: normal !important;
  color: var(--acid);
}

/* ─── Pull-quote — restrained sans, lavender bar ───────────────────── */
.pullquote {
  font-family: var(--font-body);
  font-style: normal;
  font-weight: 500;
  font-size: clamp(22px, 3vw, 32px);
  line-height: 1.3;
  letter-spacing: -0.012em;
  border-left: 3px solid var(--acid);
  padding-left: 22px;
}
.pullquote .quotemark { display: none; }

/* ─── Numcard — drop italic ────────────────────────────────────────── */
.numcard {
  background: var(--surface-1);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-lg);
}
.numcard__no {
  font-family: var(--font-body);
  font-weight: 800;
  font-style: normal;
  font-size: 28px;
  color: var(--faint);
}
.numcard__title {
  font-family: var(--font-body);
  font-weight: 600;
  font-style: normal;
  font-size: 18px;
  letter-spacing: -0.012em;
}
.numcard__body { font-size: 14px; }

/* ─── Data table ───────────────────────────────────────────────────── */
.data-wrap {
  border-radius: var(--radius-lg);
  background: var(--surface-1);
}
.data-table thead th {
  font-family: var(--font-body);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: none;
  color: var(--mute);
}
.data-table tbody tr:hover { background: rgba(196, 169, 255, 0.04); }

.data-table__id   { font-family: var(--font-mono); font-size: 12.5px; }
.data-table__meta { font-family: var(--font-body); font-size: 12.5px; color: var(--mute); }

/* Compact variant for dense admin lists (e.g. /admin/models) — tighter
   rows + narrow action column so buttons don't wrap. */
.data-table--compact thead th,
.data-table--compact tbody td {
  padding-top: 8px;
  padding-bottom: 8px;
}
.data-table--compact tbody tr + tr td { border-top: 1px solid var(--border-soft); }

/* ─── Stat / hero numbers ──────────────────────────────────────────── */
.stat-big {
  font-family: var(--font-body) !important;
  font-style: normal !important;
  font-weight: 700;
  letter-spacing: -0.02em;
}

/* ─── Code blocks — kept mono, softer borders ──────────────────────── */
pre.code-block, .code-card {
  border-radius: var(--radius);
  border-color: var(--border-soft);
}

/* ─── Selection ────────────────────────────────────────────────────── */
::selection { background: var(--acid); color: #1A1A20; }

/* ─── Plan cards (billing) — pill-shaped buttons inside, soft borders */
.plan-card {
  background: var(--surface-1);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-lg);
}
.plan-card--featured {
  border-color: rgba(196, 169, 255, 0.40);
}

/* ─── Chat sidebar / main — already soft, just unify radii ─────────── */
.chat-side,
.chat-main {
  background: var(--surface-1);
  border-color: var(--border-soft);
  border-radius: var(--radius-lg);
}
.chat-msg--user {
  background: rgba(196, 169, 255, 0.10);
  border-color: rgba(196, 169, 255, 0.22);
}
.chat-msg--asst {
  background: rgba(255, 255, 255, 0.025);
}
.chat-toolbar select {
  border-radius: 8px;
}

/* ─── Provider picker (billing) — softer ──────────────────────────── */
.provider-pick {
  border-radius: var(--radius);
}
.provider-pick__name {
  font-family: var(--font-body);
  font-weight: 600;
}

/* ─── Misc cleanups: places using --font-display directly ─────────── */
[style*="--font-display"] {
  font-family: var(--font-display) !important;
  font-style: normal !important;
}

/* ─── Alerts ────────────────────────────────────────────────────── */
.alert-ok,
.alert-error {
  border-radius: var(--radius);
}

/* Editorial § markers hidden globally (noise); titles still render via
   .section-rule__title. */
.section-rule__num { display: none; }

/* ─── Legal pages (Terms / Privacy) ─────────────────────────────────
   Read-only docs — narrow column, generous line-height, muted hierarchy,
   no grids/cards. */
.legal {
  max-width: 720px;
  margin: 48px auto 80px;
  padding: 0 4px;
}
.legal__head {
  padding-bottom: 22px;
  margin-bottom: 8px;
  border-bottom: 1px solid var(--border-soft);
}
.legal__head .page-h1 {
  margin: 12px 0 8px;
}
.legal__head .page-sub {
  color: var(--mute);
  font-size: 13.5px;
}
.legal__section {
  padding: 18px 0;
  border-bottom: 1px dashed var(--border-soft);
}
.legal__section:last-child {
  border-bottom: none;
}
.legal__h2 {
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 17px;
  letter-spacing: -0.01em;
  color: var(--paper);
  margin: 0 0 12px;
}
.legal p {
  margin: 0 0 12px;
  color: var(--paper-soft);
  font-size: 14.5px;
  line-height: 1.7;
}
.legal p:last-child {
  margin-bottom: 0;
}
.legal a {
  color: var(--acid);
  text-decoration: underline;
  text-decoration-color: rgba(196, 169, 255, 0.4);
  text-underline-offset: 2px;
}
.legal a:hover {
  text-decoration-color: var(--acid);
}
.legal strong {
  color: var(--paper);
  font-weight: 600;
}
.legal__list {
  margin: 0 0 12px;
  padding: 0;
  list-style: none;
}
.legal__list li {
  position: relative;
  padding: 6px 0 6px 22px;
  color: var(--paper-soft);
  font-size: 14.5px;
  line-height: 1.65;
}
.legal__list li::before {
  content: "";
  position: absolute;
  left: 4px;
  top: 14px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--acid);
  opacity: 0.6;
}

/* ─── Auth pages (login / register) — Boba-style centered card ────
   The page drops header/footer/ticker (block overrides in login/register
   .html). Left: one floating card centered + a "Back" pill top-left. */
body.page-auth main {
  padding: 0;
}
body.page-auth main .shell {
  max-width: none;
  margin: 0;
  padding: 0;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
}

.auth-back {
  position: fixed;
  top: 22px;
  left: 22px;
  z-index: 10;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 9px 16px 9px 12px;
  border-radius: 999px;
  background: rgba(30, 30, 38, 0.7);
  border: 1px solid var(--border-soft);
  color: var(--paper-soft);
  font-family: var(--font-body);
  font-size: 13px;
  font-weight: 500;
  text-decoration: none;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  transition: background 180ms ease, border-color 180ms ease, color 180ms ease;
}
.auth-back:hover {
  background: rgba(40, 40, 50, 0.85);
  border-color: var(--border-hot);
  color: var(--paper);
}
.auth-back svg {
  flex: 0 0 auto;
}

.auth-card {
  width: 100%;
  max-width: 420px;
  margin: 48px auto;
  padding: 36px 32px 28px;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-xl);
  background: var(--surface-1);
  text-align: center;
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.02) inset,
    0 20px 60px -20px rgba(0, 0, 0, 0.55);
}

.auth-card__logo {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 72px;
  height: 72px;
  margin: 0 auto 18px;
  border-radius: 22px;
  background: var(--acid);
  box-shadow: 0 8px 32px -8px var(--acid-glow);
}
.auth-card__logo svg,
.auth-card__logo img {
  width: 56px;
  height: 56px;
  object-fit: contain;
  display: block;
}

/* Resend block on the email code-step (below the code form). Own small
   Turnstile widget + a ghost button whose label flips "Resend in 1:43" →
   "Resend the code" on JS countdown. Kept quiet so the "Sign in" CTA leads. */
.auth-resend {
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px dashed var(--border-soft);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
}
.auth-resend__form {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  width: 100%;
}
.auth-resend__captcha {
  display: flex;
  justify-content: center;
}
.auth-resend__btn {
  height: 34px;
  padding: 0 16px;
  border-radius: 999px;
  font-size: 12.5px;
  font-weight: 500;
  letter-spacing: -0.005em;
  color: var(--paper-soft);
  background: transparent;
  border: 1px solid var(--border-soft);
  cursor: pointer;
  transition: color 140ms, border-color 140ms, background 140ms;
}
.auth-resend__btn:hover:not(:disabled) {
  color: var(--acid);
  border-color: rgba(196, 169, 255, 0.36);
  background: rgba(196, 169, 255, 0.06);
}
.auth-resend__btn:disabled {
  cursor: not-allowed;
  opacity: 0.55;
  font-family: var(--font-mono);
  font-size: 11.5px;
  letter-spacing: 0.02em;
}

.auth-card__title {
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 22px;
  line-height: 1.2;
  letter-spacing: -0.02em;
  color: var(--paper);
  margin: 0;
}

.auth-card__form {
  display: flex;
  flex-direction: column;
  gap: 16px;
  margin-top: 24px;
  text-align: left;
}

.auth-card__field {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.auth-card__field .input {
  width: 100%;
}

.auth-card__hint {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--mute-soft);
  letter-spacing: 0.02em;
}

.auth-card__submit {
  width: 100%;
  height: 48px;
  justify-content: center;
  font-size: 15px;
  font-weight: 600;
  margin-top: 4px;
}

.auth-card__alt {
  margin: 18px 0 0;
  font-size: 13px;
  color: var(--mute);
  text-align: center;
}
.auth-card__alt a {
  color: var(--acid);
  font-weight: 600;
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: border-color 160ms ease;
}
.auth-card__alt a:hover {
  border-bottom-color: var(--acid);
}

.auth-card__tos {
  margin: 18px -4px 0;
  font-size: 11px;
  line-height: 1.55;
  color: var(--mute-soft);
  text-align: center;
}
.auth-card__tos a {
  color: var(--mute);
  text-decoration: underline;
  text-decoration-color: rgba(196, 169, 255, 0.35);
  text-underline-offset: 2px;
}
.auth-card__tos a:hover {
  color: var(--paper-soft);
}

.auth-card__referral {
  margin-top: 18px;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 12px;
  border-radius: 999px;
  background: rgba(142, 213, 220, 0.08);
  border: 1px solid rgba(142, 213, 220, 0.28);
  color: var(--cyan);
  font-size: 12px;
  font-weight: 500;
}
.auth-card__referral .pill__dot {
  background: var(--cyan);
}

.auth-foot {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 22px;
  text-align: center;
  font-size: 12.5px;
  color: var(--mute-soft);
  pointer-events: none;
}
.auth-foot a,
.auth-foot span {
  display: inline-block;
  margin: 0 12px;
  pointer-events: auto;
}
.auth-foot a {
  color: var(--mute);
  text-decoration: none;
}
.auth-foot a:hover {
  color: var(--paper-soft);
}

@media (max-width: 560px) {
  .auth-back {
    top: 14px;
    left: 14px;
    padding: 7px 12px 7px 10px;
    font-size: 12px;
  }
  .auth-card {
    margin: 80px 16px 80px;
    padding: 28px 22px 22px;
  }
  .auth-card__title {
    font-size: 20px;
  }
  .auth-foot {
    bottom: 14px;
  }
}

/* ─── Language swap transition ─────────────────────────────────────
   While lang-switch.js fetches + swaps <main>/<nav>/<footer>, briefly fade
   main+footer so it's not jarring. The switcher stays opaque so you see
   which button you pressed. */
body.lang-swapping main,
body.lang-swapping .site-footer {
  transition: opacity 140ms ease;
  opacity: 0.55;
  pointer-events: none;
}

/* ─── Provider viewer (landing) ────────────────────────────────────
   Replaces the dense "models & pricing" table on /. Three tabs (logo+name)
   over a panel listing the provider's model IDs. No prices/type tags —
   pricing lives behind auth in /panel. */
[x-cloak] { display: none !important; }

.provider-viewer {
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-lg);
  background: var(--surface-1);
  overflow: hidden;
}

.provider-tabs {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  border-bottom: 1px solid var(--border-soft);
  background: rgba(255, 255, 255, 0.012);
}

.provider-tab {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: 22px 18px;
  background: transparent;
  border: 0;
  border-right: 1px solid var(--border-soft);
  color: var(--mute);
  font-family: var(--font-body);
  font-size: 15px;
  font-weight: 500;
  cursor: pointer;
  transition: color 160ms ease, background 160ms ease;
  position: relative;
}
.provider-tab:last-child { border-right: 0; }
.provider-tab:hover { color: var(--paper-soft); background: rgba(255, 255, 255, 0.02); }
.provider-tab:focus-visible {
  outline: 2px solid var(--acid-glow);
  outline-offset: -2px;
}

.provider-tab--active {
  color: var(--paper);
  background: rgba(196, 169, 255, 0.06);
}
.provider-tab--active::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 2px;
  background: var(--acid);
}

.provider-tab__logo {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  color: var(--mute);
  transition: color 160ms ease;
}
.provider-tab__logo svg {
  width: 100%;
  height: 100%;
}
.provider-tab--active .provider-tab__logo--openai    { color: #FFFFFF; }
.provider-tab--active .provider-tab__logo--anthropic { color: #D97757; }
.provider-tab--active .provider-tab__logo--gemini    { color: #8BB8FF; }

.provider-tab__name {
  letter-spacing: -0.01em;
}

.provider-panel {
  padding: 22px 22px 26px;
}

/* Alpine x-transition enter classes for the whole panel. The wrapping
   <template x-if> remounts it on each `tab` change, restarting the
   per-card staggered fade-in. */
.provider-panel--enter {
  transition: opacity 240ms ease, transform 240ms ease;
}
.provider-panel--enter-start {
  opacity: 0;
  transform: translateY(6px);
}
.provider-panel--enter-end {
  opacity: 1;
  transform: translateY(0);
}

.model-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 12px;
}

/* Each card fades up, :nth-child-staggered so rows arrive like a wave. */
.model-card {
  position: relative;
  padding: 16px 18px 14px;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
  background: rgba(255, 255, 255, 0.012);
  transition: transform 200ms ease, border-color 200ms ease, background 200ms ease;
  animation: model-card-in 360ms cubic-bezier(0.22, 1, 0.36, 1) both;
  will-change: transform, opacity;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.model-card:hover {
  transform: translateY(-2px);
  border-color: rgba(196, 169, 255, 0.32);
  background: rgba(196, 169, 255, 0.04);
}

/* Head row holds the model name; right-padding reserves space for the
   corner online dot. ×N chip lives in the meta block so the name breathes. */
.model-card__head-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding-right: 18px;
  min-width: 0;
}
.model-card__name {
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 14.5px;
  line-height: 1.2;
  color: var(--paper);
  letter-spacing: -0.01em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}

/* Meta block — two stacked "label: value" rows (rate, vs-API) between name
   and id/copy row. Value is the bright chip (coloured mult / emerald
   discount) so the eye picks it out. */
.model-card__meta {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.model-card__meta-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  font-family: var(--font-mono);
  font-size: 11.5px;
  letter-spacing: 0.02em;
}
.model-card__meta-label {
  color: var(--mute);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-size: 10.5px;
}

/* Token-rate multiplier chip — debit rate for THIS model vs the cheapest
   text model (baseline ×1). Colour-ramped to flag premium burners:
   cheap ×<1 green; base ×1-2 neutral; mid ×2-5 amber; high ×5-10 peach;
   premium ×10+ magenta; image = muted lavender (no per-token rate). */
.model-card__mult {
  flex-shrink: 0;
  font-family: var(--font-mono);
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: 0.01em;
  color: var(--paper);
  padding: 3px 9px;
  border: 1px solid var(--border-soft);
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.04);
  white-space: nowrap;
  line-height: 1.2;
}

.model-card__mult--cheap {
  color: var(--emerald);
  border-color: rgba(157, 213, 181, 0.45);
  background: rgba(157, 213, 181, 0.12);
}
.model-card__mult--base {
  color: var(--paper);
  border-color: rgba(196, 169, 255, 0.35);
  background: rgba(196, 169, 255, 0.08);
}
.model-card__mult--mid {
  color: #F4D58D;
  border-color: rgba(244, 213, 141, 0.42);
  background: rgba(244, 213, 141, 0.10);
}
.model-card__mult--high {
  color: #F49AC2;
  border-color: rgba(244, 154, 194, 0.45);
  background: rgba(244, 154, 194, 0.12);
}
.model-card__mult--premium {
  color: #FF7DAA;
  border-color: rgba(255, 125, 170, 0.55);
  background: rgba(255, 125, 170, 0.16);
  text-shadow: 0 0 8px rgba(255, 125, 170, 0.25);
}
.model-card__mult--image {
  color: var(--mute);
  font-style: italic;
  letter-spacing: 0.04em;
}

/* Emerald percent in the "vs API" meta row. Standalone class so it's
   reusable without the old savings flexbox. */
.model-card__savings-value {
  font-weight: 700;
  color: var(--emerald);
}

.model-card__id-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding-top: 8px;
  border-top: 1px dashed var(--border-soft);
}
.model-card__id {
  flex: 1;
  min-width: 0;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--mute);
  letter-spacing: -0.005em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  user-select: all;
}

/* Copy button — square mono affordance. Two stacked SVG icons swap via
   .is-copied (set briefly by the inline click handler). */
.model-card__copy {
  position: relative;
  width: 26px;
  height: 26px;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 1px solid var(--border-soft);
  border-radius: 7px;
  background: rgba(255, 255, 255, 0.02);
  color: var(--mute);
  cursor: pointer;
  transition: color 160ms ease, border-color 160ms ease, background 160ms ease;
}
.model-card__copy:hover {
  color: var(--paper);
  border-color: rgba(196, 169, 255, 0.45);
  background: rgba(196, 169, 255, 0.08);
}
.model-card__copy:focus-visible {
  outline: 2px solid rgba(196, 169, 255, 0.55);
  outline-offset: 2px;
}
.model-card__copy-icon {
  position: absolute;
  width: 14px;
  height: 14px;
  transition: opacity 160ms ease, transform 160ms ease;
}
.model-card__copy-icon--done {
  opacity: 0;
  transform: scale(0.7);
  color: var(--emerald);
}
.model-card__copy.is-copied {
  color: var(--emerald);
  border-color: rgba(157, 213, 181, 0.45);
  background: rgba(157, 213, 181, 0.08);
}
.model-card__copy.is-copied .model-card__copy-icon--idle {
  opacity: 0;
  transform: scale(0.7);
}
.model-card__copy.is-copied .model-card__copy-icon--done {
  opacity: 1;
  transform: scale(1);
}

/* Top-right pulsing emerald dot (matches hero stat dot) — signals "this
   model is callable right now". */
.model-card__online {
  position: absolute;
  top: 16px;
  right: 16px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--emerald);
  box-shadow: 0 0 0 0 rgba(157, 213, 181, 0.55);
  animation: model-card-online-pulse 2.4s ease-out infinite;
}
@keyframes model-card-online-pulse {
  0%   { box-shadow: 0 0 0 0 rgba(157, 213, 181, 0.55); }
  70%  { box-shadow: 0 0 0 6px rgba(157, 213, 181, 0); }
  100% { box-shadow: 0 0 0 0 rgba(157, 213, 181, 0); }
}

@keyframes model-card-in {
  0% {
    opacity: 0;
    transform: translateY(10px) scale(0.985);
  }
  100% {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

/* Staggered delays — fixed schedule (not inline var(--i)) to keep the
   template clean; capped after the 10th card so big rosters don't trail in. */
.model-card:nth-child(1)  { animation-delay:  20ms; }
.model-card:nth-child(2)  { animation-delay:  60ms; }
.model-card:nth-child(3)  { animation-delay: 100ms; }
.model-card:nth-child(4)  { animation-delay: 140ms; }
.model-card:nth-child(5)  { animation-delay: 180ms; }
.model-card:nth-child(6)  { animation-delay: 220ms; }
.model-card:nth-child(7)  { animation-delay: 260ms; }
.model-card:nth-child(8)  { animation-delay: 300ms; }
.model-card:nth-child(9)  { animation-delay: 340ms; }
.model-card:nth-child(n+10) { animation-delay: 380ms; }

/* Respect reduced-motion users — no slide, no stagger, just instant. */
@media (prefers-reduced-motion: reduce) {
  .model-card,
  .provider-panel--enter {
    animation: none !important;
    transition: none !important;
  }
  .model-card__online {
    animation: none;
  }
}

@media (max-width: 640px) {
  .provider-tab {
    padding: 16px 10px;
    font-size: 13px;
    gap: 8px;
  }
  .provider-tab__logo {
    width: 18px;
    height: 18px;
  }
  .provider-panel {
    padding: 16px 14px 20px;
  }
  .model-grid {
    grid-template-columns: 1fr;
    gap: 10px;
  }
}

/* ──────────────────────────────────────────────────────────────────
   Mobile responsive — landing focus. Two breakpoints on top of the
   existing 560/640/760/880:
   • ≤720px (tablet portrait + larger phones) — tighten shell/header/footer
     padding, drop hero top padding so the mascot is visible on first paint,
     trim code-card chrome.
   • ≤480px (phones 320–414) — Support label → icon-only, drop the `·moe`
     brand half, shrink mascot, tighten code-card, let footer legal wrap.
   Kept in the theme layer (not app.css) to override editorial defaults. ── */

@media (max-width: 720px) {
  .shell { padding: 0 20px; }

  .site-header__inner { padding: 0 16px; height: 56px; gap: 12px; }
  .site-footer { padding: 32px 20px 48px; }

  .hero--boba { padding-top: 32px; }
  .hero { padding: 32px 0 16px; }
  .hero__lede { margin-top: 22px; }
  .hero__cta { margin-top: 26px; }

  .code-card__head { padding: 10px 14px; }
  pre.code-block { padding: 14px 16px; font-size: 12.5px; }

  .pullquote { padding-left: 18px; font-size: clamp(20px, 4.4vw, 28px); }

  .section-rule { margin: 36px 0 18px; }
  .section-rule__title { font-size: 16px; }
}

@media (max-width: 480px) {
  .shell { padding: 0 16px; }

  .site-header__inner { padding: 0 12px; gap: 6px; }
  /* No nav rules here — at ≤880px nav is an off-canvas drawer (see
     "Hamburger drawer"). Only brand stays in the header row. */

  /* Brand mark signals the site — drop the trailing ".moe" text on the
     narrowest viewports so the header breathes. */
  .brand { gap: 8px; }
  .brand__mark { width: 32px; height: 32px; border-radius: 9px; }
  .brand__mark img,
  .brand__mark svg { width: 28px; height: 28px; }
  .brand__name { font-size: 15px; }
  .brand__name .ext { display: none; }
  .brand__name .dot { display: none; }

  .hero--boba { padding-top: 20px; }
  .hero__mascot { width: 80px; height: 80px; margin-bottom: 18px; border-radius: 18px; }
  .hero__mascot img,
  .hero__mascot svg { width: 64px; height: 64px; }
  .hero__lede { font-size: 15px; line-height: 1.55; margin-top: 18px; }
  .hero__cta { margin-top: 22px; }
  .hero__cta .btn { width: 100%; justify-content: center; }

  .code-card__head { padding: 9px 12px; }
  .code-card__title { font-size: 10px; letter-spacing: 0.14em; }
  pre.code-block { padding: 12px 14px; font-size: 12px; }

  .chip { padding: 6px 10px; font-size: 11px; letter-spacing: 0.06em; }
  .chip-grid { gap: 6px; margin-top: 18px; }

  .pullquote { padding-left: 14px; border-left-width: 2px; }

  .site-footer { padding: 24px 16px calc(36px + var(--safe-bottom)); }
  .site-footer__inner { flex-wrap: wrap; gap: 12px; }
  .site-footer__legal { flex-wrap: wrap; gap: 10px 14px; font-size: 10.5px; }
}

/* ─── Ultra-narrow viewports (iPhone SE / folded Galaxy / 320px) ──────
   Trim padding once more and wrap long mono tokens (API keys, model IDs)
   so they can't widen the column. break-word scoped to <pre>/<code> only;
   body copy wraps normally. */
@media (max-width: 360px) {
  .shell { padding: 0 12px; }

  pre, code {
    word-break: break-word;
    overflow-wrap: anywhere;
  }

  /* Tables scroll horizontally inside the card rather than blow out the page. */
  .keys-panel table,
  .usage-panel table,
  .tx-panel table { display: block; overflow-x: auto; }
}

/* ─── Terminal demo (landing) ───────────────────────────────────────
   Replaces the synthetic RPS feed. macOS-style terminal card; typewriter
   cycles 6 SDK snippets, one language at a time (JS in terminal-demo.js).
   Fixed body height prevents layout shift between languages; white-space:pre
   keeps typed indentation without word-wrap. */
.terminal-demo {
  margin: 22px 0 0;
}

.term {
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-lg);
  background: var(--surface-1);
  overflow: hidden;
}

.term__chrome {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px 18px;
  border-bottom: 1px solid var(--border-soft);
  background: var(--surface-2);
}
.term__dot {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  flex-shrink: 0;
}
.term__dot--r { background: #FF6058; }
.term__dot--y { background: #FFBD2E; }
.term__dot--g { background: #28C940; }
.term__label {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.18em;
  color: var(--mute);
  text-transform: uppercase;
}

.term__body {
  position: relative;
  margin: 0;
  padding: 22px 24px;
  font-family: var(--font-mono);
  font-size: 13px;
  line-height: 1.6;
  color: var(--paper-soft);
  background: var(--ink-soft);
  height: 380px;
  overflow: hidden;
  white-space: pre;
  word-break: normal;
}
.term__body code {
  display: block;
  white-space: pre;
  font: inherit;
  color: inherit;
}

.term__cursor {
  display: inline-block;
  width: 8px;
  height: 14px;
  margin-left: 2px;
  vertical-align: text-bottom;
  background: var(--paper);
  animation: term-cursor-blink 1s steps(2) infinite;
}
@keyframes term-cursor-blink {
  0%, 49%   { opacity: 1; }
  50%, 100% { opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .term__cursor { animation: none; opacity: 1; }
}

/* Line-level syntax tokens — one span per line, injected by the typewriter.
   Vocabulary mirrors the JS array's `type` field (terminal-demo.js). */
.tok-cmd     { color: var(--paper); }
.tok-user    { color: var(--paper); font-weight: 500; }
.tok-think   { color: var(--paper-soft); }
.tok-tool    { color: var(--acid); }
.tok-code    { color: var(--paper-soft); }
.tok-comment { color: var(--mute); font-style: italic; }
.tok-spin    { color: var(--magenta); }
.tok-fail    { color: var(--rose); }
.tok-ok      { color: var(--emerald); }

/* ─── Value pair (landing) ──────────────────────────────────────────
   Two equal cards under the terminal (boba palette: tokens icon --acid,
   pay icon --magenta). Stacks on narrow viewports. */
.pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 18px;
  margin-top: 18px;
}
.pair-card {
  padding: 24px 26px;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-lg);
  background: var(--surface-1);
}
.pair-card__icon {
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  border-radius: 12px;
  background: var(--surface-2);
  margin-bottom: 14px;
}
.pair-card__icon svg {
  width: 22px;
  height: 22px;
}
.pair-card--tokens .pair-card__icon svg { color: var(--acid); }
.pair-card--pay    .pair-card__icon svg { color: var(--magenta); }

.pair-card__title {
  font-family: var(--font-body);
  font-size: 16px;
  font-weight: 600;
  color: var(--paper);
  margin: 0;
  letter-spacing: -0.005em;
}
.pair-card__body {
  margin: 6px 0 0;
  font-family: var(--font-body);
  font-size: 13.5px;
  line-height: 1.6;
  color: var(--mute-soft);
}

@media (max-width: 760px) {
  .term__chrome { padding: 10px 14px; }
  .term__dot { width: 10px; height: 10px; }
  .term__label { font-size: 10px; }
  .term__body {
    padding: 16px 18px;
    font-size: 11.5px;
    height: 300px;
  }
  .pair { grid-template-columns: 1fr; gap: 14px; }
  .pair-card { padding: 20px 22px; }
}
