/* ==========================================================================
   STANDOUT – eigenes Stylesheet
   Version 1.0 · Stand 01.09.2026

   Regeln, die hier gelten:

   1. Alle eigenen Klassen tragen das Präfix so-.
   2. Keine Salient-eigenen Selektoren überschreiben. Nur additive Regeln.
      Grund: Theme-Update-Sicherheit.
   3. Kein !important. Das Stylesheet wird mit Priorität 9999 nach Salient
      eingebunden, bei gleicher Spezifität gewinnt es dadurch ohnehin.
   4. Klassen kommen über el_class an die WPBakery-Elemente.

   Die Datei wird vom Plugin "STANDOUT Custom CSS" verwaltet und liegt auf
   dem Server unter /wp-content/uploads/sites/2/standout/standout.css.
   ========================================================================== */


/* --------------------------------------------------------------------------
   1 · Design-Token
   Farbwerte aus dem Styleguide, Abschnitt Farbsystem.
   -------------------------------------------------------------------------- */

:root {
  /* Marke und Säulen */
  --so-brand:        #134591;  /* Brand / Accent / Säule 3  */
  --so-brand-hover:  #1D5FA8;  /* Hover, Sekundärzustände   */
  --so-brand-deep:   #0E3468;  /* CTA-Bänder, tiefe Flächen */
  --so-pillar-1:     #95BF1F;  /* Grün   */
  --so-pillar-2:     #00A09B;  /* Türkis */
  --so-pillar-3:     #134591;  /* Blau   */
  --so-pillar-4:     #FFCC07;  /* Gold   */

  /* Soft-Tints der Säulen. Laut Styleguide sind diese – nicht die
     Volltonfarben – die zulässigen Hintergründe hinter Text. */
  --so-pillar-1-soft: #F0F6E0;
  --so-pillar-2-soft: #DBF2F1;
  --so-pillar-3-soft: #DEE5F0;
  --so-pillar-4-soft: #FFF8DC;

  /* Flächen und Text */
  --so-paper:        #F5F8F3;
  --so-surface:      #FFFFFF;
  --so-mint:         #D7ECEA;  /* Partner-Mint, offizielles Asset */
  --so-mint-light:   #E7F3F1;  /* dezente Zwischenbänder */
  --so-text:         #15211D;
  --so-text-muted:   #4A574F;
  --so-text-faint:   #77837B;
  --so-line:         #DAE3D9;
  --so-shadow:       0 1px 2px rgba(20, 40, 30, .05), 0 6px 20px rgba(20, 40, 30, .06);

  /* EU-Abbinder */
  --so-eu-blue:      #003399;
  --so-eu-gold:      #FFCC00;

  /* Form */
  --so-radius:       14px;
  --so-radius-sm:    8px;
  --so-gap:          24px;

  /* Bildhöhen */
  --so-media-sm:     220px;
  --so-media-md:     280px;
  --so-media-lg:     360px;
}


/* --------------------------------------------------------------------------
   2 · Feste Bildhöhen

   Ohne sie stehen Karten mit unterschiedlich proportionierten Fotos
   treppenartig versetzt. Salient erzwingt img { width: 100% }, deshalb
   regeln wir die Höhe über den Rahmen und schneiden das Bild mit
   object-fit zu, statt am Bild selbst zu drehen.

   Verwendung: el_class="so-media so-media--md"
   -------------------------------------------------------------------------- */

.so-media {
  display: block;
  overflow: hidden;
  border-radius: var(--so-radius);
  background-color: var(--so-line);
}

.so-media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}

.so-media--sm { height: var(--so-media-sm); }
.so-media--md { height: var(--so-media-md); }
.so-media--lg { height: var(--so-media-lg); }

/* Seitenverhältnis statt fester Höhe – skaliert mit der Spaltenbreite. */
.so-media--16x9 { aspect-ratio: 16 / 9;  height: auto; }
.so-media--4x3  { aspect-ratio: 4 / 3;   height: auto; }
.so-media--1x1  { aspect-ratio: 1 / 1;   height: auto; }

/* Auf schmalen Viewports werden feste Höhen schnell zu wuchtig. */
@media (max-width: 690px) {
  .so-media--md,
  .so-media--lg { height: var(--so-media-sm); }
}


/* --------------------------------------------------------------------------
   3 · Sub-Überschriften in Säulenfarbe

   Salient kennt nur eine globale Überschriftenfarbe. Diese Klassen setzen
   sie punktuell um. Die Schrift selbst bleibt League Spartan aus den
   Theme Options – wir fassen font-family bewusst nicht an.

   Kernregel des Styleguides: Säulenfarben sind Säulen-Identität. Immer
   zusammen mit Nummer, Name oder Icon, nie als Deko.
   -------------------------------------------------------------------------- */

.so-h--green { color: var(--so-pillar-1); }
.so-h--teal  { color: var(--so-pillar-2); }
.so-h--blue  { color: var(--so-pillar-3); }
.so-h--gold  { color: var(--so-pillar-4); }
.so-h--muted { color: var(--so-text-muted); }


/* --------------------------------------------------------------------------
   4 · Eyebrow

   Kleine Vorzeile über einer Überschrift. Bisher behelfsmäßig als h5
   gelöst – ab jetzt eine eigene Klasse, damit die Überschriftenhierarchie
   im Markup wieder stimmt.
   -------------------------------------------------------------------------- */

.so-eyebrow {
  display: block;
  margin-bottom: 8px;
  /* League Spartan wie im Styleguide – und aus einem zweiten Grund: die
     Eyebrows im Seiteninhalt enthalten den Mittelpunkt ("Pillar 1 · Categories
     1–4"), der in Glacial Indifference fehlt. League Spartan hat ihn. */
  font-family: "League Spartan", "Segoe UI", -apple-system, system-ui, sans-serif;
  font-size: 13px;
  font-weight: 700;
  line-height: 1.3;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--so-text-muted);
}

.so-eyebrow--green { color: var(--so-pillar-1); }
.so-eyebrow--teal  { color: var(--so-pillar-2); }
.so-eyebrow--blue  { color: var(--so-pillar-3); }

/* Säulengold auf Weiß reicht bei 13px nicht für 4,5:1 – der Styleguide warnt
   im Barrierefreiheits-Abschnitt genau davor. Abgedunkelter Ton, dieselbe
   Begründung wie bei .so-pill--gold. */
.so-eyebrow--gold  { color: #8A6D00; }

/* Für Abschnitte mit text_color="light": Hero, Kennzahlenband und die
   Route-Karten liegen auf dunklem Bild. Dort wäre --so-text-muted unlesbar. */
.so-eyebrow--light { color: rgba(255, 255, 255, .82); }


/* --------------------------------------------------------------------------
   5 · Status-Pills

   Für Quick Check und Standards: Rand, Farbpunkt, Text. Der Punkt entsteht
   über ein Pseudoelement, es braucht also kein zusätzliches Markup.

   Verwendung: <span class="so-pill so-pill--teal">In Arbeit</span>
   -------------------------------------------------------------------------- */

.so-pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 5px 12px;
  border: 1px solid var(--so-line);
  border-radius: 999px;
  background-color: var(--so-surface);
  font-size: 13px;
  font-weight: 700;
  line-height: 1.4;
  color: var(--so-text);
  vertical-align: middle;
}

.so-pill::before {
  content: "";
  flex: 0 0 auto;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background-color: currentColor;
}

