/* The docs shell for jaque.sh/docs, rendered by internal/docsgen from
   templates/page.html -- no Starlight, no Astro, nothing underneath this
   file to derive from. It sets every token and rule the page needs
   outright and reuses the landing page's system (landing/style.css) end to
   end: IBM Plex Mono throughout, a plaintext-document register, hierarchy
   read from structure rather than from size. The two themes are both
   drawn from that one palette: dark is the landing's colours as-is, light
   is a "paper" inversion of the same set.

   The --sl-* names predate the Starlight migration and stay: they are the
   primitives (--sl-color-white, --sl-color-black, --sl-color-gray-1..7,
   the accent trio, --jq-state-*) that the derived tokens just below --
   --sl-color-bg, --sl-color-bg-nav, --sl-color-text, --sl-color-hairline*
   -- are computed from, and scripts/contrast-check.sh parses them by that
   exact name. Renaming them is a bigger change than a design pass; this
   file keeps them. */

/* Self-hosted, same two font files as landing/style.css, served from the
   same place: scripts/build-site.sh copies landing/fonts/ to public/fonts/
   once, and both surfaces link it from there. The URL is absolute because
   docsgen serves this file from /docs/_static/docs.css regardless of which
   page requested it, so a relative URL would resolve against the current
   page path instead of the asset's own. */
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/ibm-plex-mono-latin-400-normal.woff2') format('woff2');
}

@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/fonts/ibm-plex-mono-latin-500-normal.woff2') format('woff2');
}

:root {
  /* The landing page (landing/style.css) is set entirely in the mono face;
     the docs follow it, so --sl-font IS the mono stack and the sans faces
     are gone from this file. */
  --sl-font: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  --sl-font-mono: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  /* Type scale. Body stays at 0.9375rem (15px, one step above the
     landing's 14px -- docs is the long-read surface); the headings above
     it are NOT flat. The ladder is built on the ratio every docs system
     with published numbers converges on: h2 at 1.5x body (Tailwind
     Typography ships 24/16 literally, Stripe 24/15, Geist and Starlight
     land in the same 1.5-1.8x band), h3 at ~1.2x, h1 at ~1.9x, and h4
     back at body size ranked by weight alone. Adjacent steps sit at
     1.2-1.27x, which is the observed step size in all of them.

     The previous ladder put h2 at 1.0625rem against a 0.9375rem body --
     a 1.13x ratio, close enough to flat that the page had to draw rules
     under its headings to show where sections began. That is why the
     borders below are gone: the size step does the work now. */
  --sl-text-2xs: 0.6875rem;
  --sl-text-xs: 0.75rem;
  --sl-text-sm: 0.8125rem;
  --sl-text-base: 0.9375rem;
  --sl-text-lg: 1rem;
  --sl-text-xl: 1.0625rem;
  --sl-text-2xl: 1.125rem;
  --sl-text-3xl: 1.375rem;
  --sl-text-4xl: 1.75rem;
  --sl-text-5xl: 2rem;
  --sl-text-6xl: 2.25rem;
  --sl-text-h1: var(--sl-text-4xl);
  --sl-text-h4: var(--sl-text-base);
  --sl-line-height: 1.55;
  --sl-line-height-headings: 1.25;

  /* Radius and elevation. jaque's register is sharp, so the scale stops
     where the sharpest shipped systems stop (Stripe runs 1-4px, Bun
     2-6px) rather than at the 8px the softer ones use. Shadow is for
     floating surfaces only -- the search dropdown is the single one this
     page has. No static block (code, table, callout, diagram) carries a
     shadow; those separate with a border and a background step, which is
     unanimous across every docs site with published values. */
  --jq-radius: 4px;
  --jq-radius-lg: 6px;
  --jq-shadow-overlay: 0 4px 6px -1px rgb(0 0 0 / 0.18), 0 10px 24px -4px rgb(0 0 0 / 0.22);

  /* Sticky offset. The header pins, so the sidebar and the TOC pin under
     it and scroll independently -- with 45 pages in the sidebar, losing
     the nav on scroll is the difference between a reference and a
     scroll. Every docs site measured for this pass pins all three. */
  --jq-header-h: 3.5rem;
}

