/*
 * Template Kreisverband Nordhausen — Stufe 1
 * Gestaltungsrichtung: editorial, warm, ruhig. Serife für Überschriften,
 * serifenlose Systemschrift für Text und Bedienelemente.
 *
 * Alle Farb-, Abstands- und Formwerte kommen aus assets/css/tokens.css.
 * In dieser Datei steht kein direkt notierter Farbwert außer Deckkraft-Overlays.
 */

@import url("tokens.css");

/* ============================================================
   1. Grundlagen
   ============================================================ */

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

html {
  scroll-behavior: smooth;
  /* Verhindert, dass der klebende Kopfbereich Sprungziele verdeckt */
  scroll-padding-top: 6rem;
}

body {
  margin: 0;
  font-family: var(--kvnk-schrift-text);
  font-size: var(--kvnk-font-size-base);
  line-height: var(--kvnk-line-height-relaxed);
  color: var(--kvnk-text);
  background: var(--kvnk-bg);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

/* Feine Körnung — nimmt großen Farbflächen das Digitale. Rein dekorativ. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  opacity: 0.035;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)'/%3E%3C/svg%3E");
}

img,
svg {
  max-width: 100%;
  display: block;
}

/* Muss nach den Grundregeln stehen: jede Angabe von `display` in einer
   Komponentenregel überschreibt sonst das `hidden`-Attribut, und per
   JavaScript ausgeblendete Elemente bleiben sichtbar. */
[hidden] {
  display: none !important;
}

h1, h2, h3 {
  font-family: var(--kvnk-schrift-display);
  font-weight: var(--kvnk-font-weight-regular);
  letter-spacing: var(--kvnk-tracking-tight);
  line-height: var(--kvnk-line-height-tight);
  color: var(--kvnk-marke);
  text-wrap: balance;
  margin: 0;
}

p {
  margin: 0;
  text-wrap: pretty;
}

a {
  color: var(--kvnk-link);
}
a:hover {
  color: var(--kvnk-link-hover);
}

:focus-visible {
  outline: 3px solid var(--kvnk-fokus);
  outline-offset: 3px;
  border-radius: var(--kvnk-radius-sm);
}

::selection {
  background: var(--kvnk-color-primary-200);
  color: var(--kvnk-color-primary-900);
}

/* ============================================================
   2. Hilfsklassen
   ============================================================ */

.container {
  width: 100%;
  max-width: var(--kvnk-container-max);
  margin-inline: auto;
  padding-inline: var(--kvnk-space-6);
}

.nur-fuer-screenreader {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.sprunglink {
  position: absolute;
  left: -999px;
  top: 0;
  z-index: var(--kvnk-z-overlay);
  background: var(--kvnk-surface-dunkel);
  color: var(--kvnk-auf-dunkel-text);
  padding: var(--kvnk-space-3) var(--kvnk-space-6);
  border-radius: 0 0 var(--kvnk-radius-md) 0;
  text-decoration: none;
  font-weight: var(--kvnk-font-weight-medium);
}
.sprunglink:focus {
  left: 0;
  color: var(--kvnk-auf-dunkel-text);
}

/* Einblenden beim Scrollen — Grundzustand nur setzen, wenn JS aktiv ist,
   damit die Seite ohne JavaScript vollständig sichtbar bleibt (N-12). */
.js [data-reveal] {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity var(--kvnk-zeit-langsam) var(--kvnk-kurve-aus),
              transform var(--kvnk-zeit-langsam) var(--kvnk-kurve-aus);
  transition-delay: var(--reveal-verzoegerung, 0ms);
}
.js [data-reveal].ist-sichtbar {
  opacity: 1;
  transform: none;
}

/* ============================================================
   3. Kopfbereich und Navigation
   ============================================================ */

.kopfbereich {
  position: sticky;
  top: 0;
  z-index: var(--kvnk-z-kopf);
  background: color-mix(in srgb, var(--kvnk-bg) 88%, transparent);
  backdrop-filter: blur(12px) saturate(1.4);
  border-bottom: 1px solid transparent;
  transition: border-color var(--kvnk-zeit-mittel) var(--kvnk-kurve),
              box-shadow var(--kvnk-zeit-mittel) var(--kvnk-kurve);
}
.kopfbereich.ist-gescrollt {
  border-bottom-color: var(--kvnk-border);
  box-shadow: var(--kvnk-shadow-sm);
}
.kopfbereich .container {
  display: flex;
  align-items: center;
  gap: var(--kvnk-space-6);
  padding-block: var(--kvnk-space-4);
}

.marke {
  display: flex;
  align-items: center;
  gap: var(--kvnk-space-3);
  text-decoration: none;
  color: var(--kvnk-marke);
  margin-right: auto;
  flex-shrink: 0;
}
.marke__zeichen {
  position: relative;
  width: 3.25rem;
  height: 3.25rem;
  flex-shrink: 0;
  display: grid;
  place-items: center;
  border-radius: var(--kvnk-radius-md);
  /* Abgerundetes Viereck als Bühne — bewusst eine andere Form als der Kreis
     der Bildmarke, damit Träger und Motiv nicht als zwei konkurrierende
     Kreise gelesen werden. Ring, Pflanze und Topf stecken vollständig in der
     Bilddatei; sie wurde aus `img/logo.png` der Altseite rekonstruiert, deren
     unterer Rand den Kreis abschnitt (siehe E8-06). Hier deshalb bewusst kein
     zweiter, per CSS gezeichneter Ring: Der säße auf dem Mittelpunkt des
     Elements, während der Ring der Grafik seinen eigenen hat, und beide
     ergäben sichtbar zwei versetzte Kreise.
     Auf dunklem Grund ist `--kvnk-marke-flaeche` transparent — die weiße
     Marke steht dort frei, ohne Träger. */
  background: var(--kvnk-marke-flaeche);
  transition: transform var(--kvnk-zeit-mittel) var(--kvnk-kurve-aus);
}
.marke__zeichen img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.marke:hover .marke__zeichen {
  transform: rotate(-6deg) scale(1.06);
}
.marke__name {
  display: block;
  font-family: var(--kvnk-schrift-display);
  font-size: var(--kvnk-font-size-lg);
  line-height: 1.1;
  letter-spacing: var(--kvnk-tracking-tight);
}
.marke__zusatz {
  display: block;
  font-size: var(--kvnk-font-size-xs);
  color: var(--kvnk-text-muted);
  line-height: 1.2;
  margin-top: 2px;
}

.hauptnav ul {
  list-style: none;
  display: flex;
  align-items: center;
  gap: var(--kvnk-space-6);
  margin: 0;
  padding: 0;
}
.hauptnav a {
  position: relative;
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  text-decoration: none;
  color: var(--kvnk-text);
  font-size: var(--kvnk-font-size-sm);
  font-weight: var(--kvnk-font-weight-medium);
  transition: color var(--kvnk-zeit-schnell) var(--kvnk-kurve);
}
.hauptnav a::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 6px;
  height: 2px;
  border-radius: 2px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: right;
  transition: transform var(--kvnk-zeit-mittel) var(--kvnk-kurve-aus);
}
.hauptnav a:hover {
  color: var(--kvnk-link-hover);
}
.hauptnav a:hover::after {
  transform: scaleX(1);
  transform-origin: left;
}
.hauptnav a[aria-current="page"] {
  color: var(--kvnk-link);
}
.hauptnav a[aria-current="page"]::after {
  transform: scaleX(1);
}

/* Runde Bedienknöpfe im Kopfbereich */
.kopf-knopf {
  width: 44px;
  height: 44px;
  flex-shrink: 0;
  display: grid;
  place-items: center;
  border: 1px solid var(--kvnk-border);
  border-radius: var(--kvnk-radius-full);
  background: var(--kvnk-surface);
  color: var(--kvnk-text);
  cursor: pointer;
  transition: border-color var(--kvnk-zeit-schnell) var(--kvnk-kurve),
              background var(--kvnk-zeit-schnell) var(--kvnk-kurve);
}
.kopf-knopf:hover {
  border-color: var(--kvnk-formularrahmen);
  background: var(--kvnk-surface-2);
}
.kopf-knopf svg {
  width: 20px;
  height: 20px;
  stroke: currentColor;
  fill: none;
  stroke-width: 1.75;
  stroke-linecap: round;
  stroke-linejoin: round;
}
/* Sonne/Mond wechseln je nach aktivem Modus */
.themenwechsel .symbol-mond { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .themenwechsel .symbol-sonne { display: none; }
  :root:not([data-theme="light"]) .themenwechsel .symbol-mond { display: block; }
}
:root[data-theme="dark"] .themenwechsel .symbol-sonne { display: none; }
:root[data-theme="dark"] .themenwechsel .symbol-mond { display: block; }
:root[data-theme="light"] .themenwechsel .symbol-sonne { display: block; }
:root[data-theme="light"] .themenwechsel .symbol-mond { display: none; }

.menue-knopf {
  display: none;
}
.menue-knopf .balken {
  transition: transform var(--kvnk-zeit-mittel) var(--kvnk-kurve-aus),
              opacity var(--kvnk-zeit-schnell) var(--kvnk-kurve);
  transform-origin: center;
}
.menue-knopf[aria-expanded="true"] .balken-1 { transform: translateY(6px) rotate(45deg); }
.menue-knopf[aria-expanded="true"] .balken-2 { opacity: 0; }
.menue-knopf[aria-expanded="true"] .balken-3 { transform: translateY(-6px) rotate(-45deg); }

.nav-hintergrund {
  display: none;
}

/* ============================================================
   4. Hero
   ============================================================ */

.hero {
  position: relative;
  overflow: hidden;
  background: var(--kvnk-bg-gedaempft);
}
/* Weiche Farbwolke hinter dem Bild */
.hero::before {
  content: "";
  position: absolute;
  top: -30%;
  right: -10%;
  width: 60rem;
  height: 60rem;
  border-radius: 50%;
  background: radial-gradient(circle, var(--kvnk-color-primary-100), transparent 62%);
  opacity: 0.75;
  pointer-events: none;
}
.hero .container {
  position: relative;
  z-index: 2;
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
  gap: var(--kvnk-space-16);
  align-items: center;
  padding-block: var(--kvnk-abschnitt);
}

.hero h1 {
  font-size: var(--kvnk-font-size-display);
  line-height: var(--kvnk-line-height-display);
  letter-spacing: var(--kvnk-tracking-display);
  margin-bottom: var(--kvnk-space-6);
}
/* Zweite Zeile der Schlagzeile hebt sich ab */
.hero h1 em {
  font-style: italic;
  color: var(--kvnk-link);
}
.hero__lead {
  font-size: var(--kvnk-font-size-lg);
  color: var(--kvnk-text-muted);
  max-width: var(--kvnk-mass-eng);
  margin-bottom: var(--kvnk-space-8);
}
.hero__aktionen {
  display: flex;
  flex-wrap: wrap;
  gap: var(--kvnk-space-4);
  margin-bottom: var(--kvnk-space-8);
}
.hero__hinweis {
  display: flex;
  align-items: center;
  gap: var(--kvnk-space-3);
  font-size: var(--kvnk-font-size-sm);
  color: var(--kvnk-text-muted);
}
.hero__hinweis svg {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  stroke: var(--kvnk-akzent);
  fill: none;
  stroke-width: 1.75;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.hero__medien {
  position: relative;
}
.hero__bild {
  border-radius: var(--kvnk-radius-xl);
  overflow: hidden;
  box-shadow: var(--kvnk-shadow-lg);
  aspect-ratio: 4 / 5;
}
.hero__bild img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* Überlappende Karte — bricht das Raster bewusst auf */
.hero__karte {
  position: absolute;
  left: calc(-1 * var(--kvnk-space-8));
  bottom: var(--kvnk-space-12);
  display: flex;
  align-items: center;
  gap: var(--kvnk-space-4);
  padding: var(--kvnk-space-4) var(--kvnk-space-6);
  background: var(--kvnk-surface);
  border: 1px solid var(--kvnk-border);
  border-radius: var(--kvnk-radius-lg);
  box-shadow: var(--kvnk-shadow-md);
  max-width: 17rem;
}
.hero__karte-zahl {
  font-family: var(--kvnk-schrift-display);
  font-size: var(--kvnk-font-size-2xl);
  line-height: 1;
  color: var(--kvnk-link);
}
.hero__karte-text {
  font-size: var(--kvnk-font-size-xs);
  color: var(--kvnk-text-muted);
  line-height: var(--kvnk-line-height-normal);
}

/* ============================================================
   5. Schaltflächen und Verweise
   ============================================================ */

.schaltflaeche {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--kvnk-space-3);
  min-height: 54px;
  padding: var(--kvnk-space-3) var(--kvnk-space-8);
  border: 1px solid transparent;
  border-radius: var(--kvnk-radius-full);
  font-family: var(--kvnk-schrift-text);
  font-size: var(--kvnk-font-size-sm);
  font-weight: var(--kvnk-font-weight-medium);
  text-decoration: none;
  cursor: pointer;
  transition: background var(--kvnk-zeit-schnell) var(--kvnk-kurve),
              border-color var(--kvnk-zeit-schnell) var(--kvnk-kurve),
              transform var(--kvnk-zeit-schnell) var(--kvnk-kurve),
              box-shadow var(--kvnk-zeit-mittel) var(--kvnk-kurve);
}
.schaltflaeche svg {
  width: 18px;
  height: 18px;
  stroke: currentColor;
  fill: none;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: transform var(--kvnk-zeit-mittel) var(--kvnk-kurve-aus);
}
.schaltflaeche:hover svg {
  transform: translateX(4px);
}
.schaltflaeche:active {
  transform: translateY(1px);
}

.schaltflaeche--primaer {
  background: var(--kvnk-knopf-bg);
  color: var(--kvnk-knopf-text);
  box-shadow: var(--kvnk-shadow-sm);
}
.schaltflaeche--primaer:hover {
  background: var(--kvnk-knopf-bg-hover);
  color: var(--kvnk-knopf-text);
  box-shadow: var(--kvnk-shadow-md);
}
.schaltflaeche--sekundaer {
  background: var(--kvnk-surface);
  color: var(--kvnk-marke);
  border-color: var(--kvnk-border-stark);
}
.schaltflaeche--sekundaer:hover {
  background: var(--kvnk-surface);
  color: var(--kvnk-marke);
  border-color: var(--kvnk-link);
}

.pfeil-link {
  display: inline-flex;
  align-items: center;
  gap: var(--kvnk-space-2);
  min-height: 44px;
  font-size: var(--kvnk-font-size-sm);
  font-weight: var(--kvnk-font-weight-medium);
  text-decoration: none;
}
.pfeil-link::after {
  content: "→";
  transition: transform var(--kvnk-zeit-mittel) var(--kvnk-kurve-aus);
}
.pfeil-link:hover {
  text-decoration: underline;
  text-underline-offset: 4px;
}
.pfeil-link:hover::after {
  transform: translateX(4px);
}

.pfeil-link--betont {
  padding: var(--kvnk-space-3) var(--kvnk-space-5);
  border: 1px solid var(--kvnk-border-stark);
  border-radius: var(--kvnk-radius-full);
  background: var(--kvnk-surface);
  color: var(--kvnk-marke);
  box-shadow: var(--kvnk-shadow-sm);
}
.pfeil-link--betont:hover {
  background: var(--kvnk-bg-gedaempft);
  text-decoration: underline;
}
.pfeil-link--betont::after {
  font-size: 1.1em;
}

/* ============================================================
   6. Abschnitte
   ============================================================ */

.abschnitt {
  position: relative;
  z-index: 2;
  padding-block: var(--kvnk-abschnitt);
}
.abschnitt--gedaempft {
  background: var(--kvnk-bg-gedaempft);
  border-block: 1px solid var(--kvnk-border);
}

.vorlauf {
  display: inline-flex;
  align-items: center;
  gap: var(--kvnk-space-2);
  font-family: var(--kvnk-schrift-text);
  font-size: var(--kvnk-font-size-xs);
  font-weight: var(--kvnk-font-weight-medium);
  letter-spacing: var(--kvnk-tracking-weit);
  text-transform: uppercase;
  color: var(--kvnk-akzent);
  margin-bottom: var(--kvnk-space-4);
}
.vorlauf::before {
  content: "";
  width: 1.75rem;
  height: 1px;
  background: currentColor;
}

.abschnitt__kopf {
  display: flex;
  align-items: end;
  justify-content: space-between;
  gap: var(--kvnk-space-8);
  flex-wrap: wrap;
  margin-bottom: var(--kvnk-space-12);
}
.abschnitt__kopf-text {
  max-width: var(--kvnk-mass-eng);
}
.abschnitt h2 {
  font-size: var(--kvnk-font-size-3xl);
}
.abschnitt__kopf p {
  color: var(--kvnk-text-muted);
  margin-top: var(--kvnk-space-4);
}

/* ============================================================
   7. Statistikband
   ============================================================ */

/* Gartenband: heller Abschnitt, oben von einer Hecke begrenzt, unten von
   Rasen mit Kleingarten-Motiven. Führt die Bildsprache des Hero-Bildes fort. */
.statistik {
  position: relative;
  z-index: 2;
  overflow: hidden;
  background: linear-gradient(
    180deg,
    var(--kvnk-gartenband-oben) 0%,
    var(--kvnk-gartenband-unten) 62%
  );
  /* Unten bewusst ohne Trennlinie — dort endet der Rasen, eine zusätzliche
     Linie darunter würde die Illustration abschneiden. */
  border-top: 1px solid var(--kvnk-border);
}
.statistik .container {
  position: relative;
  z-index: 2;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
  gap: var(--kvnk-space-12);
  align-items: center;
  /* Unten Platz für Hecke, Rasen und Figuren. Der Abstand ist knapp gewählt:
     Der Text soll die Bepflanzung fast berühren, damit beides zusammengehört. */
  padding-block: var(--kvnk-abschnitt) 14rem;
}

.statistik h2 {
  font-size: var(--kvnk-font-size-2xl);
  margin-bottom: var(--kvnk-space-6);
}

/* Zahlen unter einer gemeinsamen Linie — liest sich als ein Block,
   nicht als drei lose nebeneinandergestellte Werte. */
.statistik__werte {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--kvnk-space-6);
  list-style: none;
  margin: 0;
  padding: 0;
}
.statistik__werte > li {
  padding-top: var(--kvnk-space-4);
  border-top: 2px solid var(--kvnk-color-primary-200);
}
.statistik__zahl {
  display: block;
  font-family: var(--kvnk-schrift-display);
  font-size: clamp(2.25rem, 1.4rem + 2.4vw, 3.25rem);
  line-height: 1;
  color: var(--kvnk-marke);
  font-variant-numeric: tabular-nums;
}
.statistik__label {
  display: block;
  margin-top: var(--kvnk-space-3);
  font-size: var(--kvnk-font-size-sm);
  line-height: var(--kvnk-line-height-normal);
  color: var(--kvnk-text-muted);
  text-wrap: balance;
}

/* ---------- Illustration: Hecke, Rasen, Motive ---------- */

/* Aufbau von hinten nach vorn: Hecke → Figuren → Rasen.
   Die Grashalme überlappen dadurch die Füße der Figuren. */
.gartenschmuck {
  position: absolute;
  left: 0;
  right: 0;
  pointer-events: none;
  user-select: none;
}
.gartenschmuck--hecke {
  bottom: 2.75rem;
  height: 9rem;
  z-index: 1;
}
.gartenschmuck--rasen {
  bottom: 0;
  height: 6rem;
  z-index: 3;
}
/* Illustration im Dunkelmodus zurücknehmen — sonst leuchtet sie heraus.
   Rein dekorativ, daher unkritisch für den Kontrastnachweis. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .gartenschmuck {
    filter: brightness(0.68) saturate(0.85);
  }
}
:root[data-theme="dark"] .gartenschmuck {
  filter: brightness(0.68) saturate(0.85);
}

/* Kleingarten-Motive stehen auf der Rasenkante. Größen und Standhöhen sind
   bewusst leicht unterschiedlich — eine exakte Reihe wirkt mechanisch. */
.gartenfigur {
  position: absolute;
  z-index: 2;
  height: auto;
  pointer-events: none;
}
/* Weiter vorn stehende Motive sind größer und stehen tiefer — das erzeugt
   Tiefe, statt alles auf eine Linie zu stellen. */
.gartenfigur--zwerg { left: 6%; width: 5.25rem; bottom: 1.5rem; }
.gartenfigur--giesskanne { left: 22%; width: 5rem; bottom: 2.6rem; }
.gartenfigur--zaun { left: 37%; width: 15rem; bottom: 2.9rem; }
.gartenfigur--vogelhaus { right: 21%; width: 4.75rem; bottom: 2.7rem; }
.gartenfigur--sonnenblume { right: 6%; width: 6.25rem; bottom: 1.7rem; }

/* Füllfarben der Illustration. Eigene Klassen, weil CSS-Variablen in
   SVG-Präsentationsattributen (fill="var(...)") nicht zuverlässig greifen. */
.dk-laub-hell { fill: var(--kvnk-laub-hell); }
.dk-laub-mittel { fill: var(--kvnk-laub-mittel); }
.dk-laub-dunkel { fill: var(--kvnk-laub-dunkel); }
.dk-gras { fill: var(--kvnk-gras); }
.dk-bluete { fill: var(--kvnk-bluete); }
.dk-bluete-2 { fill: var(--kvnk-bluete-2); }
.dk-blume { fill: var(--kvnk-blume); }
.dk-rot { fill: var(--kvnk-deko-rot); }
.dk-blau { fill: var(--kvnk-deko-blau); }
.dk-holz { fill: var(--kvnk-deko-holz); }
.dk-holz-dunkel { fill: var(--kvnk-deko-holz-dunkel); }
.dk-metall { fill: var(--kvnk-deko-metall); }
.dk-metall-hell { fill: var(--kvnk-deko-metall-hell); }
.dk-haut { fill: var(--kvnk-deko-haut); }
.dk-weiss { fill: var(--kvnk-deko-weiss); }
.dk-schnee { fill: var(--kvnk-schnee); }
.dk-schnee-schatten { fill: var(--kvnk-schnee-schatten); }
.dk-strich-gras { stroke: var(--kvnk-gras); fill: none; }
.dk-rot-dunkel { fill: var(--kvnk-deko-rot-dunkel); }
.dk-nase { fill: var(--kvnk-deko-nase); }
.dk-auge { fill: var(--kvnk-deko-auge); }
/* Buschige Augenbrauen — als Strich gezeichnet, deshalb `stroke` statt `fill`. */
.dk-strich-weiss { stroke: var(--kvnk-deko-weiss); fill: none; }

