/* Docs theme chrome (SpeQA-inspired nav + footer). */
:root {
  --docs-nav-h: 64px;
  --docs-bg1: #ffffff;
  --docs-bg2: #f7f8fa;
  --docs-fg1: #0d1117;
  --docs-fg2: #4a5568;
  --docs-pri: #3b82f6;
  --docs-pri-hover: #2563eb;
  --docs-acc: #8b5cf6;
  --docs-brd: #e2e8f0;
  --docs-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
}
[data-theme="dark"] {
  --docs-bg1: #0d1117;
  --docs-bg2: #161b22;
  --docs-fg1: #f0f6fc;
  --docs-fg2: #8b949e;
  --docs-pri: #58a6ff;
  --docs-pri-hover: #79c0ff;
  --docs-acc: #a78bfa;
  --docs-brd: #30363d;
  --docs-shadow: 0 4px 20px rgba(0, 0, 0, 0.35);
}
body.docs-theme {
  padding-top: var(--docs-nav-h);
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}
.nav {
  position: fixed; top: 0; left: 0; right: 0; z-index: 100;
  background: var(--docs-bg1);
  border-bottom: 1px solid transparent;
  transition: border-color 0.2s ease, box-shadow 0.25s ease;
}
.nav.scrolled {
  border-color: var(--docs-brd);
  box-shadow: var(--docs-shadow);
}
.nav-inner {
  max-width: 1200px; margin: 0 auto;
  padding: 0 36px;
  height: var(--docs-nav-h);
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px;
}
@media (min-width: 1200px) { .nav-inner { max-width: 1400px; } }
.nav-left { display: flex; align-items: center; gap: var(--sp-3); min-width: 0; }
.nav-brand {
  display: flex; align-items: center; gap: 8px;
  font-weight: 800; font-size: 1.25rem;
  color: var(--docs-fg1); letter-spacing: -0.01em;
  text-decoration: none; white-space: nowrap;
  min-width: 0; overflow: hidden;
}
.nav-brand:hover { color: var(--docs-pri); text-decoration: none; }
.nav-brand .brand-logo { height: 1.75rem; width: auto; flex-shrink: 0; }
.nav-brand-name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.nav-links {
  display: flex; align-items: center; gap: 32px;
  margin-left: auto; margin-right: var(--sp-3);
}
/* With no header nav (empty `header:`), `.nav-links` is absent, so `.nav-inner`'s
   space-between would center the remaining items. Push the leftmost right-cluster
   member (actions if present, else search) to the right so search always sits next
   to the theme toggle, as it does when `.nav-links` supplies the margin-left:auto. */
.nav-inner:not(:has(.nav-links)) .nav-actions { margin-left: auto; }
.nav-inner:not(:has(.nav-links)):not(:has(.nav-actions)) .site-search { margin-left: auto; }
.nav-links a {
  font-size: 0.875rem; font-weight: 500;
  color: var(--docs-fg2); text-decoration: none;
  transition: color 0.2s ease; white-space: nowrap;
}
.nav-links a:hover { color: var(--docs-pri); text-decoration: none; }
.nav-links a[aria-current="page"] { color: var(--docs-fg1); font-weight: 600; }
/* Collapsible header search: magnifier stays put on the right; the input expands
   leftward as an absolute OVERLAY so it never reflows the other header elements. */
