/* ============================================================
   40 · COMPONENTS — in sich geschlossene Bausteine
   ------------------------------------------------------------
   Jede Komponente ist kontextfrei und funktioniert in jeder
   Sektion. Kein Selektor hier enthaelt eine Sektionsklasse
   (CLAUDE.md). Varianten laufen ueber Modifier.

   Diese Bausteine stammen aus der Projektseite der Vorlage, wo
   sie unter dem seitenspezifischen Praefix .pdx- standen,
   obwohl sie generisch sind.

   Breakpoints: 600 / 768 / 1024 / 1280, nur min-width.
   ============================================================ */

/* ============================================================
   SECTION — Vertikaler Rhythmus
   ============================================================ */
.section {
  padding: var(--space-3xl) 0;
}

.section--mint {
  background: var(--mint);
}

.section--cream {
  background: var(--cream);
}

/* Traegt den FAY-Schriftzug (.watermark). Der Inhalt braucht seine eigene
   Ebene, sonst laege er unter dem absolut positionierten Schriftzug --
   dieselbe Loesung wie .stats__grid in der Kennzahlen-Sektion. */
.section--watermark {
  position: relative;
  overflow: hidden;
}

.section--watermark > .container {
  position: relative;
  z-index: var(--z-content);
}

/* ============================================================
   IMGBAND — Bildstreifen mit Parallaxe
   ------------------------------------------------------------
   Teilt eine Textstrecke, ohne selbst etwas zu sagen. Das Bild ist hoeher
   als das Band und sinkt beim Herunterscrollen darin nach unten; dadurch
   bleibt es hinter der Seite zurueck.

   Das Bild behaelt seine eigene Hoehe (height:auto) und ist damit in der
   Regel weit hoeher als das Band -- bei 1440 px Fenster sind es 961 statt
   400. Genau dieser Ueberschuss ist der Weg: Das Band faehrt einmal von
   unten nach oben durch die ganze Datei. main.js misst ihn aus Bild- und
   Bandhoehe ab, statt eine Zahl zu kennen.

   --imgband-min ist nur die Untergrenze fuer den Fall, dass die Datei fuer
   ihre Breite zu flach ist: Auf einem 375 px breiten Fenster waere das
   Startbild 250 px hoch und damit niedriger als das Band. Dann greifen
   min-height und object-fit, und es bleibt wenigstens dieser Weg.

   Die Zahlen stehen hier und nicht in theme.json: Sie sind Geometrie dieser
   einen Komponente. Gleiches Muster wie --logo-row.
   ============================================================ */
.imgband {
  --imgband-h: 260px;
  --imgband-min: 120px;

  position: relative;
  overflow: hidden;
  height: var(--imgband-h);
}

.imgband__img {
  position: absolute;
  left: 0;
  right: 0;
  /* Mittig verankert: Ohne Skript und bei prefers-reduced-motion zeigt das
     Band damit die Mitte der Datei und sieht aus wie ein gewoehnlicher
     Streifen. */
  top: 50%;
  width: 100%;
  height: auto;
  min-height: calc(100% + 2 * var(--imgband-min));
  object-fit: cover;
  /* --imgband-y setzt parallaxBand() aus der Scrollposition -- ein
     berechneter Wert, der sich nicht als Klasse abbilden laesst. */
  transform: translate3d(0, calc(-50% + var(--imgband-y, 0px)), 0);
}

@media (min-width: 768px) {
  .imgband {
    --imgband-h: 400px;
    --imgband-min: 200px;
  }
}

/* ============================================================
   BREADCRUMB
   ============================================================ */
