/* ============================================================
   OpenHelvetia — layout «Bundesnah» (decision A2, 19.08.2026)
   Ported from drafts/bundesnah/ (the decided templates) into the
   generated site. Emitted as /assets/site.css next to
   /assets/tokens.css — the token file stays the single colour
   source: every colour here is a var(--oh-*) custom property.
   This file holds layout, typography and the register motifs
   that carry the identity: file-edge, ledger lines, zebra
   tables, two-weight wordmark, mono register apparatus.
   Binding token rules honoured here — #009688 (--oh-accent)
   only as accent on large elements/non-text UI, text links
   --oh-link or darker, grey secondary text on white only,
   amber only as a thin decorative marker. Measured ratios are
   documented in drafts/bundesnah/VARIANT.md.
   ============================================================ */
:root {
  --sans: "Helvetica Neue", Helvetica, Arial, system-ui, sans-serif;
  --mono: ui-monospace, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
}

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

/* Both grounds, so the browser paints its own furniture — scrollbars,
   form controls, the space beyond the page — to match the one in
   force. The palette that answers to each lives in tokens.css. */
html { color-scheme: light dark; }

[hidden] { display: none !important; }

body {
  margin: 0;
  background: var(--oh-paper);
  color: var(--oh-text);
  font-family: var(--sans);
  font-size: 1rem;
  line-height: 1.55;
  border-top: 4px solid var(--oh-accent); /* the file-edge motif */
  /* The footer sits at the foot of the screen even when the page is
     shorter than it (Jonathan, 02.09.): the body is at least one
     viewport tall and main takes what the content leaves. The chat
     page overrides this with a definite height (see .body-app). */
  min-height: 100vh; min-height: 100dvh;
  display: flex; flex-direction: column;
}
main { flex: 1 0 auto; }
/* A local preview tree announces itself by its edge colour: bordeaux
   here, teal on the public build (the fallback covers fixture token
   sets that predate the token). */
body.preview { border-top-color: var(--oh-preview-edge, #8c1c2c); }

.wrap { max-width: 72rem; margin-inline: auto; padding-inline: 1.25rem; }

/* --- Responsive foundations ------------------------------------ */
/* Form controls inherit the page's 1rem type. This is layout AND
   behaviour: iOS Safari zooms into any focused field below 16px, and
   a select's browser default is below it — inheriting removes the
   whole class of zoom jumps instead of patching fields one by one. */
input, select, textarea, button { font: inherit; }
img, svg { max-width: 100%; }

h1, h2, h3 { line-height: 1.15; margin: 0 0 0.6em; }
h2 { font-size: 1.375rem; }
h3 { font-size: 1.0625rem; }
p  { margin: 0 0 1em; }

a { color: var(--oh-link); text-underline-offset: 0.15em; }
a:visited { color: var(--oh-link); }
a:hover { color: var(--oh-link-hover); }

a, .btn, .chip, summary { transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease; }
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition-duration: 0.01ms !important; animation: none !important; scroll-behavior: auto !important; }
}

/* Keyboard focus: 2px ring, >= 3:1 on white and tint (5.91:1 min) */
:focus-visible { outline: 2px solid var(--oh-focus); outline-offset: 2px; }
main[tabindex="-1"]:focus { outline: none; } /* programmatic skip-link target */

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

/* --- Skip link ------------------------------------------------ */
.skip-link {
  position: absolute; left: 0.5rem; top: -100vh; z-index: 10;
  background: var(--oh-dark-1); color: var(--oh-paper);
  padding: 0.65rem 1rem; font-weight: 600; text-decoration: none;
}
.skip-link:visited { color: var(--oh-paper); }
.skip-link:focus { top: 0.5rem; }
.skip-link:focus-visible { outline: 3px solid var(--oh-ink); }

/* --- Header and navigation ----------------------------------- */
.site-header { background: var(--oh-paper); border-bottom: 1px solid var(--oh-line); }
.header-inner {
  display: flex; flex-wrap: wrap; align-items: center;
  justify-content: space-between; gap: 0.5rem 1.5rem; padding-block: 0.9rem;
}
.brand {
  display: inline-flex; align-items: center; gap: 0.6rem;
  font-size: 1.25rem; letter-spacing: -0.01em;
  text-decoration: none; color: var(--oh-text);
}
.brand:visited, .brand:hover { color: var(--oh-text); }
.brand-logo { display: inline-flex; color: var(--oh-accent); }
.brand-logo svg { width: 1.65rem; height: 1.65rem; display: block; }
.brand .strong { font-weight: 700; }
.site-nav ul { list-style: none; display: flex; flex-wrap: wrap; gap: 0.25rem; margin: 0; padding: 0; }
.site-nav a {
  display: inline-block; padding: 0.5rem 0.75rem;
  text-decoration: none; color: var(--oh-text); font-weight: 500;
  border-bottom: 2px solid transparent;
}
.site-nav a:visited { color: var(--oh-text); }
.site-nav a:hover { border-bottom-color: var(--oh-grey); color: var(--oh-text); }
.site-nav a[aria-current="page"] { font-weight: 700; border-bottom-color: var(--oh-accent); }

/* --- Burger menu (narrow screens, JavaScript only) -------------- */
/* Without JavaScript the .js-nav class never appears and the menu
   stays the plain wrapped list — collapsed-but-unopenable is the one
   state this must never produce. */
.nav-toggle {
  display: none; align-items: center; gap: 0.5rem;
  min-height: 2.75rem; padding: 0.4rem 0.75rem; font-weight: 600;
  border: 1px solid var(--oh-line); background: var(--oh-paper);
  color: var(--oh-text); cursor: pointer;
}
.nav-toggle-bars {
  display: inline-block; width: 1.1rem; height: 2px;
  background: var(--oh-text); position: relative;
}
.nav-toggle-bars::before, .nav-toggle-bars::after {
  content: ""; position: absolute; left: 0; width: 1.1rem; height: 2px;
  background: var(--oh-text);
}
.nav-toggle-bars::before { top: -5px; }
.nav-toggle-bars::after { top: 5px; }
@media (max-width: 40rem) {
  .nav-toggle:not([hidden]) { display: inline-flex; }
  .site-header.js-nav .site-nav { display: none; }
  .site-header.js-nav.nav-open .site-nav { display: block; flex-basis: 100%; }
  .site-header.js-nav.nav-open .site-nav ul { flex-direction: column; gap: 0; }
  .site-header.js-nav.nav-open .site-nav a { display: block; padding: 0.7rem 0.25rem; border-bottom: 1px solid var(--oh-line); }
}

/* --- Language switcher ---------------------------------------- */
/* The gear: one button in the header instead of a row of language
   links, opening a panel with the choices a visitor makes about the
   site itself (Jonathan, 31.08.). A `details` element, so it opens
   and closes with NO JavaScript — the language links inside it work
   for a visitor who has none, which is why they stayed plain links. */
.oh-gear {
  position: relative; margin: 0 0 0 0.75rem;
  /* The generic `details` rule above dresses a documentation
     disclosure — a bordered panel with a background. It matched this
     one too and drew a SQUARE around the round button inside it
     (Jonathan, 31.08.); the generic `summary` padding then squeezed
     the glyph to a dot. The gear is a control, not a disclosure
     panel, so it takes neither. */
  border: 0; background: transparent;
}
.oh-gear-button {
  display: inline-flex; align-items: center; justify-content: center;
  width: 2.75rem; height: 2.75rem; padding: 0; border-radius: 50%;
  border: 1px solid var(--oh-line); background: var(--oh-paper); color: var(--oh-text);
  cursor: pointer; list-style: none;
}
.oh-gear-button > svg { display: block; flex: none; }
/* Safari draws its own marker on a summary; both spellings remove it. */
.oh-gear-button::-webkit-details-marker { display: none; }
.oh-gear-button::marker { content: ""; }
.oh-gear-button:hover { background: var(--oh-surface-tint); }
.oh-gear-button:focus-visible { outline: 2px solid var(--oh-focus); outline-offset: 2px; }
.oh-gear[open] > .oh-gear-button { background: var(--oh-surface-tint); }
.oh-gear-panel {
  position: absolute; right: 0; top: calc(100% + 0.4rem); z-index: 30;
  min-width: 15rem; padding: 0.35rem;
  background: var(--oh-paper); border: 1px solid var(--oh-line); border-radius: 0.7rem;
  box-shadow: 0 6px 24px rgb(0 0 0 / 0.16);
}
.oh-gear-section { padding: 0.4rem 0.5rem; }
.oh-gear-section + .oh-gear-section { border-top: 1px solid var(--oh-line); }
.oh-gear-title {
  font-family: var(--mono); font-size: 0.6875rem; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--oh-text-secondary); margin: 0 0 0.35rem;
}
.oh-gear-choices { display: flex; gap: 0.25rem; }
.oh-gear-choices button {
  flex: 1; padding: 0.4rem 0.5rem; font: inherit; font-size: 0.8125rem;
  border: 1px solid var(--oh-line); border-radius: 0.45rem;
  background: var(--oh-paper); color: var(--oh-text); cursor: pointer;
}
.oh-gear-choices button:hover { background: var(--oh-surface-tint); }
/* The chosen ground is marked by weight and an edge, never by colour
   alone — the same rule the language switcher follows. */
.oh-gear-choices button[aria-pressed="true"] {
  font-weight: 700; border-color: var(--oh-accent); background: var(--oh-surface-tint);
}
.oh-gear-item {
  display: block; width: 100%; text-align: left; padding: 0.4rem 0.5rem;
  font: inherit; font-size: 0.8125rem; border: 0; border-radius: 0.45rem;
  background: transparent; color: var(--oh-link); cursor: pointer;
}
.oh-gear-item:hover { background: var(--oh-surface-tint); color: var(--oh-link-hover); }

.lang-switch ul, ul.lang-switch { list-style: none; display: flex; flex-wrap: wrap; gap: 0.25rem; margin: 0; padding: 0; }
.lang-switch a,
.lang-switch span[aria-current] { display: inline-block; padding: 0.5rem 0.6rem; font-weight: 500; }
.lang-switch a { color: var(--oh-link); }
.lang-switch a:visited { color: var(--oh-link); }
.lang-switch a:hover { color: var(--oh-link-hover); }
.lang-switch span[aria-current] {
  font-weight: 700; color: var(--oh-text);
  border-bottom: 2px solid var(--oh-accent); /* current = bold + edge, not colour alone */
}

/* --- Hero and page headers ------------------------------------ */
.hero { position: relative; padding-block: 3.5rem 2.75rem; }
/* Decorative brand mark, hero right — accent only as a large non-text
   element (token rule), faded far below any contrast duty. */
.hero-mark {
  position: absolute; right: 1.25rem; top: 50%; transform: translateY(-50%);
  color: var(--oh-accent); opacity: 0.08; pointer-events: none;
}
.hero-mark svg { width: clamp(13rem, 24vw, 20rem); height: auto; display: block; }
@media (max-width: 56rem) { .hero-mark { display: none; } }
.page-header { padding-block: 2.25rem 0.5rem; }
.page-header h1 { font-size: clamp(1.75rem, 4vw, 2.5rem); }
.eyebrow {
  font-family: var(--mono); font-size: 0.75rem;
  letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--oh-text-secondary); margin: 0 0 1rem;
}
.wordmark-hero { font-size: clamp(2.4rem, 6.5vw, 4.25rem); letter-spacing: -0.02em; font-weight: 400; margin: 0 0 0.35em; }
.wordmark-hero .light { font-weight: 300; }
.wordmark-hero .strong { font-weight: 700; }
.hero-title { font-size: clamp(1.9rem, 4.5vw, 3rem); letter-spacing: -0.02em; font-weight: 700; margin: 0 0 0.5em; max-width: 44rem; }
.lede { font-size: clamp(1.125rem, 2.2vw, 1.375rem); max-width: 44rem; margin-bottom: 0.75em; }
.intro { max-width: 44rem; }

/* Record line: the register's ledger voice (amber square = the one
   sparing amber use, a thin decorative marker, never text) */