.so-pill--green   { color: var(--so-pillar-1); border-color: var(--so-pillar-1); }
.so-pill--teal    { color: var(--so-pillar-2); border-color: var(--so-pillar-2); }
.so-pill--blue    { color: var(--so-pillar-3); border-color: var(--so-pillar-3); }
.so-pill--gold    { color: #8A6D00;            border-color: var(--so-pillar-4); }
.so-pill--neutral { color: var(--so-text-muted); }

/* Gold auf Weiß erreicht als Textfarbe keinen ausreichenden Kontrast,
   deshalb oben ein abgedunkelter Ton für die Schrift. Der Punkt darf
   trotzdem im reinen Säulengold stehen. */
.so-pill--gold::before { background-color: var(--so-pillar-4); }


/* --------------------------------------------------------------------------
   6 · Karten und Radien

   Styleguide fordert 14px. Salient bietet nur Presets, deshalb hier.
   -------------------------------------------------------------------------- */

.so-card {
  border: 1px solid var(--so-line);
  border-radius: var(--so-radius);
  background-color: var(--so-surface);
  padding: var(--so-gap);
}

.so-card--flat  { border: 0; }
.so-card--mint  { background-color: var(--so-mint); border-color: transparent; }
.so-card--paper { background-color: var(--so-paper); }

.so-radius    { border-radius: var(--so-radius); }
.so-radius-sm { border-radius: var(--so-radius-sm); }
.so-radius-0  { border-radius: 0; }

/* Radius auf WPBakery-Spalten – am 01.09.2026 im gerenderten DOM gemessen,
   nicht vermutet:
   ---------------------------------------------------------------------------
   Salient rundet Spalten über einen Attributselektor:
       .wpb_column[data-border-radius="5px"] { border-radius: 5px }
   Das ist Spezifität (0,2,0). Die einfache Klasse .so-radius liegt bei (0,1,0)
   und verliert deshalb, auch wenn unser Stylesheet später geladen wird – im
   Browser gegengeprüft: mit angehängter Klasse blieben es 5px.

   Zweiter Messwert: Salient liefert Radius-Regeln ausschliesslich für 5px,
   10px und none. Ein column_border_radius="14px" im Shortcode erzeugt gar
   keine Regel und damit gar keinen Radius – schlechter als der Istzustand.
   Der Styleguide-Wert kann also nur von hier kommen.

   Deshalb mit .wpb_column qualifiziert: (0,2,0) gleichauf, und weil unser
   Stylesheet nach Salient kommt, gewinnen wir bei Gleichstand. Kein
   !important nötig.

   Das ist keine Überschreibung eines Salient-Selektors: die Regel greift
   ausschliesslich dort, wo wir so-radius per el_class selbst setzen. Ohne
   unsere Klasse ändert sich nichts. */
.wpb_column.so-radius,
.wpb_column.so-radius > .vc_column-inner,
.wpb_column.so-radius > .vc_column-inner > .column-link,
.wpb_column.so-radius > .vc_column-inner > .column-bg-overlay-wrap,
.wpb_column.so-radius > .vc_column-inner > .column-image-bg-wrap,
.wpb_column.so-radius > .vc_column-inner > .column-image-bg-wrap .column-image-bg {
  border-radius: var(--so-radius);
}

/* Hüllklasse für Salient-Karten, per el_class an die Spalte. Sie leistet zwei
   Dinge, die die Karte selbst nicht kann.

   Erstens Radius: der von fancy_box greift in dieser Salient-Version gar
   nicht. border_radius="5px" steht im Shortcode, gemessen wurden 0px – auf
   der Box und auf beiden Kindelementen.

   Zweitens gleiche Höhe: equal_height="yes" auf der Zeile macht die Spalten
   gleich hoch (gemessen 564/564/564), die Karten darin bleiben aber bei
   526/564/526 – sie treppen also weiter. Die Kette bricht am .wpb_wrapper:
   Spalte und .vc_column-inner stehen auf display:flex mit 564px, der Wrapper
   nimmt nur seine Inhaltshöhe. Er muss als Flex-Element wachsen und die Karte
   mitziehen.

   Beides ausschliesslich innerhalb unserer eigenen Klasse. Ohne sie ändert
   sich an Salient nichts. */
.so-radius-box .nectar-fancy-box,
.so-radius-box .nectar-fancy-box .box-link,
.so-radius-box .nectar-fancy-box .parallaxImg-wrap {
  border-radius: var(--so-radius);
  overflow: hidden;
}

.so-radius-box > .vc_column-inner > .wpb_wrapper {
  flex: 1 0 auto;
  display: flex;
  flex-direction: column;
}

.so-radius-box > .vc_column-inner > .wpb_wrapper > .nectar-fancy-box {
  flex: 1 0 auto;
}

/* Und noch eine Ebene tiefer. Die sichtbare Karte ist nicht .nectar-fancy-box,
   sondern der .parallaxImg-wrap darin – dort sitzen Bild und Rundung. Nach dem
   Flex-Fix waren die Boxen alle 564px hoch, die Wraps aber weiter 526/564/526:
   im Screenshot sah die mittlere Karte damit unverändert höher aus, während
   die Messung auf der Box längst Gleichstand meldete. Ohne den Blick aufs
   gerenderte Bild wäre das durchgegangen.

   Und es war eine Ebene mehr als gedacht: auch nachdem der Wrap auf 564 stand,
   blieben die Bildebenen darin bei 526 und endeten 38px über dem Kartenboden –
   die leere Fläche, die im Screenshot als "kürzere Karte" zu sehen war. Die
   Kette lautet .parallaxImg-wrap › .parallaxImg › -container › -layers ›
   -rendered-layer › .bg-img und muss vollständig mitwachsen. Ermittelt, indem
   alle Nachfahren zweier Karten paarweise verglichen wurden. */
.so-radius-box .nectar-fancy-box .parallaxImg-wrap,
.so-radius-box .nectar-fancy-box .parallaxImg,
.so-radius-box .nectar-fancy-box .parallaxImg-container,
.so-radius-box .nectar-fancy-box .parallaxImg-layers,
.so-radius-box .nectar-fancy-box .parallaxImg-rendered-layer,
.so-radius-box .nectar-fancy-box .bg-img {
  height: 100%;
  box-sizing: border-box;
}

/* Säulen-Kennzeichnung: schmaler Farbstreifen links, nie Vollton hinter Text. */
.so-card--pillar-1 { border-left: 4px solid var(--so-pillar-1); }
.so-card--pillar-2 { border-left: 4px solid var(--so-pillar-2); }
.so-card--pillar-3 { border-left: 4px solid var(--so-pillar-3); }
.so-card--pillar-4 { border-left: 4px solid var(--so-pillar-4); }

/* Zulässige Farbfläche hinter Text ist der Soft-Tint, nicht der Vollton.
   Verwendung: el_class="so-card so-tint--2" */
.so-tint--1 { background-color: var(--so-pillar-1-soft); border-color: transparent; }
.so-tint--2 { background-color: var(--so-pillar-2-soft); border-color: transparent; }
.so-tint--3 { background-color: var(--so-pillar-3-soft); border-color: transparent; }
.so-tint--4 { background-color: var(--so-pillar-4-soft); border-color: transparent; }

.so-card--mint-light { background-color: var(--so-mint-light); border-color: transparent; }
.so-shadow { box-shadow: var(--so-shadow); }


/* --------------------------------------------------------------------------
   7 · Dark Mode

   Werte 1:1 aus dem Styleguide (STANDOUT_Farbsystem_Styleguide_v2.html,
   Block :root[data-theme="dark"]). Abgeglichen, nicht mehr abgeleitet.

   Auch die Säulenfarben wechseln – die hellen Töne verlieren auf dunklem
   Grund zu viel Kontrast. Alle Klassen aus den Abschnitten 3 bis 6 ziehen
   ihre Werte aus den Token, es braucht deshalb keine zweiten Regelsätze.

   Der Styleguide kennt zusätzlich einen manuellen Umschalter über
   [data-theme]. Salient liefert so ein Attribut nicht aus, deshalb hier
   ausschließlich prefers-color-scheme. Kommt der Umschalter später, wird
   derselbe Token-Block unter :root[data-theme="dark"] gespiegelt.

   Greift nur auf eigene Klassen. Salient bringt keinen eigenen Dark Mode
   mit, den wir stören könnten.

   STAND 07.09.2026 – STILLGELEGT, MIT MESSUNG.

   Der Dunkelmodus kann so nicht funktionieren, weil die Bandfarben der
   Seiten als feste Hex-Werte im Seiteninhalt stehen (bg_color="#F5F8F3",
   "#D7ECEA", "#FFFFFF"). prefers-color-scheme erreicht sie nicht. Es kippen
   also nur die Token, nicht die Flächen – heraus kommen helle Bänder mit
   Dunkelmodus-Tinte. Auf der Standards-Seite gemessen:

     Säulenzeile 1   #A8CE3A hinter #EAF1EA   Kontrast 1,58
     Säulenzeile 2   #26BEB7 hinter #EAF1EA   Kontrast 2,00
     Säulenzeile 3   #6C9BE0 hinter #FFFFFF   Kontrast 2,84
     Säulenzeile 4   #FFD633 hinter #EAF1EA   Kontrast 1,22
     Eyebrow grün    #A8CE3A auf Weiß         Kontrast 1,82
     Eyebrow gold    #FFD633 auf Weiß         Kontrast 1,41
     .so-muted       #AEBBB2 auf Paper        Kontrast 1,86

   Verlangt sind 4,5:1. Im hellen Satz erreichen dieselben Stellen 7:1 und
   mehr, das Farbsystem selbst ist also in Ordnung.

   Damit der Dunkelmodus wirklich greifen kann, müssen zuerst die Bandfarben
   aus Token kommen statt aus Hex im Seiteninhalt – also eigene Klassen wie
   so-band--paper, so-band--mint, so-band--surface an die Spalten, und die
   Hex-Werte aus den Zeilen heraus. Das betrifft Home, Standards, Quick Check
   und Good Practices gleichermaßen und ist eine eigene Runde.
   -------------------------------------------------------------------------- */

@media (prefers-color-scheme: dark) {
  /* Bis auf Weiteres stillgelegt – siehe die Messung im Kopf dieses
     Abschnitts. Aktiviert wird der Dunkelmodus, indem body die Klasse
     so-dark-ready bekommt; bis dahin greifen die Token nicht, und alle
     Seiten bleiben in ihrem gemessen stimmigen hellen Satz. */
  body.so-dark-ready {
    --so-brand:         #6C9BE0;
    --so-brand-hover:   #8FBCF0;
    --so-brand-deep:    #B9D5F5;

    --so-pillar-1:      #A8CE3A;
    --so-pillar-2:      #26BEB7;
    --so-pillar-3:      #6C9BE0;
    --so-pillar-4:      #FFD633;

    --so-pillar-1-soft: #1E2A0F;
    --so-pillar-2-soft: #08302E;
    --so-pillar-3-soft: #10233F;
    --so-pillar-4-soft: #2E2708;

    --so-paper:         #0D1512;
    --so-surface:       #151F1A;
    --so-mint:          #122622;
    --so-mint-light:    #0F201D;
    --so-text:          #EAF1EA;
    --so-text-muted:    #AEBBB2;
    --so-text-faint:    #7E8C83;
    --so-line:          #2A382F;
    --so-shadow:        0 1px 2px rgba(0, 0, 0, .3), 0 6px 20px rgba(0, 0, 0, .4);
  }

  /* Im hellen Set brauchen Pill und Eyebrow einen abgedunkelten Goldton.
     Auf dunklem Grund trägt das aufgehellte Säulengold selbst. */
  body.so-dark-ready .so-pill--gold,
  body.so-dark-ready .so-eyebrow--gold { color: var(--so-pillar-4); }
}


/* --------------------------------------------------------------------------
   8 · Schrift Glacial Indifference

   Lizenz: SIL Open Font License 1.1 (Alfredo Marco Pradil / Hanken Design).
   Selbsthosting und kommerzielle Nutzung erlaubt, kostenlos. Der Styleguide
   behauptet an dieser Stelle, eine kostenpflichtige Lizenz sei nötig – das
   ist geprüft und falsch. Der Lizenztext liegt neben den Schriftdateien
   neben der Schriftdatei im Plugin-Ordner und muss dort bleiben.

   Vorhanden sind zwei Schnitte: 400 regular und 700 bold. Ein Italic
   existiert im gelieferten Paket nicht, deshalb ist der dritte Block unten
   auskommentiert. Kursive Auszeichnungen erzeugt der Browser bis dahin
   synthetisch.

   Kein 500 und kein 600. Solche Angaben erzeugen einen künstlich
   gefetteten Schnitt.

   Die Schriften liegen im Plugin-Ordner, nicht in den Uploads, und werden
   wurzelrelativ referenziert. Grund: der gelieferte SFTP-Zugang erreicht die
   Uploads nicht, wohl aber den Plugin-Ordner – und der wird über HTTP
   ausgeliefert. So kommen die Dateien ohne Mediathek und ohne zusätzlichen
   Plugin-Code an ihren Platz, und sie wandern bei jedem `deploy-plugin`
   automatisch mit.

   Wurzelrelativ statt absolut, weil der Shortcode-Vertrag einen Domainwechsel
   zum European Outdoor City Network in Aussicht stellt. /wp-content/… gilt
   auf dieser Subdomain unverändert weiter.

   Der Lizenztext liegt daneben im selben Ordner, wie die OFL es verlangt.

   Überschriften laufen weiter auf League Spartan SemiBold 600 aus den
   Salient Theme Options.
   -------------------------------------------------------------------------- */

@font-face {
  font-family: "Glacial Indifference";
  src: url("/wp-content/plugins/standout-custom/fonts/GlacialIndifference-Regular.woff2") format("woff2"),
       url("/wp-content/plugins/standout-custom/fonts/GlacialIndifference-Regular.woff")  format("woff");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Glacial Indifference";
  src: url("/wp-content/plugins/standout-custom/fonts/GlacialIndifference-Bold.woff2") format("woff2"),
       url("/wp-content/plugins/standout-custom/fonts/GlacialIndifference-Bold.woff")  format("woff");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

/*
@font-face {
  font-family: "Glacial Indifference";
  src: url("/wp-content/plugins/standout-custom/fonts/GlacialIndifference-Italic.woff2") format("woff2"),
       url("/wp-content/plugins/standout-custom/fonts/GlacialIndifference-Italic.woff")  format("woff");
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}
*/

/* Vier Zeichen fehlen im Zeichensatz und fallen still auf die Ersatzschrift
   zurück: U+00B7 Mittelpunkt, U+20AC Euro, U+201E deutsches
   Anführungszeichen unten, U+2192 Pfeil nach rechts. Praktisch relevant ist
   der Mittelpunkt – der Styleguide setzt ihn als Trenner ein. Im Fließtext
   stattdessen den Bullet oder den Halbgeviertstrich verwenden, beide sind
   vorhanden. */
.so-font-body {
  font-family: "Glacial Indifference", "Segoe UI", -apple-system, system-ui, sans-serif;
}


/* --------------------------------------------------------------------------
   8b · Schrift League Spartan, selbst gehostet

   Bisher lädt Salient die Schrift über die Theme Options von Google Fonts.
   Für ein EU-gefördertes Projekt ist das der bekannte DSGVO-Stolperstein:
   jeder Seitenaufruf erzeugt eine Verbindung zu fonts.gstatic.com, samt
   IP-Übertragung, ohne Einwilligung. Der Shortcode-Vertrag verbietet externe
   Schriften und CDN-Ressourcen aus genau diesem Grund.

   Lizenz: ebenfalls SIL Open Font License 1.1, Lizenztext neben der
   Schriftdatei im Plugin-Ordner.

   Eine Datei für alle Gewichte: der Variable Font deckt die Achse wght von
   100 bis 900 ab. Damit sind 400 für Fließtext, 600 SemiBold für
   Überschriften laut Styleguide und 700 Bold aus einer Quelle bedient, ohne
   künstliche Zwischenschnitte.

   Kein WOFF-Fallback, und das ist Absicht: ein Browser, der kein WOFF2
   versteht, versteht auch keine Variable Fonts. Der Fallback wäre wirkungslos.
   Die statischen TTF liegen als Quelle im Repository, falls doch einmal
   Einzelschnitte gebraucht werden.

   WICHTIG: Damit die Schrift nicht doppelt lädt, muss Phil League Spartan in
   den Salient Theme Options abschalten. Solange das nicht passiert ist, holt
   die Seite sie weiterhin zusätzlich von Google – der DSGVO-Punkt wäre dann
   nicht geschlossen, nur verdoppelt.

   Der Familienname ist bewusst identisch mit dem, den Salient in seinen
   Regeln verwendet. Sobald die Google-Einbindung aus ist, greift diese
   Deklaration ohne jede weitere Änderung.
   -------------------------------------------------------------------------- */

@font-face {
  font-family: "League Spartan";
  src: url("/wp-content/plugins/standout-custom/fonts/LeagueSpartan-Variable.woff2") format("woff2-variations"),
       url("/wp-content/plugins/standout-custom/fonts/LeagueSpartan-Variable.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

/* Nur das Pfeilzeichen fehlt im Zeichensatz (U+2192). Mittelpunkt, Euro und
   das deutsche Anführungszeichen unten sind vorhanden – anders als bei
   Glacial Indifference. Überschriften mit · sind also unproblematisch. */
.so-font-display {
  font-family: "League Spartan", "Segoe UI", -apple-system, system-ui, sans-serif;
  font-weight: 600;
}


/* --------------------------------------------------------------------------
   9 · Kleinkram
   -------------------------------------------------------------------------- */

/* Gleich hohe Karten ohne equal_height="yes" – das verträgt sich laut
   Messung nicht mit Spalten-Animationen, die Spalten bleiben dann auf
   opacity: 0 stehen. */
.so-stretch { display: flex; flex-direction: column; height: 100%; }
.so-stretch > .so-push { margin-top: auto; }

.so-center     { text-align: center; }
.so-muted      { color: var(--so-text-muted); }
.so-nowrap     { white-space: nowrap; }
.so-visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}


/* --------------------------------------------------------------------------
   10 · Reihenfolge-Korrekturen im eigenen System

   Beide Regeln unten stehen bewusst am Dateiende: sie haben dieselbe
   Spezifität wie die Regeln, die sie korrigieren, und gewinnen deshalb
   allein durch die Position. Kein !important nötig.
   -------------------------------------------------------------------------- */

/* .so-tint--N setzt border-color: transparent und schluckt damit den
   Säulenstreifen von .so-card--pillar-N, weil es später in der Datei steht.
   Am 02.09.2026 auf der Standards-Seite gemessen: die Kombination
   "so-card so-tint--2 so-card--pillar-2" ergab border-left:
   4px solid rgba(0, 0, 0, 0) – Breite und Stil da, Farbe weg.
   Der Streifen wird hier zurückgeholt; die Tint-Fläche bleibt. */
.so-card--pillar-1 { border-left-color: var(--so-pillar-1); }
.so-card--pillar-2 { border-left-color: var(--so-pillar-2); }
.so-card--pillar-3 { border-left-color: var(--so-pillar-3); }
.so-card--pillar-4 { border-left-color: var(--so-pillar-4); }


/* --------------------------------------------------------------------------
   11 · Ankerziele unter der fixierten Kopfzeile

   #header-outer ist fixiert und beim Laden 134 px hoch, der Platzhalter
   darunter 164 px. Ein Ankersprung landet ohne Korrektur unter der
   Kopfzeile. scroll-margin-top gehört hierher und nicht ins Markup:
   im Seiteninhalt filtert kses die Eigenschaft aus dem style-Attribut
   (am 02.09.2026 geprüft – von zehn Inline-Werten überlebte keiner).

   200 px = Unterkante des Platzhalters (196 px) plus etwas Luft.
   -------------------------------------------------------------------------- */

.so-anchor {
  display: block;
  height: 0;
  scroll-margin-top: 200px;
}


/* --------------------------------------------------------------------------
   12 · Standards-Seite: Kategorien-Explorer

   Alle Haken hängen an el_class-Feldern der WPBakery-Spalten
   (so-cat-group, so-pillar-N), nicht an Klassen im Fließtext. Damit
   übersteht die Seite das Bearbeiten der Texte im Editor, und die Regeln
   bleiben auf diesen Abschnitt begrenzt statt site-weit alle
   Salient-Toggles zu treffen.
   -------------------------------------------------------------------------- */

/* Salient rendert den Toggle-Titel mit 30 px gegen 18 px Fließtext –
   gemessen am 02.09.2026. Für eine Liste aus zwölf Zeilen ist das zu
   laut, und mobil bricht jede Zeile drei- bis vierfach. */
.so-cat-group .toggle h3 {
  font-size: 21px;
  line-height: 1.3;
}

.so-cat-group .toggle h3 a {
  padding-right: 2.5rem;   /* Platz für das Plus-Icon am rechten Rand */
}

/* Säulenzugehörigkeit auch im geschlossenen Zustand sichtbar. Salients
   color="Extra-Color-1" landet als Klasse am .toggle, färbt aber nur das
   Plus-Icon (gemessen: rgb(136, 136, 136), also gar nicht). Der Streifen
   steht nie allein – Nummer, Name und Säulenname stehen im Titel daneben. */
.so-cat-group .toggle {
  position: relative;
  padding-left: 16px;
}

.so-cat-group .toggle::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 3px;
  border-radius: 2px;
  background-color: var(--so-line);
}

.so-pillar-1 .toggle::before { background-color: var(--so-pillar-1); }
.so-pillar-2 .toggle::before { background-color: var(--so-pillar-2); }
.so-pillar-3 .toggle::before { background-color: var(--so-pillar-3); }
.so-pillar-4 .toggle::before { background-color: var(--so-pillar-4); }

/* Die Zwischentitel im geöffneten Zustand ("Why it matters", "What it
   covers") kamen als 18 px Bold heraus, also genauso groß wie der Text
   darunter. Hier bekommen sie den Eyebrow-Stil, ohne dass die Redaktion
   eine Klasse ins HTML schreiben muss. */
.so-cat-group .toggle h4 {
  font-family: "League Spartan", "Segoe UI", -apple-system, system-ui, sans-serif;
  font-size: 13px;
  font-weight: 700;
  line-height: 1.3;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--so-text-muted);
}

/* Indikatorlisten: Salient setzt list-style-type auf li mit höherer
   Spezifität als eine einzelne Klasse (siehe Learnings 2.2), deshalb ist
   der Selektor zweistufig. display: flex nimmt den Aufzählungspunkt
   ohnehin mit und erlaubt die hängende Einrückung hinter der Nummer. */
.so-cat-group .so-ind-list {
  margin: .4rem 0 0;
  padding: 0;
  list-style: none;
}

.so-cat-group .so-ind-list li {
  display: flex;
  gap: .7rem;
  margin: 0 0 .35rem;
  font-size: .95rem;
  line-height: 1.5;
  list-style: none;
  color: var(--so-text-muted);
}

.so-cat-group .so-ind-list li strong {
  flex: none;
  min-width: 2.8em;
  font-variant-numeric: tabular-nums;
  color: var(--so-text);
}


/* --------------------------------------------------------------------------
   13 · Kennzahlen (Salient-Modul milestone)

   Das Modul rendert die Zahl in Open Sans 62 px – eine dritte Schrift auf
   der Seite und in einer Reihe aus sechs Kästen zu groß. Nur innerhalb
   von so-stat korrigiert, damit andere Seiten unberührt bleiben.
   -------------------------------------------------------------------------- */

/* !important ist hier unvermeidbar und der zweite belegte Ausnahmefall neben
   dem Button-Radius. Salients Modul schreibt die Größe nicht per Stylesheet,
   sondern als Inline-Style an das Element selbst – am 03.09.2026 auf der
   Standards-Seite gemessen:

       element.style { font-size: 62px; line-height: 62px }

   Gegen eine Inline-Deklaration gewinnt keine Spezifität, egal wie hoch.
   Schriftschnitt, Farbe und Laufweite greifen dagegen ohne !important; nur
   die beiden inline gesetzten Eigenschaften brauchen es. */
.so-stat .nectar-milestone .number {
  font-family: "League Spartan", "Segoe UI", -apple-system, system-ui, sans-serif;
  font-size: 40px !important;
  font-weight: 600;
  line-height: 1.15 !important;
  letter-spacing: -0.02em;
  color: var(--so-brand);
}

.so-stat .nectar-milestone .subject {
  font-size: 14px;
  line-height: 1.35;
  color: var(--so-text-muted);
}

/* Offener Punkt, nicht per CSS lösbar: Salient blendet das Modul mit
   .nectar-milestone:not(.animated-in) { opacity: 0 } aus und holt es erst
   beim Hineinscrollen zurück. Wer per Deeplink unterhalb des Bandes landet
   (#principles, #resources – beides im Briefing verlangt), scrollt nie
   daran vorbei und sieht leere Kästen.

   Ein unbedingtes opacity: 1 wäre die naheliegende Abkürzung und ist am
   04.09.2026 verworfen worden: der Zähler setzt die Zahl beim Auslösen
   zuerst auf 0 und zählt dann hoch. Ist die Zahl vorher sichtbar, sieht man
   den Endwert, dann den Rücksprung. Das gehört ins Plugin-JavaScript –
   dort lässt sich animated-in genau dann sofort setzen, wenn das Band beim
   Laden schon oberhalb des Viewports liegt. */


/* --------------------------------------------------------------------------
   14 · Good-Practices-Teaser

   Das fremde Modul bringt seine vollständige Filterleiste samt Zähler mit.
   Als Drei-Karten-Teaser auf einer anderen Seite ist beides falsch: der
   Zähler meldet "12 Good Practices", während drei Karten stehen, und eine
   zweite Filterleiste konkurriert mit der Seitennavigation.

   Ausgeblendet wird nur die Bedienoberfläche des Moduls, nicht sein
   Inhalt – die Schnittstelle bleibt der dokumentierte Deeplink.
   -------------------------------------------------------------------------- */

.so-gp-compact #psc-filter-bar,
.so-gp-compact .psc-filters,
.so-gp-compact #psc-result-meta,
.so-gp-compact .psc-result-meta {
  display: none;
}


/* --------------------------------------------------------------------------
   15 · Buttons: einheitlich rund 10 % größer, und Abstand dazwischen

   Ausdrücklich site-weit gewünscht ("gibt es eine einheitliche Größe über
   alle Seiten?"), deshalb hier als einzige Regel, die Salients eigene
   Button-Klassen anfasst statt einer eigenen Hüllklasse. Der Rest des
   Stylesheets bleibt bei der Projektregel.

   Ausgangswerte am 03.09.2026 im gerenderten DOM gemessen:

     .nectar-button              13px 18px / 12px
     .nectar-button.large        15px 35px / 14px
     .nectar-button.large.see-*  13px 35px / 14px
     .nectar-button.medium       12px 18px / 12px

   Spezifitäten, ebenfalls gemessen – deshalb die unterschiedlichen
   Selektoren unten:

     Schriftgröße         .nectar-button.large              (0,2,0)
     Padding oben/unten   .nectar-button.large              (0,2,0)
     Padding links/rechts body.material .nectar-button.large (0,3,1)

   Nur die Seitenpolster hängen damit an Salients Button-Stil "material".
   Stellt Phil den in den Theme Options um, fallen genau diese beiden
   Zeilen aus und die Buttons kehren zu Salients Standardbreite zurück –
   ein weicher Rückfall, kein Bruch.
   -------------------------------------------------------------------------- */

.nectar-button {
  font-size: 13.2px;
  padding-top: 14.3px;
  padding-bottom: 14.3px;
}

.nectar-button.large {
  font-size: 15.4px;
  padding-top: 16.5px;
  padding-bottom: 16.5px;
}

.nectar-button.medium {
  font-size: 13.2px;
  padding-top: 13.2px;
  padding-bottom: 13.2px;
}

/* Die Durchsicht-Varianten ziehen 2px Polster ab, weil der Rahmen sie
   zurückgibt. Dieselbe Logik wie bei Salient, nur auf den neuen Werten. */
body .nectar-button.large.see-through,
body .nectar-button.large.see-through-2 {
  padding-top: 14.5px;
  padding-bottom: 14.5px;
}

body .nectar-button.medium.see-through,
body .nectar-button.medium.see-through-2 {
  padding-top: 11.2px;
  padding-bottom: 11.2px;
}

body.material .nectar-button.large {
  padding-left: 38.5px;
  padding-right: 38.5px;
}

body.material .nectar-button.medium {
  padding-left: 19.8px;
  padding-right: 19.8px;
}

/* Nebeneinanderstehende Buttons berührten sich – Salient setzt keinen
   horizontalen Abstand. Die Buttons sind direkte Geschwister, deshalb
   greift der Nachbarschaftsselektor und der letzte bekommt keinen
   überzähligen Rand. */
.nectar-button + .nectar-button {
  margin-left: 14px;
}

@media (max-width: 690px) {
  /* Untereinander gestapelt ist ein linker Rand falsch. */
  .nectar-button + .nectar-button {
    margin-left: 0;
  }
}


/* --------------------------------------------------------------------------
   16 · Säulenkarten (Abschnitt "The four pillars")
   -------------------------------------------------------------------------- */

/* "PILLAR 4 · CATEGORIES 9–12" brach in der schmalen Karte um. Etwas
   kleiner und enger gesperrt passt die Zeile wieder in eine Zeile, ohne
   dass die Eyebrow-Anmutung verloren geht. */
.so-pillar-card .so-eyebrow {
  font-size: 12px;
  letter-spacing: 0.06em;
}

/* Der "Explore Pillar N"-Link soll in allen vier Karten auf gleicher Höhe
   stehen, auch wenn die Beschreibungen unterschiedlich lang sind.
   equal_height="yes" macht nur die Spalte gleich hoch; die Kette bis zum
   letzten Absatz muss einzeln mitwachsen – dieselbe Erfahrung wie bei
   .so-radius-box. Gemessene Kette:
   .wpb_column › .vc_column-inner › .wpb_wrapper › .wpb_text_column
   › .wpb_wrapper › p */
.so-pillar-card > .vc_column-inner > .wpb_wrapper,
.so-pillar-card .wpb_text_column,
.so-pillar-card .wpb_text_column > .wpb_wrapper {
  display: flex;
  flex: 1 0 auto;
  flex-direction: column;
}

.so-pillar-card .wpb_text_column {
  margin-bottom: 0;
}

/* Nicht der Link-Absatz wird nach unten geschoben, sondern der Absatz
   darüber wächst. Grund, am 03.09.2026 gemessen: der Link-Absatz trägt aus
   dem Seiteninhalt ein Inline-margin: 0, und gegen eine Inline-Deklaration
   gewinnt kein Klassenselektor – margin-top: auto kam als 0px heraus, die
   vier Links standen 60px versetzt. Der Beschreibungsabsatz hat kein
   Inline-Margin, deshalb greift flex-grow dort ohne Umweg. */
.so-pillar-card .wpb_text_column > .wpb_wrapper > p:nth-last-child(2) {
  flex: 1 0 auto;
}

.so-pillar-card .wpb_text_column > .wpb_wrapper > p:last-child {
  padding-top: 0.9rem;
}

/* Zweizeilige Titelhöhe für alle vier Karten. Ohne sie ist "Outdoor Sports
   Providers" einzeilig (28px) und die anderen drei zweizeilig (56px) – am
   03.09.2026 bei 1600px gemessen. Der Link steht durch die Regel darüber
   trotzdem auf gleicher Höhe, aber Icon, Eyebrow, Titel und Beschreibung
   von Karte 4 sitzen 28px höher als in den Nachbarn, und die Karte liest
   sich dadurch verschoben. Mindesthöhe statt fester Höhe: bei schmalen
   Spalten dürfen die Titel drei Zeilen brauchen. */
.so-pillar-card h4 {
  min-height: 56px;   /* zwei Zeilen bei 18px Schrift und 28px Zeilenhöhe */
}


/* --------------------------------------------------------------------------
   17 · Farbige Säulenzeile im Kategorien-Explorer

   Dasselbe Muster wie das Ergebnisband im Quick-Check-Report: volle
   Fläche in der Säulenfarbe, Icon in einem hellen Kreis, darunter der
   weiße Kartenkörper mit den Toggles. Textfarbe nach Kontrastregel –
   auf Grün, Türkis und Gold dunkel, nur auf Blau weiß.
   -------------------------------------------------------------------------- */

.so-cat-group .so-pillar-head {
  display: flex;
  align-items: center;
  gap: 1.1rem;
  margin: 0;
  padding: 1.15rem 1.5rem;
  border-radius: var(--so-radius) var(--so-radius) 0 0;
}

.so-pillar-1 .so-pillar-head { background-color: var(--so-pillar-1); color: var(--so-text); }
.so-pillar-2 .so-pillar-head { background-color: var(--so-pillar-2); color: var(--so-text); }
.so-pillar-3 .so-pillar-head { background-color: var(--so-pillar-3); color: #FFFFFF; }
.so-pillar-4 .so-pillar-head { background-color: var(--so-pillar-4); color: var(--so-text); }

.so-cat-group .so-pillar-head__icon {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 76px;
  height: 76px;
  border-radius: 50%;
  background-color: rgba(255, 255, 255, 0.32);
}

/* Auf Blau ist der Kreis heller, sonst verschwindet er im Vollton. */
.so-pillar-3 .so-pillar-head__icon {
  background-color: rgba(255, 255, 255, 0.18);
}

.so-cat-group .so-pillar-head__icon img {
  width: 48px;
  height: 48px;
  display: block;
  /* Salient setzt .row .col img { margin-bottom: 15px }. Flexbox zentriert
     die Margin-Box, nicht die sichtbare Flaeche – das Icon sass dadurch in
     allen vier Kreisen exakt 7,5 px zu hoch (halbe 15), waagerecht dagegen
     genau. Am 06.09.2026 an allen vier Kreisen gemessen.
     Spezifitaet (0,3,1) gegen Salients (0,2,1), also kein !important. */
  margin: 0;
}

.so-cat-group .so-pillar-head__text {
  min-width: 0;
}

.so-cat-group .so-pillar-head .so-eyebrow {
  margin: 0;
  color: inherit;
  opacity: 0.82;
}

/* Element-qualifiziert, weil Salients Sammelregel "body h3, .row .col h3, ..."
   mit (0,2,1) sonst gewinnt und 30px setzt – am 03.09.2026 gemessen. */
.so-cat-group h3.so-pillar-head__name {
  margin: 0.15rem 0 0;
  font-family: "League Spartan", "Segoe UI", -apple-system, system-ui, sans-serif;
  font-size: 1.32rem;
  font-weight: 600;
  line-height: 1.2;
  color: inherit;
}

/* Der Textblock um die Farbzeile bringt Salients Grundabstand mit. Der muss
   weg, sonst klafft eine Lücke zwischen Farbzeile und erstem Toggle. */
.so-cat-group .wpb_text_column {
  margin-bottom: 0;
}

/* Die Karte trägt jetzt kein Spaltenpolster mehr, damit die Farbzeile bis
   an die Kante läuft. Die Toggles bekommen ihr Polster hier. */
.so-cat-group .toggles {
  padding: 0.4rem 1.5rem 1.1rem;
}

@media (max-width: 690px) {
  .so-cat-group .so-pillar-head {
    gap: 0.8rem;
    padding: 1rem 1.1rem;
  }

  .so-cat-group .so-pillar-head__icon {
    width: 56px;
    height: 56px;
  }

  .so-cat-group .so-pillar-head__icon img {
    width: 34px;
    height: 34px;
  }

  .so-cat-group h3.so-pillar-head__name {
    font-size: 1.1rem;
  }

  .so-cat-group .toggles {
    padding: 0.4rem 1.1rem 1rem;
  }
}


/* --------------------------------------------------------------------------
   18 · Foto-Karten (Abschnitt "Principles")

   Baut auf .so-radius-box auf, das die Höhenkette von fancy_box schon
   löst. Hier kommen nur Mindesthöhe und ein Abdunkler dazu, damit der
   Text auf jedem Foto lesbar bleibt.
   -------------------------------------------------------------------------- */

.so-photo-card .nectar-fancy-box {
  min-height: 250px;
}

.so-photo-card .nectar-fancy-box .parallaxImg-wrap::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: linear-gradient(180deg, rgba(13, 21, 18, 0.20) 0%, rgba(13, 21, 18, 0.55) 55%, rgba(13, 21, 18, 0.82) 100%);
}

/* Der Text muss über dem Abdunkler liegen. Die Textebene heißt in dieser
   Salient-Version .meta-wrap > .inner – gemessene Kette: .parallaxImg-wrap
   › .parallaxImg › -container › -layers › -rendered-layer › .meta-wrap › .inner.
   Ohne diese Regel malt der Abdunkler über die Schrift, weil er als
   positioniertes Geschwisterelement später dran ist. */
.so-photo-card .nectar-fancy-box .meta-wrap,
.so-photo-card .nectar-fancy-box .inner {
  position: relative;
  z-index: 2;
}

.so-photo-card .nectar-fancy-box h4 {
  color: #FFFFFF;
  margin: 0 0 0.4rem;
  font-size: 1.05rem;
  line-height: 1.25;
}

.so-photo-card .nectar-fancy-box p {
  color: rgba(255, 255, 255, 0.92);
  margin: 0;
  font-size: 0.92rem;
  line-height: 1.45;
}


/* --------------------------------------------------------------------------
   19 · Testimonial-Karten (Abschnitt "The pilot cities")

   Drei Karten in einer vc_row_inner mit equal_height="yes". Die Klasse
   so-testi hängt per el_class an den drei Spalten.

   Erst an der inneren Reihe versucht – das geht nicht: el_class an
   vc_row_inner wird gar nicht gerendert, am 03.09.2026 am DOM geprüft.
   Das ist dasselbe Verhalten, das Design-Learnings § 9.4 für el_id an
   vc_row beschreibt, nur eine Ebene tiefer. An vc_column_inner landet die
   Klasse dagegen zuverlässig am Spaltencontainer, neben vc_col-sm-4.

   Warum die ganze Flex-Kette: gleiche Kartenhöhe allein reicht nicht.
   Bei unterschiedlich langen Zitaten wandert die Zeile mit Foto und Name
   je nach Zeilenzahl auf und ab – am 03.09.2026 im gerenderten DOM
   gemessen, 75 px Unterschied zwischen der kürzesten und der längsten der
   drei Karten. Dagegen hilft margin-top: auto auf .so-testi__by, dasselbe
   Muster wie im Quick Check (Design-Learnings § 5.2). Salient gibt die
   Höhe der Spalte aber nicht an die Textbausteine weiter, deshalb muss die
   Kette .vc_column-inner › .wpb_wrapper › .wpb_text_column › .wpb_wrapper
   vollständig auf Flex stehen. Fehlt ein Glied, bleibt der auto-Rand ohne
   Wirkung.

   Unter 1000 px schaltet Salient die Gleichhöhe selbst ab
   (only screen and (max-width: 999px) auf .vc_row-flex.vc_row-o-equal-height),
   unter 690 px stapeln die Spalten. Beides braucht keine eigene Regel:
   ohne Fremdhöhe hat der auto-Rand nichts zu verteilen und fällt auf 0.
   -------------------------------------------------------------------------- */

.so-testi > .vc_column-inner,
.so-testi > .vc_column-inner > .wpb_wrapper,
.so-testi .wpb_text_column,
.so-testi .wpb_text_column > .wpb_wrapper {
  display: flex;
  flex-direction: column;
}

.so-testi > .vc_column-inner > .wpb_wrapper,
.so-testi .wpb_text_column,
.so-testi .wpb_text_column > .wpb_wrapper {
  flex: 1 1 auto;
}

/* Der Freiraum kurzer Zitate sammelt sich unter dem Zitat, nicht zwischen
   Foto und Name. */
.so-testi__quote {
  margin: 0 0 1.75rem;
}

.so-testi__by {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem;
  margin: auto 0 0;
}

/* 96 px in einer 289 px breiten Textspalte – die Spaltenbreite ist am
   gerenderten DOM gemessen. Es bleiben 177 px für Name und Funktion, das
   trägt zwei Zeilen.

   max-width statt einer festen Höhe: bei einer sehr schmalen Karte war das
   Foto der letzte Überläufer – der Namensblock wich schon aus, die 96 px
   des Kreises blieben stehen (gemessen: 96 px Inhalt in 60 px Karte).
   Mit max-width darf der Kreis mitschrumpfen, aspect-ratio hält ihn dabei
   rund. Deshalb hier keine height – eine feste Höhe würde das Verhältnis
   überstimmen. */
.so-testi__photo {
  display: block;
  flex: 0 0 auto;
  width: 96px;
  max-width: 100%;
  aspect-ratio: 1 / 1;
  border-radius: 50%;
  overflow: hidden;
  background: var(--so-mint-light);
}

/* Gleiche Spezifitätsfalle wie bei .so-path__img: Salients inline
   gedruckte Regel .row .col img:not([srcset]) { width: auto } schlägt ein
   .so-testi__photo img (0,1,1). Hier fiel es bisher nicht auf, weil die
   drei Portraits schon quadratisch zugeschnitten sind – das Bild landete
   über max-width: 100% zufällig auf denselben 96px. Ein nicht
   quadratisches Foto wäre verzerrt oder abgeschnitten worden, und
   object-fit hätte nichts zu beschneiden gehabt. Jetzt greift die Regel
   wirklich. */
.so-testi .wpb_text_column .so-testi__by .so-testi__photo img {
  display: block;
  margin: 0;   /* dasselbe .row .col img { margin-bottom: 15px } */
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Noch kein Foto freigegeben. Der Kreis bleibt als Platzhalter stehen,
   damit Name und Funktion in allen drei Karten an derselben Kante
   beginnen – ohne ihn rutscht die dritte Karte sichtbar aus der Reihe. */
.so-testi__photo--pending {
  box-shadow: inset 0 0 0 1px var(--so-line);
}

/* Der Umbruch ohne Umbruchpunkt.

   Zwischen 690 und 999 px Viewport stehen die Karten noch dreispaltig, aber
   die Textspalte schrumpft von 289 auf rund 150 px. Am 03.09.2026 gemessen:
   die Zeile aus Foto, Name und Funktion braucht dann 161 bis 196 px und
   läuft aus der Karte heraus – bei allen drei Karten, am deutlichsten bei
   "John Bøgelund Frederiksen".

   Statt zwei Medienabfragen (drei Spalten bei 999 px, gestapelt ab 690 px,
   und die Zeile müsste zweimal kippen) macht das die Flexbox selbst:
   min-width verbietet dem Namensblock zu schrumpfen, und flex-wrap auf
   .so-testi__by schiebt ihn dann unter das Foto. Passt er nebeneinander,
   wächst er über flex-grow auf die volle Restbreite.

   Das min() ist der Punkt. Ein festes min-width: 7rem wäre selbst wieder
   eine Annahme über die schmalste vorkommende Karte – und diese Annahme
   lässt sich hier nicht messen, ohne das Fenster zu verstellen: Salients
   Container-Breite und das padding-4-percent hängen beide an der
   Reihenbreite (gemessen: 49,8 px sind exakt 4 % von 1245 px, nicht 4 %
   der Spalte). min(7rem, 100%) braucht die Zahl nicht: der Block will
   7rem, nimmt aber nie mehr als die Karte hergibt. Damit kann die Zeile
   bei keiner Breite überlaufen. */
.so-testi__who {
  flex: 1 1 7rem;
  min-width: min(7rem, 100%);
  overflow-wrap: break-word;
}

.so-testi__name {
  display: block;
  font-size: 1rem;
  line-height: 1.35;
  font-weight: 700;
}

.so-testi__role {
  display: block;
  font-size: 0.9rem;
  line-height: 1.3;
  color: var(--so-text-muted);
}


/* --------------------------------------------------------------------------
   20 · Pathway-Karten (Abschnitt "Your development pathway")

   Ersetzt drei fancy_box-Kacheln mit Fotohintergrund. Die Fotos sind weg,
   dafür trägt jede Karte ihr Funktions-Icon als Plakette. Aufbau wie die
   Säulenkarten der Standards-Seite (§ 16): Icon, Eyebrow, Titel, Text,
   Link – und wie dort ohne Pfeilzeichen am Link, weil U+2192 in beiden
   Hausschriften fehlt (§ 8, § 8b).

   Die Höhenkette ist dieselbe wie bei den Testimonial-Karten (§ 12.5):
   equal_height="yes" macht nur die Spalte gleich hoch, die Textbausteine
   müssen einzeln auf Flex stehen, sonst bleibt margin-top: auto wirkungslos.
   Anders als bei den Säulenkarten trägt hier kein Absatz ein Inline-margin
   aus dem Seiteninhalt – deshalb genügt der auto-Rand und der Umweg über
   p:nth-last-child(2) aus § 10.3 ist nicht nötig.
   -------------------------------------------------------------------------- */

.so-path > .vc_column-inner,
.so-path > .vc_column-inner > .wpb_wrapper,
.so-path .wpb_text_column,
.so-path .wpb_text_column > .wpb_wrapper {
  display: flex;
  flex-direction: column;
}

.so-path > .vc_column-inner > .wpb_wrapper,
.so-path .wpb_text_column,
.so-path .wpb_text_column > .wpb_wrapper {
  flex: 1 1 auto;
}

.so-path .wpb_text_column {
  margin-bottom: 0;
}

/* Salient setzt ein nacktes p { padding-bottom: 27px } in style.css und
   skin-material.css legt p { padding-bottom: 1.5em } darauf. Beide sind
   reine Elementselektoren (0,0,1), jede eigene Klasse schlägt sie.

   In der Icon-Plakette war genau das der Fehler: align-items: center
   zentriert im *Inhaltsfeld*, und das Polster liegt darunter. Gemessen am
   04.09.2026: padding 0 0 27px, Icon 23px unter der Oberkante und 65px
   über der Unterkante – es klebte sichtbar oben.

   Deshalb alle Absätze der Karte auf padding: 0. Die Abstände kommen aus
   den Margins darunter, damit im Stylesheet steht, was auf dem Schirm
   passiert. Ohne diese Regel trägt auch die Eyebrow-Zeile 27px
   Fremdpolster zum Titel. */
.so-path .wpb_text_column p {
  padding: 0;
}


/* Icon-Plakette: gefülltes Blau mit weissem Icon. Der Styleguide nennt die
   Variante "card-dark-square" und weist sie ausdrücklich diesem Fall zu –
   "Standard-Badge für Buttons, Navigationskarten, CTA-Bereiche". Genau das
   sind diese drei Karten.

   Zuerst mit dem dezenten "tint-square" gebaut (Blau bei 10 % hinter dem
   Icon). Am Bild geprüft war das zu leise: die Plakette las sich als
   Hintergrundfläche, nicht als Icon. Voll deckend tragen die Icons den
   Abschnitt.

   Vollton ist hier erlaubt, weil Blau Marken- und Aktionsfarbe ist und
   nicht als Säulen-Tag gelesen wird – es steht ohne Nummer, ohne
   Säulenname, an allen drei Karten gleich (§ 4.2). Die Kernregel gegen
   Volltonflächen betrifft die vier Säulenfarben hinter Fließtext. */
.so-path__icon {
  display: flex;
  flex: 0 0 auto;
  align-items: center;
  justify-content: center;
  width: 88px;
  height: 88px;
  margin: 0 0 1.4rem;
  border-radius: 20px;   /* wie .icon-badge-lg.square im Styleguide */
  background: var(--so-brand);
}

/* Vier Klassen plus Element, und das ist kein Übermut.

   Salient druckt einen *inline* Stylesheet-Block mit
   .row .col img:not([srcset]) { width: auto } – Spezifität (0,3,1). Ein
   blosses .so-path__img hat (0,1,0) und verliert; das Bild wuchs damit auf
   seine Eigengrösse und wurde von max-width: 100% auf die Kastenbreite
   gestreckt: 88x88 statt 52x52, oben 7px aus der Plakette heraus
   (am 04.09.2026 gemessen).

   Ein Gleichstand bei (0,3,1) würde hier nicht genügen: bei gleicher
   Spezifität entscheidet die Reihenfolge, und ein inline gedruckter Block
   kann nach diesem Stylesheet im Kopf stehen. Deshalb (0,4,1) – damit
   gewinnt die Regel unabhängig von der Reihenfolge. */
.so-path .wpb_text_column .so-path__icon img.so-path__img {
  display: block;
  /* Salient gibt jedem Bild in einer Spalte .row .col img
     { margin-bottom: 15px }. In einem Flexcontainer mit
     align-items: center wird die *Margin-Box* zentriert – die 15px unten
     haben das Icon deshalb um 7,5px nach oben gezogen: gemessen 11px
     Abstand oben, 26px unten, wo 18/18 stehen müsste. */
  margin: 0;
  /* Am 06.09.2026 ausdruecklich um 20 % vergroessert: 52 x 1,2 = 62,4, auf
     ganze Pixel gerundet. Die Plakette bleibt 88 px, der Rand um das Icon
     geht damit von 18 auf 13 px.

     Das Blau der Plakette wurde bei derselben Gelegenheit nachgemessen:
     rgb(19, 69, 145) = #134591 an allen drei Karten, also --so-brand wie
     vorgesehen. Die Icons selbst sind weisse PNGs, tragen also keinen
     eigenen Farbton bei. */
  width: 62px;
  height: 62px;
}

/* Zwei Klassen plus Element, nicht eine. Salients Sammelregel
   ".row .col h3" hat (0,2,1); ein blosses h3.so-path__title kommt auf
   (0,1,1) und verliert – am 04.09.2026 gemessen, der Titel stand auf 30px
   statt der hier gesetzten Groesse. Mit .so-path davor steht es 2:2, und
   bei Gleichstand gewinnt dieses Stylesheet, weil es nach Salient
   eingebunden wird. Dieselbe Stelle wie h3.so-pillar-head__name in § 17 –
   dort war die Klasse von Anfang an mit dabei. */
.so-path h3.so-path__title {
  margin: 0.3rem 0 0.7rem;
  font-size: 1.28rem;
  line-height: 1.25;
  /* Zwei Zeilen Mindesthöhe: 2 x 25,6px Zeilenhöhe = 3,2rem. Ohne das
     sind "Find out where your city stands" und "Turn insight into action"
     einzeilig, "Connect through the European Outdoor Cities Network" aber
     zweizeilig – der Fließtext der dritten Karte begann 26px tiefer als
     bei den Nachbarn (am 04.09.2026 bei 1440px gemessen). Der Link stand
     durch den auto-Rand trotzdem auf gleicher Höhe, die Karte las sich
     aber verschoben. Das ist § 11.1 noch einmal: nicht nur das letzte
     Element ausrichten, sondern den Rhythmus darüber.
     Mindesthöhe, nicht Höhe – bei schmalen Spalten darf der Titel drei
     Zeilen brauchen. */
  min-height: 3.2rem;
}

.so-path__body {
  margin: 0;
}

.so-path__meta {
  margin: 1rem 0 0;
  font-size: 0.9rem;
  line-height: 1.35;
  color: var(--so-text-muted);
}

/* Der Link steht in allen drei Karten auf gleicher Unterkante. Genau ein
   auto-Rand in der Spalte – bei zwei verteilt die Flexbox den Freiraum
   gleichmäßig auf beide, und die Hälfte landet an der falschen Stelle.

   Zwei Klassen, weil die Regel "alle Absätze auf padding: 0" weiter oben
   (0,2,1) hat und einer einzelnen Klasse das padding-top wieder wegnehmen
   würde. */
.so-path p.so-path__cta {
  margin: auto 0 0;
  padding-top: 1.2rem;
}

/* Zwei Links in einer Karte (Karte 2 "Learn" verweist auf die Standards *und*
   auf die Good Practices). Der Kommentar oben gilt weiter: genau ein
   auto-Rand pro Spalte. Der erste Link traegt ihn und schiebt das Paar nach
   unten, der zweite bekommt ihn deshalb hier wieder abgenommen - sonst
   verteilt die Flexbox den Freiraum auf beide und die Haelfte landet
   *zwischen* den Links statt darueber.

   Geschwisterselektor statt zusaetzlicher Klasse: (0,2,2) schlaegt die Regel
   darueber (0,2,1), und im Seiteninhalt steht damit an beiden Links dieselbe
   Klasse. Karten mit nur einem Link merken von der Regel nichts. */
.so-path p.so-path__cta + p.so-path__cta {
  margin-top: 0;
  padding-top: 0.5rem;
}

@media (max-width: 690px) {
  .so-path__icon {
    width: 72px;
    height: 72px;
    margin-bottom: 1.1rem;
    border-radius: 16px;
  }

  .so-path .wpb_text_column .so-path__icon img.so-path__img {
    /* Mitgewachsen mit dem Desktop-Wert: 42 x 1,2 = 50,4. */
    width: 50px;
    height: 50px;
  }
}

/* --------------------------------------------------------------------------
   20 · Kennzahlenband auf der Kante

   Das Band mit 4 / 12 / 65 sitzt zwischen dem Mint-Band "From four pillars
   to practical indicators" und dem weissen Band "A shared orientation".
   Als eigener Abschnitt mit 4 % Innenabstand war es 236 px hoch – gemessen
   am 04.09.2026 – und wirkte wie ein vollwertiger Abschnitt, obwohl es nur
   eine Zwischenzeile sein soll.

   Loesung: Zeile ohne eigenen Hintergrund und ohne Innenabstand, dann um die
   halbe Kartenhoehe nach oben gezogen. Die Karten liegen damit zur Haelfte
   im Mint-Band und zur Haelfte auf Weiss. Das funktioniert nur, weil der
   Seitenhintergrund gemessen weiss ist (body: rgb(255,255,255)) und die
   untere Haelfte deshalb zum folgenden Band passt.

   Kartenhoehe 135 px, also 68 px hoch. z-index, weil die Hintergrundflaeche
   des Mint-Bandes sonst darueber liegt.
   -------------------------------------------------------------------------- */

.so-stat-seam {
  position: relative;
  z-index: 3;
}

@media (min-width: 1000px) {
  .so-stat-seam {
    margin-top: -68px;
    margin-bottom: 48px;
  }
}

/* Unter 1000 px stapeln die drei Spalten untereinander. Ein negativer
   Aussenabstand wuerde die Karten dort in die Ueberschrift des Bandes
   darueber schieben, deshalb bleibt es beim schlanken Zwischenband. */
@media (max-width: 999px) {
  .so-stat-seam {
    padding: 28px 0 12px;
  }
}

/* --------------------------------------------------------------------------
   21 · Kontaktseite: Karte, Portrait, Adresse

   Die Karte kommt aus dem Shortcode [so_map] (siehe
   includes/class-standout-css-embeds.php). Direkt im Seiteninhalt geht sie
   nicht: der MCP-Benutzer hat kein unfiltered_html, <iframe> wird beim
   Speichern entfernt.
   -------------------------------------------------------------------------- */

/* Der Rahmen gibt das Seitenverhaeltnis vor, das iframe fuellt ihn aus.
   Google liefert im iframe eine feste Pixelhoehe – ohne diesen Rahmen
   waere die Karte auf schmalen Viewports entweder zu hoch oder zu flach. */
.so-map {
  position: relative;
  display: block;
  width: 100%;
  overflow: hidden;
  border: 1px solid var(--so-line);
  border-radius: var(--so-radius);
  background-color: var(--so-paper);
}

.so-map--4x3  { aspect-ratio: 4 / 3; }
.so-map--3x2  { aspect-ratio: 3 / 2; }
.so-map--16x9 { aspect-ratio: 16 / 9; }
.so-map--1x1  { aspect-ratio: 1 / 1; }

.so-map iframe {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
}

/* Nur fuer angemeldete Redakteure, wenn die Quelle nicht zugelassen ist. */
.so-map__hint {
  padding: 12px 16px;
  border: 1px dashed var(--so-line);
  border-radius: var(--so-radius-sm);
  color: var(--so-text-muted);
  font-size: 14px;
}

/* Das Portrait ist eine freigestellte Grafik mit eigenen Formen und
   transparentem Grund – deshalb kein Rahmen, kein Radius, kein Zuschnitt.
   Sie steht auf Weiss, dort passen ihre Farbflaechen.

   Vier Klassen plus Element, und das ist kein Uebermut: Salient druckt
   .row .col img:not([srcset]) { width: auto } inline in den Seitenkopf
   (0,3,1, siehe Design-Learnings § 15.2). Ein einfaches .so-portrait__img
   verliert dagegen, und das Bild ginge auf seine Eigenbreite. */
.so-contact .wpb_text_column .so-portrait img.so-portrait__img {
  display: block;
  width: 100%;
  height: auto;
  max-width: 460px;
  margin: 0;
}

/* Salients .row .col img { margin-bottom: 15px } und das nackte
   p { padding-bottom: 27px } wuerden das Bild sonst aus der Mitte
   schieben – dieselbe Falle wie bei den Pathway-Karten (§ 15.1/15.3). */
.so-contact .wpb_text_column p.so-portrait {
  margin: 0;
  padding: 0;
}

/* Anschrift: enge Zeilen, weil die einzelnen Zeilen kurz sind und der
   normale Absatzdurchschuss sie auseinanderreisst. */
.so-contact .wpb_text_column p.so-address {
  margin: 0 0 1.25rem;
  padding: 0;
  line-height: 1.6;
}

/* Funktion und Organisation unter dem Namen. Kein 500er-Schnitt – Glacial
   Indifference hat nur 400 und 700, alles dazwischen faellt zurueck. */
.so-contact .so-role {
  display: block;
  margin: 0 0 1.25rem;
  color: var(--so-text-muted);
  font-size: 17px;
  font-weight: 400;
}

/* Gestapelte Spalten: das 1-%-Spaltenpolster sitzt je nach
   column_padding_position mal links, mal rechts. Nebeneinander ist das der
   Zwischenraum, gestapelt wird daraus eine ausgefranste linke Kante –
   gemessen am 05.09.2026 bei 390 px Fensterbreite: Portrait und Anschrift
   bei 23,4 px, Name, Button und Karte bei 27,3 px.

   Unterhalb des Umbruchpunkts trennt kein Polster mehr zwei Spalten, also
   kommt es weg. Additive Regel auf der eigenen Klasse, kein Eingriff in
   Salients .padding-1-percent selbst.

   Zwei Klassen plus die eigene, nicht eine: Salient druckt
   .col.padding-1-percent > .vc_column-inner { padding: calc(1vw) } (0,2,0)
   in einen inline <style>-Block im Seitenkopf, und der steht nach unserem
   Stylesheet. Bei Gleichstand gewinnt der spaetere - dieselbe Falle wie bei
   den Pathway-Icons, Design-Learnings § 15.2. Mit .wpb_column davor sind es
   (0,3,0) und die Reihenfolge ist egal. */
@media (max-width: 999px) {
  .wpb_column.so-contact > .vc_column-inner {
    padding-left: 0;
    padding-right: 0;
  }
}


/* --------------------------------------------------------------------------
   22 · Kopfzeile: Dropdown naeher an die Beschriftung

   Ausnahme von Regel 2 im Dateikopf: hier werden Salient-eigene Selektoren
   ueberschrieben. Es gibt keinen additiven Weg – die Kopfzeile ist
   Theme-Markup, an das WPBakery keine el_class herantraegt. Kein !important
   noetig, das Stylesheet laedt nach Salient (live gegengeprueft).

   Gemessen am 05.09.2026 auf /good-practices/ bei 1440 x 900:

     Kopfzeile 136 px = Logo 96 + 2 x Header-Padding 20 (Theme Options)
     Beschriftung senkrecht mittig, Zeile 24 px hoch, also von 56 bis 80
     Salient setzt top: 100% – das Dropdown hing an der Unterkante der
     Kopfzeile und damit 89 px unter der Schrift.

   Warum 50 % und nicht 100 % minus x: Salient verkleinert die Kopfzeile beim
   Scrollen. Ein fester Abzug von der Unterkante wird dann zu gross und zieht
   das Dropdown ueber die Beschriftung. Aus der Mitte gerechnet bleibt der
   Abstand in jeder Kopfzeilenhoehe derselbe – 50 % trifft die Mitte der
   Zeile, +12 px ihre Unterkante, +12 px Luft.

   Der geschrumpfte Zustand liess sich nicht gegenmessen: Salient fuehrt den
   Testbrowser als Touch-Geraet (body.using-touch-device) und schaltet dort
   Sticky und Schrumpfen ab. Die Annahme, dass die Beschriftung auch dann
   mittig sitzt, ist am echten Desktop zu pruefen.

   Unterstreichung: span.menu-title-text::after sitzt bei bottom: -3px, also
   rund 3 px unter der Zeile. Bei +24 px bleiben 14 px frei, sie bleibt
   sichtbar.
   -------------------------------------------------------------------------- */

#header-outer .sf-menu > li > ul.sub-menu {
  top: calc(50% + 24px);
  padding-top: 8px;
  padding-bottom: 8px;

  /* Der Schatten reichte nach oben auf die Kopfzeile und liess sie dort
     dunkler wirken als das Dropdown – beide sind in Wahrheit
     rgb(255,255,255), gemessen. Salient: 0 6px 28px rgba(0,0,0,.08).
     Ein Schatten steht blur/2 + spread ueber die Kastenkante hinaus, hier
     14 px; abzueglich 6 px Versatz bleiben 8 px, die auf der Kopfzeile
     landen. Bedingung fuer null Ueberstand: Versatz >= blur/2. Mit 10 px
     Versatz zu 20 px Weichzeichnung ist sie genau erfuellt, nach unten
     bleibt der Schatten weich. */
  box-shadow: 0 10px 20px rgba(0, 0, 0, 0.08);
}


/* --------------------------------------------------------------------------
   23 · so-hidden — einen einzelnen Baustein vorübergehend ausblenden

   Für Inhalte, die fertig gebaut sind, aber noch nicht gezeigt werden
   dürfen: eine Freigabe fehlt, ein Zitat ist noch nicht bestätigt.

   Warum nicht disable_element="yes": Das wirkt an [vc_row], aber **nicht**
   an [vc_column_inner] — am 05.09.2026 an der Viana-Testimonialkarte
   geprüft, die Spalte wurde weiter gerendert. Für eine ganze Reihe bleibt
   disable_element der bessere Weg, weil es auch im Editor sichtbar ist;
   für eine einzelne Spalte gibt es nur diese Klasse.

   Rückbau: so-hidden aus el_class entfernen. Der Inhalt bleibt die ganze
   Zeit im Seiteninhalt und ist im Editor normal bearbeitbar – er wird nur
   nicht ausgeliefert sichtbar. Für echte Geheimhaltung taugt das nicht:
   der Text steht im HTML.
   -------------------------------------------------------------------------- */

/* Zweiter belegter !important-Fall im Projekt (nach dem Button-Radius).

   Gegner ist WPBakerys js_composer.css:
       .vc_row.vc_row-flex > .span_12 > .vc_column_container { display: flex }
   Spezifität (0,4,0) gegen (0,1,0) – am 05.09.2026 gemessen, die Karte
   blieb sichtbar, obwohl Klasse und Regel beide da waren.

   Ein spezifischerer Selektor würde diesen einen Fall lösen, aber die
   Klasse soll überall wirken: in einer Flex-Reihe, in einer normalen
   Spalte, in einem Modul, das es noch nicht gibt. Eine Utility zum
   Ausblenden, die je nach Umgebung wirkt oder nicht, ist keine. */
.so-hidden {
  display: none !important;
}


/* --------------------------------------------------------------------------
   24 · Dokumentkarten (Resources-Seite)

   Acht Reports mit sehr verschiedenen Coverformaten: vier A4-Hochformate
   (848x1200), ein 16:9 (1200x675), ein 3:2 (1200x800) und zwei weitere
   Hochformate. In einer Kartenreihe treppt das ohne Zutun.

   Warum nicht .so-media aus Abschnitt 2: das schneidet mit
   object-fit: cover zu. Bei einem Foto ist das richtig, bei einem
   Dokumentcover nicht — dort steht der Titel oben und darf nicht
   angeschnitten werden. Deshalb hier der umgekehrte Weg: fester Rahmen im
   gleichen Seitenverhaeltnis fuer alle, das Cover liegt vollstaendig darin
   und behaelt seine Proportion. Hoch- und Querformat stehen damit
   nebeneinander, ohne dass eine Karte aus der Reihe faellt.

   Verwendung: el_class="so-doc so-radius" an vc_column_inner,
   zusaetzlich so-doc--featured fuer die beiden hervorgehobenen Karten.
   -------------------------------------------------------------------------- */

/* Gleiche Kartenhoehe bis nach unten durchreichen. Das ist die Kette aus
   Abschnitt 12.5 der Design-Learnings: equal_height="yes" macht die Spalten
   gleich hoch, gibt die Hoehe aber nicht an die Textbausteine weiter. Fehlt
   ein Glied, steht der Download-Link je Karte woanders. */
.so-doc > .vc_column-inner,
.so-doc > .vc_column-inner > .wpb_wrapper,
.so-doc .wpb_text_column,
.so-doc .wpb_text_column > .wpb_wrapper {
  display: flex;
  flex-direction: column;
}

.so-doc > .vc_column-inner > .wpb_wrapper,
.so-doc .wpb_text_column,
.so-doc .wpb_text_column > .wpb_wrapper {
  flex: 1 0 auto;
}

/* Salients nacktes p { padding-bottom: 27px } aus style.css, darauf
   p { padding-bottom: 1.5em } aus skin-material.css. Beide sind reine
   Elementselektoren (0,0,1) und damit leicht zu schlagen — man muss es aber
   tun, sonst sitzt das Cover in seinem Flex-Rahmen zu hoch (Abschnitt 15.1:
   align-items zentriert im Inhaltsfeld, das Polster liegt darunter). */
.so-doc .wpb_text_column p {
  padding: 0;
}

/* Quadratisch, und das ist gemessen statt geschaetzt. Mit 3:2 (erster
   Versuch) war der Rahmen bei 1440 px 289 x 192 px, das A4-Cover darin aber
   nur 110 x 156 px — die Hoehe war die knappe Grenze, und links und rechts
   blieben je 90 px leere Mattflaeche. Das las sich als Briefmarke auf einem
   Passepartout, nicht als Publikation.

   Im Quadrat traegt derselbe Rahmen ein 176 x 249 px grosses Hochformat,
   und die beiden Querformate (16:9 und 3:2) laufen weiter in die Breite,
   ohne dass eine Karte aus der Reihe faellt. Ein hochformatiger Rahmen
   waere fuer die Hochformate besser und fuer die Querformate schlechter —
   das Quadrat ist die Form, die beide Orientierungen gleich gut vertraegt. */
.so-doc .wpb_text_column .so-doc__cover {
  display: flex;
  align-items: center;
  justify-content: center;
  aspect-ratio: 1 / 1;
  margin: 0 0 18px;
  border: 1px solid var(--so-line);
  border-radius: var(--so-radius-sm);
  background-color: var(--so-paper);
  overflow: hidden;
}

/* Die hervorgehobenen Karten stehen zu zweit statt zu dritt und sind rund
   doppelt so breit (gemessen 503 px Textbreite gegen 289 px). Bei 4:3 wird
   der Rahmen 377 px hoch und traegt ein 235 x 332 px grosses Cover — hier
   ist das Cover der Blickfang, nicht die Beschreibung. */
.so-doc--featured .wpb_text_column .so-doc__cover {
  aspect-ratio: 4 / 3;
}

/* Vier Klassen plus Element, also (0,4,1). Noetig gegen zwei Salient-Regeln,
   die beide staerker sind als eine einzelne Klasse:

     .row .col img:not([srcset]) { width: auto }   (0,3,1)
   Diese steht in einem inline gedruckten style-Block im Seitenkopf und kann
   damit *nach* diesem Stylesheet kommen — ein Gleichstand genuegt hier
   nicht, siehe Abschnitt 15.2.

     .row .col img { margin-bottom: 15px }          (0,2,1)
   In einem Flexcontainer mit align-items: center wird die Margin-Box
   zentriert; die 15px unten wuerden das Cover um 7,5px nach oben ziehen
   (Abschnitt 15.3).

   width: auto zusammen mit den beiden max-Werten heisst: das Cover skaliert
   auf die knappere der beiden Grenzen und behaelt seine Proportion. Keine
   height, die wuerde das Verhaeltnis ueberstimmen. */
/* max-width groesser als max-height, und das ist Absicht: Hochformate sind
   ohnehin hoehenbegrenzt (gemessen 174 x 247 px im 289er Quadrat, die
   Breite bleibt weit unter der Grenze). Die beiden Querformate sind
   dagegen breitenbegrenzt, und bei 78 % fuellten sie nur 44 % bzw. 52 % der
   Rahmenhoehe — neben einem Hochformat mit 85 % sah das nach Versehen aus.
   Mit 92 % werden es 52 % und 61 %.

   Ganz gleich gross werden sie nicht. Ein 16:9- und ein 3:4-Bild koennen
   bei gleicher Rahmenhoehe nicht dieselbe Flaeche einnehmen, ohne dass man
   eines davon beschneidet — und beschneiden ist genau das, was bei einem
   Dokumentcover nicht geht. Die einheitliche Matte und der einheitliche
   Schatten tragen den Unterschied. Offener Punkt zur Sichtpruefung. */
.so-doc .wpb_text_column .so-doc__cover img.so-doc__img {
  width: auto;
  max-width: 92%;
  max-height: 86%;
  margin: 0;
  border-radius: 2px;
  object-fit: contain;
  box-shadow: 0 2px 6px rgba(20, 40, 30, .16), 0 10px 24px rgba(20, 40, 30, .12);
}

.so-doc--featured .wpb_text_column .so-doc__cover img.so-doc__img {
  max-width: 84%;
  max-height: 88%;
}

/* Salients h3-Sammelregel .row .col h3 setzt 30px mit (0,2,1) — eine Klasse
   plus Element hat nur (0,1,1) und verliert. Mit der Elternklasse
   qualifiziert steht es 2:2, und bei Gleichstand gewinnt dieses Stylesheet,
   weil es nach Salient eingebunden wird. Abschnitt 10.2 und 13.2. */
.so-doc h3.so-doc__title {
  margin: 0 0 .5rem;
  font-size: 1.12rem;
  line-height: 1.3;
  /* Zwei Zeilenhoehen als Mindestmass, nicht als feste Hoehe: ein langer
     Titel darf in der schmalen Spalte drei Zeilen brauchen. Ohne das sitzen
     Beschreibung und Meta-Zeile je Karte unterschiedlich hoch, auch wenn
     die Karten gleich hoch sind — Abschnitt 11.1. */
  min-height: 2.6em;
}

.so-doc--featured h3.so-doc__title {
  font-size: 1.32rem;
  min-height: 0;
}

/* Der Wachser der Karte. Nicht das letzte Element nach unten schieben,
   sondern das mittlere wachsen lassen — margin-top: auto scheitert an einem
   inline gesetzten margin (Abschnitt 10.3), flex-grow nicht. Im
   Seiteninhalt dieser Karten steht deshalb bewusst kein style="margin: 0". */
.so-doc .so-doc__desc {
  flex: 1 0 auto;
  margin: 0 0 1rem;
  color: var(--so-text-muted);
  font-size: .94rem;
}

.so-doc--featured .so-doc__desc {
  font-size: 1rem;
}

/* Seitenzahl und Dateigroesse vor dem Klick. Eine 11-MB-Datei ohne Vorwarnung
   auf einer Mobilverbindung ist eine unfreundliche Ueberraschung. */
.so-doc .so-doc__meta {
  margin: 0 0 .7rem;
  color: var(--so-text-faint);
  font-size: .82rem;
  letter-spacing: .02em;
}

.so-doc .so-doc__link {
  margin: 0;
  font-size: .94rem;
}

/* Kein Pfeilzeichen: U+2192 fehlt in Glacial Indifference und in League
   Spartan, siehe Abschnitt 13.7. Die Kennzeichnung traegt das Fettgewicht. */
.so-doc .so-doc__link a {
  font-weight: 700;
}

/* Der Salient-Button in den beiden hervorgehobenen Karten ist direktes Kind
   des .wpb_wrapper, und der steht durch die Flex-Kette oben auf
   flex-direction: column. Ein Flex-Element streckt sich in der Querachse,
   also lief der Button ueber die volle Textbreite — gemessen 503 px bei
   200 px Radius, was aus der Pille eine sehr lange Lutschtablette macht.

   align-self gibt ihm seine natuerliche Breite zurueck. Das ueberschreibt
   keine Salient-Regel: Salient setzt an dieser Stelle kein align-self, die
   Streckung kommt aus dem Flex-Standard. Der .nectar-button im Selektor
   loest im Validator eine Warnung aus; die Regel steht aber unter .so-doc
   und wirkt deshalb nur in diesen Karten, nicht site-weit. */
.so-doc > .vc_column-inner > .wpb_wrapper > a.nectar-button {
  align-self: flex-start;
}


/* --------------------------------------------------------------------------
   25 · Videokarten

   Die drei Knowledge-Exchange-Videos liegen auf YouTube. Bewusst *nicht*
   eingebettet: ein Embed laedt beim Seitenaufruf Google-Skripte und setzt
   Cookies, ohne dass der Besucher das Video ueberhaupt starten wollte. Auf
   einer Erasmus+-Projektseite ist das der falsche Standardzustand. Die
   Vorschaubilder liegen deshalb in der eigenen Mediathek, der Klick geht
   erst dann zu YouTube.

   Das Play-Zeichen ist rein zeichnerisch geloest — Kreis aus border-radius,
   Dreieck aus Rahmenbreiten. Kein SVG (ueberlebt kses nicht, Abschnitt 3),
   keine Data-URI, keine zusaetzliche Datei.

   Die Videokarten tragen zusaetzlich so-doc, sie nutzen also dieselbe
   Flex-Kette und dieselben Titel-, Text- und Linkregeln.
   -------------------------------------------------------------------------- */

.so-vid .wpb_text_column .so-vid__thumb {
  position: relative;
  display: block;
  aspect-ratio: 16 / 9;
  margin: 0 0 18px;
  padding: 0;
  border-radius: var(--so-radius-sm);
  background-color: var(--so-line);
  overflow: hidden;
}

/* Dieselbe Spezifitaetsrechnung wie bei .so-doc__img — hier aber mit
   object-fit: cover, weil ein Videostandbild ein Foto ist und angeschnitten
   werden darf. Alle drei Standbilder sind ohnehin 16:9, es wird also
   nichts beschnitten. */
.so-vid .wpb_text_column .so-vid__thumb img.so-vid__img {
  display: block;
  width: 100%;
  height: 100%;
  max-width: none;
  margin: 0;
  object-fit: cover;
  object-position: center;
}

/* Das Standbild ist verlinkt, und der Link muss ein Block sein: die
   Hoehenangabe am Bild (height: 100%) rechnet gegen den Elternkasten, und
   ein inline gesetztes <a> hat keine eigene Hoehe — das Bild fiele auf 0. */
.so-vid .wpb_text_column .so-vid__thumb a {
  display: block;
  width: 100%;
  height: 100%;
}

.so-vid .wpb_text_column .so-vid__thumb::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 54px;
  height: 54px;
  margin: -27px 0 0 -27px;
  border-radius: 50%;
  background-color: rgba(255, 255, 255, .92);
  box-shadow: 0 2px 10px rgba(0, 0, 0, .28);
  /* Beide Pseudoelemente haengen am <p>, nicht am <a> darin. Ohne dies
     schluckt gerade das Play-Zeichen — das offensichtlichste Klickziel —
     den Klick, weil es ueber dem Link liegt und nicht zu ihm gehoert. */
  pointer-events: none;
}