.breadcrumb {
  margin-bottom: 26px;
  color: var(--ink-60);
  font-size: var(--fs-200);
  font-weight: 800;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.breadcrumb a {
  transition: color var(--dur-fast);
}

.breadcrumb a:hover {
  color: var(--green-deep);
}

/* Auf dunklem Grund, etwa im Seitenkopf ueber dem Bild. */
.breadcrumb--light {
  color: var(--on-dark-80);
}

.breadcrumb--light a:hover {
  color: var(--amber-soft);
}

/* ============================================================
   FACTGRID — Schluessel/Wert-Raster
   ============================================================ */
/* Die Trennlinien gehoeren zu den Feldern, nicht zum Raster: Eine leere
   Rasterzelle wuerde sonst den Rasterhintergrund als Block zeigen. Die Fuge
   laeuft in der Seitenfarbe, nicht als graue Linie.

   Zwei Spalten schon auf dem Telefon (Zuruf 2026-08-27, KI-055): Ein Fakt
   traegt zwei kurze Zeilen, untereinander ergaben acht davon eine lange
   Fahrt.

   Ab 1024px fuenf Spalten (KI-060): Die Regelbestueckung sind zehn Angaben,
   und zehn gehen sowohl durch zwei als auch durch fuenf auf -- beide Raster
   schliessen damit ohne Fueller ab. */
.factgrid {
  display: grid;
  grid-template-columns: 1fr 1fr;
}

/* Die seitliche Polsterung waechst langsamer als die senkrechte: Bei genau
   1024px ist eine von fuenf Spalten 204,8px breit, davon bleiben mit 22px je
   Seite 160,8px fuer den Text. Mit den urspruenglichen 2,4vw waeren es 155,6px
   -- zu wenig fuer „Landesärztekammer". Unterhalb von 917px greift ohnehin
   der Mindestwert; das freigegebene Bild auf Telefon und Tablet aendert sich
   durch die flachere Steigung nicht. */
.factgrid__item {
  padding: clamp(26px, 3vw, 40px) clamp(22px, 1.8vw, 36px);
  border: 1px solid var(--paper);
  background: var(--cream);
}

/* Schliesst die letzte Reihe, wenn die Zahl der Fakten nicht aufgeht.
   Wie viele Kaesten das Template ausgibt: template-parts/project/facts.php.
   Bei zehn Fakten entsteht kein einziger -- gebraucht werden sie nur, wenn
   ein Projekt von der Regelbestueckung abweicht. Was das zweispaltige Raster
   nicht braucht, erscheint erst mit der dritten bis fuenften Spalte.

   `--empty` traegt bewusst keine Regel: Ein leerer Kasten sieht aus wie ein
   voller ohne Inhalt, das leistet `.factgrid__item` schon. Die Klasse steht im
   Markup als Gegenstueck zu `--wide-only` und macht im Quelltext lesbar, warum
   dort ein Kasten ohne Text steht. */
.factgrid__item--wide-only {
  display: none;
}

.factgrid__key {
  display: flex;
  align-items: center;
  gap: 10px;
  /* Abstand zum gruenen Wert: 18px statt 12px (Zuruf 2026-09-18). Der
     Feldname steht in Versalien mit weiter Laufweite und liest sich als
     eigene Zeile -- bei 12px klebte der Wert daran. */
  margin-bottom: 18px;
  color: var(--ink-60);
  font-size: var(--fs-100);
  font-weight: 800;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.factgrid__key::before {
  content: "";
  flex: none;
  width: 22px;
  height: 2px;
  background: var(--amber);
}

.factgrid__value {
  color: var(--green);
  font-size: var(--fs-fact);
  font-weight: 800;
  /* In jeder Breite: Die fuenfte Spalte ist bei 1024px kaum breiter als die
     zweite auf einem grossen Telefon, und eine Trennung nach Sprachregeln
     greift ohnehin nur, wenn ein Wort sonst ueberliefe. */
  hyphens: auto;
  letter-spacing: -0.01em;
  line-height: 1.35;
}

/* Zwei Spalten lassen auf dem Telefon rund 140px Text je Feld. Der Bestand
   geht bis „Joint-Venture-Partner" (21 Zeichen) und „Investitionsvolumen"
   (19) -- beides breiter als die Spalte. Ohne Vorkehrung stuende das Wort
   ueber den Rand der Kachel hinaus.

   Feldname und Wert werden dabei verschieden behandelt:

   Der WERT ist Fliesstext und wird nach Sprachregeln getrennt -- „Gastro-
   nomie" liest sich, wie man es aus dem Satz kennt.

   Der FELDNAME nicht. Er steht in Versalien und traegt fast immer schon
   Bindestriche; „Joint-Venture-Partner" bricht an ihnen von selbst sauber um.
   Mit hyphens: auto kam dort ein zweiter Strich hinzu -- „JOINT-VEN-TURE-
   PARTNER". Bleibt nur der harte Umbruch als Notnagel fuer das eine lange
   Wort ohne Fuge („Investitionsvolumen").

   Nur hier: Ab 600px ist die Spalte breit genug, und eine Trennung, die
   niemand braucht, soll das Schriftbild nicht unruhig machen. */
@media not all and (min-width: 600px) {
  /* Der Strich gehoert zur ersten Zeile, nicht zur Mitte des Blocks: Bei
     einem dreizeiligen Feldnamen stand er sonst neben der zweiten Zeile und
     sah aus, als markiere er sie. */
  .factgrid__key {
    align-items: flex-start;
    /* anywhere und nicht break-word: Der Feldname ist ein Flex-Element, und
       ein solches schrumpft nicht unter seine Mindestbreite. break-word laesst
       diese Mindestbreite unberuehrt -- „INVESTITIONSVOLUMEN" stand deshalb
       weiterhin ueber den Rand der Kachel hinaus, nachgemessen bei 375px.
       anywhere rechnet die Trennstellen in die Mindestbreite ein. Vorhandene
       Bindestriche bleiben die bevorzugten Umbruchstellen. */
    overflow-wrap: anywhere;
  }

  /* Hebt den Strich auf die Mitte der ersten Zeile -- in em, damit er der
     Schriftgroesse folgt statt an einem Pixelwert zu kleben. */
  .factgrid__key::before {
    margin-top: 0.62em;
  }

  /* Die Silbentrennung steht in der Grundregel und ist die schoenere
     Loesung -- aber sie zaehlt nicht in die Mindestbreite, die eine
     Rasterzelle beansprucht.
     „FAY Projektentwicklungs - GmbH" auf der englischen Motel-One-Seite zog
     deshalb bei 320px die ganze Seite auf 349px auf, mitsamt Kopfleiste.
     anywhere rechnet die Trennstellen mit ein; die Silbentrennung bleibt
     trotzdem die bevorzugte Umbruchstelle. */
  .factgrid__value {
    overflow-wrap: anywhere;
  }
}

@media (min-width: 1024px) {
  .factgrid {
    grid-template-columns: repeat(5, 1fr);
  }

  .factgrid__item--wide-only {
    display: block;
  }
}

/* ============================================================
   EDITORIAL — zweispaltiger Fliesstext mit mitlaufendem Kopf
   ============================================================ */
.editorial {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(28px, 4vw, 64px);
  align-items: start;
}

/* Variante: Kopf und Text beginnen auf einer Linie.
   ------------------------------------------------------------
   Der mitlaufende Kopf (weiter unten, ab 1024 px) braucht die Seite als
   Scrollbereich. Steht der Abschnitt auf overflow:hidden -- der Schriftzug
   im Hintergrund verlangt das --, ist der Abschnitt selbst der
   Scrollbereich: Der Kopf klebt dann nie, rutscht aber um seinen
   Stickyabstand nach unten und steht tiefer als der Text daneben (KI-048). */
.editorial--flush .editorial__head {
  position: static;
}

/* Logo unter der Ueberschrift, etwa ein Siegel oder eine Mitgliedschaft.
   Breite in Pixeln: Die Datei ist ein Bildlogo ohne eigene Groesse, und der
   Kopf ist ueber alle Breakpoints etwa gleich breit. */
.editorial__logo {
  display: block;
  width: 100%;
  max-width: 220px;
  height: auto;
  margin-top: var(--space-m);
}

.editorial__lead {
  margin-bottom: 22px;
  color: var(--ink);
  font-size: var(--fs-lead);
  /* Leichter Schnitt wie bei den uebrigen Vorspaenden, siehe KI-033. */
  font-weight: 400;
  line-height: 1.45;
  letter-spacing: -0.015em;
}

.editorial__lead strong {
  color: var(--green);
  font-weight: 800;
}

/* Steht der Fliesstext unmittelbar unter einem Sektionstitel -- etwa als
   Einleitung eines Sektionskopfes --, traegt er den Abstand selbst. Am Titel
   kann er nicht haengen: Der steht auch allein. Derselbe Abstand wie bei
   .section-lead, dem anderen Nachbarn des Titels. */
.section-title + .editorial__body {
  margin-top: var(--space-s);
}

.editorial__body p {
  margin-bottom: 16px;
  color: var(--ink-60);
  font-size: var(--fs-600);
  line-height: 1.75;
}

.editorial__body p:last-child {
  margin-bottom: 0;
}

/* Der hervorgehobene Einstiegssatz. Dunkler als der uebrige Fliesstext,
   sonst traegt das Fettgedruckte auf --ink-60 zu wenig. */
.editorial__body strong {
  color: var(--green);
  font-weight: 800;
}

/* Aufzaehlungen. 10-base.css nimmt Listen global die Punkte, weil sie dort
   als Navigation und Kachelraster auftreten -- im Fliesstext sind sie aber
   genau das, was sie behaupten zu sein, und brauchen ihre Marke zurueck. */
.editorial__body ul,
.editorial__body ol {
  margin-bottom: 16px;
  padding-left: 1.25em;
  list-style: revert;
}

.editorial__body li {
  margin-bottom: 6px;
  color: var(--ink-60);
  font-size: var(--fs-600);
  line-height: 1.75;
}

.editorial__body li::marker {
  color: var(--amber);
}

/* Links im Fliesstext tragen die Unterlinie, weil die Farbe allein sie nicht
   ausreichend von der Umgebung abhebt (WCAG 1.4.1). */
.editorial__body a {
  color: var(--green);
  font-weight: 700;
  text-decoration: underline;
  text-decoration-color: var(--amber);
  text-underline-offset: 3px;
  transition: color var(--dur-fast);
}

.editorial__body a:hover {
  color: var(--amber-deep);
}

/* Fliesstext auf dunklem Grund -- die Rechtstexte im Seitenfuss. Nur die
   Farben kehren sich um; Abstaende, Zeilenhoehe und Listenmarken bleiben.
   Als Modifier und nicht als Regel aus dem Fuss heraus: Sonst griffe eine
   Sektion in die Komponente (CSS-Architektur, CLAUDE.md). */
/* Lange Fliesstexte, die gelesen und nicht ueberflogen werden -- die
   Rechtstexte im Seitenfuss. Eine begrenzte Zeilenlaenge hilft dort mehr als
   jede Auszeichnung. Als Modifier und nicht als Regel aus dem Seitenfuss
   heraus: Sonst griffe eine Ebene von aussen in die Komponente. */
.editorial__body--narrow > * {
  max-width: 68ch;
}

.editorial__body--invers p,
.editorial__body--invers li {
  color: var(--on-dark-70);
  font-size: var(--fs-200);
}

.editorial__body--invers strong {
  color: var(--white);
}

.editorial__body--invers a {
  color: var(--white);
  text-decoration-color: var(--amber);
}

.editorial__body--invers a:hover {
  color: var(--amber);
}

.editorial__body--invers h2 {
  margin-top: var(--space-m);
  margin-bottom: 0.5em;
  color: var(--white);
  font-size: var(--fs-300);
}

.editorial__body--invers h2:first-child {
  margin-top: 0;
}

/* ---------- Versalien-Label ----------
   Dieselbe Schriftbehandlung an fuenf Stellen: Datum und Quelle im Artikelkopf,
   die Beschriftung der Blaetterleiste, die Trefferzahl des Filters, die Rolle
   im Team und das Datum der Meldungskarte. Nur die Farbe unterscheidet sie, und
   die bleibt bei jeder Regel.

   Nicht als eigene Utility-Klasse: Sie stuende dann zusaetzlich im Markup an
   fuenf Stellen, ohne dass die Redaktion je damit zu tun haette. Eine
   Selektorgruppe sagt dasselbe und laesst das Markup in Ruhe.

   Bewusst **nicht** dabei: .stats__label sieht fast gleich aus, traegt aber
   font-weight 700. Ob das Absicht oder ein Ausrutscher ist, entscheidet das
   Auge des Kunden -- angefasst wird es hier nicht. */
.editorial__meta,
.pagenav__label,
.pfilter__count,
.person__role,
.nitem__date {
  font-size: var(--fs-200);
  font-weight: 800;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

/* Datum und Quelle in der mitlaufenden Kopfspalte. */
.editorial__meta {
  margin-bottom: 14px;
  color: var(--ink-60);
}

.editorial__meta a {
  color: var(--green);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.editorial__meta a:hover {
  color: var(--amber-deep);
}

@media (min-width: 1024px) {
  .editorial {
    grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  }

  .editorial__head {
    position: sticky;
    top: calc(var(--nav-h) + 24px);
  }
}

/* ============================================================
   KEYPOINTS — Kernpunkte unter einer Ueberschrift
   ------------------------------------------------------------
   Die Kurzfassung einer Meldung, eine Aussage je Zeile. Bis zum 2026-08-21
   stand sie als Aufzaehlung am Anfang des Fliesstextes; sie steht jetzt
   direkt unter der Ueberschrift und traegt keine Marken mehr, sondern die
   Farbe (Kundenwunsch).

   --amber-deep und nicht --amber: In Fliesstextgroesse auf hellem Grund
   verlangt WCAG AA 4,5 : 1, und das erfuellt allein die dunkle Stufe
   (KI-001). Listenmarken nimmt 10-base.css allen Listen ohnehin ab.
   ============================================================ */
.keypoints {
  margin-top: var(--space-m);
  color: var(--amber-deep);
  font-size: var(--fs-600);
  line-height: 1.5;
}

.keypoints li {
  display: flex;
  gap: var(--rule-gap);
}

.keypoints li + li {
  margin-top: var(--space-2xs);
}

/* Derselbe Strich wie am Eyebrow -- seine Masse stehen deshalb in den Token
   und nicht hier (Kundenwunsch 2026-08-21).

   align-items:center scheidet aus: Ein Punkt, der ueber zwei Zeilen laeuft,
   haette den Strich in der Mitte des Blocks statt an seiner ersten Zeile.
   Der Rand rechnet ihn stattdessen auf die optische Mitte der ersten Zeile --
   halbe Zeilenhoehe, abzueglich der halben Strichstaerke. */
.keypoints li::before {
  content: "";
  flex: none;
  width: var(--rule-w);
  height: var(--rule-h);
  margin-top: calc(0.75em - var(--rule-h) / 2);
  background: var(--amber);
}

/* ============================================================
   GALLERY — vollbreite Slideshow mit Scroll-Snap
   ============================================================ */
.gallery {
  position: relative;
  margin-inline: calc(50% - 50vw);
  width: 100vw;
  overflow: hidden;
  background: var(--paper);
}

.gallery__track {
  position: relative;
  display: flex;
  gap: clamp(10px, 1.4vw, 20px);
  padding: clamp(24px, 3vw, 44px) 5%;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}

.gallery__track::-webkit-scrollbar {
  display: none;
}

.gallery__slide {
  position: relative; /* Anker fuer .aicredit */
  flex: 0 0 90%;
  margin: 0;
  scroll-snap-align: center;
}

.gallery__slide img,
.gallery__video {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  object-fit: cover;
}

/* Das Video wird nicht beschnitten: Die Filme liegen teils in 4:3 vor, cover
   naehme ihnen links und rechts ein Viertel. Der freie Rand bleibt dunkel --
   Bild und Standbild fuellen die Folie damit gleich hoch wie die Bilder. */
.gallery__video {
  object-fit: contain;
  background: var(--ink);
}

.gallery__arrow {
  position: absolute;
  top: 50%;
  z-index: var(--z-overlay);
  display: flex;
  align-items: center;
  justify-content: center;
  width: clamp(48px, 4vw, 60px);
  height: clamp(48px, 4vw, 60px);
  border: 1px solid var(--line);
  border-radius: 50%;
  background: var(--surface-raised);
  color: var(--green);
  box-shadow: var(--shadow-float);
  transform: translateY(-50%);
  transition:
    background var(--dur-fast) var(--ease),
    color var(--dur-fast),
    opacity var(--dur-fast);
}

.gallery__arrow svg {
  width: 42%;
  height: 42%;
}

.gallery__arrow:hover {
  background: var(--amber-strong);
  color: var(--white);
}

.gallery__arrow--prev {
  left: clamp(16px, 3vw, 40px);
}

.gallery__arrow--next {
  right: clamp(16px, 3vw, 40px);
}

.gallery__arrow[disabled] {
  opacity: 0.32;
  cursor: default;
}

.gallery__arrow[disabled]:hover {
  background: var(--surface-raised);
  color: var(--green);
}

.gallery__dots {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 20px;
  z-index: var(--z-overlay);
  display: flex;
  justify-content: center;
  gap: 10px;
}

.gallery__dot {
  width: 30px;
  height: 3px;
  padding: 0;
  background: var(--line-strong);
  transition: background var(--dur-fast);
}

.gallery__dot:hover {
  background: var(--line-strongest);
}

.gallery__dot.is-active {
  background: var(--amber);
}

/* Weniger als zwei Bilder: keine Bedienelemente. */
.gallery--single .gallery__arrow,
.gallery--single .gallery__dots {
  display: none;
}

@media (min-width: 768px) {
  .gallery__track {
    padding-inline: 9%;
  }

  .gallery__slide {
    flex: 0 0 82%;
  }
}

@media (prefers-reduced-motion: reduce) {
  .gallery__track {
    scroll-behavior: auto;
  }
}

/* ============================================================
   CERTLIST — Zertifikate als Logo mit Bezeichnung darunter
   ------------------------------------------------------------
   Steht in der Faktenkachel „Zertifizierung" und erbt von
   .factgrid__value Farbe und Schnitt. Loest die fruehere
   Zertifikatssektion ab, die dieselben Logos ein zweites Mal
   zeigte (KI-061).
   ============================================================ */
.certlist {
  /* Das Mass steht wie bei .logogrid als lokale Eigenschaft, weil Logogroesse
     und Spaltenbreite zusammengehoeren und sonst an zwei Stellen gepflegt
     werden muessten. */
  --cert-logo: 56px;
  /* auto-fit statt einer festen Spaltenzahl: In der Faktenkachel bleiben bei
     1024px rund 161px, das ergibt zwei Spalten; auf breiten Fenstern drei.
     Ein einzelnes Zertifikat -- der Regelfall -- fuellt die Zeile allein,
     weil auto-fit leere Spuren einzieht. Ohne das Raster stand MITZSCH mit
     seinen vier Angaben untereinander und zog die Rasterreihe in die Hoehe. */
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(var(--cert-logo), 1fr));
  gap: var(--space-xs);
}

.certlist__item {
  display: flex;
  flex-direction: column;
  /* Die Bezeichnung beginnt an der linken Kante des Logos, auch wenn sie
     breiter ist als dieses. */
  align-items: flex-start;
  /* Die Bezeichnungen stehen auf einer Linie, auch wenn ein Zertifikat kein
     Logo hat -- KfW 55 und EU Taxonomie konform fuehren keines. */
  justify-content: flex-end;
  gap: var(--space-2xs);
  min-width: 0;
}

.certlist__logo {
  width: var(--cert-logo);
  height: var(--cert-logo);
  object-fit: contain;
}

/* Kleiner als der uebrige Faktenwert: Bei vier Zertifikaten -- MITZSCH fuehrt
   so viele -- stehen sonst nicht zwei Bezeichnungen nebeneinander. */
.certlist__name {
  font-size: var(--fs-200);
  /* Nimmt die Silbentrennung aus .factgrid__value zurueck: Das hier sind
     Eigennamen, und „WiredS-core Silver" liest sich wie ein Tippfehler. */
  hyphens: none;
  line-height: 1.3;
}

/* ============================================================
   PAGI — Blaetterfunktion
   ------------------------------------------------------------
   Das innere Markup erzeugt paginate_links(). .page-numbers,
   .current und .dots sind Klassennamen des WordPress-Kerns und
   nicht umbenennbar -- der zweistufige Selektor ist deshalb
   technisch bedingt und keine unnoetige Spezifitaet.
   ============================================================ */
.pagi {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-2xs);
  margin-top: var(--space-2xl);
  padding-top: var(--space-l);
  border-top: 1px solid var(--line);
}

/* min-height/min-width 44px: Mindestgroesse einer Schaltflaeche nach
   WCAG 2.5.8. Die Ziffer allein waere rund 20 px hoch. */
.pagi .page-numbers {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  min-width: 44px;
  min-height: 44px;
  padding: 0 14px;
  color: var(--ink-60);
  font-size: var(--fs-300);
  font-weight: 800;
  letter-spacing: 0.1em;
  transition:
    color var(--dur-fast),
    background var(--dur-fast);
}

.pagi a.page-numbers:hover {
  color: var(--amber-deep);
  background: var(--white);
}

.pagi .current {
  color: var(--green);
  background: var(--white);
}

/* Die Auslassung ist kein Ziel und braucht deshalb auch keine Trefferflaeche. */
.pagi .dots {
  min-width: auto;
  padding: 0 4px;
}

/* ============================================================
   PAGENAV — Vorheriges / Naechstes
   ============================================================ */
.pagenav {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1px;
  border-top: 1px solid var(--line);
  background: var(--line);
}

.pagenav__item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding: clamp(28px, 4vw, 52px) var(--gutter-wide);
  background: var(--paper);
  transition: background 0.35s var(--ease);
}

.pagenav__item:hover {
  background: var(--white);
}

.pagenav__item--prev {
  justify-content: flex-start;
  gap: clamp(20px, 3vw, 40px);
}

.pagenav__item--prev .pagenav__arrow {
  order: -1;
}

.pagenav__label {
  display: block;
  margin-bottom: 10px;
  color: var(--ink-60);
}

.pagenav__name {
  display: block;
  color: var(--green);
  font-size: var(--fs-pagenav);
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.1;
}

.pagenav__arrow {
  flex: none;
  color: var(--green);
  transition:
    transform var(--dur-fast) var(--ease),
    color var(--dur-fast);
}

.pagenav__arrow svg {
  display: block;
  width: 26px;
  height: 26px;
}

.pagenav__item--prev:hover .pagenav__arrow {
  transform: translateX(-6px);
  color: var(--amber);
}

.pagenav__item--next:hover .pagenav__arrow {
  transform: translateX(6px);
  color: var(--amber);
}

@media (min-width: 600px) {
  .pagenav {
    grid-template-columns: 1fr 1fr;
  }
}

/* ============================================================
   SCOL — Leistungskachel
   ============================================================ */
.scol {
  position: relative;
  display: grid;
  justify-items: center;
  align-content: start;
  gap: 16px;
  padding: clamp(28px, 3vw, 44px) clamp(20px, 3vw, 48px) clamp(24px, 2.6vw, 38px);
  /* Eigene Flaeche statt durchscheinendem Seitengrund: Im Raster der
     Leistungen ist die Fuge zwischen den Kacheln die Trennlinie, und die
     deckt nur ab, wer selbst einen Grund hat. Auf der Seite sieht man davon
     nichts -- es ist dieselbe Farbe --, bis die Kachel beim Zeigen auf Weiss
     wechselt. */
  background: var(--paper);
  text-align: center;
  transition:
    background var(--dur-base) var(--ease),
    box-shadow var(--dur-base) var(--ease);
}

.scol::after {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  right: 0;
  height: 3px;
  background: var(--amber);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.5s var(--ease);
}

.scol:hover {
  z-index: 1;
  background: var(--white);
  box-shadow: var(--shadow-card);
}

.scol:hover::after {
  transform: scaleX(1);
}

.scol__icon {
  width: clamp(56px, 5vw, 76px);
  height: auto;
  margin-bottom: 6px;
  /* Das Symbol ist eine Vektorgrafik mit currentColor. */
  color: var(--amber);
  transition: transform var(--dur-base) var(--ease);
}

.scol:hover .scol__icon {
  transform: translateY(-5px) scale(1.05);
}

.scol__name {
  color: var(--ink);
  font-size: var(--fs-h3-service);
  font-weight: 800;
  /* Notnagel, kein Regelfall: Die Groesse ist so gewaehlt, dass auch die
     laengste Ueberschrift einzeilig bleibt (siehe theme.json). Traegt eine
     kuenftige Leistung einen laengeren Namen, bricht er nach Sprachregeln um
     statt ueber die Kachel hinauszustehen. */
  hyphens: auto;
  letter-spacing: -0.015em;
  line-height: 1.2;
  transition: color var(--dur-fast);
}

.scol:hover .scol__name {
  color: var(--green);
}

.scol__text {
  max-width: 36ch;
  color: var(--ink-60);
  font-size: var(--fs-400);
}

@media (prefers-reduced-motion: reduce) {
  .scol,
  .scol::after,
  .scol__icon {
    transition: none;
  }
}

/* ============================================================
   PCARD — Projektkachel
   ============================================================ */
.pcard {
  /* Dunkle Flaeche: heller Fokusring (Rueckfall in 10-base.css). */
  --focus-ring: var(--amber-soft);
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  overflow: hidden;
  min-height: 320px;
  background: var(--green-deep);
  color: var(--white);
}

.pcard img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 1.1s var(--ease);
}