.site-search { position: relative; display: flex; align-items: center; flex-shrink: 0; }
.site-search-input {
  position: absolute; right: calc(100% + 6px); top: 50%; transform: translateY(-50%);
  appearance: none; -webkit-appearance: none;
  width: 0; min-width: 0; height: 34px; padding: 0; margin: 0;
  border: 1px solid var(--docs-brd); border-radius: 6px;
  background: var(--docs-bg1); color: var(--docs-fg1);
  font: inherit; font-size: 0.875rem;
  opacity: 0; pointer-events: none; z-index: 20;
  transition: width 0.22s ease, opacity 0.18s ease, padding 0.22s ease;
}
.site-search-input::-webkit-search-cancel-button { -webkit-appearance: none; }
.site-search.open .site-search-input {
  width: 240px; max-width: 42vw; padding: 0 10px;
  opacity: 1; pointer-events: auto; box-shadow: var(--docs-shadow);
}
.site-search-input:focus-visible { outline: none; border-color: var(--docs-pri); }
.search-toggle {
  flex-shrink: 0; width: 38px; height: 34px;
  background: transparent; border: 1px solid var(--docs-brd); border-radius: 6px;
  cursor: pointer; color: var(--docs-fg2);
  display: inline-flex; align-items: center; justify-content: center;
  transition: border-color 0.2s ease, color 0.2s ease;
}
.search-toggle:hover { border-color: var(--docs-pri); color: var(--docs-pri); }
.search-toggle svg { width: 18px; height: 18px; }
.docs-theme .theme-toggle {
  position: relative; flex-shrink: 0;
  width: 38px; height: 34px;
  background: transparent;
  border: 1px solid var(--docs-brd);
  border-radius: 6px;
  cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--docs-fg2);
  transition: border-color 0.2s ease, color 0.2s ease;
}
.docs-theme .theme-toggle:hover {
  border-color: var(--docs-pri);
  color: var(--docs-pri);
}
.docs-theme .theme-toggle svg {
  position: absolute; top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: 18px; height: 18px;
}
.docs-theme .theme-toggle .dark-icon { display: none; }
[data-theme="light"] .docs-theme .theme-toggle .light-icon { display: none; }
[data-theme="light"] .docs-theme .theme-toggle .dark-icon { display: block; }
html:not([data-theme]) .docs-theme .theme-toggle .light-icon { display: none; }
html:not([data-theme]) .docs-theme .theme-toggle .dark-icon { display: block; }
.footer-wrap {
  padding: 48px 0;
  background: var(--docs-bg2);
  border-top: 1px solid var(--docs-brd);
  font-size: 0.9rem;
  line-height: 1.6;
}
.footer-grid-layout {
  max-width: 1200px; margin: 0 auto;
  display: flex; justify-content: space-between;
  gap: 48px; padding: 0 36px;
  align-items: flex-start;
}
@media (min-width: 1200px) { .footer-grid-layout { max-width: 1400px; } }
.ftr-brand-box h4 {
  margin: 0 0 6px;
  font-size: 1.1rem; font-weight: 700;
  color: var(--docs-fg1);
}
.ftr-brand-box h4 a { color: inherit; text-decoration: none; }
.ftr-brand-box h4 a:hover { color: var(--docs-pri); }
.ftr-brand-box p {
  margin: 0;
  font-size: 0.85rem;
  color: var(--docs-fg2);
  line-height: 1.5;
}
.ftr-brand-box .site-description { margin-top: 4px; }
.ftr-copyright {
  margin-top: 12px !important;
  font-size: 0.8rem !important;
  color: var(--docs-fg2);
  opacity: 0.7;
}
.ftr-copyright a { color: inherit; text-decoration: underline; }
.ftr-lk-wrap {
  display: flex; flex-direction: column; gap: 8px;
}
.ftr-lk-wrap a {
  font-size: 0.85rem;
  color: var(--docs-fg2);
  text-decoration: none;
  transition: color 0.2s ease;
}
.ftr-lk-wrap a:hover { color: var(--docs-pri); }
.ftr-lk-wrap a[aria-current="page"] { color: var(--docs-fg1); font-weight: 600; }
@media (max-width: 960px) {
  .nav-inner { padding: 0 16px; }
  .nav-links { display: none; }
  .footer-grid-layout {
    flex-direction: column;
    gap: 24px;
    padding: 0 20px;
  }
  .footer-wrap { padding: 32px 0; }
  body.docs-theme {
    padding-top: var(--docs-nav-h);
    min-height: 100vh;
    display: flex;
    flex-direction: column;
  }
  .docs-theme .page-toc { top: 0; }
  /* Drawer opens BELOW the fixed header (header stays visible/clickable above it):
     full remaining height, first nav item never hidden under the bar. Height is
     explicit because the base rule's align-self:start makes this fixed grid child
     shrink to content instead of stretching between its top/bottom insets. */
  .docs-theme .sidebar {
    top: var(--docs-nav-h);
    height: calc(100vh - var(--docs-nav-h));
    height: calc(100dvh - var(--docs-nav-h));
  }
  /* Narrow header: github collapses to its icon; tighter clusters. With .nav-links
     display:none the :has(.nav-links) rules still match (the node stays in the DOM),
     so nothing supplies margin-left:auto - space-between would spread the right
     cluster across the bar. Pack it right explicitly. */
  /* NOTE: .nav-actions/.nav-btn base rules live LATER in this file (appended header-
     actions block) - equal-specificity media overrides here would lose; prefix with
     .nav-inner to outrank them. */
  .nav-inner { gap: 12px; }
  .nav-inner .nav-actions { gap: 10px; margin-left: auto; }
  .nav-inner:not(:has(.nav-actions)) .site-search { margin-left: auto; }
  .nav-github span { display: none; }
}
@media (max-width: 640px) {
  /* Phone: brand is logo-only (clean, instead of an ellipsized name), CTA compact;
     search stays - it collapses to an icon and expands as an overlay anyway.
     Shrink order: everything in the bar is fixed-size EXCEPT the CTA label, which
     ellipsizes last - without this, flex crushes the brand (the only min-width:0
     item) to zero width and the logo vanishes. */
  .nav-brand-name { display: none; }
  /* Both the brand AND its container: .nav-left's own min-width:0 otherwise shrinks
     around the logo and the actions group starts on top of it. */
  .nav-left { flex-shrink: 0; }
  .nav-brand { flex-shrink: 0; }
  .nav-inner { gap: 10px; padding: 0 12px; }
  /* The actions group is the ONLY shrinkable bar item (base rule pins it with
     flex-shrink:0, which would push the theme toggle off-screen); inside it the
     icons stay fixed and the CTA label ellipsizes last. .nav-inner prefix outranks
     the later-in-file base rules. */
  .nav-inner .nav-actions { flex-shrink: 1; min-width: 0; }
  .nav-inner .nav-github { flex-shrink: 0; }
  .nav-inner .nav-btn { padding: 7px 10px; font-size: 0.75rem; min-width: 0; }
  .nav-inner .nav-btn span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
}
@media (min-width: 961px) {
  .docs-theme .sidebar,
  .docs-theme .page-toc {
    top: calc(var(--docs-nav-h) + var(--sp-4));
  }
}
/* Design tokens (single source of truth for the docs template). */
:root {
  color-scheme: light;
  --fs-0: 0.8125rem; --fs-1: 0.9375rem; --fs-2: 1rem;
  --fs-3: 1.125rem; --fs-4: 1.25rem; --fs-5: 1.5rem;
  --fs-6: 1.875rem; --fs-7: 2.25rem;
  --lh-tight: 1.2; --lh-snug: 1.35; --lh-body: 1.65; --lh-relaxed: 1.75;
  --sp-1: 0.25rem; --sp-2: 0.5rem; --sp-3: 0.75rem; --sp-4: 1rem;
  --sp-5: 1.5rem; --sp-6: 2rem; --sp-7: 3rem;
  --r-sm: 4px; --r-md: 6px; --r-lg: 10px;
  --content-max: 760px; --sidebar-w: 260px; --rail-w: 220px;
  --ff-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Arial, sans-serif;
  --ff-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
  --c-bg: #ffffff;
  --c-bg-soft: #f7f8fa;
  --c-bg-sunken: #eef0f3;
  --c-text: #1a1d21;
  --c-text-muted: #5b6573;
  --c-text-subtle: #8a93a0;
  --c-border: #e3e6eb;
  --c-border-strong: #cdd2d9;
  --c-accent: #2257d1;
  --c-accent-hover: #1a47b3;
  --c-link: var(--c-accent);
  --c-link-hover: var(--c-accent-hover);
  --c-code-bg: #f3f4f6;
  --c-code-text: #1a1d21;
  --c-syntax-keyword: #cf222e;
  --c-syntax-string: #0a3069;
  --c-syntax-comment: #6e7781;
  --c-syntax-number: #0550ae;
  --c-syntax-name: #8250df;
  --c-syntax-attr: #116329;
  --c-quote-border: #cdd2d9;
  --c-quote-text: #4b5360;
  --c-chip-bg: #eef0f3;
  --c-chip-text: #4b5360;
  --c-active-bg: rgba(34, 87, 209, 0.10);
  --c-active-text: var(--c-accent);
  --c-shadow: 0 1px 2px rgba(15, 23, 42, 0.06), 0 4px 12px rgba(15, 23, 42, 0.04);
  --c-focus: #2257d1;
}
[data-theme="dark"] {
  color-scheme: dark;
  --c-bg: #0f1115;
  --c-bg-soft: #161a21;
  --c-bg-sunken: #1c2128;
  --c-text: #e6e8ec;
  --c-text-muted: #9aa3b2;
  --c-text-subtle: #6c7585;
  --c-border: #262c36;
  --c-border-strong: #364050;
  --c-accent: #6ea8ff;
  --c-accent-hover: #8fbeff;
  --c-link: var(--c-accent);
  --c-link-hover: var(--c-accent-hover);
  --c-code-bg: #161a21;
  --c-code-text: #e6e8ec;
  --c-syntax-keyword: #ff7b72;
  --c-syntax-string: #a5d6ff;
  --c-syntax-comment: #8b949e;
  --c-syntax-number: #79c0ff;
  --c-syntax-name: #d2a8ff;
  --c-syntax-attr: #7ee787;
  --c-quote-border: #364050;
  --c-quote-text: #9aa3b2;
  --c-chip-bg: #1c2128;
  --c-chip-text: #c2c9d4;
  --c-active-bg: rgba(110, 168, 255, 0.14);
  --c-active-text: var(--c-accent);
  --c-shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 4px 12px rgba(0, 0, 0, 0.25);
  --c-focus: #6ea8ff;
}
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; background: var(--c-bg); color: var(--c-text); }
html, body { scrollbar-color: var(--c-border-strong) var(--c-bg); }
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: var(--c-bg); }
::-webkit-scrollbar-thumb { background: var(--c-border-strong); border-radius: 999px; }
::-webkit-scrollbar-thumb:hover { background: var(--c-text-subtle); }
[data-theme="dark"] ::-webkit-scrollbar-thumb { background: #3a4352; }
[data-theme="dark"] ::-webkit-scrollbar-thumb:hover { background: #536070; }
body {
  margin: 0;
  font-family: var(--ff-sans);
  font-size: var(--fs-2);
  line-height: var(--lh-body);
  color: var(--c-text);
  background: var(--c-bg);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
/* Underline is a CONSTANT property of in-content links (article body), never a hover
   effect: chrome/navigation links signal hover by color only. */
a { color: var(--c-link); text-decoration: none; }
a:hover { color: var(--c-link-hover); }
:focus-visible { outline: 2px solid var(--c-focus); outline-offset: 2px; border-radius: var(--r-sm); }
.skip-link {
  position: absolute; left: var(--sp-2); top: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  background: var(--c-bg); color: var(--c-text);
  border: 1px solid var(--c-border-strong); border-radius: var(--r-md);
  transform: translateY(-200%); transition: transform 120ms ease;
  z-index: 100;
}
.skip-link:focus { transform: translateY(0); }
.topbar {
  position: sticky; top: 0; z-index: 20;
  padding: var(--sp-3) 0 0;
  background: color-mix(in srgb, var(--c-bg) 88%, transparent);
  backdrop-filter: saturate(180%) blur(8px);
  -webkit-backdrop-filter: saturate(180%) blur(8px);
}
/* Constrain topbar content to the same column box .layout uses so the
   brand sits flush with the sidebar's left edge and the theme toggle
   sits flush with the right rail's (or, below 1200px, the content's)
   right edge. The topbar element itself still spans full width for
   the sticky background band, but the divider lives on .topbar-inner
   so its left/right ends sit flush with the column box instead of
   extending past the brand and toggle. */
.topbar-inner {
  position: relative;
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-3);
  max-width: 1200px; margin: 0 auto;
  padding: 0 var(--sp-5) var(--sp-3);
}
/* Divider rendered as a pseudo-element so its ends can fade to
   transparent — a flat border-bottom would stop abruptly at the
   column box's left/right edges, leaving two hard line-ends. The
   12%/88% stops give a soft taper a sixth of the way in from each
   side, scaling automatically with the column width. */
.topbar-inner::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 1px;
  background: linear-gradient(
    to right,
    transparent,
    var(--c-border) 12%,
    var(--c-border) 88%,
    transparent
  );
}
@media (min-width: 1200px) { .topbar-inner { max-width: 1400px; } }
.brand { font-weight: 600; font-size: var(--fs-3); color: var(--c-text); letter-spacing: -0.01em; display: flex; align-items: center; gap: 0.375rem; }
.brand:hover { text-decoration: none; color: var(--c-text); }
.brand-logo { height: 1.5rem; width: auto; flex-shrink: 0; }
.brand-name { white-space: nowrap; }
.topbar-left { display: flex; align-items: center; gap: var(--sp-3); }
.topbar-right { display: flex; align-items: center; gap: var(--sp-4); }
.topbar-nav, .footer-nav {
  list-style: none; margin: 0; padding: 0;
  display: flex; align-items: center; gap: var(--sp-4);
}
.topbar-nav a, .footer-nav a {
  color: var(--c-text-muted);
  font-size: var(--fs-1);
  text-decoration: none;
  transition: color 120ms ease;
}
.topbar-nav a:hover, .footer-nav a:hover { color: var(--c-text); }
.topbar-nav a[aria-current="page"],
.footer-nav a[aria-current="page"] { color: var(--c-text); }
.footer-nav { justify-content: center; margin-bottom: var(--sp-3); }
.layout {
  flex: 1 0 auto;
  display: grid;
  grid-template-columns: var(--sidebar-w) minmax(0, 1fr);
  gap: var(--sp-6);
  max-width: 1200px; margin: 0 auto;
  padding: var(--sp-5) var(--sp-5) var(--sp-7);
  width: 100%;
}
/* Three-column layout once the viewport has room for the right rail.
   1200px floor matches the existing max-width plus two columns of
   gutter; the .layout max-width below scales up so the rail doesn't
   cause horizontal scrolling. */
@media (min-width: 1200px) {
  .layout {
    grid-template-columns: var(--sidebar-w) minmax(0, 1fr) var(--rail-w);
    max-width: 1400px;
  }
}
.sidebar {
  position: sticky; top: calc(var(--sp-3) * 2 + 1.5rem + 1px);
  align-self: start; max-height: calc(100vh - 5rem);
  overflow-y: auto; padding-right: var(--sp-3);
}
main { min-width: 0; }
main:focus { outline: none; }
/* Right-rail "On this page" outline. Hidden below 1200px viewport
   (the breakpoint at which .layout drops to two columns) so the
   article stays comfortable on narrower screens. */
.page-toc {
  display: none;
  position: sticky; top: calc(var(--sp-3) * 2 + 1.5rem + 1px);
  align-self: start; max-height: calc(100vh - 5rem);
  overflow-y: auto;
  font-size: var(--fs-0);
  line-height: var(--lh-snug);
}
@media (min-width: 1200px) {
  .page-toc { display: block; }
}
.page-toc__title {
  margin: 0 0 var(--sp-2);
  padding: 0 var(--sp-3);
  font-size: var(--fs-0); font-weight: 600;
  letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--c-text-subtle);
}
.page-toc__list { list-style: none; margin: 0; padding: 0; }
.page-toc__item a {
  display: block;
  padding: var(--sp-1) var(--sp-3);
  color: var(--c-text-muted);
  border-left: 2px solid transparent;
  text-decoration: none;
  transition: color 120ms, border-color 120ms;
}
.page-toc__item a:hover { color: var(--c-text); text-decoration: none; }
.page-toc__item--h3 a { padding-left: calc(var(--sp-3) + var(--sp-3)); }
.page-toc__item.is-active a {
  color: var(--c-accent);
  border-left-color: var(--c-accent);
}
.nav-list { list-style: none; margin: 0; padding: 0; }
.nav-section {
  display: block;
  margin: var(--sp-4) 0 var(--sp-2);
  padding: 0 var(--sp-3);
  font-size: var(--fs-0); font-weight: 600;
  letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--c-text-subtle);
}
.nav-list .nav-section:first-child { margin-top: 0; }
.nav-list a {
  display: block;
  padding: var(--sp-2) var(--sp-3);
  margin: 1px 0;
  border-radius: var(--r-md);
  color: var(--c-text-muted);
  font-size: var(--fs-1);
  line-height: var(--lh-snug);
}
.nav-list a:hover { background: var(--c-bg-soft); color: var(--c-text); text-decoration: none; }
.nav-list a[aria-current="page"] {
  background: var(--c-active-bg);
  color: var(--c-active-text);
  font-weight: 500;
}
/* Section children nest under their label (slightly indented); the label and
   top-level items stay flush at the left edge. */