/* Schneeelemente liegen im Markup immer vor, werden aber nur im Winter
   gezeigt. So bleibt eine einzige Illustration für alle vier Jahreszeiten. */
.nur-winter {
  display: none;
}
:root[data-jahreszeit="winter"] .nur-winter {
  display: block;
}

/* Schnee auf den Figuren braucht eine Kante: er liegt vor dem Heckenschnee
   und wäre sonst weiß auf weiß — die Dachhaube des Vogelhauses verschwand
   dadurch vollständig. `paint-order` zeichnet die Kontur vor der Füllung,
   sie liegt also außen. */
.gartenfigur .dk-schnee {
  stroke: var(--kvnk-schnee-schatten);
  stroke-width: 1.5;
  paint-order: stroke fill;
}
.dk-strich-metall { stroke: var(--kvnk-deko-metall); fill: none; }
.dk-strich-holz { stroke: var(--kvnk-deko-holz); fill: none; }

/* Bewegung innerhalb der Motive statt am ganzen Bild. */
@media (prefers-reduced-motion: no-preference) {
  .anim-vogel,
  .anim-vogel-fluegel,
  .anim-tropfen,
  .anim-bluete {
    transform-box: fill-box;
  }

  .anim-vogel {
    transform-origin: 60% 70%;
    animation: kvnk-vogel-schaukel 4.8s ease-in-out infinite;
  }

  .anim-vogel-fluegel {
    transform-origin: 100% 50%;
    animation: kvnk-vogel-flattern 1.6s ease-in-out infinite;
  }

  .anim-tropfen {
    transform-origin: 50% 0%;
    animation: kvnk-tropfen-fallen 2.8s ease-in infinite;
  }
  .anim-tropfen--2 { animation-delay: 0.35s; }
  .anim-tropfen--3 { animation-delay: 0.7s; }

  .anim-bluete {
    transform-origin: 50% 92%;
    animation: kvnk-bluete-wiegt 7.5s ease-in-out infinite;
  }
}

@keyframes kvnk-vogel-schaukel {
  0%,
  100% { transform: translateY(0) rotate(0deg); }
  45% { transform: translateY(-0.6px) rotate(1.2deg); }
  70% { transform: translateY(0.4px) rotate(-0.9deg); }
}

@keyframes kvnk-vogel-flattern {
  0%,
  100% { transform: rotate(0deg); }
  30% { transform: rotate(10deg); }
  55% { transform: rotate(-7deg); }
}

@keyframes kvnk-tropfen-fallen {
  0% { transform: translateY(0) scale(1); opacity: 0; }
  18% { opacity: 1; }
  75% { transform: translateY(7px) scale(0.95); opacity: 0.85; }
  100% { transform: translateY(9px) scale(0.9); opacity: 0; }
}

@keyframes kvnk-bluete-wiegt {
  0%,
  100% { transform: rotate(0deg); }
  50% { transform: rotate(1.4deg); }
}

/* ============================================================
   8. Kacheln
   ============================================================ */

.kachel-raster {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: var(--kvnk-space-6);
  list-style: none;
  margin: 0;
  padding: 0;
}

.kachel {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--kvnk-space-3);
  padding: var(--kvnk-space-8);
  background: var(--kvnk-surface);
  border: 1px solid var(--kvnk-border);
  border-radius: var(--kvnk-radius-lg);
  overflow: hidden;
  transition: border-color var(--kvnk-zeit-mittel) var(--kvnk-kurve),
              box-shadow var(--kvnk-zeit-mittel) var(--kvnk-kurve),
              transform var(--kvnk-zeit-mittel) var(--kvnk-kurve-aus);
}
/* Farbverlauf, der beim Überfahren von unten einwächst */
.kachel::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 3px;
  background: linear-gradient(90deg, var(--kvnk-link), var(--kvnk-akzent));
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--kvnk-zeit-mittel) var(--kvnk-kurve-aus);
}
.kachel:hover,
.kachel:focus-within {
  border-color: var(--kvnk-color-primary-200);
  box-shadow: var(--kvnk-shadow-md);
  transform: translateY(-4px);
}
.kachel:hover::after,
.kachel:focus-within::after {
  transform: scaleX(1);
}

.kachel__symbol {
  width: 3rem;
  height: 3rem;
  display: grid;
  place-items: center;
  border-radius: var(--kvnk-radius-md);
  background: var(--kvnk-color-primary-50);
  color: var(--kvnk-color-primary-700);
  margin-bottom: var(--kvnk-space-2);
}
/* Der Strichstil hängt seit E8-14 am Zeichen selbst (`.piktogramm`), nicht an
   der Hülle: Sonst wäre dasselbe Zeichen im Steckbrief eine schwarze Fläche
   gewesen, weil dort kein `.kachel__symbol` darüberliegt. Die Hülle bestimmt
   nur noch Größe und Umfeld. */
.piktogramm {
  stroke: currentColor;
  fill: none;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.kachel__symbol svg {
  width: 24px;
  height: 24px;
}
.kachel h3 {
  font-size: var(--kvnk-font-size-xl);
}
.kachel p {
  color: var(--kvnk-text-muted);
  font-size: var(--kvnk-font-size-sm);
  flex-grow: 1;
}
/* Ganze Kachel klickbar, ohne die Verweisbedeutung zu verlieren */
.kachel__link::after {
  content: "";
  position: absolute;
  inset: 0;
}

/* ============================================================
   9. Kennzeichen
   ============================================================ */

.kennzeichen {
  display: inline-flex;
  align-items: center;
  gap: var(--kvnk-space-2);
  padding: var(--kvnk-space-1) var(--kvnk-space-3);
  border-radius: var(--kvnk-radius-full);
  background: var(--kvnk-status-frei-bg);
  color: var(--kvnk-status-frei-text);
  font-size: var(--kvnk-font-size-xs);
  font-weight: var(--kvnk-font-weight-medium);
  line-height: var(--kvnk-line-height-normal);
  white-space: nowrap;
}
.kennzeichen::before {
  content: "";
  width: 0.5rem;
  height: 0.5rem;
  flex-shrink: 0;
  border-radius: 50%;
  background: currentColor;
}
.kennzeichen--neutral {
  background: var(--kvnk-surface-2);
  color: var(--kvnk-text-muted);
}

/* ============================================================
   10. Meldungen und Zeitstrahl
   ============================================================ */

.meldungsraster {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
  gap: var(--kvnk-space-6);
  list-style: none;
  margin: 0;
  padding: 0;
}
.meldung {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--kvnk-space-3);
  padding: var(--kvnk-space-8);
  background: var(--kvnk-surface);
  border: 1px solid var(--kvnk-border);
  border-radius: var(--kvnk-radius-lg);
  transition: border-color var(--kvnk-zeit-mittel) var(--kvnk-kurve),
              box-shadow var(--kvnk-zeit-mittel) var(--kvnk-kurve),
              transform var(--kvnk-zeit-mittel) var(--kvnk-kurve-aus);
}
.meldung:hover,
.meldung:focus-within {
  border-color: var(--kvnk-color-primary-200);
  box-shadow: var(--kvnk-shadow-md);
  transform: translateY(-4px);
}
.meldung__datum {
  font-size: var(--kvnk-font-size-xs);
  color: var(--kvnk-text-subtle);
  letter-spacing: var(--kvnk-tracking-weit);
  text-transform: uppercase;
}
.meldung h3 {
  font-size: var(--kvnk-font-size-xl);
}
.meldung h3 a {
  text-decoration: none;
  color: inherit;
}
.meldung h3 a::after {
  content: "";
  position: absolute;
  inset: 0;
}
.meldung:hover h3 a {
  color: var(--kvnk-link-hover);
}
.meldung p {
  color: var(--kvnk-text-muted);
  font-size: var(--kvnk-font-size-sm);
  flex-grow: 1;
}
.meldung__mehr {
  display: inline-flex;
  align-items: center;
  gap: var(--kvnk-space-2);
  font-size: var(--kvnk-font-size-sm);
  font-weight: var(--kvnk-font-weight-medium);
  color: var(--kvnk-link);
}
.meldung__mehr::after {
  content: "→";
  transition: transform var(--kvnk-zeit-mittel) var(--kvnk-kurve-aus);
}
.meldung:hover .meldung__mehr::after {
  transform: translateX(4px);
}

/* ------------------------------------------------------------
   Zeitstrahl — Meldungen und Termine auf /aktuelles (ADR-0004)

   Zwei Spalten: links Datum und Art, rechts der Inhalt. Die senkrechte
   Linie hängt am Inhalt statt an einem eigenen Element — so wächst sie
   mit jedem Eintrag mit, ohne dass eine Höhe gerechnet werden muss.

   Das Meldungsraster darüber bleibt bestehen: die Startseite zeigt ihre
   drei jüngsten Meldungen weiter als Kacheln.
   ------------------------------------------------------------ */

.zeitstrahl {
  list-style: none;
  margin: 0;
  padding: 0;
}

.zeitstrahl__eintrag {
  display: grid;
  grid-template-columns: 11rem 1fr;
  gap: var(--kvnk-space-6);
  align-items: start;
}

.zeitstrahl__wann {
  display: flex;
  flex-direction: column;
  gap: var(--kvnk-space-1);
  padding-top: var(--kvnk-space-6);
}

.zeitstrahl__datum {
  font-size: var(--kvnk-font-size-sm);
  color: var(--kvnk-text-muted);
  font-variant-numeric: tabular-nums;
}

.zeitstrahl__uhrzeit {
  display: block;
}

.zeitstrahl__art {
  font-size: var(--kvnk-font-size-xs);
  letter-spacing: var(--kvnk-tracking-weit);
  text-transform: uppercase;
  color: var(--kvnk-text-subtle);
}

.zeitstrahl__inhalt {
  position: relative;
  border-left: 1px solid var(--kvnk-border);
  padding: var(--kvnk-space-6) 0 var(--kvnk-space-6) var(--kvnk-space-6);
}

/* Der Punkt auf der Linie. Gefüllt für Termine, offen für Meldungen —
   als Zugabe zur Beschriftung „Termin"/„Meldung" in der linken Spalte,
   nicht als deren Ersatz: Form und Farbe allein dürfen die Bedeutung
   nicht tragen (WCAG 1.4.1). */
.zeitstrahl__inhalt::before {
  content: "";
  position: absolute;
  left: -5px;
  top: calc(var(--kvnk-space-6) + 0.55em);
  width: 9px;
  height: 9px;
  border-radius: var(--kvnk-radius-full);
  background: var(--kvnk-bg);
  border: 2px solid var(--kvnk-border-stark);
}

.zeitstrahl__eintrag--termin .zeitstrahl__inhalt::before {
  background: var(--kvnk-link);
  border-color: var(--kvnk-link);
}

.zeitstrahl__titel {
  font-size: var(--kvnk-font-size-xl);
}
.zeitstrahl__titel a {
  text-decoration: none;
  color: inherit;
}
.zeitstrahl__titel a:hover {
  color: var(--kvnk-link-hover);
  text-decoration: underline;
}

.zeitstrahl__text {
  margin-top: var(--kvnk-space-2);
  color: var(--kvnk-text-muted);
  font-size: var(--kvnk-font-size-sm);
}

.zeitstrahl__ort {
  display: flex;
  align-items: center;
  gap: var(--kvnk-space-2);
  margin-top: var(--kvnk-space-2);
  font-size: var(--kvnk-font-size-sm);
  color: var(--kvnk-text-muted);
}
.zeitstrahl__ort svg {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
  stroke: currentColor;
  fill: none;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Verweise eines Termins: „Weitere Infos" führt auf die Terminseite, der
   Kalender-Knopf lädt die ICS-Datei. Sie stehen nebeneinander und brechen
   erst um, wenn die Zeile zu schmal wird — untereinander gesetzt zögen sie
   jeden Termin im Strom unnötig in die Länge. */
.zeitstrahl__aktionen {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--kvnk-space-2) var(--kvnk-space-6);
  margin-top: var(--kvnk-space-3);
}

/* Knopf statt Pfeil-Verweis: Neben dem grünen „Weitere Infos" wären zwei
   gleich aussehende Verweise nebeneinander nicht zu unterscheiden — und der
   Kalender-Verweis tut etwas anderes als navigieren, er lädt eine Datei.
   Flacher als der Regelknopf, wie schon bei `.dokumentzeile__download`:
   in einer Listenzeile ist die volle Knopfhöhe zu viel Gewicht. */
.zeitstrahl__ics {
  min-height: 44px;
  padding-inline: var(--kvnk-space-6);
}
.zeitstrahl__ics svg,
.terminzeile__ics svg {
  width: 16px;
  height: 16px;
}
/* Der Regelknopf schiebt sein Symbol beim Zeigen nach rechts — gemeint war
   der Pfeil. Ein wandernder Kalender ist nur Unruhe. */
.zeitstrahl__ics:hover svg,
.terminzeile__ics:hover svg {
  transform: none;
}

/* ---- Vergangene Termine ----
   Sie stehen aufgeklappt am Seitenende und sahen dort aus wie die
   anstehenden: gefüllter Punkt, dieselbe Beschriftung „Termin". Ihr Zustand
   steht jetzt zuerst im Text („Vergangener Termin", im Makro), und die
   Gestaltung nimmt ihn auf drei Wegen auf, von denen keiner allein die
   Aussage trägt (WCAG 1.4.1): abgesetzte Beschriftung, offener Punkt,
   gestrichelte Linie.

   Ausdrücklich **nicht** über `opacity` oder eine blassere Schriftfarbe:
   genau daran ist an dieser Stelle schon einmal ein Verstoß gegen WCAG 1.4.3
   entstanden (E9-02) — Deckkraft rechnet keine Kontrastprüfung mit. Der Text
   bleibt in voller Stärke lesbar, zurück tritt nur das Beiwerk. */
.zeitstrahl__eintrag--vergangen .zeitstrahl__art {
  /* `width: fit-content` statt `align-self`: In der schmalen Ansicht steht
     die Spalte als Zeile mit `align-items: baseline`, und ein `align-self`
     würde die Marke dort aus der Grundlinie heben. */
  width: fit-content;
  padding: 0.15rem 0.5rem;
  border-radius: var(--kvnk-radius-full);
  /* Zusätzlich zur Fläche eine Kante: Im Dunkelmodus liegt `surface-2` nur
     1,25:1 über dem Seitengrund — die Fläche allein wäre dort nicht zu
     sehen. Beides ist Beiwerk, die Aussage steht im Wort. */
  border: 1px solid var(--kvnk-border);
  background: var(--kvnk-surface-2);
  color: var(--kvnk-text-muted);
  text-transform: none;
  letter-spacing: 0;
}

/* Offener Punkt — der gefüllte bleibt dem vor, was noch bevorsteht. */
.zeitstrahl__eintrag--vergangen .zeitstrahl__inhalt::before {
  background: var(--kvnk-bg);
  border-color: var(--kvnk-border-stark);
}

/* Der abgelaufene Strang ist keine fortlaufende Linie mehr. */
.zeitstrahl--vergangen .zeitstrahl__inhalt {
  border-left-style: dashed;
}

/* Übergang von Anstehendem zu Zurückliegendem. Sitzt in Spalte 2, damit
   die gestrichelte Kante genau über der Linie des Zeitstrahls ansetzt. */
.zeitstrahl__marke {
  display: grid;
  grid-template-columns: 11rem 1fr;
  gap: var(--kvnk-space-6);
}
.zeitstrahl__marke > span {
  grid-column: 2;
  border-left: 1px solid var(--kvnk-border);
  border-top: 1px dashed var(--kvnk-border-stark);
  padding: var(--kvnk-space-3) 0 var(--kvnk-space-3) var(--kvnk-space-6);
  font-size: var(--kvnk-font-size-xs);
  letter-spacing: var(--kvnk-tracking-weit);
  text-transform: uppercase;
  color: var(--kvnk-text-subtle);
}

@media (max-width: 600px) {
  .zeitstrahl__eintrag,
  .zeitstrahl__marke {
    grid-template-columns: 1fr;
    gap: 0;
  }
  /* Datum und Art nebeneinander statt untereinander — eine eigene Zeile
     je Angabe verschwendet auf schmalen Geräten zu viel Höhe. */
  .zeitstrahl__wann {
    flex-direction: row;
    align-items: baseline;
    gap: var(--kvnk-space-3);
    padding-top: var(--kvnk-space-6);
  }
  .zeitstrahl__uhrzeit {
    display: inline;
  }
  /* Ohne die zweite Spalte hätte die Linie nichts, woran sie sich
     ausrichtet — sie entfällt samt Punkten. */
  .zeitstrahl__inhalt {
    border-left: 0;
    padding: var(--kvnk-space-2) 0 var(--kvnk-space-6);
  }
  .zeitstrahl__inhalt::before {
    display: none;
  }
  .zeitstrahl__marke > span {
    grid-column: 1;
    border-left: 0;
    padding-left: 0;
  }
}

/* ============================================================
   11. Innenseiten — Kopf
   ============================================================ */

.seitenkopf {
  position: relative;
  overflow: hidden;
  background: var(--kvnk-bg-gedaempft);
  border-bottom: 1px solid var(--kvnk-border);
}
.seitenkopf::before {
  content: "";
  position: absolute;
  top: -50%;
  right: -5%;
  width: 40rem;
  height: 40rem;
  border-radius: 50%;
  background: radial-gradient(circle, var(--kvnk-color-primary-100), transparent 65%);
  opacity: 0.6;
  pointer-events: none;
}
.seitenkopf .container {
  position: relative;
  z-index: 2;
  padding-block: var(--kvnk-space-12) var(--kvnk-space-16);
}
.seitenkopf h1 {
  font-size: var(--kvnk-font-size-3xl);
  margin-bottom: var(--kvnk-space-4);
}
.seitenkopf__lead {
  color: var(--kvnk-text-muted);
  font-size: var(--kvnk-font-size-lg);
  max-width: var(--kvnk-mass-weit);
}

/* Variante mit Illustration — auf allen Seiten, im selben Bildaufbau wie das
   Hero-Bild der Startseite. Jede Seite trägt ihr eigenes Motiv aus derselben
   Illustrationsfamilie (Register: macros/components.html.twig, Begründung:
   designrichtlinie.md Abschnitt 5). */
.seitenkopf--bild .container {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 0.8fr);
  gap: var(--kvnk-space-10);
  align-items: center;
}
.seitenkopf__bild {
  border-radius: var(--kvnk-radius-xl);
  overflow: hidden;
  box-shadow: var(--kvnk-shadow-md);
  aspect-ratio: 16 / 10;
}
.seitenkopf__bild img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* Im Dunkelmodus wird die Illustration zurückgenommen — dieselbe Behandlung
   wie beim Gartenband der Startseite (Abschnitt 8). Ungedämpft leuchtet die
   helle Himmelsfläche aus der dunklen Seite heraus, und das auf jeder Seite.
   Rein dekorativ, daher unkritisch für den Kontrastnachweis. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .kopfbild-illustration,
  :root:not([data-theme="light"]) .hero__bild img {
    filter: brightness(0.82) saturate(0.9);
  }
}
:root[data-theme="dark"] .kopfbild-illustration,
:root[data-theme="dark"] .hero__bild img {
  filter: brightness(0.82) saturate(0.9);
}

.brotkrumen {
  margin-bottom: var(--kvnk-space-8);
  font-size: var(--kvnk-font-size-xs);
  color: var(--kvnk-text-subtle);
}
.brotkrumen ol {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--kvnk-space-2);
  margin: 0;
  padding: 0;
}
.brotkrumen a {
  text-decoration: none;
}
.brotkrumen a:hover {
  text-decoration: underline;
  text-underline-offset: 3px;
}
.brotkrumen li:not(:last-child)::after {
  content: "/";
  margin-left: var(--kvnk-space-2);
  color: var(--kvnk-border-stark);
}

.inhaltsbereich {
  padding-block: var(--kvnk-space-12) var(--kvnk-abschnitt);
}

/* ============================================================
   12. Filter
   ============================================================ */

/* ---- Vereinsfinder: Karte und Filter als ein Werkzeug (E5-07) ----
   Vorher waren das drei gestapelte Blöcke — Karte, dann ein grau
   hinterlegter Formularkasten, dann die Liste. Der Kasten war die
   auffälligste Anleihe beim Formularstil der frühen 2010er und trennte
   optisch, was zusammengehört. Jetzt trägt der Abschnitt die Fläche, die
   Leiste sitzt darin und bleibt beim Blättern stehen. */
/* Zwei Seiten tragen denselben Aufbau — Überschrift, Einleitung, klebende
   Filterleiste, Trefferzeile, Liste: die Vereinsübersicht (E5-07) und seit
   Stufe 2a die Gartenbörse (E11-02). Sie teilen sich die Regeln, statt sie
   zu verdoppeln; die Bausteinnamen bleiben je Abschnitt eigen, damit im
   Markup ablesbar bleibt, wo man ist. */
