/* Color Palette & Themes
 * --------------------------------------------------------------
 * Every visible colour derives from one base hex that the worker
 * resolves from the Caddy ``X-Portal-Flavor`` header, looked up in
 * ``backend/themes/<flag>.conf`` (the folder is canonical — no env
 * fallback). The portal-theme injection (see backend/portal_theme.py
 * + frontend/badges.css) writes the computed values into the
 * ``--bg/--card/--text/--muted/--border/--primary/--primary-hover/
 * --secondary/--secondary-hover/--accent/--highlight`` slots, plus
 * eight ``--district-1..8`` accents and three ``--shadow-*`` tints.
 * The defaults below are the Opal base; the worker overrides them
 * per request.
 * -------------------------------------------------------------- */

:root {
  --bg: #f4f8f7;
  --card: #ffffff;
  --text: #192421;
  --muted: #536560;
  --border: #c0d8d2;

  --primary: #317765;
  --primary-hover: #265e50;
  --secondary: #458991;
  --secondary-hover: #397279;
  --accent: #e236b9;
  --highlight: #166534;

  --shadow-sm: rgba(49, 119, 101, 0.08);
  --shadow-md: rgba(49, 119, 101, 0.15);
  --shadow-lg: rgba(49, 119, 101, 0.25);
  --shadow-sm: color-mix(in srgb, var(--primary) 8%, transparent);
  --shadow-md: color-mix(in srgb, var(--primary) 15%, transparent);
  --shadow-lg: color-mix(in srgb, var(--primary) 25%, transparent);

  /* Document badge groups — ONE harmony colour per semantic type
     (backend/portal_theme.py DOC_TYPE_GROUPS). The worker's injection
     writes the same named vars with the flavour-derived values; these
     Opal-derived defaults only apply when no injection ran. An Antrag
     is an Antrag (plain, gemeinsamer, interfraktionell), an Anfrage is
     an Anfrage, a Mitteilung is a Mitteilung — each type keeps its own
     colour. */
  --doc-group-protokoll-bg: #347f7e;
  --doc-group-protokoll-fg: #ffffff;
  --doc-group-antrag-bg: #355d82;
  --doc-group-antrag-fg: #ffffff;
  --doc-group-anfrage-bg: #353682;
  --doc-group-anfrage-fg: #ffffff;
  --doc-group-mitteilung-bg: #5b3582;
  --doc-group-mitteilung-fg: #ffffff;
  --doc-group-antwort-bg: #823582;
  --doc-group-antwort-fg: #ffffff;
  --doc-group-beschluss-bg: #82355d;
  --doc-group-beschluss-fg: #ffffff;
  --doc-group-bericht-bg: #823536;
  --doc-group-bericht-fg: #ffffff;
  --doc-group-drucksache-bg: #825b35;
  --doc-group-drucksache-fg: #ffffff;
  --doc-group-gesetz-bg: #777731;
  --doc-group-gesetz-fg: #ffffff;
  --doc-group-einladung-bg: #5a7f34;
  --doc-group-einladung-fg: #ffffff;
  --doc-group-anlage-bg: #368235;
  --doc-group-anlage-fg: #ffffff;
  --doc-group-sonstige-bg: #35825b;
  --doc-group-sonstige-fg: #ffffff;
  --doc-group-admin-bg: var(--doc-group-sonstige-bg); /* legacy alias */
  --doc-group-admin-fg: var(--doc-group-sonstige-fg);

  /* District accent colours. The injection writes --district-1..10;
     the named vars below are the fallback chain so a page rendered
     without a portal-theme injection (dev tools, error pages) still
     gets a brand-on ladder. Every district (incl. Hamburg-Nord and
     Bürgerschaft) is a distinct harmony step — none sits on the base
     hue. The hex defaults are Opal-derived so Volt purple NEVER leaks
     into a fallback render. */
  --district-hamburgnord: var(--district-1, #367072);
  --district-hamburgmitte: var(--district-2, #364c72);
  --district-altona: var(--district-3, #453672);
  --district-eimsbuettel: var(--district-4, #693672);
  --district-wandsbek: var(--district-5, #723658);
  --district-bergedorf: var(--district-6, #723936);
  --district-harburg: var(--district-7, #725d36);
  --district-buergerschaft: var(--district-8, #647236);
  --district-senat: var(--district-9, #407236);
  --district-extern: var(--district-10, #367251);
  --district-on-hamburgnord: var(--district-on-1, #ffffff);
  --district-on-hamburgmitte: var(--district-on-2, #ffffff);
  --district-on-altona: var(--district-on-3, #ffffff);
  --district-on-eimsbuettel: var(--district-on-4, #ffffff);
  --district-on-wandsbek: var(--district-on-5, #ffffff);
  --district-on-bergedorf: var(--district-on-6, #ffffff);
  --district-on-harburg: var(--district-on-7, #ffffff);
  --district-on-buergerschaft: var(--district-on-8, #ffffff);
  --district-on-senat: var(--district-on-9, #ffffff);
  --district-on-extern: var(--district-on-10, #ffffff);
  --district-default: var(--primary);

  /* LLM info banner gradient anchors — derived from the primary. */
  --llm-info-bg-start: color-mix(in srgb, var(--primary) 12%, var(--card));
  --llm-info-bg-end: color-mix(in srgb, var(--secondary) 12%, var(--card));

  /* ---------------------------------------------------------------------------
     Fluid layout + WCAG design tokens (Bürgerportal refactor)
     All distances use relative units (rem, %, vw/vh/dvh, clamp/min/max).
     Breakpoint tiers (mobile-first):
       base              < 40rem    (640px)  mobile / large phone
       min-width:40rem   ≥ 40rem              small tablet
       min-width:48rem   ≥ 48rem   (768px)    tablet — container padding kicks in
       min-width:64rem   ≥ 64rem  (1024px)    desktop — side-panel morph, map row
       min-width:112.5rem ≥ 112.5rem (1800px) ultra-wide — container cap
     --------------------------------------------------------------------------- */
  --container-max: 112.5rem;     /* 1800px ultra-wide cap */
  --measure: 75ch;               /* prose readability guard */
  --gutter: clamp(1rem, 5vw, 4rem);
  --tap-min: 2.75rem;            /* 44px WCAG 2.5.5 minimum hit target */
  --map-min-h: 30vh;
  --map-min-h: 30dvh;
  --map-max-h: 65vh;
  --map-max-h: 65dvh;
  --map-aspect: 16 / 10;

  --primary-on: #ffffff;
  --header-grad-end: #316f77;
}

/* Dark Theme Variables — same slot names; values come from the
   portal-theme injection's :root.dark block. The static fallbacks
   below keep dark-mode primary identical to light-mode primary (the
   "main colour same in both modes" rule); primary-ink is lightened
   for text legibility on the darker surface. */
:root.dark {
  --bg: #0d1e1a;
  --card: #172c26;
  --text: #f0f4f3;
  --muted: #a0b1ac;
  --border: #305047;

  /* Dark --primary === light --primary (Volt stays Volt). */
  --primary: #317765;
  --primary-hover: #317765;
  --secondary: #80b6bd;
  --secondary-hover: #9ac5cb;
  --accent: #e25ac1;
  --highlight: #166534;
  --primary-ink: #80c9b3;

  --shadow-sm: rgba(49, 119, 101, 0.15);
  --shadow-md: rgba(49, 119, 101, 0.25);
  --shadow-lg: rgba(49, 119, 101, 0.35);
  --shadow-sm: color-mix(in srgb, var(--primary) 15%, transparent);
  --shadow-md: color-mix(in srgb, var(--primary) 25%, transparent);
  --shadow-lg: color-mix(in srgb, var(--primary) 35%, transparent);

  /* Dark districts mirror light — same ladder, same hex. Doc-group
     badges are mode-independent too, so they are NOT redefined here:
     they inherit the :root values (injected flavour colours or the
     Opal defaults). */
  --district-hamburgnord: var(--district-1, #367072);
  --district-hamburgmitte: var(--district-2, #364c72);
  --district-altona: var(--district-3, #453672);
  --district-eimsbuettel: var(--district-4, #693672);
  --district-wandsbek: var(--district-5, #723658);
  --district-bergedorf: var(--district-6, #723936);
  --district-harburg: var(--district-7, #725d36);
  --district-buergerschaft: var(--district-8, #647236);
  --district-senat: var(--district-9, #407236);
  --district-extern: var(--district-10, #367251);
  --district-on-hamburgnord: var(--district-on-1, #ffffff);
  --district-on-hamburgmitte: var(--district-on-2, #ffffff);
  --district-on-altona: var(--district-on-3, #ffffff);
  --district-on-eimsbuettel: var(--district-on-4, #ffffff);
  --district-on-wandsbek: var(--district-on-5, #ffffff);
  --district-on-bergedorf: var(--district-on-6, #ffffff);
  --district-on-harburg: var(--district-on-7, #ffffff);
  --district-on-buergerschaft: var(--district-on-8, #ffffff);
  --district-on-senat: var(--district-on-9, #ffffff);
  --district-on-extern: var(--district-on-10, #ffffff);
  --district-default: var(--primary);

  --llm-info-bg-start: color-mix(in srgb, var(--primary) 18%, var(--card));
  --llm-info-bg-end: color-mix(in srgb, var(--secondary) 18%, var(--card));

  --primary-on: #ffffff;
  --header-grad-end: #316f77;
}

/* System dark theme selection: same slot names; values come from the
   portal-theme injection's :root.dark block, which is appended to
   the document by the worker and therefore always wins the cascade.
   Static fallbacks mirror the :root.dark block above so non-injected
   pages still get the "same primary in both modes" behaviour. */
@media (prefers-color-scheme: dark) {
  :root.system-theme-active {
    --bg: #0d1e1a;
    --card: #172c26;
    --text: #f0f4f3;
    --muted: #a0b1ac;
    --border: #305047;

    --primary: #317765;
    --primary-hover: #317765;
    --secondary: #80b6bd;
    --secondary-hover: #9ac5cb;
    --accent: #e25ac1;
    --highlight: #166534;
    --primary-ink: #80c9b3;

    --shadow-sm: rgba(49, 119, 101, 0.15);
    --shadow-md: rgba(49, 119, 101, 0.25);
    --shadow-lg: rgba(49, 119, 101, 0.35);
    --shadow-sm: color-mix(in srgb, var(--primary) 15%, transparent);
    --shadow-md: color-mix(in srgb, var(--primary) 25%, transparent);
    --shadow-lg: color-mix(in srgb, var(--primary) 35%, transparent);

    --district-hamburgnord: var(--district-1, #367072);
    --district-hamburgmitte: var(--district-2, #364c72);
    --district-altona: var(--district-3, #453672);
    --district-eimsbuettel: var(--district-4, #693672);
    --district-wandsbek: var(--district-5, #723658);
    --district-bergedorf: var(--district-6, #723936);
    --district-harburg: var(--district-7, #725d36);
    --district-buergerschaft: var(--district-8, #647236);
    --district-senat: var(--district-9, #407236);
    --district-extern: var(--district-10, #367251);
    --district-on-hamburgnord: var(--district-on-1, #ffffff);
    --district-on-hamburgmitte: var(--district-on-2, #ffffff);
    --district-on-altona: var(--district-on-3, #ffffff);
    --district-on-eimsbuettel: var(--district-on-4, #ffffff);
    --district-on-wandsbek: var(--district-on-5, #ffffff);
    --district-on-bergedorf: var(--district-on-6, #ffffff);
    --district-on-harburg: var(--district-on-7, #ffffff);
    --district-on-buergerschaft: var(--district-on-8, #ffffff);
    --district-on-senat: var(--district-on-9, #ffffff);
    --district-on-extern: var(--district-on-10, #ffffff);
    --district-default: var(--primary);

    --llm-info-bg-start: color-mix(in srgb, var(--primary) 18%, var(--card));
    --llm-info-bg-end: color-mix(in srgb, var(--secondary) 18%, var(--card));
  }
}

* { box-sizing: border-box; }

/* ---------------------------------------------------------------------------
   WCAG 1.4.10 Reflow + 1.4.4 Resize Text guard.
   Text-bearing containers must never overflow their parent at 320 CSS pixels
   (reflow) and must scale with browser zoom (relative units everywhere).
   - overflow-wrap:break-word  — break inside long words/URLs (WCAG 1.4.10)
   - hyphens:auto              — German hyphenation (lang="de" on <html>)
   - word-break:break-word     — legacy fallback for older engines
   The container measure guard (max-width: var(--measure)) keeps prose lines
   readable on ultra-wide screens; cards/panels themselves stay full-width
   so the map and interactive controls can use all available space.
   --------------------------------------------------------------------------- */
.result-title,
.result-meta,
.doc-title-row,
.layer-1 .layer-heading,
.layer-1 .answer,
.doc-card-title,
.doc-card-relevance,
.layer-3-card-title,
.layer-3-card-meta,
.layer-3-relevance,
.paragraph-display,
.einfache-sprache-card,
.einfache-sprache-card-body,
.vds-result-card,
.vds-result-card-title,
.vds-result-card-body,
.autocomplete-item-primary,
.autocomplete-item-secondary,
.llm-info-text,
.chunk {
  overflow-wrap: break-word;
  word-break: break-word;
  hyphens: auto;
}

/* Prose measure guard — applied to compact UI text (status line,
   autocomplete items) where the measure stays helpful. The result
   content (answer, Zusammenfassung, page-hit snippets) uses the full
   container width so nothing artificially breaks mid-screen on wide
   displays. */
.status,
.autocomplete-item-primary {
  max-width: var(--measure);
}

body {
  margin: 0;
  font-family: "Ubuntu", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
  background: var(--bg);
  color: var(--text);
  line-height: 1.5;
  transition: background 0.3s ease, color 0.3s ease;
}

/* Universal Focus States for Accessibility
   WCAG 1.4.11: non-text contrast must be ≥ 3:1.
   --primary (always the configured brand hex) gives ≥ 4.5:1 against
   the page bg in both modes. */
*:focus-visible {
  outline: 3px solid var(--primary);
  outline-offset: 2px;
}

/* Global link colour — covers the footer legal links (Impressum ·
   Datenschutz · Barrierefreiheit), the mailto/contact links inside
   those pages, and any bare anchor without a component class. Tracks
   the active portal theme; dark mode uses --primary-ink (the
   text-safe variant) so the link stays legible on dark surfaces. */
a {
  color: var(--primary);
}
a:hover {
  color: var(--primary-hover);
}
:root.dark a {
  color: var(--primary-ink, var(--primary));
}
:root.dark a:hover {
  color: color-mix(in srgb, var(--primary-ink, var(--primary)) 82%, #ffffff);
}

/* WCAG 2.4.1 Bypass Blocks — skip-to-content link, hidden until focused.
   Uses the same clip/clip-path technique as the .sr-only helper below so
   the link is removed from the visual + accessibility layout until keyboard
   focus reveals it. */
.skip-link {
  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:focus,
.skip-link:focus-visible {
  position: absolute;
  top: 0;
  left: 0;
  width: auto;
  height: auto;
  padding: 0.6rem 1.2rem;
  margin: 0;
  clip: auto;
  white-space: normal;
  overflow: visible;
  background: var(--card);
  color: var(--text);
  border: 2px solid var(--primary);
  text-decoration: none;
  font-weight: 600;
  border-radius: 0 0 8px 0;
  z-index: 9999;
  /* Card surface + primary border makes the focused link stand out against
     the green header gradient (was "green on same green"); the border
     replaces the global outline so we suppress it here. */
  outline: none;
}

/* Floating "Back to Top" button — fixed bottom-right, fades in after scroll.
   WCAG 2.5.5: ≥44×44 tap target (3rem = 48px). */
.back-to-top {
  position: fixed;
  bottom: 1.5rem;
  right: 1.5rem;
  width: 3rem;
  height: 3rem;
  border-radius: 50%;
  border: none;
  background: var(--primary);
  color: #fff;
  cursor: pointer;
  box-shadow: var(--shadow-md);
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transform: translateY(8px);
  pointer-events: none;
  transition: opacity 0.2s ease, transform 0.2s ease, background-color 0.15s ease;
  z-index: 100; /* below pdf-modal-backdrop (999), above content */
}
.back-to-top.visible {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}
.back-to-top:hover {
  background: var(--primary-hover);
}
.back-to-top:active {
  transform: translateY(0) scale(0.96);
}
.back-to-top svg {
  width: 1.375rem;
  height: 1.375rem;
  stroke: currentColor;
  fill: none;
  stroke-width: 2.25;
  stroke-linecap: round;
  stroke-linejoin: round;
}
@media (prefers-reduced-motion: reduce) {
  .back-to-top { transition: opacity 0.2s ease; transform: none; }
  .back-to-top.visible { transform: none; }
  .back-to-top:active { transform: none; }
}

/* Visually Hidden Helper for Screen Readers */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.hidden { display: none !important; }
.muted { color: var(--muted); }

/* Login Page Styling */
.login-page {
  position: fixed; inset: 0;
  background: var(--bg);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1.25rem;
  z-index: 2000;
}
.login-box {
  background: var(--card);
  padding: 1.5rem;
  border-radius: 16px;
  box-shadow: var(--shadow-md);
  max-width: 25rem;
  width: min(92%, 25rem);
  text-align: center;
  border: 1px solid var(--border);
}
.login-box h2 {
  margin-top: 0;
  margin-bottom: 0.5rem;
  color: var(--primary-ink, var(--primary));
}
.login-box p {
  color: var(--muted);
  margin-top: 0;
  margin-bottom: 1.5rem;
  font-size: 0.95rem;
}
.login-box input {
  width: 100%;
  padding: 0.75rem 1rem;
  border: 1px solid var(--border);
  background: var(--card);
  color: var(--text);
  border-radius: 8px;
  font-size: 1rem;
  margin-bottom: 1.2rem;
  outline: none;
  transition: border-color 0.15s;
}
.login-box input:focus {
  border-color: var(--primary);
}
.login-box button {
  width: 100%;
}
.error { color: #dc2626; margin: 0.5rem 0 0; min-height: 1.2em; }
.success { color: #15803d; margin: 0.5rem 0 0; min-height: 1.2em; }
:root.dark .error { color: #fca5a5; }
:root.dark .success { color: #86efac; }

/* Site Header Revamp */
.site-header {
  background: linear-gradient(135deg, var(--primary), var(--header-grad-end));
  color: var(--primary-on);
  padding: 1.5rem 2rem;
  box-shadow: 0 4px 12px var(--shadow-md);
}
.site-header h1 { margin: 0; font-size: clamp(0.9rem, 3vw, 1.2rem); line-height: 1.2; }
.header-title-flex {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  min-width: 0;
}
/* Header brand link ("Hamburg • LocalPolitics") — inherits .site-header's
   white (= textOn() of the primary/secondary gradient; primary-on-white
   5.31:1, secondary-on-white ~4.0:1, both pass title-large AA). The global
   `a { color: var(--primary) }` rule at style.css:316 would otherwise paint
   the brand link green on the green gradient ("green on almost the same
   green"). inline-flex so icon + text sit side-by-side; span truncates
   instead of wrapping on narrow viewports. */
.site-header .header-home-link {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  color: inherit;
  text-decoration: none;
  min-width: 0;
}
.site-header .header-home-link:hover,
.site-header .header-home-link:focus-visible {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
}
.site-header .header-home-link span {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}
/* Title never line-breaks on any viewport (UI.md: "no line break for
   Hamburg LocalPolitics"). Flex child needs min-width:0 + nowrap +
   ellipsis so the actions keep their space and the title truncates
   instead of wrapping. */
.header-title-flex > span {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}
.header-icon {
  width: 1.25rem;
  height: 1.25rem;
  stroke: currentColor;
  flex-shrink: 0;
}
.inline-flex-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  justify-content: center;
}
.btn-icon {
  width: 1.125rem;
  height: 1.125rem;
  stroke: currentColor;
  flex-shrink: 0;
}
.subtitle { margin: 0.3rem 0 0; opacity: 0.9; font-size: 0.95rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.subtitle-sub { display: none; }
@media (min-width: 40rem) {
  .subtitle-sub { display: inline; }
}

.site-header-content {
  width: 100%;
  max-width: var(--container-max);
  margin: 0 auto;
  padding-inline: 1rem;
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  align-items: center;
  gap: 0.5rem;
}
@media (min-width: 48rem) {
  .site-header-content { padding-inline: var(--gutter); }
}
.site-header-title {
  text-align: left;
  flex: 1;
  min-width: 0;
}

/* Header Actions & Theme Switcher */
.header-actions {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  flex-shrink: 0;
  justify-content: flex-end;
  flex-direction: row;
  width: auto;
}

.theme-toggle-btn,
.logout-btn.icon-btn,
.reset-app-btn {
  position: relative;
  background: transparent;
  border: 1px solid color-mix(in srgb, var(--primary-on) 40%, transparent);
  color: var(--primary-on);
  border-radius: 6px;
  width: 2.25rem;
  height: 2.25rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: all 0.2s ease;
  padding: 0;
  line-height: 1;
}
.theme-toggle-btn::before,
.logout-btn.icon-btn::before,
.reset-app-btn::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  min-width: var(--tap-min);
  min-height: var(--tap-min);
}
.theme-toggle-btn:hover,
.logout-btn.icon-btn:hover,
.reset-app-btn:hover {
  background: var(--primary-on);
  color: var(--primary-ink, var(--primary));
  border-color: var(--primary-on);
}
.theme-toggle-btn #theme-icon {
  display: block;
  font-size: 0.85rem;
  line-height: 1;
}

.logout-icon {
  width: 1rem;
  height: 1rem;
  stroke: currentColor;
  display: block;
  flex-shrink: 0;
}

/* Main Layout
   Fluid container: edge-to-edge on mobile, growing percentage gutters on
   tablet/desktop, capped at --container-max on ultra-wide. Prose inside
   is measure-limited separately (see .layer-1 .answer, .snippet etc.).
   The selector list covers the bare <main> in index.html and the
   page-specific *-main classes used by impressum/datenschutz/barrierefreiheit. */
main,
.impressum-main,
.datenschutz-main,
.barrierefreiheit-main {
  width: 100%;
  max-width: var(--container-max);
  margin-inline: auto;
  margin-block: 2rem;
  padding-inline: 1rem;
}
@media (min-width: 48rem) {
  main,
  .impressum-main,
  .datenschutz-main,
  .barrierefreiheit-main { padding-inline: var(--gutter); }
}

/* Legal pages (Impressum / Datenschutz / Barrierefreiheit) — same
   theme as the rest of the portal: headings pick up the primary, body
   text the palette text colour, inline <code> gets a primary-tinted
   chip. No hardcoded colours — everything resolves through the
   portal-theme variables, so a flavour switch recolours these pages
   too. */
.impressum-main,
.datenschutz-main,
.barrierefreiheit-main {
  max-width: 46rem;
  padding-block: 1rem 2rem;
}
.impressum-main h2,
.datenschutz-main h2,
.barrierefreiheit-main h2 {
  color: var(--primary);
  margin: 0 0 1rem;
}
:root.dark .impressum-main h2,
:root.dark .datenschutz-main h2,
:root.dark .barrierefreiheit-main h2 {
  color: var(--primary-ink, var(--primary));
}
.impressum-main h3,
.datenschutz-main h3,
.barrierefreiheit-main h3 {
  color: var(--text);
  margin-top: 1.75rem;
}
.impressum-main p,
.datenschutz-main p,
.barrierefreiheit-main p,
.impressum-main ul,
.datenschutz-main ul,
.barrierefreiheit-main ul {
  color: var(--text);
}
.impressum-main code,
.datenschutz-main code,
.barrierefreiheit-main code {
  background: color-mix(in srgb, var(--primary) 10%, var(--card));
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.1rem 0.4rem;
  font-size: 0.9em;
}
.impressum-back,
.datenschutz-back {
  margin-top: 2.5rem;
}

/* "← Zurück zur Startseite" helper link on Impressum / Datenschutz /
   Barrierefreiheit. Renders as an inline link instead of a heavy CTA button.
   Colour tracks the active portal theme via the global `a` rules already at
   style.css:316–327 (light → var(--primary); dark → var(--primary-ink,
   var(--primary))). Tap target meets WCAG 2.5.5 (44 px). Focus ring inherits
   the global *:focus-visible rule at style.css:306. */
.back-link {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.5rem 0.25rem;
  min-height: var(--tap-min);
  font-size: 0.95rem;
  font-weight: 500;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
  border-radius: 4px;
}
.back-link:hover {
  text-decoration-thickness: 2px;
}
/* Dark-mode override: --primary-ink is sometimes set equal to --primary by
   the portal-theme injection (see backend/portal_theme.py _derive_text_ink,
   which only lightens when contrast vs --bg falls below 3:1). On the
   darker --card surface, that produces a green-on-green link below WCAG AA.
   --secondary is always derived as a card-safe light teal (L=62), so we
   pin the helper link to it in dark mode — no hardcoded colours. */
:root.dark .back-link {
  color: var(--secondary);
}
:root.dark .back-link:hover {
  color: color-mix(in srgb, var(--secondary) 82%, #ffffff);
}
@media (prefers-reduced-motion: no-preference) {
  .back-link { transition: text-decoration-thickness 0.15s ease; }
}

.search-section { margin-bottom: 1.5rem; }

/* Unified modern Chat-like Search Bar */
.search-bar {
  display: flex;
  flex-direction: column;
  background: var(--card);
  padding: 0.5rem 0.75rem;
  border-radius: 12px;
  border: 1px solid var(--border);
  box-shadow: var(--shadow-md);
  transition: border-color 0.2s, box-shadow 0.2s;
  gap: 0.5rem;
}
.search-bar:focus-within {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary) 15%, transparent);
}

.query-container {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  width: 100%;
  position: relative;
}
.query-container textarea {
  flex: 1;
  min-width: 0;
  width: 100%;
  border: none;
  background: transparent;
  padding: 0.5rem 0;
  font-size: 1.1rem;
  color: var(--text);
  resize: none;
  /* Query is the PRIMARY input — must dominate the search card. 4rem
     (≈64 px) holds a 2-line placeholder without clipping and visually
     outweighs the compact single-line location row (UI.md item #1:
     "Set this as the primary input with the larger vertical
     proportion"). */
  min-height: 4rem;
  max-height: 12.5rem;
  outline: none;
  font-family: inherit;
  line-height: 1.5;
  overflow-y: hidden;
}
.query-container textarea::placeholder {
  /* bürgerfixes + WCAG 1.4.3: removed opacity:0.8 — effective contrast
     was ~3.2:1, below the 4.5:1 minimum. */
  color: var(--muted);
}

/* G2: shared base class for circular icon controls (?, ↩, reset).
   All three look like siblings of the help trigger.
   Visual size stays compact (rem); a transparent ::before expands the
   clickable hit area to --tap-min (44px) for WCAG 2.5.5. */
.icon-ctrl {
  position: relative;
  cursor: pointer;
  background: color-mix(in srgb, var(--text) 8%, transparent);
  color: var(--muted);
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.8rem;
  font-weight: bold;
  user-select: none;
  transition: background 0.15s, color 0.15s;
  border: none;
  padding: 0;
  font-family: inherit;
  flex-shrink: 0;
}
.icon-ctrl::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  min-width: var(--tap-min);
  min-height: var(--tap-min);
}
.icon-ctrl:hover, .icon-ctrl:focus-visible {
  background: var(--primary);
  color: white;
  outline: none;
}
.icon-ctrl svg { display: block; }

/* The "?" trigger sits at the top of the search row by default; the
   location-input-wrap version is inline. Hidden on touch-only viewports
   (the help content is in the visible "Tipp" hint + button label). */
.field-help-trigger { margin-top: 0.4rem; display: none; }
.location-input-wrap .field-help-trigger { margin-top: 0; }

/* G2: revert "↩" — round icon sibling of "?", same .icon-ctrl family. */
.location-revert-btn {
  /* Inherits .icon-ctrl visual rules. */
  font-size: 0.95rem;
  font-weight: 600;
}

.search-bar-actions {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  border-top: 1px solid var(--border);
  padding-top: 0.4rem;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.search-options {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0.4rem;
}

.buttons {
  display: flex;
  flex-direction: row;
  width: 100%;
  gap: 0.4rem;
}
.buttons .btn {
  flex: 1;
  padding: 0.5rem 0.6rem;
  font-size: 0.85rem;
  white-space: nowrap;
}

.btn {
  padding: 0.7rem 1.1rem;
  border: none;
  border-radius: 8px;
  font-size: 0.95rem;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s, transform 0.05s;
  text-decoration: none;
  display: inline-block;
  color: white;
}
.btn:active { transform: translateY(1px); }
.btn:disabled { opacity: 0.6; cursor: not-allowed; }
.btn.primary { background: var(--primary); }
.btn.primary:hover:not(:disabled) { background: var(--primary-hover); }
/* WCAG 1.4.11 (non-text contrast ≥3:1 for UI component boundaries):
   in dark mode the green primary fill (#317765) is only 2.78:1 vs the
   dark card — a 1px --primary-ink border (#80c9b3 = 7.67:1 vs card)
   restores the visible boundary without changing the brand green. */
:root.dark .btn.primary,
:root.system-theme-active .btn.primary {
  border: 1px solid var(--primary-ink);
}
:root.dark .btn.primary:hover:not(:disabled),
:root.system-theme-active .btn.primary:hover:not(:disabled) {
  border-color: var(--primary-ink);
}
.btn.secondary { background: var(--secondary); }
.btn.secondary:hover:not(:disabled) { background: var(--secondary-hover); }
.btn.small {
  padding: 0.5rem 0.85rem;
  font-size: 0.875rem;
  /* WCAG contrast (verified): surface=--muted + text=--bg inverts the
     themed muted-on-bg pair → same ≥4.5:1 ratio (1.4.3); surface vs
     card ≥3:1 (1.4.11). Light defaults: 6.18 / 5.62. Dark defaults:
     6.58 / 7.7. Adapts automatically to any portal-theme flavour that
     satisfies its own muted text contract. */
  background: var(--muted);
  color: var(--bg);
  min-height: var(--tap-min);
}
.btn.small:hover:not(:disabled) {
  /* Hover mixes 60/40 toward --text — darkens in light mode / lightens
     in dark mode — improving both contrasts (light hover 9.17/8.34,
     dark hover 8.92/10.44) with one formula. */
  background: color-mix(in srgb, var(--muted) 60%, var(--text));
}

.status {
  margin-top: 0.35rem;
  padding: 0;
  font-size: 0.72rem;
  color: var(--muted);
  min-height: 0;
}

/* Small inline cache badge that stays visible next to the status line
   after a cached LLM result. Designed to be clearly seeable (green
   pill) without dominating the UI. */
.llm-cache-badge {
  display: inline-block;
  margin-left: 0.5rem;
  padding: 0.15rem 0.55rem;
  font-size: 0.78rem;
  font-weight: 600;
  color: #14532d;
  background: #dcfce7;
  border: 1px solid #86efac;
  border-radius: 999px;
  vertical-align: middle;
  white-space: nowrap;
  transition: background 0.2s ease;
}
.llm-cache-badge::before {
  content: "📦";
  margin-right: 0.3rem;
}
.dark .llm-cache-badge {
  color: #bbf7d0;
  background: #14532d;
  border-color: #166534;
}

/* LLM Results & Analysis Box */
.llm-info {
  background: linear-gradient(135deg, var(--llm-info-bg-start), var(--llm-info-bg-end));
  border-left: 4px solid var(--secondary);
  padding: 0.6rem 0.75rem;
  border-radius: 12px;
  margin-bottom: 1.5rem;
  font-size: 0.85rem;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0.5rem;
  flex-wrap: wrap;
}
.llm-info-text { flex: 1 1 auto; min-width: 0; line-height: 1.6; }
.export-pdf-btn {
  background: var(--primary);
  color: white;
  white-space: nowrap;
  box-shadow: 0 1px 3px var(--shadow-md);
  width: 100%;
  text-align: center;
  padding: 0.5rem 0.6rem;
  font-size: 0.85rem;
}
.export-pdf-btn:hover:not(:disabled) {
  background: var(--primary-hover);
  box-shadow: 0 2px 6px var(--shadow-lg);
}
.export-pdf-btn:disabled { opacity: 0.6; cursor: not-allowed; }

.followup-label {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.875rem;
  color: var(--muted);
  cursor: pointer;
  padding: 0.5rem 0.85rem;
  border-radius: 999px;
  background: color-mix(in srgb, var(--primary) 8%, transparent);
  border: 1px solid color-mix(in srgb, var(--primary) 18%, transparent);
  user-select: none;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
  min-height: var(--tap-min);
}
.followup-label:has(input:checked) {
  background: color-mix(in srgb, var(--primary) 18%, transparent);
  border-color: color-mix(in srgb, var(--primary) 35%, transparent);
  color: var(--primary-ink, var(--primary));
}
:root.dark .followup-label {
  background: color-mix(in srgb, var(--primary) 14%, transparent);
  border-color: color-mix(in srgb, var(--primary) 25%, transparent);
}
:root.dark .followup-label:has(input:checked) {
  background: color-mix(in srgb, var(--primary) 24%, transparent);
  border-color: color-mix(in srgb, var(--primary) 45%, transparent);
}
.followup-label input[type="checkbox"] {
  width: 0.875rem;
  height: 0.875rem;
  accent-color: var(--primary);
  cursor: pointer;
  margin: 0;
}

.followup-context {
  margin-top: 0.5rem;
  padding: 0.45rem 0.7rem;
  font-size: 0.85rem;
  color: var(--secondary);
  font-style: italic;
  background: color-mix(in srgb, var(--secondary) 8%, transparent);
  border-radius: 8px;
  border-left: 3px solid var(--secondary);
}

/* LLM Status Row + Slide-out Side Panel */
.status-row {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin-top: 0.75rem;
  padding: 0 0.25rem;
}
.status-row .status {
  margin-top: 0;
  flex: 1;
}

.llm-log-toggle-btn {
  background: none;
  border: 1px solid transparent;
  border-radius: 6px;
  padding: 0.2rem 0.3rem;
  cursor: pointer;
  color: var(--muted);
  display: flex;
  align-items: center;
  transition: color 0.15s, border-color 0.15s, background 0.15s;
  flex-shrink: 0;
  position: relative;
  min-height: var(--tap-min);
  min-width: var(--tap-min);
  justify-content: center;
}
.llm-log-toggle-btn::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  min-width: var(--tap-min);
  min-height: var(--tap-min);
}
.llm-log-toggle-btn:hover {
  color: var(--primary-ink, var(--primary));
  border-color: var(--border);
  background: color-mix(in srgb, var(--primary) 8%, transparent);
}
.llm-log-toggle-btn svg {
  width: 0.9375rem;
  height: 0.9375rem;
  position: relative;
  z-index: 1;
}
.llm-log-toggle-btn.active::after {
  content: "";
  position: absolute;
  top: 2px;
  right: 2px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent);
  animation: llm-pulse 1.5s ease-in-out infinite;
}
@keyframes llm-pulse {
  0%, 100% { opacity: 0.4; }
  50% { opacity: 1; }
}

.llm-log-backdrop {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.3);
  z-index: 39;
  animation: llm-fade-in 0.2s ease;
}

.llm-log-panel {
  position: fixed;
  top: 0;
  right: 0;
  height: 100vh;
  height: 100dvh;
  width: clamp(15rem, 22vw, 25rem);
  min-width: 15rem;
  background: var(--card);
  border-left: 1px solid var(--border);
  border-top: 3px solid var(--primary);
  box-shadow: -4px 0 24px rgba(0, 0, 0, 0.12);
  z-index: 40;
  display: flex;
  flex-direction: column;
  transform: translateX(100%);
  transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1);
  pointer-events: none;
}
.llm-log-panel.open {
  transform: translateX(0);
  pointer-events: auto;
}

@media (min-width: 64rem) {
  .llm-log-panel {
    height: auto;
    max-height: 75vh;
    max-height: 75dvh;
    top: 50%;
    transform: translate(100%, -50%);
    border-radius: 12px 0 0 12px;
    border-left: 1px solid var(--border);
    border-top: 3px solid var(--primary);
  }
  .llm-log-panel.open {
    transform: translate(0, -50%);
  }
  .llm-log-backdrop { display: none !important; }
}

/* Map panel heights — the base :root values are 30dvh / 65dvh, fine on
   phone-portrait but excessive on tablet. Cap with absolute rem at 48rem
   and grow again for desktop where the panel runs side-by-side with
   the committee list. */
@media (min-width: 48rem) {
  :root { --map-min-h: 22rem; --map-max-h: 28rem; }
}
@media (min-width: 64rem) {
  :root { --map-min-h: 26rem; --map-max-h: 34rem; }
}

.llm-log-panel-list {
  list-style: none;
  margin: 0;
  padding: 0.5rem 1rem;
  overflow-y: auto;
  flex: 1;
  font-size: 0.82rem;
  line-height: 1.5;
  font-family: inherit;
}
.llm-log-panel-item {
  padding: 0.35rem 0;
  border-bottom: 1px solid color-mix(in srgb, var(--border) 50%, transparent);
  color: var(--muted);
  transition: color 0.15s;
  white-space: pre-wrap;
  word-break: break-word;
}
.llm-log-panel-item:last-child { border-bottom: none; }
.llm-log-panel-item:first-child { color: #92400e; font-weight: 500; }
:root.dark .llm-log-panel-item:first-child { color: var(--accent); }

@keyframes llm-fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

/* Results Listing */
.results { display: flex; flex-direction: column; gap: 0.75rem; }

/* B5: cache-hit badge — sits below the results, shows "⚡ Aus dem Cache" */
.cache-hit-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  margin-top: 0.25rem;
  padding: 0.25rem 0.75rem;
  border-radius: 999px;
  background: color-mix(in srgb, var(--primary) 12%, var(--card, transparent));
  border: 1px solid color-mix(in srgb, var(--primary) 40%, var(--border, #ccc));
  color: var(--primary-ink, var(--primary));
  font-size: 0.8rem;
  font-weight: 600;
  align-self: flex-start;
}
.cache-hit-badge.hidden { display: none; }
:root.dark .cache-hit-badge {
  background: color-mix(in srgb, var(--primary) 18%, var(--card));
  color: var(--primary-ink, var(--primary));
}
.cache-hit-icon { font-size: 1rem; }

/* Revamped Result Card with beautiful CSS color-mix tints */
.result-card {
  background: var(--card);
  border: 1px solid var(--border);
  border-left: 4px solid var(--border);
  border-radius: 10px;
  padding: 0.7rem 0.8rem;
  transition: box-shadow 0.2s ease, border-color 0.2s ease, transform 0.1s ease;
}
.result-card:hover {
  box-shadow: var(--shadow-md);
  transform: translateY(-1px);
}

.result-header {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 0.5rem;
  margin-bottom: 0.75rem;
  flex-wrap: wrap;
}
.result-title { font-weight: 700; font-size: 1rem; color: var(--text); }
.result-meta {
  font-size: 0.78rem;
  color: var(--muted);
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
  align-items: center;
  margin-bottom: 0.5rem;
}

.doc-type-badge {
  display: inline-block;
  padding: 0.15rem 0.6rem;
  border-radius: 999px;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  white-space: nowrap;
  text-transform: uppercase;
}
.doc-type-badge.doc-badge-protokoll { background: var(--doc-group-protokoll-bg); color: var(--doc-group-protokoll-fg); }
.doc-type-badge.doc-badge-antrag { background: var(--doc-group-antrag-bg); color: var(--doc-group-antrag-fg); }
.doc-type-badge.doc-badge-anfrage { background: var(--doc-group-anfrage-bg); color: var(--doc-group-anfrage-fg); }
.doc-type-badge.doc-badge-mitteilung { background: var(--doc-group-mitteilung-bg); color: var(--doc-group-mitteilung-fg); }
.doc-type-badge.doc-badge-antwort { background: var(--doc-group-antwort-bg); color: var(--doc-group-antwort-fg); }
.doc-type-badge.doc-badge-beschluss { background: var(--doc-group-beschluss-bg); color: var(--doc-group-beschluss-fg); }
.doc-type-badge.doc-badge-bericht { background: var(--doc-group-bericht-bg); color: var(--doc-group-bericht-fg); }
.doc-type-badge.doc-badge-drucksache { background: var(--doc-group-drucksache-bg); color: var(--doc-group-drucksache-fg); }
.doc-type-badge.doc-badge-gesetz { background: var(--doc-group-gesetz-bg); color: var(--doc-group-gesetz-fg); }
.doc-type-badge.doc-badge-einladung { background: var(--doc-group-einladung-bg); color: var(--doc-group-einladung-fg); }
.doc-type-badge.doc-badge-anlage { background: var(--doc-group-anlage-bg); color: var(--doc-group-anlage-fg); }
.doc-type-badge.doc-badge-sonstige { background: var(--doc-group-sonstige-bg); color: var(--doc-group-sonstige-fg); }
.doc-type-badge.doc-badge-admin { background: var(--doc-group-admin-bg); color: var(--doc-group-admin-fg); }

.district-badge {
  display: inline-block;
  padding: 0.2rem 0.65rem;
  border-radius: 999px;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  white-space: nowrap;
  background: var(--district-color, var(--district-default));
  color: var(--district-on, #ffffff);
  border: 1px solid color-mix(in srgb, var(--district-color, var(--district-default)) 60%, #000);
}
.committee-label {
  display: inline-block;
  font-weight: 500;
  font-size: 0.8rem;
  color: var(--muted);
  padding: 0.12rem 0.5rem;
  border-radius: 6px;
  background: color-mix(in srgb, var(--text) 5%, transparent);
  border: 1px solid color-mix(in srgb, var(--text) 12%, transparent);
}
.result-badge {
  background: var(--highlight);
  color: #ffffff;
  padding: 0.15rem 0.55rem;
  border-radius: 4px;
  font-size: 0.78rem;
  font-weight: 700;
}
.score-bar {
  height: 0.375rem;
  background: var(--border);
  border-radius: 3px;
  margin: 0.6rem 0;
  overflow: hidden;
}
.score-bar-fill {
  height: 100%;
  background: linear-gradient(90deg,
    var(--district-color, var(--primary)),
    color-mix(in srgb, var(--district-color, var(--primary)) 50%, var(--secondary))
  );
}

.snippet {
  font-size: 0.88rem;
  color: var(--text);
  line-height: 1.6;
  margin: 0.4rem 0;
  max-width: 100%;
  overflow-wrap: anywhere;
  word-break: break-word;
}
.snippet mark {
  background: var(--highlight);
  color: #ffffff;
  padding: 0.05em 0.2em;
  border-radius: 2px;
  font-weight: 700;
}
.llm-reason {
  font-size: 0.82rem;
  color: var(--secondary);
  font-style: italic;
  margin-top: 0.5rem;
  font-weight: 500;
  max-width: 100%;
  overflow-wrap: anywhere;
  word-break: break-word;
}
.result-actions {
  display: flex;
  gap: 0.5rem;
  margin-top: 0.75rem;
  flex-wrap: wrap;
}

/* Grouped page hits inside a single document card */
.page-hits {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  margin: 0.6rem 0;
}
.page-hit {
  border: 1px solid color-mix(in srgb, var(--district-color, var(--border)) 30%, var(--border));
  border-left: 3px solid var(--district-color, var(--primary));
  border-radius: 8px;
  padding: 0.55rem 0.7rem;
  background: color-mix(in srgb, var(--district-color, var(--card)) 6%, var(--card));
  transition: background 0.15s ease;
}
.page-hit:hover {
  background: color-mix(in srgb, var(--district-color, var(--card)) 12%, var(--card));
}
.page-hit-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0.4rem;
  flex-wrap: wrap;
}
.page-hit-label {
  font-size: 0.82rem;
  font-weight: 700;
  color: var(--text);
  opacity: 0.9;
}
.page-hit-snippet {
  font-size: 0.85rem;
  color: var(--text);
  line-height: 1.55;
  max-width: 100%;
  overflow-wrap: anywhere;
  word-break: break-word;
}
.page-hit .btn {
  font-size: 0.8125rem;
  padding: 0.4rem 0.7rem;
  min-height: var(--tap-min);
}
.page-hit .llm-reason {
  margin-top: 0.4rem;
  font-size: 0.85rem;
}

/* Card Accent Classes (dynamically set in JS) */
.result-card.district-accent-hamburgnord,
.doc-card.district-accent-hamburgnord { --district-color: var(--district-hamburgnord); --district-on: var(--district-on-hamburgnord); }
.result-card.district-accent-hamburgmitte,
.doc-card.district-accent-hamburgmitte { --district-color: var(--district-hamburgmitte); --district-on: var(--district-on-hamburgmitte); }
.result-card.district-accent-altona,
.doc-card.district-accent-altona { --district-color: var(--district-altona); --district-on: var(--district-on-altona); }
.result-card.district-accent-eimsbuettel,
.doc-card.district-accent-eimsbuettel { --district-color: var(--district-eimsbuettel); --district-on: var(--district-on-eimsbuettel); }
.result-card.district-accent-wandsbek,
.doc-card.district-accent-wandsbek { --district-color: var(--district-wandsbek); --district-on: var(--district-on-wandsbek); }
.result-card.district-accent-bergedorf,
.doc-card.district-accent-bergedorf { --district-color: var(--district-bergedorf); --district-on: var(--district-on-bergedorf); }
.result-card.district-accent-harburg,
.doc-card.district-accent-harburg { --district-color: var(--district-harburg); --district-on: var(--district-on-harburg); }
.result-card.district-accent-buergerschaft,
.doc-card.district-accent-buergerschaft { --district-color: var(--district-buergerschaft); --district-on: var(--district-on-buergerschaft); }
.result-card.district-accent-senat,
.doc-card.district-accent-senat { --district-color: var(--district-senat); --district-on: var(--district-on-senat); }
.result-card.district-accent-extern,
.doc-card.district-accent-extern { --district-color: var(--district-extern); --district-on: var(--district-on-extern); }
.result-card.district-accent-default,
.doc-card.district-accent-default { --district-color: var(--district-default); }

.result-card {
  --district-color: var(--district-default);
  border-left: 4px solid var(--district-color);
  border-top: 1px solid color-mix(in srgb, var(--district-color) 25%, transparent);
  border-right: 1px solid color-mix(in srgb, var(--district-color) 25%, transparent);
  border-bottom: 1px solid color-mix(in srgb, var(--district-color) 25%, transparent);
  background: color-mix(in srgb, var(--district-color) 12%, var(--card));
  transition: box-shadow 0.2s ease, border-color 0.2s ease, transform 0.1s ease, background 0.2s ease;
}
:root.dark .result-card {
  background: color-mix(in srgb, var(--district-color) 18%, var(--card));
  border-top-color: color-mix(in srgb, var(--district-color) 35%, transparent);
  border-right-color: color-mix(in srgb, var(--district-color) 35%, transparent);
  border-bottom-color: color-mix(in srgb, var(--district-color) 35%, transparent);
}

.doc-title-row {
  margin-top: 0.375rem;
  font-weight: 600;
  font-size: 0.95em;
  color: var(--text);
  opacity: 0.95;
}

/* Modals & PDF Viewer */
.pdf-modal-backdrop {
  position: fixed; inset: 0;
  background: rgba(0, 0, 0, 0.6); /* Neutral dim — not Volt-tinted */
  z-index: 999;
  backdrop-filter: blur(4px);
}
.pdf-viewer {
  position: fixed;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: 96vw;
  height: 96vh;
  height: 96dvh;
  background: var(--card);
  box-shadow: var(--shadow-md);
  border-radius: 8px;
  z-index: 1000;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border: 1px solid var(--border);
}
.pdf-header, .pdf-controls {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0.5rem 0.75rem;
  background: var(--bg);
  border-bottom: 1px solid var(--border);
  gap: 0.5rem;
  flex-wrap: wrap;
  color: var(--text);
}
.pdf-header > div { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.pdf-status {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.15rem 0.55rem;
  border-radius: 999px;
  font-size: 0.78rem;
  font-weight: 600;
  line-height: 1.2;
  border: 1px solid var(--border);
  background: var(--bg);
  color: var(--text);
}
.pdf-status--loading {
  border-color: color-mix(in srgb, var(--primary) 60%, var(--border));
  color: var(--primary-ink, var(--primary));
}
.pdf-status--loading::before {
  content: "";
  width: 0.65rem;
  height: 0.65rem;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  animation: pdf-status-spin 0.9s linear infinite;
}
.pdf-status--error {
  border-color: color-mix(in srgb, #c0392b 60%, var(--border));
  color: #c0392b;
  background: color-mix(in srgb, #c0392b 8%, var(--bg));
}
.pdf-status--done { display: none; }
@keyframes pdf-status-spin {
  to { transform: rotate(360deg); }
}
.pdf-container {
  flex: 1;
  overflow: hidden;
  background: color-mix(in srgb, var(--border) 40%, #000);
}
.pdf-iframe {
  width: 100%;
  height: 100%;
  border: none;
}

/* Indexer Status Messages (moved from inline styles) */
.indexer-status-msg {
  margin-top: 0.5rem;
  color: var(--primary-ink, var(--primary));
  font-weight: 600;
  display: flex;
  align-items: center;
  gap: 0.375rem;
  justify-content: center;
}
.indexer-spinner {
  display: inline-block;
  width: 0.875rem;
  height: 0.875rem;
  border: 2px solid var(--primary);
  border-radius: 50%;
  border-top-color: transparent;
  animation: spin 1s linear infinite;
}
.indexer-status-file {
  font-size: 0.8em;
  color: var(--muted);
  margin-top: 0.125rem;
}
.indexer-status-failed {
  color: #b00020;
  font-weight: 600;
}

/* Subtle KI/privacy hint above the legal-link row in the site footer.
   Tracks the link colour so it visibly belongs to the same row; dark
   mode uses --secondary (the same card-safe teal used by .back-link)
   because the portal-theme injection currently resolves --primary-ink
   equal to --primary, which would otherwise reproduce the green-on-green
   contrast failure (2.78:1 vs --card) on this exact spot. No
   hardcoded colours. */
.footer-notice {
  margin: 0 0 0.5rem;
  font-size: 0.8rem;
  color: var(--primary);
  font-weight: 400;
  line-height: 1.4;
}
:root.dark .footer-notice {
  color: var(--secondary);
}

/* Site Footer */
.site-footer {
  text-align: center;
  padding: 1rem;
  color: var(--muted);
  font-size: 0.8rem;
  border-top: 1px solid var(--border);
  /* bürgerfixes #6: 2rem instead of 3rem so the footer sits closer to
     the content and is more likely to be visible above the fold in
     light mode on the default empty loaded screen. */
  margin-top: 2rem;
  line-height: 1.6;
}

.app-version {
  margin: 0;
  font-size: 0.75rem;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  line-height: 1.4;
}
.site-footer p:has(+ .app-version) {
  margin-bottom: 0;
}

.nightly-status {
  margin-top: 0.5rem;
  font-size: 0.8rem;
  font-variant-numeric: tabular-nums;
  line-height: 1.4;
}
.nightly-stats-details {
  font-size: 0.75rem;
  color: var(--muted);
  margin-top: 0.25rem;
  font-variant-numeric: tabular-nums;
}
.nightly-ok {
  color: #1a7f37;
  font-weight: 600;
}
:root.dark .nightly-ok {
  color: #34d399;
}
.nightly-warn {
  color: #b35900;
  font-weight: 600;
}
:root.dark .nightly-warn {
  color: #fbbf24;
}

.status-dot {
  display: inline-block;
  width: 0.6em;
  height: 0.6em;
  border-radius: 50%;
  margin-right: 0.35em;
  vertical-align: 0.08em;
}
a.status-dot {
  cursor: pointer;
  text-decoration: none;
}
.status-dot-ok   { background: #1a7f37; }
:root.dark .status-dot-ok { background: #34d399; }
.status-dot-warn { background: #d97706; }
:root.dark .status-dot-warn { background: #fbbf24; }
.status-dot-err  { background: #cf222e; }
:root.dark .status-dot-err { background: #f87171; }

/* ---------------------------------------------------------------------------
   Mobile-first breakpoint tiers (inverted from the old max-width: 600px
   desktop-first approach). Base styles above are the mobile defaults;
   these blocks enhance progressively on tablet / desktop / ultra-wide.

     @media (min-width: 40rem)  = ≥640px   large phone / small tablet
     @media (min-width: 48rem)  = ≥768px   tablet — gutter padding kicks in
     @media (min-width: 64rem)  = ≥1024px  desktop — side-panel morph
     @media (min-width: 112.5rem) ≥1800px  ultra-wide — container cap
   --------------------------------------------------------------------------- */

@media (min-width: 40rem) {
  /* Show the help trigger once the user has a real pointer (hover/focus
     affordances are useful). Hidden by default on touch. */
  .field-help-trigger { display: flex; }

  /* Site header expands for larger viewports. */
  .site-header { padding: 1.25rem 1.5rem; }
  .site-header-content { gap: 1.25rem; flex-wrap: wrap; }
  .site-header h1 { font-size: 1.4rem; }
  .header-icon { width: 1.5rem; height: 1.5rem; }
  .header-title-flex { gap: 0.6rem; }
  .header-actions { gap: 0.75rem; }
  .theme-toggle-btn #theme-icon { font-size: 1rem; }

  /* More comfortable vertical rhythm. */
  main { margin-block: 1.5rem 2rem; }
  .search-section { margin-bottom: 1.25rem; }

  /* Search bar grows back. */
  .search-bar { padding: 0.75rem 1rem; border-radius: 16px; gap: 0.75rem; }
  .query-container textarea { font-size: 1.15rem; min-height: 4rem; }

  /* Stack → horizontal for the actions row. */
  .search-bar-actions {
    flex-direction: row;
    justify-content: space-between;
    align-items: center;
    gap: 0.75rem;
    padding-top: 0.6rem;
  }
  .search-options { flex-direction: row; align-items: center; gap: 1rem; }
  .buttons { width: auto; }
  .buttons .btn { flex: 0 1 auto; padding: 0.7rem 1.1rem; font-size: 0.95rem; }

  /* Status: a little breathing room. */
  .status {
    margin-top: 0.75rem;
    padding: 0 0.25rem;
    font-size: 0.9rem;
    min-height: 1.2em;
  }

  /* Login box expands. */
  .login-box { padding: 2rem; }

  /* LLM info — side-by-side on tablet+. */
  .llm-info {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    gap: 0.8rem;
    padding: 1rem 1.2rem;
    font-size: 0.95rem;
  }
  .export-pdf-btn {
    width: auto;
    text-align: center;
    padding: 0.7rem 1.1rem;
    font-size: 0.95rem;
  }

  /* Result cards expand. */
  .result-card { padding: 1.25rem 1.5rem; border-radius: 12px; }
  .result-title { font-size: 1.1rem; }
  .result-meta { font-size: 0.85rem; gap: 0.8rem; }
  .snippet { font-size: 0.95rem; margin: 0.6rem 0; }
  .llm-reason { font-size: 0.9rem; }
  .result-actions { margin-top: 0.75rem; }
  .page-hit { padding: 0.75rem 1rem; }
  .page-hit-snippet { font-size: 0.92rem; }

  /* Site footer expands. */
  .site-footer { padding: 1.5rem 1rem; font-size: 0.85rem; }

  /* PDF viewer: capped modal size, generous header padding. */
  .pdf-viewer {
    width: min(90vw, 68.75rem);
    height: min(90vh, 56.25rem);
    height: min(90dvh, 56.25rem);
    border-radius: 16px;
  }
  .pdf-header, .pdf-controls { padding: 0.75rem 1.25rem; }
}

/* 48rem tier — tablet / small-desktop. Search bar gains a touch more
   breathing room and the LLM info grows; the layout is now stable on
   its way to the 64rem desktop tier. */
@media (min-width: 48rem) {
  .search-bar { padding: 0.9rem 1.1rem; border-radius: 18px; gap: 0.85rem; }
  .query-container textarea { font-size: 1.2rem; min-height: 4.5rem; }
  .search-bar-actions { gap: 1rem; padding-top: 0.7rem; }
  .llm-info { padding: 1.1rem 1.4rem; font-size: 1rem; }
}

@keyframes spin {
  to { transform: rotate(360deg); }
}

/* ---------------------------------------------------------------------------
   Markdown rendering inside snippets.
   The `.md` class is added to .snippet and .page-hit-snippet containers
   that hold rendered pymupdf4llm markdown (GFM tables, ## headers,
   **bold**, lists, etc.). Kept scoped to snippet containers so we never
   accidentally restyle other markdown on the page.
   --------------------------------------------------------------------------- */
.snippet.md table,
.page-hit-snippet.md table {
  border-collapse: collapse;
  width: 100%;
  max-width: 100%;
  margin: 0.4rem 0;
  font-size: 0.88em;
  background: var(--card, transparent);
}
.snippet.md th,
.snippet.md td,
.page-hit-snippet.md th,
.page-hit-snippet.md td {
  border: 1px solid var(--border, #d0d0d0);
  padding: 0.3rem 0.55rem;
  text-align: left;
  vertical-align: top;
  overflow-wrap: anywhere;
}
.snippet.md th,
.page-hit-snippet.md th {
  background: var(--th-bg, rgba(127, 127, 127, 0.08));
  font-weight: 600;
}
.snippet.md tbody tr:nth-child(even),
.page-hit-snippet.md tbody tr:nth-child(even) {
  background: var(--row-alt-bg, rgba(127, 127, 127, 0.04));
}
.snippet.md h1,
.snippet.md h2,
.snippet.md h3,
.snippet.md h4,
.snippet.md h5,
.snippet.md h6,
.page-hit-snippet.md h1,
.page-hit-snippet.md h2,
.page-hit-snippet.md h3,
.page-hit-snippet.md h4,
.page-hit-snippet.md h5,
.page-hit-snippet.md h6 {
  font-size: 1em;
  margin: 0.4rem 0 0.2rem;
  font-weight: 600;
}
.snippet.md p,
.page-hit-snippet.md p {
  margin: 0.25rem 0;
}
.snippet.md ul,
.snippet.md ol,
.page-hit-snippet.md ul,
.page-hit-snippet.md ol {
  margin: 0.25rem 0 0.25rem 1.25rem;
  padding: 0;
}
.snippet.md li,
.page-hit-snippet.md li {
  margin: 0.1rem 0;
}
.snippet.md code,
.page-hit-snippet.md code {
  background: var(--code-bg, rgba(127, 127, 127, 0.12));
  padding: 0.05rem 0.25rem;
  border-radius: 3px;
  font-size: 0.92em;
}
.snippet.md blockquote,
.page-hit-snippet.md blockquote {
  border-left: 3px solid var(--border, #d0d0d0);
  margin: 0.3rem 0;
  padding: 0.1rem 0.6rem;
  color: var(--muted, #666);
  font-style: italic;
}
/* Honor the existing <mark> highlight style inside rendered markdown. */
.snippet.md mark,
.page-hit-snippet.md mark {
  background: var(--highlight);
  color: #ffffff;
  padding: 0 0.05rem;
  border-radius: 2px;
}

/* --- Bürgerportal additions --- */
/* Location display under the search bar. Empty until a location is
 * resolved; .active turns it into the Volt purple when set. */
.location-display {
  font-size: 0.9rem;
  color: var(--muted);
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  text-align: left;
}
.location-display.active {
  color: var(--primary-ink, var(--primary));
  font-weight: 500;
}

/* --- Bürgerportal Phase 3 — 3-layer progressive disclosure + map --- */

/* Location panel — inline, large, toggled by the 📍 button.
 * Same card styling as the rest of the page (NOT a popup with a
 * different design). The map is full-width and tall — the user said
 * "you have the screen size you don't need to annoy the user with
 * such a minimap". */
.location-panel {
  margin: 0.8rem 0;
  padding: 1rem;
  border: 1px solid var(--border, #d8d4cf);
  border-radius: 12px;
  background: var(--card, #ffffff);
}
.location-panel-bar {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
  align-items: center;
  margin-bottom: 0.8rem;
}
.location-panel-bar input[type="text"] {
  flex: 1 1 13.75rem;
  min-width: 12.5rem;
  padding: 0.6rem 0.8rem;
  font-size: 1rem;
  border: 1px solid var(--border, #d8d4cf);
  border-radius: 8px;
  background: var(--bg, #ffffff);
  color: var(--text, #1a1a1a);
  min-height: var(--tap-min);
}
.location-panel-bar input[type="text"]:focus {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
  border-color: var(--primary);
}

/* Dark-mode: don't let the map area be a white block. */
:root.dark .location-panel {
  background: var(--card, #2a2a2a);
  border-color: var(--border, #444);
}
:root.dark .location-panel-bar input[type="text"] {
  background: var(--bg, #1a1a1a);
  color: var(--text, #f0f0f0);
  border-color: var(--border, #444);
}
:root.dark .buerger-map {
  background: #1a1a1a; /* matches dark map bg */
}

/* Layer 1 — the einfache-Sprache answer (always visible). */
.layer-1 {
  background: var(--card, #ffffff);
  border-left: 4px solid var(--primary);
  border-radius: 12px;
  padding: 1.2rem 1.4rem;
  margin: 1.2rem 0;
  box-shadow: 0 1px 3px rgba(0,0,0,0.06);
}
.layer-1 .layer-heading {
  margin: 0 0 0.6rem 0;
  font-size: 1.25rem;
  color: var(--primary-ink, var(--primary));
}
.layer-1 .answer {
  font-size: 1.08rem;
  line-height: 1.6;
}
.layer-1 .answer p { margin: 0.6rem 0; }
.layer-1 .answer ul, .layer-1 .answer ol { padding-left: 1.4rem; }

/* Top-level "Lesen hilft!" toggle. */
.layer-2-toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  gap: 0.8rem;
  padding: 0.9rem 1.2rem;
  font-size: 1.15rem;
  font-weight: 700;
  border-radius: 12px;
  margin: 0.4rem 0 0 0;
  cursor: pointer;
  background: var(--primary);
  color: #ffffff;
  border: none;
  text-align: left;
}
.layer-2-toggle:hover { filter: brightness(0.95); }
.layer-2-toggle .layer-toggle-label { flex: 1; }
.layer-2-toggle .layer-toggle-meta {
  font-size: 0.95rem;
  font-weight: 500;
  opacity: 0.92;
}
.layer-2-toggle .layer-toggle-arrow {
  display: inline-block;
  transition: transform 0.15s ease;
}
.layer-2-toggle[aria-expanded="true"] .layer-toggle-arrow {
  transform: rotate(180deg);
}

/* Layer 2 — list of per-Drucksache cards. */
.layer-2 {
  margin-top: 0.6rem;
}
.doc-card {
  background: var(--card, #ffffff);
  border: 1px solid var(--border, #e2dcd6);
  border-radius: 12px;
  padding: 1rem 1.2rem;
  margin: 0.7rem 0;
  box-shadow: 0 1px 3px rgba(0,0,0,0.05);
}
/* Politician-parity district accent on the Layer-2 doc-card.
   The district-accent selectors above set --district-color on the
   element; this block paints the left border + tinted background so
   the closed card shows where the document is from. */
.doc-card.district-accent-hamburgnord,
.doc-card.district-accent-hamburgmitte,
.doc-card.district-accent-altona,
.doc-card.district-accent-eimsbuettel,
.doc-card.district-accent-wandsbek,
.doc-card.district-accent-bergedorf,
.doc-card.district-accent-harburg,
.doc-card.district-accent-buergerschaft,
.doc-card.district-accent-senat,
.doc-card.district-accent-extern,
.doc-card.district-accent-default {
  --district-color: var(--district-color, var(--district-default));
  border-left: 4px solid var(--district-color);
  background: color-mix(in srgb, var(--district-color) 10%, var(--card, #ffffff));
}
.doc-card-meta {
  margin-top: 0.85rem;
  font-size: 0.9rem;
  color: var(--text, #1a1a1a);
}
.doc-card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.6rem;
  width: 100%;
  padding: 0;
  margin: 0;
  background: transparent;
  border: none;
  text-align: left;
  cursor: pointer;
  color: var(--text, #1a1a1a);
  font: inherit;
}
.doc-card-title {
  font-size: 1.05rem;
  font-weight: 700;
  flex: 1;
}
.doc-card-arrow {
  color: var(--muted);
  transition: transform 0.15s ease;
}
.doc-card-header[aria-expanded="true"] .doc-card-arrow {
  transform: rotate(180deg);
}
.doc-card-relevance {
  margin-top: 0.5rem;
  color: var(--text, #1a1a1a);
  font-size: 1rem;
  line-height: 1.55;
}
.doc-card-detail {
  margin-top: 0.8rem;
  padding-top: 0.8rem;
  border-top: 1px solid var(--border, #e2dcd6);
}
.layer-3-heading {
  font-size: 1rem;
  margin: 0 0 0.6rem 0;
  color: var(--primary-ink, var(--primary));
}
.chunks { display: flex; flex-direction: column; gap: 0.5rem; }
.chunk {
  background: var(--bg, #faf6f2);
  border-left: 3px solid var(--accent, #ffb84d);
  padding: 0.7rem 0.9rem;
  margin: 0;
  font-size: 0.95rem;
  line-height: 1.5;
  border-radius: 6px;
  white-space: pre-wrap;
  word-wrap: break-word;
}
.layer-3-actions {
  display: flex;
  gap: 0.6rem;
  margin-top: 0.9rem;
  flex-wrap: wrap;
}

/* Layer-3 card — same shape as the politician portal's result-card:
   one box per document with title, meta row (Ausschuss, date, page
   count, district), chunks, and action buttons. The Bürgerportal
   3-layer accordion keeps Layer 1 (answer) and Layer 2 (toggle +
   doc list) intact; only the per-document detail in Layer 3 uses
   this card style so users see a familiar box across both portals. */
.layer-3-card {
  background: var(--card, #ffffff);
  border: 1px solid var(--border, #e2dcd6);
  border-radius: 12px;
  padding: 0.85rem 1rem 1rem;
  box-shadow: 0 2px 6px var(--shadow-sm);
}
.layer-3-card-header {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin-bottom: 0.35rem;
}
.layer-3-card-title {
  font-size: 1rem;
  font-weight: 600;
  color: var(--text, #1a1a1a);
}
.layer-3-card-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 0.6rem;
  align-items: center;
  font-size: 0.85rem;
  color: var(--muted, #6b6b6b);
  margin-bottom: 0.6rem;
}
.layer-3-card-meta .meta-item { display: inline-flex; align-items: center; gap: 0.2rem; }
.layer-3-card-meta .meta-sep { color: var(--border, #e2dcd6); }
.layer-3-relevance {
  font-size: 0.92rem;
  line-height: 1.5;
  color: var(--text, #1a1a1a);
  margin: 0.4rem 0 0.7rem;
  padding: 0.5rem 0.7rem;
  background: color-mix(in srgb, var(--primary) 5%, transparent);
  border-radius: 8px;
}
:root.dark .layer-3-card {
  background: var(--card, #1c0e2a);
  border-color: var(--border, #381c54);
}
:root.dark .layer-3-relevance {
  background: color-mix(in srgb, var(--primary) 12%, transparent);
}

/* Status line variant colors (Phase 3 palette — overrides the earlier
   .status.error/.warning/.loading/.success colors via cascade order).
   The base .status rules live in the main status block above; mobile-first
   base + min-width: 40rem desktop restore handle size/spacing. */
.status.error { color: #c0392b; font-weight: 600; }
.status.warning { color: #b35900; font-weight: 600; }
.status.loading { color: var(--primary-ink, var(--primary)); }
.status.success { color: #2c7a4b; }
:root.dark .status.error { color: #fca5a5; }
:root.dark .status.warning { color: #fcd34d; }
:root.dark .status.success { color: #86efac; }

/* ---------------------------------------------------------------------------
   Bürgerportal landing rewrite — location row, autocomplete dropdown,
   granularity chips, radius selector, map panel toolbar, help popover,
   drag preview. All dark-mode aware via the :root.dark block below.
   --------------------------------------------------------------------------- */

.location-input-row {
  /* Single compact line on every viewport (UI.md item #1: "Shrink this
     to a compact, single-line input row"). Mobile-first row layout —
     the button + address input sit side by side as one row so the
     total height is ~44 px instead of the previous ~88 px stacked. */
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 0.5rem;
  min-width: 0;
  flex-wrap: wrap;
}
.location-toggle-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  white-space: nowrap;
  /* Compact on mobile so the button + input fit one line at 320 px
     viewport. Padding/font-size step up ≥40 rem in the tier below. */
  padding: 0.5rem 0.75rem;
  font-size: 0.85rem;
  font-weight: 600;
  min-height: var(--tap-min);
  flex-shrink: 0;
}
.location-toggle-btn .location-toggle-icon { font-size: 1.05rem; line-height: 1; }
.location-toggle-btn[aria-expanded="true"] {
  background: var(--primary);
  color: #fff;
  border: 1px solid var(--primary);
}
:root.dark .location-toggle-btn[aria-expanded="true"] {
  background: var(--primary);
  color: #fff;
}

.location-input-wrap {
  position: relative;
  /* Fill the remaining row width without forcing a large minimum that
     would push the toggle button off-screen at 320 px. */
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 0.4rem;
  border: 1px solid var(--border, #d8d4cf);
  border-radius: 8px;
  background: transparent;
  padding: 0 0.4rem 0 0.75rem;
  transition: border-color 0.15s, box-shadow 0.15s;
  min-height: var(--tap-min);
}
.location-input-wrap:focus-within {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary) 18%, transparent);
}
.location-input {
  flex: 1 1 auto;
  min-width: 0;
  border: none;
  background: transparent;
  padding: 0.4rem 0;
  font-size: 0.9rem;
  color: var(--text, #1a1a1a);
  outline: none;
  font-family: inherit;
}
.location-input::placeholder {
  /* bürgerfixes + WCAG 1.4.3: removed opacity:0.85 — see query textarea. */
  color: var(--muted, #888);
}
:root.dark .location-input-wrap {
  background: transparent;
  border-color: var(--border, #444);
}
:root.dark .location-input { color: var(--text, #f0f0f0); }

/* Autocomplete dropdown — absolutely positioned below the input. */
.autocomplete-suggestions {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  max-height: 20rem;
  overflow-y: auto;
  background: var(--card, #ffffff);
  border: 1px solid var(--border, #d3c4e3);
  border-radius: 10px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12), 0 2px 6px rgba(0, 0, 0, 0.06);
  z-index: 50;
  padding: 0.3rem 0;
}
:root.dark .autocomplete-suggestions {
  background: var(--card, #1c0e2a);
  border-color: var(--border, #381c54);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5), 0 2px 6px rgba(0, 0, 0, 0.4);
}
.autocomplete-item {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  padding: 0.55rem 0.85rem;
  cursor: pointer;
  font-size: 0.95rem;
  line-height: 1.35;
  border: none;
  background: transparent;
  text-align: left;
  width: 100%;
  color: var(--text, #1a1a1a);
  font-family: inherit;
}
.autocomplete-item:hover,
.autocomplete-item.selected,
.autocomplete-item:focus-visible {
  background: color-mix(in srgb, var(--primary) 14%, transparent);
  outline: none;
}
.autocomplete-item-primary {
  font-weight: 600;
  color: var(--text, #1a1a1a);
}
.autocomplete-item-secondary {
  font-size: 0.8rem;
  color: var(--muted, #4b5563);
}
.autocomplete-empty {
  padding: 0.6rem 0.85rem;
  font-size: 0.9rem;
  color: var(--muted, #666);
  font-style: normal;
}

/* Granularity chips — visible after a full address is resolved. */
.location-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-top: 0.55rem;
}
.location-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.5rem 0.85rem;
  font-size: 0.875rem;
  font-weight: 600;
  border-radius: 999px;
  background: color-mix(in srgb, var(--primary) 10%, transparent);
  border: 1px solid color-mix(in srgb, var(--primary) 30%, transparent);
  color: var(--primary-ink, var(--primary));
  cursor: pointer;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
  font-family: inherit;
  line-height: 1.2;
  min-height: var(--tap-min);
}
.location-chip:hover,
.location-chip:focus-visible {
  background: color-mix(in srgb, var(--primary) 22%, transparent);
  outline: none;
}
.location-chip.active {
  background: var(--primary);
  color: #fff;
  border-color: var(--primary);
}
:root.dark .location-chip {
  background: color-mix(in srgb, var(--primary) 18%, transparent);
  border-color: color-mix(in srgb, var(--primary) 38%, transparent);
  color: var(--text, #f3f4f6);
}
:root.dark .location-chip.active {
  background: var(--primary);
  color: #fff;
  border-color: var(--primary);
}

/* Long mouse-over help popover (shared by both ? triggers).
   Position is computed by `positionPopover()` in app.js (anchor to the
   trigger's bounding rect, viewport flip + shift + clamp). CSS only owns
   visuals and the z-index slot. */
.field-help-popover {
  position: fixed;
  top: 0;
  left: 0;
  width: min(21.25rem, 90vw);
  padding: 0.85rem 1rem;
  background: var(--card, #ffffff);
  border: 1px solid var(--border, #d3c4e3);
  border-radius: 10px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
  font-size: 0.9rem;
  line-height: 1.5;
  color: var(--text, #1a1a1a);
  z-index: 60;
  text-align: left;
  overflow-wrap: break-word;
}
.field-help-popover p { margin: 0.4rem 0; }
.field-help-popover p:first-child { margin-top: 0; }
.field-help-popover p:last-child { margin-bottom: 0; }
.field-help-popover ul { margin: 0.4rem 0 0.6rem 1.2rem; padding: 0; }
.field-help-popover li { margin: 0.2rem 0; }
:root.dark .field-help-popover {
  background: var(--card, #1c0e2a);
  border-color: var(--border, #381c54);
  color: var(--text, #f3f4f6);
}

/* Map panel toolbar — glassmorphic ghost buttons (ui.md §3). */
.location-panel-toolbar {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
  margin-bottom: 0.6rem;
}
/* G3: glassmorphic ghost button — translucent dark background, thin
   violet border, muted text, hover→brighter. Subset of the .icon-ctrl
   design language: same family as ?, ↩, the header reset icon. */
.map-toolbar-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.5rem 0.9rem;
  font-size: 0.85rem;
  font-weight: 500;
  color: var(--primary-ink, var(--primary));
  background: color-mix(in srgb, var(--primary) 6%, transparent);
  border: 1px solid color-mix(in srgb, var(--primary) 30%, transparent);
  border-radius: 999px;
  cursor: pointer;
  font-family: inherit;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  min-height: var(--tap-min);
}
.map-toolbar-btn:hover,
.map-toolbar-btn:focus-visible {
  background: color-mix(in srgb, var(--primary) 14%, transparent);
  border-color: color-mix(in srgb, var(--primary) 55%, transparent);
  color: var(--primary-ink, var(--primary));
  outline: none;
}
.map-toolbar-btn svg {
  display: block;
  flex-shrink: 0;
  width: 0.9375rem;
  height: 0.9375rem;
}
/* Ghost variant — used for secondary actions ("Auswahl aufheben")
   that should not fight for attention. */
.map-toolbar-btn--ghost {
  color: var(--muted, #555);
  background: transparent;
  border-color: color-mix(in srgb, var(--text, #1a1a1a) 18%, transparent);
}
.map-toolbar-btn--ghost:hover,
.map-toolbar-btn--ghost:focus-visible {
  color: var(--text, #1a1a1a);
  background: color-mix(in srgb, var(--text, #1a1a1a) 6%, transparent);
  border-color: color-mix(in srgb, var(--text, #1a1a1a) 35%, transparent);
}
:root.dark .map-toolbar-btn--ghost {
  color: var(--muted, #aaa);
  border-color: rgba(255, 255, 255, 0.18);
}
:root.dark .map-toolbar-btn--ghost:hover,
:root.dark .map-toolbar-btn--ghost:focus-visible {
  color: var(--text, #f3f4f6);
  background: rgba(255, 255, 255, 0.06);
  border-color: rgba(255, 255, 255, 0.35);
}

/* Radius selector — pill group. */
.radius-selector {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  margin-left: auto;
  flex-wrap: wrap;
  padding: 0.25rem 0.4rem;
  background: color-mix(in srgb, var(--primary) 6%, transparent);
  border: 1px solid color-mix(in srgb, var(--primary) 22%, transparent);
  border-radius: 999px;
}
.radius-label {
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--muted, #4b5563);
  padding: 0 0.3rem;
}
.radius-option {
  background: transparent;
  border: 1px solid transparent;
  padding: 0.5rem 0.85rem;
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--text, #1a1a1a);
  border-radius: 999px;
  cursor: pointer;
  font-family: inherit;
  line-height: 1.2;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
  min-height: var(--tap-min);
}
.radius-option:hover {
  background: color-mix(in srgb, var(--primary) 12%, transparent);
}
.radius-option.active {
  background: var(--primary);
  color: #fff;
  border-color: var(--primary);
}
:root.dark .radius-selector {
  background: color-mix(in srgb, var(--primary) 12%, transparent);
  border-color: color-mix(in srgb, var(--primary) 32%, transparent);
}
:root.dark .radius-option { color: var(--text, #f3f4f6); }
:root.dark .radius-option.active {
  background: var(--primary);
  color: #fff;
  border-color: var(--primary);
}

/* Drag preview — small label that follows the marker during drag,
   updated smoothly to avoid the "blink-y" feel. */
.drag-preview {
  position: absolute;
  bottom: 0.6rem;
  left: 50%;
  transform: translateX(-50%);
  padding: 0.4rem 0.85rem;
  background: color-mix(in srgb, var(--card, #fff) 92%, transparent);
  border: 1px solid var(--border, #d3c4e3);
  border-radius: 8px;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.18);
  font-size: 0.9rem;
  color: var(--text, #1a1a1a);
  z-index: 5;
  pointer-events: none;
  white-space: nowrap;
  max-width: 90%;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: opacity 0.15s;
}
:root.dark .drag-preview {
  background: color-mix(in srgb, var(--card, #1c0e2a) 95%, transparent);
  border-color: var(--border, #381c54);
  color: var(--text, #f3f4f6);
}

/* Make the map panel contain the drag-preview absolutely. */
.location-panel { position: relative; }

/* Fluid map sizing — scales with container width via aspect-ratio, bounded
   by dynamic viewport units so mobile Safari toolbar show/hide doesn't jump.
   No fixed px caps or floors. */
.buerger-map {
  width: 100%;
  aspect-ratio: var(--map-aspect);
  max-height: var(--map-max-h);
  min-height: var(--map-min-h);
  border-radius: 8px;
  overflow: hidden;
  background: var(--bg, #f6f1ea);
}

/* bürgerfixes #1/#3: shrink the map to a compact strip while a search is
   running so the VDS results below it are visible without scrolling.
   The .search-active class is toggled by freezeSearchControls() in app.js.
   rem keeps the strip readable regardless of base font size; aspect-ratio
   is overridden so the fixed min-height wins. */
.location-panel.search-active .buerger-map {
  aspect-ratio: auto;
  height: 12.5rem;
  min-height: 12.5rem;
  max-height: 12.5rem;
}

/* Tablet+: location-input-row becomes a horizontal row with the radius
   selector on the right. */
@media (min-width: 40rem) {
  .location-input-row {
    flex-direction: row;
    align-items: center;
    flex: 1 1 auto;
  }
  .location-toggle-btn { width: auto; justify-content: center; }
  .location-input-wrap { width: auto; }
  .radius-selector { width: auto; }
}

/* prefers-reduced-motion: kill the arrow rotation transition. */
@media (prefers-reduced-motion: reduce) {
  .layer-2-toggle .layer-toggle-arrow,
  .doc-card-arrow { transition: none; }
}

/* G5: custom violet map marker (ui.md §4).
   A primary violet pin with a lighter accent ring pulsing underneath.
   MapLibre's Marker anchors the element's top-left at the lat/lng; we
   offset the pin to sit on the ring's centre with translate(-50%,-100%). */
.buerger-marker {
  position: relative;
  width: 24px;
  height: 24px;
  pointer-events: auto;
  cursor: grab;
}
.buerger-marker:active { cursor: grabbing; }
.buerger-marker-pulse {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 18px;
  height: 18px;
  margin: -9px 0 0 -9px;
  background: color-mix(in srgb, var(--primary) 55%, transparent);
  border-radius: 50%;
  animation: buerger-marker-ping 1.6s cubic-bezier(0, 0, 0.2, 1) infinite;
  z-index: 0;
}
.buerger-marker-pin {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 14px;
  height: 14px;
  margin: -7px 0 0 -7px;
  background: var(--primary);
  border: 2px solid #fff;
  border-radius: 50%;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.35);
  z-index: 1;
}
:root.dark .buerger-marker-pin {
  border-color: rgba(255, 255, 255, 0.85);
}
@keyframes buerger-marker-ping {
  0%   { transform: scale(1);   opacity: 0.7; }
  75%  { transform: scale(2.4); opacity: 0;   }
  100% { transform: scale(2.4); opacity: 0;   }
}
@media (prefers-reduced-motion: reduce) {
  .buerger-marker-pulse { animation: none; }
}

.map-note {
  font-size: 0.72rem;
  color: var(--muted);
  margin: 0.4rem 0 0 0;
  line-height: 1.3;
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
  align-items: center;
}
.map-note a {
  color: var(--muted);
  text-decoration: underline;
}
.map-note a:hover {
  color: var(--primary-ink, var(--primary));
}

/* ── Debug panel (buerger_dbg_* events) ── */
.debug-panel {
  margin: 1rem 0;
  padding: 0.75rem 1rem;
  background: color-mix(in srgb, var(--card) 88%, var(--text));
  border: 1px solid var(--border);
  border-radius: 8px;
  max-height: 60dvh;
  overflow-y: auto;
  font-family: "Ubuntu Mono", "Fira Code", monospace;
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--text);
}
.debug-header {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-bottom: 0.5rem;
  padding-bottom: 0.4rem;
  border-bottom: 1px solid hsl(var(--bg-hue, 215), var(--bg-sat, 20%), 40%);
  font-size: 0.875rem;
}
.debug-toggle {
  cursor: pointer;
  font-weight: 700;
  font-size: 1rem;
  color: hsl(var(--bg-hue, 215), var(--bg-sat, 40%), 70%);
}
.debug-toggle:hover { color: var(--primary-ink, var(--primary)); }
.debug-event {
  margin: 0.25rem 0 0.6rem 0;
  padding: 0.35rem 0.6rem;
  background: hsl(var(--bg-hue, 215), var(--bg-sat, 15%), 12%);
  border-radius: 4px;
}
[data-theme="light"] .debug-event { background: #e9ecef; }
.debug-event-label {
  font-weight: 600;
  margin-bottom: 0.15rem;
  color: var(--primary-ink, var(--primary));
}
.debug-event-ts {
  font-size: 0.7rem;
  opacity: 0.6;
  margin-left: 0.5rem;
}
.debug-event pre {
  margin: 0.25rem 0 0 0;
  white-space: pre-wrap;
  word-break: break-word;
  max-height: 18.75rem;
  overflow-y: auto;
  background: hsl(var(--bg-hue, 215), var(--bg-sat, 10%), 6%);
  padding: 0.35rem 0.5rem;
  border-radius: 4px;
  font-size: 0.75rem;
}
[data-theme="light"] .debug-event pre { background: #dee2e6; }

/* ── Phase 7 — search lifecycle polish (frozen / collapsed / einfache-Sprache) ── */

/* Freeze the query + location inputs during an active search so the user
   doesn't accidentally retype mid-stream. Visual only — `disabled` is
   the real gate (runSearch sets both). */
.query-input.frozen,
.location-input.frozen {
  opacity: 0.55;
  cursor: not-allowed;
  filter: grayscale(0.4);
  transition: opacity 0.2s ease, filter 0.2s ease;
}

/* Marker fixated: drop the grab cursor + pulse so the location reads as
   pinned while the answer composes. The marker is still on the map; we
   only suppress its drag handles via marker.dragging.disable(). */
.buerger-marker.locked { cursor: default; }
.buerger-marker.locked .buerger-marker-pulse { animation: none; opacity: 0.5; }

/* Subtle spinner on the status line while .loading — the user said
   "still it should ee somthing going one!" A 3/4-turn rotating bar
   keeps the page alive without being noisy. Small + low-contrast. */
.status.loading::before {
  content: "";
  display: inline-block;
  width: 0.85em;
  height: 0.85em;
  margin-right: 0.4rem;
  vertical-align: -0.1em;
  border: 2px solid color-mix(in srgb, var(--primary) 45%, transparent);
  border-top-color: var(--primary-ink, var(--primary));
  border-radius: 50%;
  animation: buerger-status-spin 0.9s linear infinite;
}
@keyframes buerger-status-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .status.loading::before { animation: none; }
}

/* Map collapsed: when the einfache-Sprache panel is up, hide the map
   behind a thin toggle row. The marker + circle are paused (CSS only —
   we keep them in the DOM so re-expanding restores the view). */
.location-panel.map-collapsed .buerger-map {
  height: 0;
  padding: 0;
  margin: 0;
  overflow: hidden;
  border: 0;
  visibility: hidden;
}
.location-panel.map-collapsed .location-panel-toolbar {
  display: none;
}
.map-collapsed-toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  margin: 0.8rem 0;
  padding: 0.7rem 1.2rem;
  font-size: 0.95rem;
  background: var(--card, #fff);
  border: 1px solid var(--border, #d8d4cf);
  border-radius: 999px;
  color: var(--primary-ink, var(--primary));
  cursor: pointer;
  text-align: center;
  min-height: var(--tap-min);
}
.map-collapsed-toggle:hover { background: color-mix(in srgb, var(--primary) 8%, transparent); }
:root.dark .map-collapsed-toggle {
  background: var(--card, #2a2a2a);
  border-color: var(--border, #444);
}

/* Einfache-Sprache panel — K5 snippets from Stage 1.5. Less metadata
   noise than the full result cards: just bezirk + date + plain-language
   text + a "PDF lesen" button. */
.einfache-sprache-panel {
  margin: 1rem 0;
}
.einfache-sprache-panel-header {
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--primary-ink, var(--primary));
  margin-bottom: 0.6rem;
}
.einfache-sprache-card {
  margin: 0 0 0.7rem 0;
  padding: 0.8rem 1rem;
  border: 1px solid var(--border, #d8d4cf);
  border-left: 3px solid var(--primary);
  border-radius: 8px;
  background: var(--card, #fff);
  font-size: 0.95rem;
  line-height: 1.45;
}
.einfache-sprache-card-meta {
  font-size: 0.78rem;
  color: var(--muted);
  margin-bottom: 0.4rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}
.einfache-sprache-card-body { color: var(--text, #1a1a1a); }
.einfache-sprache-card .pdf-link {
  display: inline-flex;
  align-items: center;
  margin-top: 0.5rem;
  font-size: 0.875rem;
  color: var(--primary-ink, var(--primary));
  text-decoration: none;
  padding: 0.5rem 0.85rem;
  border: 1px solid var(--primary);
  border-radius: 6px;
  min-height: var(--tap-min);
}
.einfache-sprache-card .pdf-link:hover {
  background: color-mix(in srgb, var(--primary) 8%, transparent);
}
:root.dark .einfache-sprache-card {
  background: var(--card, #2a2a2a);
  border-color: var(--border, #444);
}

/* ── Phase 4 — intermediate VDS panel ─────────────────────────────────
 *
 * Rendered as soon as `buerger_vds_results` arrives (bürger.txt step
 * 7: show VDS results immediately). The panel sits above the final
 * answer; on `buerger_done` it collapses behind a `.vds-toggle` button
 * (smooth transition via max-height so the collapse isn't jarring). */
.vds-intermediate-panel {
  margin: 1rem 0;
  padding: 0.8rem 1rem;
  border: 1px solid var(--border);
  border-left: 3px solid var(--primary);
  border-radius: 8px;
  background: color-mix(in srgb, var(--primary) 4%, var(--card, #fff));
  overflow: hidden;
  transition: max-height 220ms ease;
  /* brr.md step 6 (parity with politician .llm-waiting-panel):
     no artificial max-height — the content determines the height.
     Prevents clipping the full politician cards + page-hits when
     many VDS hits are surfaced. */
  max-height: none;
}
.vds-intermediate-panel.vds-collapsed {
  max-height: 0;
  padding-top: 0;
  padding-bottom: 0;
  margin-top: 0;
  margin-bottom: 0;
  border-width: 0;
  opacity: 0;
}
.vds-panel-header {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--primary-ink, var(--primary));
  margin-bottom: 0.5rem;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}
.vds-result-list {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}
.vds-result-card {
  padding: 0.6rem 0.8rem;
  border: 1px solid var(--border, #d8d4cf);
  border-left: 3px solid var(--primary);
  border-radius: 6px;
  background: var(--card, #fff);
  font-size: 0.9rem;
  line-height: 1.4;
}
.vds-result-card-meta {
  font-size: 0.75rem;
  color: var(--muted);
  margin-bottom: 0.25rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}
.vds-result-card-title {
  font-weight: 600;
  margin-bottom: 0.25rem;
}
.vds-result-card-body {
  color: var(--text, #1a1a1a);
  font-size: 0.85rem;
  margin-bottom: 0.4rem;
}
.vds-result-card .pdf-link {
  display: inline-flex;
  align-items: center;
  font-size: 0.8125rem;
  color: var(--primary-ink, var(--primary));
  text-decoration: none;
  padding: 0.4rem 0.7rem;
  border: 1px solid var(--primary);
  border-radius: 5px;
  min-height: var(--tap-min);
}
.vds-result-card .pdf-link:hover {
  background: color-mix(in srgb, var(--primary) 8%, transparent);
}
.vds-toggle {
  margin: 0 0 0.6rem 0;
  font-size: 0.85rem;
}
:root.dark .vds-intermediate-panel {
  background: color-mix(in srgb, var(--primary) 10%, var(--card, #2a2a2a));
  border-color: var(--border);
  border-left-color: var(--primary);
}
:root.dark .vds-result-card {
  background: var(--card, #2a2a2a);
  border-color: var(--border, #444);
}

/* ── Phase 5 — Result display ─────────────────────────────────────────
 *
 * Per-document "Originaltext anzeigen" toggle, bulk expand-all
 * button, download button, refresh button on cache hits. The
 * ``.btn.subtle`` class is a low-emphasis sibling of
 * ``.btn.primary`` — same shape, transparent background + bordered.
 */
.btn.subtle {
  background: transparent;
  color: var(--primary-ink, var(--primary));
  border: 1px solid var(--primary);
  padding: 0.65rem 1.1rem;
  font-size: 0.95rem;
  min-height: var(--tap-min);
}
.btn.subtle:hover:not(:disabled) {
  background: color-mix(in srgb, var(--primary) 8%, transparent);
}
.paragraph-toggle {
  align-self: flex-start;
}
.layer-3-originaltext-row {
  margin: 0.6rem 0;
}
.paragraph-display {
  margin: 0.6rem 0 1rem 0;
  padding: 0.7rem 0.9rem;
  border-left: 3px solid var(--primary);
  background: color-mix(in srgb, var(--primary) 5%, var(--card, #fff));
  border-radius: 4px;
  font-size: 0.95rem;
  line-height: 1.5;
}
.paragraph-display.hidden { display: none; }
.paragraph-display .paragraph {
  margin: 0;
  padding: 0.4rem 0;
  font-style: normal;
  border: none;
  background: transparent;
}
.paragraph-display .paragraph-sep {
  border: 0;
  border-top: 1px dashed var(--border, #d8d4cf);
  margin: 0.4rem 0;
}
:root.dark .paragraph-display {
  background: color-mix(in srgb, var(--primary) 12%, var(--card, #2a2a2a));
}
:root.dark .paragraph-display .paragraph-sep {
  border-top-color: var(--border, #444);
}

.expand-all-paragraphs,
.download-result,
.refresh-result {
  margin: 0.6rem 0;
}
.expand-all-paragraphs { display: block; }
.download-result {
  display: block;
  margin-top: 1rem;
}
.refresh-result { display: inline-block; margin-left: 0.5rem; }

/* ==========================================================
   Portal credit line — bürger sponsor line
   ("Bereitgestellt mit Unterstützung von {party}"). Solid
   party-coloured chip rendered by theme.js as a single inline
   row: prefix span + logo + linked name. Reads --party-* vars
   injected by backend/portal_theme.render_theme_css.

   The chip background is the party's pure hex (--party-color) so
   it stays clearly party-branded in both light and dark modes
   and in both default and hover/clicked states — no transparency,
   no wash fade. The auto-computed --party-on provides the
   readable text colour regardless of the party hue. On hover the
   chip steps one shade deeper via --party-color-hover; text and
   underline stay readable (no contrast loss).
   ========================================================== */

.portal-credit {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: fit-content;
  max-width: 100%;
  min-width: 0;
  flex-wrap: wrap;
  row-gap: 0.15rem;
  padding: 0.4rem 1rem;
  margin: 0.75rem auto 0;
  border-radius: 9999px;
  /* Solid party colour — visible in light AND dark mode. Fallback
     chain keeps pages without an injection (dev tools, error
     pages) sane. */
  background: var(--party-color, var(--primary));
  border: 1px solid rgba(0, 0, 0, 0.25);
  border: 1px solid color-mix(in srgb, var(--party-color, var(--primary)) 75%, #000 25%);
  color: var(--party-on, #ffffff);
  text-align: left;
  transition: background 0.2s ease, border-color 0.2s ease;
}
.portal-credit[hidden] {
  display: none;
}
/* Hover / focus — stay in party colour, just one shade deeper. No
   transparency, no wash fade; the chip never loses its identity. */
.portal-credit:hover,
.portal-credit:focus-within {
  background: var(--party-color-hover, var(--primary-hover));
  border-color: color-mix(in srgb, var(--party-color-hover, var(--primary-hover)) 60%, #000);
}
.portal-credit .badge-label {
  font-size: 0.85rem;
  color: inherit;
  opacity: 0.88;
  letter-spacing: 0.01em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
  flex-shrink: 1;
}
/* Compact chip padding on very narrow viewports (~352 px and below)
   so the prefix + name row fit without wrapping. */
@media (max-width: 22rem) {
  .portal-credit {
    padding: 0.3rem 0.6rem;
    font-size: 0.78rem;
  }
  .portal-credit .badge-label {
    font-size: 0.78rem;
  }
}
.portal-credit .badge-name-row {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.85rem;
  color: inherit;
  font-weight: 500;
}
.portal-credit a.badge-name {
  color: inherit;
  text-decoration: underline;
  text-decoration-color: color-mix(in srgb, currentColor 35%, transparent);
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
}
.portal-credit a.badge-name:link,
.portal-credit a.badge-name:visited {
  color: inherit;
}
.portal-credit a.badge-name:hover,
.portal-credit a.badge-name:focus {
  /* Text colour stays the same (still inherits --party-on) so
     contrast is preserved on the deeper hover bg. Only the
     underline solidifies for clear feedback. */
  color: inherit;
  text-decoration-color: currentColor;
}
.portal-credit a.badge-name:focus-visible {
  outline-color: var(--party-on, #ffffff);
}
.portal-credit .badge-name {
  color: inherit;
}
/* Logo plate — the 16 px party logo carries the party fill, which
   would disappear into a party-coloured chip. A small contrasting
   circle (using --party-on) gives the logo a clear home inside
   the chip. */
.portal-credit .badge-logo {
  width: calc(1rem + 4px);
  height: calc(1rem + 4px);
  flex-shrink: 0;
  border-radius: 50%;
  vertical-align: middle;
  background: color-mix(in srgb, var(--party-on, #ffffff) 22%, transparent);
  padding: 2px;
  box-sizing: border-box;
}

/* Login-page placement — sits centred below the login box. The
   .login-page column layout (see Login Page Styling above) stacks
   the box and the credit line. */
.login-page .portal-credit {
  margin: 0;
}