.nav-sublist { list-style: none; margin: 0; padding: 0; }
.nav-sublist a { padding-left: calc(var(--sp-3) + 14px); }
.nav-list > li.nav-group:first-child .nav-section { margin-top: 0; }
/* Clickable heading anchors: "#" appears on hover, links to the section. */
.body h1, .body h2, .body h3, .body h4 { scroll-margin-top: calc(var(--docs-nav-h) + 12px); }
.heading-anchor {
  margin-left: 0.35em; font-weight: 400; text-decoration: none;
  color: var(--docs-fg2); opacity: 0; transition: opacity 0.15s ease;
}
.body h1:hover .heading-anchor, .body h2:hover .heading-anchor,
.body h3:hover .heading-anchor, .body h4:hover .heading-anchor { opacity: 0.55; }
.heading-anchor:hover, .heading-anchor:focus-visible { opacity: 1; color: var(--docs-pri); text-decoration: none; }
.theme-toggle, .menu-toggle {
  display: inline-flex; align-items: center; justify-content: center;
  flex-shrink: 0;
  width: 36px; height: 36px; padding: 0;
  background: transparent;
  border: 1px solid var(--c-border);
  border-radius: var(--r-md);
  color: var(--c-text-muted);
  cursor: pointer;
  transition: background 120ms ease, color 120ms ease, border-color 120ms ease;
}
.theme-toggle:hover, .menu-toggle:hover { background: var(--c-bg-soft); color: var(--c-text); border-color: var(--c-border-strong); }
.theme-toggle svg, .menu-toggle svg { width: 18px; height: 18px; display: block; }
.theme-toggle [data-icon] { display: none; }
/* Icon visibility is fully CSS-driven so morphdom patches that strip
   inline style attributes leave the toggle in a consistent state.
   The html:not([data-theme]) fallback shows the sun briefly while
   the bootstrap inline script has not yet written data-theme onto
   the root - without it the toggle would render iconless on first paint. */