.vereinsfinder,
.boersenfinder {
  margin-bottom: var(--kvnk-space-12);
}
.vereinsfinder__titel,
.boersenfinder__titel {
  font-size: var(--kvnk-font-size-2xl);
  margin-bottom: var(--kvnk-space-3);
}
.vereinsfinder__lead,
.boersenfinder__lead {
  color: var(--kvnk-text-muted);
  max-width: var(--kvnk-mass-weit);
  margin-bottom: var(--kvnk-space-6);
}
.vereinsfinder__karte {
  margin-bottom: var(--kvnk-space-6);
}

/* ---- Die Börsenkarte: im Container, aber flach (2026-07-30) ----
   Zwischenzeitlich lief sie als Band über die ganze Fensterbreite. Auf Wunsch
   des Auftraggebers wieder eingerückt — sie steht jetzt im selben Textmaß wie
   der Rest der Seite und behält ihren Rahmen.

   Flach bleibt sie trotzdem, und das ist keine Geschmacksfrage: Im vollen
   16:10-Format wäre sie im Container rund 750 px hoch und schöbe die erste
   Angebotskachel um eine weitere Bildschirmhöhe nach unten. Vier dicht
   beieinanderliegende Marken brauchen Breite, nicht Höhe.

   Nach oben und unten gedeckelt: ohne Obergrenze wüchse sie auf einem hohen
   Bildschirm wieder zum Kasten, ohne Untergrenze bliebe auf einem flachen
   Fenster ein Schlitz. Das Verhältnis, auf das der Ausschnitt eingepasst wird,
   steht als `einpassen_verhaeltnis` in `gartenboerse.html.twig` — es muss grob
   zu dieser Höhe passen, sonst weitet `passung()` den Ausschnitt in die Breite
   und stößt an den Rand der Kartendaten (Begründung in anlagenkarte.html.twig). */
.boersenfinder__karte .anlagenkarte__rahmen {
  aspect-ratio: 5 / 2;
  max-height: none;
}
/* Auf schmalen Anzeigen wieder Richtung Hochformat: 5:2 wären dort 130 px
   Höhe, in denen vier Marken übereinander keinen Platz haben. */
@media (max-width: 46rem) {
  .boersenfinder__karte .anlagenkarte__rahmen {
    aspect-ratio: 4 / 3;
  }
}

.filterleiste {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  gap: var(--kvnk-space-4) var(--kvnk-space-6);
  align-items: end;
  /* Klebt unter dem Seitenkopf: Bei vierzig Kacheln liegt der Filter sonst
     nach dem ersten Bildschirm außer Reichweite. Der Wert ist die Höhe des
     Kopfbereichs — darunter, nicht darunter hindurch. */
  position: sticky;
  top: var(--kvnk-kopfhoehe);
  z-index: var(--kvnk-z-filter);
  padding: var(--kvnk-space-4) 0;
  /* Der Seitengrund muss mitlaufen, sonst scheinen die Kacheln durch. Der
     Schatten ohne Weichzeichnung weitet die Fläche über die Containerbreite
     hinaus — sonst bliebe links und rechts ein Streifen, durch den die
     Kacheln hindurchwandern. */
  background: var(--kvnk-bg);
  box-shadow: 0 0 0 var(--kvnk-space-4) var(--kvnk-bg);
  margin-bottom: var(--kvnk-space-6);
}
/* Auf schmalen Anzeigen stehen die drei Felder untereinander — die Leiste ist
   dann rund 450 px hoch und verdeckte klebend den halben Bildschirm. Dort
   läuft sie mit. */
@media (max-width: 46rem) {
  .filterleiste {
    position: static;
    box-shadow: none;
  }
}
.filterleiste__feld {
  display: flex;
  flex-direction: column;
  gap: var(--kvnk-space-2);
}
.filterleiste__feld label {
  font-size: var(--kvnk-font-size-sm);
  font-weight: var(--kvnk-font-weight-medium);
}
.filterleiste__feld input,
.filterleiste__feld select {
  font-family: var(--kvnk-schrift-text);
  font-size: var(--kvnk-font-size-sm);
  min-height: 50px;
  padding: var(--kvnk-space-2) var(--kvnk-space-4);
  border: 1px solid var(--kvnk-formularrahmen);
  border-radius: var(--kvnk-radius-md);
  background: var(--kvnk-surface);
  color: var(--kvnk-text);
  transition: border-color var(--kvnk-zeit-schnell) var(--kvnk-kurve),
              box-shadow var(--kvnk-zeit-schnell) var(--kvnk-kurve);
}
.filterleiste__feld input:hover,
.filterleiste__feld select:hover {
  border-color: var(--kvnk-link);
}
.filterleiste__feld input:focus,
.filterleiste__feld select:focus {
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--kvnk-link) 25%, transparent);
}
.filterleiste__aktionen {
  display: flex;
  align-items: center;
}
.filterleiste__zuruecksetzen {
  font-family: var(--kvnk-schrift-text);
  font-size: var(--kvnk-font-size-sm);
  font-weight: var(--kvnk-font-weight-medium);
  min-height: 50px;
  padding-inline: var(--kvnk-space-4);
  background: none;
  border: 1px solid transparent;
  border-radius: var(--kvnk-radius-md);
  color: var(--kvnk-link);
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 4px;
  transition: background var(--kvnk-zeit-schnell) var(--kvnk-kurve);
}
.filterleiste__zuruecksetzen:hover:not(:disabled) {
  background: var(--kvnk-surface);
}
/* Ungefiltert gibt es nichts zurückzusetzen. Sichtbar bleibt der Knopf, damit
   die Leiste beim ersten Filtereingriff nicht die Höhe wechselt — bedienbar
   wird er erst dann (theme.js setzt `disabled`). `--kvnk-text-subtle` statt
   Deckkraft, siehe die Begründung an `.vereinskachel__symbol`. */
.filterleiste__zuruecksetzen:disabled {
  color: var(--kvnk-text-subtle);
  cursor: default;
  text-decoration: none;
}

.ergebnis-info {
  font-size: var(--kvnk-font-size-sm);
  color: var(--kvnk-text-muted);
  margin-bottom: var(--kvnk-space-6);
}
.ergebnis-info strong {
  color: var(--kvnk-text);
  font-weight: var(--kvnk-font-weight-medium);
}

/* Was die Dokumentsuche durchsucht (E7-04). Steht zwischen Suchfeld und
   Ergebniszeile: die Erwartung muss vor dem ersten Treffer stimmen. */
.sucherklaerung {
  font-size: var(--kvnk-font-size-sm);
  color: var(--kvnk-text-muted);
  max-width: var(--kvnk-mass-weit);
  margin-top: calc(-1 * var(--kvnk-space-4));
  margin-bottom: var(--kvnk-space-4);
}
.sucherklaerung strong {
  color: var(--kvnk-text);
  font-weight: var(--kvnk-font-weight-medium);
}
.sucherklaerung--hinweis {
  padding: var(--kvnk-space-3) var(--kvnk-space-4);
  border-left: 3px solid var(--kvnk-border-stark);
  background: var(--kvnk-surface-2);
  border-radius: 0 var(--kvnk-radius-md) var(--kvnk-radius-md) 0;
}

/* Stand der Gesamtliste (A-17/E6-02) — steht über der Liste, nicht darunter:
   wer die Angebote überfliegt, soll das Alter der Daten vorher kennen. */
.listenstand {
  font-size: var(--kvnk-font-size-sm);
  color: var(--kvnk-text-muted);
  margin-bottom: var(--kvnk-space-6);
  padding: var(--kvnk-space-3) var(--kvnk-space-4);
  border-left: 3px solid var(--kvnk-border-stark);
  background: var(--kvnk-surface-2);
  border-radius: 0 var(--kvnk-radius-md) var(--kvnk-radius-md) 0;
}
.listenstand strong {
  color: var(--kvnk-text);
  font-weight: var(--kvnk-font-weight-medium);
}

/* ============================================================
   13. Vereinskacheln
   ============================================================

   Vorher trug jeder Verein einen umrandeten Kasten mit Schatten, Anhebung
   beim Zeigen und eigener Fußzeile hinter einer Trennlinie — Behälter für
   drei Angaben, von denen zwei auf allen vierzig Kacheln dieselben waren
   („Nordhausen“ 27-mal, „Angaben folgen“ 40-mal). Das Bild trägt die Kachel
   jetzt; der Text steht darunter auf dem Seitengrund, ohne Rahmen. Der
   Grundriss der eigenen Anlage macht dabei jede Kachel unverwechselbar,
   ohne dass ein einziges Foto vorliegt (partials/anlagenriss.html.twig). */

.vereinsraster {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
  gap: var(--kvnk-space-8) var(--kvnk-space-6);
  list-style: none;
  margin: 0;
  padding: 0;
}
.vereinskachel {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--kvnk-space-3);
}

/* ---- Das Bild ---- */
.vereinskachel__bild {
  position: relative;
  aspect-ratio: 16 / 10;
  overflow: hidden;
  border-radius: var(--kvnk-radius-lg);
  background: var(--kvnk-karte-grund);
  /* Der Riss endet an der Kachelkante; ohne die feine Linie schwimmt eine
     helle Kartenfläche im hellen Seitengrund. */
  box-shadow: inset 0 0 0 1px var(--kvnk-border);
  transition: box-shadow var(--kvnk-zeit-mittel) var(--kvnk-kurve);
}
.vereinskachel__bild img,
.vereinskachel__bild .anlagenriss {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--kvnk-zeit-mittel) var(--kvnk-kurve-aus);
}
/* Statt die ganze Kachel anzuheben: das Bild zieht sacht heran. Die Anhebung
   samt Schlagschatten war die auffälligste Anleihe beim Kachelstil der
   frühen 2010er — und bei vierzig Kacheln nebeneinander ein Zappeln. */
.vereinskachel:hover .vereinskachel__bild img,
.vereinskachel:hover .vereinskachel__bild .anlagenriss,
.vereinskachel:focus-within .vereinskachel__bild img,
.vereinskachel:focus-within .vereinskachel__bild .anlagenriss {
  transform: scale(1.04);
}
.vereinskachel:hover .vereinskachel__bild,
.vereinskachel:focus-within .vereinskachel__bild {
  box-shadow: inset 0 0 0 1px var(--kvnk-karte-anlage-rand);
}

/* „Gärten frei“ liegt auf dem Bild — der einzige Zustand, der ein Signal
   verdient. Die beiden anderen stehen als Text in der Metazeile. */
.vereinskachel__marke {
  position: absolute;
  top: var(--kvnk-space-3);
  left: var(--kvnk-space-3);
  z-index: 1;
}
.vereinskachel__marke .kennzeichen {
  box-shadow: var(--kvnk-shadow-sm);
}

/* ---- Der Text ---- */
.vereinskachel__titel {
  font-size: var(--kvnk-font-size-base);
  line-height: var(--kvnk-line-height-tight);
  margin: 0;
}
.vereinskachel__titel a {
  text-decoration: none;
  color: inherit;
}
/* Ein aufgespannter Verweis je Kachel — kein doppelter Tabstopp, und
   Screenreader lesen den Vereinsnamen als Linktext. */
.vereinskachel__titel a::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: var(--kvnk-radius-lg);
}
.vereinskachel:hover .vereinskachel__titel a {
  color: var(--kvnk-link-hover);
}

.vereinskachel__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--kvnk-space-1) var(--kvnk-space-2);
  margin: calc(var(--kvnk-space-1) * -1) 0 0;
  font-size: var(--kvnk-font-size-sm);
  color: var(--kvnk-text-muted);
}
/* Trennpunkt zwischen Ort und Stand — als erzeugtes Zeichen, damit er nicht
   im Text steht und mitgelesen wird. */
.vereinskachel__ort + .vereinskachel__stand::before {
  content: "·";
  margin-right: var(--kvnk-space-2);
  color: var(--kvnk-text-subtle);
}
.vereinskachel__stand--offen {
  color: var(--kvnk-text-subtle);
}
/* Der eine Zustand, der eine Handlung nach sich zieht, trägt die Textfarbe
   statt der abgeschwächten — dieselbe Stufe wie der Vereinsname. Die Marke auf
   dem Bild sagt „hier ist etwas frei", diese Zeile sagt wie viel. */
.vereinskachel__stand--frei {
  color: var(--kvnk-text);
  font-weight: var(--kvnk-font-weight-medium);
}

/* Die laufende Nummer stand hier bis E5-08 ganz rechts (`margin-left: auto`).
   Sie ist die Ordnung des Kreisverbandes, nicht die Frage, mit der jemand
   herkommt — und in einem umbrechenden Flex riss sie bei langen Ortsnamen eine
   eigene, rechtsbündige Zeile auf („Niedersachswerfen · Angaben folgen" /
   „Nr. 33"). Sie steht jetzt nur noch im Vorlauf der Vereinsseite. */

/* ---- Die Ansprechperson (E5-08) ----
   Eigene Zeile, nicht in der Metazeile: Sie ist die Antwort auf „wen frage
   ich", keine Eigenschaft der Anlage — und bei zwei Spalten auf dem Telefon
   bräche ein Name neben Ort und Stand ohnehin um. */
.vereinskachel__kontakt {
  display: flex;
  align-items: center;
  gap: var(--kvnk-space-2);
  margin: 0;
  font-size: var(--kvnk-font-size-sm);
  color: var(--kvnk-text-muted);
}
.vereinskachel__kontakt--gst {
  color: var(--kvnk-text-subtle);
  font-style: italic;
}
.vereinskachel__symbol {
  flex: 0 0 auto;
  width: 1.05em;
  height: 1.05em;
  fill: none;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  /* Zurückhaltender als der Name daneben — aber über eine Farbmarke, nicht
     über `opacity`: Deckkraft rechnet die Kontrastprüfung nicht mit, und genau
     so ist bei `.terminliste--vergangen` einmal ein 1.4.3-Verstoß entstanden
     (E9-02). Das Symbol ist `aria-hidden` und wiederholt nur, was der
     versteckte Beschriftungstext ohnehin sagt. */
  stroke: var(--kvnk-text-subtle);
}

/* ---- Schmale Anzeigen ----
   Zwei Spalten statt einer. Eine Spalte mit Bild ergäbe für vierzig Vereine
   rund 16 000 Bildpunkte Seitenlänge — mehr als die Kastenliste vorher
   brauchte, und das Bild wäre teuer bezahlt. Zu zweit nebeneinander sind die
   Risse noch gut zu erkennen und die Seite ist wieder etwa so lang wie zuvor. */
@media (max-width: 34rem) {
  .vereinsraster {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--kvnk-space-6) var(--kvnk-space-4);
  }
  .vereinskachel__titel {
    font-size: var(--kvnk-font-size-sm);
  }
  .vereinskachel__meta {
    font-size: var(--kvnk-font-size-xs);
  }
  /* Ort und Stand untereinander: nebeneinander bricht der Trennpunkt bei
     „Niedersachswerfen · Angaben folgen" an unschöner Stelle um. */
  .vereinskachel__meta {
    flex-direction: column;
    gap: 0;
  }
  .vereinskachel__ort + .vereinskachel__stand::before {
    content: none;
  }
  .vereinskachel__kontakt {
    font-size: var(--kvnk-font-size-xs);
  }
}

/* ---- Der Grundriss ----
   Schichtfarben und Strichstärken kommen aus den Regeln der großen Karte
   (`.karte-grund__*`, Abschnitt 20) — der Riss benutzt dieselben Klassen.
   Hier steht deshalb **keine** eigene `.anlagenriss .karte-grund path`-Regel:
   Sie wäre spezifischer als `.karte-grund__wald path` und setzte alle
   Schichten zurück auf `fill: none` — der Riss zeigte dann nur noch die
   nackte Fläche ohne Umgebung. */
.anlagenriss {
  background: var(--kvnk-karte-grund);
}
.anlagenriss__flaeche {
  fill: var(--kvnk-karte-anlage-stark);
  stroke: var(--kvnk-karte-anlage-rand);
  stroke-width: 1.5;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}
/* An drei Stellen führt OpenStreetMap eine Fläche für zwei Vereine. Beide
   Kacheln zeigten sonst denselben Umriss als je eigenen — gestrichelt und
   blasser sagt: „hier ungefähr“, nicht „genau das“. */
.anlagenriss__flaeche--unklar {
  fill: var(--kvnk-karte-anlage);
  stroke-dasharray: 5 4;
}
/* Straßennamen auf der Kachel — der offen gebliebene Rest von E5-07. Ohne sie
   unterscheiden sich vierzig Kartenausschnitte für einen Ortsunkundigen kaum:
   Man sieht einen Umriss zwischen Strichen und weiß nicht, wo das ist.

   Aufhellender Saum wie bei den Ortsnamen der großen Karte (`paint-order`),
   damit der Name über einer Straße lesbar bleibt. `vector-effect` hält ihn in
   Bildpunkten, sonst wüchse er mit dem Kachelmaßstab mit. Die Größe selbst
   steht als Attribut am Element — sie ist je Kachel verschieden. */
.anlagenriss__strassenname {
  fill: var(--kvnk-karte-beschriftung);
  font-family: var(--kvnk-schrift-text);
  paint-order: stroke fill;
  stroke: var(--kvnk-karte-grund);
  stroke-width: 3;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
  user-select: none;
}

/* ============================================================
   14. Gartenangebote
   ============================================================ */

/* Zwei breite Spalten statt drei schmaler (2026-07-30). Die Kachel liegt seit
   dem Kompakt-Umbau quer — Riss links, Angaben rechts —, und dafür braucht sie
   Breite statt Höhe. Bei `minmax(19rem)` standen im Container drei Spalten à
   384 px; die Eckdaten brachen dort in zwei Zeilen um. Mit 26rem sind es zwei
   Spalten à 588 px, in die Größe, Ablöse und Verfügbarkeit nebeneinander
   passen. Der Zeilenabstand darf mit, weil die Kacheln nur noch etwa ein
   Drittel so hoch sind. */
.angebotsliste {
  display: grid;
  /* `min(26rem, 100%)` statt `26rem`: Eine feste Mindestbreite größer als der
     Container lässt die Spur trotzdem 26rem breit werden — auf 375 px ergäbe
     das 416 px Kacheln und damit waagerechtes Scrollen der ganzen Seite. */
  grid-template-columns: repeat(auto-fill, minmax(min(26rem, 100%), 1fr));
  /* `--kvnk-space-5` gibt es nicht (tokens.css springt von 4 auf 6) — eine
     Deklaration mit unbekannter Variable ist ungültig und fällt **ersatzlos**
     aus, die Kacheln klebten dadurch ohne Zeilenabstand aneinander. */
  gap: var(--kvnk-space-4) var(--kvnk-space-6);
  list-style: none;
  margin: 0;
  padding: 0;
}

/* Gliederung der Börse (E11-03). Der Abstand zwischen zwei Gruppen hängt am
   **unteren** Rand des Abschnitts, nicht am oberen Rand der Überschrift: Ein
   ausgefilterter Abschnitt ist `display: none` und bringt dann auch keinen
   Abstand mit. Am oberen Rand wäre er geblieben, und die erste sichtbare
   Gruppe stünde nach jedem Filtereingriff woanders. */
.boersenfinder [data-angebots-gruppe] {
  /* War `--kvnk-space-10` — ebenfalls nicht definiert, der Abstand zwischen
     zwei Vereinsgruppen betrug dadurch 0. Fiel nicht auf, weil die
     Gruppierung nur in der Sortierung „nach Verein" mehr als einen Abschnitt
     erzeugt. */
  margin-bottom: var(--kvnk-space-12);
}
.angebotsgruppe__titel {
  font-size: var(--kvnk-font-size-xl);
  margin-bottom: var(--kvnk-space-6);
}
/* Die Zahl ist Beiwerk zur Überschrift, nicht Teil des Namens — sie tritt
   deshalb in Größe und Ton zurück, statt in der Anzeigeschrift mitzulaufen.
   Das trennende „·" steht als `aria-hidden`-Span im Markup, nicht als
   `content` einer ::before-Regel: Ob CSS-erzeugter Text im Screenreader
   ankommt, hängt vom Programm ab — und wenn er ankommt, wird er vorgelesen.
   Gleiches Vorgehen wie in der Ergebniszeile und auf der Vereinskachel. */
.angebotsgruppe__zahl {
  font-family: var(--kvnk-schrift-text);
  font-size: var(--kvnk-font-size-sm);
  color: var(--kvnk-text-muted);
  white-space: nowrap;
}
/* ---- Die Karte je Angebot: quer statt hochkant (2026-07-30) ----
   Sie trug den Riss als 16:10-Bild über die volle Kachelbreite — 239 px von
   379 px Kachelhöhe, also zwei Drittel. Das war vertretbar, solange man den
   Riss für einen Blickfang je Angebot hielt; er ist aber **je Verein
   derselbe**: siebenmal dasselbe Bild bei Braune Erde, fünfmal bei
   Beethovenring, fünfmal bei Stürzetal. Er zeigt die Anlage, nicht die
   Parzelle — bei einer Liste aus 19 Angeboten viermal dieselbe Karte
   untereinander, und die Werte, nach denen man vergleicht, standen darunter
   im Kleingedruckten.

   Jetzt liegt er als schmale Spalte links. Der Ortsbezug bleibt, die Kachel
   fällt von 379 px auf rund 150 px, und die Angaben rücken auf Augenhöhe.
   `align-items: stretch` (Vorgabe): der Riss läuft über die volle Kachelhöhe
   mit, statt oben zu kleben. */
.angebot {
  position: relative;
  display: grid;
  grid-template-columns: 9.5rem 1fr;
  background: var(--kvnk-surface);
  border: 1px solid var(--kvnk-border);
  border-radius: var(--kvnk-radius-lg);
  overflow: hidden;
  transition: border-color var(--kvnk-zeit-mittel) var(--kvnk-kurve),
              box-shadow var(--kvnk-zeit-mittel) var(--kvnk-kurve),
              transform var(--kvnk-zeit-mittel) var(--kvnk-kurve-aus);
}
/* Unter rund 30rem bleibt neben dem Riss zu wenig für drei Werte nebeneinander.
   Die Spalte schrumpft dort mit, statt die Angaben zu erdrücken. */
