/* ============================================================================
   paper: the default okf-wiki theme
   ----------------------------------------------------------------------------
   Layout and prose, on the tokens in tokens.css and the faces in fonts.css.

   The class names here (site-header, breadcrumb-bar, sidebar, toc, callout-*,
   search-* including search-result-group, search-group-heading and search-scope,
   wiki-lbx-*) are the DOM contract. They are the ids the shared
   clients look for and the hooks Go writes into, so a theme that wants a
   different skin restyles them and a theme that wants a different layout
   replaces template.html. Changing a class name is a breaking change to the
   contract, not a style tweak.

   What this stylesheet expresses, from the design it is drawn from:

     - Pill-first controls. Search, the theme toggle, the mobile buttons and
       every chip share the pill radius, so the control set is recognisable from
       its silhouette before any colour loads.
     - Sentence case throughout. The design keeps no all-caps register, so the
       sidebar section labels and the contents summary are set in sentence case
       rather than as small capitals. Weight and colour, not case, carry the
       hierarchy.
     - Hairline before shadow. In light mode a raised surface keeps the page
       colour and the 1px rule does the work; in dark mode it is genuinely
       lighter than its ground. See tokens.css on why that is not the same
       system twice.
     - Focus is always visible, on every control, as a 2px ring at a 2px offset.
   ========================================================================== */
/* The token and font layers are linked before this file rather than @import-ed
   here: an @import is discovered only after this stylesheet parses, which made
   the browser wait on two serial round trips before it could paint. See the
   template's link tags. */

* { box-sizing: border-box; }

html { scroll-behavior: smooth; background: var(--color-bg); }

body {
  margin: 0;
  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-display);
  font-size: var(--text-body);
  line-height: var(--lh-normal);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

::selection { background: var(--color-selection-bg); color: var(--color-selection-fg); }

a { color: var(--color-accent-text); text-decoration: none; }

/* One focus treatment, everywhere, in both grounds. */
:focus-visible {
  outline: var(--focus-ring-width) solid var(--focus-ring);
  outline-offset: var(--focus-ring-offset);
  border-radius: var(--radius-sm);
}
:focus:not(:focus-visible) { outline: none; }

.wrap { max-width: 1400px; margin: 0 auto; padding: 0 var(--space-6); }

.skip-link {
  position: absolute; top: -100%; left: var(--space-4); z-index: var(--z-skip-link);
  padding: var(--space-2) var(--space-4);
  background: var(--color-accent); color: var(--color-on-accent);
  font-family: var(--font-ui); font-size: var(--text-sm); font-weight: var(--fw-semibold);
  border-radius: 0 0 var(--radius-md) var(--radius-md);
}
.skip-link:focus { top: 0; }

/* ------------------------------------------------------------------ header */
/* Sticky and blurred rather than elevated: the blur does the work a shadow
   would in a system that spent its elevation budget elsewhere. */
.site-header {
  position: sticky; top: 0; z-index: var(--z-header);
  background: color-mix(in srgb, var(--color-bg) 82%, transparent);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--color-line);
}
.header-inner { display: flex; align-items: center; justify-content: space-between; gap: var(--space-4); height: 72px; }

.brand { display: flex; align-items: center; gap: var(--space-2); color: var(--color-heading); white-space: nowrap; }
.brand-mark { flex-shrink: 0; border-radius: var(--radius-sm); }

.wordmark {
  font-family: var(--font-display); font-weight: var(--fw-bold);
  font-size: 1.2rem; letter-spacing: var(--ls-display); color: var(--color-heading);
}
.wordmark-dot { color: var(--color-accent-text); }

.brand-sub {
  font-family: var(--font-ui); font-size: var(--text-sm); font-weight: var(--fw-medium);
  color: var(--color-text-muted);
  border-left: 1px solid var(--color-line-strong); padding-left: var(--space-3);
}

/* The wordmark and an optional version tag, held together at the left end of
   the header so space-between still sends the controls to the right. */
.brand-cluster { display: flex; align-items: center; gap: var(--space-3); min-width: 0; }

/* A freeform version label beside the wordmark, drawn only when one is
   configured. A quiet pill, so it reads as metadata rather than part of the
   name, and tabular figures keep "v1.10" from jumping sideways next to "v1.9". */
.version-tag {
  font-family: var(--font-ui); font-size: var(--text-xs); font-weight: var(--fw-medium);
  font-variant-numeric: tabular-nums; line-height: 1; white-space: nowrap;
  color: var(--color-text-muted);
  background: var(--color-accent-soft);
  border: 1px solid var(--color-line);
  border-radius: var(--radius-pill);
  padding: 5px var(--space-3);
  /* The label is freeform, so it yields before it can push the controls off
     the bar: the pill shrinks and trims rather than widening the header. */
  min-width: 0; max-width: 40vw; overflow: hidden; text-overflow: ellipsis;
}

.nav-cluster { display: flex; align-items: center; gap: var(--space-2); }
/* The header's outbound links. None of them is ever "current", so they carry no
   fill at rest, and the hover signal is a rule under the label rather than a
   wash: the same accent the table of contents draws down the side for the
   section in view, laid along the bottom. That is what lets a row of them stay
   quiet where a row of chips would not. A hairline on the right sets the group
   apart from the search and theme controls, and it arrives with the list, since
   an empty nav renders nothing at all. */
.top-nav {
  display: flex; align-items: center; gap: var(--space-1);
  padding-right: var(--space-2); border-right: 1px solid var(--color-line);
}
.top-nav a {
  position: relative;
  display: inline-flex; align-items: center; min-height: 36px; padding: 0 var(--space-3);
  font-family: var(--font-ui); font-size: var(--text-sm); font-weight: var(--fw-medium);
  color: var(--color-text-muted);
  transition: color var(--dur) var(--ease);
}
.top-nav a::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 4px;
  height: 2px; border-radius: 1px; background: var(--color-accent-text);
  opacity: 0; transition: opacity var(--dur) var(--ease);
}
.top-nav a:hover, .top-nav a:focus-visible { color: var(--color-heading); }
.top-nav a:hover::after, .top-nav a:focus-visible::after { opacity: 1; }
/* Marks a link that leaves the wiki and opens in a new tab. */
.nav-ext { flex-shrink: 0; margin-left: 5px; color: var(--color-text-faint); }

/* Every control in the cluster is a pill, and none of them carries a border at
   rest: the pill outline is the control. A border is added only where a control
   needs to read as an input, and then it is --color-line-control, which clears
   3:1. */