[data-theme="light"] .theme-toggle [data-icon="sun"] { display: block; }
[data-theme="dark"] .theme-toggle [data-icon="moon"] { display: block; }
html:not([data-theme]) .theme-toggle [data-icon="sun"] { display: block; }
.menu-toggle { display: none; }
article { max-width: var(--content-max); padding: 0 var(--sp-5) var(--sp-7); }
article .article-meta {
  margin: 0 0 var(--sp-6);
  padding-bottom: var(--sp-3);
  border-bottom: 1px solid var(--c-border);
}
article .article-meta-row,
article .article-taxonomy-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--sp-3);
  min-height: 1.75rem;
}
article .article-taxonomy-row {
  margin-top: 0;
}
article .article-meta-row + .article-taxonomy-row {
  margin-top: var(--sp-2);
}
article .article-meta .post-date {
  flex: 0 0 auto;
  margin: 0;
  font-size: var(--fs-0);
  line-height: var(--lh-snug);
  font-weight: 400;
  color: var(--c-text-muted);
}
article .article-meta .categories,
article .article-meta .tags {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  min-width: 0;
}
article .article-meta .tags {
  flex: 0 1 auto;
  margin: 0 0 0 auto;
  justify-content: flex-end;
}
article .article-meta .categories {
  flex: 0 1 auto;
}
article .article-meta-row .tags:only-child,
article .article-taxonomy-row .tags:only-child {
  margin-left: 0;
}
article .article-meta .categories li,
article .article-meta .tags li {
  display: inline-flex;
  align-items: center;
  margin: 0;
  padding: 2px var(--sp-2);
  font-size: var(--fs-0);
  line-height: var(--lh-snug);
  font-weight: 500;
  background: var(--c-chip-bg);
  color: var(--c-chip-text);
  border: 1px solid var(--c-border);
  border-radius: 999px;
}
article .article-meta .categories li {
  background: var(--c-active-bg);
  color: var(--c-active-text);
  border-color: color-mix(in srgb, var(--c-accent) 22%, transparent);
  font-weight: 600;
}
article .article-meta .category-icon {
  display: inline-flex;
  width: 0.9em;
  height: 0.9em;
  margin-right: var(--sp-1);
}
article .article-meta .category-icon svg { width: 100%; height: 100%; }
article .article-meta .tag-hash {
  margin-right: var(--sp-1);
  color: var(--c-text-subtle);
}
article .body h1,
article .body h2,
article .body h3,
article .body h4,
article .body h5,
article .body h6 {
  color: var(--c-text);
  line-height: var(--lh-tight);
  margin: var(--sp-6) 0 var(--sp-3);
  letter-spacing: -0.01em;
}
article .body h1:first-child,
article .body h2:first-child,
article .body h3:first-child { margin-top: 0; }
article .body h1 { font-size: var(--fs-7); font-weight: 700; }
article .body h2 { font-size: var(--fs-5); font-weight: 600; padding-bottom: var(--sp-2); border-bottom: 1px solid var(--c-border); }
article .body h3 { font-size: var(--fs-4); font-weight: 600; }
article .body h4 { font-size: var(--fs-3); font-weight: 600; }
article .body h5 { font-size: var(--fs-2); font-weight: 600; }
article .body h6 { font-size: var(--fs-1); font-weight: 600; color: var(--c-text-muted); }
article .body p,
article .body ul,
article .body ol { margin: 0 0 var(--sp-4); line-height: var(--lh-relaxed); }
article .body li > p { margin-bottom: var(--sp-2); }
article .body ul,
article .body ol { padding-left: var(--sp-5); }
article .body li { margin: var(--sp-2) 0; }
article .body blockquote {
  margin: var(--sp-5) 0;
  padding: var(--sp-2) var(--sp-5);
  border-left: 3px solid var(--c-quote-border);
  color: var(--c-quote-text);
  font-style: italic;
}
article .body blockquote p:last-child { margin-bottom: 0; }
article .body code {
  font-family: var(--ff-mono);
  font-size: 0.9em;
  background: var(--c-code-bg);
  color: var(--c-code-text);
  padding: 0.15em 0.35em;
  border-radius: var(--r-sm);
}
article .body pre {
  background: var(--c-code-bg);
  color: var(--c-code-text);
  margin: 0 0 var(--sp-4);
  padding: var(--sp-4) var(--sp-7) var(--sp-4) var(--sp-4);
  overflow-x: auto;
  border-radius: var(--r-md);
  border: 1px solid var(--c-border);
  font-size: var(--fs-1);
  line-height: var(--lh-snug);
}
article .body .code-block {
  position: relative;
  margin: 0 0 var(--sp-4);
}
article .body .code-block pre {
  margin: 0;
}
article .body pre code {
  background: transparent; padding: 0; border-radius: 0; font-size: inherit;
}
.code-copy-button {
  position: absolute;
  top: var(--sp-2);
  right: var(--sp-2);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  height: 1.5rem;
  padding: 0;
  background: color-mix(in srgb, var(--c-code-bg) 84%, var(--c-bg));
  border: 1px solid var(--c-border);
  border-radius: var(--r-sm);
  color: var(--c-text-muted);
  cursor: pointer;
  opacity: 0;
  pointer-events: none;
  z-index: 1;
  transition: opacity 120ms ease, color 120ms ease, border-color 120ms ease, background 120ms ease;
}
article .body .code-block:hover .code-copy-button,
.code-copy-button:focus-visible,
.code-copy-button[data-copied="true"] {
  opacity: 1;
  pointer-events: auto;
}
.code-copy-button:hover {
  background: var(--c-bg);
  border-color: var(--c-border-strong);
  color: var(--c-text);
}
.code-copy-button svg {
  display: block;
  width: 0.95rem;
  height: 0.95rem;
}
.code-copy-tooltip {
  position: absolute;
  right: 0;
  bottom: calc(100% + var(--sp-1));
  top: auto;
  padding: 2px var(--sp-2);
  border: 1px solid var(--c-border-strong);
  border-radius: var(--r-sm);
  background: var(--c-bg);
  color: var(--c-text);
  font-family: var(--ff-sans);
  font-size: var(--fs-0);
  line-height: var(--lh-snug);
  white-space: nowrap;
  box-shadow: var(--c-shadow);
  opacity: 0;
  pointer-events: none;
}
.code-copy-button:hover .code-copy-tooltip,
.code-copy-button:focus-visible .code-copy-tooltip {
  opacity: 1;
}
/* Syntax highlight classes emitted by rehype-highlight (lowlight).
   Five token buckets covers ~95% of hljs class names; remaining
   classes inherit the surrounding pre/code colour. */