/* Das Dreieck. Ein Rahmen-Dreieck wirkt optisch nach links versetzt, wenn
   man den Kasten exakt zentriert — die sichtbare Masse liegt links der
   Spitze. Deshalb 2px Ausgleich im linken Rand. */
.so-vid .wpb_text_column .so-vid__thumb::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  z-index: 2;
  width: 0;
  height: 0;
  margin: -10px 0 0 -5px;
  border-style: solid;
  border-width: 10px 0 10px 17px;
  border-color: transparent transparent transparent var(--so-brand);
  pointer-events: none;
}


/* --------------------------------------------------------------------------
   26 · Das hervorgehobene Video oben auf der Seite

   Steht als erster Inhalt nach dem Hero, zweispaltig: Standbild links,
   Text rechts. Es ist keine Karte — kein Hintergrund, kein Rand, damit es
   sich vom Kartenraster darunter unterscheidet.

   Der Rahmen ist hier rund doppelt so breit wie in den Kartenspalten
   (gemessen 503 px gegen 289 px). Ein 54-px-Play-Zeichen waere darin
   proportional zu klein, deshalb ein groesseres — dieselbe Zeichnung, nur
   skaliert. Der 2-px-Ausgleich der Dreiecksmitte waechst mit (jetzt 3 px).
   -------------------------------------------------------------------------- */