.icon-btn {
  display: inline-flex; align-items: center; gap: var(--space-2); min-height: 36px;
  padding: 0 var(--space-3);
  background: transparent; border: 1px solid transparent; border-radius: var(--radius-pill);
  color: var(--color-text-muted);
  font-family: var(--font-ui); font-size: var(--text-sm); cursor: pointer;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.icon-btn:hover { color: var(--color-heading); background: var(--color-accent-soft); }
.search-btn-text { font-weight: var(--fw-medium); }
.search-btn-kbd { display: inline-flex; gap: 2px; }
.search-btn-kbd kbd, .icon-btn kbd {
  font-family: var(--font-code); font-size: 10px; padding: 1px 5px;
  border-radius: var(--radius-sm);
  background: var(--color-surface-sunken); border: 1px solid var(--color-line);
  color: var(--color-text-faint);
}
.theme-toggle { padding: 0 var(--space-2); }
.theme-toggle .icon-moon { display: none; }
:root[data-theme="dark"] .theme-toggle .icon-sun { display: none; }
:root[data-theme="dark"] .theme-toggle .icon-moon { display: block; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-toggle .icon-sun { display: none; }
  :root:not([data-theme="light"]) .theme-toggle .icon-moon { display: block; }
}

/* ----------------------------------------------------------- breadcrumb bar */
/* Sticky under the 72px header plus its 1px border; the two are coupled, so a
   header height change moves this top offset with it. */
.breadcrumb-bar {
  position: sticky; top: 73px; z-index: var(--z-sticky);
  background: var(--color-bg); border-bottom: 1px solid var(--color-line);
}
.breadcrumb-inner { display: flex; align-items: center; gap: var(--space-3); height: 40px; position: relative; }
.breadcrumb { display: flex; align-items: center; gap: var(--space-1); overflow-x: auto; scrollbar-width: none; white-space: nowrap; }
.breadcrumb::-webkit-scrollbar { display: none; }
.breadcrumb, .breadcrumb a { color: var(--color-text-muted); font-family: var(--font-ui); font-size: 13px; }
.breadcrumb a:hover { color: var(--color-accent-text); }
.crumb-sep { color: var(--color-line-strong); }
.crumb-cur { color: var(--color-heading); font-family: var(--font-ui); font-size: 13px; font-weight: var(--fw-medium); }
.crumb-ellipsis { color: var(--color-text-faint); }

.menu-btn {
  display: none; align-items: center; gap: var(--space-1);
  background: transparent; border: 1px solid transparent; color: var(--color-heading);
  padding: 6px var(--space-3); border-radius: var(--radius-pill); cursor: pointer;
  font-family: var(--font-ui); font-size: var(--text-xs); font-weight: var(--fw-medium);
  transition: background var(--dur) var(--ease);
  /* Touch target floor. This button only shows below 980px, so desktop is unaffected. */
  min-height: 44px; min-width: 44px; justify-content: center;
}
.menu-btn:hover { background: var(--color-accent-soft); }

/* ------------------------------------------------------------------ layout */
.layout {
  display: grid; grid-template-columns: 264px minmax(0, 1fr) 220px;
  gap: var(--space-12); padding-top: var(--space-8); padding-bottom: var(--space-16);
  align-items: start;
}
/* A page with no sidebar, such as a multi-site group index, drops the column
   rather than reserving an empty rail. A contents column still counts when the
   page has one. The two classes are deliberate: the layout's own rules sit in
   media queries below this one and would otherwise win at narrow widths. */
.layout.layout-solo { grid-template-columns: minmax(0, 1fr); }
.layout.layout-solo:has(.toc-aside) { grid-template-columns: minmax(0, 1fr) 220px; }
/* The reading column caps at 760px; the grid column itself keeps growing, so
   the prev/next cards span the column while the text stays readable. It also
   fills the viewport, so the cards sit at the foot of a short page instead of
   floating just under a few lines. The subtraction is the header, the
   breadcrumb bar, both one-pixel borders, and the layout's own padding, so a
   short page still fits without scrolling. */
.content {
  min-width: 0; width: 100%; max-width: 760px;
  display: flex; flex-direction: column;
  min-height: calc(100vh - 210px);
}

.drawer-backdrop {
  display: none; position: fixed; inset: 0;
  background: var(--color-scrim); z-index: var(--z-overlay); backdrop-filter: blur(3px);
}
.drawer-backdrop.open { display: block; }

/* ----------------------------------------------------------------- sidebar */
.sidebar {
  position: sticky; top: 132px; max-height: calc(100vh - 156px);
  overflow-y: auto; padding-right: var(--space-3);
}
.sidebar::-webkit-scrollbar { width: 4px; }
.sidebar::-webkit-scrollbar-thumb { background: var(--color-line-strong); border-radius: 2px; }

.side-sec { margin-bottom: var(--space-1); }
details.side-sec[open] { margin-bottom: var(--space-3); }

/* Sentence case, and the current section is a fill plus a weight step plus
   colour, never colour alone. */
details.side-sec summary.side-summary, .side-sec.side-leaf .side-summary {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-2);
  list-style: none; cursor: pointer; user-select: none;
  padding: var(--space-2) var(--space-2);
  border-radius: var(--radius-sm);
  transition: background var(--dur) var(--ease);
}
details.side-sec summary.side-summary::-webkit-details-marker { display: none; }
details.side-sec summary.side-summary:hover, .side-sec.side-leaf .side-summary:hover { background: var(--color-accent-soft); }

.side-title-link, .side-title-text {
  flex: 1;
  font-family: var(--font-ui); font-size: var(--text-sm); font-weight: var(--fw-semibold);
  color: var(--color-text-muted);
}
.side-title-link:hover { color: var(--color-heading); }
.side-title-link.active { color: var(--color-accent-text); }

.side-chevron { display: inline-flex; align-items: center; color: var(--color-text-faint); padding: 2px; }
.side-chevron svg { transition: transform var(--dur) var(--ease); transform: rotate(0deg); }
details.side-sec:not([open]) .side-chevron svg { transform: rotate(-90deg); }

.side ul { list-style: none; padding-left: var(--space-1); margin: var(--space-1) 0 0; }
.side li { margin: 1px 0; }
.side li a {
  display: block; font-family: var(--font-ui); font-size: var(--text-sm);
  color: var(--color-text-muted);
  padding: 6px var(--space-3); border-radius: var(--radius-sm); line-height: 1.4;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.side li a:hover { color: var(--color-heading); background: var(--color-accent-soft); }
/* Current position: a tinted fill, a weight step and colour together. Three
   signals, none of them load-bearing alone. */
.side li.active a {
  color: var(--color-accent-text); background: var(--color-current-tint);
  font-weight: var(--fw-semibold);
}

/* A sub-directory of a section, one level deep: a disclosure inside the
   section's list, so a bundle two directories deep reads as its folders rather
   than as a flat run of pages. Quieter than a section: a smaller summary at
   medium weight and no extra indent on the summary itself, so it stays aligned
   with its siblings. */
.side details.side-sub { margin: 1px 0; }
details.side-sub summary.side-subsum {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-2);
  list-style: none; cursor: pointer; user-select: none;
  padding: 6px var(--space-3); border-radius: var(--radius-sm);
  transition: background var(--dur) var(--ease);
}
details.side-sub summary.side-subsum::-webkit-details-marker { display: none; }
details.side-sub summary.side-subsum:hover { background: var(--color-accent-soft); }
.side-subsum a, .side-subsum span {
  flex: 1; font-family: var(--font-ui); font-size: var(--text-sm);
  font-weight: var(--fw-medium); color: var(--color-text-muted);
}
.side-subsum a:hover { color: var(--color-heading); }
.side-subsum a.active { color: var(--color-accent-text); }
details.side-sub:not([open]) .side-chevron svg { transform: rotate(-90deg); }
/* The group's pages hang off a hairline rule rather than a deep indent, so the
   third level reads as the group's leaves at any rail width: the rule sits under
   the group's text and the leaves carry one weight below it. */
.side details.side-sub > ul {
  margin: var(--space-1) 0 0 var(--space-3);
  padding-left: 0;
  border-left: 1px solid var(--color-line);
}
.side details.side-sub > ul li a { font-weight: var(--fw-regular); }
.side li.side-leaf a { color: var(--color-text-muted); }

/* The header's outbound links, carried in the drawer on a phone where the
   header has no room for a row of them. Hidden on desktop, which shows them in
   the header instead, so only one copy is ever in the accessibility tree. */