.pcard:hover img {
  transform: scale(1.05);
}

.pcard__scrim {
  position: absolute;
  inset: 0;
  background: var(--scrim-card);
}

.pcard__meta {
  position: relative;
  z-index: var(--z-content);
  padding: var(--space-m);
}

.pcard__name {
  font-size: var(--fs-h3);
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.12;
}

.pcard__loc {
  margin-top: 6px;
  font-size: var(--fs-300);
  font-weight: 500;
  opacity: 0.85;
}

/* ---------- Variante: Text neben oder unter dem Bild ---------- */
/* Im Archiv stehen die Kacheln gleich gross nebeneinander und tragen neben
   dem Namen eine Kopfzeile und die Adresse. Ueber dem Bild waere das zu viel
   Text -- er steht deshalb darunter auf hellem Grund, wie im freigegebenen
   Entwurf.

   Auf dem Telefon steht der Text stattdessen neben dem Bild. Untereinander
   braucht eine Kachel dort ueber 340px Hoehe und fuellt den Bildschirm allein
   aus; als Zeile kommt sie mit rund einem Drittel davon aus, und die Uebersicht
   zeigt wieder mehrere Projekte auf einmal. Ab 600px stehen zwei Kacheln
   nebeneinander -- dann ist eine Spalte zu schmal fuer Bild und Text
   nebeneinander, und der Text wandert zurueck unter das Bild. */