/* docsgen's own reset (below, "html, body") does not set a font-size on
   body -- it leaves it at the browser default (1rem against the root's
   16px) -- so --sl-text-base has no effect on running text unless
   something applies it. This does that, to match the landing page's body
   copy; rem units elsewhere in this file resolve against the root
   element's font-size, not body's, so it does not also rescale anything
   sized in rem. */
body {
  font-size: var(--sl-text-base);
}

/* Weight 500, because 500 is the heaviest cut landing/fonts/ actually
   ships: asking for 600 got a synthetic bold, which a browser fakes by
   redrawing the glyph offset from itself. On a mono face at heading
   sizes that smears, and the smear was the newspaper ink. The size ramp
   carries the contrast instead. Headings also take a tighter leading
   than body copy (1.25 against 1.55), consistent across every published
   scale. */
:is(h1, h2, h3, h4, h5, h6) {
  font-family: var(--sl-font-mono);
  font-weight: 500;
  line-height: var(--sl-line-height-headings);
}

:root,
:root[data-theme='dark'] {
  --sl-color-white: #F4F5F6;
  --sl-color-gray-1: #ECEDEE;
  --sl-color-gray-2: #E8EAED;
  /* gray-3 #9AA0A6 measures 7.11:1 on --sl-color-black (#101214), clear of
     the 4.5:1 floor this file uses gray-3 for secondary body text; the
     accent #C7CCD1 clears it further still, at 11.61:1 on the same ground
     -- see scripts/contrast-check.sh. */
  --sl-color-gray-3: #9AA0A6;
  --sl-color-gray-4: #4E545A;
  --sl-color-gray-5: #2C3136;
  --sl-color-gray-6: #1A1E22;
  --sl-color-black: #101214;

  --sl-color-accent-low: #22262B;
  --sl-color-accent: #C7CCD1;
  --sl-color-accent-high: #E8EAED;

  /* State colors -- the Nagios exit-code vocabulary (OK/WARNING/CRITICAL/
     UNKNOWN/PENDING), never the board's paper/ink tones. Rule: a state is
     never carried by color alone -- always the color AND the word, set in
     the mono face. Each value measures 4.92-4.97:1 as text against
     --sl-color-black (#101214) and, being at or above the 4.5:1 floor,
     also clears the 3:1 graphical-boundary floor a badge's own fill needs.
     Same hues as internal/ui/web's --status-* tokens, relit for graphite
     instead of slate -- see scripts/contrast-check.sh. */
  --jq-state-ok: #259563;
  --jq-state-warning: #b57515;
  --jq-state-critical: #ef3e58;
  --jq-state-unknown: #916aee;
  --jq-state-pending: #75849b;
}

:root[data-theme='light'] {
  --sl-color-white: #17181A;
  --sl-color-gray-1: #101214;
  --sl-color-gray-2: #17181A;
  --sl-color-gray-3: #33363A;
  --sl-color-gray-4: #55595E;
  /* gray-5 #5C6166 measures 5.99:1 on --sl-color-black (#FAFAF8), clear of
     the 4.5:1 floor this file uses gray-5 for; the accent #2E3236 clears it
     further still, at 12.36:1 on the same ground -- see
     scripts/contrast-check.sh. */
  --sl-color-gray-5: #5C6166;
  --sl-color-gray-6: #E1E2E0;
  --sl-color-gray-7: #F0F1EF;
  --sl-color-black: #FAFAF8;

  --sl-color-accent-low: #E9EAE8;
  --sl-color-accent: #2E3236;
  --sl-color-accent-high: #17181A;

  /* Same five states, relit for --sl-color-black (#FAFAF8) instead of graphite.
     Each measures 5.60-5.65:1 text / clears 3:1 fill on this ground -- see
     scripts/contrast-check.sh. */
  --jq-state-ok: #1c724c;
  --jq-state-warning: #8c5a11;
  --jq-state-critical: #c8102c;
  --jq-state-unknown: #703fe9;
  --jq-state-pending: #58657a;
}

/* The index page's only hero (page.html): a tagline and its actions,
   centred above the abstract the way the landing page centres its own
   tagline under the title (landing/style.css `.tagline`). No hero image
   exists in the page data (Hero has no such field), so there is nothing to
   reserve a second column for. */