.so-vid--featured .wpb_text_column .so-vid__thumb {
  margin: 0;
}

.so-vid--featured .wpb_text_column .so-vid__thumb::after {
  width: 76px;
  height: 76px;
  margin: -38px 0 0 -38px;
}

.so-vid--featured .wpb_text_column .so-vid__thumb::before {
  margin: -14px 0 0 -7px;
  border-width: 14px 0 14px 24px;
}


/* --------------------------------------------------------------------------
   27 · News-Teaser auf der Seite News & Resources

   Der Abschnitt hängt an Salients Shortcode
   `[recent_posts category="project-news" columns="3" posts_per_page="3"]`.
   Das ist mit Absicht so: neue Beiträge in der Kategorie erscheinen dort
   von selbst, ohne dass jemand die Seite anfasst.

   Was der Shortcode NICHT kann, am 06.09.2026 gemessen: Die Attribute
   `remove_post_author`, `remove_post_comment_number` und `remove_post_date`
   werden **verworfen**. Salient druckt zwar `data-remove-post-author=""` an
   das Wurzelelement, füllt es aber nur aus seinem eigenen
   Seitenbaukasten-Element, nicht aus dem Shortcode. Übrig blieben damit drei
   Meta-Angaben, die auf einer Projektseite alle falsch sind:

     .meta-author         "mtfai"        — das technische MCP-Konto
     .meta-category       "| Project news" — redundant, die Überschrift sagt es
     .meta-comment-count  "| No Comments"  — Kommentare sind hier kein Thema

   Ein Datum, das bei News das einzig Nützliche wäre, gibt der Shortcode
   dagegen gar nicht her. Die Meta-Zeile fliegt deshalb ganz heraus; das
   Datum steht im Beitrag selbst und im Archiv unter
   /category/project-news/.

   Alle Regeln stehen unter .so-news und wirken damit nur in diesem einen
   Abschnitt — dasselbe Vorgehen wie bei .so-cat-group (Abschnitt 12) und
   .so-gp-compact (Abschnitt 14).
   -------------------------------------------------------------------------- */