.record-line {
  font-family: var(--mono); font-size: 0.8125rem; color: var(--oh-text-secondary);
  border-block: 1px solid var(--oh-line); padding: 0.55rem 0;
  margin: 1.25rem 0 1.75rem; max-width: 44rem;
}
.record-line::before {
  content: ""; display: inline-block; width: 0.45rem; height: 0.45rem;
  background: var(--oh-amber); margin-right: 0.55rem;
}
.record-line strong { color: var(--oh-text); font-weight: 700; }

.cta-row { display: flex; flex-wrap: wrap; align-items: center; gap: 0.75rem 1.5rem; }
.cta-link { display: inline-flex; align-items: center; min-height: 2.75rem; font-weight: 600; }
/* inline-block keeps the arrow outside the underline */
.cta-link span { display: inline-block; margin-left: 0.35rem; }
.btn {
  display: inline-flex; align-items: center; min-height: 2.75rem;
  padding: 0.5rem 1.25rem; font-weight: 600; text-decoration: none;
  border: 2px solid var(--oh-dark-1);
}
.btn-primary { background: var(--oh-dark-1); color: var(--oh-paper); }
.btn-primary:visited { color: var(--oh-paper); }
.btn-primary:hover { background: var(--oh-dark-2); border-color: var(--oh-dark-2); color: var(--oh-paper); }
.btn-secondary { background: transparent; color: var(--oh-dark-1); }
.btn-secondary:visited { color: var(--oh-dark-1); }
.btn-secondary:hover { color: var(--oh-dark-2); border-color: var(--oh-dark-2); }

/* --- Sections -------------------------------------------------- */
.section { padding-block: 2.5rem; border-top: 1px solid var(--oh-line); }
/* Full-bleed tint bands give the start page its rhythm; inside a band
   the section border is redundant and grey text is forbidden on tint
   (tokens.css) — the eyebrow switches to dark-1. */
.band-tint { background: var(--oh-surface-tint); }
.band-tint .section { border-top: 0; }
.band-tint .eyebrow { color: var(--oh-dark-1); }
.band-tint + .wrap.section { border-top: 0; }
.feature-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 1.5rem 2rem; margin-top: 1.5rem;
}
.feature {
  background: var(--oh-paper); border: 1px solid var(--oh-line);
  border-top: 2px solid var(--oh-accent);
  padding: 1.1rem 1.25rem 1.25rem;
}
.feature h3 { margin-bottom: 0.4em; }
.feature p { font-size: 0.9375rem; margin: 0; }

/* --- Start page: three entry cards, the about line ---------------- */
.start-section { padding-block: 0 2.75rem; border-top: 0; }
.start-grid {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: 1.25rem 1.5rem;
}
.start-card {
  position: relative; display: flex; flex-direction: column; gap: 0.5rem;
  background: var(--oh-paper); border: 1px solid var(--oh-line);
  border-top: 3px solid var(--oh-accent); padding: 1.25rem 1.4rem 1.3rem;
}
.start-card h3 { margin: 0; font-size: 1.375rem; }
.start-card h3 a { text-decoration: none; color: var(--oh-text); }
.start-card h3 a:visited { color: var(--oh-text); }
.start-card h3 a span { display: inline-block; margin-left: 0.4rem; transition: transform 0.15s ease; }
/* The whole card is the link: the heading's anchor is stretched over it. */
.start-card h3 a::after { content: ""; position: absolute; inset: 0; }
.start-card:hover { border-color: var(--oh-dark-1); border-top-color: var(--oh-accent); }
.start-card:hover h3 a { text-decoration: underline; text-underline-offset: 0.15em; }
.start-card:hover h3 a span { transform: translateX(0.2rem); }
.start-card:focus-within { outline: 2px solid var(--oh-focus); outline-offset: 2px; }
.start-card h3 a:focus-visible { outline: 0; }
.start-card p { margin: 0; font-size: 0.9375rem; }
.start-figure {
  margin-top: auto !important; padding-top: 0.75rem; border-top: 1px solid var(--oh-line);
  font-family: var(--mono); font-size: 0.8125rem; color: var(--oh-text-secondary);
  font-variant-numeric: tabular-nums;
}
.start-figure strong { color: var(--oh-text); }
.about-line .intro, .machine-line p { margin: 0; }
.machine-line { padding-block: 2rem; }
.machine-line p { font-family: var(--mono); font-size: 0.875rem; }
@media (prefers-reduced-motion: reduce) { .start-card h3 a span { transition: none; } }

/* --- Entry card (teaser) -------------------------------------- */
.entry-card {
  background: var(--oh-paper); border: 1px solid var(--oh-line);
  border-left: 4px solid var(--oh-accent);
  padding: 1.25rem 1.5rem; max-width: 44rem;
}
.entry-card h3 { margin-bottom: 0.15em; }
.entry-card .card-meta { font-size: 0.8125rem; color: var(--oh-text-secondary); margin: 0; }

.slug { font-family: var(--mono); font-size: 0.75rem; color: var(--oh-text-secondary); }

/* --- Chips (interface types, keywords) ------------------------ */
.chip-row { display: flex; flex-wrap: wrap; gap: 0.4rem; margin: 0.75rem 0; padding: 0; list-style: none; }
.chip {
  font-family: var(--mono); font-size: 0.75rem; letter-spacing: 0.05em;
  border: 1px solid var(--oh-dark-1); color: var(--oh-dark-1);
  padding: 0.15rem 0.5rem; white-space: nowrap;
}
.chip-neutral { border-color: var(--oh-grey); color: var(--oh-grey); } /* on white surfaces only */

/* --- Search (progressively enhanced on the directory page) ----- */
.search-block { margin: 1.5rem 0 2rem; max-width: 34rem; }
.search-block label { display: block; font-weight: 600; margin-bottom: 0.4rem; }
.search-block input {
  width: 100%; min-height: 2.75rem; padding: 0.5rem 0.75rem;
  font: inherit; color: var(--oh-text); background: var(--oh-paper);
  border: 1px solid var(--oh-grey); border-radius: 0;
}
.search-block input::placeholder { color: var(--oh-text-secondary); opacity: 1; }
.hint { font-size: 0.8125rem; color: var(--oh-text-secondary); margin: 0.4rem 0 0; }

/* --- Tables ---------------------------------------------------- */
.table-scroll { overflow-x: auto; background: var(--oh-paper); border: 1px solid var(--oh-line); }
table { border-collapse: collapse; width: 100%; font-size: 0.875rem; }
caption {
  text-align: left; font-family: var(--mono); font-size: 0.8125rem;
  color: var(--oh-text-secondary); padding: 0.75rem; border-bottom: 1px solid var(--oh-line);
  background: var(--oh-paper);
}
thead th {
  background: var(--oh-surface-tint); color: var(--oh-text);
  font-family: var(--mono); font-size: 0.75rem;
  text-transform: uppercase; letter-spacing: 0.06em;
  text-align: left; vertical-align: bottom;
  padding: 0.6rem 0.75rem; border-bottom: 2px solid var(--oh-ink);
}
td, tbody th {
  padding: 0.7rem 0.75rem; border-top: 1px solid var(--oh-line);
  text-align: left; vertical-align: top; font-weight: 400;
}
tbody tr:first-child td, tbody tr:first-child th { border-top: 0; }
tbody tr:nth-child(even) { background: var(--oh-surface-tint); }
/* JS re-striping after filtering (same specificity, later rules win) */
tbody tr.stripe-on { background: var(--oh-surface-tint); }
tbody tr.stripe-off { background: transparent; }
tbody .slug { color: var(--oh-dark-2); } /* grey never on tint: 8.41:1 on zebra rows */
tbody th .entry-name { font-weight: 600; }
td .chip-row { margin: 0; }
.desc-col { min-width: 22rem; max-width: 34rem; font-size: 0.8125rem; }
.org-col { font-size: 0.8125rem; min-width: 11rem; }
.license-col { font-size: 0.8125rem; min-width: 9rem; }
.nowrap { white-space: nowrap; }
.endpoint { font-family: var(--mono); font-size: 0.8125rem; word-break: break-all; }

.footnotes { font-size: 0.8125rem; color: var(--oh-text-secondary); margin-top: 0.75rem; max-width: 44rem; }
.footnotes p { margin: 0.25rem 0; }

/* --- Organisation sections (register ledger lists) ------------- */
.org-section h2 { margin-bottom: 0.2em; }
.entry-list { list-style: none; margin: 0.5rem 0 0; padding: 0; max-width: 44rem; }
.entry-list li {
  display: flex; flex-wrap: wrap; align-items: baseline;
  justify-content: space-between; gap: 0.25rem 1rem;
  border-top: 1px solid var(--oh-line); padding: 0.6rem 0;
}
.entry-list li:last-child { border-bottom: 1px solid var(--oh-line); }

/* --- Path/pointer list (standard page apparatus) --------------- */
.path-list { list-style: none; margin: 0.75rem 0 0; padding: 0; max-width: 44rem; }
.path-list li {
  display: flex; flex-wrap: wrap; align-items: baseline;
  justify-content: space-between; gap: 0.25rem 1rem;
  border-top: 1px solid var(--oh-line); padding: 0.5rem 0;
}
.path-list li:last-child { border-bottom: 1px solid var(--oh-line); }
.path-list code { font-family: var(--mono); font-size: 0.8125rem; }
.path-desc { font-size: 0.8125rem; color: var(--oh-text-secondary); }

/* --- Entry detail layout -------------------------------------- */
.breadcrumb { font-size: 0.8125rem; padding-top: 1.5rem; }
.breadcrumb ol { list-style: none; display: flex; flex-wrap: wrap; gap: 0.35rem; margin: 0; padding: 0; }
.breadcrumb li { display: flex; gap: 0.35rem; align-items: baseline; }
.breadcrumb .sep { color: var(--oh-text-secondary); }
.breadcrumb [aria-current="page"] { color: var(--oh-text-secondary); font-family: var(--mono); }

.entry-layout { display: grid; grid-template-columns: minmax(0, 2fr) minmax(16rem, 1fr); gap: 2.5rem; align-items: start; padding-block: 1.5rem 2.5rem; }
@media (max-width: 56rem) { .entry-layout { grid-template-columns: 1fr; } }

.title-alt { color: var(--oh-text-secondary); font-size: 1.0625rem; margin-top: -0.5em; }
.text-secondary { color: var(--oh-text-secondary); font-size: 0.9375rem; }

.meta-panel { background: var(--oh-paper); border: 1px solid var(--oh-line); border-left: 4px solid var(--oh-accent); padding: 1.25rem 1.5rem; }
.facts-panel { max-width: 44rem; margin-block: 1rem 2.5rem; }
.meta-panel h2 {
  font-family: var(--mono); font-size: 0.8125rem;
  text-transform: uppercase; letter-spacing: 0.08em; margin-bottom: 1rem;
}
.meta-panel dl { margin: 0; }
.meta-panel dt {
  font-family: var(--mono); font-size: 0.75rem;
  text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--oh-text-secondary); margin-top: 0.9rem;
}
.meta-panel dt:first-child { margin-top: 0; }
.meta-panel dd { margin: 0.15rem 0 0; font-size: 0.875rem; overflow-wrap: anywhere; }
.uri { font-family: var(--mono); font-size: 0.8125rem; }

/* --- Donation: the QR stage ----------------------------------- */
/* The symbol brings its own white ground (a Swiss QR Code stops
   scanning on a dark field), so the stage around it stays neutral
   and never paints behind it. */
.donate-stage {
  display: flex; flex-wrap: wrap; gap: 2rem; align-items: flex-start;
  background: var(--oh-paper); border: 1px solid var(--oh-line);
  padding: 1.5rem; margin-block: 1.5rem 2.5rem; max-width: 44rem;
}
.donate-symbol { flex: 0 0 auto; width: min(14rem, 62vw); }
.donate-symbol svg { display: block; width: 100%; height: auto; }
.donate-symbol figcaption {
  font-family: var(--mono); font-size: 0.75rem;
  color: var(--oh-text-secondary); margin-top: 0.6rem; text-align: center;
}
.donate-facts { flex: 1 1 17rem; min-width: 0; }
/* References and IBANs are read digit by digit against a bank
   statement — monospace keeps the blocks aligned between the page
   and the statement. */