@media (max-width: 30rem) {
  .angebot {
    grid-template-columns: 6.5rem 1fr;
  }
}
.angebot:hover,
.angebot:focus-within {
  border-color: var(--kvnk-color-primary-200);
  box-shadow: var(--kvnk-shadow-md);
  transform: translateY(-3px);
}

.angebot__bild {
  position: relative;
  overflow: hidden;
  background: var(--kvnk-karte-grund);
  box-shadow: inset 0 0 0 1px var(--kvnk-border);
}
.angebot__bild img,
.angebot__bild .anlagenriss,
.angebot__bild-platzhalter {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--kvnk-zeit-mittel) var(--kvnk-kurve-aus);
}
/* Der generische Platzhalter (kein Foto, keine Kartengeometrie für den
   Verein) bleibt eine kleine Umrisszeichnung statt eines gestreckten Bildes —
   auf 100 % Kachelbreite gezogen sähe er wie ein Ladefehler aus. */
.angebot__bild-platzhalter {
  object-fit: contain;
  /* Kleiner als vorher (`space-8`): In einer 9,5rem-Spalte bliebe von der
     Zeichnung sonst kaum etwas übrig. */
  padding: var(--kvnk-space-4);
}
.angebot:hover .angebot__bild img,
.angebot:hover .angebot__bild .anlagenriss,
.angebot:focus-within .angebot__bild img,
.angebot:focus-within .angebot__bild .anlagenriss {
  transform: scale(1.04);
}

/* Die Parzellen-Nr. war vorher ein eigenes Feld links der Zeile — jetzt eine
   Marke über der Bildecke, dieselbe Rolle wie „Gärten frei" auf der
   Vereinskachel, nur mit Zahl statt Punkt: Sie ist der Blickfang, mit dem im
   Verein über eine Parzelle gesprochen wird. */
.angebot__nummer {
  position: absolute;
  top: var(--kvnk-space-3);
  left: var(--kvnk-space-3);
  z-index: 1;
  display: grid;
  place-items: center;
  width: 3.75rem;
  height: 3.75rem;
  border-radius: var(--kvnk-radius-md);
  background: var(--kvnk-status-frei-bg);
  color: var(--kvnk-status-frei-text);
  text-align: center;
  box-shadow: var(--kvnk-shadow-sm);
}
.angebot__nummer b {
  display: block;
  font-family: var(--kvnk-schrift-display);
  font-size: var(--kvnk-font-size-lg);
  font-weight: var(--kvnk-font-weight-regular);
  line-height: 1;
}
.angebot__nummer span {
  display: block;
  font-size: 0.7rem;
  margin-top: 2px;
}
/* `.angebot__marke` („Sofort verfügbar" über der Bildecke) ist am 2026-07-30
   entfallen — es trug 17 der 19 Kacheln und unterschied damit nichts mehr.
   Begründung in `partials/angebotskarte.html.twig`; `verfuegbar_ab` steht
   jetzt als Wert in der Eckdatenzeile. Das Kennzeichen selbst
   (`.kennzeichen`) lebt weiter auf der Detailseite. */

.angebot__inhalt {
  display: grid;
  gap: var(--kvnk-space-2);
  align-content: center;
  min-width: 0;
  /* Siehe `.angebotsliste`: `--kvnk-space-5` ist nicht definiert. Die frühere
     Fassung trug hier deshalb einen Ersatzwert (`var(--kvnk-space-5, 1.25rem)`);
     ohne ihn fiel das ganze `padding` aus und der Text klebte am Riss. */
  padding: var(--kvnk-space-4) var(--kvnk-space-6);
}
/* Kleiner als vorher (`xl`): Auf einer kompakten Kachel ist der Titel eine
   Zeile im Vergleich, keine Überschrift eines Textes. */
.angebot__titel {
  font-size: var(--kvnk-font-size-lg);
  line-height: var(--kvnk-line-height-tight);
  margin: 0;
}
.angebot__titel a {
  text-decoration: none;
  color: inherit;
}
/* Ein aufgespannter Verweis je Kachel — kein doppelter Tabstopp, und
   Screenreader lesen den Angebotstitel als Linktext. Gleiches Muster wie
   Kachel, Meldung und Vereinskachel (docs/02-design/komponenten.md). */
.angebot__titel a::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: var(--kvnk-radius-lg);
}
.angebot:hover .angebot__titel a {
  color: var(--kvnk-link-hover);
}

/* ---- Eckdaten als Piktogramm-Zeile ----
   Löst die frühere Definitionsliste aus bloßen Wortpaaren ab (Größe, Verfügbar
   ab, Ablösesumme). Kurze Werte stehen als Häppchen nebeneinander, nicht als
   zweispaltige Tabelle mit viel Leerraum dazwischen — dieselben Zeichen wie im
   Steckbrief der Vereinsseite (`k.piktogramm()`, `.steckbrief__symbol`). */
.angebot__eckdaten {
  display: flex;
  flex-wrap: wrap;
  gap: var(--kvnk-space-2) var(--kvnk-space-4);
  list-style: none;
  margin: 0;
  padding: 0;
  font-size: var(--kvnk-font-size-sm);
  color: var(--kvnk-text);
}
.angebot__eckdaten li {
  display: flex;
  align-items: center;
  gap: var(--kvnk-space-2);
}
/* Der Wert trägt die Zeile, nicht das Piktogramm daneben. Bis 2026-07-30 stand
   die ganze Zeile klein und grau unter einem 239 px hohen Bild — ausgerechnet
   Größe, Ablöse und Verfügbarkeit, also das, wonach verglichen wird. Gewicht
   und Grundton statt einer eigenen Farbe: Damit bleibt es bei den bereits
   kontrastgeprüften Token-Paaren (E3-03). */
.angebot__eckdaten b {
  font-weight: var(--kvnk-font-weight-medium);
  color: var(--kvnk-text);
}
.angebot__hinweis {
  color: var(--kvnk-text-muted);
  font-size: var(--kvnk-font-size-sm);
  margin: 0;
}
.angebot__stand {
  font-size: var(--kvnk-font-size-xs);
  color: var(--kvnk-text-subtle);
  margin: 0;
}
/* Veraltete und fehlende Standangaben (A-17/E6-02) treten aus dem Kleingedruckten
   heraus. Unterschieden wird über Größe und Gewicht, nicht über Farbe: die Aussage
   steht ohnehin im Text (WCAG 1.4.1), und beide Töne sind über die bestehenden
   Tokens bereits für hell und dunkel kontrastgeprüft (E3-03) — ein eigener
   Warnton hätte ein neues, ungeprüftes Farbpaar bedeutet. */
.angebot__stand--veraltet,
.angebot__stand--unbekannt {
  font-size: var(--kvnk-font-size-sm);
  color: var(--kvnk-text-muted);
  font-weight: var(--kvnk-font-weight-medium);
}
/* Laufzeit-Ansage (A-42). Gleiche Abstufung wie beim Stand: der Regelfall bleibt
   Kleingedrucktes, die fehlende Laufzeit tritt heraus — wieder über Größe und
   Gewicht statt über eine eigene Warnfarbe (WCAG 1.4.1, E3-03). */
.angebot__ablauf {
  font-size: var(--kvnk-font-size-xs);
  color: var(--kvnk-text-subtle);
  margin: 0;
}
.angebot__ablauf--fehlt {
  font-size: var(--kvnk-font-size-sm);
  color: var(--kvnk-text-muted);
  font-weight: var(--kvnk-font-weight-medium);
  margin: 0;
}

/* Die Knopfgruppe steht seit dem Kompakt-Umbau nur noch auf der Detailseite —
   in der Liste trägt die Kachel einen einzigen aufgespannten Verweis. */
.angebot__aktion {
  display: flex;
  flex-wrap: wrap;
  gap: var(--kvnk-space-3);
}
.angebot__aktion .schaltflaeche {
  white-space: nowrap;
}

/* ============================================================
   14b. Seite eines einzelnen Gartenangebots

   Bis 2026-07-30 zeigte sie nur die Listenkachel noch einmal. Seit die Kachel
   kompakt ist (damit eine wachsende Liste vergleichbar bleibt), trägt diese
   Seite den Rest: alle Angaben, den Kontaktweg und die Lage der Anlage.
   ============================================================ */

.angebotsseite {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--kvnk-space-8) var(--kvnk-space-12);
  align-items: start;
  margin-bottom: var(--kvnk-space-12);
}
.angebotsseite__bild {
  position: relative;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  border-radius: var(--kvnk-radius-lg);
  background: var(--kvnk-karte-grund);
  box-shadow: inset 0 0 0 1px var(--kvnk-border);
}
.angebotsseite__bild img,
.angebotsseite__bild .anlagenriss {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.angebotsseite__bild .angebot__bild-platzhalter {
  object-fit: contain;
  padding: var(--kvnk-space-12);
}
/* Bild und Unterschrift in einem `figure` — als getrennte Rasterzellen rutschte
   die Unterschrift unter die *ganze* rechte Spalte, rund 90 Bildpunkte unter
   das Bild, auf das sie sich bezieht. */
.angebotsseite__medien {
  margin: 0;
}
.angebotsseite__kein-foto {
  margin-top: var(--kvnk-space-3);
  font-size: var(--kvnk-font-size-xs);
  color: var(--kvnk-text-subtle);
  font-style: italic;
}
.angebotsseite__daten {
  display: grid;
  gap: var(--kvnk-space-6);
  align-content: start;
}
.angebotsseite__daten h2 {
  font-size: var(--kvnk-font-size-xl);
  margin: 0;
}
/* Vorlauf und Kennzeichen auf einer Zeile im Seitenkopf. */
.angebotsseite__vorlauf {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--kvnk-space-4);
  margin-bottom: var(--kvnk-space-2);
}

/* ---- Die drei Zahlen, auf die es ankommt ----
   Nebeneinander und groß gesetzt: Größe, Verfügbarkeit und Ablöse entscheiden,
   ob jemand weiterliest. Vorher standen sie gleichwertig zwischen Laube und
   Ausstattung — die Seite hatte dadurch keine Reihenfolge, in der man sie
   liest, und „Wasser- und Stromanschluss vorhanden" wog so schwer wie der
   Preis. `auto-fit` statt fester Spalten, damit zwei Werte nicht ein Drittel
   Leerraum stehen lassen, wenn ein Feld fehlt. */
.angebotszahlen {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
  gap: var(--kvnk-space-4);
  margin: 0;
  padding: var(--kvnk-space-6);
  background: var(--kvnk-surface-2);
  border-radius: var(--kvnk-radius-lg);
}
.angebotszahlen > div {
  min-width: 0;
}
.angebotszahlen dt {
  display: flex;
  align-items: center;
  gap: var(--kvnk-space-2);
  font-size: var(--kvnk-font-size-xs);
  font-weight: var(--kvnk-font-weight-medium);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--kvnk-text-subtle);
}
.angebotszahlen dd {
  margin: var(--kvnk-space-2) 0 0;
  font-size: var(--kvnk-font-size-sm);
  color: var(--kvnk-text-muted);
  /* Lange Freitextwerte („laut letzter Meldung: Januar 2025") dürfen umbrechen,
     ohne die Spalte zu sprengen. */
  overflow-wrap: anywhere;
}
/* `inline`, damit die Einheit neben der Zahl steht: Als Block brach „m²" auf
   eine eigene Zeile und die Kachel las sich als „300 / m²". */
.angebotszahlen dd b {
  font-family: var(--kvnk-schrift-display);
  font-size: var(--kvnk-font-size-xl);
  font-weight: var(--kvnk-font-weight-regular);
  line-height: var(--kvnk-line-height-tight);
  color: var(--kvnk-text);
}

/* ---- Die übrigen Angaben ----
   Zeilen mit Trennlinie statt luftiger Blöcke: Begriff links, Wert rechts.
   Das hält die Spalte zusammen und macht aus sechs gleich aussehenden
   Absätzen eine lesbare Aufstellung. */
.angebotsangaben {
  margin: 0;
  display: grid;
}
.angebotsangaben > div {
  display: grid;
  grid-template-columns: 11rem minmax(0, 1fr);
  gap: var(--kvnk-space-4);
  align-items: baseline;
  padding: var(--kvnk-space-3) 0;
  border-top: 1px solid var(--kvnk-border);
}
.angebotsangaben > div:last-child {
  border-bottom: 1px solid var(--kvnk-border);
}
.angebotsangaben dt {
  display: flex;
  align-items: center;
  gap: var(--kvnk-space-2);
  font-size: var(--kvnk-font-size-sm);
  color: var(--kvnk-text-subtle);
}
.angebotsangaben dd {
  margin: 0;
  font-size: var(--kvnk-font-size-sm);
  color: var(--kvnk-text);
}
/* Auf schmalen Spalten untereinander — bei 11 rem Begriffsspalte bliebe für
   einen ganzen Satz sonst kaum Platz. */
@media (max-width: 34rem) {
  .angebotsangaben > div {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--kvnk-space-1);
  }
}
/* Der Kontaktblock ist das Ziel der Seite und wird abgesetzt, nicht nur
   angehängt: A-19 verlangt einen direkten Kontaktweg je Angebot, und seit dem
   Kompakt-Umbau ist dies die einzige Stelle, an der er steht. */
.angebotsseite__kontakt {
  margin-top: var(--kvnk-space-2);
  padding: var(--kvnk-space-6);
  background: var(--kvnk-surface-2);
  border-radius: var(--kvnk-radius-lg);
}
.angebotsseite__kontakt h2 {
  font-size: var(--kvnk-font-size-lg);
  margin: 0 0 var(--kvnk-space-4);
}
.angebotsseite__lage {
  margin-bottom: var(--kvnk-space-12);
}
.angebotsseite__lage h2 {
  font-size: var(--kvnk-font-size-xl);
  margin-bottom: var(--kvnk-space-3);
}
.angebotsseite__lage-text {
  color: var(--kvnk-text-muted);
  max-width: var(--kvnk-mass-weit);
  margin-bottom: var(--kvnk-space-6);
}
.angebotsseite__zurueck {
  margin-top: var(--kvnk-space-8);
}

/* Einspaltig, sobald zwei Spalten die Angaben zu schmal machen. Das Bild bleibt
   oben — es ist der Einstieg, nicht Beiwerk. */
@media (max-width: 60rem) {
  .angebotsseite {
    grid-template-columns: minmax(0, 1fr);
  }
}

.leerzustand {
  padding: var(--kvnk-space-16) var(--kvnk-space-8);
  text-align: center;
  background: var(--kvnk-surface-2);
  border: 1px dashed var(--kvnk-border-stark);
  border-radius: var(--kvnk-radius-lg);
}
.leerzustand__bild {
  width: 12rem;
  max-width: 60%;
  height: auto;
  margin: 0 auto var(--kvnk-space-6);
}
/* h2, weil der Leerzustand direkt unter der h1 der Seite steht — eine h3
   an dieser Stelle wäre ein Sprung in der Gliederung (E9-02, WCAG 1.3.1).
   h3 bleibt vorerst mitversorgt, falls ein Leerzustand später in einem
   Abschnitt mit eigener Überschrift landet. */
.leerzustand h2,
.leerzustand h3 {
  font-size: var(--kvnk-font-size-xl);
  margin-bottom: var(--kvnk-space-3);
}
.leerzustand p {
  color: var(--kvnk-text-muted);
  max-width: var(--kvnk-mass-eng);
  margin-inline: auto;
  margin-bottom: var(--kvnk-space-6);
}
/* Ausblenden übernimmt die globale [hidden]-Regel am Dateianfang. */

/* ---- Abschluss des Vereinsfinders (E5-08) ----
   Nach der vierzigsten Kachel endete die Seite unmittelbar im Fußbereich. Wer
   alles durchgesehen und nichts Passendes gefunden hat, ist genau der Fall, für
   den die Geschäftsstelle da ist — der Hinweis stand aber nur im Leerzustand,
   den nur sieht, wer sich vorher leergefiltert hat.

   Deutlich ruhiger als der Leerzustand: kein Bild, keine gestrichelte Umrandung,
   nur eine Trennlinie. Er ist ein Nachsatz, keine Aufforderung — sonst
   konkurriert er mit den vierzig Kacheln über ihm. */
.finderabschluss {
  margin-top: var(--kvnk-space-12);
  padding-top: var(--kvnk-space-8);
  border-top: 1px solid var(--kvnk-border);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--kvnk-space-4) var(--kvnk-space-8);
}
.finderabschluss__text {
  flex: 1 1 22rem;
  margin: 0;
  color: var(--kvnk-text-muted);
  max-width: var(--kvnk-mass-weit);
}
.finderabschluss__text strong {
  color: var(--kvnk-text);
}
.finderabschluss__wege {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--kvnk-space-3) var(--kvnk-space-4);
  margin: 0;
  font-size: var(--kvnk-font-size-sm);
}

/* ---- Zurück zum Filter (E5-08) ----
   Nur dort, wo die Filterleiste **nicht** klebt: Auf breiten Anzeigen steht sie
   ohnehin immer oben, dort wäre der Knopf überflüssiges Bedienwerk. Die Grenze
   ist dieselbe wie bei `.filterleiste` (46rem) — laufen die beiden Werte
   auseinander, erscheint der Knopf neben einer klebenden Leiste.
   Eingeblendet wird er von theme.js (`filtersprungAufbauen`); ohne JavaScript
   bleibt das `hidden`-Attribut stehen. */
.filtersprung {
  display: none;
}
@media (max-width: 46rem) {
  .filtersprung {
    position: fixed;
    right: var(--kvnk-space-4);
    /* Über dem unteren Rand, nicht auf ihm: Auf iOS liegt dort die
       Adressleiste. */
    bottom: calc(var(--kvnk-space-6) + env(safe-area-inset-bottom, 0px));
    z-index: var(--kvnk-z-filter);
    display: flex;
    align-items: center;
    gap: var(--kvnk-space-2);
    /* 50px wie die Filterfelder selbst — Zielgröße für den Finger
       (WCAG 2.5.8). */
    min-height: 50px;
    padding: 0 var(--kvnk-space-5);
    border-radius: 999px;
    background: var(--kvnk-color-primary-700, var(--kvnk-surface-dunkel-2));
    color: var(--kvnk-auf-dunkel-text);
    font-size: var(--kvnk-font-size-sm);
    font-weight: var(--kvnk-font-weight-medium);
    text-decoration: none;
    box-shadow: var(--kvnk-shadow-md);
  }
  .filtersprung svg {
    width: 1.15em;
    height: 1.15em;
    fill: none;
    stroke: currentColor;
    stroke-width: 2;
    stroke-linecap: round;
  }
}

/* ---- Angebote eines Vereins auf seiner Seite (E5-08) ----
   Der Weg bestand vorher nur in einer Richtung: Jedes Angebot verweist über
   `verein_route` auf seinen Verein, zurück verwies nichts. */
.vereinsangebote__titel {
  font-size: var(--kvnk-font-size-lg);
  margin-top: var(--kvnk-space-8);
  margin-bottom: var(--kvnk-space-4);
}
.vereinsangebote {
  list-style: none;
  margin: 0 0 var(--kvnk-space-4);
  padding: 0;
  display: grid;
  gap: var(--kvnk-space-2);
}
.vereinsangebote li {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--kvnk-space-2) var(--kvnk-space-4);
  padding: var(--kvnk-space-3) var(--kvnk-space-4);
  background: var(--kvnk-surface-2);
  border-radius: var(--kvnk-radius-md);
}
.vereinsangebote__wert {
  font-size: var(--kvnk-font-size-sm);
  color: var(--kvnk-text-muted);
}
/* Bewusst **kein** `margin-left: auto` auf dem letzten Wert. Es hätte die
   Ablöse rechts ausgerichtet — aber bei zwei Parzellen ist keine Ablöse
   hinterlegt („Auf Anfrage", E6-01), dort spränge dann die Größe nach rechts.
   Dieselbe Falle wie die laufende Nummer auf der Vereinskachel. */
.vereinsangebote__mehr {
  font-size: var(--kvnk-font-size-sm);
  margin: 0;
}

/* ============================================================
   15. Fußbereich
   ============================================================ */

.fussbereich {
  position: relative;
  z-index: 2;
  background: var(--kvnk-surface-dunkel-2);
  color: var(--kvnk-auf-dunkel-text);
}

/* Heckenhorizont: sitzt über dem Fußbereich und ist in dessen eigener Farbe
   gefüllt. Dadurch wächst der dunkle Block organisch aus der Seite heraus,
   statt sie mit einer harten Linie zu zerschneiden. */
.fussbereich__horizont {
  position: absolute;
  bottom: 100%;
  left: 0;
  right: 0;
  height: 4.5rem;
  pointer-events: none;
  /* Verhindert eine Haarlinie zwischen Grafik und Fußbereich */
  margin-bottom: -1px;
}
.hz-hinten { fill: var(--kvnk-border-dunkel); }
.hz-vorn { fill: var(--kvnk-surface-dunkel-2); }
/* Feste Spalten statt auto-fit: Bei nur drei Linklisten erzeugt auto-fit
   je nach Breite leere Spuren und lässt den Bereich ausgefranst wirken. */
.fussbereich .container {
  display: grid;
  grid-template-columns: minmax(0, 1.7fr) repeat(3, minmax(0, 1fr));
  gap: var(--kvnk-space-12) var(--kvnk-space-8);
  padding-block: var(--kvnk-space-24) var(--kvnk-space-8);
}

.fussbereich .marke {
  color: var(--kvnk-auf-dunkel-text);
  margin-right: 0;
  margin-bottom: var(--kvnk-space-4);
}
/* Der Fußbereich ist in beiden Farbmodi dunkel, nicht nur im Dunkelmodus —
   das Token allein greift hier also nicht. Die weiße Marke steht frei. */