.so-news .blog-recent .post-header > span {
  display: none;
}

/* Hier gewinnt nicht die bekannte h3-Sammelregel, sondern ein Stylesheet,
   das dem Projekt bisher nicht bekannt war: Salient liefert **je
   Baukasten-Element eine eigene Datei**. Für diesen Shortcode ist es
   `css/element-recent-posts.css`, und dort steht

       .blog-recent[data-style="default"] .col .post-header h3
           { font-size: 16px }

   Das ist ein Attributselektor plus drei Klassen plus Element, also
   (0,4,1) — stärker als alles, was in diesem Stylesheet bisher gegen
   Salient antreten musste. Ein erster Versuch mit
   `.so-news .blog-recent h3.title` (0,3,1) verlor, und zwar still: die
   Mindesthöhe griff, die Schriftgröße nicht.

   `.post-header` mitzuschreiben bringt es auf (0,4,1) und damit auf
   Gleichstand; den gewinnt diese Datei, weil sie nach Salient eingebunden
   wird. Zielwert ist die Titelgröße der Dokumentkarten (gemessen 17,9 px),
   damit beide Kartenfamilien auf derselben Seite gleich klingen. */
.so-news .blog-recent .post-header h3.title {
  margin: 0 0 .5rem;
  font-size: 1.05rem;
  line-height: 1.35;
  /* Zwei Zeilen als Mindestmass. Gemessen waren die drei Titel 46/23/46 px
     hoch, wodurch der Auszug der mittleren Karte 23 px höher ansetzte als
     bei den Nachbarn. Mindesthöhe statt fester Höhe, damit ein langer Titel
     in der schmalen Spalte drei Zeilen nehmen darf. */
  min-height: 2.7em;
}