article .body .hljs-keyword,
article .body .hljs-built_in,
article .body .hljs-literal,
article .body .hljs-tag,
article .body .hljs-selector-tag { color: var(--c-syntax-keyword); }
article .body .hljs-string,
article .body .hljs-regexp,
article .body .hljs-doctag { color: var(--c-syntax-string); }
article .body .hljs-comment,
article .body .hljs-quote { color: var(--c-syntax-comment); font-style: italic; }
article .body .hljs-number,
article .body .hljs-symbol,
article .body .hljs-meta { color: var(--c-syntax-number); }
article .body .hljs-title,
article .body .hljs-name,
article .body .hljs-section,
article .body .hljs-type,
article .body .hljs-class .hljs-title,
article .body .hljs-function .hljs-title { color: var(--c-syntax-name); }
article .body .hljs-attr,
article .body .hljs-attribute,
article .body .hljs-variable,
article .body .hljs-template-variable,
article .body .hljs-property { color: var(--c-syntax-attr); }
article .body .hljs-emphasis { font-style: italic; }
article .body .hljs-strong { font-weight: 600; }
article .body table {
  width: 100%;
  border-collapse: collapse;
  margin: var(--sp-5) 0;
  font-size: var(--fs-1);
}
article .body th,
article .body td {
  padding: var(--sp-2) var(--sp-3);
  border-bottom: 1px solid var(--c-border);
  text-align: left;
}
article .body th { font-weight: 600; color: var(--c-text); background: var(--c-bg-soft); }
article .body tr:hover td { background: var(--c-bg-soft); }
article .body img { max-width: 100%; height: auto; border-radius: var(--r-md); }
article .body hr { border: 0; border-top: 1px solid var(--c-border); margin: var(--sp-6) 0; }
article .body a { text-decoration: underline; text-underline-offset: 2px; text-decoration-thickness: 1px; }
footer {
  padding: var(--sp-6) 0 0;
  font-size: var(--fs-1); color: var(--c-text-muted);
}
/* Mirror .topbar-inner / .layout: footer text aligns with the brand
   on the left and the right rail (or content, when no rail) on the
   right. The divider lives on .footer-inner (not on the full-width
   <footer>) so its left/right ends sit flush with the column box
   instead of extending past the brand on the left and the toggle on
   the right. */