.donate-facts dd.mono { font-family: var(--mono); overflow-wrap: anywhere; }

/* --- Raw manifest disclosure ---------------------------------- */
details { background: var(--oh-paper); border: 1px solid var(--oh-line); margin-top: 1rem; }
summary { cursor: pointer; padding: 0.8rem 1rem; font-weight: 600; }
summary:hover { background: var(--oh-surface-tint); }
details pre {
  margin: 0; padding: 1rem; border-top: 1px solid var(--oh-line);
  overflow-x: auto; font-family: var(--mono); font-size: 0.75rem; line-height: 1.5;
}

.back-link { margin-top: 2rem; }

/* --- Logo preview page (/{lang}/design/) ----------------------- */
.mark-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: 1.5rem 2rem; margin-top: 1.5rem;
}
.mark-card { border: 1px solid var(--oh-line); border-top: 2px solid var(--oh-accent); }
.mark-card h3 { padding: 0.75rem 1rem 0; margin-bottom: 0.15em; }
.mark-card .slug { display: block; padding: 0 1rem 0.5rem; }
.mark-stages { display: flex; }
.mark-stage {
  flex: 1; display: flex; align-items: center; justify-content: center;
  padding: 1.25rem 0.5rem;
}
.mark-stage img { width: 3rem; height: 3rem; max-width: 100%; }
.mark-stage-paper { background: var(--oh-paper); }
.mark-stage-tint { background: var(--oh-surface-tint); }
.mark-stage-deep { background: var(--oh-surface-deep); }
.mark-note { font-size: 0.8125rem; color: var(--oh-text-secondary); padding: 0.75rem 1rem; margin: 0; border-top: 1px solid var(--oh-line); }

/* --- Root forwarder (x-default) -------------------------------- */
.forwarder { padding-block: 3.5rem; max-width: 44rem; }

/* --- Footer band ----------------------------------------------- */
.site-footer { margin-top: 3.5rem; background: var(--oh-surface-deep); color: var(--oh-paper); padding-block: 2.25rem; }
.site-footer a { color: var(--oh-paper); }
.site-footer a:visited { color: var(--oh-paper); }
.site-footer a:hover { color: var(--oh-surface-tint); }
.site-footer :focus-visible { outline-color: var(--oh-surface-tint); }
.footer-brand { font-size: 1.125rem; color: var(--oh-paper); margin-bottom: 0.5rem; }
.footer-brand .strong { font-weight: 700; }
.footer-meta { font-size: 0.875rem; margin: 0 0 0.25rem; }
.footer-note { font-family: var(--mono); font-size: 0.75rem; color: var(--oh-surface-tint); margin: 0.75rem 0 0; }
.footer-nav ul { list-style: none; display: flex; flex-wrap: wrap; gap: 1.25rem; margin: 0.9rem 0 0; padding: 0; }
.footer-nav ul + ul { margin-top: 0.25rem; font-size: 0.875rem; opacity: 0.85; }
.footer-nav a { display: inline-block; padding: 0.35rem 0; }
/* Financing chapter: the donation symbol and the amount field (03.09.2026) */
.donation-form { margin: 0 0 1rem; max-width: 22rem; }
.donation-form p { margin: 0 0 0.75rem; }
.donation-form label { display: block; font-weight: 600; margin-bottom: 0.35rem; }
.donation-form input { width: 100%; min-height: 2.75rem; padding: 0.5rem 0.75rem; font: inherit; font-variant-numeric: tabular-nums; border: 1px solid var(--oh-line); border-radius: 0.3rem; background: var(--oh-paper); color: var(--oh-text); }
.donation-form input:focus-visible { outline: 2px solid var(--oh-focus); outline-offset: 2px; }
.donation-form .hint { margin: 0.4rem 0 0; font-size: 0.875rem; color: var(--oh-text-secondary); min-height: 1.3em; }
.donation-qr { margin: 0 0 1.25rem; }
.donation-qr img, .donation-qr svg { display: block; width: 14rem; max-width: 100%; height: auto; }
.docs .donation-qr img, .docs .donation-qr svg { margin: 0; }

/* ---- The chat page (BI) ---------------------------------------- */
/* The page is an APPLICATION: the document fills the viewport, the
   transcript scrolls inside its own column, the input row keeps the
   foot. The transcript borrows the site's plain vocabulary: bordered
   blocks, mono machine steps, three states with their own edges. */
/* **The chat page is bound to the viewport, and only it.**
   `min-height` was a MINIMUM: a flex column whose children want more
   room grows past the screen, so the DOCUMENT scrolled and the log
   never had to. Two things followed from that, both of them wrong —
   scrolling reached the end of the page instead of the end of the
   conversation, and the two openers, which are anchored inside the
   chat, scrolled away with it (Jonathan, 31.08.).

   A definite height gives `flex: 1; min-height: 0` something to
   divide, so the log scrolls inside itself and the header, the
   openers and the input bar stay where they are. `overflow: hidden`
   is the promise that the document itself never scrolls. This class
   is on the two chat pages and nowhere else; every other page of the
   site scrolls as a page should. */