/* Das Vorschaubild ist ein nackter Link um ein img. Ohne overflow bleibt die
   Rundung am Bild wirkungslos, weil das img den Kasten überzeichnet. */
.so-news .blog-recent > .col > a {
  display: block;
  border-radius: var(--so-radius-sm);
  overflow: hidden;
}

.so-news .blog-recent .excerpt {
  color: var(--so-text-muted);
  font-size: .94rem;
}

.so-news .so-news__more {
  margin: 1.2rem 0 0;
  font-size: .94rem;
}

/* Kein Pfeilzeichen, siehe Abschnitt 13.7 — U+2192 fehlt in beiden
   Projektschriften. Das Fettgewicht trägt die Kennzeichnung. */
.so-news .so-news__more a {
  font-weight: 700;
}


/* --------------------------------------------------------------------------
   28 · Kopfbild des News-Archivs

   /category/project-news/ trug bis zum 06.09.2026 noch ein
   Salient-Demobild: `2019/09/roman-purtov-…-unsplash.jpg`. Ersetzt durch
   Anhang 6365, „Knowledge Exchange Lecco – Header".

   **Warum das hier steht und nicht in den Theme Options:** Salient setzt das
   Archiv-Kopfbild als Inline-Style am Element —

       <div class="page-header-bg-image" style="background-image: url(…)">

   Gegen eine Inline-Deklaration gewinnt keine Spezifität (Abschnitt 2.1, an
   drei Versuchen belegt). Es braucht `!important`. Das ist damit der
   **vierte** dokumentierte Ausnahmefall im Projekt, nach Button-Radius
   (2.1), Kennzahlengröße (9.2) und so-hidden (23).

   Der saubere Weg wäre *Theme Options → Blog → Archiv-Kopfbild*. Der ist
   über den MCP-Zugang nicht erreichbar (Kontext-Briefing § 4), liegt also
   bei Phil. Wird er dort gesetzt, kann dieser Abschnitt ersatzlos weg.

   **Eng auf die eine Kategorie begrenzt.** `body.category-project-news`
   trifft nur dieses Archiv; die leeren Demo-Archive und die Beitragsseiten
   bleiben unberührt. Einzelne Beiträge brauchen ohnehin nichts: sie zeigen
   ihr eigenes Beitragsbild im Kopf, am 06.09.2026 geprüft.

   **Die Staffelung ist Handarbeit, weil ein background-image kein `srcset`
   kennt** (Abschnitt 14.6). Gemessene Dateigrößen desselben Bildes:
   2560 px 576 KB, 1536 px 235 KB, 1024 px 118 KB. Ein Kopfband ist nur
   einige Hundert Pixel hoch — die 2560er Fassung lohnt erst auf einem
   entsprechend breiten Bildschirm.
   -------------------------------------------------------------------------- */