.side-links { display: none; }

/* ------------------------------------------------------------------ prose */
.prose { min-width: 0; line-height: 1.7; }

/* The page title is the design's display size: 36 to 48px, leading 1.05, and
   tracking tightened to match. The tightening is what stops a heading that
   large from looking loose. */
.prose h1 {
  font-family: var(--font-display); font-size: var(--text-h1);
  font-weight: var(--fw-bold); letter-spacing: var(--ls-display);
  line-height: var(--lh-tight); color: var(--color-heading);
  margin: 0 0 var(--space-3); text-wrap: balance;
}

.page-lead {
  font-family: var(--font-display); font-size: var(--text-lg);
  line-height: var(--lh-snug); color: var(--color-text-muted);
  max-width: var(--measure); margin: 0 0 var(--space-5); text-wrap: pretty;
}

.page-meta { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); margin: 0 0 var(--space-6); }
/* The page's own Markdown, offered for download. Pushed to the end of the meta
   row and dressed like a chip, so it reads as page metadata rather than a
   second run of controls under the title. Scoped under .prose to outrank the
   prose link style, like the chip links. */
.prose a.page-download {
  display: inline-flex; align-items: center; gap: var(--space-2);
  margin-left: auto;
  font-family: var(--font-ui); font-size: var(--text-xs); font-weight: var(--fw-medium);
  padding: 3px var(--space-3); border-radius: var(--radius-pill);
  border: 1px solid var(--color-line); background: var(--color-surface);
  color: var(--color-text-muted); text-decoration: none;
  transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.prose a.page-download:hover { color: var(--color-accent-text); border-color: var(--color-accent-ring); background: var(--color-accent-soft); }
.page-download-icon { flex-shrink: 0; }
/* Tags in the page head are raw text, not pills: the type chip already
   carries the pill, so the tags read as trailing metadata. Scoped under
   .prose to outrank the prose link style, like the chip links. */
.prose .tag-link {
  font-family: var(--font-ui); font-size: var(--text-xs);
  color: var(--color-text-muted); text-decoration: none;
}
.prose a.tag-link:hover { color: var(--color-accent-text); }
.chip {
  display: inline-flex; align-items: center;
  font-family: var(--font-ui); font-size: var(--text-xs); font-weight: var(--fw-medium);
  padding: 3px var(--space-3); border-radius: var(--radius-pill);
  border: 1px solid var(--color-line);
  color: var(--color-text-muted); background: var(--color-surface);
}
.chip-type {
  color: var(--color-accent-text); border-color: var(--color-accent-ring);
  background: var(--color-accent-soft); font-weight: var(--fw-semibold);
}
/* Tag chips are links to their tag page. They keep the chip look rather than
   the prose link look, so a row of them reads as metadata, not content. The
   .prose scope outranks .prose a, which would otherwise paint them as links. */
.prose a.chip { color: var(--color-text-muted); text-decoration: none; }
.prose a.chip:hover { color: var(--color-accent-text); border-color: var(--color-accent-ring); }
.prose a.chip[aria-current="true"] {
  color: var(--color-accent-text); border-color: var(--color-accent-ring);
  background: var(--color-accent-soft); font-weight: var(--fw-semibold);
}
/* The hash marks tag identity; the name carries the meaning. Muted everywhere
   it appears: chips, breadcrumbs, and tag headings. The heading rule scopes
   to pages holding a tag listing, so ordinary H1s starting with # are
   untouched. */
.tag-hash { color: var(--color-text-faint); }
/* Eyebrow above the title on synthetic pages, which have no section to speak
   through the breadcrumb alone. */
.kicker {
  font-family: var(--font-ui); font-size: var(--text-xs); font-weight: var(--fw-semibold);
  letter-spacing: 0.12em; text-transform: uppercase; color: var(--color-text-muted);
  margin: 0 0 var(--space-2);
}

/* ------------------------------------------------------- tag listing pages
   A tag page is a header (count, co-occurring tags), a control row, grouped
   rows, and the full catalogue. Everything below is structural: colours come
   from the chip and prose tokens above. */
.tag-muted { color: var(--color-text-muted); }
.tag-often { display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-2); }
.tag-all-link { margin-left: auto; font-family: var(--font-ui); font-size: var(--text-sm); }
.tag-controls {
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: var(--space-3); margin: var(--space-5) 0 var(--space-2);
}
.seg {
  display: inline-flex; gap: 2px; padding: 2px;
  border: 1px solid var(--color-line); border-radius: var(--radius-pill);
}
.seg button {
  border: 0; background: transparent; cursor: pointer;
  border-radius: var(--radius-pill); padding: 4px var(--space-3);
  min-height: 36px;
  font-family: var(--font-ui); font-size: var(--text-sm); color: var(--color-text-muted);
}
.seg button[aria-pressed="true"] {
  background: var(--color-accent-soft); color: var(--color-heading);
  font-weight: var(--fw-semibold);
}
.tag-check {
  display: inline-flex; align-items: center; gap: var(--space-2);
  min-height: 44px; cursor: pointer;
  font-family: var(--font-ui); font-size: var(--text-sm); color: var(--color-text-muted);
}
.tag-check input { accent-color: var(--color-accent-text); }
.tag-group { display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--space-2); }
.tag-group code { font-size: var(--text-sm); }
.tag-group .tag-muted { margin-left: auto; font-size: var(--text-sm); font-weight: var(--fw-regular); }
.tag-row { border-top: 1px solid var(--color-line); padding: var(--space-4) 0; }
/* The whole row navigates, so it shows a wash and a pointer on hover. The
   title keeps heading colour rather than link colour; the wash plus the
   pointer is the affordance, and the title link stays the keyboard path. */
.tag-row:hover { background: var(--color-surface-sunken); cursor: pointer; }
.tag-row:hover .tag-row-head > a { color: var(--color-accent-text); }
.tag-row-head { display: flex; align-items: baseline; justify-content: space-between; flex-wrap: wrap; gap: var(--space-2); }
.prose .tag-row-head > a {
  font-family: var(--font-ui); font-size: var(--text-body); font-weight: var(--fw-semibold);
  color: var(--color-heading); text-decoration: none;
}
.tag-badges { display: inline-flex; flex-wrap: wrap; gap: var(--space-2); }
.tag-row-meta { color: var(--color-text-muted); font-size: var(--text-sm); }
.tag-all { display: flex; flex-wrap: wrap; gap: var(--space-2); }

/* Section headings sit one step below the title: 22px semibold with a full
   48px of air above, so sections read as units rather than continuations. */
.prose h2 {
  font-family: var(--font-display); font-size: 1.375rem; font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-snug); line-height: 1.2; color: var(--color-heading);
  margin: var(--space-12) 0 0.55em; padding-bottom: var(--space-2);
  border-bottom: 1px solid var(--color-line);
  scroll-margin-top: 132px; text-wrap: balance;
}
.prose h3 {
  font-family: var(--font-display); font-size: var(--text-h3); font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-snug); color: var(--color-heading);
  margin: 1.7em 0 0.4em; scroll-margin-top: 132px; text-wrap: balance;
}
.prose h4 {
  font-family: var(--font-ui); font-size: var(--text-body); font-weight: var(--fw-semibold);
  color: var(--color-heading); margin: 1.4em 0 0.35em;
}

.prose p { margin: 0 0 1.1em; max-width: var(--measure); overflow-wrap: anywhere; text-wrap: pretty; }
/* Prose fills the 760px reading column; the 68ch measure stays in tokens for
   themes that reference it, but this theme reads at the column width. */