.body-app {
  height: 100vh; height: 100dvh;
  overflow: hidden;
  display: flex; flex-direction: column;
}
.body-app main { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.chat-page { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.chat-app { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.chat-page > .chat-nojs, .chat-page > .chat-absent { margin: 1.5rem auto 0; width: min(44rem, calc(100% - 2.5rem)); }
.chat-app > .chat-loading { margin: 1.5rem auto 0; width: min(44rem, calc(100% - 2.5rem)); }

.chat-layout { flex: 1; min-height: 0; display: flex; position: relative; }

/* The sidebar: chats and settings. Hidden until its toggle opens it;
   the application opens it itself on wide screens. */
.chat-aside {
  display: none; flex-direction: column; min-height: 0;
  width: 17rem; flex-shrink: 0;
  border-right: 1px solid var(--oh-line); background: var(--oh-raised);
}
.chat-layout-aside-open .chat-aside { display: flex; }
.chat-aside-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 0.5rem; padding: 0.75rem 1rem; border-bottom: 1px solid var(--oh-line);
}
.chat-aside-title { font-size: 0.8125rem; font-family: var(--mono); text-transform: uppercase; letter-spacing: 0.08em; margin: 0; }
.chat-new {
  min-height: 2.25rem; padding: 0.25rem 0.85rem; font-weight: 600; font-size: 0.875rem;
  border: 1px solid var(--oh-dark-1); border-radius: 0.5rem;
  background: var(--oh-paper); color: var(--oh-dark-1); cursor: pointer;
  transition: background-color 0.15s ease, border-color 0.15s ease;
}
.chat-new:hover { background: var(--oh-surface-tint); }
.chat-list { list-style: none; margin: 0; padding: 0.5rem; overflow-y: auto; flex: 1; min-height: 0; display: flex; flex-direction: column; gap: 0.2rem; }
.chat-list li {
  display: flex; align-items: stretch;
  border: 1px solid transparent; border-radius: 0.55rem;
  transition: background-color 0.13s ease, border-color 0.13s ease;
}
.chat-list li:hover { border-color: var(--oh-line); background: var(--oh-paper); }
.chat-list li:has(.chat-list-item[aria-current="true"]) { border-color: var(--oh-dark-1); background: var(--oh-paper); }
.chat-list-item {
  flex: 1; min-width: 0; text-align: left; padding: 0.55rem 0.35rem 0.55rem 0.7rem;
  border: 0; background: transparent; color: var(--oh-text); cursor: pointer;
  font-size: 0.875rem; border-radius: 0.55rem;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.chat-list-item[aria-current="true"] { font-weight: 600; }
.chat-delete {
  border: 0; background: transparent; color: var(--oh-grey); cursor: pointer;
  padding: 0 0.6rem; font-size: 1rem; line-height: 1; border-radius: 0.55rem;
  opacity: 0; transition: opacity 0.13s ease;
}
/* Visible at rest, not only on hover: a touch screen has no hover, so
   a control that appears on it appears never. Quiet rather than
   hidden. */
.chat-delete { opacity: 0.45; }
.chat-list li:hover .chat-delete, .chat-delete:focus-visible { opacity: 1; }

/* The way back from a delete. It sits at the foot of the list, where
   the row was, and stands until it is used or replaced — no timer. */
.chat-undo {
  display: flex; align-items: baseline; justify-content: space-between; gap: 0.5rem;
  margin: 0.4rem 0.35rem 0; padding: 0.5rem 0.6rem;
  background: var(--oh-raised); border-radius: 0.55rem; font-size: 0.8125rem;
}
.chat-undo-title {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  color: var(--oh-text-secondary);
}
.chat-undo-button {
  flex: none; border: 0; background: transparent; padding: 0; cursor: pointer;
  color: var(--oh-link); text-decoration: underline; font-size: 0.8125rem;
}
.chat-undo-button:hover { color: var(--oh-link-hover); }
/* Still going. The dot pulses, and stands still for a visitor who
   asked for no motion (WCAG 2.3.3) — the mark carries the meaning,
   the motion only draws the eye. */
.chat-running { color: var(--oh-dark-1); margin-left: 0.35rem; font-size: 0.7rem; }
.chat-running > span[aria-hidden] { animation: oh-blink 1.4s ease-in-out infinite; display: inline-block; }
/* Its own name: `oh-pulse` already exists inside the reduced-motion
   block for the spinner, and two keyframes under one name is a bug
   waiting for the day the two want different numbers. */
@keyframes oh-blink { 0%, 100% { opacity: 1; } 50% { opacity: 0.25; } }
@media (prefers-reduced-motion: reduce) {
  .chat-running > span[aria-hidden] { animation: none; }
}
/* Touch devices know no hover — the control is always there. */
@media (hover: none) { .chat-delete { opacity: 1; } }
.chat-delete:hover { color: var(--oh-link-hover); }
.chat-aside .chat-setup-row label { min-width: 0; flex-basis: 100%; margin-bottom: -0.35rem; }
.chat-aside .chat-setup-row label:has(input[type="checkbox"]) { flex-basis: auto; margin-bottom: 0; }
.chat-aside-head .chat-aside-toggle { flex: 0 0 auto; }

/* On narrow screens the open sidebar is a drawer over the transcript. */
@media (max-width: 56rem) {
  .chat-layout-aside-open .chat-aside {
    position: absolute; inset-block: 0; left: 0; z-index: 5;
    width: min(19rem, 88%); box-shadow: 0 0 24px rgb(0 0 0 / 0.18);
  }
  /* **A drawer a tap outside closes.** On a 360px phone a rail at
     min(19rem, 88%) covers almost the whole screen, and the only way
     back was the small button it had covered. The scrim is what every
     phone drawer has and this one did not; it exists only where the
     rails ARE drawers, so the wide layout is untouched. */
  .chat-scrim {
    position: absolute; inset: 0; z-index: 4;
    background: rgb(0 0 0 / 0.28); border: 0; padding: 0; margin: 0;
    cursor: pointer;
  }
}
/* Above the breakpoint the rails sit in the layout and nothing is
   covered, so there is nothing to dismiss. */
@media (min-width: 56.0625rem) { .chat-scrim { display: none; } }

.chat-main { flex: 1; min-width: 0; min-height: 0; display: flex; flex-direction: column; position: relative; }
.chat-aside-toggle {
  display: inline-flex; align-items: center; justify-content: center;
  width: 2.5rem; height: 2.5rem; border: 1px solid var(--oh-line); border-radius: 0.5rem;
  background: var(--oh-paper); color: var(--oh-text); cursor: pointer;
}
.chat-aside-toggle:hover { background: var(--oh-surface-tint); }
/* With the sidebar closed, one floating opener — no permanent bar. */
.chat-open-aside { position: absolute; top: 0.6rem; left: 0.6rem; z-index: 4; box-shadow: 0 1px 4px rgb(0 0 0 / 0.08); }
.chat-burger { display: inline-block; width: 1.1rem; height: 2px; background: var(--oh-text); position: relative; }
.chat-burger::before, .chat-burger::after {
  content: ""; position: absolute; left: 0; width: 1.1rem; height: 2px; background: var(--oh-text);
}
.chat-burger::before { top: -5px; }
.chat-burger::after { top: 5px; }

/* The sources rail: the sidebar's right-hand mirror, holding only
   what the platform vouched for in this chat. */
.chat-sources {
  display: none; flex-direction: column; min-height: 0;
  /* The width is the visitor's, set inline and remembered; this is
     the fallback for a first visit and for a build without the
     application. */
  width: 16rem; flex-shrink: 0; position: relative;
  border-left: 1px solid var(--oh-line); background: var(--oh-raised);
}
/* The grip on the rail's LEFT edge — the rail is pinned right, so
   that is the edge that can move. Wider than the border it sits on,
   because a two-pixel target is a target only for a mouse. */
.chat-rail-grip {
  position: absolute; inset-block: 0; left: -3px; width: 9px; z-index: 6;
  cursor: col-resize; touch-action: none;
}
.chat-rail-grip:hover, .chat-rail-grip:focus-visible {
  background: color-mix(in srgb, var(--oh-accent) 45%, transparent);
  outline: none;
}
/* While the edge is held, the whole viewport tracks the pointer. */
.chat-rail-drag { position: fixed; inset: 0; z-index: 60; cursor: col-resize; }
/* Below the breakpoint the rail is a drawer at a width the layout
   chooses, so there is no edge to drag and the inline width must not
   fight the drawer's own. */
@media (max-width: 56rem) {
  .chat-rail-grip { display: none; }
  .chat-layout-sources-open .chat-sources { width: min(19rem, 88%) !important; }
}
.chat-layout-sources-open .chat-sources { display: flex; }
.chat-open-sources { position: absolute; top: 0.6rem; right: 0.6rem; z-index: 4; box-shadow: 0 1px 4px rgb(0 0 0 / 0.08); }
.chat-sources-empty { font-size: 0.8125rem; color: var(--oh-grey); margin: 0; padding: 0.75rem 1rem; }
.chat-source-list {
  list-style: none; margin: 0; padding: 0.5rem; overflow-y: auto;
  flex: 1; min-height: 0; display: flex; flex-direction: column; gap: 0.4rem;
}
.chat-source { margin: 0; border: 1px solid var(--oh-line); border-radius: 0.55rem; background: var(--oh-paper); }
.chat-source > summary { padding: 0.5rem 0.7rem; font-size: 0.8125rem; font-weight: 600; overflow-wrap: anywhere; }
.chat-source-number { font-family: var(--mono); color: var(--oh-text-secondary); }
.chat-source-body { padding: 0 0.7rem 0.6rem; font-size: 0.75rem; color: var(--oh-grey); }
.chat-source-body p { margin: 0.15rem 0 0; overflow-wrap: anywhere; }
.chat-source-body a { overflow-wrap: anywhere; }
.chat-source-tool { font-family: var(--mono); }
@media (max-width: 56rem) {
  .chat-layout-sources-open .chat-sources {
    position: absolute; inset-block: 0; right: 0; z-index: 5;
    width: min(19rem, 88%); box-shadow: 0 0 24px rgb(0 0 0 / 0.18);
  }
}

.chat-scroll { flex: 1; min-height: 0; overflow-y: auto; padding: 1rem 1.25rem; overscroll-behavior: contain; }
.chat-status {
  min-height: 1.25rem; font-size: 0.875rem; color: var(--oh-grey); margin: 0;
  padding: 0.25rem 1.25rem;
  display: flex; align-items: center; gap: 0.5rem;
}
/* What the wording check found: green when every quotation is in a
   text that was read, amber when one is not — and the amber case
   names the passages, because a count without them makes a reader
   distrust the whole answer. */
.chat-quotecheck { margin: 0.6rem 1.25rem 0; padding: 0.5rem 0.75rem; border-radius: 0.6rem; font-size: 0.8125rem; }
.chat-quotecheck p { margin: 0; }
.chat-quotecheck ul { margin: 0.35rem 0 0.35rem 1.1rem; padding: 0; }
.chat-quotecheck li { margin: 0.15rem 0; }
.chat-quotecheck-ok { background: var(--oh-tint); border-left: 3px solid var(--oh-dark-1); }
.chat-quotecheck-open {
  background: color-mix(in srgb, var(--oh-amber) 12%, var(--oh-paper));
  border-left: 3px solid var(--oh-amber);
}
/* Nothing with a wording was read, so nothing could be checked. That
   is an ABSENCE, not a failure — a figure is not a text — and dressing
   it in amber would be the same overclaim as the sentence it replaced
   (01.09.2026). Neutral, and it says why in its own words. */
.chat-quotecheck-none { background: var(--oh-raised); border-left: 3px solid var(--oh-line); }
.chat-quotecheck-unread { margin-top: 0.35rem; }

/* The verbatim text a source delivered, in the rail's card. */
.chat-source-verified { margin: 0 0 0.35rem; font-size: 0.75rem; color: var(--oh-dark-1); }
.chat-source-quote {
  margin: 0 0 0.5rem; padding: 0.5rem 0.6rem; max-height: 22rem; overflow: auto;
  background: var(--oh-raised); border-left: 3px solid var(--oh-dark-1);
  font-size: 0.8125rem; line-height: 1.45; white-space: pre-wrap; word-break: break-word;
}

/* The rows a data source delivered. A table, so it keeps its columns
   and scrolls in its own box rather than wrapping into soup; slightly
   tighter than a quotation, because there is more of it. */
.chat-source-rows {
  margin: 0 0 0.5rem; padding: 0.5rem 0.6rem; max-height: 22rem; overflow: auto;
  background: var(--oh-raised); border-left: 3px solid var(--oh-accent);
  font-family: var(--mono); font-size: 0.6875rem; line-height: 1.45;
  white-space: pre; tab-size: 2;
}

/* How the evidence was served. A recording is honest evidence and
   says so in the same breath — the rail must never let a fixture pass
   for a fetch from the Confederation. */
.chat-source-served { margin: 0 0 0.35rem; font-size: 0.75rem; color: var(--oh-grey); }

/* The command that re-fetches a source. Folded, because a reader who
   trusts the citation should not have to scroll past a SPARQL query
   to reach the next source — and open in one click for the reader who
   does not. It scrolls in its own box: a query is wide, the rail is
   narrow, and the page may not move sideways (WCAG 1.4.10). */
.chat-source-reproduce { margin: 0.35rem 0 0; font-size: 0.75rem; }
.chat-source-reproduce > summary { cursor: pointer; color: var(--oh-dark-1); }
.chat-source-command {
  margin: 0.35rem 0 0; padding: 0.5rem 0.6rem; max-height: 16rem; overflow: auto;
  background: var(--oh-raised); border-left: 3px solid var(--oh-dark-1);
  font-family: var(--mono); font-size: 0.75rem; line-height: 1.45;
  white-space: pre; -webkit-user-select: all; user-select: all;
}

/* A table inside an answer: it scrolls in its own box, never the
   page (WCAG 1.4.10), and its head stays readable while it does. */
.chat-table-scroll { overflow-x: auto; margin: 0.5rem 0; }
.chat-table { border-collapse: collapse; width: 100%; font-size: 0.9375rem; }
.chat-table th, .chat-table td {
  border-bottom: 1px solid var(--oh-line);
  padding: 0.35rem 0.6rem; text-align: left; vertical-align: top;
}
.chat-table th { font-weight: 600; white-space: nowrap; }

/* The turning ring while a question runs. Reduced motion gets a
   pulse instead of a rotation — the information is «something is
   happening», and that does not have to spin. */
.chat-spinner {
  flex: none; width: 0.9rem; height: 0.9rem; border-radius: 50%;
  border: 2px solid var(--oh-line); border-top-color: var(--oh-dark-1);
  animation: oh-spin 0.9s linear infinite;
}
@keyframes oh-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .chat-spinner { animation: oh-pulse 1.4s ease-in-out infinite; }
  @keyframes oh-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }
}

/* The standing disclaimer under the input (BI's page-level promise). */
.chat-disclaimer { margin: 0; padding: 0.25rem 1.25rem 0.6rem; font-size: 0.75rem; }

/* Example questions in the empty state: they fill the input, the
   visitor still sends. */
.chat-examples {
  max-width: 40rem; margin: auto; padding: 2rem 1.25rem;
  display: flex; flex-direction: column; gap: 0.6rem;
}
.chat-examples-title {
  margin: 0; text-align: center;
  font-size: 1.4rem; line-height: 1.25; font-weight: 700;
}
.chat-examples-lead {
  margin: 0 0 0.6rem; text-align: center;
  font-size: 0.9375rem; line-height: 1.5; color: var(--oh-text-secondary);
}
.chat-example {
  display: block; width: 100%; margin: 0; padding: 0.85rem 1rem;
  border: 1px solid var(--oh-line); border-radius: 0.9rem;
  background: var(--oh-surface-tint); color: inherit;
  font: inherit; font-size: 0.9375rem; line-height: 1.4;
  text-align: left; cursor: pointer;
  transition: border-color 0.15s ease, background-color 0.15s ease;
}
.chat-example:hover { border-color: var(--oh-dark-1); background: var(--oh-paper); }
.chat-example:focus-visible { outline: 2px solid var(--oh-focus); outline-offset: 2px; }
.chat-examples-note {
  margin: 0.8rem 0 0; text-align: center;
  font-size: 0.8125rem; line-height: 1.45; color: var(--oh-text-secondary);
}

/* The first-visit hint: one box above the input, one line down to
   the plus — the way to the key is shown, not guessed. */
.chat-hint {
  position: relative; z-index: 3;
  margin: 0 1.25rem 0.4rem; max-width: 22rem;
  padding: 0.7rem 0.95rem;
  border: 1px solid var(--oh-dark-1); border-radius: 0.75rem 0.75rem 0.75rem 0.25rem;
  background: var(--oh-surface-tint); font-size: 0.875rem;
}
.chat-hint p { margin: 0; }
.chat-hint p.chat-hint-title { font-weight: 600; margin-bottom: 0.2rem; padding-right: 1.5rem; }
.chat-hint-close {
  position: absolute; top: 0.35rem; right: 0.35rem;
  width: 1.6rem; height: 1.6rem; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border: 0; border-radius: 50%; background: transparent;
  color: var(--oh-text-secondary); font-size: 1rem; line-height: 1; cursor: pointer;
}
.chat-hint-close:hover { background: var(--oh-paper); color: var(--oh-dark-1); }

/* First-visit labels beside the two rail openers, a pointer each. */
.chat-opener-hint {
  position: absolute; top: 0.95rem; z-index: 4;
  margin: 0; padding: 0.3rem 0.4rem 0.3rem 0.6rem; font-size: 0.8125rem;
  display: inline-flex; align-items: center; gap: 0.25rem;
  border: 1px solid var(--oh-dark-1); border-radius: 0.5rem;
  background: var(--oh-surface-tint);
  box-shadow: 0 1px 4px rgb(0 0 0 / 0.08);
  white-space: nowrap;
}
.chat-opener-hint::before { content: ""; position: absolute; top: 50%; transform: translateY(-50%); border-block: 0.4rem solid transparent; }
.chat-opener-hint-left { left: 3.6rem; }
.chat-opener-hint-left::before { left: -0.45rem; border-right: 0.45rem solid var(--oh-dark-1); }
/* The sources label sits BELOW its button, pointing up — beside it,
   the two labels would collide on a phone's width. */
.chat-opener-hint-right { top: 3.55rem; right: 0.6rem; }
.chat-opener-hint-right::before {
  top: -0.45rem; right: 1rem; transform: none;
  border-block: 0; border-inline: 0.42rem solid transparent;
  border-bottom: 0.45rem solid var(--oh-dark-1);
}
/* The plus menu's label sits above its button, pointing down. */
.chat-menu-hint { top: auto; bottom: calc(100% + 0.55rem); left: 0; }
.chat-menu-hint::before {
  top: 100%; transform: none; left: 0.95rem;
  border: 0.42rem solid transparent; border-top-color: var(--oh-dark-1); border-bottom: 0;
}
.chat-hint-dismiss {
  width: 1.25rem; height: 1.25rem; padding: 0; border: 0; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: transparent; color: var(--oh-text-secondary);
  font-size: 0.9rem; line-height: 1; cursor: pointer;
}
.chat-hint-dismiss:hover { background: var(--oh-paper); color: var(--oh-dark-1); }

.chat-hint-arrow {
  position: absolute; left: 0.85rem; bottom: -2.25rem;
  color: var(--oh-dark-1); pointer-events: none;
}

/* The input bar: raised strip at the foot (ansV pattern), round
   symbol button beside the field. */
.chat-form {
  display: flex; gap: 0.6rem; align-items: flex-end;
  /* The home indicator of a modern phone sits over the bottom of the
     viewport, and the input bar sat under it. `viewport-fit=cover` in
     the page's viewport meta is what makes this function resolve at
     all; without that half it is zero everywhere and this line does
     nothing. */
  padding: 0.75rem 1.25rem calc(0.75rem + env(safe-area-inset-bottom));
  border-top: 1px solid var(--oh-line);
  background: var(--oh-raised);
}
/* The question field. It is a textarea that GROWS with what is typed
   — `field-sizing: content`, the same one line the bubble's field has
   used all along — because the page's own example question is a
   hundred and thirty characters and used to scroll out of sight the
   moment it was inserted. A browser without the declaration keeps a
   one-row field that scrolls, which is where this started.

   Scoped to the question and no longer to `.chat-form input`: that
   selector also matched the two hidden file pickers and gave them a
   2.75rem box inside the form. */
.chat-question {
  flex: 1; min-width: 0; min-height: 2.75rem; max-height: 11rem;
  padding: 0.5rem 1rem; resize: none; overflow-y: auto;
  border: 1px solid var(--oh-grey); border-radius: 0.5rem; background: var(--oh-paper);
  font: inherit; line-height: 1.4;
  field-sizing: content;
}
/* The ring is removed for the POINTER and kept for the keyboard: a
   focus a mouse gave needs no ring, a focus the Tab key gave is the
   only way that visitor knows where they are (WCAG 2.4.7). */
.chat-question:focus:not(:focus-visible) { border-color: var(--oh-dark-1); outline: none; }
.chat-question:focus-visible { border-color: var(--oh-dark-1); outline: 2px solid var(--oh-focus); outline-offset: 1px; }
.chat-send {
  flex: 0 0 auto; width: 2.75rem; height: 2.75rem; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 50%; border: 2px solid var(--oh-dark-1);
  background: var(--oh-dark-1); color: var(--oh-paper);
  cursor: pointer;
}
.chat-send svg, .chat-plus svg { display: block; }
.chat-send:hover { background: var(--oh-dark-2); border-color: var(--oh-dark-2); }
.chat-send[disabled] { opacity: 0.55; cursor: default; }
/* While a question runs, the send button IS the stop: same place,
   same size, a square instead of an arrow — the person is the only
   bound on a loop whose other bound is the context window. */
.chat-stop { background: var(--oh-paper); color: var(--oh-dark-1); }
.chat-stop:hover { background: var(--oh-tint); border-color: var(--oh-dark-2); }

/* The plus beside the input: uploads and settings, in a popover
   opening upward (ansV) or the sectioned dialog. */
.chat-settings { position: relative; display: inline-flex; flex: 0 0 auto; }
.chat-plus {
  width: 2.75rem; height: 2.75rem; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 50%; border: 1px solid var(--oh-grey);
  background: var(--oh-paper); color: var(--oh-text-secondary);
  cursor: pointer;
}
.chat-plus:hover, .chat-plus[aria-expanded="true"] { border-color: var(--oh-dark-1); color: var(--oh-dark-1); }
.chat-popover-backdrop { position: fixed; inset: 0; z-index: 40; border: 0; background: transparent; cursor: default; }
.chat-popover {
  position: absolute; bottom: calc(100% + 0.6rem); left: 0; z-index: 41;
  width: min(22rem, calc(100vw - 2rem));
  padding: 0.85rem 1rem; display: flex; flex-direction: column; gap: 0.15rem;
  background: var(--oh-paper); border: 1px solid var(--oh-line); border-radius: 0.5rem;
  box-shadow: 0 8px 28px rgb(0 0 0 / 0.16);
}
.chat-quickmenu { width: min(14rem, calc(100vw - 2rem)); padding: 0.4rem; }
.chat-quickmenu .chat-quickmenu-item {
  display: block; text-align: left; padding: 0.55rem 0.7rem; border: 0; border-radius: 0.4rem;
  background: transparent; color: var(--oh-text); font-size: 0.9rem; font-weight: 400; cursor: pointer;
}
.chat-quickmenu .chat-quickmenu-item:hover { background: var(--oh-surface-tint); }

/* Picked files above the input row. */
.chat-attach-row {
  display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem;
  padding: 0.35rem 1.25rem 0.5rem;
}
.chat-attach-chip {
  display: inline-flex; align-items: center; gap: 0.3rem;
  font-family: var(--mono); font-size: 0.75rem; color: var(--oh-text);
  border: 1px solid var(--oh-line); border-radius: 999px; padding: 0.2rem 0.35rem 0.2rem 0.7rem;
  background: var(--oh-raised);
}
.chat-attach-remove {
  border: 0; background: transparent; color: var(--oh-grey); cursor: pointer;
  padding: 0 0.25rem; font-size: 0.9rem; line-height: 1;
}
.chat-attach-remove:hover { color: var(--oh-link-hover); }
.chat-attach-row .chat-detail { margin: 0; flex-basis: 100%; font-size: 0.75rem; }

/* The settings dialog, sectioned like an application's. */
.chat-modal-backdrop { position: fixed; inset: 0; z-index: 50; border: 0; background: rgb(0 0 0 / 0.45); cursor: default; }
.chat-modal {
  position: fixed; inset: 0; margin: auto; z-index: 51;
  width: min(42rem, calc(100vw - 2rem)); height: min(30rem, calc(100vh - 4rem));
  display: flex; flex-direction: column; overflow: hidden;
  background: var(--oh-paper); border: 1px solid var(--oh-line); border-radius: 0.75rem;
  box-shadow: 0 24px 60px rgb(0 0 0 / 0.25);
}
.chat-modal-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 0.85rem 1.25rem; border-bottom: 1px solid var(--oh-line);
}
.chat-modal-head h2 { margin: 0; font-size: 1.0625rem; }
.chat-modal-close {
  width: 2.25rem; height: 2.25rem; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--oh-line); border-radius: 50%;
  background: var(--oh-paper); color: var(--oh-text-secondary);
  font-size: 1.1rem; line-height: 1; cursor: pointer;
}
.chat-modal-close:hover { border-color: var(--oh-dark-1); color: var(--oh-dark-1); }
.chat-modal-split { flex: 1; min-height: 0; display: flex; }
.chat-modal-nav {
  width: 11rem; flex-shrink: 0; padding: 0.5rem;
  display: flex; flex-direction: column; gap: 0.15rem;
  border-right: 1px solid var(--oh-line); background: var(--oh-raised);
  overflow-y: auto;
}
.chat-modal-nav button {
  text-align: left; padding: 0.5rem 0.7rem; border: 0; border-radius: 0.4rem;
  background: transparent; color: var(--oh-text); font-size: 0.875rem; cursor: pointer;
}
.chat-modal-nav button:hover { background: var(--oh-paper); }
.chat-modal-nav button[aria-current="true"] { background: var(--oh-paper); font-weight: 600; box-shadow: inset 3px 0 0 var(--oh-accent); }
.chat-modal-body { flex: 1; min-width: 0; overflow-y: auto; padding: 1rem 1.25rem; }
.chat-modal-body p { max-width: 34rem; }
.chat-danger {
  padding: 0.5rem 0.9rem; font-weight: 600; font-size: 0.875rem;
  border: 1px solid var(--oh-red); border-radius: 0.5rem;
  background: var(--oh-paper); color: var(--oh-red); cursor: pointer;
}
.chat-danger:hover { background: rgb(187 34 51 / 0.06); }
@media (max-width: 40rem) {
  .chat-modal { height: min(34rem, calc(100vh - 2rem)); width: calc(100vw - 1rem); }
  .chat-modal-split { flex-direction: column; }
  .chat-modal-nav { width: auto; flex-direction: row; overflow-x: auto; border-right: 0; border-bottom: 1px solid var(--oh-line); }
  .chat-modal-nav button { white-space: nowrap; }
  .chat-modal-nav button[aria-current="true"] { box-shadow: inset 0 -3px 0 var(--oh-accent); }
}
.chat-popover .chat-setup-row label { min-width: 0; flex-basis: 100%; margin-bottom: -0.35rem; font-weight: 600; }
.chat-popover .chat-setup-row label:has(input[type="checkbox"]) { flex-basis: auto; margin-bottom: 0; font-weight: 400; }
.chat-popover .chat-setup-row select { width: 100%; }