body.category-project-news #page-header-wrap .page-header-bg-image {
  background-image: url("/wp-content/uploads/sites/2/2026/08/II-Knowledge-Exchange-Lecco-122-1536x1024.jpg") !important;
}

@media (max-width: 999px) {
  body.category-project-news #page-header-wrap .page-header-bg-image {
    background-image: url("/wp-content/uploads/sites/2/2026/08/II-Knowledge-Exchange-Lecco-122-1024x683.jpg") !important;
  }
}

@media (min-width: 1600px) {
  body.category-project-news #page-header-wrap .page-header-bg-image {
    background-image: url("/wp-content/uploads/sites/2/2026/08/II-Knowledge-Exchange-Lecco-122-scaled.jpg") !important;
  }
}


/* --------------------------------------------------------------------------
   29 · Saeulenkarten der Startseite im Quick-Check-Stil

   Die vier Karten unter "Built on transparent European Standards" tragen ab
   jetzt dieselbe Gestalt wie Schritt 2 des Quick Checks (Modul
   eocn-quickcheck, Klasse .eocn-qc__pillar-card): 5 px Saeulenfarbe an der
   Oberkante, runde Plakette mit dem Saeulenicon, Vorzeile, Name, Kurztext.
   Vorher stand dort ein 48-px-Farbstrich ueber einem 64-px-Badge-PNG.

   Uebernommene Masse, damit beide Seiten wirklich dieselbe Karte zeigen:
   Rand 1 px, Radius 10 px, Oberkante 5 px, Plakette 46 px, Icon 24 px.
   Typografie bleibt die der Startseite (Eyebrow League Spartan ueber
   .so-eyebrow, Name in der Theme-Ueberschriftenschrift) - der Quick Check
   bringt seine eigenen Schriften mit, die Startseite nicht.

   Aufbau der Spalte, am 06.09.2026 am gerenderten DOM gemessen:

     .wpb_column.so-qcp
       |- .vc_column-inner
            |- .column-bg-overlay-wrap    position:absolute, inset 0,
            |    |- .column-bg-overlay      overflow:hidden, radius 5px
            |- .wpb_wrapper
                 |- .wpb_text_column > .wpb_wrapper > (p, h4, p)

   Das Weiss liegt auf .column-bg-overlay, und zwar auf inset 0 des
   *Polsterkastens* der Huelle. Ein Rand an der Huelle liegt deshalb
   ausserhalb der weissen Flaeche und wird nicht ueberdeckt - genau dort
   sitzt die Saeulenfarbe. Ohne diesen Umweg muesste die Farbe in den
   Seiteninhalt, und dort ueberlebt kein <svg> (kein unfiltered_html).

   Die Icons sind die vier Pfade aus quickcheck.json, als Data-URI ins
   Stylesheet gelegt. Strichfarbe: Weiss nur auf Blau. Auf Gruen, Tuerkis
   und Gold steht der dunkle Ton #15211D - Weiss reicht dort im Kontrast
   nicht, dieselbe Regel wie im Quick Check (--eocn-pN-ink).
   -------------------------------------------------------------------------- */

.so-qcp--1 {
  --so-pc: var(--so-pillar-1);
  --so-pc-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2315211D' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 19c0-8 6-14 15-14 0 9-6 15-15 14z'/%3E%3Cpath d='M5 19c4-6 8-8 12-9'/%3E%3C/svg%3E");
}

.so-qcp--2 {
  --so-pc: var(--so-pillar-2);
  --so-pc-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2315211D' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='9' cy='8' r='3'/%3E%3Ccircle cx='17' cy='9' r='2.2'/%3E%3Cpath d='M3.5 20c0-3 2.5-5 5.5-5s5.5 2 5.5 5'/%3E%3Cpath d='M15 15c2.5 0 5 1.6 5 5'/%3E%3C/svg%3E");
}

.so-qcp--3 {
  --so-pc: var(--so-pillar-3);
  --so-pc-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23FFFFFF' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 20V10M10 20V4M16 20v-7M22 20H2'/%3E%3C/svg%3E");
}

.so-qcp--4 {
  --so-pc: var(--so-pillar-4);
  --so-pc-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2315211D' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='6.5' cy='12' r='3'/%3E%3Ccircle cx='17.5' cy='12' r='3'/%3E%3Cline x1='9.7' y1='12' x2='14.3' y2='12'/%3E%3C/svg%3E");
}

/* Der Innenabstand kommt hierher statt aus column_padding: die Spalte steht
   im Seiteninhalt auf no-extra-padding, damit die Karte dieselben knappen
   Raender hat wie im Quick Check. */
.so-qcp > .vc_column-inner {
  padding: 1.4rem 1.5rem 1.6rem;
}

/* Haarlinie und farbige Oberkante an der Huelle, nicht an der Spalte:
   nur die Huelle ist so gross wie die sichtbare weisse Flaeche. */
.so-qcp .column-bg-overlay-wrap {
  border: 1px solid var(--so-line);
  border-top: 5px solid var(--so-pc);
  border-radius: 10px;
}

/* Die Plakette als ::before des Textblocks - so bleibt der Seiteninhalt
   frei von Hilfsmarkup. */
.so-qcp .wpb_text_column > .wpb_wrapper::before {
  content: "";
  display: block;
  width: 46px;
  height: 46px;
  margin: 0 0 0.7rem;
  border-radius: 50%;
  background-color: var(--so-pc);
  background-image: var(--so-pc-icon);
  background-repeat: no-repeat;
  background-position: center center;
  background-size: 24px 24px;
}

/* Salients nacktes p { padding-bottom: 27px } aus style.css und das
   p { padding-bottom: 1.5em } aus skin-material.css, beide (0,0,1).
   Ohne das steht unter jeder Zeile ein Fremdpolster (Abschnitt 15.1). */
.so-qcp .wpb_text_column p {
  padding: 0;
}

.so-qcp .wpb_text_column p.so-eyebrow {
  margin: 0 0 0.35rem;
}

/* Drei Klassen plus Element, nicht eine: Salients Sammelregel
   ".row .col h4" hat (0,2,1). Ein blosses h4.so-qcp__name kaeme auf
   (0,1,1) und verliert; ein Gleichstand bei (0,2,1) haengt an der
   Einbindungsreihenfolge und damit auch am inline gedruckten Block
   (Abschnitt 15.2). (0,3,1) gewinnt unabhaengig davon. */
.so-qcp .wpb_text_column h4.so-qcp__name {
  margin: 0 0 0.5rem;
  font-size: 1.15rem;
  line-height: 1.25;
  color: var(--so-text);
}

.so-qcp .wpb_text_column p.so-qcp__text {
  margin: 0;
  font-size: 15px;
  line-height: 1.55;
  color: var(--so-text-muted);
}

@media (max-width: 690px) {
  .so-qcp > .vc_column-inner {
    padding: 1.2rem 1.3rem 1.4rem;
  }
}