.footer-inner {
  position: relative;
  max-width: 1200px; margin: 0 auto;
  padding: var(--sp-5) var(--sp-5) var(--sp-6);
  text-align: center;
}
/* Mirror of .topbar-inner::after — fade the divider ends so the
   line never sits flush against the column edge. */
.footer-inner::before {
  content: "";
  position: absolute;
  left: 0; right: 0; top: 0;
  height: 1px;
  background: linear-gradient(
    to right,
    transparent,
    var(--c-border) 12%,
    var(--c-border) 88%,
    transparent
  );
}
@media (min-width: 1200px) { .footer-inner { max-width: 1400px; } }
footer a { color: var(--c-text-muted); text-decoration: none; }
footer a:hover { color: var(--c-text); }
@media (max-width: 960px) {
  .layout { grid-template-columns: minmax(0, 1fr); padding: var(--sp-4); }
  .topbar-inner { padding: 0 var(--sp-4) var(--sp-3); }
  .footer-inner { padding: var(--sp-5) var(--sp-4) var(--sp-6); }
  .menu-toggle { display: inline-flex; }
  .sidebar {
    position: fixed; top: 0; left: 0; bottom: 0;
    width: min(86vw, 320px); max-height: 100vh;
    background: var(--c-bg);
    border-right: 1px solid var(--c-border);
    padding: var(--sp-5);
    transform: translateX(-100%);
    transition: transform 180ms ease;
    /* Shadow only while open: a closed (translated-off) drawer's shadow would
       bleed into the viewport as a stripe along the left edge. */
    z-index: 30;
  }
  .sidebar.open { transform: translateX(0); box-shadow: var(--c-shadow); }
  .sidebar-backdrop {
    position: fixed; inset: 0; background: rgba(0,0,0,0.4);
    opacity: 0; pointer-events: none;
    transition: opacity 180ms ease; z-index: 25;
  }
  .sidebar-backdrop.open { opacity: 1; pointer-events: auto; }
}
@media (min-width: 961px) { .sidebar-backdrop { display: none; } }
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
  }
}
/* Posts listing & cards.
   The listing is a container-query root so cards adapt to the
   article column width (not viewport). That lets them stay
   horizontal in the IDE preview pane AND in a full-width browser
   deploy, collapsing to vertical only when the column itself is
   too narrow. */