.chat-disclaimer { font-weight: 600; margin-top: 0.5rem; }
.chat-detail { font-size: 0.875rem; color: var(--oh-grey); }
.chat-setup { border: 1px solid var(--oh-line); padding: 0.75rem 1rem; margin-bottom: 1rem; }
.chat-setup summary { cursor: pointer; font-weight: 600; padding: 0; }
.chat-setup summary:hover { background: transparent; color: var(--oh-link-hover); }
/* The prose disclosure (key & privacy) inherits the generic details
   box, whose only padded child is the summary — pad the prose too. */
.chat-setup-prose p { padding: 0 1rem; }
.chat-setup-prose p:last-child { padding-bottom: 0.8rem; }
.chat-setup-row { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem 0.75rem; margin: 0.6rem 0; }
.chat-setup-row label { font-weight: 600; min-width: 7.5rem; }
.chat-setup-row label:has(input[type="checkbox"]) { font-weight: 400; min-width: 0; }
.chat-setup-row input[type="password"],
.chat-setup-row input[type="text"] { flex: 1 1 16rem; font-family: var(--mono); padding: 0.4rem 0.5rem; border: 1px solid var(--oh-grey); border-radius: 0.5rem; }
.chat-setup-row select { padding: 0.45rem 0.5rem; border: 1px solid var(--oh-grey); border-radius: 0.5rem; background: var(--oh-paper); max-width: 100%; }
.chat-setup-row .chat-detail { flex-basis: 100%; margin: 0; }

.chat-log { display: flex; flex-direction: column; gap: 0.75rem; margin: 0 0 0.75rem; }
.chat-log:empty { margin: 0; }
/* Bubbles borrow ansV's shape language: the visitor's question is an
   accent bubble on the right, the model's answer a bordered card on
   the left — white on dark-1 is 7.16:1, any text size. */
.chat-bubble { padding: 0.7rem 1rem; max-width: 85%; }
.chat-bubble > p:last-child { margin-bottom: 0; }
.chat-you {
  align-self: flex-end;
  background: var(--oh-dark-1); color: var(--oh-paper);
  border: 0; border-radius: 1rem 1rem 0.25rem 1rem;
}
.chat-model {
  align-self: flex-start;
  background: var(--oh-paper); border: 1px solid var(--oh-line);
  border-radius: 0.25rem 1rem 1rem 1rem;
}
.chat-model-streaming { margin-top: 0.75rem; }
.chat-model-ungrounded { border-left: 3px solid var(--oh-amber); }
.chat-label {
  font-family: var(--mono); font-size: 0.6875rem; text-transform: uppercase;
  letter-spacing: 0.06em; color: var(--oh-text-secondary); margin: 0 0 0.35rem;
}
.chat-you .chat-label { color: var(--oh-surface-tint); }

.chat-step { border: 1px dashed var(--oh-line); border-left: 3px solid var(--oh-line); border-radius: 0.5rem; padding: 0.5rem 0.9rem; font-size: 0.875rem; max-width: 85%; }
.chat-step-head { font-family: var(--mono); margin: 0 0 0.25rem; }

/* The activity fold: one run of machine steps behind a summary line
   (the transcript's Claude-ish strip). Open while running and when a
   step failed — a refusal must not fold itself out of sight. */