/* --------------------------------------------------------------------------
   30 · Partnerlogos (Wuerdigung des Konsortiums)

   Zehn Logos, jedes verlinkt auf die Homepage der Organisation.

   **Herkunft der Bilder:** Es gab sie nicht einzeln. In der Mediathek lag
   der offizielle Partner-Logostreifen des Projekts (Anhang 6341–6344, vier
   Groessen, 2560 px breit), ein 2x5-Raster mit allen zehn Logos in *einem*
   Bild. Ein einziges Bild kann keine zehn verschiedenen Ziele verlinken,
   also ist der Streifen zerlegt worden: Alphakanal spaltenweise auf
   Luecken ab 60 px geprueft, die Fassung „ohne bg" als Quelle, weil nur die
   echte Transparenz hat (Alpha 0–255; die anderen drei beginnen bei 132).
   Jeder Schnitt am Bild gegengeprueft. Naeheres in den Design-Learnings
   § 19.

   **Warum ein Raster und keine Spalten:** Zehn WPBakery-Spalten waeren zehn
   Attributbloecke im Seiteninhalt, und 1/5 gehoert nicht zu den Breiten,
   die WPBakery anbietet. Die zehn Links stehen deshalb als einfache Liste
   in *einem* Textblock, das Raster macht CSS.
   -------------------------------------------------------------------------- */

/* Hier bewusst *mit* Umbruchpunkt, gegen die Regel aus Abschnitt 12.4.

   Der erste Versuch war die min()-Loesung von dort,
   `repeat(auto-fit, minmax(min(220px, 45%), 1fr))`. Gemessen ergab sie:

     1440 px Viewport (Raster 1245) → 5 + 5    ✔
     1000 px          (Raster  805) → 3+3+3+1  ✘
      768 px          (Raster  663) → 2 x 5    ✔
      375 px          (Raster  330) → 2 x 5    ✔

   Bei 1000 px steht damit ein einzelnes Logo allein in der letzten Reihe.
   Fuer eine Wuerdigung, in der alle Partner gleichrangig stehen sollen, ist
   ein Waisenkind das falsche Bild.

   Der Unterschied zu Abschnitt 12.4: Dort war die *Anzahl* der Karten offen,
   deshalb durfte die Regel keine Zahl kennen. Hier ist sie fest — zehn
   Konsortialpartner. Und zehn teilt sich glatt durch fuenf und durch zwei,
   also gibt es genau zwei Anordnungen ohne Rest. Eine bekannte Anzahl
   rechtfertigt einen Umbruchpunkt; eine unbekannte nicht. */
/* Abstaende am 07.09.2026 auf Wunsch der Nutzerin geoeffnet: mehr Luft nach
   oben, nach unten und zwischen den beiden Logoreihen. Der Zeilenabstand
   steht im ersten Wert von `gap` (46px), der Spaltenabstand bleibt bei 24px
   — nach mehr Platz *zwischen* den Logos einer Reihe war nicht gefragt.

   **Nach unten steht hier bewusst kein margin.** Ein erster Versuch mit
   `margin: 32px 0 16px` kam als `margin-bottom: 0px` heraus, weil zwei
   Salient-Regeln staerker sind:

     .wpb_wrapper > div:last-child                  { margin-bottom: 0 }  (0,2,1)
     .wpb_text_column > .wpb_wrapper > :last-child  { margin-bottom: 0 }  (0,3,0)

   Gegen (0,1,0) verlieren beide zu Recht. Erzwingen liesse es sich mit
   `.wpb_text_column > .wpb_wrapper > div.so-partners` (0,3,1) — aber diese
   Regeln von Salient sind kein Versehen: Sie halten Textbloecke frei von
   Streurand, weil der Abstand nach unten aus dem Polster der *Reihe*
   kommen soll. Genau dort steht er jetzt auch, bottom_padding 8 % statt
   6 % im Seiteninhalt.

   Eine Regel, die still zur Haelfte verliert, waere das schlechtere
   Ergebnis gewesen — siehe Abschnitt 18.6 der Design-Learnings. */
.so-partners {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 46px 24px;
  align-items: center;
  margin: 32px 0 0;
}

/* Ab 1100 px ist das Raster rund 905 px breit, eine Kachel also gut 160 px —
   genug fuer die breitesten Logos (400 x 86). Darunter sind zwei Spalten die
   ruhigere Wahl: fuenf Reihen, aber jedes Logo gross. */
@media (min-width: 1100px) {
  .so-partners {
    grid-template-columns: repeat(5, 1fr);
  }
}

/* wpautop macht aus jedem Zeilenumbruch zwischen den zehn Links ein <br>.
   Gemessen am 07.09.2026: 19 Rasterelemente statt 10 — zehn Links und neun
   <br>, und jedes <br> nimmt eine Rasterzelle ein.

   Die Alternative waere, die zehn Links im Seiteninhalt in *eine* Zeile zu
   schreiben. Dann haette wpautop nichts umzuwandeln, aber die Redaktion
   haette eine 4000 Zeichen lange Zeile vor sich. Ein Logo pro Zeile bleibt
   bearbeitbar; die Nebenwirkung kostet hier eine Regel. */
.so-partners br {
  display: none;
}

/* Gleich hohe Kachel fuer alle. Die Logos haben sehr verschiedene
   Seitenverhaeltnisse — gemessen von 400x86 (Silkeborg) bis 184x245
   (Viana do Castelo), also von 4,7:1 bis 0,75:1. Ohne gemeinsame Kachel
   bestimmt das breiteste Logo die Reihenhoehe und das hochformatige wirkt
   winzig. Dasselbe Problem wie bei den Dokumentcovern, Abschnitt 24. */
/* 07.09.2026 um rund 10 % zurueckgenommen: 84 auf 76 px. Das allein reicht
   aber nicht — es begrenzt nur die *hochformatigen* Logos. Die breiten sind
   breitenbegrenzt und brauchen die zweite Schraube weiter unten
   (max-width 100 % auf 90 %). Gemessen vorher/nachher:
   ENOS 202x84 → 183x76, Silkeborg 230x49 → 207x44. */
.so-partners .so-partners__item {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 76px;
  padding: 0;
  /* Graustufen im Ruhezustand waere die uebliche Loesung fuer eine ruhige
     Logoreihe. Hier bewusst nicht: die Logos tragen Landes- und
     Markenfarben (TUM-Blau, das Wappen von Silkeborg, das Vereinsabzeichen
     von Tara), und eine Wuerdigung, die die Partner entfaerbt, ist keine. */
}

/* Vier Klassen plus Element, also (0,4,1). Noetig gegen zwei Salient-Regeln,
   die eine einzelne Klasse schlagen — dieselbe Rechnung wie in
   Abschnitt 24:

     .row .col img:not([srcset]) { width: auto }   (0,3,1), inline im Kopf
     .row .col img { margin-bottom: 15px }          (0,2,1)

   Die zweite ist hier besonders tueckisch: in einem Flexcontainer mit
   align-items: center wird die Margin-Box zentriert, die 15 px unten
   ziehen das Logo also um 7,5 px nach oben (Abschnitt 15.3). */
/* Die zweite der beiden Schrauben aus dem Kommentar oben: 90 statt 100 %
   nimmt die breitenbegrenzten Logos um dieselben 10 % zurueck wie die
   Kachelhoehe die hochformatigen. Ohne das waeren nur die halben Logos
   kleiner geworden. */
.wpb_text_column .so-partners .so-partners__item img.so-partners__logo {
  width: auto;
  max-width: 90%;
  max-height: 100%;
  margin: 0;
}

/* Ein Logo ist ein Klickziel, kein Text. Salient unterstreicht Links im
   Inhalt; auf einem Bild ergibt das einen Strich unter dem Logo. */
.so-partners .so-partners__item,
.so-partners .so-partners__item:hover {
  text-decoration: none;
  border-bottom: 0;
}

/* Rueckmeldung beim Ueberfahren, ohne die Kachelhoehe zu veraendern —
   eine Transformation verschiebt nichts im Fluss. */
.so-partners .so-partners__item img.so-partners__logo {
  transition: transform .18s ease-out;
}

.so-partners .so-partners__item:hover img.so-partners__logo,
.so-partners .so-partners__item:focus-visible img.so-partners__logo {
  transform: scale(1.05);
}

/* Die Logos sind transparente PNG und auf Weiss gezeichnet. Im Dark Mode
   stehen sie sonst als dunkle Schrift auf dunklem Grund. Eine weisse
   Flaeche darunter ist die ehrlichste Loesung: sie faelscht keine
   Markenfarbe, sie gibt dem Logo den Grund, fuer den es gemacht ist. */
@media (prefers-color-scheme: dark) {
  .so-partners .so-partners__item {
    padding: 10px 14px;
    border-radius: var(--so-radius-sm);
    background-color: #FFFFFF;
  }
}

/* --------------------------------------------------------------------------
   21 · Weisser Button auf farbigem Grund

   Der Styleguide sieht auf Markenblau den weissen Button vor. Salients
   nectar_btn kennt dafuer color_override – das setzt aber nur die Flaeche
   (inline background-color). Fuer die Schrift gibt es kein Gegenstueck:
   text_color_override wird nicht angenommen, es entsteht kein
   data-Attribut. Uebrig bleibt .nectar-button { color: #fff }, und damit
   steht weisse Schrift auf weisser Flaeche – am 07.09.2026 in der Karte
   "First step · Orientation" gemessen, Kontrast 1,0.

   Die Regeln, die die Schrift setzen, arbeiten ohne !important
   (.nectar-button und .nectar-button.medium, beide (0,2,0)). Eine eigene
   Klasse an der Spalte genuegt also. Der Rahmen wird mitgefaerbt, sonst
   zeichnet Salient eine weisse Linie um eine weisse Flaeche.
   -------------------------------------------------------------------------- */

.so-cta-invert .nectar-button,
.so-cta-invert .nectar-button span,
.so-cta-invert .nectar-button:hover,
.so-cta-invert .nectar-button:hover span {
  color: var(--so-text);
}

.so-cta-invert .nectar-button {
  border-color: transparent;
}


/* --------------------------------------------------------------------------
   31 · Pilot-Cities-Stadtseite: Faktenleiste und erweiterte Saeulenkarte
   (18.09.2026, gebaut fuer Sundsvall)

   Zwei Bausteine, die es noch nicht gab. Alles andere auf der Stadtseite
   kommt aus vorhandenen Abschnitten: Hero wie Kontaktseite (§ 16.4),
   Saeulenkarte .so-qcp aus § 29, Testimonial .so-testi aus § 19,
   Bildkacheln .so-media aus § 2.
   -------------------------------------------------------------------------- */

/* 31.1 Faktenleiste

   Fuenf knappe Werte unter dem Hero. Bewusst kein Salient-"milestone":
   das Modul zaehlt Zahlen hoch, und drei der fuenf Werte sind keine Zahl,
   die man hochzaehlen kann ("2010 · 2018 · 2026", "Vaesternorrland").   */
.so-fact .wpb_text_column p {
  padding: 0;              /* Salients nacktes p{padding-bottom}, siehe § 15.1 */
}

.so-fact .wpb_text_column p.so-eyebrow {
  margin: 0 0 0.3rem;
}

/* (0,3,1) wie bei .so-qcp__name: Salients Sammelregel ".row .col h4"
   liegt bei (0,2,1) und wuerde eine einfachere Auszeichnung schlagen.
   Begruendung ausfuehrlich in § 29. */
.so-fact .wpb_text_column h4.so-fact__value {
  margin: 0 0 0.2rem;
  font-size: 1.45rem;
  line-height: 1.2;
  color: var(--so-pillar-3);
}

.so-fact .wpb_text_column p.so-fact__note {
  margin: 0;
  font-size: 14px;
  line-height: 1.45;
  color: var(--so-text-muted);
}

/* Trennlinie zwischen den Werten, nicht davor und nicht dahinter.
   Auf schmalen Schirmen stapeln die Spalten, dann waere ein linker Strich
   sinnlos - dort wandert er nach oben. */
.so-fact + .so-fact > .vc_column-inner {
  border-left: 1px solid var(--so-line);
  padding-left: 1.4rem;
}

@media (max-width: 999px) {
  .so-fact + .so-fact > .vc_column-inner {
    border-left: 0;
    border-top: 1px solid var(--so-line);
    padding-left: 0;
    padding-top: 1rem;
    margin-top: 1rem;
  }
}

/* 31.2 Saeulenkarte mit Schlagzeile und Ausblick

   Die Karte aus § 29 traegt auf der Startseite Vorzeile, Namen und einen
   Kurztext. Auf der Stadtseite kommen zwei Zeilen dazu: die Schlagworte
   ueber dem Fliesstext und ein Ausblickssatz darunter.

   Beide Regeln stehen auf (0,3,1) aus demselben Grund wie § 29.          */
.so-qcp .wpb_text_column p.so-qcp__lead {
  margin: 0 0 0.6rem;
  font-size: 15px;
  line-height: 1.5;
  font-weight: 700;        /* 700, nicht 600: Glacial Indifference hat keine
                              Zwischenschnitte, 600 spraenge auf Bold und 500
                              fiele auf Regular zurueck. */
  color: var(--so-text);
}

.so-qcp .wpb_text_column p.so-qcp__next {
  margin: 0.9rem 0 0;
  padding-top: 0.75rem;
  border-top: 1px solid var(--so-line);
  font-size: 14px;
  line-height: 1.5;
  color: var(--so-text-muted);
}

/* Das vorangestellte Wort traegt die Saeulenfarbe - dieselbe Rolle wie die
   Vorzeile: Farbe als Kennzeichnung, nie als Flaeche hinter Fliesstext. */
.so-qcp .wpb_text_column p.so-qcp__next strong {
  color: var(--so-pc);
  font-weight: 700;
}

/* Gold als Schriftfarbe reicht im Kontrast nicht (dieselbe Regel wie beim
   Eyebrow, § 4): auf der vierten Karte der dunklere Goldton. */
.so-qcp--4 .wpb_text_column p.so-qcp__next strong {
  color: #8A6D00;
}

/* 31.3 Bildergalerie der Stadtseite

   Gleiche Hoehe fuer alle Kacheln, damit die Reihe ruhig steht. Der
   Zuschnitt uebernimmt .so-media aus § 2; hier nur der Radius und der
   Abstand nach unten, den Salients ".row .col img" sonst setzt (§ 15.3). */
.so-gallery img {
  border-radius: 10px;
  margin-bottom: 0;
}