.pcard--stacked {
  flex-direction: row;
  justify-content: flex-start;
  min-height: 0;
  background: var(--white);
  color: var(--ink);
  /* Die Trennlinie gehoert zur Kachel, nicht zum Raster: Zwei benachbarte
     Rahmen ergeben denselben Strich wie zuvor die Rasterfuge, und eine
     unvollstaendige Reihe hinterlaesst keine graue Flaeche. */
  border: 1px solid var(--line);
  transition: background var(--dur-fast) var(--ease);
  /* Heller Grund: hier gilt wieder der dunkle Fokusring (ADR-011). */
  --focus-ring: var(--amber);
}

/* Bei Mauskontakt nimmt die Kachel denselben Cremeton an wie der Abschnitt
   „Das Unternehmen" auf der Startseite -- die Kachel hat sonst keine eigene
   Reaktion auf hellem Grund ausser dem Bildzoom. Alle drei Textfarben stehen
   darauf ueber 5 : 1 (gruen 8,4, Text 13,5, Text sekundaer 5,2). */
.pcard--stacked:hover {
  background: var(--cream);
}

/* Bild und Video sind weiterhin absolut positioniert -- nur ist ihr Rahmen
   jetzt dieser Kasten und nicht mehr die ganze Kachel. In der Zeile nimmt er
   ein gutes Drittel der Breite und wird vom Text auf Zeilenhoehe gezogen: Ein
   festes Seitenverhaeltnis liesse unter dem Bild sonst eine weisse Flaeche
   stehen, sobald der Text mehr Platz braucht als das Bild hoch ist. */