.hero {
  text-align: center;
  margin: 0.5rem 0 3rem;
}
.hero .tagline {
  margin: 0 0 1rem;
  color: var(--sl-color-gray-3);
}
.hero .actions {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: 0.5rem 1.5rem;
}
.hero .action {
  text-decoration: underline;
  text-underline-offset: 0.2em;
}
.hero .action-primary {
  font-weight: 500;
}

/* AsciiReplay (src/components/AsciiReplay.astro): the frame rests in a
   plain <pre>; the caption carries the title and the replay button, which
   stays hidden until the script has confirmed it can animate. */
.ascii-replay {
  margin: 1.5rem 0;
}
.ascii-replay pre {
  margin: 0;
  font-family: var(--sl-font-mono);
  line-height: 1.35;
  overflow-x: auto;
}
.ascii-replay figcaption {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  margin-top: 0.4rem;
  font-size: var(--sl-text-xs);
  color: var(--sl-color-gray-3);
}
.ascii-replay button {
  background: none;
  border: 1px solid var(--sl-color-gray-5);
  border-radius: 0;
  color: inherit;
  cursor: pointer;
  font: inherit;
  padding: 0 0.5rem;
}

/* ---- docsgen base layer ----
   Everything above is theme tokens; everything below is the page docsgen
   actually renders around them -- the sidebar/content/TOC grid, base
   typography, tables, code and blockquotes. page.html sets data-theme on
   <html> unconditionally (docs.js only ever flips it between "light" and
   "dark", never removes it), so the two blocks above are the only theme
   sources this file needs: there is no third, attribute-less state to
   derive a default for. */

:root {
  --sl-color-bg: var(--sl-color-black);
  --sl-color-bg-nav: var(--sl-color-gray-6);
  --sl-color-text: var(--sl-color-white);

  /* A hairline is a boundary, not a line of type, so it is mixed from the
     foreground at 14% rather than taken from the gray ramp. The ramp's
     grays are picked to clear a 4.5:1 text floor, and --sl-color-gray-5
     on paper (#5C6166 on #FAFAF8) reads at 5.99:1 -- correct for a
     caption, far too loud for an edge, and the single biggest reason the
     light theme looked ruled like a newspaper. 10-15% of the foreground
     is where the sites measured for this pass sit.

     This is a derived token only; the ramp itself is untouched, so
     scripts/contrast-check.sh still reads the same values out of the two
     theme blocks above. */
  --sl-color-hairline: color-mix(in srgb, var(--sl-color-text) 14%, transparent);
  --sl-color-hairline-light: color-mix(in srgb, var(--sl-color-text) 8%, transparent);
}

*, *::before, *::after {
  box-sizing: border-box;
}

html {
  background: var(--sl-color-bg);
  color: var(--sl-color-text);
}

body {
  margin: 0;
  font-family: var(--sl-font);
  line-height: var(--sl-line-height);
  background: var(--sl-color-bg);
  color: var(--sl-color-text);
}

a {
  color: var(--sl-color-accent-high);
}

/* Prose links carry a permanently visible underline, drawn in a muted
   colour and intensified on hover. Colour alone does not distinguish a
   link (WCAG 1.4.1), and hover-only underlines fail the same way for
   anyone not using a pointer; an always-on underline is what the sites
   measured for this pass ship, at a 2-4px offset and 1px thickness.

   The landing's fg/bg inversion is not repeated here. It is a terminal-era
   gesture that appears on none of them, and a docs sidebar of 45 entries
   is where it hurts most: every pointer pass down the nav strobes a solid
   block. Navigation gets a colour and tint change instead (below). */
.content a {
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.25em;
  text-decoration-color: var(--sl-color-gray-4);
}
.content a:hover {
  text-decoration-color: currentColor;
}

.skip-link {
  position: absolute;
  top: 0;
  left: -999px;
  padding: 0.5rem 1rem;
  background: var(--sl-color-bg);
  border: 1px solid var(--sl-color-hairline);
  z-index: 1;
}
.skip-link:focus {
  left: 0.5rem;
  top: 0.5rem;
}

.site-header {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  gap: 1rem;
  min-height: var(--jq-header-h);
  padding: 0 1rem;
  border-bottom: 1px solid var(--sl-color-hairline);
  background: var(--sl-color-bg-nav);
}
/* The mark is /favicon.svg, the same file `just brand` generates from
   internal/brand's Bitmap, so there is no hand copy here to drift the way
   landing/'s cell grids can. It carries its own dark tile, which is why
   it needs no color of its own in either theme. */