.fussbereich .marke__zeichen {
  background: transparent;
}
.fussbereich .marke__zusatz {
  color: var(--kvnk-auf-dunkel-muted);
}
.fussbereich__beschreibung {
  font-size: var(--kvnk-font-size-sm);
  color: var(--kvnk-auf-dunkel-muted);
  max-width: 24rem;
  margin-bottom: var(--kvnk-space-6);
}

.fussbereich h2 {
  font-family: var(--kvnk-schrift-text);
  font-size: var(--kvnk-font-size-xs);
  font-weight: var(--kvnk-font-weight-medium);
  letter-spacing: var(--kvnk-tracking-weit);
  text-transform: uppercase;
  color: var(--kvnk-auf-dunkel-akzent);
  margin-bottom: var(--kvnk-space-4);
}
.fussbereich ul {
  list-style: none;
  display: grid;
  gap: var(--kvnk-space-3);
  margin: 0;
  padding: 0;
  font-size: var(--kvnk-font-size-sm);
}
.fussbereich a {
  color: var(--kvnk-auf-dunkel-text);
  text-decoration: none;
}
.fussbereich a:hover {
  color: var(--kvnk-auf-dunkel-text);
  text-decoration: underline;
  text-underline-offset: 4px;
}

.fussbereich__kontakt {
  display: grid;
  gap: var(--kvnk-space-4);
  font-size: var(--kvnk-font-size-sm);
  color: var(--kvnk-auf-dunkel-muted);
}
.fussbereich__kontakt dt {
  font-size: var(--kvnk-font-size-xs);
  letter-spacing: var(--kvnk-tracking-weit);
  text-transform: uppercase;
  color: var(--kvnk-auf-dunkel-muted);
  margin-bottom: var(--kvnk-space-1);
}
.fussbereich__kontakt dd {
  margin: 0;
  color: var(--kvnk-auf-dunkel-text);
  line-height: var(--kvnk-line-height-relaxed);
}
.fussbereich__kontakt address {
  font-style: normal;
}

.fussbereich__abschluss {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--kvnk-space-4) var(--kvnk-space-8);
  margin-top: var(--kvnk-space-8);
  padding-top: var(--kvnk-space-6);
  border-top: 1px solid var(--kvnk-linie-auf-dunkel);
  font-size: var(--kvnk-font-size-xs);
  color: var(--kvnk-auf-dunkel-muted);
}
.fussbereich__rechtliches {
  display: flex;
  flex-wrap: wrap;
  gap: var(--kvnk-space-6);
}
.fussbereich__abschluss a {
  color: var(--kvnk-auf-dunkel-muted);
}

/* ============================================================
   16. Entwurfshinweis
   ============================================================ */

.entwurfshinweis {
  position: relative;
  z-index: 3;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--kvnk-space-2) var(--kvnk-space-6);
  background: var(--kvnk-akzent-flaeche);
  color: var(--kvnk-akzent);
  font-size: var(--kvnk-font-size-xs);
  line-height: var(--kvnk-line-height-normal);
  text-align: center;
  padding: var(--kvnk-space-3) var(--kvnk-space-6);
}
.entwurfshinweis p {
  margin: 0;
}
.entwurfshinweis a {
  color: inherit;
}
.entwurfshinweis__jahreszeiten {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--kvnk-space-2) var(--kvnk-space-3);
}
.entwurfshinweis__jahreszeiten a {
  padding: var(--kvnk-space-1) var(--kvnk-space-3);
  border: 1px solid currentColor;
  border-radius: var(--kvnk-radius-full);
  text-decoration: none;
}
.entwurfshinweis__jahreszeiten a:hover {
  color: inherit;
  text-decoration: underline;
}

/* ============================================================
   17. Umbruchpunkte
   ============================================================ */

@media (max-width: 1080px) {
  .hero .container {
    grid-template-columns: 1fr;
    gap: var(--kvnk-space-12);
  }
  .statistik .container {
    grid-template-columns: 1fr;
    gap: var(--kvnk-space-12);
  }
  /* Markenblock über die volle Breite, Listen darunter zu dritt */
  .fussbereich .container {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
  .fussbereich__marke {
    grid-column: 1 / -1;
  }
  .fussbereich__beschreibung {
    max-width: 34rem;
  }
  .hero__medien {
    max-width: 32rem;
  }
  .hero__bild {
    aspect-ratio: 16 / 10;
  }
  /* Beim Querformat-Zuschnitt den unteren Bildteil zeigen — dort liegen
     Laube, Zaun und Parzellen. Mittig zugeschnitten sähe man nur Himmel. */
  .hero__bild img {
    object-position: center 78%;
  }
  .hero__karte {
    left: auto;
    right: var(--kvnk-space-6);
    bottom: calc(-1 * var(--kvnk-space-6));
  }
}

@media (max-width: 900px) {
  /* Navigation wird zu einer eingeblendeten Tafel */
  .menue-knopf {
    display: grid;
    order: 3;
  }
  .kopfbereich .container {
    gap: var(--kvnk-space-3);
  }
  /* Ohne dies bleibt .marke bei seiner vollen Inhaltsbreite (flex-shrink: 0
     greift für den Desktop-Zustand mit eingereihter Navigation) und drängt
     den Menü-Knopf rechts aus dem Sichtfeld — unterhalb von etwa 426 px war
     er per Koordinate gar nicht mehr antippbar, obwohl display/visibility
     „sichtbar" meldeten. */
  .marke {
    flex-shrink: 1;
    min-width: 0;
  }

  .hauptnav {
    position: fixed;
    inset: 0 0 0 auto;
    width: min(22rem, 82vw);
    z-index: var(--kvnk-z-overlay);
    background: var(--kvnk-bg);
    border-left: 1px solid var(--kvnk-border);
    box-shadow: var(--kvnk-shadow-lg);
    padding: var(--kvnk-space-24) var(--kvnk-space-8) var(--kvnk-space-8);
    transform: translateX(100%);
    visibility: hidden;
    transition: transform var(--kvnk-zeit-mittel) var(--kvnk-kurve-aus),
                visibility var(--kvnk-zeit-mittel);
    overflow-y: auto;
  }
  .hauptnav[data-offen="true"] {
    transform: none;
    visibility: visible;
  }
  .hauptnav ul {
    flex-direction: column;
    align-items: stretch;
    gap: var(--kvnk-space-1);
  }
  .hauptnav a {
    min-height: 52px;
    font-size: var(--kvnk-font-size-lg);
    padding-block: var(--kvnk-space-2);
    border-bottom: 1px solid var(--kvnk-border);
  }
  .hauptnav a::after {
    display: none;
  }

  .nav-hintergrund {
    display: block;
    position: fixed;
    inset: 0;
    z-index: calc(var(--kvnk-z-overlay) - 1);
    background: rgb(0 0 0 / 0.45);
    opacity: 0;
    visibility: hidden;
    transition: opacity var(--kvnk-zeit-mittel) var(--kvnk-kurve),
                visibility var(--kvnk-zeit-mittel);
    border: 0;
    cursor: pointer;
  }
  .nav-hintergrund[data-offen="true"] {
    opacity: 1;
    visibility: visible;
  }

  /* Einspaltig: das Motiv rutscht unter den Text. Es bleibt sichtbar — die
     Bildsprache trägt den ganzen Auftritt, auf dem Telefon genauso wie am
     Schreibtisch —, wird aber zum flachen Band gestaucht. Ein 16:10-Bild
     wäre auf 360 px rund 225 px hoch und schöbe den Inhalt zu weit nach
     unten; als Band kostet es rund 110 px. Die Vereinsliste ist auf 360 px
     ohnehin lang (E5-01), deshalb hier die schmalste vertretbare Fassung. */
  .seitenkopf--bild .container {
    grid-template-columns: 1fr;
  }
  .seitenkopf__medien {
    margin-top: var(--kvnk-space-8);
  }
  .seitenkopf__medien--illustration .seitenkopf__bild {
    aspect-ratio: 21 / 9;
    max-height: 11rem;
  }
  /* Der untere Bildteil trägt das Motiv (Laube, Zaun, Beet); mittig
     zugeschnitten zeigte das Band vor allem Himmel. Gleiche Begründung wie
     beim Querformat-Zuschnitt des Hero-Bildes. 85 % statt 100 %, damit die
     hohen Motive (Schaukastendach, Wegweiser, Messlatte) oben nicht
     abgeschnitten werden. */
  .seitenkopf__medien--illustration .seitenkopf__bild img {
    object-position: center 85%;
  }
}

@media (max-width: 600px) {
  .abschnitt__kopf {
    margin-bottom: var(--kvnk-space-8);
  }
  .kachel,
  .meldung {
    padding: var(--kvnk-space-6);
  }
  .hero__karte {
    position: static;
    max-width: none;
    margin-top: var(--kvnk-space-4);
  }
  .fussbereich .container {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--kvnk-space-8);
    padding-block: var(--kvnk-space-16) var(--kvnk-space-8);
  }
  .statistik__werte {
    gap: var(--kvnk-space-4);
  }
  /* Weniger Motive, damit die schmale Rasenkante nicht überladen wirkt */
  .gartenfigur--zaun,
  .gartenfigur--vogelhaus {
    display: none;
  }
  .statistik .container {
    padding-bottom: 11rem;
  }
  .gartenschmuck--hecke {
    height: 7rem;
  }
}

@media (max-width: 480px) {
  .container {
    padding-inline: var(--kvnk-space-4);
  }
  .hero__aktionen .schaltflaeche {
    width: 100%;
  }
  .fussbereich .container {
    grid-template-columns: 1fr;
  }
  .statistik__werte {
    grid-template-columns: 1fr;
  }
  .statistik__werte > li {
    display: flex;
    align-items: baseline;
    gap: var(--kvnk-space-4);
  }
  .statistik__zahl {
    min-width: 4.5rem;
  }
  .statistik__label {
    margin-top: 0;
  }
  .gartenfigur--giesskanne {
    display: none;
  }
  /* Mehr Luft als auf großen Bildschirmen: die Zahlen stehen hier
     untereinander und kämen der Bepflanzung sonst zu nah. */
  .statistik .container {
    padding-bottom: 12rem;
  }
  .gartenschmuck--hecke {
    height: 6.5rem;
    bottom: 2.25rem;
  }
  .gartenschmuck--rasen {
    height: 4.5rem;
  }
  .gartenfigur--zwerg { width: 4rem; bottom: 1.4rem; }
  .gartenfigur--sonnenblume { width: 4.75rem; bottom: 1.5rem; }
}

/* ============================================================
   18. Bewegung reduzieren — muss zuletzt stehen
   ============================================================ */

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  /* Eingeblendete Inhalte sofort zeigen, statt sie zu verstecken */
  .js [data-reveal] {
    opacity: 1;
    transform: none;
  }
  .kachel:hover,
  .meldung:hover,
  .angebot:hover {
    transform: none;
  }
  /* Vereinskachel und Gartenangebot-Karte heben sich nicht mehr an — beide
     ziehen nur ihr Bild heran. Auch das ist Bewegung und entfällt hier. */
  .vereinskachel:hover .vereinskachel__bild img,
  .vereinskachel:hover .vereinskachel__bild .anlagenriss,
  .vereinskachel:focus-within .vereinskachel__bild img,
  .vereinskachel:focus-within .vereinskachel__bild .anlagenriss,
  .angebot:hover .angebot__bild img,
  .angebot:hover .angebot__bild .anlagenriss,
  .angebot:focus-within .angebot__bild img,
  .angebot:focus-within .angebot__bild .anlagenriss {
    transform: none;
  }
}

/* Drucken */
@media print {
  .kopfbereich,
  .entwurfshinweis,
  .nav-hintergrund,
  .hero__medien,
  .seitenkopf__medien,
  .fussbereich nav {
    display: none;
  }
  body {
    color: #000;
    background: #fff;
  }
}

/* ============================================================
   19. Terminliste
   ============================================================ */

.terminliste {
  list-style: none;
  display: grid;
  gap: 0;
  margin: 0;
  padding: 0;
}

.terminzeile {
  display: grid;
  grid-template-columns: 11rem 1fr auto;
  gap: var(--kvnk-space-6);
  align-items: start;
  padding: var(--kvnk-space-6) 0;
  border-bottom: 1px solid var(--kvnk-border);
}
.terminzeile:first-child {
  border-top: 1px solid var(--kvnk-border);
}

.terminzeile__datum {
  font-size: var(--kvnk-font-size-sm);
  color: var(--kvnk-text-muted);
  font-variant-numeric: tabular-nums;
  padding-top: 2px;
}

.terminzeile__titel {
  font-size: var(--kvnk-font-size-xl);
}

/* Wie bei den Meldungskacheln: der Titel führt auf die Terminseite, bleibt
   aber in der Textfarbe — die Zeile trägt daneben schon den Verweis
   „Kalender", zwei farbige Links nebeneinander wären unruhig. Bewusst ohne
   die dortige Flächenvergrößerung (::after mit inset: 0): sie würde den
   Kalender-Verweis derselben Zeile überdecken. */
.terminzeile__titel a {
  color: inherit;
  text-decoration: none;
}
.terminzeile__titel a:hover,
.terminzeile__titel a:focus-visible {
  color: var(--kvnk-link-hover);
  text-decoration: underline;
}

.terminzeile__ort {
  display: flex;
  align-items: center;
  gap: var(--kvnk-space-2);
  font-size: var(--kvnk-font-size-sm);
  color: var(--kvnk-text-muted);
  margin-top: var(--kvnk-space-2);
}
.terminzeile__ort svg {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
  stroke: currentColor;
  fill: none;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Wie im Zeitstrahl ein flacher Zweitknopf. `white-space: nowrap` hält die
   Beschriftung in einer Zeile — die dritte Rasterspalte ist `auto` und
   richtet sich danach, statt den Knopf umbrechen zu lassen. */
.terminzeile__ics {
  align-self: center;
  min-height: 44px;
  padding-inline: var(--kvnk-space-6);
  white-space: nowrap;
}

@media (max-width: 600px) {
  .terminzeile {
    grid-template-columns: 1fr;
    gap: var(--kvnk-space-2);
    padding: var(--kvnk-space-5) 0;
  }
  /* Einspaltig steht der Knopf unter dem Termin und darf die volle Breite
     nehmen — `nowrap` bliebe sonst über den Rand hinaus stehen. */
  .terminzeile__ics {
    justify-self: start;
    margin-top: var(--kvnk-space-3);
    white-space: normal;
  }
}

/* ============================================================
   20. Dokumentliste
   ============================================================ */

.dokumentliste {
  list-style: none;
  display: grid;
  gap: 0;
  margin: 0;
  padding: 0;
  /* Obere Abgrenzung an der Liste, nicht an der ersten Zeile: sobald die
     Suche die erste Zeile ausblendet, verschwände sonst der obere Strich
     und die Liste begänne ohne Kante (E7-04). */
  border-top: 1px solid var(--kvnk-border);
}

.dokumentzeile {
  display: flex;
  align-items: center;
  gap: var(--kvnk-space-6);
  padding: var(--kvnk-space-5) 0;
  border-bottom: 1px solid var(--kvnk-border);
}
.dokumentzeile__inhalt {
  flex: 1;
  min-width: 0;
}
.dokumentzeile__kategorie {
  display: inline-flex;
  font-size: var(--kvnk-font-size-xs);
  font-weight: var(--kvnk-font-weight-medium);
  letter-spacing: var(--kvnk-tracking-weit);
  text-transform: uppercase;
  color: var(--kvnk-akzent);
  margin-bottom: var(--kvnk-space-1);
}
.dokumentzeile__titel {
  font-size: var(--kvnk-font-size-lg);
}
.dokumentzeile__meta {
  font-size: var(--kvnk-font-size-xs);
  color: var(--kvnk-text-subtle);
  margin-top: var(--kvnk-space-1);
}
/* Scan ohne Textebene (E7-04): abgesetzt, aber nicht als Warnung eingefärbt —
   die Aussage steht im Text, Farbe trägt sie nicht allein (WCAG 1.4.1), und
   ein eigener Warnton wäre ein ungeprüftes Farbpaar. */
.dokumentzeile__scanhinweis {
  font-size: var(--kvnk-font-size-sm);
  color: var(--kvnk-text-muted);
  margin-top: var(--kvnk-space-2);
  padding-left: var(--kvnk-space-3);
  border-left: 3px solid var(--kvnk-border-stark);
  max-width: var(--kvnk-mass-weit);
}
/* Der Treffer steht im Dokumenttext, nicht in der Überschrift — ohne diese
   Zeile wirkt das Ergebnis wie ein Fehlgriff der Suche. */
.dokumentzeile__fundstelle {
  font-size: var(--kvnk-font-size-xs);
  font-weight: var(--kvnk-font-weight-medium);
  color: var(--kvnk-text-muted);
  margin-top: var(--kvnk-space-2);
}
.dokumentzeile__download {
  min-height: 44px;
  white-space: nowrap;
  flex-shrink: 0;
}
.dokumentzeile__download svg {
  width: 16px;
  height: 16px;
}

@media (max-width: 600px) {
  .dokumentzeile {
    flex-wrap: wrap;
  }
  .dokumentzeile__download {
    width: 100%;
  }
}

/* ============================================================
   21. Fließtext-Inhalt (Redaktionelle Seiten)
   ============================================================ */

/* Zeilenlänge des Fließtextes begrenzen — galt vorher als Inline-Angabe
   in jeder Vorlage, gehört als Grundmaß an die Komponente selbst. */
.inhalt-text {
  max-width: var(--kvnk-mass-weit);
}

/* Fließtext, der unter einer Liste steht (Gartenbörse). */
.inhalt-text--abgesetzt {
  margin-top: var(--kvnk-space-12);
}

/* Fließtext, der direkt an seinen eigenen Datensatz anschließt (Gartenangebot). */
.inhalt-text--anschluss {
  margin-top: var(--kvnk-space-8);
}

.inhalt-text h2,
.inhalt-text h3 {
  margin-top: var(--kvnk-space-8);
  margin-bottom: var(--kvnk-space-4);
}

/* Ohne diese beiden Regeln erben Überschriften in langem Fließtext nur die
   Browser-Grundgröße (~1.5em bzw. ~1.17em) — bei einem Gesetzestext mit über
   zwanzig §§ hintereinander reicht der Unterschied zum Fließtext nicht, um
   beim Überfliegen als Absprungpunkt zu wirken. Andere Überschriften auf der
   Seite haben immer eine eigene, kontextbezogene Größe; `.inhalt-text` war
   die einzige Stelle ohne, weil bisherige Texte hier kurz waren. */
.inhalt-text h2 {
  font-size: var(--kvnk-font-size-2xl);
}
.inhalt-text h3 {
  font-size: var(--kvnk-font-size-xl);
}

.inhalt-text p,
.inhalt-text ul,
.inhalt-text ol {
  margin-top: var(--kvnk-space-4);
}

.inhalt-text ul,
.inhalt-text ol {
  padding-left: var(--kvnk-space-6);
}

/* Verschachtelte Aufzählung (z. B. „a., b., c." unter „1., 2., 3." in
   Satzungstexten) braucht eine eigene Markierung — sonst zählt sie einfach
   von 1 weiter und ist von der übergeordneten Ebene kaum zu unterscheiden. */
.inhalt-text ol ol {
  list-style-type: lower-alpha;
  margin-top: var(--kvnk-space-2);
}
.inhalt-text ol ol li {
  margin-top: var(--kvnk-space-1);
}

.inhalt-text li {
  margin-top: var(--kvnk-space-2);
}

.inhalt-text a {
  text-underline-offset: 4px;
}

.inhalt-text strong {
  font-weight: var(--kvnk-font-weight-medium);
}

.inhalt-text blockquote {
  border-left: 3px solid var(--kvnk-akzent);
  margin-left: 0;
  padding-left: var(--kvnk-space-6);
  color: var(--kvnk-text-muted);
  font-size: var(--kvnk-font-size-sm);
}

/* Tabellen aus dem Redaktionssystem. Markdown erzeugt nacktes <table> ohne
   Klassen — ohne diese Regeln steht die Browser-Grundform in der Seite.
   Bewusst schlicht: waagerechte Linien wie in Termin- und Dokumentliste,
   keine Rahmen um jede Zelle. */
.inhalt-text table {
  width: 100%;
  margin-top: var(--kvnk-space-6);
  border-collapse: collapse;
  font-size: var(--kvnk-font-size-sm);
}

.inhalt-text th,
.inhalt-text td {
  text-align: left;
  padding: var(--kvnk-space-3) var(--kvnk-space-4) var(--kvnk-space-3) 0;
  border-bottom: 1px solid var(--kvnk-border);
  vertical-align: top;
}

.inhalt-text th {
  font-weight: var(--kvnk-font-weight-medium);
  font-size: var(--kvnk-font-size-xs);
  text-transform: uppercase;
  letter-spacing: var(--kvnk-tracking-weit);
  color: var(--kvnk-text-muted);
  border-bottom-color: var(--kvnk-border-stark);
}

.inhalt-text tr:last-child td {
  border-bottom: none;
}

/* ============================================================
   21b. Portal für die Selbstpflege — Gartenangebote (E12-08)
        und eigene Kontaktdaten (E12-09)
   ============================================================ */

.portal-app {
  display: grid;
  gap: var(--kvnk-space-8);
}

.portal-app__kopf {
  display: grid;
  gap: var(--kvnk-space-4);
}

.portal-app__steuerung {
  display: grid;
  gap: var(--kvnk-space-4);
  align-items: start;
}

.portal-gruppen,
.portal-status,
.portal-route {
  font-size: var(--kvnk-font-size-sm);
  color: var(--kvnk-text-muted);
}

.portal-status {
  padding: var(--kvnk-space-3) var(--kvnk-space-4);
  border: 1px solid var(--kvnk-border);
  border-radius: var(--kvnk-radius-md);
  background: var(--kvnk-surface);
}

.portal-status[data-kind="success"] {
  border-color: var(--kvnk-status-frei-text);
}

.portal-status[data-kind="error"] {
  border-color: var(--kvnk-status-vergangen-text);
}

.portal-layout {
  display: grid;
  grid-template-columns: minmax(0, 0.95fr) minmax(0, 1.05fr);
  gap: var(--kvnk-space-8);
  align-items: start;
}

.portal-spalte {
  display: grid;
  gap: var(--kvnk-space-5);
}

.portal-kopfzeile {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--kvnk-space-4);
}