.chat-activity {
  align-self: flex-start; max-width: 85%; margin: 0;
  border: 1px dashed var(--oh-line); border-radius: 0.5rem; background: transparent;
}
.chat-activity > summary {
  font-family: var(--mono); font-size: 0.8125rem; font-weight: 500;
  color: var(--oh-text-secondary); padding: 0.45rem 0.9rem;
}
.chat-activity[open] > summary { border-bottom: 1px dashed var(--oh-line); }
.chat-activity-failed { border-left: 3px solid var(--oh-amber); }
.chat-activity-body { display: flex; flex-direction: column; gap: 0.5rem; padding: 0.6rem 0.9rem; }
.chat-activity .chat-step { max-width: 100%; border: 0; border-left: 3px solid var(--oh-line); border-radius: 0; padding-block: 0.15rem; }

.chat-json summary { padding: 0.15rem 0; font-weight: 500; font-size: 0.8125rem; }
.chat-json { border: 0; margin-top: 0.25rem; }
.chat-json pre { overflow-x: auto; font-size: 0.75rem; margin: 0.25rem 0 0; border-top: 0; padding: 0.25rem 0 0; }
.chat-provenance { font-size: 0.8125rem; color: var(--oh-grey); margin: 0.4rem 0 0; }
/* Citation marks in the prose: superscript numbers leading to the
   rail's card of the same number. */
.chat-cite {
  font-size: 0.75em; vertical-align: super; font-weight: 600;
  text-decoration: none; padding: 0 0.1em;
}
.chat-cite:hover { text-decoration: underline; }
.chat-ungrounded { display: inline-block; border: 1px solid var(--oh-red); color: var(--oh-red); font-size: 0.75rem; padding: 0.1rem 0.5rem; margin-top: 0.5rem; }

/* The three states, each with its own edge. */
.chat-state { border: 1px solid var(--oh-line); border-left: 3px solid var(--oh-grey); border-radius: 0.5rem; padding: 0.6rem 0.9rem; font-size: 0.9375rem; max-width: 44rem; }
.chat-state p { margin: 0.25rem 0 0; }
.chat-state p:first-child { margin-top: 0; }
.chat-refusal { border-left-color: var(--oh-amber); }
.chat-absent { border-left-color: var(--oh-red); }
.chat-absent h3, .chat-refusal h3 { font-size: 1rem; margin: 0 0 0.25rem; }
/* A bound is a state, not a refusal: the window was reached and an
   answer follows. Blue edge, never amber. */
.chat-bound { border-left-color: var(--oh-blue); }
/* A bound that RECOVERED: the window filled and the machine made room
   instead of ending the exchange. The accent edge tells it apart from
   the blue of a bound that stood and the grey of a stop. */
.chat-compacted { border-left-color: var(--oh-accent); }

/* The exchange ended without an answer, and says who ended it. A
   state with the bound's shape, never a failure's: nothing broke. */
.chat-stopped { border-left-color: var(--oh-grey); }

/* Who wrote an answer and the day its sources put it on. Under the
   answer, quiet: provenance about the answer itself, which a reader
   who does not need it should not have to read past. */
.chat-answered {
  margin: 0.15rem 1.25rem 0.5rem; font-size: 0.75rem; color: var(--oh-grey);
  font-variant-numeric: tabular-nums;
}

/* Taking the evidence off the page. The stamp and the copy action
   share one row, so the answer's provenance and the way to keep it sit
   together and cost one line rather than two. */
/* The footer sits on --oh-surface-deep with --oh-paper on it, and on
   a dark ground the paper role IS the ground — near-black on
   near-black. The band stays deep; its text becomes the page's text. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .site-footer,
  :root:not([data-theme="light"]) .site-footer a,
  :root:not([data-theme="light"]) .site-footer a:visited,
  :root:not([data-theme="light"]) .footer-brand {
    color: var(--oh-text);
  }
}
/* And when the visitor CHOSE dark on a system that prefers light —
   the same gap the palette had, and the same repair: a media query
   alone answers only half the states the gear offers. */
:root[data-theme="dark"] .site-footer,
:root[data-theme="dark"] .site-footer a,
:root[data-theme="dark"] .site-footer a:visited,
:root[data-theme="dark"] .footer-brand {
  color: var(--oh-text);
}

.chat-answered-row {
  display: flex; align-items: baseline; gap: 0.6rem; flex-wrap: wrap;
  margin: 0.15rem 1.25rem 0.5rem;
}
.chat-answered-row .chat-answered { margin: 0; }
.chat-copy { display: inline-flex; flex-direction: column; gap: 0.3rem; }
.chat-copy-button {
  border: 0; background: transparent; padding: 0; cursor: pointer;
  font-size: 0.75rem; color: var(--oh-link); text-decoration: underline;
}
.chat-copy-button:hover { color: var(--oh-link-hover); }
/* The refusal is a state: the browser said no, so the text is put on
   the page and selected as one block for the hand that has to do it. */
.chat-copy-denied { max-width: 40rem; }
.chat-copy-text {
  margin: 0.25rem 0 0; padding: 0.5rem 0.6rem; max-height: 18rem; overflow: auto;
  background: var(--oh-raised); border-left: 3px solid var(--oh-line);
  font-size: 0.75rem; line-height: 1.45; white-space: pre-wrap; word-break: break-word;
  -webkit-user-select: all; user-select: all;
}

/* The whole conversation as a file. An anchor the visitor clicks —
   this application may not synthesize a click — with the small print
   saying what the file carries and what silence would mean. */
.chat-download { margin: 0; padding: 0 1.25rem 0.4rem; font-size: 0.75rem; }
.chat-download-link { color: var(--oh-link); }
.chat-download-link:hover { color: var(--oh-link-hover); }

/* What the platform has left for this visitor today. Beside the
   meter, in the same quiet register: it is what the gateway last
   said, not a counter this browser keeps. */
.chat-allowance {
  margin: 0; padding: 0 1.25rem 0.25rem; font-size: 0.8125rem;
  color: var(--oh-text-secondary); font-variant-numeric: tabular-nums;
}

/* The meter: what the last request read and what the question spent
   — the visitor's own money, in the unit it is counted in. */
.chat-meter { font-size: 0.8125rem; color: var(--oh-grey); margin: 0; padding: 0 1.25rem 0.25rem; font-variant-numeric: tabular-nums; }
.chat-kind { font-family: var(--mono); font-weight: 600; margin: 0 0 0.25rem; }

/* Long tool ids, ELIs and provenance URLs must wrap, not push the
   page sideways — a transcript is exactly where untrusted-length
   strings arrive. */
.chat-bubble, .chat-step, .chat-activity { overflow-wrap: break-word; }
.chat-step-head, .chat-provenance, .chat-activity > summary { overflow-wrap: anywhere; }

/* --- Small screens: the same page, denser ----------------------- */
/* The layout is fluid by construction (wrapping flex rows, auto-fit
   grids, clamp() type, tables in their own scroll containers); these
   two blocks only re-tune spacing so phone and tablet get the density
   the content deserves instead of a shrunken desktop. Nothing is
   hidden on small screens: every element earns its place at every
   width or should not exist at all (WCAG 1.4.10 reflow). */
@media (max-width: 56rem) {
  .hero { padding-block: 2.5rem 2rem; }
  .section { padding-block: 2rem; }
  .site-footer { margin-top: 2.5rem; }
}
@media (max-width: 40rem) {
  .wrap { padding-inline: 1rem; }
  /* Header: brand and language share the first row, the menu takes a
     full row beneath — six wrapping items stay readable and every
     target keeps its height. */
  .header-inner { padding-block: 0.6rem; }
  .site-nav { order: 1; flex-basis: 100%; }
  .site-nav ul { margin-inline: -0.5rem; }
  .site-nav a { padding: 0.6rem 0.5rem; }
  .hero { padding-block: 2rem 1.5rem; }
  .page-header { padding-block: 1.5rem 0.25rem; }
  .section { padding-block: 1.75rem; }
  thead th, td, tbody th { padding: 0.5rem; }
  .desc-col { min-width: 16rem; }
  .meta-panel, .entry-card { padding: 1rem; }
  .chat-form { flex-wrap: nowrap; padding-inline: 0.75rem; }
  .chat-bubble, .chat-step { padding-inline: 0.6rem; max-width: 100%; }
  .chat-scroll { padding: 0.75rem; }
  .chat-status { padding-inline: 0.75rem; }
  .chat-hint { margin-inline: 0.75rem; }
  .footer-nav ul { gap: 0.5rem 1.25rem; }
}

/* ---- The one infrastructure page (filter chips) ----------------- */
.infra-filter { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 0 0 1.5rem; }
.infra-filter .btn[aria-pressed="true"] { background: var(--oh-dark-1); color: var(--oh-paper); }

/* ---- The site-wide assistant: bubble and panel (BN) ------------- */
/* Fixed to the bottom-right on every page. The button and the panel
   are two elements, not one growing box: the button keeps its place
   and its accessible name while the panel appears beside it, which is
   what lets `aria-expanded` describe a stable control.

   Contrast: white on --oh-dark-1 is 7.16:1 (tokens.css), so the mark
   is legible at any size; the focus ring is the site's own
   :focus-visible rule and needs nothing here. */
.oh-assistant-open {
  position: fixed; right: 1rem; bottom: 1rem; z-index: 40;
  width: 3rem; height: 3rem; border-radius: 50%;
  border: 2px solid var(--oh-dark-1); background: var(--oh-dark-1); color: var(--oh-paper);
  font: inherit; font-size: 1.5rem; line-height: 1; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 2px 8px rgb(0 0 0 / 0.25);
}
.oh-assistant-open:hover { background: var(--oh-dark-2); border-color: var(--oh-dark-2); }
.oh-assistant-open-mark { font-weight: 700; }

.oh-assistant-panel {
  position: fixed; right: 1rem; bottom: 5rem; z-index: 41;
  width: min(24rem, calc(100vw - 2rem));
  /* Bounded height with its own scroll: a long transcript must never
     make the DOCUMENT scroll sideways or grow past the viewport
     (WCAG 1.4.10). */
  height: min(32rem, calc(100vh - 7rem));
  max-height: calc(100vh - 7rem); min-height: 16rem;
  max-width: calc(100vw - 2rem); min-width: 18rem;
  /* The visitor sizes the window by its TOP-LEFT corner — the panel
     is pinned bottom right, so that is the corner that can move.
     Native `resize` only ever offers the bottom right, hence the own
     grip. */
  border-radius: 1rem;
  display: flex; flex-direction: column;
  overflow: hidden; overscroll-behavior: contain;
  background: var(--oh-paper); color: var(--oh-text);
  border: 1px solid var(--oh-line); box-shadow: 0 4px 16px rgb(0 0 0 / 0.2);
  padding: 1rem;
}
.oh-assistant-panel:focus-visible { outline: 2px solid var(--oh-focus); outline-offset: -2px; }
.oh-assistant-grip {
  position: absolute; top: 0; left: 0; width: 1.5rem; height: 1.5rem;
  cursor: nwse-resize; touch-action: none; border-top-left-radius: 1rem;
}
.oh-assistant-grip::before {
  content: ""; position: absolute; top: 0.45rem; left: 0.45rem;
  width: 0.55rem; height: 0.55rem;
  border-top: 2px solid var(--oh-line); border-left: 2px solid var(--oh-line);
  border-top-left-radius: 0.2rem;
}
.oh-assistant-grip:hover::before { border-color: var(--oh-dark-1); }
.oh-assistant-drag-surface { position: fixed; inset: 0; z-index: 60; cursor: nwse-resize; }
.oh-assistant-head { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; padding-left: 1rem; }
.oh-assistant-head h2 { font-size: 1.125rem; margin: 0; }
.oh-assistant-close {
  border: 1px solid var(--oh-line); border-radius: 50%;
  background: var(--oh-paper); color: var(--oh-text);
  font: inherit; font-size: 1.25rem; line-height: 1; cursor: pointer;
  width: 2rem; height: 2rem; min-width: 2rem; min-height: 2rem;
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0;
}
.oh-assistant-close:hover { border-color: var(--oh-dark-1); }
.oh-assistant-lead { font-size: 0.875rem; color: var(--oh-text-secondary); margin: 0.25rem 0 0.75rem; }
.oh-assistant-keyless { border-left: 3px solid var(--oh-accent); padding-left: 0.75rem; }
.oh-assistant-keyless h3 { font-size: 1rem; margin: 0 0 0.25rem; }
/* The conversation scrolls; the field does not move. */
.oh-assistant-scroll { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; }
.oh-assistant-form { flex: none; display: flex; align-items: flex-end; gap: 0.5rem; margin: 0.75rem 0 0; }
/* The field grows with the text — one line at rest, up to eight, then
   it scrolls. `field-sizing` does it natively where the browser has
   it; the rows attribute and the max-height keep the shape everywhere
   else. */