.site-header .logo {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  font-weight: 500;
  text-decoration: none;
}
.site-header .logo img {
  display: block;
  border-radius: var(--jq-radius);
}
.site-header .theme-toggle {
  background: none;
  border: 1px solid var(--sl-color-hairline);
  border-radius: var(--jq-radius);
  color: var(--sl-color-gray-3);
  cursor: pointer;
  font: inherit;
  font-size: var(--sl-text-sm);
  padding: 0.25rem 0.6rem;
}
.site-header .theme-toggle:hover {
  border-color: var(--sl-color-gray-4);
  color: var(--sl-color-text);
}

.layout {
  display: grid;
  grid-template-columns: 17.5rem minmax(0, 1fr) 15rem;
  gap: 2.5rem;
  max-width: 84rem;
  margin: 0 auto;
  padding: 2rem 1.5rem;
  align-items: start;
}

/* The one vertical rule on the page. Nav and reading column serve
   different purposes, so the edge between them carries information; 5 of
   the 6 docs sites measured draw exactly this one and nothing else. The
   TOC's own rule is gone (only Starlight's stock theme drew it) and so is
   the rule between sidebar sections, which none of them draw -- an 9-way
   ruled nav was the newspaper grid in miniature. Sections separate by
   space now. */
.sidebar {
  position: sticky;
  top: var(--jq-header-h);
  max-height: calc(100vh - var(--jq-header-h));
  overflow-y: auto;
  overscroll-behavior: contain;
  border-right: 1px solid var(--sl-color-hairline);
  padding: 0.25rem 1rem 2rem 0;
}

/* Both rails scroll on their own, so both would otherwise show the
   platform scrollbar at full width against a 280px column. Thin, drawn in
   the same mixed neutral as the hairlines. */
.sidebar,
.toc {
  scrollbar-width: thin;
  scrollbar-color: var(--sl-color-hairline) transparent;
}
.sidebar details + details {
  margin-top: 1.75rem;
}
/* The summary is the flex row, not the h2 inside it: a summary defaults to
   display: list-item, which puts a block-level h2 on its own line under the
   disclosure marker instead of beside it. Making the summary a flex box
   fixes the line and removes the native marker in the same declaration.
   Safari draws its marker through a pseudo-element that survives that, so
   it still needs hiding by name. */
.sidebar summary {
  display: flex;
  align-items: center;
  cursor: pointer;
}
.sidebar summary::-webkit-details-marker {
  display: none;
}
/* The rail is itself one more disclosure, so it can fold away on a narrow
   viewport where 11 section headings would otherwise sit between the site
   header and the first paragraph. It ships open and docs.js closes it below
   the breakpoint, which leaves the no-JS rendering exactly as it was. Its
   summary is the mobile control and has no job on a wide screen. */
.sidebar-drawer > summary {
  display: none;
}
.sidebar h2 {
  font-size: var(--sl-text-sm);
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--sl-color-gray-3);
  margin: 0;
}
/* ASCII, because check-ascii covers this file and a disclosure triangle is
   not ASCII. The fixed width keeps the label from shifting when the glyph
   swaps between the two. */
.sidebar h2::before {
  content: '+';
  display: inline-block;
  width: 1em;
  color: var(--sl-color-gray-4);
}
.sidebar details[open] > summary h2 {
  margin-bottom: 0.4rem;
}
.sidebar details[open] > summary h2::before {
  content: '-';
}
.sidebar summary:hover h2 {
  color: var(--sl-color-text);
}
.sidebar ul {
  list-style: none;
  margin: 0;
  padding: 0;
}
/* One step below the section label it hangs from. Without this the links
   inherit the body's --sl-text-base and each item renders larger than the
   heading above it, which reads as an inverted hierarchy. The TOC's links
   are set to the same size for the same reason. */