.prose p, .prose ul, .prose ol, .page-lead { max-width: 100%; }
.prose a {
  color: var(--color-accent-text);
  text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 2px;
  text-decoration-color: color-mix(in srgb, var(--color-accent-text) 35%, transparent);
}
.prose a:hover { text-decoration-color: var(--color-accent-text); }
.prose strong { color: var(--color-heading); font-weight: var(--fw-semibold); }

.prose ul, .prose ol { margin: 0 0 1.1em; padding-left: 1.4em; max-width: var(--measure); }
.prose li { margin-bottom: 0.3em; line-height: var(--lh-relaxed); }
.prose li::marker { color: var(--color-accent-text); }
.prose hr { border: none; border-top: 1px solid var(--color-line); margin: 2.4em 0; }
.prose img { max-width: 100%; height: auto; border-radius: var(--radius-lg); }
.prose mark { background: var(--color-mark); color: var(--color-mark-ink); padding: 0 0.15em; border-radius: 3px; }

.prose code {
  font-family: var(--font-code); font-size: 0.875em; font-variant-numeric: tabular-nums;
  background: var(--color-inline-code-bg); color: var(--color-inline-code-fg);
  padding: 2px 6px; border-radius: var(--radius-sm); overflow-wrap: anywhere;
}
.prose blockquote:not(.callout) {
  border-left: 2px solid var(--color-accent-text);
  padding: var(--space-3) var(--space-4); margin: 1.3em 0;
  color: var(--color-text-muted); background: var(--color-surface-sunken);
  border-radius: 0 var(--radius-md) var(--radius-md) 0;
}

/* -------------------------------------------------------------- GFM tables */
.prose table { width: 100%; border-collapse: collapse; font-size: 0.9rem; margin: 1.3em 0; display: block; overflow-x: auto; }
.prose thead th {
  text-align: left; font-family: var(--font-ui); font-size: var(--text-xs);
  font-weight: var(--fw-semibold); color: var(--color-text-muted);
  padding: var(--space-2) var(--space-3);
  border-bottom: 1px solid var(--color-line-strong); white-space: nowrap;
}
.prose tbody td { padding: var(--space-2) var(--space-3); border-bottom: 1px solid var(--color-line); vertical-align: top; }
.prose tbody tr:hover { background: var(--color-accent-soft); }

/* ------------------------------------------------------------------- TOC */
.toc {
  margin: 0 0 var(--space-6);
  border: 1px solid var(--color-line); border-radius: var(--radius-lg);
  background: var(--color-surface);
}
.toc > summary {
  cursor: pointer; list-style: none;
  padding: var(--space-3) var(--space-4);
  font-family: var(--font-ui); font-size: var(--text-sm); font-weight: var(--fw-semibold);
  color: var(--color-text-muted);
  transition: color var(--dur) var(--ease);
}
.toc > summary::-webkit-details-marker { display: none; }
.toc > summary:hover { color: var(--color-accent-text); }
.toc ul { list-style: none; margin: 0; padding: var(--space-1) var(--space-4) var(--space-3); }
.toc li { margin: 1px 0; }
.toc a { display: block; font-family: var(--font-ui); font-size: var(--text-sm); color: var(--color-text-muted); padding: 4px 0; }
.toc a:hover { color: var(--color-accent-text); }

/* Section headings carry a # permalink, revealed on hover and focus. The
   link is client-built, so without JS the headings are simply unlinked. */
.prose h2 .heading-anchor {
  color: var(--color-text-faint); text-decoration: none; font-weight: var(--fw-regular);
  margin-left: var(--space-2); opacity: 0;
  transition: opacity var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.prose h2:hover .heading-anchor, .prose h2 .heading-anchor:focus-visible { opacity: 1; }
.prose h2 .heading-anchor:hover { color: var(--color-accent-text); }

/* A citation that resolves to a sources entry reads as a superscript
   reference number, so it sits in the line without breaking it. */
.prose .source-ref {
  font-size: 0.75em; vertical-align: super; text-decoration: none;
  padding: 0 0.1em;
}
/* The Sources list is a reference list, not prose: the signals after each
   entry are quieter than the title. */
.prose h2 + ol { padding-left: 1.4em; }
.prose h2 + ol li { margin-bottom: 0.5em; }

/* --------------------------------------------- table of contents, relocated
   The same list serves the sidebar column on wide screens and the dropdown
   panel below it. Both link to the same anchors, so rendering it twice
   introduces no duplicate ids. */
.toc-list { list-style: none; margin: 0; padding: 0; }
.toc-list li { margin: 1px 0; }
.toc-list a { display: block; font-family: var(--font-ui); font-size: var(--text-sm); color: var(--color-text-muted); padding: 4px 0; text-decoration: none; }
.toc-list a:hover { color: var(--color-accent-text); }
.toc-aside { position: sticky; top: 132px; max-height: calc(100vh - 156px); overflow-y: auto; }
.toc-aside-title {
  font-family: var(--font-ui); font-size: var(--text-xs); font-weight: var(--fw-semibold);
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--color-text-muted);
  margin: 0 0 var(--space-2);
}
.toc-aside .toc-list { border-left: 1px solid var(--color-line); }
.toc-aside .toc-list a { border-left: 2px solid transparent; margin-left: -1px; padding-left: var(--space-3); }
.toc-btn {
  display: none; align-items: center; gap: var(--space-1);
  /* Pushed to the far end of the bar: the button is the right-hand control,
     mirroring the hamburger on the left. */
  margin-left: auto;
  background: transparent; border: 1px solid transparent; color: var(--color-heading);
  padding: 6px var(--space-3); border-radius: var(--radius-pill); cursor: pointer;
  font-family: var(--font-ui); font-size: var(--text-xs); font-weight: var(--fw-medium);
  transition: background var(--dur) var(--ease);
}
.toc-btn:hover { background: var(--color-accent-soft); }
/* The panel is the drawer's surface in a smaller frame: same background, same
   hairline, same width, and the same square top corner where it meets the bar
   it hangs from. It is anchored to the bar's right edge, below the button. */
.toc-panel {
  /* right is measured from the padding box, so it repeats the bar's own inset
     to line the panel up with the button rather than the viewport edge. */
  position: absolute; top: 100%; right: var(--space-6);
  width: min(320px, 84vw); max-height: 60vh; overflow-y: auto;
  background: var(--color-bg-elevated); border: 1px solid var(--color-line);
  border-top: 0;
  border-radius: 0 0 var(--radius-lg) var(--radius-lg);
  box-shadow: var(--shadow-lg);
  padding: var(--space-4) var(--space-4) var(--space-5); z-index: var(--z-overlay);
}
.toc-panel[hidden] { display: none; }
.toc-panel .toc-list { border-left: 1px solid var(--color-line); }
.toc-panel .toc-list a {
  border-left: 2px solid transparent; margin-left: -1px;
  padding: 6px 0 6px var(--space-3);
}
/* The section in view carries the same left guard in both the rail and the
   panel, so the marker reads as one thing wherever it appears. */
.toc-panel .toc-list a.active,
.toc-aside .toc-list a.active {
  color: var(--color-heading); font-weight: var(--fw-semibold);
  border-left-color: var(--color-accent-text);
}

/* ------------------------------------------------------- previous and next
   Two cards following the section order. A lone card holds its side so the
   grid never collapses it across the column. The auto top margin takes any
   slack in a short reading column, and the padding keeps a fixed minimum
   distance from the prose when there is none. */