.portal-angebote {
  display: grid;
  gap: var(--kvnk-space-4);
}

.portal-angebote__leer {
  color: var(--kvnk-text-subtle);
  font-style: italic;
}

.portal-card {
  display: grid;
  gap: var(--kvnk-space-3);
  padding: var(--kvnk-space-5);
  border: 1px solid var(--kvnk-border);
  border-radius: var(--kvnk-radius-lg);
  background: var(--kvnk-surface);
  box-shadow: var(--kvnk-shadow-sm);
}

.portal-card__kopf {
  display: flex;
  justify-content: space-between;
  gap: var(--kvnk-space-4);
  align-items: start;
}

.portal-card h3 {
  font-size: var(--kvnk-font-size-lg);
}

.portal-card__badge {
  display: inline-flex;
  align-items: center;
  padding: 0.2rem 0.55rem;
  border-radius: 999px;
  font-size: var(--kvnk-font-size-xs);
  font-weight: var(--kvnk-font-weight-medium);
  letter-spacing: var(--kvnk-tracking-weit);
  text-transform: uppercase;
}

.portal-card__badge--live {
  background: var(--kvnk-status-frei-bg);
  color: var(--kvnk-status-frei-text);
}

.portal-card__badge--draft {
  background: var(--kvnk-status-vergangen-bg);
  color: var(--kvnk-status-vergangen-text);
}

.portal-card__meta {
  font-size: var(--kvnk-font-size-sm);
  color: var(--kvnk-text-muted);
}

.portal-card__aktionen {
  display: flex;
  flex-wrap: wrap;
  gap: var(--kvnk-space-3);
}

.portal-form {
  display: grid;
  gap: var(--kvnk-space-6);
  padding: var(--kvnk-space-6);
  border: 1px solid var(--kvnk-border);
  border-radius: var(--kvnk-radius-lg);
  background: var(--kvnk-surface);
}

.portal-form__felder {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--kvnk-space-4);
}

.portal-feld {
  display: grid;
  gap: var(--kvnk-space-2);
}

.portal-feld--breit {
  grid-column: 1 / -1;
}

.portal-feld > span {
  font-size: var(--kvnk-font-size-sm);
  font-weight: var(--kvnk-font-weight-medium);
}

.portal-feld input,
.portal-feld textarea,
.portal-feld select {
  width: 100%;
}

.portal-checkbox {
  grid-template-columns: auto 1fr;
  align-items: center;
}

.portal-checkbox input {
  width: 1rem;
  height: 1rem;
}

.portal-vorschau {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--kvnk-space-3);
  padding: var(--kvnk-space-4);
  border-radius: var(--kvnk-radius-md);
  /* `--kvnk-flaeche-zart` stand hier und ist in tokens.css nirgends definiert
     (Fund bei E12-09): Eine unbekannte Custom Property macht die ganze
     Deklaration ungültig, die Fläche blieb also durchsichtig — sichtbar nur
     als fehlende Absetzung, nicht als Fehler. Richtig ist
     `--kvnk-bg-gedaempft`; es ist für beide Darstellungen belegt. */
  background: var(--kvnk-bg-gedaempft);
}

.portal-vorschau span {
  display: block;
  font-size: var(--kvnk-font-size-xs);
  color: var(--kvnk-text-subtle);
  text-transform: uppercase;
  letter-spacing: var(--kvnk-tracking-weit);
  margin-bottom: 0.15rem;
}

.portal-vorschau strong {
  display: block;
  font-size: var(--kvnk-font-size-sm);
}

.portal-form__aktionen {
  display: flex;
  flex-wrap: wrap;
  gap: var(--kvnk-space-3);
}

/* ---- Wegweiser zwischen den Portalbereichen (E12-09) ---- */

.portal-wege ul {
  display: flex;
  flex-wrap: wrap;
  gap: var(--kvnk-space-2);
  margin: 0 0 var(--kvnk-space-6);
  padding: 0;
  list-style: none;
}

.portal-wege a {
  display: inline-block;
  padding: var(--kvnk-space-2) var(--kvnk-space-4);
  border: 1px solid var(--kvnk-border);
  border-radius: var(--kvnk-radius-md);
  background: var(--kvnk-surface);
  font-size: var(--kvnk-font-size-sm);
  text-decoration: none;
}

/* Der aktive Bereich ist nicht nur farblich markiert: `aria-current` trägt
   die Aussage, das CSS hängt sich daran. Eine Klasse „aktiv" hätte dasselbe
   Aussehen und keine Bedeutung. */
.portal-wege a[aria-current="page"] {
  border-color: var(--kvnk-border-dunkel);
  background: var(--kvnk-akzent-flaeche);
  font-weight: var(--kvnk-font-weight-medium);
}

/* ---- Einwilligungsstufe (E12-09) ---- */

.portal-einwilligung {
  display: grid;
  gap: var(--kvnk-space-3);
  margin: 0;
  padding: var(--kvnk-space-5);
  border: 1px solid var(--kvnk-border-stark);
  border-radius: var(--kvnk-radius-md);
  /* `--kvnk-flaeche-zart` stand hier und ist in tokens.css nirgends definiert
     (Fund bei E12-09): Eine unbekannte Custom Property macht die ganze
     Deklaration ungültig, die Fläche blieb also durchsichtig — sichtbar nur
     als fehlende Absetzung, nicht als Fehler. Richtig ist
     `--kvnk-bg-gedaempft`; es ist für beide Darstellungen belegt. */
  background: var(--kvnk-bg-gedaempft);
}

.portal-einwilligung legend {
  padding: 0 var(--kvnk-space-2);
  font-size: var(--kvnk-font-size-sm);
  font-weight: var(--kvnk-font-weight-medium);
}

.portal-radio {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--kvnk-space-3);
  align-items: start;
  font-size: var(--kvnk-font-size-sm);
  line-height: var(--kvnk-line-height-normal);
}

/* Kein `outline: none` und kein selbstgemalter Ring: Der globale
   :focus-visible-Rahmen bleibt stehen — er ist das, was
   werkzeuge/tastaturpruefung.mjs überhaupt erkennen kann. */
.portal-radio input {
  width: 1rem;
  height: 1rem;
  margin-top: 0.2rem;
}

.portal-warnung {
  margin: 0;
  padding: var(--kvnk-space-3) var(--kvnk-space-4);
  border-left: 3px solid var(--kvnk-akzent);
  border-radius: var(--kvnk-radius-sm);
  background: var(--kvnk-surface);
  font-size: var(--kvnk-font-size-sm);
  color: var(--kvnk-text-muted);
}

/* Ein Konto, ein Verein: dann steht der Name da, statt in einer Auswahlliste
   mit einem Eintrag zu stecken. */
.portal-feld--fest {
  margin: 0;
}

.portal-feld--fest > span {
  display: block;
  font-size: var(--kvnk-font-size-sm);
  font-weight: var(--kvnk-font-weight-medium);
}

/* Die Vorschau benutzt die Steckbrief-Darstellung der Vereinsseite — damit
   sie zeigt, wie es dort aussieht, und nicht, wie es hier aussieht. */
.steckbrief--vorschau {
  padding: var(--kvnk-space-5);
  border: 1px solid var(--kvnk-border);
  border-radius: var(--kvnk-radius-lg);
  background: var(--kvnk-surface);
}

@media (max-width: 68rem) {
  .portal-layout {
    grid-template-columns: 1fr;
  }

  .portal-form__felder,
  .portal-vorschau {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 42rem) {
  .portal-kopfzeile {
    flex-direction: column;
    align-items: start;
  }
}

/* Telefonnummern nicht umbrechen. Ersetzt die früheren &nbsp;-Entities in
   site.yaml — Umbruchverhalten ist Darstellung und gehört ins CSS. */
a[href^="tel:"] {
  white-space: nowrap;
}

/* ============================================================
   22. Zweispalter mit Nebenspalte (Vereinsdetail, Kontakt)
   ============================================================ */

.zweispalter {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 18rem);
  gap: var(--kvnk-space-12);
  align-items: start;
}

/* Kontaktseite: beide Spalten gleich breit. */
.zweispalter--gleich {
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
}

/* Ab hier stapeln sich die Spalten. Die frühere Inline-Angabe hatte keinen
   Umbruchpunkt — die Nebenspalte wurde auf schmalen Geräten zusammengedrückt
   (Ziel Z2: 360 px ohne horizontales Scrollen). */
@media (max-width: 900px) {
  .zweispalter,
  .zweispalter--gleich {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--kvnk-space-8);
  }
}

.infokasten {
  background: var(--kvnk-surface-2);
  border: 1px solid var(--kvnk-border);
  border-radius: var(--kvnk-radius-lg);
  padding: var(--kvnk-space-8);
}

.infokasten__titel {
  font-size: var(--kvnk-font-size-xl);
  margin-bottom: var(--kvnk-space-6);
}

.service-detail__seitenleiste {
  display: grid;
  gap: var(--kvnk-space-6);
}

.service-detail__block--abgesetzt {
  padding-top: var(--kvnk-space-6);
  border-top: 1px solid var(--kvnk-border);
}

.service-detail__hinweis {
  margin: 0;
  color: var(--kvnk-text-muted);
  font-size: var(--kvnk-font-size-sm);
  line-height: var(--kvnk-line-height-relaxed);
}

.service-detail__liste {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: var(--kvnk-space-3);
}

.service-detail__aktuell {
  display: inline-block;
  font-weight: var(--kvnk-font-weight-semibold);
}

.service-detail__kontakt {
  gap: var(--kvnk-space-4);
}

.service-detail__kontakt .kennzeichen {
  justify-self: start;
}

.service-detail__kontakt p {
  margin: 0;
}

/* Überschrift eines Inhaltsabschnitts außerhalb eines Kastens. */
.abschnittstitel {
  font-size: var(--kvnk-font-size-2xl);
  margin-bottom: var(--kvnk-space-6);
}

/* --- Steckbrief: Definitionsliste im Infokasten --- */

.steckbrief {
  display: grid;
  gap: var(--kvnk-space-4);
  font-size: var(--kvnk-font-size-sm);
}

.steckbrief dt {
  display: flex;
  align-items: center;
  gap: var(--kvnk-space-2);
  font-weight: var(--kvnk-font-weight-medium);
  color: var(--kvnk-text-muted);
  font-size: var(--kvnk-font-size-xs);
  text-transform: uppercase;
  letter-spacing: var(--kvnk-tracking-weit);
}

/* Piktogramm vor dem Begriff (E8-14). Klein und ohne Kasten — anders als in
   der Kachel, wo das Zeichen der Blickfang ist. Hier ist es eine Marke zum
   Wiederfinden: Acht Begriffe stehen auf allen 40 Vereinsseiten in gleicher
   Reihenfolge, und ab der dritten Seite wird nicht mehr gelesen, sondern
   gesucht.

   Die Versalien der Begriffe machen das nötig: Sie sind gut zu unterscheiden,
   solange man liest, aber als Formen einander sehr ähnlich. */
.steckbrief__symbol {
  display: inline-flex;
  flex-shrink: 0;
  color: var(--kvnk-color-primary-600);
}

.steckbrief__symbol .piktogramm {
  width: 1.125rem;
  height: 1.125rem;
}

.steckbrief dd {
  margin: var(--kvnk-space-1) 0 0;
}

/* Kontaktangaben vom übrigen Steckbrief abtrennen. */
.steckbrief__gruppe--abgetrennt {
  padding-top: var(--kvnk-space-4);
  border-top: 1px solid var(--kvnk-border);
}

/* Erläuterung, warum statt einer Person die Geschäftsstelle genannt wird.
   Bewusst kein `opacity` und keine eigene Farbe — der Hinweis trägt die
   Information, nicht nur Beiwerk (vgl. E9-02). */
.steckbrief__hinweis {
  display: inline-block;
  margin-bottom: var(--kvnk-space-2);
  line-height: var(--kvnk-line-height-relaxed);
}

/* ============================================================
   23. Kontaktangaben (Kontaktseite)
   ============================================================ */

.kontaktadresse {
  font-style: normal;
  font-size: var(--kvnk-font-size-base);
  line-height: var(--kvnk-line-height-relaxed);
}

.kontaktzeile {
  display: inline-flex;
  align-items: center;
  gap: var(--kvnk-space-2);
}

/* Die Zeilen sind durch <br> getrennt — daher der allgemeine
   Geschwister-Selektor statt "+". */
.kontaktzeile ~ .kontaktzeile {
  margin-top: var(--kvnk-space-2);
}

.kontaktzeile svg {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  stroke: currentColor;
  fill: none;
  stroke-width: 1.75;
  stroke-linecap: round;
}

/* Redaktioneller Zusatztext unter den Kontaktangaben. */
.kontakt-zusatztext {
  margin-top: var(--kvnk-space-8);
}

.sprechzeiten {
  color: var(--kvnk-text-muted);
  font-size: var(--kvnk-font-size-sm);
  line-height: var(--kvnk-line-height-relaxed);
}

.sprechzeitenliste {
  margin: 0;
  display: grid;
  gap: var(--kvnk-space-3);
}

.sprechzeitenliste__eintrag {
  margin: 0;
  display: grid;
  grid-template-columns: minmax(7.5rem, auto) 1fr;
  align-items: baseline;
  gap: var(--kvnk-space-2) var(--kvnk-space-4);
}

.sprechzeitenliste__eintrag dt,
.sprechzeitenliste__eintrag dd {
  margin: 0;
}

.sprechzeitenliste__eintrag dt {
  font-weight: var(--kvnk-font-weight-semibold);
}

.sprechzeitenliste__eintrag dd {
  color: var(--kvnk-text-muted);
}

@media (max-width: 30rem) {
  .sprechzeitenliste__eintrag {
    grid-template-columns: 1fr;
    gap: 0;
  }

  .sprechzeitenliste__eintrag dd {
    margin-top: 0.15rem;
  }
}

/* ============================================================
   24. Fußnavigation einer Detailseite (Meldung, Termin)
   ============================================================ */

.meldungsfuss,
.terminfuss {
  margin-top: var(--kvnk-space-12);
  padding-top: var(--kvnk-space-6);
  border-top: 1px solid var(--kvnk-border);
}

/* Rücksprung zur Übersicht: Pfeil nach links.
   Vorher spiegelte eine Inline-Angabe (scaleX(-1)) den gesamten Link —
   damit stand auch die Beschriftung seitenverkehrt. Gespiegelt wird jetzt
   nur das Pfeilzeichen, und es steht vor dem Text. */
.pfeil-link--zurueck::after {
  content: none;
}

.pfeil-link--zurueck::before {
  content: "←";
  transition: transform var(--kvnk-zeit-mittel) var(--kvnk-kurve-aus);
}

.pfeil-link--zurueck:hover::before {
  transform: translateX(-4px);
}

/* ============================================================
   25. Wiederkehrende Kleinteile
   ============================================================ */

/* Hinweis, wenn eine Liste keinen Eintrag enthält. */
.leer-hinweis {
  color: var(--kvnk-text-muted);
  margin-bottom: var(--kvnk-space-12);
}

/* Kategorieüberschrift in der Dokumentenübersicht. */
.kategorietitel {
  display: flex;
  align-items: center;
  gap: var(--kvnk-space-3);
  font-size: var(--kvnk-font-size-xl);
  margin-top: var(--kvnk-space-12);
  margin-bottom: var(--kvnk-space-6);
}

/* Zeichen vor dem Kategorienamen (E8-14). Größer als im Steckbrief, weil es
   neben einer Überschrift steht und nicht neben einem Kleinbuchstaben-Label;
   in einem eigenen Kasten wie in der Kachel aber nicht — eine Überschrift mit
   Kasten davor sähe aus wie ein Aufklapper. */
.kategorietitel__symbol {
  display: inline-flex;
  flex-shrink: 0;
  color: var(--kvnk-color-primary-600);
}

.kategorietitel__symbol .piktogramm {
  width: 1.5rem;
  height: 1.5rem;
}

/* Aufklappbare Liste der vergangenen Termine. */
.vergangene-termine {
  margin-top: var(--kvnk-space-12);
}

.vergangene-termine > summary {
  cursor: pointer;
  font-size: var(--kvnk-font-size-sm);
  color: var(--kvnk-text-muted);
  margin-bottom: var(--kvnk-space-6);
}

/* E9-02 geprüft: `opacity: 0.6` ist ersatzlos entfallen. Die Deckkraft lag
   über bereits abgeschwächtem Text (--kvnk-text-muted) und drückte dessen
   nachgewiesenes Kontrastverhältnis unter die 4,5:1 aus WCAG 1.4.3 — die
   Kontrastprüfung rechnet Deckkraft nicht mit und hätte den Verstoß nie
   gemeldet. Dass ein Termin vergangen ist, sagt bereits das `<details>`
   mit seiner Beschriftung; die Abschwächung trug keine eigene Information.
   Die Klasse bleibt im Markup als Aufhänger stehen, hat hier aber bewusst
   keine Regel mehr. */

/* ============================================================
   26. Fehlerseite (404)
   ============================================================ */

.fehlerwege ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
  gap: var(--kvnk-space-2) var(--kvnk-space-8);
  border-top: 1px solid var(--kvnk-border);
}

.fehlerwege li {
  border-bottom: 1px solid var(--kvnk-border);
}

.fehlerwege__hinweis {
  margin-top: var(--kvnk-space-12);
  color: var(--kvnk-text-muted);
  font-size: var(--kvnk-font-size-sm);
  max-width: var(--kvnk-mass-weit);
}

/* ============================================================
   27. Anlagenkarte
   ============================================================
   Erzeugte Geometrie aus user/config/karte.yaml, gezeichnet von
   partials/anlagenkarte.html.twig, bewegt von js/theme.js
   (`anlagenkarteAufbauen`). Keine Kartenkacheln, kein fremder Server —
   Begründung in ADR-0003.

   `--karte-k` ist der Umrechnungsfaktor Karteneinheit → Bildpunkt. Alles,
   was seine Bildschirmgröße behalten soll — Marker, Ortsnamen, der
   Maßstabsbalken — rechnet damit. Linien brauchen ihn nicht: sie tragen
   `vector-effect: non-scaling-stroke`, ihre Strichstärke ist dadurch
   ohnehin in Bildpunkten angegeben.

   Der Vorgabewert 8 gilt, solange kein JavaScript gelaufen ist. Er passt zur
   Übersichtskarte auf üblicher Bildschirmbreite; die Karte steht dann still
   und ist trotzdem vollständig (N-12). */

/* Der frühere eigene `.kartenbereich`-Abschnitt samt Überschrift und
   Vorspann ist im Vereinsfinder aufgegangen (E5-07, Abschnitt 12) — die
   Karte ist dort keine eigene Sache mehr, sondern die eine Hälfte eines
   Werkzeugs. Was hier bleibt, gilt der Karte selbst und wird auch von der
   Vereinsseite genutzt: Übersprung, Lückenhinweis, Namensnennung. */

/* Sprung über die Kartenverweise. Nach demselben Muster wie .sprunglink,
   aber im Textfluss statt am Seitenrand — er gehört zu diesem Abschnitt
   und nicht zur Seite als Ganzes. */
.kartenbereich__sprung {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
}
.kartenbereich__sprung:focus {
  position: static;
  width: auto;
  height: auto;
  clip-path: none;
  display: inline-block;
  margin-bottom: var(--kvnk-space-4);
}

.anlagenkarte {
  position: relative;
}
.anlagenkarte__titel {
  font-size: var(--kvnk-font-size-lg);
  margin-bottom: var(--kvnk-space-2);
}
.anlagenkarte__hinweis {
  font-size: var(--kvnk-font-size-sm);
  color: var(--kvnk-text-muted);
  margin-bottom: var(--kvnk-space-4);
}
/* Der Rahmen gibt das Format vor, nicht die Geometrie: Der Landkreis ist fast
   quadratisch, eine Karte will man im Querformat sehen. Das Skript weitet den
   Ausschnitt auf dieses Verhältnis (`passung()` in js/theme.js), statt das
   Bild zu verzerren oder leere Balken stehen zu lassen. */
.anlagenkarte__rahmen {
  position: relative;
  aspect-ratio: 16 / 10;
  max-height: 78vh;
  overflow: hidden;
  background: var(--kvnk-karte-grund);
  border: 1px solid var(--kvnk-border);
  border-radius: var(--kvnk-radius-md);
}
.anlagenkarte__zeichnung {
  --karte-k: 8;
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  /* `pan-y` bis zur ersten Berührung: Wer über die Karte hinwegscrollen will,
     soll das können — eine Karte, die auf einer 12 000 Bildpunkte langen Seite
     jede Fingerbewegung an sich nimmt, ist eine Falle. Nach dem ersten Tippen
     setzt js/theme.js `data-aktiv`, und dann gehört der Finger der Karte. */
  touch-action: pan-y;
}
.anlagenkarte[data-aktiv] .anlagenkarte__zeichnung {
  touch-action: none;
}
.js .anlagenkarte__zeichnung {
  cursor: grab;
}
.js .anlagenkarte[data-zieht] .anlagenkarte__zeichnung {
  cursor: grabbing;
}