.sidebar li a {
  display: block;
  font-size: var(--sl-text-sm);
  padding: 0.15rem 0 0.15rem 0.6rem;
  margin-left: -0.6rem;
  border-left: 2px solid transparent;
  text-decoration: none;
  color: var(--sl-color-gray-2);
}
.sidebar li a[aria-current='page'] {
  border-left-color: var(--sl-color-accent-high);
  color: var(--sl-color-accent-high);
  font-weight: 500;
}
.sidebar li a:hover {
  background: var(--sl-color-hairline-light);
  border-left-color: var(--sl-color-gray-4);
  color: var(--sl-color-text);
}

/* 72ch of mono. The ch unit is exact here rather than approximate, which
   is why the mono-set references use it directly; 72 sits inside the
   75-90ch band those use and below the 65-75ch one proportional text
   needs, because a mono glyph is narrower per em. */
.content {
  max-width: 72ch;
}
.content > :first-child {
  margin-top: 0;
}

/* Space above a heading is roughly twice the space below it, so a heading
   binds to the section it opens instead of floating between two. Tailwind
   Typography ships this ratio literally (2em over 1em on h2) and the
   grid-locked mono references arrive at the same 2:1 independently.

   No heading carries a border. Not one of the eight docs sites surveyed
   for this pass rules its headings; the size step below does that work,
   and drawing both is what made the page read as a broadsheet. */
.content :is(h1, h2, h3, h4, h5, h6) {
  margin-top: 2.5rem;
  margin-bottom: 0.6rem;
}
.content h1 {
  font-size: var(--sl-text-h1);
  margin-top: 0;
  margin-bottom: 1.25rem;
  letter-spacing: -0.01em;
}
.content h2 {
  font-size: var(--sl-text-3xl);
  margin-top: 3rem;
}
.content h3 {
  font-size: var(--sl-text-2xl);
}
/* h4 and below rank by weight at body size, which is where every
   published scale puts them. The uppercase they used to carry is a
   wayfinding device for taxonomic labels (the sidebar and TOC headings
   keep it, correctly); on a heading inside running prose it is
   decoration, and it read as one. */
.content :is(h4, h5, h6) {
  font-size: var(--sl-text-h4);
  color: var(--sl-color-gray-3);
}

.content p {
  margin: 0.8rem 0;
}

/* A block box rather than a table box, so the reference tables that carry
   a flag name, a default and a description scroll inside the column
   instead of widening the page. */
.content table {
  border-collapse: collapse;
  display: block;
  overflow-x: auto;
  width: 100%;
  margin: 1.5rem 0;
}
.content table th,
.content table td {
  padding: 0.4rem 0.75rem;
  text-align: left;
  border-bottom: 1px solid var(--sl-color-hairline);
}
/* Sentence case, not uppercase: of the six docs sites whose table CSS
   could be read, none uppercases a header cell. Horizontal rules only,
   never verticals -- also unanimous. */
.content table th {
  border-bottom-color: var(--sl-color-hairline-light);
  font-weight: 500;
  color: var(--sl-color-text);
}

/* Code sits one step below body copy at 0.875em, the single most
   consistent number in the whole survey: every site with readable values
   sets it between 0.8 and 0.875 of body. The block gets a tint plus a
   hairline and no shadow -- static content separates with an edge and a
   background step everywhere, without exception. */
.content pre {
  background: var(--sl-color-gray-6);
  border: 1px solid var(--sl-color-hairline);
  border-radius: var(--jq-radius);
  font-size: 0.875em;
  line-height: 1.5;
  margin: 1.5rem 0;
  overflow-x: auto;
  padding: 1rem;
}
.content :not(pre) > code {
  background: var(--sl-color-gray-6);
  border: 1px solid var(--sl-color-hairline-light);
  border-radius: var(--jq-radius);
  padding: 0.05rem 0.3rem;
  font-size: 0.875em;
}
.content a > code,
.content :is(h1, h2, h3, h4, h5, h6) > code {
  font-size: inherit;
}

/* A bar and no fill. Every site that has both distinguishes them: the
   tinted, icon-led panel is the dedicated callout component, and a plain
   markdown blockquote -- which is all this page emits -- gets the bar
   alone. Filling it made every quote read as a warning. */
.content blockquote {
  margin: 1.5rem 0;
  padding: 0.2rem 0 0.2rem 1.25rem;
  border-left: 2px solid var(--sl-color-hairline);
  color: var(--sl-color-gray-3);
}
.content blockquote p {
  margin: 0.4rem 0;
}