.prevnext { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-4); margin: auto 0 0; padding-top: var(--space-12); }
.prevnext-card {
  display: block; border: 1px solid var(--color-line); border-radius: var(--radius-lg);
  padding: var(--space-4) var(--space-5); text-decoration: none;
}
.prevnext-card:hover { border-color: var(--color-accent-ring); }
.prevnext-card:hover .prevnext-title { color: var(--color-accent-text); }
.prevnext-dir {
  display: block; font-family: var(--font-ui); font-size: var(--text-xs);
  font-weight: var(--fw-semibold); letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--color-text-muted); margin-bottom: var(--space-1);
}
.prevnext-title { display: block; font-family: var(--font-ui); font-weight: var(--fw-semibold); color: var(--color-heading); }
.prevnext-next { text-align: right; }
.prevnext > :only-child.prevnext-next { grid-column: 2; }

/* ------------------------------------------------------------ site catalog
   A multi-site group index. The wikis of a group lead as cards; the folders
   that hold wikis and other groups follow, compact, under their own heading, so
   a reader meets the destinations before the containers. Both borrow the
   previous/next card shape, so a group reads as one more page of the wiki
   family. */
.prose .site-list {
  list-style: none; padding: 0; margin: 0; max-width: 100%;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: var(--space-4);
}
.site-item {
  position: relative;
  display: flex; flex-direction: column;
  border: 1px solid var(--color-line); border-radius: var(--radius-lg);
  padding: var(--space-4) var(--space-5);
  transition: border-color var(--dur) var(--ease);
}
.site-item:hover { border-color: var(--color-accent-ring); }
.site-item:hover .site-name { color: var(--color-accent-text); }
.prose a.site-link {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-3);
  text-decoration: none;
}
/* The link stretches over the whole card, so a tap anywhere on a phone opens
   it. The link text stays the title and badge, so a screen reader names the
   card by its title rather than by the description. The focus ring sits on the
   overlay, so it circles the card rather than the title row. */
.prose a.site-link::after { content: ""; position: absolute; inset: 0; border-radius: var(--radius-lg); }
.prose a.site-link:focus-visible { outline: none; }
.prose a.site-link:focus-visible::after {
  outline: var(--focus-ring-width) solid var(--focus-ring);
  outline-offset: var(--focus-ring-offset);
}
.site-name {
  min-width: 0; line-height: var(--lh-normal);
  font-family: var(--font-ui); font-weight: var(--fw-semibold); color: var(--color-heading);
}
.site-badge {
  flex: none; font-family: var(--font-ui); font-size: var(--text-xs); font-weight: var(--fw-semibold);
  letter-spacing: 0.06em; text-transform: uppercase; padding: 2px var(--space-2);
  border-radius: var(--radius-pill); border: 1px solid var(--color-line); color: var(--color-text-muted);
}
.site-badge-wiki { color: var(--color-accent-text); border-color: var(--color-accent-ring); background: var(--color-accent-soft); }
/* In one column a card is a list item with nothing beside it, so its title and
   description size to their content: no reserved line and no clamp to cut a
   long one. The reserves and the clamps arrive with the second column, below. */
.prose .site-desc {
  margin: var(--space-2) 0 0; font-size: 0.95rem; color: var(--color-text-muted); max-width: 100%;
  line-height: var(--lh-relaxed);
}

/* A card holds a fixed slice of the row it sits in, so when cards sit side by
   side the title reserves two lines and the description three whatever they
   actually fill. That is what keeps a short card's text on the same lines as
   its taller neighbour's and holds every row to one height. The clamp cuts a
   longer line rather than letting it grow the card and break the row; three
   lines is where the description, the only preview of the wiki, stops looking
   abandoned and a typical two-to-three line one fits whole. The site grid turns
   to two columns at 568px, measured against the 260px minimum column plus the
   1rem gap, so this starts there: at 567px the grid is still one column and a
   card keeps its full text. */
@media (min-width: 568px) {
  .site-name {
    display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
    overflow: hidden;
    min-height: calc(2 * var(--lh-normal) * 1em);
  }
  .prose .site-desc {
    display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3;
    overflow: hidden;
    min-height: calc(3 * var(--lh-relaxed) * 1em);
  }
}

/* The folders of a group, below the wikis. A lighter, denser list than the wiki
   cards: a folder is a container on the way to a wiki, not a destination in
   itself, so it does not take a full card. */
.site-group { margin-top: var(--space-8); }
.prose .site-group-title {
  margin: 0 0 var(--space-3); padding: 0; border: 0;
  font-family: var(--font-ui); font-size: var(--text-xs); font-weight: var(--fw-semibold);
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--color-text-faint);
}
.prose .folder-list {
  list-style: none; padding: 0; margin: 0; max-width: 100%;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: var(--space-2) var(--space-3);
}
.folder-item { position: relative; }
.prose a.folder-link {
  display: grid; grid-template-columns: 1fr auto; align-items: baseline;
  column-gap: var(--space-2); padding: var(--space-2) var(--space-3);
  text-decoration: none; border-radius: var(--radius-md);
  transition: background var(--dur) var(--ease);
}
.folder-item:hover a.folder-link { background: var(--color-accent-soft); }
.folder-name { font-family: var(--font-ui); font-weight: var(--fw-medium); color: var(--color-heading); }
.folder-arrow {
  font-size: var(--text-sm); color: var(--color-text-faint);
  transition: transform var(--dur) var(--ease), color var(--dur) var(--ease);
}
.folder-item:hover .folder-arrow { color: var(--color-accent-text); transform: translateX(2px); }
.prose .folder-desc {
  grid-column: 1 / -1; margin: 0; font-size: var(--text-sm);
  color: var(--color-text-muted); max-width: 100%;
}

/* --------------------------------------------------------------- callouts */
/* A status family rather than five one-off cards: each callout kind is a tint, a
   line, and a label, and each label clears 4.5:1 on its own tint. */
.callout {
  border-radius: var(--radius-lg); padding: var(--space-4) var(--space-5);
  margin: 1.4em 0; font-size: 0.95rem; line-height: var(--lh-relaxed);
  color: var(--color-text);
  border: 1px solid var(--status-neutral-line);
  background: var(--status-neutral-tint);
  border-left: 3px solid var(--status-neutral-text);
}
.callout-title {
  display: flex; align-items: center; gap: var(--space-2); margin-bottom: var(--space-2);
  font-family: var(--font-ui); font-size: var(--text-sm); font-weight: var(--fw-semibold);
  color: var(--status-neutral-text);
}
.callout-icon { flex-shrink: 0; }
.callout-body > :last-child { margin-bottom: 0; }
.callout-body p, .callout-body ul, .callout-body ol { max-width: none; }
.callout-body code { background: color-mix(in srgb, currentColor 12%, transparent); color: inherit; }

.callout-note { background: var(--status-info-tint); border-color: var(--status-info-line); border-left-color: var(--status-info-text); }
.callout-note .callout-title { color: var(--status-info-text); }
.callout-tip { background: var(--status-success-tint); border-color: var(--status-success-line); border-left-color: var(--status-success-text); }
.callout-tip .callout-title { color: var(--status-success-text); }
.callout-important { background: var(--status-danger-tint); border-color: var(--status-danger-line); border-left-color: var(--status-danger-text); }
.callout-important .callout-title { color: var(--status-danger-text); }
.callout-warning, .callout-caution { background: var(--status-warn-tint); border-color: var(--status-warn-line); border-left-color: var(--status-warn-text); }
.callout-warning .callout-title, .callout-caution .callout-title { color: var(--status-warn-text); }