.oh-assistant-input {
  flex: 1; min-width: 0; resize: none; overflow-y: auto;
  padding: 0.55rem 0.7rem; border: 1px solid var(--oh-line); border-radius: 0.9rem;
  font: inherit; line-height: 1.4; max-height: 11rem;
  field-sizing: content;
}
.oh-assistant-input:focus-visible { outline: 2px solid var(--oh-focus); outline-offset: 1px; }
/* The send button is round, like the chat page's — the label stays as
   its accessible name. */
.oh-assistant-send {
  flex: none; width: 2.5rem; height: 2.5rem; border-radius: 50%;
  border: 0; background: var(--oh-dark-1); color: var(--oh-paper);
  font-size: 1.1rem; line-height: 1; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
}
.oh-assistant-send:hover:not(:disabled) { background: var(--oh-dark-2); }
/* The bubble's action, while an answer is being earned: it stops it. */
.oh-assistant-stop { background: var(--oh-paper); color: var(--oh-dark-1); border: 2px solid var(--oh-dark-1); }
.oh-assistant-stop:hover { background: var(--oh-tint); }
.oh-assistant-send:disabled { opacity: 0.5; cursor: default; }
.oh-assistant-settings { margin-top: 0.75rem; font-size: 0.875rem; }
.oh-assistant-settings summary { cursor: pointer; }
.oh-assistant-ephemeral { margin-top: 0.75rem; }

/* The offer: a link that looks like the destination it leads to, so
   what is clicked and where it goes are the same thing on screen. */
.oh-assistant-offer { margin: 0.5rem 0; }
.oh-assistant-offer-lead { font-size: 0.875rem; margin: 0 0 0.25rem; }
.oh-assistant-offer-reason { font-size: 0.875rem; margin: 0 0 0.5rem; }
.oh-assistant-offer-link {
  display: block; padding: 0.6rem 0.75rem;
  border: 1px solid var(--oh-dark-1); background: var(--oh-surface-tint);
  color: var(--oh-link); text-decoration: none;
}
.oh-assistant-offer-link:hover { background: var(--oh-paper); }
.oh-assistant-offer-title { display: block; font-weight: 600; text-decoration: underline; }
.oh-assistant-offer-purpose { display: block; font-size: 0.875rem; color: var(--oh-ink); }
.oh-assistant-offer-path { display: block; font-family: var(--mono); font-size: 0.75rem; overflow-wrap: anywhere; }

@media (max-width: 40rem) {
  /* On a phone the panel takes the width it needs and sits above the
     button rather than beside it — nothing is hidden, it reflows. */
  .oh-assistant-panel { right: 0.5rem; left: 0.5rem; bottom: 4.75rem; width: auto; }
  .oh-assistant-open { right: 0.75rem; bottom: 0.75rem; }
}

/* --- Documentation page (the task page, 02.09.2026) ------------- */
/* Every rule is scoped to `.doc` so the chat, the about page's own
   `ol.steps` and the entry page keep their markup untouched. Grey and
   chips appear only on paper here — the page uses no tint band. */
.doc [id] { scroll-margin-top: 1.25rem; }
.doc .intro + .intro { margin-top: -0.25em; }
.doc .lead-line { margin: 1.5rem 0 0; max-width: 44rem; }
.doc code { font-family: var(--mono); font-size: 0.875em; overflow-wrap: anywhere; }
.doc th code, .doc td code { font-size: 0.8125rem; }

/* The glossary under the intro: six terms, one line each. */
.doc .defs {
  display: grid; grid-template-columns: minmax(7rem, max-content) 1fr;
  gap: 0.45rem 1.25rem; margin: 1.25rem 0 0; max-width: 44rem;
}
.doc .defs dt { font-family: var(--mono); font-size: 0.8125rem; color: var(--oh-dark-2); }
.doc .defs dd { margin: 0; font-size: 0.9375rem; overflow-wrap: anywhere; }
@media (max-width: 40rem) {
  .doc .defs { grid-template-columns: 1fr; }
  .doc .defs dd { margin-bottom: 0.5rem; }
}

/* The four «Ich möchte …» rows: the page's primary navigation as a
   ledger — mono counter, bold verb link, one-line description. */
.doc .task-list { margin-top: 1.5rem; }
.doc .task-list ol { list-style: none; margin: 0; padding: 0; max-width: 44rem; counter-reset: task; }
.doc .task-list li {
  counter-increment: task; display: grid; grid-template-columns: 2rem 1fr;
  gap: 0.15rem 0.75rem; align-items: baseline;
  border-top: 1px solid var(--oh-line); padding: 0.85rem 0; min-height: 2.75rem;
}
.doc .task-list li:last-child { border-bottom: 1px solid var(--oh-line); }
.doc .task-list li::before {
  content: counter(task, decimal-leading-zero);
  font-family: var(--mono); font-size: 0.75rem; color: var(--oh-text-secondary);
  grid-row: 1 / span 2; padding-top: 0.2rem;
}
.doc .task-list a { font-weight: 600; font-size: 1.0625rem; }
.doc .task-desc { grid-column: 2; font-size: 0.875rem; color: var(--oh-text-secondary); }
@media (max-width: 40rem) { .doc .task-list li { grid-template-columns: 1.5rem 1fr; } }

/* The quieter second navigation: one mono line of anchors. */
.doc .toc { margin-top: 1rem; }
.doc .toc ul {
  list-style: none; display: flex; flex-wrap: wrap; gap: 0.35rem 0.75rem;
  margin: 0; padding: 0;
  font-family: var(--mono); font-size: 0.75rem; letter-spacing: 0.06em; text-transform: uppercase;
}
.doc .toc li + li + li::before { content: "·"; color: var(--oh-text-secondary); margin-right: 0.75rem; }
.doc .toc .toc-lead { color: var(--oh-text-secondary); }

/* Numbered steps as ledger rows; the <ol> keeps its native numbering,
   the counter is the visible form. Ink, never teal, for the numeral. */
.doc .steps { list-style: none; margin: 1rem 0 0; padding: 0; max-width: 44rem; counter-reset: step; }
.doc .steps li {
  counter-increment: step; position: relative;
  padding: 0.8rem 0 0.8rem 2.75rem; border-top: 1px solid var(--oh-line);
}
.doc .steps li:last-child { border-bottom: 1px solid var(--oh-line); }
.doc .steps li::before {
  content: counter(step); position: absolute; left: 0; top: 0.8rem; width: 1.9rem;
  font-family: var(--mono); font-size: 0.8125rem; font-weight: 700; color: var(--oh-text);
  border-right: 1px solid var(--oh-line);
}
.doc .steps li strong { display: block; margin-bottom: 0.15em; }
@media (max-width: 40rem) { .doc .steps li { padding-left: 2.25rem; } }

/* The four state words, as text: dark-2 holds 10.19:1 on paper and
   8.41:1 on the zebra tint (the precedent is `tbody .slug`). */
.doc .state {
  font-family: var(--mono); font-size: 0.75rem; letter-spacing: 0.05em;
  text-transform: uppercase; color: var(--oh-dark-2); white-space: nowrap;
}
.doc .path-desc .state { margin-right: 0.35rem; }
.doc .meta-panel dd .state { margin-right: 0.35rem; }

/* The facts panel gained an h3 (the section already owns the h2). */
.doc .meta-panel h3 {
  font-family: var(--mono); font-size: 0.8125rem; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.08em; margin-bottom: 1rem;
}
.doc .facts-panel { margin-block: 1.25rem 1.5rem; }

/* Code figures outside <details>: caption in the table-caption voice,
   the pre focusable and scrollable in its own box. */
.doc .code-block { margin: 1rem 0 0; max-width: 44rem; }
.doc .code-caption {
  font-family: var(--mono); font-size: 0.75rem; color: var(--oh-text-secondary);
  background: var(--oh-paper); border: 1px solid var(--oh-line); border-bottom: 0;
  padding: 0.5rem 0.75rem;
}
.doc .code-block pre {
  margin: 0; padding: 1rem; background: var(--oh-paper); border: 1px solid var(--oh-line);
  overflow-x: auto; font-family: var(--mono); font-size: 0.75rem; line-height: 1.5;
}
.doc .code-block pre:focus-visible { outline: 2px solid var(--oh-focus); outline-offset: 2px; }
.doc .path-list + .lead-line { margin-top: 1.75rem; }
/* Row headers that are identifiers never break mid-word; the region
   scrolls instead (the wrapper is focusable and labelled). */
.doc tbody th code { white-space: nowrap; }

/* Module state words (modules.json): one word, never a sentence, never
   colour alone — the same treatment the documentation page uses. */
.state {
  font-family: var(--mono); font-size: 0.75rem; letter-spacing: 0.05em;
  text-transform: uppercase; color: var(--oh-dark-2); white-space: nowrap;
}
.state-reason { display: block; font-size: 0.8125rem; margin-top: 0.25rem; }
.evidence-note { display: block; font-size: 0.8125rem; color: var(--oh-dark-2); margin-top: 0.2rem; }

/* Infrastructure page (rebuilt 03.09.2026): jump bar, section heads
   with their counts, catalogue tables without running text, pills for
   state and verification, facets from the first row, machine list. */