/* ---- Grundkarte: reines Beiwerk ----
   `.karte-grund path` ist Typ- plus Klassenselektor und schlägt damit jede
   reine Klasse. Die Flächenregeln darunter führen deshalb `path` mit —
   sonst gewinnt `fill: none`, und Wald, Siedlung und Gewässerflächen bleiben
   unsichtbar, ohne dass irgendetwas fehlschlägt. */
/* `.anlagenriss__nahdetail` steht bewusst mit in diesem Selektor: Im Riss liegen
   Wege und Lauben **über** der Anlagenfläche und damit außerhalb der
   `.karte-grund`-Gruppe. Ohne diese Grundeinstellung erbten sie SVGs Vorgabe
   `fill: black` — die Wege wurden dann als schwarze Keile gefüllt statt als
   Linien gezeichnet, und ohne `vector-effect` wüchsen die Strichstärken beim
   Zoomen mit. */
.karte-grund path,
.anlagenriss__nahdetail path {
  fill: none;
  stroke: none;
  stroke-linecap: round;
  stroke-linejoin: round;
  /* Strichstärken sind dadurch in Bildpunkten angegeben und bleiben beim
     Zoomen gleich — ohne dass ein Skript sie nachführen müsste. Als
     CSS-Eigenschaft statt als Attribut an 3800 Pfaden: das Attribut kostete
     mehr Bytes als die Geometrie, die es beschreibt. */
  vector-effect: non-scaling-stroke;
}
.karte-grund__wald path {
  fill: var(--kvnk-karte-wald);
}
.karte-grund__siedlung path {
  fill: var(--kvnk-karte-siedlung);
}
.karte-grund__wasser path {
  fill: var(--kvnk-karte-wasser);
}
.karte-grund__fluss path {
  stroke: var(--kvnk-karte-wasser-linie);
  stroke-width: 2;
}
.karte-grund__grenze path {
  stroke: var(--kvnk-karte-grenze);
  stroke-width: 2;
  stroke-dasharray: 10 7;
}
.karte-grund__bahn path {
  stroke: var(--kvnk-karte-strasse-haupt);
  stroke-width: 1.6;
  stroke-dasharray: 9 6;
}
.karte-grund__strasse--wohn path {
  stroke: var(--kvnk-karte-strasse);
  stroke-width: 1.4;
}
.karte-grund__strasse--klein path {
  stroke: var(--kvnk-karte-strasse);
  stroke-width: 1.8;
}
.karte-grund__strasse--mittel path {
  stroke: var(--kvnk-karte-strasse);
  stroke-width: 2.6;
}
.karte-grund__strasse--gross path {
  stroke: var(--kvnk-karte-strasse-haupt);
  stroke-width: 3.4;
}

/* ---- Nahbereich (Kachelausschnitte und Vereinsseite) ----
   Vier Schichten, die es nur im Umkreis der Anlagen gibt und die auf der
   Kreisübersicht bewusst nicht ausgeliefert werden (Begründung in
   `werkzeuge/kartenbau.mjs`). Auf einer Kachel von rund 245 m Breite sind
   sie der eigentliche Inhalt: Ohne sie ist eine Kleingartenanlage ein
   grüner Umriss neben ein paar Strichen, mit ihnen ist sie an ihrem
   Wegemuster zu erkennen. */
.karte-grund__bach path {
  stroke: var(--kvnk-karte-wasser-linie);
  stroke-width: 1.1;
}
.karte-grund__strasse--nah path {
  stroke: var(--kvnk-karte-strasse);
  stroke-width: 1.6;
}
/* Gartenwege heller und dünner als eine Straße — sie sind befahrbar, aber
   keine Straße, und in dieser Dichte (ein Weg je Gartenreihe) würde
   Straßenstärke die Fläche zulaufen lassen. */
.karte-grund__weg path {
  stroke: var(--kvnk-karte-weg);
  stroke-width: 0.9;
}
/* Lauben: gefüllt statt umrandet. Bei rund 6 × 4 m sind sie auf der Kachel
   wenige Bildpunkte groß — ein Umriss wäre bei dieser Größe ein Fleck mit
   Loch, die Füllung ein erkennbarer Punkt. */
.karte-grund__gebaeude path {
  fill: var(--kvnk-karte-gebaeude);
  stroke: none;
}

/* ---- Darstellungsstufen ----
   Welcher Ortsname auf welcher Stufe erscheint, hat werkzeuge/kartenbau.mjs
   entschieden — mit Kollisionsprüfung je Stufe. Hier wird nur ein- und
   ausgeblendet. Ohne JavaScript bleibt Stufe 0 stehen. */
[data-stufe="0"] .karte-grund__strasse--klein,
[data-stufe="0"] .karte-grund__strasse--wohn,
[data-stufe="1"] .karte-grund__strasse--wohn {
  display: none;
}
[data-stufe="0"] .karte-ort:not([data-ab="0"]),
[data-stufe="0"] .karte-anlagenname:not([data-ab="0"]),
[data-stufe="1"] .karte-ort[data-ab="2"],
[data-stufe="1"] .karte-ort[data-ab="3"],
[data-stufe="1"] .karte-anlagenname[data-ab="2"],
[data-stufe="2"] .karte-ort[data-ab="3"] {
  display: none;
}

/* ---- Anlagenflächen ---- */
/* Ohne eindeutige Zuordnung: OSM führt an drei Stellen eine gemeinsame
   Fläche für zwei Vereine. Sie wird gezeigt, aber keinem zugeschrieben —
   deshalb blasser und mit dünnerem Rand. */
.karte-flaeche,
.karte-anlage__flaeche {
  vector-effect: non-scaling-stroke;
}
.karte-flaeche {
  fill: var(--kvnk-karte-anlage);
  /* Umriss auch hier: Die Füllung allein hält keine 3:1 zum Kartengrund
     (WCAG 1.4.11) — die Form wird vom Rand getragen, nachgewiesen in
     werkzeuge/kontrastpruefung.mjs. */
  stroke: var(--kvnk-karte-anlage-rand);
  stroke-width: 1;
}
.karte-anlage__flaeche {
  fill: var(--kvnk-karte-anlage-stark);
  stroke: var(--kvnk-karte-anlage-rand);
  stroke-width: 1.8;
  transition: fill var(--kvnk-zeit-schnell) var(--kvnk-kurve);
}
/* Die Anlage, um die es auf einer Vereinsseite geht, hebt sich ab. */
.karte-anlage--eigen .karte-anlage__flaeche {
  stroke-width: 2.6;
}

/* ---- Marker ----
   Zwei verschachtelte Gruppen: Die äußere setzt den Ort in Kartenkoordinaten
   (Attribut, unveränderlich), die innere hält die Bildschirmgröße. Deshalb
   braucht kein Skript beim Zoomen 40 Marker einzeln anzufassen.
   `transform-box: fill-box` bezieht den Ursprung auf das Element selbst —
   ohne das bezöge sich `transform-origin` auf die viewBox, und die Marker
   flögen beim Zoomen aus der Karte. */
.karte-anlage__marke {
  transform: scale(var(--karte-k));
  transform-box: fill-box;
  transform-origin: center;
}
.karte-anlage {
  cursor: pointer;
}
/* Trefferfläche für Finger und Maus — unsichtbar, aber anklickbar
   (WCAG 2.5.8; der sichtbare Marker allein wäre zu klein). */
.karte-anlage__ziel {
  fill: transparent;
  stroke: none;
}
/* Zusätzlicher Ring am Marker. Er ERSETZT den `outline` aus der globalen
   :focus-visible-Regel nicht, sondern ergänzt ihn: Ein eigener Kreis sitzt
   enger am Marker als ein Rechteck, aber ein Prüfwerkzeug (und mancher
   Nutzer-Stylesheet) erkennt nur den `outline`. Beides zusammen ist
   robuster als das Hübschere allein. */
.karte-anlage__ring {
  fill: none;
  stroke: var(--kvnk-fokus);
  stroke-width: 3.5;
  opacity: 0;
  transition: opacity var(--kvnk-zeit-schnell) var(--kvnk-kurve);
}
.karte-anlage:hover .karte-anlage__ring,
.karte-anlage:focus .karte-anlage__ring,
.karte-anlage:focus-visible .karte-anlage__ring,
.karte-anlage--gezeigt .karte-anlage__ring {
  opacity: 1;
}

/* ---- Karte und Kacheln gekoppelt (E5-07, js/theme.js) ----

   `--gefiltert`: Der Verein fällt aus dem Filter. Der Marker verschwindet
   nicht, er tritt zurück — wer nach „Ellrich" sucht, will trotzdem sehen, wo
   Ellrich im Landkreis liegt, und eine Karte, aus der Punkte verschwinden,
   liest sich als Ladefehler. `pointer-events: none`, damit ein
   ausgefilterter Verein nicht doch angeklickt werden kann; `tabindex` bleibt
   unangetastet — die Marker sind Verweise, und ein Verweis, der beim
   Tabben verschwände, ließe den Fokus ins Leere laufen.

   `--gezeigt`: Zeiger oder Tastaturfokus liegt auf der zugehörigen Kachel.
   Derselbe Ring wie beim Zeigen auf den Marker selbst — die Kachel und ihr
   Punkt sind dasselbe Ding, also sehen sie im selben Zustand gleich aus. */
.karte-anlage--gefiltert {
  opacity: 0.28;
  pointer-events: none;
  transition: opacity var(--kvnk-zeit-mittel) var(--kvnk-kurve);
}
.karte-anlage--gefiltert:focus-visible {
  opacity: 1;
  pointer-events: auto;
}
.karte-anlage--gezeigt .karte-anlage__punkt {
  transform: scale(1.25);
  transform-box: fill-box;
  transform-origin: center;
}
.karte-anlage--eigen .karte-anlage__ring {
  stroke: var(--kvnk-karte-anlage-rand);
  opacity: 1;
}
.karte-anlage:hover .karte-anlage__flaeche {
  fill: var(--kvnk-karte-anlage-rand);
}

.karte-anlage__punkt {
  stroke: var(--kvnk-karte-grund);
  stroke-width: 2.4;
}
.karte-anlage__zeichen {
  fill: none;
  stroke: var(--kvnk-karte-grund);
  stroke-width: 2.8;
  stroke-linecap: round;
}
/* Drei Zustände, drei Formen — die Farbe trägt die Aussage nie allein
   (WCAG 1.4.1): frei ist größer und trägt ein Pluszeichen, unbekannt ist
   hohl mit gestricheltem Rand. Im Text steht der Zustand ohnehin. */
.karte-anlage--frei .karte-anlage__punkt {
  fill: var(--kvnk-karte-marker-frei);
}
.karte-anlage--belegt .karte-anlage__punkt {
  fill: var(--kvnk-karte-marker-belegt);
}
.karte-anlage--unbekannt .karte-anlage__punkt {
  fill: var(--kvnk-karte-grund);
  stroke: var(--kvnk-karte-marker-unbekannt);
  stroke-width: 3.4;
  stroke-dasharray: 5 3.6;
}

/* ---- Zählmarker der Gartenbörse (E11-04) ----
   Statt des Pluszeichens die Zahl der Angebote: Auf einer Karte, die nur
   Vereine mit freien Gärten zeigt, sagt ein Pluszeichen bei jedem Marker
   dasselbe. Die Zahl steht zusätzlich im `<title>` — sie ist Beschriftung,
   nicht die einzige Trägerin der Aussage (WCAG 1.4.1). */
.karte-anlage__zahl {
  fill: var(--kvnk-karte-grund);
  font-family: var(--kvnk-schrift-text);
  font-weight: var(--kvnk-font-weight-medium);
  /* **Feste Größe in Nutzereinheiten, nicht an `--karte-k` gehängt.** Anders
     als Ortsnamen und Maßstab sitzt die Zahl *innerhalb* von
     `.karte-anlage__marke`, und diese Gruppe wird bereits mit `--karte-k`
     skaliert. Ein zweiter Faktor hier ergäbe k² — bei k = 3,3 stand die Zahl
     dann rund fünfzehnmal zu groß über der Karte statt im Marker. Die Zahl
     verhält sich wie die Kreisradien daneben: schlichte Einheiten, das Skalieren
     erledigt die Gruppe. */
  font-size: 15px;
  /* Kein Saum wie bei den Ortsnamen: Die Zahl steht auf der vollen Fläche des
     Markers, ein aufhellender Rand fräse sie von innen aus. */
  user-select: none;
  pointer-events: none;
}
/* Der Marker ist hier ein Knopf in die Liste, kein Wegweiser auf eine andere
   Seite — beim Überfahren wächst er sichtbar an, damit das ankommt. */
.karte-anlage--zahl:hover .karte-anlage__punkt,
.karte-anlage--zahl:focus-visible .karte-anlage__punkt {
  transform: scale(1.12);
  transform-box: fill-box;
  transform-origin: center;
}
/* **Ausgefilterte Zählmarker bleiben anklickbar.** Auf /vereine ist ein
   zurückgetretener Marker ein Suchergebnis, das nicht passt — dort ist
   `pointer-events: none` richtig. Hier ist der Marker das Bedienelement des
   Filters selbst: Wäre er nach dem ersten Klick tot, käme man von Verein A
   nicht mehr zu Verein B, ohne vorher zurückzusetzen. Er tritt zurück, bleibt
   aber der Schalter, der er ist. */
.karte-anlage--zahl.karte-anlage--gefiltert {
  pointer-events: auto;
}

/* ---- Beschriftung und Maßstab ---- */
.karte-beiwerk text,
.karte-massstab text {
  fill: var(--kvnk-karte-beschriftung);
  font-family: var(--kvnk-schrift-text);
  /* Aufhellender Saum, damit Ortsnamen über Straßen lesbar bleiben. */
  paint-order: stroke fill;
  stroke: var(--kvnk-karte-grund);
  stroke-width: 3;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
  /* Beschriftung ist kein Ziehgriff — sonst markiert ein Zug über die Karte
     Text, statt zu verschieben. */
  user-select: none;
}
.karte-ort {
  font-size: calc(var(--karte-k) * 13px);
}
.karte-ort--city,
.karte-ort--town {
  font-size: calc(var(--karte-k) * 16px);
  font-weight: var(--kvnk-font-weight-medium);
}
/* Name der Anlage, unter dem Marker. Der Versatz läuft über `translate` und
   nicht über das `y`-Attribut: Eine reine Verschiebung hängt nicht vom
   `transform-origin` ab und verhält sich bei SVG-Text deshalb überall gleich. */
.karte-anlagenname {
  font-size: calc(var(--karte-k) * 12px);
  font-weight: var(--kvnk-font-weight-medium);
  fill: var(--kvnk-karte-anlage-rand);
  transform: translateY(calc(var(--karte-k) * 26px));
}
.karte-massstab path {
  fill: none;
  stroke: var(--kvnk-karte-beschriftung);
  stroke-width: 2;
}
.karte-massstab text {
  font-size: 13px;
}
/* Die Umrechnung Bildpunkt → Karteneinheit steht beim Maßstab als
   `transform`-Attribut, nicht hier: Balkenlänge und Beschriftung ändern sich
   ohnehin bei jedem Zoomschritt, dann kann derselbe Schritt auch den
   Maßstabsfaktor setzen. */

/* ---- Bedienung ----
   Im Rahmen liegend, gestapelt in der Ecke: Das ist die Stelle, an der man
   Kartenbedienung sucht. Die Knöpfe sind 2,75 rem groß und erfüllen damit die
   Zielgröße aus WCAG 2.5.8 auch auf dem Telefon. */
.anlagenkarte__bedienung {
  position: absolute;
  top: var(--kvnk-space-3);
  right: var(--kvnk-space-3);
  display: flex;
  flex-direction: column;
  gap: var(--kvnk-space-2);
}
.anlagenkarte__knopf {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  height: 2.75rem;
  font: inherit;
  font-size: var(--kvnk-font-size-lg);
  font-weight: var(--kvnk-font-weight-medium);
  line-height: 1;
  color: var(--kvnk-text);
  background: var(--kvnk-surface);
  border: 1px solid var(--kvnk-formularrahmen);
  border-radius: var(--kvnk-radius-sm);
  box-shadow: var(--kvnk-shadow-sm);
  cursor: pointer;
  transition: background var(--kvnk-zeit-schnell) var(--kvnk-kurve);
}
.anlagenkarte__knopf:hover {
  background: var(--kvnk-surface-2);
}
.anlagenkarte__symbol {
  width: 1.25rem;
  height: 1.25rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
/* Namensnennung wie bei jedem Kartendienst in der Ecke des Kartenbildes.
   Lizenzpflicht der ODbL, kein Kleingedrucktes zum Weglassen (ADR-0003). */
.anlagenkarte__herkunft {
  position: absolute;
  /* Zwei Bildpunkte Abstand statt bündig: bündig schnitt die abgerundete
     Ecke des Kartenrahmens das letzte Zeichen der Lizenzangabe ab („(ODbL"
     statt „(ODbL)"). Die Namensnennung ist eine Lizenzpflicht der ODbL und
     darf nicht angeschnitten sein. Fiel auf der Vereinsseite bei 360 px auf,
     nachdem die Karte dort überhaupt wieder sichtbar wurde (Befund B1). */
  right: 2px;
  bottom: 2px;
  margin: 0;
  padding: 0.1rem var(--kvnk-space-2);
  /* Kleiner als der Fließtext und einzeilig: In der schmalen Karte des
     Seitenkopfs brach der Hinweis sonst um, und die zweite Zeile lag
     außerhalb des Rahmens. */
  font-size: 0.72rem;
  line-height: 1.6;
  white-space: nowrap;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--kvnk-text-muted);
  background: var(--kvnk-surface);
  border-radius: var(--kvnk-radius-sm);
}
.anlagenkarte__tastatur {
  font-size: var(--kvnk-font-size-xs);
  color: var(--kvnk-text-subtle);
  margin: var(--kvnk-space-2) 0 0;
}
.anlagenkarte__tastatur kbd {
  font-family: inherit;
  font-weight: var(--kvnk-font-weight-medium);
  border: 1px solid var(--kvnk-border-stark);
  border-radius: 3px;
  padding: 0 0.3em;
}

/* ---- Legende ---- */
.kartenlegende {
  list-style: none;
  margin: var(--kvnk-space-6) 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--kvnk-space-3) var(--kvnk-space-8);
  font-size: var(--kvnk-font-size-sm);
  color: var(--kvnk-text-muted);
}
.kartenlegende li {
  display: inline-flex;
  align-items: center;
  gap: var(--kvnk-space-2);
}
.kartenlegende__zeichen {
  width: 26px;
  height: 26px;
  flex-shrink: 0;
  background: var(--kvnk-karte-grund);
  border-radius: var(--kvnk-radius-sm);
}

.kartenbereich__luecke {
  margin-top: var(--kvnk-space-4);
  font-size: var(--kvnk-font-size-sm);
  color: var(--kvnk-text-muted);
  padding: var(--kvnk-space-3) var(--kvnk-space-4);
  border-left: 3px solid var(--kvnk-border-stark);
  background: var(--kvnk-surface-2);
  border-radius: 0 var(--kvnk-radius-md) var(--kvnk-radius-md) 0;
}
/* Namensnennung ist Lizenzpflicht der ODbL, kein Kleingedrucktes zum
   Weglassen (ADR-0003). */
.kartenbereich__quelle {
  margin-top: var(--kvnk-space-4);
  font-size: var(--kvnk-font-size-xs);
  color: var(--kvnk-text-subtle);
}

/* ---- Schmale Anzeigen ----
   Auf 330 Bildpunkten Breite zeigt die Übersichtskarte denselben Landkreis wie
   auf 1200. Die Beschriftung behält dabei ihre Lesegröße — es passen also
   deutlich weniger Namen nebeneinander, und die Auswahl aus
   werkzeuge/kartenbau.mjs (auf breite Darstellung gerechnet) ergibt hier ein
   Gedränge. Deshalb bleiben in den beiden weitesten Stufen nur Städte und
   größere Orte stehen. Die Anlagen selbst bleiben vollzählig. */
@media (max-width: 700px) {
  .anlagenkarte__rahmen {
    aspect-ratio: 1 / 1;
  }
  [data-stufe="0"] .karte-ort--village,
  [data-stufe="0"] .karte-ort--suburb,
  [data-stufe="0"] .karte-ort--quarter,
  [data-stufe="0"] .karte-ort--hamlet,
  [data-stufe="1"] .karte-ort--quarter,
  [data-stufe="1"] .karte-ort--hamlet {
    display: none;
  }
  /* Im Seitenkopf ist die Karte schon nah dran — dort stört die Dichte nicht.
     Das Format gibt weiterhin `.seitenkopf__bild` vor. */
  .seitenkopf__bild .anlagenkarte__rahmen {
    aspect-ratio: auto;
  }
}

/* Karte auf einer Vereinsseite: im Hero-Bereich läuft sie in dessen
   Bildrahmen, weiter unten steht sie als eigener Abschnitt. */
.vereinskarte-lage {
  margin-top: var(--kvnk-space-12);
}
.vereinskarte-lage h2 {
  font-size: var(--kvnk-font-size-xl);
  margin-bottom: var(--kvnk-space-3);
}
/* Im Seitenkopf läuft die Karte im Bildrahmen mit — gleiche Rundung, gleiches
   Format wie ein Foto an dieser Stelle. Das Seitenverhältnis gibt dort
   `.seitenkopf__bild` vor; ein eigenes hier hatte den Rahmen höher gemacht als
   sein Elternteil, und dessen `overflow: hidden` schnitt die untere Kante mit
   der Namensnennung ab — sichtbar nur als weißer Streifen. */
.seitenkopf__bild .anlagenkarte,
.seitenkopf__bild .anlagenkarte__rahmen {
  height: 100%;
}
.seitenkopf__bild .anlagenkarte__rahmen {
  /* Ohne die Höhe am Elternteil bliebe `height: 100%` ohne Bezug: Der Rahmen
     hat keinen eigenen Inhalt im Fluss (das SVG liegt absolut) und fiele auf
     null zusammen. */
  aspect-ratio: auto;
  max-height: none;
  border: 0;
  border-radius: 0;
}