/* Bordered cards with the direction as a label above the destination
   title. None of the sites surveyed still ships bare text-with-arrows;
   the label/title card is the current shape, at roughly 16px of padding.
   The labels are ::before content because the template emits a bare <a>
   and this pass changes no markup. */
.page-footer {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
  margin-top: 4rem;
  padding-top: 2rem;
  border-top: 1px solid var(--sl-color-hairline);
}
.page-footer :is(.prev, .next) {
  border: 1px solid var(--sl-color-hairline);
  border-radius: var(--jq-radius-lg);
  padding: 0.75rem 1rem;
  text-decoration: none;
  color: var(--sl-color-text);
}
.page-footer :is(.prev, .next):hover {
  border-color: var(--sl-color-gray-4);
  background: var(--sl-color-hairline-light);
}
.page-footer :is(.prev, .next)::before {
  display: block;
  margin-bottom: 0.15rem;
  font-size: var(--sl-text-xs);
  color: var(--sl-color-gray-3);
}
.page-footer .prev {
  grid-column: 1;
}
.page-footer .prev::before {
  content: "<- Previous";
}
.page-footer .next {
  grid-column: 2;
  text-align: right;
}
.page-footer .next::before {
  content: "Next ->";
}
.page-footer .view-markdown {
  grid-column: 1 / -1;
  font-size: var(--sl-text-xs);
  color: var(--sl-color-gray-3);
  text-decoration: none;
}
.page-footer .view-markdown:hover {
  color: var(--sl-color-text);
}

.toc {
  position: sticky;
  top: var(--jq-header-h);
  max-height: calc(100vh - var(--jq-header-h));
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 0.25rem 0 2rem;
}
.toc-label {
  font-size: var(--sl-text-sm);
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--sl-color-gray-3);
  margin: 0 0 0.4rem;
}
.toc ul {
  list-style: none;
  margin: 0;
  padding: 0;
  font-size: var(--sl-text-sm);
}
.toc li {
  margin: 0.2rem 0;
}
.toc li a {
  display: block;
  padding: 0.1rem 0.4rem;
  margin-left: -0.4rem;
  border-radius: var(--jq-radius);
  text-decoration: none;
  color: var(--sl-color-gray-3);
}
.toc li a:hover {
  background: var(--sl-color-hairline-light);
  color: var(--sl-color-text);
}
.toc .toc-level-3 {
  padding-left: 1rem;
}

/* 1024px, the breakpoint the whole Tailwind-derived family collapses at
   (Tailwind's own docs, Cloudflare, Supabase, Bun all use `lg:` for
   exactly this transition). Below it the TOC is dropped and the sidebar
   stops pinning -- a sticky rail with no room to sit is worse than none. */
@media (max-width: 1024px) {
  .layout {
    /* minmax, not 1fr: a bare 1fr row track takes its minimum from the
       content, and the nav's longest entry is wider than a phone. */
    grid-template-columns: minmax(0, 1fr);
    gap: 1.5rem;
    padding: 1.5rem 1rem;
  }
  .sidebar {
    position: static;
    max-height: none;
    overflow-y: visible;
    border-right: none;
    border-bottom: 1px solid var(--sl-color-hairline);
    padding: 0 0 1.5rem;
  }
  .sidebar-drawer > summary {
    display: flex;
    align-items: center;
    font-size: var(--sl-text-sm);
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--sl-color-gray-3);
  }
  .sidebar-drawer > summary::before {
    content: '+';
    display: inline-block;
    width: 1em;
    color: var(--sl-color-gray-4);
  }
  .sidebar-drawer[open] > summary {
    margin-bottom: 1rem;
  }
  .sidebar-drawer[open] > summary::before {
    content: '-';
  }
  .toc {
    display: none;
  }
}

/* Bare and centred, not boxed: framing is split across the surveyed
   sites and the unframed side is the larger one. The diagrams already
   draw their own hairline boxes, so a second box around them competes.

   Their colours come from the theme tokens below rather than from hex
   baked into the markup, which is what lets one asset serve both themes.
   That is the part the survey found nobody had solved generally -- the
   sites that ship diagrams either hand-write a set of per-mode overrides
   or simply do not retheme. Keeping the fills and strokes as tokens is
   the whole reason the toggle works here. */