/* ------------------------------------------------------ code and Chroma ---- */
/* The code surface is dark in both grounds. See tokens.css for why. */
.prose pre.code {
  background: var(--color-code-bg); color: var(--color-code-fg);
  border: 1px solid var(--color-code-line);
  border-radius: var(--radius-lg); padding: var(--space-4) var(--space-5);
  overflow-x: auto; margin: 1.3em 0;
  font-family: var(--font-code); font-size: 13.5px; line-height: 1.7;
}
.prose pre.code code { background: none; border: none; padding: 0; color: inherit; font-size: inherit; }

.chroma .err { color: #FCA5A5; }
.chroma .lnlinks { outline: none; text-decoration: none; color: inherit; }
.chroma .lntd { vertical-align: top; padding: 0; margin: 0; border: 0; }
.chroma .lntable { border-spacing: 0; padding: 0; margin: 0; border: 0; }
.chroma .hl { background-color: #3A3A40; }
.chroma .lnt { white-space: pre; user-select: none; margin-right: 0.4em; padding: 0 0.4em; color: #7C7C85; }
.chroma .ln { white-space: pre; user-select: none; margin-right: 0.4em; padding: 0 0.4em; color: #8A8A93; }
.chroma .k, .chroma .kd, .chroma .kn, .chroma .kr, .chroma .kt, .chroma .nn { color: #F9A8D4; }
.chroma .kc, .chroma .kp, .chroma .no, .chroma .nl, .chroma .py, .chroma .nv, .chroma .vc, .chroma .vg, .chroma .vi, .chroma .vm, .chroma .ld, .chroma .sa, .chroma .dl, .chroma .se, .chroma .sh, .chroma .sr { color: #93C5FD; }
.chroma .nc, .chroma .ne { color: #FCD34D; font-weight: 600; }
.chroma .nd, .chroma .nf, .chroma .fm { color: #C4B5FD; font-weight: 600; }
.chroma .ni { color: #FCD34D; }
.chroma .nt { color: #86EFAC; }
.chroma .l, .chroma .s, .chroma .sb, .chroma .sc, .chroma .sd, .chroma .s2, .chroma .si, .chroma .sx, .chroma .s1, .chroma .ss, .chroma .m, .chroma .mb, .chroma .mf, .chroma .mh, .chroma .mi, .chroma .il, .chroma .mo { color: #BBF7D0; }
.chroma .o, .chroma .ow, .chroma .or { color: #F9A8D4; font-weight: 600; }
.chroma .c, .chroma .ch, .chroma .cm, .chroma .c1 { color: #8A8A93; font-style: italic; }
.chroma .cs, .chroma .cp, .chroma .cpf { color: #8A8A93; font-weight: 600; font-style: italic; }
.chroma .gd { color: #FCA5A5; background-color: #2A1710; }
.chroma .ge { font-style: italic; }
.chroma .gr { color: #FCA5A5; }
.chroma .gh { color: #93C5FD; font-weight: 600; }
.chroma .gi { color: #6EE7A8; background-color: #10231A; }
.chroma .go, .chroma .gp { color: #8A8A93; }
.chroma .gs { font-weight: 600; }
.chroma .gu { color: #93C5FD; }
.chroma .gt { color: #FCA5A5; }
.chroma .gl { text-decoration: underline; }
.chroma .w { color: #6B6B6B; }

/* ---------------------------------------------------------------- diagrams */
pre.mermaid {
  background: var(--color-surface-sunken); border: 1px solid var(--color-line);
  border-radius: var(--radius-lg); padding: var(--space-5); margin: 1.4em 0;
  text-align: center; overflow-x: auto;
  color: var(--color-text-muted); font-family: var(--font-ui); font-size: var(--text-sm);
}
/* The client sizes the drawing to fit its card, so the stylesheet only centres
   it. The viewer's clone is sized separately. */
pre.mermaid svg { height: auto; display: block; margin: 0 auto; }
pre.mermaid-fallback { color: var(--status-danger-text); text-align: left; white-space: pre-wrap; }

/* ---------------------------------------------------------- diagram cards
   A diagram is a card: a toolbar naming the type and carrying the zoom, copy
   and expand affordances, then the drawing in a scroll area. The drawing opens
   fitted to the card, so its whole shape is visible, and the zoom buttons grow
   it into the scroll area; the card caps the height so a tall one scrolls
   rather than taking the page. */
.mermaid-frame {
  position: relative; margin: var(--space-6) 0;
  border: 1px solid var(--color-line); border-radius: var(--radius-lg);
  background: var(--color-surface); overflow: hidden;
}
.mermaid-toolbar {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  border-bottom: 1px solid var(--color-line);
  background: var(--color-surface-sunken);
  font-family: var(--font-ui); font-size: var(--text-xs);
}
.mermaid-type { color: var(--color-text-muted); font-weight: var(--fw-medium); }
.mermaid-actions { display: inline-flex; align-items: center; gap: var(--space-1); }
/* Zoom first, a hairline, then copy and expand: two groups rather than five
   buttons in a row. */
.mermaid-zoom {
  display: inline-flex; align-items: center; gap: 2px;
  padding-right: var(--space-2); border-right: 1px solid var(--color-line);
}
.mermaid-copy, .mermaid-expand, .mermaid-zoom-out, .mermaid-zoom-in {
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; padding: 0;
  background: transparent; border: 1px solid transparent; border-radius: var(--radius-md);
  color: var(--color-text-muted); cursor: pointer;
  transition: color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
.mermaid-copy:hover, .mermaid-expand:hover, .mermaid-zoom-out:hover, .mermaid-zoom-in:hover {
  color: var(--color-accent-text); border-color: var(--color-accent-ring);
  background: var(--color-bg-elevated);
}
.mermaid-zoom-pct {
  min-width: 44px; height: 30px; padding: 0 var(--space-2);
  background: transparent; border: 1px solid transparent; border-radius: var(--radius-md);
  color: var(--color-text-muted); cursor: pointer;
  font-family: var(--font-ui); font-size: var(--text-xs); font-variant-numeric: tabular-nums;
  transition: color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
.mermaid-zoom-pct:hover {
  color: var(--color-accent-text); border-color: var(--color-accent-ring);
  background: var(--color-bg-elevated);
}
/* Copy feedback without text: the button takes the accent ring on success
   and the danger ring on failure. */
.mermaid-actions[data-copy="ok"] .mermaid-copy { color: var(--color-accent-text); border-color: var(--color-accent-ring); }
.mermaid-actions[data-copy="fail"] .mermaid-copy { color: var(--status-danger-text); border-color: var(--status-danger-text); }
/* The drawing's scroll area. Height is capped so a tall diagram stays a card,
   and it scrolls once a zoomed drawing outgrows it. */
.mermaid-frame pre.mermaid { margin: 0; max-height: 560px; overflow: auto; }
.mermaid-frame pre.mermaid svg { display: block; }
/* One type size across every diagram type. Mermaid's sequence renderer writes
   its own font size inline from a snapshot of its defaults, so neither
   themeVariables nor the sequence config block reaches it and its message,
   note and actor text render a step larger than every other type. Pinned here
   rather than in the renderer, which cannot win against the inline style. */
.mermaid-frame .messageText, .mermaid-frame .noteText, .mermaid-frame .actor,
.mermaid-frame .loopText, .mermaid-frame .sequenceNumber,
.mermaid-frame .labelText, .mermaid-frame .actor-man {
  font-size: 14px !important;
}
pre.mermaid.mermaid-rendered { cursor: zoom-in; }
.mermaid-frame pre.mermaid[hidden] { display: none; }

/* A diagram that will not parse: a red card carrying the parser's message and
   the source, rather than an empty box. */
.mermaid-error { border-top: 0; padding: var(--space-4); }
.mermaid-error-head {
  font-family: var(--font-ui); font-size: var(--text-sm); font-weight: var(--fw-semibold);
  color: var(--status-danger-text); margin: 0 0 var(--space-1);
}
.mermaid-error-detail {
  font-family: var(--font-code); font-size: var(--text-xs);
  color: var(--color-text-muted); margin: 0 0 var(--space-3); overflow-wrap: anywhere;
}
.mermaid-error-source {
  margin: 0; padding: var(--space-3); overflow: auto;
  background: var(--color-surface-sunken); border-radius: var(--radius-md);
  border: 1px solid var(--status-danger-line);
  font-family: var(--font-code); font-size: var(--text-xs); color: var(--color-text);
}
.mermaid-frame:has(.mermaid-error) { border-color: var(--status-danger-line); background: var(--status-danger-tint); }
.mermaid-frame:has(.mermaid-error) .mermaid-toolbar { background: transparent; }

/* ------------------------------------------------- full-screen diagram view
   The viewer stages a diagram on a dark field in both grounds. It is a
   different surface from the page, so it borrows nothing from the page's
   neutrals and carries its own --lb-* tokens. */
.wiki-lbx {
  position: fixed; inset: 0; z-index: var(--z-lightbox);
  display: none; flex-direction: column;
  background: var(--lb-bg); font-family: var(--font-ui);
}
.wiki-lbx.is-open { display: flex; }
.wiki-lbx-bar {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-3);
  padding: var(--space-3) var(--space-4); padding-top: max(var(--space-3), env(safe-area-inset-top));
  flex: none; border-bottom: 1px solid var(--lb-line);
}
.wiki-lbx-id { display: flex; align-items: center; gap: var(--space-2); min-width: 0; }
.wiki-lbx-pill {
  font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase; font-weight: var(--fw-bold);
  flex: none; color: var(--lb-accent);
  background: color-mix(in srgb, var(--lb-accent) 14%, transparent);
  border: 1px solid var(--lb-accent-line); border-radius: var(--radius-pill);
  padding: 2px var(--space-2);
}
.wiki-lbx-title {
  font-family: var(--font-code); font-size: 12px; color: var(--lb-muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.wiki-lbx-ctrls { display: flex; align-items: center; gap: var(--space-2); flex: none; }
.wiki-lbx-btn {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 44px; height: 44px; padding: 0 var(--space-3);
  border-radius: var(--radius-md); border: 1px solid var(--lb-line);
  background: var(--lb-bar); color: var(--lb-text);
  cursor: pointer; font-family: var(--font-code); font-size: 12px;
  transition: background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.wiki-lbx-btn:hover { background: var(--color-surface-sunken-deep); border-color: var(--lb-line-strong); color: var(--lb-accent); }
.wiki-lbx-btn:active { transform: translateY(1px); }
.wiki-lbx-stage { position: relative; flex: 1; overflow: hidden; touch-action: none; cursor: grab; }
.wiki-lbx-stage.is-grabbing { cursor: grabbing; }
/* The clone has to lay out at the text size the card rendered at. Mermaid
   measured every label for the card's 14px, so at the viewer's larger base size
   a label outgrows the box drawn around it and is clipped. */
.wiki-lbx-content { position: absolute; left: 0; top: 0; transform-origin: 0 0; will-change: transform; font-size: var(--text-sm); }
.wiki-lbx-hint {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: var(--space-3) var(--space-4); padding-bottom: max(var(--space-3), env(safe-area-inset-bottom));
  text-align: center; color: var(--lb-hint); font-size: 11px; letter-spacing: 0.04em;
  pointer-events: none;
}

/* ------------------------------------------------------------------ search */
.search-modal-backdrop {
  position: fixed; inset: 0; z-index: var(--z-overlay); display: none;
  align-items: flex-start; justify-content: center;
  background: var(--color-scrim); backdrop-filter: blur(4px);
  padding: 12vh var(--space-4) var(--space-4);
}
.search-modal-backdrop.open { display: flex; }
.search-modal {
  width: 100%; max-width: 640px; background: var(--color-bg-elevated);
  border: 1px solid var(--color-line); border-radius: var(--radius-xl);
  box-shadow: var(--shadow-lg); overflow: hidden;
  display: flex; flex-direction: column; max-height: 70vh;
}
.search-modal-header {
  display: flex; align-items: center; gap: var(--space-3);
  padding: var(--space-3) var(--space-4); border-bottom: 1px solid var(--color-line);
}
.search-modal-icon { color: var(--color-text-faint); flex-shrink: 0; }
.search-input {
  /* A flex item's min-width defaults to auto, so an input's intrinsic size would
     floor the header and push the close control past the modal edge on a narrow
     viewport. */
  flex: 1; min-width: 0; border: none; outline: none; background: transparent;
  color: var(--color-heading); font-family: var(--font-ui); font-size: var(--text-body);
}
.search-input::placeholder { color: var(--color-text-faint); }
.search-close-btn { background: transparent; border: none; cursor: pointer; padding: 2px; }
.kbd-esc {
  font-family: var(--font-code); font-size: 10px; padding: 2px 6px;
  border-radius: var(--radius-sm); border: 1px solid var(--color-line);
  color: var(--color-text-faint);
}

.search-modal-body { overflow-y: auto; padding: var(--space-2); }
.search-empty-state { padding: var(--space-6) var(--space-4); color: var(--color-text-muted); font-size: var(--text-sm); text-align: center; }
.search-empty-hint { color: var(--color-text-faint); }
.search-quick-links { display: flex; flex-wrap: wrap; gap: var(--space-2); justify-content: center; margin-top: var(--space-3); align-items: center; }
.search-quick-links span { font-family: var(--font-ui); font-size: var(--text-xs); color: var(--color-text-faint); }
.search-quick-links a {
  font-family: var(--font-ui); font-size: var(--text-sm);
  padding: 4px var(--space-3); border: 1px solid var(--color-line);
  border-radius: var(--radius-pill); color: var(--color-text-muted);
}
.search-quick-links a:hover { border-color: var(--color-accent-ring); color: var(--color-accent-text); }

.search-result-item {
  display: block; padding: var(--space-3);
  border-radius: var(--radius-md); border: 1px solid transparent;
}
.search-result-item.selected, .search-result-item:hover {
  background: var(--color-accent-soft); border-color: var(--color-accent-ring);
}
.search-result-top {
  display: flex; align-items: center; gap: var(--space-1);
  font-family: var(--font-ui); font-size: var(--text-xs);
  color: var(--color-text-faint); margin-bottom: 2px;
}
.search-result-section { color: var(--color-accent-text); font-weight: var(--fw-semibold); }
.search-result-sep { color: var(--color-line-strong); }
.search-result-doc { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.search-result-title {
  display: flex; align-items: center; gap: var(--space-2);
  color: var(--color-heading); font-weight: var(--fw-medium); font-size: var(--text-sm);
}
.search-result-icon { color: var(--color-text-faint); flex-shrink: 0; }
.search-result-snippet { margin-top: var(--space-1); font-size: var(--text-xs); color: var(--color-text-muted); line-height: 1.5; }
.search-match { background: var(--color-mark); color: var(--color-mark-ink); border-radius: 3px; padding: 0 2px; }

.search-result-group + .search-result-group { margin-top: var(--space-2); }
.search-group-heading {
  padding: var(--space-2) var(--space-3) var(--space-1);
  font-family: var(--font-ui); font-size: var(--text-xs);
  font-weight: var(--fw-semibold); color: var(--color-text-muted);
}

.search-modal-footer {
  /* The scope toggle and the keyboard hints share one row on a wide modal and
     wrap to two on a phone, so the footer never scrolls horizontally. */
  display: flex; flex-wrap: wrap; gap: var(--space-3) var(--space-5);
  padding: var(--space-3) var(--space-4);
  border-top: 1px solid var(--color-line);
}
.search-scope {
  margin-right: auto; align-self: center; white-space: nowrap;
  font-family: var(--font-ui); font-size: var(--text-xs);
  padding: var(--space-1) var(--space-3);
  border: 1px solid var(--color-line); border-radius: var(--radius-pill);
  background: transparent; color: var(--color-text-muted); cursor: pointer;
}
.search-scope:hover { border-color: var(--color-accent-ring); color: var(--color-accent-text); }
.search-scope[aria-pressed="true"] {
  background: var(--color-accent-soft); border-color: var(--color-accent-ring);
  color: var(--color-accent-text);
}
.search-footer-hint { display: flex; align-items: center; gap: var(--space-1); font-size: var(--text-xs); color: var(--color-text-faint); }
.kbd-key {
  font-family: var(--font-code); font-size: 10px; padding: 1px 5px;
  border: 1px solid var(--color-line); border-radius: var(--radius-sm); color: var(--color-text-muted);
}

/* --------------------------------------------------------------- responsive */
/* Below the wide breakpoint the right column is gone: the aside hides and the
   breadcrumb button opens the same list as a panel. */
@media (max-width: 1180px) {
  .layout { grid-template-columns: 264px minmax(0, 1fr); }
  .toc-aside { display: none; }
  .toc-btn { display: inline-flex; }
}
@media (max-width: 860px) {
  .layout { grid-template-columns: 1fr; gap: 0; }
  .menu-btn { display: inline-flex; }
  .top-nav { display: none; }
  .search-btn-text, .search-btn-kbd { display: none; }
  .search-btn { padding: 0 var(--space-2); }
  /* Touch target floor for the header controls, which are icon-only at this width. */
  .icon-btn { min-height: 44px; min-width: 44px; justify-content: center; }
  .search-close-btn {
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 44px; min-height: 44px; padding: 0;
  }
  .sidebar {
    position: fixed; top: 0; left: 0; bottom: 0; width: min(320px, 84vw);
    max-height: none; z-index: var(--z-overlay);
    background: var(--color-bg-elevated); border-right: 1px solid var(--color-line);
    padding: var(--space-5) var(--space-4); overflow-y: auto;
    transform: translateX(-102%); transition: transform var(--dur-slow) var(--ease);
  }
  .sidebar.open { transform: translateX(0); }
  /* A phone drawer is narrower than the desktop rail, so the third level spends
     less on indentation and leans on the rule alone. */
  .side details.side-sub > ul { margin-left: var(--space-2); }
  .breadcrumb { flex: 1; }
  /* The header links move here on a phone, under a rule that sets them apart
     from the section navigation above them. */
  .side-links {
    display: block; margin-top: var(--space-5); padding-top: var(--space-4);
    border-top: 1px solid var(--color-line);
  }
  .side-links-title {
    margin: var(--space-4) 0 var(--space-2); font-family: var(--font-ui); font-size: var(--text-xs);
    font-weight: var(--fw-semibold); letter-spacing: 0.08em; text-transform: uppercase;
    color: var(--color-text-muted);
  }
  .side-links-title:first-child { margin-top: 0; }
  .side-links a {
    display: block; padding: 6px var(--space-3); border-radius: var(--radius-sm);
    font-family: var(--font-ui); font-size: var(--text-sm); color: var(--color-text-muted);
  }
  .side-links a:hover { color: var(--color-heading); background: var(--color-accent-soft); }
}
@media (max-width: 620px) {
  /* Only the horizontal inset narrows. The shorthand also resets the layout's
     own vertical padding to zero, which puts the first heading against the
     breadcrumb bar and the cards against the foot of the viewport. */
  .wrap { padding-left: var(--space-4); padding-right: var(--space-4); }
  .toc-panel { right: var(--space-4); }
  .brand-sub { display: none; }
  .search-modal-backdrop { padding-top: 6vh; }
  /* Diagram cards run edge to edge on a phone: the reading column's padding
     is dead space around a drawing that wants the width. */
  .mermaid-frame { margin-left: calc(var(--space-4) * -1); margin-right: calc(var(--space-4) * -1); border-radius: 0; border-left: 0; border-right: 0; }
  .prevnext { grid-template-columns: 1fr; }
  .prevnext-next { text-align: left; }
  .prevnext > :only-child.prevnext-next { grid-column: 1; }
  /* The design this theme comes from overflows a 320px viewport by 2px. Every
     fixed-width offender here is a padding or a fixed column, so this is the
     reflow guard rather than a second breakpoint. */
  .prose table, .prose pre.code { max-width: 100%; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { scroll-behavior: auto !important; transition: none !important; }
  .wiki-lbx-btn { transition: none; }
}

/* ------------------------------------------------------------------- print */
/* The page as a document: one column, ink on paper. Hidden here are the
   controls, the jumps and the links out of the page; kept together are the
   things that read badly when split: a heading and what follows it, a callout,
   a code block, a diagram, a table row. */
@media print {
  .site-header, .breadcrumb-bar, .sidebar, .search-modal-backdrop,
  .theme-toggle, .skip-link, .toc, .toc-aside, .toc-btn, .toc-panel,
  .mermaid-actions, .heading-anchor, .prevnext, .page-download, .tag-controls {
    display: none !important;
  }
  .layout, .content { display: block; max-width: none; min-height: 0; }
  .prose a { text-decoration: underline; }

  h1, h2, h3, h4, h5, h6 { break-after: avoid; break-inside: avoid; }
  p, li, dd { orphans: 3; widows: 3; }
  .callout, pre.code, figure, .mermaid-frame, tr, img { break-inside: avoid; }
  /* A table longer than a page still breaks, but its header repeats, so the
     columns stay named. The old rule kept whole tables together, which pushed
     a long one onto a fresh page and stranded the heading above it. */
  table { break-inside: auto; }
  thead { display: table-header-group; }
  /* The on-screen height cap is for scrolling, not for paper, and a diagram
     wider than the page is scaled to the paper rather than cut off at its
     edge. On screen it keeps its natural width and scrolls instead. */
  .mermaid-frame pre.mermaid { max-height: none; overflow: visible; }
  .mermaid-frame pre.mermaid svg { max-width: 100% !important; height: auto !important; }
  /* The code surface is dark on screen by design. On paper that is a slab of
     ink, and with background printing off its light syntax colours would be
     invisible, so a printed code block is a light block with ink text. */
  .prose pre.code { background: #F7F7F8 !important; border-color: #D4D4D4 !important; color: #1A1A1A !important; }
  .prose pre.code * { background: transparent !important; color: inherit !important; }
}