.pcard--stacked .pcard__media {
  position: relative;
  flex: 0 0 38%;
  overflow: hidden;
  background: var(--green-deep);
}

.pcard__body {
  display: flex;
  flex: 1;
  flex-direction: column;
  /* In der Zeile ist der Textblock das nachgiebige Element: Ohne diese Angabe
     unterschreitet ein Flex-Element seine Inhaltsbreite nicht und schoebe das
     Bild zusammen, statt selbst umzubrechen. */
  min-width: 0;
  padding: var(--space-s);
  /* Oben knapper als an den uebrigen Seiten: Die Kopfzeile ist Versalschrift
     ohne Unterlaengen, ihre Zeilenbox reicht deutlich ueber die Versalhoehe
     hinaus. Gleicher Zahlenwert saehe darum oben nach mehr Luft aus. */
  padding-top: var(--space-xs);
}

/* Versalschrift mit weiter Laufweite traegt optisch mehr als ihre Punktzahl
   verspricht -- eine Stufe unter der uebrigen Kleinschrift.

   In der Zeile stehen Nutzungsart und Status untereinander: Die Textspalte ist
   dort nur gut halb so breit wie die Kachel, nebeneinander blieben beiden nur
   wenige Zeichen. */
.pcard__tag {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-2xs);
  margin-bottom: 10px;
  color: var(--green);
  font-size: var(--fs-50);
  font-weight: 800;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

/* In gedecktem Ton, weil der Status die Nutzungsart einordnet und ihr nicht
   gleichrangig ist. */
.pcard__status {
  flex-shrink: 0;
  color: var(--ink-60);
}

/* Kleiner als im Mosaik: Dort traegt der Name die Kachel allein, hier steht
   darunter noch die Adresse. Feste Groesse statt clamp, weil die Kachelbreite
   ueber alle Breakpoints kaum schwankt. */
.pcard--stacked .pcard__name {
  font-size: var(--fs-600);
  transition: color var(--dur-fast);
}

.pcard--stacked:hover .pcard__name {
  color: var(--green);
}

/* Auf hellem Grund traegt die Adresse ihre eigene Farbe -- die Abschwaechung
   der Vorgabe gilt fuer Text ueber dem Bild. */
.pcard--stacked .pcard__loc {
  color: var(--ink-60);
  opacity: 1;
}

/* Ab zwei Rasterspalten: Text unter dem Bild, Kopfzeile wieder auf einer
   Zeile. Der Status weicht dabei nicht aus -- er ist kurz und steht am rechten
   Rand auf der Flucht der Kachel. Bei drei Nutzungsarten in einer schmalen
   Kachel bricht deshalb die linke Seite um, nicht er. */
@media (min-width: 600px) {
  .pcard--stacked {
    flex-direction: column;
  }

  .pcard--stacked .pcard__media {
    flex: none;
    aspect-ratio: var(--ar-media);
  }

  .pcard__tag {
    flex-direction: row;
    align-items: baseline;
    justify-content: space-between;
  }

  .pcard__status {
    text-align: right;
  }
}

/* Abschlusskachel, die auf das Archiv verweist. */
.pcard--link {
  align-items: center;
  justify-content: center;
  min-height: 220px;
  background: var(--mint);
  color: var(--green);
  text-align: center;
  transition: background 0.35s var(--ease);
}

.pcard--link:hover {
  background: var(--mint-dark);
}

/* ============================================================
   PFILTER — Auswahlleiste ueber einer Kachelliste
   ------------------------------------------------------------
   Ein Formular, kein reines Schaltflaechenband: ohne JavaScript
   filtert die Absende-Schaltflaeche serverseitig, mit JavaScript
   greift die Auswahl unmittelbar und .pfilter--live blendet die
   Schaltflaeche aus.
   ============================================================ */
.pfilter {
  padding: var(--space-m);
  margin-bottom: var(--space-l);
  background: var(--green-soft);
}

.pfilter__row {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-s);
}