.jump-bar { position: sticky; top: 0; z-index: 5; background: var(--oh-paper); border-block: 1px solid var(--oh-line); margin: 0.5rem 0 1.5rem; }
.jump-bar ul { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 0 1.75rem; }
.jump-bar a { display: inline-block; padding: 0.7rem 0; font-weight: 600; text-decoration: none; color: var(--oh-dark-1); border-bottom: 2px solid transparent; }
.jump-bar a:hover, .jump-bar a:focus { border-bottom-color: var(--oh-accent); }
.section-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.5rem 1rem; }
.section-head h2 { margin: 0; }
.section-lead { margin: 0; font-family: var(--mono); font-size: 0.8125rem; color: var(--oh-text-secondary); }
.section-foot { font-size: 0.9375rem; margin: 1rem 0 0; }
.catalogue-tools { margin: 1rem 0 0; }
.catalogue-tools .search-block { margin: 0 0 0.75rem; }
.pill { display: inline-block; font-family: var(--mono); font-size: 0.75rem; letter-spacing: 0.04em; text-transform: uppercase; padding: 0.15rem 0.55rem; border: 1px solid var(--oh-line); border-radius: 999px; color: var(--oh-dark-2); background: var(--oh-paper); white-space: nowrap; }
.pill-row { display: flex; flex-wrap: wrap; gap: 0.4rem; margin: 0 0 0.75rem; align-items: center; }
.gh-mark { width: 1em; height: 1em; vertical-align: -0.15em; }
a.pill-link { text-decoration: none; color: var(--oh-dark-1); border-color: var(--oh-dark-1); text-transform: none; letter-spacing: 0; font-family: var(--sans); font-size: 0.8125rem; }
a.pill-link:hover, a.pill-link:focus { background: var(--oh-tint); text-decoration: underline; }
.source-link { white-space: nowrap; }
.pill.state { color: var(--oh-dark-2); }
.pill.state-in-operation { border-color: var(--oh-accent); color: var(--oh-dark-1); background: var(--oh-tint); }
.pill.state-prepared { border-color: var(--oh-dark-2); color: var(--oh-dark-1); }
.pill.state-draft, .pill.state-in-progress, .pill.state-open { border-style: dashed; }
.pill.state-internal { color: var(--oh-text-secondary); }
.pill.check-ok { border-color: var(--oh-accent); color: var(--oh-dark-1); background: var(--oh-tint); }
.pill.check-fail { border-color: var(--oh-dark-1); color: var(--oh-dark-1); border-width: 2px; }
.pill.check-none { color: var(--oh-text-secondary); }
.legend { margin: 0.75rem 0 0; }
.infra .not-yet { font-family: var(--mono); color: var(--oh-dark-2); }
.infra .na { color: var(--oh-text-secondary); }
.infra table.catalogue th[scope="row"] { font-weight: 600; }
.infra table.catalogue th[scope="row"] .slug { font-weight: 400; }
.infra table.catalogue td { vertical-align: top; }
.machine-list { display: grid; grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr)); gap: 0.75rem 2rem; margin: 1rem 0 0; }
.machine-list div { border-top: 1px solid var(--oh-line); padding: 0.6rem 0; }
.machine-list dt { font-family: var(--mono); font-size: 0.875rem; }
.machine-list dd { margin: 0.2rem 0 0; font-size: 0.9375rem; color: var(--oh-text-secondary); }
.use-block { margin: 0 0 1.25rem; min-width: 0; }
/* A long one-line call scrolls inside its box; the page never widens. */
.entry-layout > * { min-width: 0; }
.entry-main .code-block { margin: 0; max-width: 100%; }
.entry-main .code-block pre { overflow-x: auto; max-width: 100%; margin: 0; padding: 0.75rem 1rem; background: var(--oh-surface-tint); border: 1px solid var(--oh-line); font-family: var(--mono); font-size: 0.8125rem; line-height: 1.5; }
.use-facts { margin: 0 0 0.5rem; font-size: 0.9375rem; overflow-wrap: anywhere; }
.use-block .code-block { margin: 0; }
.infra table.modules th, .infra table.modules td { vertical-align: top; }
.infra table.modules .desc-col { min-width: 16rem; max-width: 24rem; }
.infra .legend dt .state { font-size: 0.75rem; }
.infra .facets { margin: 1rem 0 1.5rem; display: grid; gap: 0.5rem; }
.infra .facet-group { display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem; }
.infra .facet-title { font-family: var(--mono); font-size: 0.75rem; letter-spacing: 0.05em; text-transform: uppercase; color: var(--oh-dark-2); margin-right: 0.25rem; }
.infra .facets .btn { padding: 0.2rem 0.6rem; font-size: 0.8125rem; }
.infra .facets .btn[aria-pressed="true"] { background: var(--oh-dark-1); color: var(--oh-paper); }
.infra .facets .count { font-family: var(--mono); font-size: 0.75rem; margin-left: 0.25rem; }
.infra .check-col { min-width: 9rem; }
.dep-figure { margin: 1rem 0; max-width: 100%; overflow-x: auto; background: var(--oh-paper); border: 1px solid var(--oh-line); padding: 0.5rem; }
.dep-figure svg { display: block; max-width: 100%; height: auto; font-family: var(--sans, inherit); }
/* In the documentation column the figure keeps its drawn size and scrolls sideways instead of shrinking its labels below legibility. */
.docs .dep-figure svg { max-width: none; }
.dep-figure rect { fill: var(--oh-paper); stroke: var(--oh-dark-1); stroke-width: 1; }
.dep-figure line { stroke: var(--oh-dark-2); stroke-width: 1; }
.dep-figure text { fill: var(--oh-text); font-size: 13px; }
.dep-figure .dep-state { font-family: var(--mono); font-size: 10px; letter-spacing: 0.05em; text-transform: uppercase; fill: var(--oh-dark-2); }
.dep-figure a:hover rect, .dep-figure a:focus rect { stroke-width: 2; }
.dep-figure figcaption { font-size: 0.8125rem; color: var(--oh-dark-2); margin-top: 0.5rem; }
.infra table.compose th[scope="row"] { font-weight: 600; white-space: normal; }
@media (max-width: 48rem) {
  .infra table.catalogue, .infra table.catalogue tbody, .infra table.catalogue tr, .infra table.catalogue td, .infra table.catalogue th { display: block; }
  .infra table.catalogue thead { position: absolute; left: -9999px; }
  .infra table.catalogue tr { border-bottom: 1px solid var(--oh-line); padding: 0.5rem 0; }
  .infra table.catalogue th[scope="row"] { border-bottom: 0; font-size: 1rem; }
  .infra table.catalogue tr.layer-row th { font-size: 0.75rem; }
  .infra table.catalogue td { border-bottom: 0; padding: 0.15rem 0.6rem; display: grid; grid-template-columns: 6rem 1fr; gap: 0.5rem; }
  .infra table.catalogue td::before { content: attr(data-label); font-family: var(--mono); font-size: 0.7rem; letter-spacing: 0.05em; text-transform: uppercase; color: var(--oh-dark-2); }
  .jump-bar { position: static; }
}
/* Module page: «noch nicht» is always followed by its reason. */
.module-page .reason { font-size: 0.9375rem; }
.module-page .defs dd .state { margin-left: 0.25rem; }
.module-page .record-line .uri { font-size: 0.75rem; }
/* Grid children must be allowed to shrink below their content width,
   or a long command line widens the whole page on a phone. */
.module-page .entry-layout > * { min-width: 0; }
.module-page .code-block pre { max-width: 100%; overflow-x: auto; }

/* Documentation site (02.09.2026): map on the left, page in the middle,
   chapters on the right; on a phone map and chapters fold into native
   disclosures above the text — no script decides what is visible. */
.docs .docs-layout { display: grid; grid-template-columns: 15rem minmax(0, 1fr) 13rem; gap: 2.5rem; align-items: start; padding-block: 1.5rem 3rem; }
.docs .docs-nav, .docs .docs-side { position: sticky; top: 1rem; max-height: calc(100vh - 2rem); overflow-y: auto; font-size: 0.875rem; }
.docs .docs-nav-mobile, .docs .docs-toc-mobile { display: none; }
.docs .docs-nav-title { margin: 0 0 0.75rem; font-family: var(--mono); font-size: 0.75rem; letter-spacing: 0.05em; text-transform: uppercase; }
.docs .docs-nav-title a[aria-current="page"], .docs .docs-nav a[aria-current="page"] { color: var(--oh-text); font-weight: 600; }
.docs .docs-nav-flat { list-style: none; margin: 0; padding: 0.4rem 0; border-block: 1px solid var(--oh-line); }
.docs .docs-nav-flat li { margin: 0; }
.docs .docs-nav-flat a { display: block; padding: 0.3rem 0.5rem; text-decoration: none; color: var(--oh-dark-1); border-left: 2px solid transparent; }
.docs .docs-nav-flat a:hover, .docs .docs-nav-flat a:focus { text-decoration: underline; }
.docs .docs-nav-flat a[aria-current="page"] { border-left-color: var(--oh-primary); background: var(--oh-tint); }
.docs .docs-nav-section { border-top: 1px solid var(--oh-line); padding: 0.4rem 0; }
.docs .docs-nav-section:last-of-type { border-bottom: 1px solid var(--oh-line); }
.docs .docs-nav-section > summary { cursor: pointer; font-weight: 600; padding: 0.3rem 0; list-style-position: inside; }
.docs .docs-nav-section > summary::marker { color: var(--oh-dark-2); font-size: 0.75em; }
.docs .docs-nav-section ul { list-style: none; margin: 0.2rem 0 0.4rem; padding: 0 0 0 0.9rem; border-left: 2px solid var(--oh-line); }
.docs .docs-nav-section li { margin: 0; }
.docs .docs-nav-section a { display: block; padding: 0.22rem 0.5rem; text-decoration: none; color: var(--oh-dark-1); border-left: 2px solid transparent; margin-left: calc(-0.9rem - 2px); padding-left: calc(0.9rem + 0.5rem); }
.docs .docs-nav-section a:hover, .docs .docs-nav-section a:focus { text-decoration: underline; }
.docs .docs-nav-section a[aria-current="page"] { border-left-color: var(--oh-primary); background: var(--oh-tint); }
.docs .docs-toc-title { margin: 0 0 0.5rem; font-family: var(--mono); font-size: 0.75rem; letter-spacing: 0.05em; text-transform: uppercase; color: var(--oh-dark-2); }
.docs .docs-toc ul, .docs .docs-toc-mobile ul { list-style: none; margin: 0; padding: 0; }
.docs .docs-toc li, .docs .docs-toc-mobile li { margin: 0; }
.docs .docs-toc a, .docs .docs-toc-mobile a { display: block; padding: 0.2rem 0 0.2rem 0.75rem; border-left: 2px solid var(--oh-line); text-decoration: none; color: var(--oh-dark-1); }
.docs .docs-toc a:hover, .docs .docs-toc a:focus, .docs .docs-toc-mobile a:hover { text-decoration: underline; }
.docs .docs-toc-sub a, .docs .docs-toc-mobile .docs-toc-sub a { padding-left: 1.5rem; font-size: 0.8125rem; }
.docs .docs-main { min-width: 0; max-width: 46rem; }
.docs .docs-body > h2 { margin-top: 2.5rem; }
.docs .docs-body > h3 { margin-top: 1.75rem; }
.docs .docs-body p, .docs .docs-body li { max-width: 46rem; }
.docs .docs-body .code-block { margin: 1rem 0 1.5rem; }
.docs .docs-body pre { max-width: 100%; overflow-x: auto; }
.docs .docs-body img { max-width: 100%; height: auto; }
.docs .docs-body blockquote { margin: 1rem 0; padding: 0.25rem 0 0.25rem 1rem; border-left: 3px solid var(--oh-line); color: var(--oh-dark-2); }
.docs .docs-pager { margin-top: 3rem; padding-top: 1rem; border-top: 1px solid var(--oh-line); font-size: 0.875rem; }
.docs .docs-pager-links { display: flex; justify-content: space-between; gap: 1rem; flex-wrap: wrap; }
.docs .docs-pager-links a:last-child:not(:first-child) { margin-left: auto; text-align: right; }
.docs .docs-pager-label { font-family: var(--mono); font-size: 0.7rem; letter-spacing: 0.05em; text-transform: uppercase; color: var(--oh-dark-2); display: block; }
.docs .docs-source { margin-top: 1rem; color: var(--oh-dark-2); }
.docs .docs-kinds { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.5rem 2.5rem; }
.docs .docs-kind h2 { font-size: 1.125rem; margin: 0.5rem 0 0.25rem; }
.docs .docs-kind-purpose { margin: 0 0 0.5rem; color: var(--oh-dark-2); font-size: 0.875rem; }
.docs .docs-machines { font-size: 0.875rem; color: var(--oh-dark-2); margin: 1rem 0 2rem; }
@media (max-width: 64rem) {
  .docs .docs-layout { grid-template-columns: 14rem minmax(0, 1fr); }
  .docs .docs-side { display: none; }
  .docs .docs-toc-mobile { display: block; margin: 0 0 1.5rem; border: 1px solid var(--oh-line); padding: 0.5rem 0.75rem; background: var(--oh-paper); }
  .docs .docs-toc-mobile > summary { cursor: pointer; font-weight: 600; }
  .docs .docs-toc-mobile ul { margin-top: 0.5rem; }
}
@media (max-width: 48rem) {
  .docs .docs-layout { grid-template-columns: 1fr; gap: 1rem; }
  .docs .docs-nav { display: none; }
  .docs .docs-nav-mobile { display: block; margin: 1rem 0 0; border: 1px solid var(--oh-line); padding: 0.5rem 0.75rem; background: var(--oh-paper); }
  .docs .docs-nav-mobile > summary { cursor: pointer; font-weight: 600; }
  .docs .docs-nav-mobile .docs-nav-title { margin-top: 0.75rem; }
  .docs .docs-kinds { grid-template-columns: 1fr; }
}
/* Catalogue table: layer group rows. */
.infra .layer-row th { background: var(--oh-tint); font-family: var(--mono); font-size: 0.75rem; letter-spacing: 0.05em; text-transform: uppercase; color: var(--oh-dark-2); font-weight: 600; padding-top: 0.6rem; }
.infra table.modules th[scope="row"] .slug { font-weight: 400; }
.module-page .defs { margin-bottom: 1.75rem; }
.module-page .entry-main > section + section { margin-top: 2rem; }