/* Prev/next page navigation over the published TOC sequence (docs-only). */
.page-nav { display: flex; justify-content: space-between; gap: 16px; margin: 40px 0 8px; }
.page-nav-prev, .page-nav-next {
  display: flex; flex-direction: column; gap: 2px; max-width: 48%;
  padding: 12px 16px; border: 1px solid var(--docs-brd); border-radius: 8px;
  text-decoration: none; color: var(--docs-fg1); overflow: hidden;
}
.page-nav-next { text-align: right; margin-left: auto; }
.page-nav-spacer { flex: 0 0 auto; }
.page-nav-prev:hover, .page-nav-next:hover { border-color: var(--docs-pri); color: var(--docs-pri); }
.page-nav-dir { font-size: 0.75rem; color: var(--docs-fg2); }
.page-nav-prev .page-nav-dir::before { content: "\2190  "; }   /* left arrow */
.page-nav-next .page-nav-dir::after { content: "  \2192"; }    /* right arrow */
.page-nav-title { font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* Header actions: CTA buttons (and GitHub link) from tree.yml header entries. */
.nav-actions { display: flex; align-items: center; gap: 12px; flex-shrink: 0; }
.nav-btn {
  display: inline-flex; align-items: center;
  padding: 8px 16px; border-radius: 6px;
  background: var(--nav-btn-bg, var(--docs-pri));
  color: #ffffff; font-size: 0.875rem; font-weight: 600;
  text-decoration: none; white-space: nowrap;
  transition: opacity 0.2s ease;
}
.nav-btn:hover { opacity: 0.88; color: #ffffff; text-decoration: none; }
.nav-btn { gap: 6px; }
.nav-btn svg { width: 14px; height: 14px; flex-shrink: 0; }
/* External-link cue for icon-less text links: a small NE arrow after the label.
   Icon-carrying elements (.nav-github, buttons with inline svg) are exempt by construction. */
article .body a[href^="http"]:not(:has(img))::after,
.nav-links a[href^="http"]::after,
.ftr-lk-wrap a[href^="http"]::after {
  content: "\2197"; display: inline-block;
  font-size: 0.75em; margin-left: 3px;
}
.nav-github {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 0.875rem; font-weight: 500;
  color: var(--docs-fg2); text-decoration: none; white-space: nowrap;
  transition: color 0.2s ease;
}
.nav-github:hover { color: var(--docs-pri); text-decoration: none; }
.nav-github svg { width: 18px; height: 18px; }

/* ---- Landing sections (frontmatter `sections:`) ---- */
.landing { display: flex; flex-direction: column; }
.landing section { padding: 64px 24px; }
.landing-label {
  display: inline-block; font-size: 0.7rem; font-weight: 700;
  letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--docs-pri); background: rgba(59, 130, 246, 0.08);
  border-radius: 99px; padding: 4px 10px; margin-bottom: 8px;
}
[data-theme="dark"] .landing-label { background: rgba(88, 166, 255, 0.1); }
.landing-hero { text-align: center; background: linear-gradient(180deg, var(--docs-bg2) 0%, var(--docs-bg1) 100%); }
.landing-hero-inner { max-width: 860px; margin: 0 auto; }
.landing-badge {
  display: inline-block; padding: 4px 12px; border: 1px solid var(--docs-brd);
  border-radius: 999px; font-size: 0.8125rem; color: var(--docs-fg2); margin-bottom: 20px;
}
.landing-hero h1 { font-size: 2.75rem; line-height: 1.15; letter-spacing: -0.02em; color: var(--docs-fg1); margin: 0 0 16px; }
.landing-subtitle { font-size: 1.125rem; color: var(--docs-fg2); margin: 0 auto 28px; max-width: 640px; }
.landing-btn-row { display: flex; justify-content: center; gap: 12px; flex-wrap: wrap; }
.landing-btn-primary, .landing-btn-outline {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 12px 22px; border-radius: 8px;
  font-size: 0.9375rem; font-weight: 600; text-decoration: none; white-space: nowrap;
}
.landing-btn-primary { background: var(--docs-pri); color: #ffffff; }
.landing-btn-primary:hover { background: var(--docs-pri-hover); color: #ffffff; text-decoration: none; }
.landing-btn-outline { border: 1px solid var(--docs-brd); color: var(--docs-fg1); }
.landing-btn-outline:hover { border-color: var(--docs-pri); color: var(--docs-pri); text-decoration: none; }
.landing-btn-primary svg, .landing-btn-outline svg { width: 14px; height: 14px; flex-shrink: 0; }
.landing-steps, .landing-features, .landing-code, .landing-cta { text-align: center; }
.landing h2 { font-size: 1.875rem; letter-spacing: -0.01em; color: var(--docs-fg1); margin: 0 0 32px; }
.landing-card-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 20px; max-width: 1100px; margin: 0 auto; text-align: left;
}
/* Steps read as full-width horizontal rows (old landing's steps-layout), not columns:
   a leading marker block (auto number, or the item's icon) sits inline with the title,
   the text hangs indented under the title. */
.landing-steps .landing-card-grid { grid-template-columns: 1fr; max-width: 960px; gap: 24px; }
.landing-steps .landing-card { padding: 28px 32px; }
.landing-card-head { display: flex; align-items: center; gap: 14px; margin-bottom: 12px; }
.landing-card-head h3 { margin: 0; }
.landing-step-marker {
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; border-radius: 8px; flex-shrink: 0;
  background: rgba(59, 130, 246, 0.1); color: var(--docs-pri);
  font-weight: 800; font-size: 0.9rem;
}
[data-theme="dark"] .landing-step-marker { background: rgba(88, 166, 255, 0.12); }
.landing-step-marker img { width: 20px; height: 20px; display: block; }
/* Hang the text under the title only when a marker sets that indent (numbered: false
   cards without icons have no marker and stay flush left). */
.landing-steps .landing-card:has(.landing-step-marker) p { padding-left: 54px; }
.landing-card {
  padding: 22px; border: 1px solid var(--docs-brd); border-radius: 10px; background: var(--docs-bg1);
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
.landing-card:hover { border-color: var(--docs-pri); box-shadow: var(--docs-shadow); }
.landing-card h3 { margin: 0 0 8px; font-size: 1rem; color: var(--docs-fg1); }
.landing-card p { margin: 0; font-size: 0.9375rem; color: var(--docs-fg2); }
.landing-card-icon { display: block; width: 48px; height: 48px; margin-bottom: 16px; }
.landing-card-icon img { width: 48px; height: 48px; display: block; }
.landing-code .code-sample { max-width: 760px; margin: 0 auto; text-align: left; }
.landing-code .code-sample pre {
  background: var(--docs-bg2); border: 1px solid var(--docs-brd);
  border-radius: 10px; padding: 24px 28px;
  box-shadow: var(--docs-shadow); overflow: auto;
}
/* Distinct accent band so the closing CTA does not blend into the neighboring sections. */
.landing-cta { background: linear-gradient(135deg, var(--docs-pri) 0%, var(--docs-acc) 100%); }
.landing-cta h2 { color: #ffffff; }
.landing-cta .landing-subtitle { color: rgba(255, 255, 255, 0.85); }
.landing-cta .landing-btn-primary {
  background: #ffffff; color: var(--docs-pri);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.landing-cta .landing-btn-primary:hover {
  background: #ffffff; color: var(--docs-pri);
  transform: translateY(-2px); box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);
}
.landing-content { text-align: initial; }
.landing-content article { max-width: 860px; margin: 0 auto; }
/* `layout: full` chrome: no sidebar, no local toc, hero starts under the fixed header. */
body.layout-full { padding-top: 0; }
.layout-full .sidebar, .layout-full .page-toc, .layout-full .menu-toggle { display: none; }
.layout-full .layout { display: block; max-width: none; padding: 0; margin: 0; }
.layout-full main { max-width: none; padding: 0; }
.layout-full .landing-hero { padding-top: calc(var(--docs-nav-h) + 72px); padding-bottom: 72px; }