.pfilter__group {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.pfilter__label {
  color: var(--ink-60);
  font-size: var(--fs-100);
  font-weight: 800;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.pfilter__field {
  position: relative;
  display: block;
}

/* Der Pfeil entsteht aus Rahmenkanten. Ein eingebettetes SVG muesste den
   Farbwert wiederholen, den theme.json bereits fuehrt (ADR-003) -- genau
   dieser Fehler steckt im Entwurf. */
.pfilter__field::after {
  content: "";
  position: absolute;
  top: 50%;
  right: 16px;
  width: 0;
  height: 0;
  margin-top: -3px;
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
  border-top: 6px solid var(--green);
  pointer-events: none;
}

.pfilter__select {
  appearance: none;
  -webkit-appearance: none;
  width: 100%;
  padding: 14px 40px 14px 16px;
  background: var(--white);
  border: 1px solid var(--line-strong);
  color: var(--ink);
  font-family: inherit;
  font-size: var(--fs-300);
  font-weight: 500;
  cursor: pointer;
  transition: border-color var(--dur-fast);
}

.pfilter__select:hover {
  border-color: var(--green);
}

.pfilter__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-s);
  margin-top: var(--space-s);
}

.pfilter__count {
  color: var(--ink-60);
}

.pfilter--live .pfilter__submit {
  display: none;
}

@media (min-width: 600px) {
  .pfilter__row {
    grid-template-columns: 1fr 1fr;
  }
}

@media (min-width: 1024px) {
  .pfilter__row {
    grid-template-columns: repeat(4, 1fr);
  }
}

/* ---------- Variante: am Fensterrand angedockt ----------
   Bis 768px sitzt die Auswahlleiste am unteren Fensterrand: ein Streifen mit
   Symbol, Wort und Trefferzahl, der die Felder erst auf Tippen freigibt. Sie
   laeuft damit mit, statt einmal oben zu stehen und beim Weiterscrollen fort
   zu sein -- auf dem Telefon war sie rund 400px hoch und danach unerreichbar
   (KI-053).

   Gebunden an .pfilter--live, die Klasse, die projects-filter.js erst setzt,
   wenn dort alle Guards durch sind: Ohne JavaScript gibt es nichts
   aufzuklappen, dann bleibt es bei der statischen Leiste ueber dem Raster.
   Dieselbe Bindung blendet schon die Absende-Schaltflaeche aus -- 90-nojs.css
   braucht dafuer nichts.

   `not all and (min-width: 768px)` ist die logische Verneinung genau dieser
   Bedingung und damit lueckenlos komplementaer -- die Grenzkollision, gegen
   die die max-width-Queries verboten sind, kann sie nicht erzeugen. Der Preis
   waere sonst ein spiegelbildlicher Ruecknahmeblock, in dem jede vergessene
   Gegenzeile still den Desktop-Filter braeche (ADR-039). */
@media not all and (min-width: 768px) {
  .pfilter--live {
    position: fixed;
    inset: auto 0 0 0;
    z-index: var(--z-dock);
    display: flex;
    flex-direction: column;
    /* Die Felder duerfen nie unter die Kopfleiste wachsen. Gerechnet statt
       geraten: Die Panelhoehe haengt an Sprache, Schriftgroesse und Format --
       ein fester Wert klemmte im Querformat oder liesse Leerraum stehen.
       svh und nicht dvh: der kleinere der beiden Werte, damit die Flaeche
       beim Einfahren der Adresszeile nicht ueber den Kopf laeuft. */
    max-height: calc(100svh - var(--nav-h));
    padding: 0;
    /* Bei position: fixed schoebe der Aussenabstand die Leiste vom unteren
       Rand weg -- darunter bliebe ein Spalt stehen. */
    margin-bottom: 0;
    box-shadow: var(--shadow-float);
    transition:
      transform var(--dur-base) var(--ease),
      opacity var(--dur-base) var(--ease),
      visibility 0s;
  }

  /* Ausserhalb der Projekte unsichtbar UND aus der Tabfolge genommen:
     visibility statt opacity allein, sonst blieben Schalter und Felder
     unsichtbar erreichbar. Die Verzoegerung laesst das Wegschieben erst zu
     Ende laufen -- dieselbe Technik wie .mnav in 30-layout.css. */
  .pfilter--live:not(.is-in) {
    visibility: hidden;
    opacity: 0;
    transform: translateY(100%);
    transition-delay: 0s, 0s, var(--dur-base);
  }

  /* Die Felder: eigene Bildlauflaeche, damit im Querformat der Streifen
     stehen bleibt und nur der Inhalt rollt. Der Innenabstand liegt hier und
     nicht mehr am Formular -- der Fokusring steht 5px ueber dem Feldrand
     (10-base.css) und wuerde an einer randlosen Bildlauflaeche beschnitten.
     scroll-padding haelt denselben Abstand an Ober- und Unterkante frei.

     Auf- und zugeklappt wird ueber display und nicht ueber eine Hoehe: Die
     Hoehe des Panels ist nicht vorherzusagen, ein Zahlenwert waere geraten,
     und eine Animation darueber brauchte overflow: hidden an einer Kante,
     an der die Felder buendig sitzen -- der Fokusring fiele ihr zum Opfer. */
  .pfilter--live .pfilter__row {
    display: none;
    padding: var(--space-m);
    overflow-y: auto;
    overscroll-behavior: contain;
    scroll-padding: var(--space-2xs);
    min-height: 0;
  }

  .pfilter--live.is-open .pfilter__row {
    display: grid;
  }

  .pfilter--live .pfilter__bar {
    flex: none;
    display: flex;
    align-items: stretch;
    justify-content: space-between;
    gap: var(--space-s);
    padding-inline: var(--space-m);
    /* Der Streifen haelt den Bereich der Home-Anzeige frei. Kein Token: env()
       ist eine Angabe des Geraets, kein Gestaltungswert -- im Stylesheet
       steht keine Zahl. Beim heutigen Viewport-Meta (ohne viewport-fit=cover)
       liefert es 0px und aendert nichts; es haelt die Leiste erst dann heil,
       wenn der Kopf spaeter randlos gesetzt wird. */
    padding-bottom: env(safe-area-inset-bottom);
    border-top: 1px solid var(--line-green);
  }

  /* Der Schalter gibt dem Streifen seine Hoehe und traegt damit die ganze
     Tippflaeche -- der freigehaltene Rand der Home-Anzeige bleibt aussen vor. */
  .pfilter--live .pfilter__toggle {
    padding-block: var(--space-s);
  }

  .pfilter--live .pfilter__foot {
    margin-top: 0;
  }
}

/* Ausserhalb der Query: Ohne .pfilter--live schaltet der Schalter nichts, dann
   darf er auch nicht dastehen (dieselbe Regel wie .person__toggle, ADR-025).
   Ab 768px verschwindet er ebenso -- dort steht die Leiste offen. */
.pfilter__toggle {
  display: none;
}

@media not all and (min-width: 768px) {
  .pfilter--live .pfilter__toggle {
    display: inline-flex;
  }
}

@media (prefers-reduced-motion: reduce) {
  .pfilter--live {
    transition: none;
  }
}

/* ============================================================
   PRINCIPLES — nummerierte Grundsaetze
   ============================================================ */
.principles {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-l);
}

.principles__item {
  padding-top: var(--space-s);
  border-top: 1px solid var(--line-strong);
}

.principles__num {
  color: var(--amber-deep);
  font-size: var(--fs-h2);
  font-weight: 200;
  letter-spacing: -0.01em;
  line-height: 1;
}

/* An der Stelle der Nummer -- gleiche Farbe, gleiche optische Groesse. Die
   Symbole tragen stroke="currentColor" und folgen damit der Textfarbe. */
.principles__icon {
  display: block;
  width: 40px;
  height: 40px;
  color: var(--amber-deep);
  stroke-width: 1.25;
}