.diagram {
  margin: 2rem 0;
  text-align: center;
}
.diagram svg {
  max-width: 100%;
  height: auto;
}
/* The deployment diagrams (content/docs/deployment/*.svg) carry only
   semantic classes now that the Astro scoped stylesheet is gone -- style
   them here, scoped under .diagram svg so nothing leaks. */
.diagram svg text {
  font-family: var(--sl-font-mono);
  fill: var(--sl-color-text);
  text-anchor: middle;
  font-size: var(--sl-text-sm);
}
.diagram svg .caption,
.diagram svg .annotation,
.diagram svg .foreign {
  fill: var(--sl-color-gray-3);
  font-size: var(--sl-text-2xs);
}
.diagram svg .caption.accent {
  fill: var(--sl-color-accent-high);
}
.diagram svg .box,
.diagram svg .infra {
  fill: none;
  stroke: var(--sl-color-hairline);
  stroke-width: 1;
}
.diagram svg .box.owner {
  stroke: var(--sl-color-gray-3);
}
.diagram svg .box.owner.ghost {
  stroke-dasharray: 4 3;
  opacity: 0.5;
}
.diagram svg .connector {
  fill: none;
  stroke: var(--sl-color-gray-4);
}
.diagram svg .connector.dashed {
  stroke-dasharray: 4 3;
}
.diagram svg .arrowhead {
  fill: var(--sl-color-gray-4);
}
.diagram details {
  margin-top: 0.75rem;
  text-align: left;
  font-size: var(--sl-text-xs);
  color: var(--sl-color-gray-3);
}
.diagram details pre {
  margin-top: 0.5rem;
}
.diagram summary {
  cursor: pointer;
}

/* ---- search ---- */

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

#search {
  position: relative;
  /* Shrinkable, not fixed: the header is a flex row and a rigid 15rem box
     between the logo and the theme button overflows a phone. It still
     measures 15rem wherever that fits. */
  flex: 0 1 15rem;
  min-width: 0;
  margin-left: auto;
  margin-right: 1rem;
}

#search-input {
  font-family: var(--sl-font);
  font-size: var(--sl-text-sm);
  color: var(--sl-color-text);
  background: var(--sl-color-bg);
  border: 1px solid var(--sl-color-hairline);
  border-radius: var(--jq-radius);
  padding: 0.35rem 0.6rem;
  width: 100%;
}

#search-input::placeholder {
  color: var(--sl-color-gray-3);
}

#search-input:hover {
  border-color: var(--sl-color-gray-4);
}

#search-input:focus {
  outline: none;
  border-color: var(--sl-color-gray-3);
}

/* Elevation lives here and nowhere else on the page. Shadow has narrowed
   to floating surfaces -- dialogs, palettes, dropdowns -- and is absent
   from static blocks on every site surveyed; this list is the only
   floating surface the docs shell has. */
#search-results {
  position: absolute;
  top: calc(100% + 0.35rem);
  right: 0;
  z-index: 10;
  min-width: 26rem;
  margin: 0;
  padding: 0.25rem;
  list-style: none;
  background: var(--sl-color-bg-nav);
  border: 1px solid var(--sl-color-hairline);
  border-radius: var(--jq-radius-lg);
  box-shadow: var(--jq-shadow-overlay);
  max-height: 70vh;
  overflow-y: auto;
}

#search-results li {
  margin: 0;
}

#search-results a {
  display: block;
  padding: 0.4rem 0.6rem;
  border-radius: var(--jq-radius);
  font-size: var(--sl-text-sm);
  color: var(--sl-color-text);
  text-decoration: none;
}

#search-results a:hover,
#search-results a.active {
  background: var(--sl-color-hairline-light);
  color: var(--sl-color-accent-high);
}

/* Same breakpoint as the layout's, in its own block because the search
   rules are declared after that one and would otherwise win on order.
   Pinned to the header rather than hung off the input's right edge: the
   input has shrunk by here, and a 26rem panel anchored to its right edge
   starts to the left of the viewport, where nothing scrolls it back. */
@media (max-width: 1024px) {
  #search-results {
    position: fixed;
    top: calc(var(--jq-header-h) + 0.35rem);
    left: 1rem;
    right: 1rem;
    min-width: 0;
  }
}