/* ============================================================
   28. Zeitleiste der Verbandsgeschichte (Historisches)

   Nicht zu verwechseln mit `.zeitstrahl` (Abschnitt 10): Der zeigt
   Meldungen und Termine der nächsten Wochen und wird aus Seiten erzeugt.
   Hier geht es um 120 Jahre, die Einträge stehen im Frontmatter, und
   zwischen den Abschnitten läuft Fließtext mit.

   Beides teilt sich dieselbe Grundform — links das Datum, rechts der
   Inhalt an einer senkrechten Linie —, weil beides dieselbe Frage
   beantwortet: was wann. Zusammenlegen ließe es sich trotzdem nicht. Die
   Spaltenbreite unterscheidet sich (Jahreszahlen statt langer
   Datumsangaben), und die Zeitleiste trägt zusätzlich die
   Abschnittsköpfe auf derselben Linie.
   ============================================================ */

/* ---- Sprungmarken über der Zeitleiste ---- */

.epochenwahl {
  margin-bottom: var(--kvnk-space-16);
  padding-bottom: var(--kvnk-space-8);
  border-bottom: 1px solid var(--kvnk-border);
}

.epochenwahl__titel {
  font-size: var(--kvnk-font-size-xs);
  letter-spacing: var(--kvnk-tracking-weit);
  text-transform: uppercase;
  color: var(--kvnk-text-subtle);
  margin-bottom: var(--kvnk-space-4);
}

.epochenwahl ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--kvnk-space-3);
}

.epochenwahl a {
  display: flex;
  flex-direction: column;
  gap: var(--kvnk-space-1);
  padding: var(--kvnk-space-3) var(--kvnk-space-4);
  border: 1px solid var(--kvnk-border);
  border-radius: var(--kvnk-radius-md);
  text-decoration: none;
  color: var(--kvnk-text);
  background: var(--kvnk-surface);
  transition: border-color var(--kvnk-zeit-schnell) var(--kvnk-kurve),
              background-color var(--kvnk-zeit-schnell) var(--kvnk-kurve);
}

.epochenwahl a:hover {
  border-color: var(--kvnk-link);
  background: var(--kvnk-bg-gedaempft);
}

.epochenwahl__zeitraum {
  font-family: var(--kvnk-schrift-display);
  font-size: var(--kvnk-font-size-sm);
  color: var(--kvnk-link);
  font-variant-numeric: tabular-nums;
}

.epochenwahl__titeltext {
  font-size: var(--kvnk-font-size-xs);
  color: var(--kvnk-text-muted);
}

/* ---- Abschnitt (Epoche) ----

   Kopf und Einträge nutzen dasselbe Raster, damit die Linie in Spalte 2
   ohne Unterbrechung durchläuft. Die Linie hängt — wie beim Zeitstrahl —
   am Inhalt und nicht an einem eigenen Element: so wächst sie mit, ohne
   dass eine Höhe gerechnet werden muss. */

.geschichte {
  --zeitleiste-spalte: 12rem;
}

.epoche + .epoche {
  margin-top: var(--kvnk-space-16);
}

.epoche__kopf,
.zeitleiste__eintrag {
  display: grid;
  grid-template-columns: var(--zeitleiste-spalte) 1fr;
  gap: var(--kvnk-space-6);
  align-items: start;
}

.epoche__zeitraum {
  font-family: var(--kvnk-schrift-display);
  font-size: var(--kvnk-font-size-lg);
  color: var(--kvnk-akzent);
  font-variant-numeric: tabular-nums;
  text-align: right;
  padding-top: var(--kvnk-space-6);
}

.epoche__einleitung {
  position: relative;
  border-left: 1px solid var(--kvnk-border);
  padding: var(--kvnk-space-6) 0 var(--kvnk-space-4) var(--kvnk-space-8);
}

/* Der Abschnittskopf sitzt als größerer, gefüllter Punkt auf derselben
   Linie wie die Einträge, nur schwerer. Rein dekorativ: was der Abschnitt
   ist, steht in der Überschrift daneben. */
.epoche__einleitung::before {
  content: "";
  position: absolute;
  left: -8px;
  top: calc(var(--kvnk-space-6) + 0.5em);
  width: 15px;
  height: 15px;
  border-radius: var(--kvnk-radius-full);
  background: var(--kvnk-akzent);
  border: 3px solid var(--kvnk-bg);
}

.epoche__einleitung h2 {
  font-size: var(--kvnk-font-size-2xl);
  margin-bottom: var(--kvnk-space-4);
}

.epoche__text {
  max-width: var(--kvnk-mass-weit);
  color: var(--kvnk-text-muted);
}

.epoche__text p + p {
  margin-top: var(--kvnk-space-4);
}

.epoche__text strong {
  font-weight: var(--kvnk-font-weight-medium);
  color: var(--kvnk-text);
}

/* ---- Einträge ---- */

.zeitleiste {
  list-style: none;
  margin: 0;
  padding: 0;
}

.zeitleiste__wann {
  display: flex;
  flex-direction: column;
  gap: var(--kvnk-space-1);
  padding-top: var(--kvnk-space-4);
  text-align: right;
}

.zeitleiste__jahr {
  font-family: var(--kvnk-schrift-display);
  font-size: var(--kvnk-font-size-lg);
  color: var(--kvnk-text);
  font-variant-numeric: tabular-nums;
  line-height: var(--kvnk-line-height-tight);
}

.zeitleiste__art {
  font-size: var(--kvnk-font-size-xs);
  letter-spacing: var(--kvnk-tracking-weit);
  text-transform: uppercase;
  color: var(--kvnk-text-subtle);
}

.zeitleiste__inhalt {
  position: relative;
  border-left: 1px solid var(--kvnk-border);
  padding: var(--kvnk-space-4) 0 var(--kvnk-space-4) var(--kvnk-space-8);
}

.zeitleiste__inhalt::before {
  content: "";
  position: absolute;
  left: -5px;
  top: calc(var(--kvnk-space-4) + 0.55em);
  width: 9px;
  height: 9px;
  border-radius: var(--kvnk-radius-full);
  background: var(--kvnk-link);
  border: 2px solid var(--kvnk-link);
}

.zeitleiste__titel {
  font-size: var(--kvnk-font-size-lg);
  line-height: var(--kvnk-line-height-tight);
}

.zeitleiste__text {
  margin-top: var(--kvnk-space-2);
  color: var(--kvnk-text-muted);
  font-size: var(--kvnk-font-size-sm);
  max-width: var(--kvnk-mass-weit);
}

/* ---- Zeitgeschichte tritt zurück ----

   Diese Einträge erklären den Rahmen, sie sind nicht die Geschichte des
   Verbandes. Deshalb kleiner, gedämpft und mit offenem Punkt. Getragen
   wird die Unterscheidung trotzdem vom Wort „Zeitgeschichte“ in der linken
   Spalte — Farbe, Größe und Form allein dürfen eine Bedeutung nicht
   tragen (WCAG 1.4.1). */

.zeitleiste__eintrag--zeitgeschichte .zeitleiste__jahr {
  font-size: var(--kvnk-font-size-sm);
  color: var(--kvnk-text-muted);
}

.zeitleiste__eintrag--zeitgeschichte .zeitleiste__inhalt::before {
  background: var(--kvnk-bg);
  border-color: var(--kvnk-border-stark);
}

.zeitleiste__eintrag--zeitgeschichte .zeitleiste__titel {
  font-size: var(--kvnk-font-size-base);
  font-weight: var(--kvnk-font-weight-regular);
  color: var(--kvnk-text-muted);
}

.zeitleiste__eintrag--zeitgeschichte .zeitleiste__text {
  font-size: var(--kvnk-font-size-xs);
  color: var(--kvnk-text-subtle);
}

.geschichte__nachsatz {
  margin-top: var(--kvnk-space-16);
  padding-top: var(--kvnk-space-8);
  border-top: 1px solid var(--kvnk-border);
  color: var(--kvnk-text-muted);
  font-size: var(--kvnk-font-size-sm);
}

/* ---- Schmale Anzeigen ----

   Unter 700 px hat die zweite Spalte keinen Platz mehr. Die Linie entfällt
   dann samt Punkten — sie hätte nichts, woran sie sich ausrichten könnte
   (dieselbe Entscheidung wie beim Zeitstrahl). Jahr und Art rücken
   nebeneinander über den Eintrag. */

@media (max-width: 700px) {
  .epoche__kopf,
  .zeitleiste__eintrag {
    grid-template-columns: 1fr;
    gap: 0;
  }

  .epoche__zeitraum {
    text-align: left;
    padding-top: var(--kvnk-space-6);
    padding-bottom: var(--kvnk-space-2);
  }

  .zeitleiste__wann {
    flex-direction: row;
    align-items: baseline;
    gap: var(--kvnk-space-3);
    text-align: left;
    padding-top: var(--kvnk-space-6);
  }

  .epoche__einleitung,
  .zeitleiste__inhalt {
    border-left: 0;
    padding: var(--kvnk-space-2) 0 var(--kvnk-space-4);
  }

  .epoche__einleitung::before,
  .zeitleiste__inhalt::before {
    display: none;
  }

  /* Ohne die Linie fehlt die Trennung zwischen den Einträgen — sie kommt
     als schmale Kante zurück, damit die Liste nicht zu einem Block
     verläuft. */
  .zeitleiste__eintrag + .zeitleiste__eintrag {
    border-top: 1px solid var(--kvnk-border);
  }

  /* Die Marken liegen im `li`, nicht im `a` — das `li` ist das Flex-Element
     und trägt deshalb die Breite. Am `a` blieb die Angabe wirkungslos, und
     die Marken standen unterschiedlich breit untereinander. */
  .epochenwahl li {
    flex: 1 1 100%;
  }
}

/* ============================================================
   28a. Rechtsgrundlagen-Kacheln (/service/kleingartenrecht)

   Die Kachel aus Abschnitt 12, aber mit Download statt Pfeil-Verweis: Der
   Knopf navigiert nicht, er lädt eine Datei — dieselbe Unterscheidung wie
   beim Kalender-Knopf des Zeitstrahls (ADR-0004). Deshalb hängt er unten an
   der Kachel und trägt darunter die Dateiangabe.
   ============================================================ */

/* `.kachel` ist bereits eine Spalten-Flexbox (Abschnitt 12) — hier ist nur
   zu regeln, welcher der drei Absätze den freien Raum bekommt.

   **Der Grund für diese Regeln:** Abschnitt 12 setzt `.kachel p { flex-grow: 1 }`,
   weil eine Verteilerkachel genau einen Absatz hat. Diese Kachel hat drei
   (Rang, Erklärung, Dateiangabe). Alle drei wuchsen und schaukelten sich im
   Raster gegenseitig auf — die Seite war 38 000 px hoch, statt 2 300. */
.kachel--rechtsgrundlage > .kennzeichen,
.kachel--rechtsgrundlage > .kachel__dateiangabe {
  flex-grow: 0;
}

/* Breitere Spalten als beim Verteiler-Raster (16 rem). „Bundeskleingartengesetz"
   und „Rahmenkleingartenordnung" sind 23 bzw. 25 Zeichen ohne Trennstelle; in
   einer 16-rem-Spalte ragten sie über die Kachel hinaus und wurden von deren
   `overflow: hidden` mitten im Wort abgeschnitten. */
.kachel-raster--breit {
  grid-template-columns: repeat(auto-fit, minmax(19rem, 1fr));
}

/* Zusätzlich zur breiteren Spalte: Wo auch das nicht reicht (schmale Anzeigen),
   soll das Wort umbrechen statt abgeschnitten zu werden. `hyphens` setzt den
   Trennstrich, wo die Silbentrennung ihn erlaubt — dafür trägt `<html>` das
   `lang="de"`. */
.kachel--rechtsgrundlage h3 {
  overflow-wrap: break-word;
  hyphens: auto;
}

.kachel--rechtsgrundlage .kachel__link {
  align-self: flex-start;
  margin-top: var(--kvnk-space-2);
}

.kachel__dateiangabe {
  margin-top: 0;
  font-size: var(--kvnk-font-size-sm);
  color: var(--kvnk-text-subtle);
}

/* Die Rangzeile steht über dem Titel, nicht darunter: Sie beantwortet die
   Frage „gilt das für mich?" und wird vor dem Namen des Gesetzes gelesen.

   `align-self` ist hier nicht Kosmetik: Als Block in einer Spalten-Flexbox
   dehnt sich das `<p>` auf die volle Kachelbreite, und die Marke sah aus wie
   ein grauer Balken quer über der Kachel statt wie eine Marke. */
.kachel--rechtsgrundlage > .kennzeichen {
  align-self: flex-start;
  margin-bottom: 0;
}

.abschnitt__nachsatz {
  margin-top: var(--kvnk-space-8);
  color: var(--kvnk-text-muted);
  font-size: var(--kvnk-font-size-sm);
}

.zwergecke {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  gap: var(--kvnk-space-6);
}

/* ============================================================
   28b. Gartenzwerg als einzelne Figur

   Bis E8-13 gab es Zwerge nur eingebaut in den Kopfbild-Szenen. Als eigene
   Figur (Makro `zwerg()` in macros/gartenzwerg.html.twig) lässt sie sich
   über die Seite verteilen — an Abschnittsköpfen, in Leerzuständen, neben
   einem Hinweis.

   Die Grundgröße ist bewusst klein: Ein Zwerg ist eine Zierde am Rand des
   Blicks, kein Bildmotiv. Wo er groß werden soll, gibt es `--gross`.
   ============================================================ */

.gartenzwerg {
  display: block;
  width: auto;
  height: 5rem;
  flex-shrink: 0;
}

.gartenzwerg--klein { height: 3rem; }
.gartenzwerg--gross { height: 9rem; }

/* Am Abschnittskopf: steht neben der Überschrift, ohne die Zeile zu dehnen. */
.gartenzwerg--beistehend {
  align-self: flex-end;
  margin-inline-start: var(--kvnk-space-6);
}

/* Zwei Figuren nebeneinander wirken schnell wie eine Reihe. Die zweite
   steht deshalb etwas tiefer und leicht gedreht — beides so gering, dass es
   nicht als Effekt auffällt, aber die Symmetrie bricht. */
.gartenzwerg--versetzt {
  transform: translateY(0.5rem) rotate(-4deg);
}

/* Im Dunkelmodus stehen die Figuren auf dunklem Grund; der eingebaute
   Schatten unter den Füßen liegt dann auf Dunkel und wirkt als Loch. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .gartenzwerg ellipse[opacity=".28"] {
    opacity: 0.15;
  }
}
:root[data-theme="dark"] .gartenzwerg ellipse[opacity=".28"] {
  opacity: 0.15;
}

@media (prefers-reduced-motion: no-preference) {
  /* Winken nur bei der Gruß-Variante und nur sehr sparsam: zwei Grad,
     langsam, unendlich. Mehr wäre auf einer Vereinsseite albern. */
  .gartenzwerg--winkt {
    transform-origin: 50% 90%;
    animation: zwerg-wippen 6s ease-in-out infinite;
  }
  @keyframes zwerg-wippen {
    0%, 88%, 100% { transform: rotate(0deg); }
    92% { transform: rotate(2deg); }
    96% { transform: rotate(-2deg); }
  }
}

/* ============================================================
   29. Personen (Vorstand und Kassenprüfung)

   Vorstand und Kassenprüfung standen als Markdown-Tabellen im
   Fließtext — zwei Spalten Name/Funktion, die im Bereich des
   Lesetextes endeten und die rechte Hälfte der Seite leer ließen.
   Mit den Porträts aus dem Bestand (E8-06) werden daraus Karten.

   Zwei Formen, weil zwei Ränge: Der Vorstand steht im Raster mit
   großem Porträt, die Kassenprüfung als schmale Zeilen. Der
   Unterschied ist beabsichtigt und entspricht der Sache — die
   Kassenprüfung ist ein Kontrollamt, kein vertretungsberechtigtes.
   ============================================================ */

.personenraster {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
  gap: var(--kvnk-space-8) var(--kvnk-space-6);
  list-style: none;
  margin: 0;
  padding: 0;
}

.person {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--kvnk-space-4);
}

/* Rund und einheitlich groß: Die acht Aufnahmen des Bestandes sind
   unterschiedlich ausgeleuchtet und unterschiedlich nah — erst der
   gleiche Zuschnitt macht daraus eine Reihe. `object-fit: cover`
   ergänzt den serverseitigen Zuschnitt (`cropZoom` in der Vorlage)
   und fängt Bilder ab, die die Redaktion später nicht quadratisch
   einstellt. */
.person__portraet {
  width: 100%;
  max-width: 10.5rem;
  aspect-ratio: 1;
  height: auto;
  object-fit: cover;
  border-radius: var(--kvnk-radius-full);
  background: var(--kvnk-surface-2);
  border: 3px solid var(--kvnk-surface);
  box-shadow: var(--kvnk-shadow-md);
}

/* Ohne Foto die Initialen — eine neu gewählte Person steht damit sofort
   auf der Seite, statt auf ein Foto zu warten oder als Lücke im Raster
   zu erscheinen. */
.person__portraet--initialen {
  display: grid;
  place-items: center;
  font-family: var(--kvnk-schrift-display);
  font-size: var(--kvnk-font-size-2xl);
  color: var(--kvnk-color-primary-700);
  background: var(--kvnk-color-primary-50);
  border-color: var(--kvnk-color-primary-100);
  box-shadow: none;
}

.person__angaben {
  display: flex;
  flex-direction: column;
  gap: var(--kvnk-space-1);
}

.person__name {
  font-size: var(--kvnk-font-size-lg);
  line-height: var(--kvnk-line-height-tight);
}

.person__funktion {
  color: var(--kvnk-text-muted);
  font-size: var(--kvnk-font-size-sm);
  text-wrap: balance;
}

/* ---- Kassenprüfung: Zeilenform ---- */

/* `auto-fit` statt `auto-fill` wie oben: Bei drei Prüferinnen und Platz für
   vier Spalten ließe `auto-fill` die vierte leer stehen — die Zeile bräche
   rechts ab. `auto-fit` verteilt die drei Karten auf die volle Breite. Beim
   großen Raster spielt der Unterschied keine Rolle, dort füllen fünf
   Vorstandsmitglieder die Zeile ohnehin. */
.personenraster--kompakt {
  grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
  gap: var(--kvnk-space-6);
}

.person--kompakt {
  flex-direction: row;
  align-items: center;
  text-align: left;
  gap: var(--kvnk-space-4);
  padding: var(--kvnk-space-4) var(--kvnk-space-5);
  background: var(--kvnk-surface);
  border: 1px solid var(--kvnk-border);
  border-radius: var(--kvnk-radius-lg);
}

.person--kompakt .person__portraet {
  width: 3.75rem;
  max-width: none;
  flex-shrink: 0;
  border-width: 2px;
  box-shadow: var(--kvnk-shadow-sm);
}

.person--kompakt .person__portraet--initialen {
  font-size: var(--kvnk-font-size-base);
  box-shadow: none;
}

.person--kompakt .person__name {
  font-size: var(--kvnk-font-size-base);
}

/* Abstand zwischen Vorstand und Kassenprüfung im selben Abschnitt —
   zwei Ämter, ein Bereich. Die Linie trennt sie, ohne dass die
   Kassenprüfung einen eigenen Abschnitt mit eigener Hintergrundfarbe
   bräuchte. */
.personengruppe {
  margin-top: var(--kvnk-space-16);
  padding-top: var(--kvnk-space-12);
  border-top: 1px solid var(--kvnk-border);
}

.personengruppe__titel {
  font-size: var(--kvnk-font-size-2xl);
  margin-bottom: var(--kvnk-space-8);
}

/* ---- Geschäftsstelle auf der Verbandsseite ---- */

.geschaeftsstelle__aktionen {
  margin-top: var(--kvnk-space-8);
}

.infokasten__hinweis {
  margin-top: var(--kvnk-space-6);
  padding-top: var(--kvnk-space-6);
  border-top: 1px solid var(--kvnk-border);
  font-size: var(--kvnk-font-size-sm);
  color: var(--kvnk-text-muted);
}

/* Der Einleitungstext der Seite steht im Abschnittskopf und soll dort
   wie ein Vorspann wirken, nicht wie ein Fließtextblock: Der Abstand
   der <p> aus Abschnitt 21 würde ihn vom Titel wegdrücken. */
.abschnitt__einleitung {
  margin-top: var(--kvnk-space-4);
  color: var(--kvnk-text-muted);
}

.abschnitt__einleitung p {
  margin: 0;
}

.abschnitt__einleitung p + p {
  margin-top: var(--kvnk-space-4);
}

/* Auszug der Zeitleiste (Abschnitt 28) auf der Verbandsseite: nur
   Jahreszahlen, deshalb schmalere Spalte als auf /verband/historisches,
   wo dort Zeiträume wie „1904–1926" stehen. */
.zeitleiste--auszug {
  --zeitleiste-spalte: 7rem;
}

@media (max-width: 42rem) {
  .personenraster {
    grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
    gap: var(--kvnk-space-6) var(--kvnk-space-4);
  }
  .person__portraet {
    max-width: 7.5rem;
  }
  /* Muss mitgenannt werden, obwohl `--kompakt` weiter oben eine eigene
     Spaltenangabe hat: gleiche Spezifität, und die Regel hier steht später —
     die Zeilenkarten hätten sonst die 9-rem-Spalte des Porträtrasters
     übernommen und zu zweit nebeneinander gestanden. Bei 360 px schnitt das
     „Kassenprüferin" mitten im Wort ab. */
  .personenraster--kompakt {
    grid-template-columns: minmax(0, 1fr);
  }
}