.principles__title {
  margin-top: var(--space-xs);
  color: var(--ink);
  font-size: var(--fs-h3-profile);
  font-weight: 800;
  letter-spacing: -0.01em;
  line-height: 1.25;
}

.principles__text {
  max-width: 54ch;
  margin-top: 12px;
  color: var(--ink-60);
  font-size: var(--fs-400);
  line-height: 1.65;
}

@media (min-width: 768px) {
  .principles {
    grid-template-columns: 1fr 1fr;
  }

  /* Der abschliessende Grundsatz laeuft ueber beide Spalten. */
  .principles__item--wide {
    grid-column: 1 / -1;
  }
}

/* ============================================================
   TEAM / PERSON — Bild und Text im Wechsel
   ------------------------------------------------------------
   Einspaltig steht das Bild ueber dem Text. Ab 768 px teilen sie sich die
   Zeile im Verhaeltnis des Projektkopfs (5fr 7fr), und jede zweite Zeile
   spiegelt sich.

   Gespiegelt wird ueber die Rasterspalte, nicht ueber order: Das Markup
   bleibt in beiden Faellen Bild-dann-Text, ein Screenreader liest jede
   Person also gleich.

   Das Foto behaelt bewusst sein eigenes Seitenverhaeltnis -- anders als die
   Projektflaechen, die einem festen Format folgen (ADR-023). Ein Zuschnitt
   traefe hier Gesichter, und die Lieferung ist mit 600 x 480 ohnehin knapp.
   ============================================================ */
/* Zwei Personen nebeneinander (Kundenwunsch 2026-08-21). Die Bilder stehen
   auf einer Linie, darunter Name und Funktion; die Vita klappt in der
   eigenen Kachel auf. Dass die Kachel dabei waechst und die Nachbarin
   Fussraum bekommt, ist gewollt -- die Alternative waere, die Vita ueber die
   ganze Zeile zu legen, und die Zeile kennt nur das Raster, nicht das
   Markup. */
.team {
  display: grid;
  gap: var(--space-2xl);
}

.person {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}

/* Die Fotos werden nicht beschnitten -- es gilt das Seitenverhaeltnis der
   Datei, so wie es im Feld steht. Die vier gelieferten sind 600 x 480 und
   stehen damit von selbst auf einer Linie (KI-034). */
.person__media {
  width: 100%;
  margin-bottom: var(--space-s);
}

.person__media img {
  display: block;
  width: 100%;
  height: auto;
}

.person__name {
  color: var(--ink);
  font-size: var(--fs-h3-profile);
  font-weight: 800;
  letter-spacing: -0.01em;
  line-height: 1.2;
}

.person__role {
  margin-top: 4px;
  color: var(--green);
}

.person__toggle {
  margin-top: var(--space-xs);
}

/* Eingeklappt ist der Regelfall. Ohne JavaScript hebt 90-nojs.css das auf:
   Dann steht die Vita offen da und die Schaltflaeche verschwindet -- ein
   Schalter, der nichts schaltet, waere schlimmer als kein Schalter. */
.person__vita {
  display: none;
  margin-top: var(--space-s);
}

.person__vita.is-open {
  display: block;
}

@media (min-width: 600px) {
  .team {
    grid-template-columns: 1fr 1fr;
    column-gap: var(--gap-grid);
  }
}

/* ============================================================
   PAGEHEAD — heller Seitenkopf (Brotkrume, Titel, erste Ueberschrift)
   ============================================================ */
/* ============================================================
   LOGOGRID — Logowand in Gruppen (Partner, Mitgliedschaften)
   ============================================================ */
/* Gleiche Felder fuer ungleiche Logos: Jedes Logo steht in einem Feld
   gleicher Groesse und fuellt es nach eigenem Seitenverhaeltnis aus
   (object-fit: contain). Ohne das straeube sich ein breites Schriftlogo
   gegen ein quadratisches Signet.

   Die Zeilenlinien zeichnet das Raster als Hintergrund, nicht die Felder als
   Rahmen. Grund ist die letzte Zeile: Sie ist fast nie voll, und eine Linie
   am Feld endete dann mitten in der Reihe. Ueber den Hintergrund laeuft sie
   durch -- so wie in der Vorlage des Kunden.

   Moeglich ist das nur, weil die Zeilenhoehe feststeht (--logo-row): Der
   Streifenabstand des Verlaufs und die Rasterzeile muessen dieselbe Zahl
   sein. Eine nth-child-Regel waere die Alternative gewesen, haette aber an
   der Spaltenzahl geklebt und waere bei jedem Wechsel von zwei auf fuenf
   Spalten umgesprungen -- dieselbe Ueberlegung wie bei .nitem--card. */
.logogroup + .logogroup {
  margin-top: var(--space-xl);
}

.logogroup__title {
  margin-bottom: var(--space-s);
  color: var(--green);
  font-size: var(--fs-h3);
  font-weight: 800;
  letter-spacing: -0.01em;
}

/* Der Zusatz "(Auswahl)" gehoert zum Titel, sagt aber etwas ueber die Liste
   und nicht ueber die Gruppe -- er steht deshalb leichter daneben. */
.logogroup__title .logogroup__hint {
  color: var(--ink-60);
  font-weight: 400;
}

.logogroup__note {
  margin-top: var(--space-l);
  color: var(--ink-60);
  font-size: var(--fs-400);
}

.logogrid {
  --logo-row: 104px;

  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  grid-auto-rows: var(--logo-row);
  border-bottom: 1px solid var(--line);
  background-image: repeating-linear-gradient(
    to bottom,
    var(--line) 0,
    var(--line) 1px,
    transparent 1px,
    transparent var(--logo-row)
  );
}

/* Der senkrechte Innenabstand steht in Pixeln und nicht als Token: Er und die
   Bildhoehe muessen zusammen genau die Zeilenhoehe ergeben, sonst laeuft das
   Feld aus seiner Zeile und die Linien des Rasters passen nicht mehr. */
.logogrid__item {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px var(--space-xs);
}

/* Graustufen halten die fremden Markenfarben im Farbklima der Seite. Farbig
   wird ein Logo unter dem Mauszeiger. Vom 2026-08-20 bis zum 2026-08-21 wurde
   zusaetzlich farbig, was beim Scrollen durch die Fenstermitte wanderte; das
   ist auf Zuruf wieder entfallen. */
.logogrid__item img {
  /* Alle Dateien haben dasselbe Format (612 x 180, siehe tools/logos-prepare.py)
     -- deshalb genuegt hier eine einzige Regel, und alle Logos erscheinen
     gleich gross. Die Hoehe passt mit dem Innenabstand des Feldes genau in
     eine Rasterzeile.

     Ohne min-width bliebe das Logo auf seiner eigenen Breite stehen: Ein
     Flex-Kind darf von sich aus nicht unter seine Inhaltsbreite schrumpfen,
     und diese automatische Mindestbreite sticht max-width. Auf zwei Spalten
     liefen die breiten Schriftlogos damit aus ihrer Spalte heraus. */
  min-width: 0;
  max-width: 100%;
  max-height: 64px;
  width: auto;
  height: auto;
  object-fit: contain;
  filter: grayscale(1);
  opacity: 0.75;
  transition:
    filter var(--dur-base) var(--ease),
    opacity var(--dur-base) var(--ease);
}

/* In @media (hover: hover), damit die Farbe auf Tippgeraeten nicht am zuletzt
   beruehrten Logo haengenbleibt. */
@media (hover: hover) {
  .logogrid__item:hover img {
    filter: none;
    opacity: 1;
  }
}

/* ---------- Eingeklappte Gruppe (bis 768px) ----------
   Sieben Gruppen mit zusammen 76 Logos ergaben auf dem Telefon ueber 4000px
   Rasterhoehe. Jede Gruppe zeigt darum nur ihre erste Zeile und einen
   Anschnitt der zweiten; der Rest kommt auf Tippen (KI-056).

   Anderthalb Zeilen und nicht eine: Ein Verlauf braucht etwas zum
   Ausblenden. Ueber der einzigen sichtbaren Zeile laege er auf den Logos und
   truebte genau das, was man sehen soll -- so liegt er auf der angeschnittenen
   zweiten Zeile und sagt, dass es weitergeht.

   --collapsible setzt das Template (nur wo mehr als anderthalb Zeilen
   anfallen), --live das Skript. Ohne Skript bleibt die Wand offen und die
   Schaltflaeche unsichtbar -- 90-nojs.css braucht dafuer nichts. */
@media not all and (min-width: 768px) {
  .logogrid--collapsible.logogrid--live {
    position: relative;
    max-height: calc(var(--logo-row) * 1.5);
    overflow: hidden;
  }

  /* Genau der Anschnitt, keinen Millimeter mehr: eine halbe Rasterzeile, die
     an der Linie unter der ersten Zeile beginnt. Ueber eine ganze Zeile
     gezogen legte er sich auch auf die untere Haelfte der ersten und truebte
     die Logos, die man gerade sehen soll. pointer-events: none, damit er
     nichts vom Tippen abhaelt. */
  .logogrid--collapsible.logogrid--live::after {
    content: "";
    position: absolute;
    inset: auto 0 0 0;
    height: calc(var(--logo-row) / 2);
    background: linear-gradient(to bottom, transparent, var(--paper));
    pointer-events: none;
  }

  .logogrid--collapsible.logogrid--live.is-open {
    max-height: none;
  }

  .logogrid--collapsible.logogrid--live.is-open::after {
    display: none;
  }

  /* Der Schalter steht nur da, wo er auch etwas zu tun hat. */
  .logogrid--live + .logogroup__more {
    display: inline-flex;
  }
}

/* Grundzustand: kein Schalter. Ab 768px steht die Wand ohnehin offen, und
   ohne Skript ebenso. */
.logogroup__more {
  display: none;
}

@media (min-width: 600px) {
  .logogrid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (min-width: 768px) {
  .logogrid {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

@media (min-width: 1024px) {
  .logogrid {
    grid-template-columns: repeat(5, minmax(0, 1fr));
  }
}

/* ============================================================
   NITEM — Nachrichteneintrag
   ============================================================ */
/* Ohne Trennlinie: Die Grundvariante steht im Raster der Startseite und der
   Suche, wo nur der senkrechte Strich zwischen den Spalten trennt (KI-026).
   Die Kachelvariante bringt ihre eigene Oberlinie mit. */
.nitem {
  display: block;
  padding: clamp(28px, 3vw, 40px) 0;
}

/* display:block, weil <time> sonst inline bleibt -- der Abstand darunter
   griffe an einem Inline-Kasten gar nicht. */
.nitem__date {
  display: block;
  margin-bottom: 12px;
  color: var(--green);
}

.nitem__title {
  max-width: 34ch;
  color: var(--ink);
  font-size: var(--fs-h3-news);
  font-weight: 800;
  letter-spacing: -0.01em;
  line-height: 1.3;
  transition: color var(--dur-fast);
}

.nitem:hover .nitem__title {
  color: var(--green);
}

.nitem__excerpt {
  max-width: 54ch;
  margin-top: 10px;
  color: var(--ink-60);
  font-size: var(--fs-400);
  line-height: 1.65;
}

.nitem .textlink {
  margin-top: 20px;
  font-size: var(--fs-200);
}

/* ---------- Variante: Kachel ---------- */
/* Die Trennlinie sitzt oben und gehoert damit der Kachel selbst. Eine
   nth-child-Regel im Raster waere an dessen Spaltenzahl gebunden und
   spraenge bei jedem Wechsel von zwei auf drei Spalten um. */
.nitem--card {
  display: flex;
  flex-direction: column;
  border-top: 1px solid var(--line);
}

.nitem--card .nitem__body {
  display: flex;
  flex-direction: column;
  flex: 1;
}

/* Schiebt den Weiterlesen-Link an den unteren Rand, damit die Links einer
   Rasterzeile trotz unterschiedlich langer Anrisse auf einer Linie stehen. */
.nitem--card .nitem__excerpt {
  flex: 1;
}

.nitem--card .textlink {
  align-self: flex-start;
}

/* ============================================================
   CTA-BAND — Handlungsaufforderung auf gruenem Grund
   ------------------------------------------------------------
   Eigene Komponente statt Zweckentfremdung des Claim-Bands, das
   in der Vorlage dafuer zusaetzliche Ad-hoc-Klassen bekam.
   ============================================================ */
.cta-band {
  /* Dunkle Flaeche: heller Fokusring (Rueckfall in 10-base.css). */
  --focus-ring: var(--amber-soft);
  padding: var(--space-5xl) 0;
  background: var(--green);
  text-align: center;
}

.cta-band .eyebrow {
  justify-content: center;
}

.cta-band__title {
  max-width: 20ch;
  margin: 0 auto;
}

.cta-band__btn {
  margin-top: clamp(28px, 3.4vw, 40px);
}

/* ============================================================
   AICREDIT — Vermerk zur KI-Herkunft eines Videos
   ------------------------------------------------------------
   Eine Regel fuer alle Videoflaechen: Startseitenkopf, Aussagen-
   band, Projektkopf, Mosaikkachel und Galerie. Der Elternteil ist
   ueberall positioniert und beschneidend.

   Unten rechts, weil der Inhalt dieser Flaechen durchweg links
   steht -- Name und Ort der Kachel, Schaltflaeche und Beitext im
   Kopf.

   Sichtbar nur, solange das Video laeuft: main.js setzt
   .is-playing auf das Videoelement, der Vermerk steht direkt
   dahinter. Ueber einem Standbild behauptete er eine Animation,
   die es gerade nicht gibt -- und in der Kachel laeuft das Video
   erst bei Mauskontakt. Ohne JavaScript und bei reduzierter
   Bewegung laeuft kein Video und erscheint folglich auch kein
   Vermerk.

   Kein Schleier hinter der Schrift, sondern ein Schatten
   (Kundenentscheidung 2026-08-18). Auf bewegtem Bild ist der
   Untergrund nicht vorhersagbar; der Schatten haelt die Schrift
   auf mittlerem und dunklem Grund lesbar, auf sehr hellem Bild
   ist der Kontrast nicht mehr messbar garantiert (KI-035).
   ============================================================ */

.aicredit {
  position: absolute;
  right: var(--space-2xs);
  bottom: var(--space-2xs);
  z-index: var(--z-overlay);
  margin: 0;
  color: var(--white);
  font-size: var(--fs-50);
  line-height: 1.3;
  letter-spacing: 0.04em;
  text-shadow: var(--aicredit-shadow);
  opacity: 0;
  transition: opacity var(--dur-fast) var(--ease);
  pointer-events: none;
}

video.is-playing + .aicredit {
  opacity: 1;
}
