a,
button,
img,
.wp-block-group,
.wp-block-columns,
.wp-block-column {
  transition: all ease 0.23s;
}
.wp-block-group.is-style-fritz-fritz-2026-boxshadow {
  box-shadow: 0 0 40px rgba(0, 0, 0, 0.12);
}
/*button hover style*/
.wp-block-button.is-style-button-hover-primary-bgcolor a.wp-block-button__link.wp-element-button:hover {
  background-color: var(--wp--preset--color--primary) !important;
  opacity: 1;
  color: var(--wp--preset--color--light-color) !important;
  border-color: var(--wp--preset--color--primary) !important;
}

/*style list for ul*/
.is-style-list-style-no-bullet {
  list-style-type: none;
}
.wp-block-gallery.fritz-fritz-2026-brands-logos .wp-block-image {
  align-items: center;
}
.wp-site-blocks > * + * {
  margin-block-start: 0 !important;
}
.fritz-fritz-2026-duotone-primary {
  filter: var(--wp--preset--duotone--primary);
}
.is-style-fritz-fritz-2026-page-list-bullet-hide-style.wp-block-page-list,
.wp-block-categories-list.is-style-fritz-fritz-2026-categories-bullet-hide-style {
  list-style: none;
  margin: 0;
  padding: 0;
}
figure.wp-block-image.fritz-fritz-2026-service-icon {
  background: var(--wp--preset--color--primary);
  width: 5rem;
  height: 5rem;
  display: flex;
  justify-content: center;
  align-items: center;
  border-radius: 0.625rem;
}
.wp-block-button.is-style-button-with-arrow-icon a.wp-element-button,
.wp-block-button.is-style-button-with-uparrow-icon a.wp-element-button {
  position: relative;
}
.wp-block-button.is-style-button-with-arrow-icon a.wp-element-button:after,
.wp-block-button.is-style-button-with-uparrow-icon a.wp-element-button:after {
  content: "";
  width: 1.5em;
  height: 0.5em;
  background-color: var(--wp--preset--color--light-color);
  -webkit-mask-image: url(../images/arrow_icon.svg);
  mask-image: url(../images/arrow_icon.svg);
  mask-repeat: no-repeat;
  mask-position: center center;
  -webkit-mask-repeat: no-repeat;
  -webkit-mask-position: center center;
  display: inline-block;
  left: 0;
  top: 0;
  border-radius: 50px;
  transition: all ease 0.23s;
  margin-left: 0.5em;
}
.wp-block-button.is-style-button-with-uparrow-icon a.wp-element-button:after {
  -webkit-mask-image: url(../images/upward-arrow.svg);
  mask-image: url(../images/upward-arrow.svg);
  height: 0.75em;
}
.wp-block-button.is-style-button-with-arrow-icon a.wp-element-button.has-foreground-color:after,
.wp-block-button.is-style-button-with-uparrow-icon a.wp-element-button.has-foreground-color:after {
  background-color: var(--wp--preset--color--foreground);
}
.wp-block-button.is-style-button-with-arrow-icon a.wp-element-button.has-dark-shade-color:after,
.wp-block-button.is-style-button-with-uparrow-icon a.wp-element-button.has-dark-shade-color:after {
  background-color: var(--wp--preset--color--dark-shade);
}
.wp-block-button.is-style-button-with-arrow-icon a.wp-element-button.has-primary-color:after,
.wp-block-button.is-style-button-with-uparrow-icon a.wp-element-button.has-primary-color:after {
  background-color: var(--wp--preset--color--primary);
}
.wp-block-button.is-style-button-with-arrow-icon a.wp-element-button.has-secondary-color:after,
.wp-block-button.is-style-button-with-uparrow-icon a.wp-element-button.has-secondary-color:after {
  background-color: var(--wp--preset--color--secondary);
}
.wp-block-button.is-style-button-with-arrow-icon a.wp-element-button.has-foreground-color:after,
.wp-block-button.is-style-button-with-uparrow-icon a.wp-element-button.has-foreground-color:after {
  background-color: var(--wp--preset--color--foreground);
}
.wp-block-button.is-style-button-with-arrow-icon a.wp-element-button.has-background-alt-color:after,
.wp-block-button.is-style-button-with-uparrow-icon a.wp-element-button.has-background-alt-color:after {
  background-color: var(--wp--preset--color--background-alt);
}
.wp-block-button.is-style-button-with-arrow-icon a.wp-element-button:hover:after {
  margin-left: 0.75em;
}
ul.wp-block-list.is-style-list-style-check-circle,
ul.wp-block-list.is-style-list-style-check-circle-white,
ul.wp-block-list.is-style-list-style-check-circle-fade-primary {
  list-style: none;
}
ul.wp-block-list.is-style-list-style-check-circle li,
ul.wp-block-list.is-style-list-style-check-circle-white li,
ul.wp-block-list.is-style-list-style-check-circle-fade-primary li {
  position: relative;
  padding-bottom: 0.6rem;
}
ul.wp-block-list.is-style-list-style-check-circle li:before,
ul.wp-block-list.is-style-list-style-check-circle-white li:before,
ul.wp-block-list.is-style-list-style-check-circle-fade-primary li:before {
  content: "";
  position: absolute;
  width: 1em;
  background-color: var(--wp--preset--color--primary);
  height: 1em;
  border-radius: 50%;
  left: -1.5em;
  top: 0.75em;
  margin-top: -0.5em;
}
ul.wp-block-list.is-style-list-style-check-circle-white li:before {
  background-color: var(--wp--preset--color--light-color);
}
ul.wp-block-list.is-style-list-style-check-circle-fade-primary li:before {
  opacity: 0.1;
}
ul.wp-block-list.is-style-list-style-check-circle li:after,
ul.wp-block-list.is-style-list-style-check-circle-white li:after,
ul.wp-block-list.is-style-list-style-check-circle-fade-primary li:after {
  content: "";
  width: 0.625em;
  height: 0.625em;
  background-color: var(--wp--preset--color--light-color);
  -webkit-mask-image: url(../images/check_icon.svg);
  mask-image: url(../images/check_icon.svg);
  mask-repeat: no-repeat;
  mask-position: center center;
  -webkit-mask-repeat: no-repeat;
  -webkit-mask-position: center center;
  display: inline-block;
  left: -1.5em;
  top: 0.75em !important;
  border-radius: 50px;
  transition: all ease 0.23s;
  position: absolute;
  margin-top: -0.3125em;
  mask-size: contain;
  margin-left: 0.1875em;
}
ul.wp-block-list.is-style-list-style-check-circle-white li:after,
ul.wp-block-list.is-style-list-style-check-circle-fade-primary li:after {
  background-color: var(--wp--preset--color--primary);
}
.wp-block-group.fritz-fritz-2026-slider {
  overflow: hidden;
  position: relative;
}
.fritz-fritz-2026-slider .swiper-slide {
  display: flex;
}
.wp-block-group.fritz-fritz-2026-slider-controls {
  position: unset;
}
.wp-block-group.fritz-fritz-2026-slider .wp-block-cover.swiper-slide {
  margin-block-start: 0 !important;
}
.fritz-fritz-2026-pagination.swiper-pagination-clickable.swiper-pagination-bullets {
  position: absolute;
  bottom: 1.25rem;
  z-index: 1;
  width: 100%;
  text-align: center;
  left: 50%;
  transform: translateX(-50%);
}
.fritz-fritz-2026-pagination.swiper-pagination-clickable.swiper-pagination-bullets span.swiper-pagination-bullet {
  width: 0.625rem;
  height: 0.625rem;
}
.fritz-fritz-2026-pagination.swiper-pagination-clickable.swiper-pagination-bullets span.swiper-pagination-bullet.swiper-pagination-bullet-active {
  background: var(--wp--preset--color--primary);
}
.wp-block-group.fritz-fritz-2026-slider .fritz-fritz-2026-button-prev,
.wp-block-group.fritz-fritz-2026-slider .fritz-fritz-2026-button-next {
  width: 3.125rem;
  height: 3.125rem;
  border-radius: 50%;
  background: #fff;
  color: var(--wp--preset--color--primary);
  transition: all ease 0.23s;
  opacity: 0;
  top: 50%;
  margin: -1.25rem 0 0 0;
}
.wp-block-group.fritz-fritz-2026-slider:hover .fritz-fritz-2026-button-prev,
.wp-block-group.fritz-fritz-2026-slider:hover .fritz-fritz-2026-button-next {
  opacity: 1;
}
.wp-block-group.fritz-fritz-2026-slider:hover .fritz-fritz-2026-button-prev {
  left: 1.875rem;
}
.wp-block-group.fritz-fritz-2026-slider:hover .fritz-fritz-2026-button-next {
  right: 1.875rem;
}
.wp-block-group.fritz-fritz-2026-slider .fritz-fritz-2026-button-prev:hover,
.wp-block-group.fritz-fritz-2026-slider .fritz-fritz-2026-button-next:hover {
  background: var(--wp--preset--color--primary);
  color: #fff;
}
.wp-block-group.fritz-fritz-2026-slider .fritz-fritz-2026-button-prev:after,
.wp-block-group.fritz-fritz-2026-slider .fritz-fritz-2026-button-next:after {
  font-size: 1rem;
}

.fritz-fritz-2026-slider-controls.wp-block-group.block-editor-block-list__layout .wp-block.wp-block-html {
  display: none;
}

.fritz-fritz-2026-slider-controls.wp-block-group.block-editor-block-list__layout .wp-block.is-selected.wp-block-html {
  display: block !important;
}
.wp-block-button.is-style-button-with-uparrow-icon a.wp-block-button__link.has-foreground-color:hover {
  background: var(--wp--preset--color--foreground) !important;
  color: #fff !important;
}
.wp-block-button.is-style-button-with-uparrow-icon a.wp-block-button__link.has-foreground-color:hover:after {
  background: #fff !important;
}
.wp-block-button.is-style-button-with-uparrow-icon a.wp-block-button__link.has-primary-color:hover {
  background: var(--wp--preset--color--primary) !important;
  color: #fff !important;
}
.wp-block-button.is-style-button-with-uparrow-icon a.wp-block-button__link.has-primary-color:hover:after {
  background: #fff !important;
}
.wp-block-woocommerce-product-collection.fritz-fritz-2026-stack-products ul li {
  margin-bottom: 0 !important;
}
.fritz-fritz-2026-search-icon.wp-block-search button.wp-block-search__button {
  padding: 0;
}
.fritz-fritz-2026-search-icon.wp-block-search button.wp-block-search__button svg.search-icon {
  font-size: 1.625rem;
}

.wp-block-contact-form-7-contact-form-selector.fritz-fritz-2026-newsletter-3 .wpcf7-form-control.wpcf7-submit {
  width: 100%;
  margin-top: 0.625rem;
  background: var(--wp--preset--color--light-color);
  color: var(--wp--preset--color--foreground);
}
.wp-block-contact-form-7-contact-form-selector.fritz-fritz-2026-newsletter-3 .wpcf7-form-control.wpcf7-submit:hover {
  background: var(--wp--preset--color--primary) !important;
  color: var(--wp--preset--color--light-color);
}
/* ============================================================
   CI Signature Devices (Fritz & Fritz 2026)
   Bordeaux-Kasten, überragendes &-Signet, umrandeter Callout,
   Icon-Faktenliste, Zitatkasten, Overline.

   Umgesetzt als native WordPress Block Styles (register_block_style,
   siehe inc/core/block-style.php): Das .is-style-ff-* am Wrapper treibt das
   komplette Erscheinungsbild – inklusive aller Sub-Elemente per
   Child-/Descendant-Selektor. Es gibt bewusst KEINE ff-* Sub-Block-Klassen mehr.
   ============================================================ */

/* --- Das &-Signet an gefüllten Bordeaux-Kästen (Titelkasten, Zitatkasten) ---
   Zwei Ebenen, damit die komplexe Form funktioniert:
   - ::before = rote Füllung der Box, aus der die Negativ-Form (signet-clip)
     per mask-composite HERAUSGESCHNITTEN wird -> Hintergrund/Bild scheint durch.
   - ::after  = rote Glyphe (signet-ampersand), die über die Ecke HINAUSRAGT.
   Die Box selbst wird transparent; die Füllung liefert ::before.
   Alle Positions-/Größen-Werte sind als Custom Props tunebar.

   Die Zeichnung endet unten auf genau einer Linie: y = 394.958 im viewBox,
   dort liegen der Bogen der Schale und die waagerechte Endkante des Schwanzes
   rechts. Darunter bleiben 2.042 von 397 Einheiten Luft (0,51 % der Höhe),
   rechts der Zeichnung 1.395 von 339 (0,41 % der Breite) — um so viel weniger
   ragt sie heraus als der Pseudo-Element-Kasten, den `--ff-signet-right` und
   `--ff-signet-bottom` setzen.

   `signet-ampersand-callout.svg` (Callout, Personen-Profilkarte) ist eine
   eigene Zeichnung im viewBox 0 0 347 425 und folgt diesem Abschnitt nicht:
   dort positionieren `right`/`bottom`/`transform` am Callout selbst. */
.is-style-ff-titlebox,
.is-style-ff-quotebox {
  --ff-signet-full: url(../images/signet-ampersand.svg);
  --ff-signet-clip: url(../images/signet-ampersand-clip.svg);
  --ff-signet-color: var(--wp--preset--color--primary);
  /* Beide SVGs haben denselben viewBox (0 0 339 397) und sind komplementär –
     ::before (Cut-Out) und ::after (Glyphe) werden IDENTISCH platziert.

     `--ff-signet-w` folgt dem viewBox-Verhältnis (339/397 ≈ 0.854) und wird
     deshalb aus der Höhe gerechnet: `mask-size` skaliert die Zeichnung auf
     genau Breite × Höhe, ein abweichender Faktor verzerrt sie. So steht es in
     allen vier Wertesätzen — hier, Hero, Karte und mobil. */
  --ff-signet-h: 6rem;
  --ff-signet-w: calc(var(--ff-signet-h) * 0.854);
  /* Anker an der unteren rechten Ecke (negativ = ragt hinaus). Der Wert gilt
     dem Pseudo-Element-Kasten; sichtbar ragt die Zeichnung in diesem Satz rund
     1,4 px unter die Kante (Grundlinien-Luft, siehe oben). */
  --ff-signet-right: -1.44rem;
  --ff-signet-bottom: -0.06rem;
  position: relative;
  isolation: isolate; /* eigener Stacking-Kontext für die negativen z-index */
  /* Füllung kommt aus ::before, Box selbst transparent */
  background-color: transparent;
}
/* Füllung + Cut-Out (Negativ-Form aus der Fläche subtrahiert) */
.is-style-ff-titlebox::before,
.is-style-ff-quotebox::before {
  content: "";
  position: absolute;
  inset: 0;
  background-color: var(--ff-signet-color);
  z-index: -2;
  /* Basis komplett opak (Gradient), Negativ-Form abziehen (exclude/xor) */
  -webkit-mask:
    linear-gradient(#000 0 0),
    var(--ff-signet-clip) no-repeat right var(--ff-signet-right) bottom var(--ff-signet-bottom) / var(--ff-signet-w) var(--ff-signet-h);
  mask:
    linear-gradient(#000 0 0),
    var(--ff-signet-clip) no-repeat right var(--ff-signet-right) bottom var(--ff-signet-bottom) / var(--ff-signet-w) var(--ff-signet-h);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  pointer-events: none;
}
/* Glyphe, die über die Ecke ragt – gleiche Position & Größe wie das Cut-Out */
.is-style-ff-titlebox::after,
.is-style-ff-quotebox::after {
  content: "";
  position: absolute;
  right: var(--ff-signet-right);
  bottom: var(--ff-signet-bottom);
  width: var(--ff-signet-w);
  height: var(--ff-signet-h);
  background-color: var(--ff-signet-color);
  -webkit-mask: var(--ff-signet-full) no-repeat right bottom / 100% 100%;
  mask: var(--ff-signet-full) no-repeat right bottom / 100% 100%;
  z-index: -1;
  pointer-events: none;
}
/* Editor: Gutenberg belegt am selektierten/gehoverten Block-Wrapper selbst das
   ::after für die Auswahl-/Hover-Umrandung – dasselbe Pseudo-Element wie unser
   überhängendes &-Glyph. Da beide Signet-Ebenen schon belegt sind (::before =
   Füllung, ::after = Glyph), kann das Glyph nicht ausweichen. Wir nehmen daher
   im aktiven Zustand unsere Glyph-Darstellung zurück UND geben den z-index frei:
   Gutenbergs Umrandung liegt sonst hinter dem Block (unser z-index:-1). So wird
   das Glyph unsichtbar und die Auswahl-Umrandung wieder sichtbar. Frontend ist
   nicht betroffen (.is-selected/.is-hovered existieren dort nicht); die Füllung
   (::before) bleibt stehen. */
.is-style-ff-titlebox.is-selected::after,
.is-style-ff-titlebox.is-hovered::after,
.is-style-ff-quotebox.is-selected::after,
.is-style-ff-quotebox.is-hovered::after {
  background-color: transparent !important;
  -webkit-mask: none !important;
  mask: none !important;
  z-index: auto !important;
  /* Ohne diese Resets erbt Gutenbergs Umrandung unsere Glyph-Maße (klein,
     oben links). inset:0 + auto lässt das ::after den ganzen Block abdecken,
     sodass die Umrandung um den kompletten Block läuft. */
  inset: 0 !important;
  width: auto !important;
  height: auto !important;
}

/* --- Overline / Eyebrow (Versalien, gesperrt, über der Headline) ---
   .ff-overline ist eine themenweite Utility (Hero, Leistungen, FAQ, Portfolio …).
   Die Faktenliste holt denselben Look strukturell über ihren ersten Absatz.

   Der Titelkasten stand hier bis zum 2026-09-07 mit drin
   (`.is-style-ff-titlebox > p:first-of-type`) und ist heraus: er unterstellte,
   der erste Absatz sei eine Overline. In einer Karte ist er der Fließtext und
   stand dadurch fett, versalisiert und gesperrt da. Seine Typografie kommt
   jetzt als Block-Setting aus dem Markup — siehe „Bordeaux-Titelkasten". */
.ff-overline,
.is-style-ff-factlist > p:first-child {
  display: block;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  line-height: 1.2;
  color: var(--wp--preset--color--primary);
  margin: 0 0 0.75rem;
}

/* --- Standard-Innenabstand für die Group-Signets (Callout, Titelkasten) ---
   Damit eine frisch eingefügte Group nicht ohne Padding dasteht. Bewusst als
   Longhand mit erhöhter Spezifität (.wp-block-group…), weil WordPress bei
   Root-Level-Gruppen die Klasse .has-global-padding setzt, die padding-left/right
   per Longhand belegt – ein padding-Shorthand würde im Editor davon überschrieben
   (Text klebt links). Explizites Block-Padding (Inline-Style aus den Patterns
   oder aus den Abstands-Reglern) gewinnt weiterhin.
   Die Personen-Profilkarte hängt mit drin, weil sie dieselbe Callout-Optik
   trägt (siehe Abschnitt „Personen & Team"); dort gibt es keinen
   .has-global-padding-Konflikt, die Spezifität stimmt aber ohnehin. */
.wp-block-group.is-style-ff-callout,
.wp-block-group.is-style-ff-titlebox,
.ff-person-profiles > .person {
  padding-top: var(--wp--preset--spacing--60);
  padding-right: var(--wp--preset--spacing--80);
  padding-bottom: var(--wp--preset--spacing--70);
  padding-left: var(--wp--preset--spacing--60);
}

/* --- Umrandeter Maßnahmen-/Checklist-Callout ---
   Dieselbe Optik trägt die Personen-Profilkarte (view "detailed"), deshalb
   steht sie in allen drei Regeln mit drin. */
.is-style-ff-callout,
.ff-person-profiles > .person {
  --ff-signet-url: url(../images/signet-ampersand-callout.svg);
  --ff-signet-h: 4.5rem;
  --ff-signet-w: 3.76rem;

  position: relative;
  /* eigener Stacking-Kontext, damit das Signet per negativem z-index unter den
     Inhalt rutscht, ohne hinter Vorfahren-Hintergründe zu fallen */
  isolation: isolate;
  border: 1px solid var(--wp--preset--color--primary);
  border-radius: 0.7rem;
}
/* Das &-Signet hängt über die untere rechte Ecke des Kastens.
   Bewusst ::before (nicht ::after): Der Group-Block-Wrapper ist im Editor
   dasselbe Element, und Gutenberg belegt dort ::after für die Auswahl-Umrandung
   (.is-selected::after). Über ::after würde das Signet beim Auswählen im Editor
   umpositioniert; ::before ist frei.
   Bei .person ist das Pseudo-Element absolut positioniert und damit aus dem
   Fluss – es wird also kein Flex-Item der Karte.
   z-index: -1 legt es HINTER den Inhalt (sonst schneidet es z. B. einen Button
   an, der bis in die Ecke reicht). Innerhalb des isolierten Stacking-Kontexts
   malt der Browser negative z-indizes trotzdem noch ÜBER Rahmen und Hintergrund
   des Kastens – die weiße Fläche im SVG unterbricht die Rahmenlinie also
   weiterhin. */
.is-style-ff-callout::before,
.ff-person-profiles > .person::before {
    content: "";
    position: absolute;
    right: -0.4rem;
    bottom: 1.6rem;
    width: var(--ff-signet-w);
    height: var(--ff-signet-h);
    /* sitzt in der unteren rechten Ecke und ragt über beide Kanten */
    transform: translate(22%, 42%);
    background: var(--ff-signet-url);
    /* prevent a small red subpixel line on the right edge */
    border: 1px solid var(--wp--preset--color--light-color);
    z-index: -1;
    pointer-events: none;
}
.is-style-ff-callout :where(h2, h3, h4, h5) {
  color: var(--wp--preset--color--primary);
}

/* --- Bordeaux-Zitatkasten (Quote- & Pullquote-Block) ---
   Zitattext = innere Absätze, Autor/Quelle = <cite>.
   Der Style liegt bei core/quote am <blockquote>, bei core/pullquote an der
   <figure> – beide Strukturen werden hier abgedeckt. Die Signet-Mechanik greift
   bereits über die gemeinsame .is-style-ff-quotebox-Basis (oben). */
blockquote.wp-block-quote.is-style-ff-quotebox,
figure.wp-block-pullquote.is-style-ff-quotebox {
  color: var(--wp--preset--color--light-color);
  font-style: italic;
  border: 0;
  border-radius: 4px;
  padding: var(--wp--preset--spacing--70, 2.5rem);
  margin-left: 0;
  margin-right: 0;
  background-color: transparent;
}
blockquote.wp-block-quote.is-style-ff-quotebox :where(p, h1, h2, h3, h4, h5, h6),
figure.wp-block-pullquote.is-style-ff-quotebox :where(p, h1, h2, h3, h4, h5, h6) {
  color: var(--wp--preset--color--light-color);
}
/* Autor/Quelle: nicht kursiv, halbfett, gedämpft */
blockquote.wp-block-quote.is-style-ff-quotebox cite,
figure.wp-block-pullquote.is-style-ff-quotebox cite {
  font-style: normal;
  font-weight: 600;
  opacity: 0.85;
}

/* --- Bordeaux-Titelkasten (Overline + Headline + Subline) --- */
.is-style-ff-titlebox {
  color: var(--wp--preset--color--light-color);
  /* Hero nutzt das größere Signet (seitenverhältnistreu) */
  --ff-signet-h: 7.5rem;
  --ff-signet-w: calc(var(--ff-signet-h) * 0.854);
  --ff-signet-right: -1.84rem;
  --ff-signet-bottom: -0.04rem;
}
/* Überschriften in einem Bordeaux-Kasten sind weiß. Diese Regel bleibt
   bewusst hier, anders als die Absatz-Regeln darunter, die am 2026-09-07
   ausgebaut sind: sie unterstellt **keine Rolle** — sie gilt für jede
   Überschrift in jeder Verwendung des Kastens, auch in einer Karte. Und sie
   kostet keine Flexibilität: Core gibt seine Preset-Farbklassen mit
   `!important` aus (`.has-primary-color{color:… !important}`), ein im Editor
   gesetzter `textColor` gewinnt also immer gegen diese Zeile. */
.is-style-ff-titlebox :where(h1, h2, h3, h4, h5, h6) {
  color: var(--wp--preset--color--light-color);
}

/* Hier standen bis zum 2026-09-07 zwei Regeln, die Overline und Subline über
   `> p:first-of-type` / `> p:last-of-type` gestalteten. Sie sind ausgebaut:
   die Rollen gibt es nur im Hero, und in der Karte trafen sie Fließtext und
   Link. Die Optik liegt jetzt in zwei **Block Styles** an `core/paragraph`
   (`ff-titlebox-overline`, `ff-titlebox-subline`, registriert in
   `inc/core/block-style.php`): die Rolle ist damit ausgesprochen statt aus
   der Position geraten, im Editor wähl- und abwählbar, und das gespeicherte
   Markup trägt nur noch die Klasse.

   Typografie und Abstand kommen dort aus `style_data`. Übrig bleibt hier
   allein die Dämpfung — `opacity` hat kein natives Block-Setting und keine
   theme.json-Entsprechung. Sie hängt an derselben Klasse wie der Rest der
   Optik, es gibt also weiterhin genau eine Stelle je Rolle.

   Auf die **nackte** Klasse zu zielen ist Absicht und nutzt aus, dass Core
   sie zusätzlich zu seiner Instanzklasse (`…--2`, `…--3`) im Markup lässt —
   siehe den Gotcha „Block Styles mit `style_data` erzeugen CSS pro Instanz". */
.is-style-ff-titlebox-overline,
.is-style-ff-titlebox-subline {
  opacity: 0.85;
}
/* Titelkasten ragt auf dem Desktop über die Kante des Bildes */
@media (min-width: 782px) {
  .is-style-ff-titlebox {
    z-index: 2;
    margin-right: -3.5rem;
  }
}

/* --- Overlay-Hero (Titelkasten über einem Cover-Bild) ---
   Begrenzte Box-Breite, damit die Cover-Platzierung (contentPosition) die Box
   auch horizontal verschieben kann. Der Spalten-Overlap des Titelkastens wird
   hier neutralisiert (im Cover soll die Box nicht über die Kante ragen). */
.ff-hero-box {
  max-width: 600px;
}
@media (min-width: 782px) {
  .ff-hero-box.is-style-ff-titlebox {
    margin-right: 0;
  }
}
/* Horizontale Zentrierung der Overlay-Box bei mittiger Position.
   WICHTIG: „center center" ist die DEFAULT-Position des Cover-Blocks – dabei
   setzt WordPress KEINE Positionsklassen (weder has-custom-content-position noch
   is-position-*). Ein is-position-Selektor greift dort also nie; wir müssen den
   Default über :not(.has-custom-content-position) mit abdecken. Bei den mittigen
   Positionen bleibt der Inner-Container voll breit (WordPress vergibt width:auto
   nur bei links/rechts), deshalb zentrieren wir die Box selbst per auto-Margins.
   Nur .ff-hero-box, damit andere Cover-Blöcke unberührt bleiben. */
.wp-block-cover:not(.has-custom-content-position) .ff-hero-box,
.wp-block-cover.is-position-top-center .ff-hero-box,
.wp-block-cover.is-position-bottom-center .ff-hero-box {
  margin-left: auto;
  margin-right: auto;
}

/* --- Titelkasten-Heroes auf schmalen Viewports ------------------------------
   Bis 781 px (dem Punkt, an dem WordPress core/columns ohnehin stapelt) kehrt
   sich die Leserichtung um: erst das Bild, darunter der Titelkasten, der 3 rem
   in das Bild hineinragt und dabei seitlich 1,25 rem schmaler bleibt. Der
   Rücksprung ist kein Zierrat – er schafft dem überhängenden &-Signet rechts
   den Platz, den es auf dem Desktop aus dem Spalten-Overlap bezieht
   (margin-right: -3.5rem). Ohne ihn läuft das Signet in den Displayrand.

   Bewusst OHNE eigene Wrapper-Klasse, rein über die Struktur (`:has()`):
   Patterns werden beim Einfügen als statisches Markup in den Beitrag kopiert –
   eine neue Klasse in patterns/*.php erreicht die bereits angelegten Seiten
   nicht. Der Block Style .is-style-ff-titlebox ist dagegen überall vorhanden.
   Deckt damit auch den Beitragskopf (.ff-post-hero in templates/single.html)
   ab, der dieselbe Spaltenstruktur trägt.

   Seit dem Zitat-Karussell nennt jede dieser Regeln BEIDE Bordeaux-Kästen:
   `:is(.is-style-ff-titlebox, .is-style-ff-quotebox)`. Die vier getunten Werte
   (-3rem Rücksprung, 1.25rem bzw. 2rem seitlich, die clamp()-Formel des
   Signets) bleiben dadurch an einer Stelle, statt in einem zweiten Abschnitt
   auseinanderzulaufen. Gegen die Datenbank geprüft: is-style-ff-quotebox kam
   in keinem post_content vor, die Erweiterung konnte also keine Bestandsseite
   verändern. Für neue Inhalte ist sie eine Verhaltensänderung, und zwar eine
   gewollte — jeder Bordeaux-Hero-Kasten in einer Hero-Spalte soll sich mobil
   gleich verhalten. */
@media (max-width: 781px) {

  /* -- Spalten-Varianten (titlebox-hero, -thirds, -full, -full-thirds) -- */

  /* Kein Zeilenabstand zwischen den gestapelten Spalten: die Überlappung
     kommt allein aus dem negativen margin-top des Kastens. blockGap ist im
     Pattern nur horizontal auf 0 gesetzt, row-gap läuft sonst weiter. */
  .wp-block-columns:has(> .wp-block-column > :is(.is-style-ff-titlebox, .is-style-ff-quotebox)) {
    row-gap: 0;
  }
  /* Titelkasten-Spalte ans Ende (Bildspalte bleibt bei order: 0) */
  .wp-block-columns:has(> .wp-block-column > :is(.is-style-ff-titlebox, .is-style-ff-quotebox))
    > .wp-block-column:has(> :is(.is-style-ff-titlebox, .is-style-ff-quotebox)) {
    order: 2;
    position: relative;
    z-index: 1;
  }
  .wp-block-columns:has(> .wp-block-column > :is(.is-style-ff-titlebox, .is-style-ff-quotebox))
    > .wp-block-column > :is(.is-style-ff-titlebox, .is-style-ff-quotebox) {
    margin: -3rem 1.25rem 0;
  }

  /* -- Kasten-Innenmaße für beide Bauarten --
     Signet: der feste Desktop-Wert (7.5rem) füllt in einem 248 px breiten
     Kasten (iPhone SE) fast die halbe Fläche und läuft in die Headline. Statt
     eines harten Sprungs am Umschaltpunkt wächst es fließend mit; 16vw
     erreicht die 7.5rem bei ~750 px, also knapp vor 782 px – der Wechsel zum
     Desktop-Layout bleibt dadurch unsichtbar. Anker (right/bottom) und Breite
     sind aus der Höhe abgeleitet, damit Proportion und Überhang in jeder Größe
     stimmen; der Breitenfaktor ist derselbe wie in den festen Sätzen.
     Padding: die Patterns setzen 2.25rem seitlich / 3.38rem unten als Inline-
     Style; davon blieben dem Text auf 320 px nur 176 px Zeilenbreite. Der
     Inline-Style lässt sich nur mit !important zurücknehmen. */
  .wp-block-columns:has(> .wp-block-column > :is(.is-style-ff-titlebox, .is-style-ff-quotebox))
    > .wp-block-column > :is(.is-style-ff-titlebox, .is-style-ff-quotebox),
  .wp-block-cover:has(.ff-hero-box) .ff-hero-box {
    --ff-signet-h: clamp(4.5rem, 16vw, 7.5rem);
    --ff-signet-w: calc(var(--ff-signet-h) * 0.854);
    --ff-signet-right: calc(var(--ff-signet-h) * -0.245);
    --ff-signet-bottom: calc(var(--ff-signet-h) * -0.015);
    padding: var(--wp--preset--spacing--50) var(--wp--preset--spacing--50)
      var(--wp--preset--spacing--60) !important;
  }
  /* Bild im festen 3:2-Ausschnitt – sonst bestimmt das Seitenverhältnis der
     jeweiligen Datei, wie hoch der Auftakt ausfällt. Der Beitragskopf bringt
     seinen 3:2-Rahmen über .ff-post-hero-media schon selbst mit. */
  .wp-block-columns:has(> .wp-block-column > :is(.is-style-ff-titlebox, .is-style-ff-quotebox))
    .wp-block-image img {
    aspect-ratio: 3 / 2;
    object-fit: cover;
    width: 100%;
  }

  /* -- „über Bild"-Varianten (Cover-Block) --
     Hier gibt es kein Bild im Fluss: der Cover-Block trägt es als absolut
     positioniertes Hintergrundbild und legt die Box darüber. Für dieselbe
     Abfolge holen wir das Bild in den Fluss und lassen den Cover-Block zu
     einem gewöhnlichen Block-Container werden. Die feste Mindesthöhe aus den
     Block-Attributen (520–600 px, auf der Startseite 812 px) muss dabei weg –
     sie ergibt mobil einen sehr hohen Hochkant-Ausschnitt. */
  .wp-block-cover:has(.ff-hero-box) {
    display: block;
    min-height: 0 !important;
    /* Seitenabstand auf denselben Wert wie bei den Spalten-Varianten
       (deren äußere Group nutzt spacing|40); die Cover-Patterns bringen
       inline spacing|50 mit, deshalb !important. */
    padding-left: var(--wp--preset--spacing--40) !important;
    padding-right: var(--wp--preset--spacing--40) !important;
    /* der Signet-Kasten ragt unten über den Kasten hinaus, mobil um 1,5 % der
       Signethöhe */
    overflow: visible;
  }
  .wp-block-cover:has(.ff-hero-box) > img.wp-block-cover__image-background {
    position: relative;
    inset: auto;
    width: 100%;
    height: auto;
    aspect-ratio: 3 / 2;
    border-radius: 4px;
  }
  /* Die Abdunkelungs-Ebene liegt per inset: 0 über dem ganzen Cover-Block –
     also nach dem Umbau auch über dem Titelkasten. Auf die Bildfläche
     eingrenzen (dieselben Ränder, dasselbe Format wie das Bild). */
  .wp-block-cover:has(.ff-hero-box) > .wp-block-cover__background {
    inset: 0 var(--wp--preset--spacing--40) auto;
    aspect-ratio: 3 / 2;
    border-radius: 4px;
  }
  /* Bei den Positionen links/rechts vergibt WordPress width: auto, was als
     Flex-Item Shrink-to-fit bedeutet – der Kasten wird dort nur so breit wie
     sein Text. Im Block-Fluss soll er die volle Breite nutzen. */
  .wp-block-cover:has(.ff-hero-box) > .wp-block-cover__inner-container {
    width: auto;
  }
  /* Überschreibt auch die auto-Margins der mittigen Positionen (gleiche
     Spezifität, spätere Quellreihenfolge). */
  .wp-block-cover:has(.ff-hero-box) .ff-hero-box {
    max-width: none;
    margin: -3rem 1.25rem 0;
  }

  /* -- Bild randlos über die volle Viewport-Breite --
     Betrifft die Spalten-Varianten immer und die „über Bild"-Varianten nur in
     Wide- oder Voll-Breite; das inhaltsbreite `titlebox-hero-image` behält
     seinen Seitenabstand, sonst wäre es von den anderen nicht mehr zu
     unterscheiden. Der Kasten rückt dafür von 1,25 rem auf 2 rem ein — bündig
     zum Displayrand hätte er sonst keinen Abstand mehr zur Kante. */

  /* Spalten-Varianten: die äußere Group ist bereits alignfull und reicht damit
     bis an den Rand, nur ihr eigenes Seitenpadding muss weg. Es kommt als
     Inline-Style aus den Block-Attributen, deshalb !important. Gilt über die
     Struktur auch für den Beitragskopf (.ff-post-hero). */
  .wp-block-group.alignfull:has(
      > .wp-block-columns > .wp-block-column > :is(.is-style-ff-titlebox, .is-style-ff-quotebox)
    ) {
    padding-left: 0 !important;
    padding-right: 0 !important;
  }
  .wp-block-group.alignfull:has(
      > .wp-block-columns > .wp-block-column > :is(.is-style-ff-titlebox, .is-style-ff-quotebox)
    )
    :is(.is-style-ff-titlebox, .is-style-ff-quotebox) {
    margin-left: 2rem;
    margin-right: 2rem;
  }
  /* Randlos heißt eckig: der 4-px-Radius säße sonst an der Displaykante und
     ließe dort einen hellen Keil stehen. Er kommt als Inline-Style aus den
     Block-Attributen, deshalb !important. Beim Beitragskopf sitzt er zusätzlich
     an der Bildspalte selbst (.ff-post-hero-media trägt die neutrale Fläche
     für Beiträge ohne Bild). */
  .wp-block-group.alignfull:has(
      > .wp-block-columns > .wp-block-column > :is(.is-style-ff-titlebox, .is-style-ff-quotebox)
    )
    > .wp-block-columns
    > .wp-block-column img,
  .wp-block-group.alignfull:has(
      > .wp-block-columns > .wp-block-column > :is(.is-style-ff-titlebox, .is-style-ff-quotebox)
    )
    .ff-post-hero-media {
    border-radius: 0 !important;
  }

  /* Cover-Varianten: alignfull reicht schon bis an den Rand, alignwide endet
     am Body-Padding. Der negative Außenabstand holt es zurück und hebt zugleich
     die auto-Margins auf, mit denen das Constrained-Layout alignwide zentriert.
     Fällt --wp--style--root--padding-* weg (useRootPaddingAwareAlignments aus),
     greift der Fallback auf denselben Wert, den theme.json dort einsetzt. */
  .wp-block-cover:has(.ff-hero-box).alignwide,
  .wp-block-cover:has(.ff-hero-box).alignfull {
    padding-left: 0 !important;
    padding-right: 0 !important;
  }
  .wp-block-cover:has(.ff-hero-box).alignwide {
    max-width: none;
    /* !important, weil das Constrained-Layout alignwide selbst mit
       `margin-left: auto !important` zentriert (wp_get_layout_style()) –
       ohne das bliebe der Negativ-Abstand wirkungslos. */
    margin-left: calc(
      -1 * var(--wp--style--root--padding-left, var(--wp--preset--spacing--40))
    ) !important;
    margin-right: calc(
      -1 * var(--wp--style--root--padding-right, var(--wp--preset--spacing--40))
    ) !important;
  }
  /* Die Abdunkelungs-Ebene ist oben auf die Bildfläche eingegrenzt worden und
     trägt dieselben Seitenränder – die fallen hier mit weg. */
  .wp-block-cover:has(.ff-hero-box).alignwide > .wp-block-cover__background,
  .wp-block-cover:has(.ff-hero-box).alignfull > .wp-block-cover__background {
    inset: 0 0 auto;
  }
  .wp-block-cover:has(.ff-hero-box).alignwide .ff-hero-box,
  .wp-block-cover:has(.ff-hero-box).alignfull .ff-hero-box {
    margin-left: 2rem;
    margin-right: 2rem;
  }
  .wp-block-cover:has(.ff-hero-box).alignwide
    > img.wp-block-cover__image-background,
  .wp-block-cover:has(.ff-hero-box).alignfull
    > img.wp-block-cover__image-background,
  .wp-block-cover:has(.ff-hero-box).alignwide > .wp-block-cover__background,
  .wp-block-cover:has(.ff-hero-box).alignfull > .wp-block-cover__background {
    border-radius: 0;
  }
}

/* --- Icon-Block (core/icon): Kreis bleibt Kreis ---
   Core gibt dem SVG `:where(.wp-block-icon) svg { width: 100%; height: 100% }`,
   damit eine am Block gesetzte Breite durchschlägt. Das `height: 100%` ist die
   Falle: steht der Block in einem Container mit *bestimmter* Höhe — etwa in
   einer Karte, die als Flex-Element einer `core/columns`-Zeile auf
   Geschwisterhöhe gestreckt wird — löst sich die Prozentangabe auf, und das
   SVG wird so hoch wie die Karte. Aus der Bordeaux-Scheibe der Services-Karten
   wurde so eine 570 px hohe Ellipse (Seite 382 „Karriere").

   Steht der Block dagegen in einem Container mit inhaltsabhängiger Höhe, ist
   die Prozentangabe unbestimmt und zählt als `auto` — dort fällt der Fehler
   nicht auf. Beim Prüfen also im echten Layout ansehen, nicht freistehend.

   `aspect-ratio: 1` statt einer festen Höhe: die Breite kann aus dem Block
   Style, aus theme.json oder aus dem Editor kommen, das Seitenverhältnis hält
   in allen drei Fällen. Alle Zeichen der Sammlung stehen im quadratischen
   viewBox 32×32, die Angabe verzerrt also nichts.

   Spezifität (0,1,1) gegen Cores (0,0,1) — `:where()` zählt nicht mit. */
.wp-block-icon svg {
  height: auto;
  aspect-ratio: 1;
}

/* --- Icon-Faktenliste ("Auf einen Blick") ---
   Struktur (flach): Overline > Heading > Intro > Zeilen (core/columns). */
/* Jede Zeile ist eine core/columns; Trennlinie zwischen den Zeilen */
.is-style-ff-factlist > .wp-block-columns {
  border-top: 1px solid var(--wp--preset--color--light-grey);
  padding: 0.9rem 0;
  margin-bottom: 0 !important;
  align-items: center;
}
.is-style-ff-factlist > .wp-block-columns:last-child {
  border-bottom: 1px solid var(--wp--preset--color--light-grey);
}
/* Rundes rotes Icon mit weißem Zeichen (ein core/icon pro Zeile).
   Kreis, Farbe und Größe sitzen am <svg>: dorthin legt `core/icon` seine
   Block-Supports (`selectors.root`), und dort greift auch Cores
   `fill: currentColor` — die Zeichenfarbe kommt deshalb als `color`, nicht als
   `fill`. Zusammen mit dem `box-sizing: border-box` aus Cores Block-Stylesheet
   ist das Padding Teil der 2,5 rem, der Kreis bleibt also exakt so groß.

   Bewusst als Child-Regel und nicht über `is-style-ff-icon-kreis`: der Kreis
   gehört zum Bauteil, und er ist hier kleiner als die freistehende Variante
   (2,5 statt 3,75 rem), weil er in einer Listenzeile neben zwei Textzeilen
   sitzt. Das Zeichen deckt dieselben ~45 % des Durchmessers — die
   Glyphicons-Zeichnungen stehen im viewBox 32 nur 24 Einheiten breit, aus
   2,5 rem − 2×0,5 rem = 1,5 rem Zeichenfläche werden also rund 1,125 rem
   sichtbares Zeichen. */
.is-style-ff-factlist .wp-block-icon svg {
  width: 2.5rem;
  height: 2.5rem;
  padding: 0.5rem;
  border-radius: 50%;
  background-color: var(--wp--preset--color--primary);
  color: var(--wp--preset--color--light-color);
}
/* Label (fett) + Wert (kursiv) je Zeile: Textspalte = 2. Spalte der Zeile */
.is-style-ff-factlist .wp-block-columns .wp-block-column:last-child p:first-of-type {
  font-weight: 700;
  margin: 0;
}
.is-style-ff-factlist .wp-block-columns .wp-block-column:last-child p:last-of-type {
  font-style: italic;
  margin: 0;
}

/* --- Lead-Absatz (Einleitung eines Abschnitts) ---
   Reine Typo-Variante ohne Signet, registriert für core/paragraph
   (siehe inc/core/block-style.php). `--wp--preset--font-size--medium` ist
   wegen `fluid: true` in theme.json bereits ein clamp(), die Größe skaliert
   also mit. Selektor bewusst mit Elementtyp (Spezifität 0,1,1), damit die
   Basistypografie der Elemente aus theme.json sicher überschrieben wird;
   eine zusätzlich gewählte Preset-Schriftgröße (`has-*-font-size`, !important)
   gewinnt weiterhin. */
p.is-style-ff-lead {
  font-size: var(--wp--preset--font-size--medium);
  line-height: 1.6;
}

/* --- CTA-Button (Primär-Aktion, z. B. „Termin vereinbaren" im Header) ---
   Nimmt die Formensprache der CI-Signets auf: Bordeaux-Fläche, kleiner Radius
   (derselbe Wert wie die Button-Vorgabe in theme.json), Versalien + Sperrung
   wie Overline/Subline. Bewusst flach — kein Pill-Radius, kein Lift/Schatten.
   Selektor mit .wp-block-button (0,2,0), damit die Element-Styles für Buttons
   aus theme.json (0,1,0) sicher überschrieben werden; im Editor gewählte
   Preset-Farben/-Schriftgrößen (`has-*`, !important) gewinnen weiterhin.

   Der Suchen-Knopf des Beitragsfilters teilt sich diese Regel, statt ihre
   Werte zu kopieren: „Suchen" ist dort die Primär-Aktion und soll dieselbe
   Geste tragen. core/search erlaubt keinen Block Style am Knopf (er steckt im
   Markup des Blocks), deshalb der Klassen-Selektor — ebenfalls (0,2,0), und
   Cores eigene Vorgaben stehen in `:where()`, zählen also nicht.

   Aus demselben Grund hängt der Absende-Knopf des Kontaktformulars mit drin:
   „Anfrage senden" ist die Primär-Aktion jenes Abschnitts, und Contact
   Form 7 rendert sein `<input type="submit">` selbst — ein Block Style ist
   dort nicht zu vergeben. Wer die CTA-Optik ändert, fasst diese eine
   Stelle an.

   Dasselbe gilt für den „Ansehen"-Knopf der Stellenliste und „Jetzt
   bewerben" auf der Stellenseite (Plugin job-postings). Ihr Selektor trägt
   `:root` vorn, weil die Plugin-Regeln
   NACH dieser Datei kommen und bis (0,4,1) reichen — siehe Abschnitt
   „Stellenanzeigen". */
.wp-block-button.is-style-ff-cta > .wp-block-button__link,
.ff-postfilter .wp-block-search__button,
.ff-kontaktformular .wpcf7-submit,
:root .job-listing .job-preview .job-cta .apply-btn,
:root .job-post .jp-apply-button {
  background-color: var(--wp--preset--color--primary);
  color: var(--wp--preset--color--light-color);
  border: 0;
  border-radius: 0.375em;
  padding: 0.85em 1.5em;
  font-size: var(--wp--preset--font-size--small);
  font-weight: 700;
  line-height: 1.2;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  transition: background-color 0.2s ease;
}
/* Hover/Fokus auf den helleren Bordeaux-Ton der Palette (statt Lift + Schatten) */
.wp-block-button.is-style-ff-cta > .wp-block-button__link:hover,
.wp-block-button.is-style-ff-cta > .wp-block-button__link:focus,
.ff-postfilter .wp-block-search__button:hover,
.ff-postfilter .wp-block-search__button:focus,
.ff-kontaktformular .wpcf7-submit:hover,
.ff-kontaktformular .wpcf7-submit:focus,
:root .job-listing .job-preview:is(:hover, :focus-within) .job-cta .apply-btn,
:root .job-post .jp-apply-button:is(:hover, :focus) {
  background-color: var(--wp--preset--color--bordeaux-82);
  color: var(--wp--preset--color--light-color);
}

/* --- CTA auf dunklem Grund (`ff-cta-invers`) ---
   Dieselbe Geometrie und Typografie wie `ff-cta` oben, nur die beiden Farben
   getauscht: weisse Flaeche, Bordeaux-Schrift. Fuer Aktionen IM
   Bordeaux-Titelkasten, wo der gefuellte CTA in seinem Grund verschwaende.
   Wer an der Geometrie dreht, zieht beide Regeln nach — sie sind absichtlich
   nicht zusammengelegt, damit jede für sich lesbar bleibt.

   Der Hover geht auf `background-alt` und behaelt die Bordeaux-Schrift; ein
   Wechsel auf Bordeaux-Flaeche liesse den Knopf im Kasten verschwinden. */
.wp-block-button.is-style-ff-cta-invers > .wp-block-button__link {
  background-color: var(--wp--preset--color--light-color);
  color: var(--wp--preset--color--primary);
  border: 0;
  border-radius: 0.375em;
  padding: 0.85em 1.5em;
  font-size: var(--wp--preset--font-size--small);
  font-weight: 700;
  line-height: 1.2;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  text-decoration: none;
  transition: background-color 0.2s ease;
}
.wp-block-button.is-style-ff-cta-invers > .wp-block-button__link:hover,
.wp-block-button.is-style-ff-cta-invers > .wp-block-button__link:focus {
  background-color: var(--wp--preset--color--background-alt);
  color: var(--wp--preset--color--primary);
}

/* ============================================================
   Beiträge: Übersicht (Archiv, Blog-Startseite, Suche, Fallback-Index)
   und Kopf des Einzelbeitrags

   Die Listen-Templates `templates/archive.html`, `home.html`, `search.html`
   und `index.html` teilen sich dieselbe Karte. Die Klassen sind reine
   Utilities und bewusst NICHT über register_block_style registriert: sie
   gehören zu den Templates, nicht in die Stil-Auswahl im Editor.

   | Klasse         | sitzt an                                      |
   |----------------|-----------------------------------------------|
   | .ff-post-card  | core/group je Beitrag im Loop                  |
   | .ff-pagination | core/query-pagination, core/comments-pagination |

   Formensprache wie die CI-Signets oben: flach, 4px-Radius, Bordeaux als
   Akzent – kein Schatten, kein Lift, keine Pillen-Radien.
   ============================================================ */

/* --- Beitragsbild ---
   Der feste 3:2-Ausschnitt kommt aus dem Block-Attribut `aspectRatio`, damit
   die Kacheln einer Reihe gleich hoch starten. `overflow: hidden` begrenzt den
   Hover-Zoom auf den Bildausschnitt; die Fläche darunter fängt Beiträge ohne
   Beitragsbild neutral ab. */
.ff-post-card .wp-block-post-featured-image {
  overflow: hidden;
  border-radius: 4px;
  background-color: var(--wp--preset--color--background-alt);
}
.ff-post-card .wp-block-post-featured-image img {
  transition: transform 0.35s ease;
}
.ff-post-card:hover .wp-block-post-featured-image img,
.ff-post-card:focus-within .wp-block-post-featured-image img {
  transform: scale(1.03);
}

/* --- Titel ---
   Schrift (Miranda Sans) und Größe kommen aus theme.json bzw. dem Block; hier
   nur die Verlinkung, die sonst die globale Link-Farbe (Bordeaux) erbt. */
.ff-post-card .wp-block-post-title a {
  color: var(--wp--preset--color--foreground);
  text-decoration: none;
  transition: color 0.2s ease;
}
.ff-post-card .wp-block-post-title a:hover,
.ff-post-card .wp-block-post-title a:focus {
  color: var(--wp--preset--color--primary);
}

/* --- Beitragskopf: Titelkasten-Hero (templates/single.html) ---
   Übernimmt die Optik von patterns/titlebox-hero.php: Bordeaux-Titelkasten
   links (44%), Beitragsbild rechts (56%), alignfull-Group mit constrained-
   Layout auf 1380px (nicht die Vollbreiten-Variante). Fläche, Signet und
   helle Textfarbe kommen aus dem Block Style .is-style-ff-titlebox.

   Nötig ist hier nur, was der Block Style NICHT abdeckt: Er adressiert Overline
   und Subline über die <p>-Kinder (`> p:first-of-type` / `:last-of-type`), im
   Beitrag liefern diese Rollen aber core/post-terms (Kategorie) und
   core/post-date (Datum) – beides <div>. Ohne die Regeln unten bliebe der
   Kategorie-Link außerdem in Bordeaux auf Bordeaux stehen. */

.ff-post-hero .wp-block-post-terms,
.ff-post-hero .wp-block-post-date {
  color: var(--wp--preset--color--light-color);
  opacity: 0.85;
}
/* Die Overline zeigt ALLE Kategorien des Beitrags (3–6 bei den Bestands-
   beiträgen), als durchgehende Versalien-Kette. Die Typografie sitzt deshalb
   am Container und nicht am <a>: sonst blieben die Trenner
   (.wp-block-post-terms__separator, „, ") als einzige ungesperrt und normal
   gewichtet zwischen den Versalien stehen. */
.ff-post-hero .wp-block-post-terms {
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  line-height: 1.2;
}
.ff-post-hero .wp-block-post-terms a {
  color: inherit;
  text-decoration: none;
}
.ff-post-hero .wp-block-post-date {
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
/* Bildspalte im festen 3:2-Ausschnitt. Die neutrale Fläche trägt die 7 (von
   227) Beiträge ohne Beitragsbild: dort bleibt die Spalte sonst leer und der
   Hero steht halb im Nichts. Bei gesetztem Bild deckt dieses sie vollständig. */
.wp-block-column.ff-post-hero-media {
  aspect-ratio: 3 / 2;
  border-radius: 4px;
  background-color: var(--wp--preset--color--background-alt);
}
.ff-post-hero-media .wp-block-post-featured-image,
.ff-post-hero-media .wp-block-post-featured-image img {
  height: 100%;
}

/* --- Blätter-Navigation ---
   Versalien + Sperrung wie CTA und Overline, abgesetzt durch eine Haarlinie.
   `.page-numbers` deckt Zahlen (a) und die aktuelle Seite (span) ab.
   Abstände gehören hierher, nicht ins Template: core/query-pagination
   unterstützt margin/padding nicht – im Block gesetzte Werte fallen weg. */
.ff-pagination {
  margin-top: var(--wp--preset--spacing--70);
  padding-top: var(--wp--preset--spacing--50);
  border-top: 1px solid var(--wp--preset--color--light-grey);
}
.ff-pagination a,
.ff-pagination .page-numbers {
  font-size: var(--wp--preset--font-size--small);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--wp--preset--color--foreground);
}
.ff-pagination a:hover,
.ff-pagination a:focus,
.ff-pagination .page-numbers.current {
  color: var(--wp--preset--color--primary);
}

/* ============================================================
   Beitragsfilter: Suche und Themen-Chips

   Der Template-Part `parts/beitragsfilter.html` steht in allen vier
   Listen-Templates (`home.html`, `archive.html`, `search.html`, `index.html`)
   zwischen Kopf und Kachelraster: zwei Spalten, links auf 2/3 die Kategorien
   als Chip-Reihe (`core/terms-query` + `core/term-template` +
   `core/term-name`), rechts auf 1/3 ein `core/search`-Feld. Beide Spalten
   oeffnen mit einer `ff-overline`, damit sie auf derselben Linie beginnen.
   Unter 782 px stapelt `core/columns` von sich aus — dann steht erst Themen,
   dann Suche.

   `.ff-postfilter` und `.ff-topic-chips` sind — wie `.ff-post-card` und
   `.ff-pagination` — reine Utilities und bewusst NICHT über
   `register_block_style()` registriert: sie gehören zu den Templates, nicht in
   die Stil-Auswahl im Editor.

   Die Flex-Zeile der Chips kommt aus dem Block-Layout des `core/term-template`
   (`layout.type: flex`, `flexWrap: wrap`), nicht von hier — unten stehen nur
   Optik und Zustände. Welche Kategorien überhaupt erscheinen und welcher Chip
   als der aufgerufene markiert wird, entscheidet `inc/core/term-list.php`.
   ============================================================ */

/* Cores Vorgaben für Feld und Knopf stehen durchweg in `:where()`
   (Spezifität 0), eine Ein-Klassen-Regel genügt also.

   Die Breite gibt im Normalfall die 1/3-Spalte vor; die Deckelung greift erst,
   wenn `core/columns` unter 782 px stapelt und das Feld sonst über die ganze
   Zeile liefe. Deshalb hier als `max-width` und nicht über das
   `width`/`widthUnit`-Attribut des Blocks — das setzt eine feste Breite und
   nimmt der Spalte die Kontrolle. */
.ff-postfilter .wp-block-search {
  max-width: 480px;
}
/* Radius wie beim Knopf (`0.375em`, der Button-Wert aus theme.json) und nicht
   wie bei den Karten (4px) — Feld und Knopf sitzen als ein Paar in einer Zeile
   und sollen dieselbe Kante haben. */
.ff-postfilter .wp-block-search__input {
  border: 1px solid var(--wp--preset--color--light-grey);
  border-radius: 0.375em;
  padding: 0.75em 1em;
  background-color: var(--wp--preset--color--light-color);
  color: var(--wp--preset--color--foreground);
}
.ff-postfilter .wp-block-search__input:focus-visible {
  outline: 2px solid var(--wp--preset--color--primary);
  outline-offset: 1px;
  border-color: var(--wp--preset--color--primary);
}

/* Themen-Chips: Formensprache der Karten (`ff-post-card`, `ff-refcard`) —
   flach, Haarlinie, 4px, Bordeaux beim Hover. Die Chip-Fläche sitzt am `<a>`,
   damit die ganze Fläche klickbar ist; `core/term-name` rendert `<p><a>…</a></p>`
   in einem `<li>`, das Core selbst schon auf `list-style: none` setzt.
   Der globale Unterstrich aus style.css greift hier nicht — er hängt an
   `.entry-content.wp-block-post-content a`, die Leiste steht im Template. */
.ff-topic-chips .wp-block-term-name {
  margin: 0;
}
.ff-topic-chips .wp-block-term-name a {
  display: inline-block;
  padding: 0.45em 1em;
  border: 1px solid var(--wp--preset--color--light-grey);
  border-radius: 4px;
  font-size: var(--wp--preset--font-size--small);
  font-weight: 600;
  line-height: 1.4;
  color: var(--wp--preset--color--foreground);
  text-decoration: none;
  transition: color 0.2s ease, border-color 0.2s ease, background-color 0.2s ease;
}
.ff-topic-chips .wp-block-term-name a:hover,
.ff-topic-chips .wp-block-term-name a:focus-visible {
  color: var(--wp--preset--color--primary);
  border-color: var(--wp--preset--color--primary);
}
/* Der Chip „Alle" (eingesetzt in `inc/core/term-list.php`) traegt bewusst
   dieselbe Optik wie die Themen. Ein zusaetzlicher Abstand dahinter, um ihn
   als Zuruecksetzen abzuheben, war ausprobiert und wieder verworfen: schon
   7px kosteten bei 1280px eine ganze Zeile — „Wellness" stand allein in
   Zeile 3. Die gefuellte Markierung sagt ohnehin, welcher Zustand gilt.

   Aufgerufenes Thema — und auf der Beitragsseite der Chip „Alle". Das
   `aria-current` setzt `inc/core/term-list.php`: core/term-template kennt das
   Queried Object nicht. */
.ff-topic-chips .wp-block-term-name a[aria-current="page"] {
  background-color: var(--wp--preset--color--primary);
  border-color: var(--wp--preset--color--primary);
  color: var(--wp--preset--color--light-color);
}

/* ============================================================
   Akkordeon (core/accordion)
   ============================================================ */

/* Ein geschlossenes Panel bleibt mit `hidden="until-found"` im Layout stehen:
   Core setzt darauf nur `content-visibility: hidden` und nimmt die Blocklücke
   weg (`margin-block-start: 0`), der Innenabstand des Panels zählt aber weiter
   und wächst als leerer Streifen unter der Überschrift auf. Im Editor fällt
   das nicht auf, weil dort kein geschlossener Zustand gerendert wird. Der
   Abstand kommt als Inline-Style aus den Block-Attributen – deshalb !important. */
.wp-block-accordion-panel[hidden] {
  padding-top: 0 !important;
  padding-bottom: 0 !important;
}

/* Block Style „Mit Unterzeile" (ff-accordion-subline): der kursive Teil des
   Titels wird zur Kurzzeile darunter – kleiner, aufrecht, in der Fließtext-
   Schrift. Gedämpft über `opacity` statt über eine Farbe, damit dieselbe
   Regel auf hellem wie auf Bordeaux-Grund trägt (wie die Titelkasten-Rollen).
   `hyphens: manual` nimmt die Silbentrennung der Überschriften zurück:
   die Kurzzeile ist Fließtext. */
.wp-block-accordion.is-style-ff-accordion-subline .wp-block-accordion-heading__toggle-title em {
  display: block;
  margin-top: 0.4rem;
  font-family: var(--wp--preset--font-family--inter);
  font-size: var(--wp--preset--font-size--small);
  font-style: normal;
  font-weight: 400;
  line-height: 1.6;
  letter-spacing: normal;
  hyphens: manual;
  text-wrap: pretty;
  opacity: 0.8;
}

/* ============================================================
   Personen & Team (Plugin-Block fritzufritz/person)

   Der Person-Block (Plugin `fritzufritz-blocks`) ist ein dynamischer Block
   OHNE eigenen Wrapper: er gibt direkt `<div class="row person">` mit den
   Bootstrap-Klassen `.col-sm-4` (Bild) / `.col-sm-8` (Text) aus – ein Erbe des
   Ursprungs-Themes, dessen Grid-CSS es im 2026-Theme nicht mehr gibt. Die
   Regeln hier ersetzen dieses Grid und geben beiden Ansichten ihr Layout:

   - `view: "compact"` (Default) -> Name + Meta (Ausbildung, Abteilung, [T]/[F],
     Mail). Gedacht für die Team-Übersicht, siehe .ff-team-grid.
   - `view: "detailed"`          -> Name + Fließtext aus dem Mitarbeiter-Post.
     Gedacht für Einzelprofile, siehe .ff-person-profiles.

   Beide Wrapper-Klassen werden im Block-Markup der Seite als `className` an
   eine core/group gesetzt; die Person-Blöcke sind deren direkte Kinder.
   ============================================================ */

/* --- Basis: Bild links, Text rechts (aus dem Bootstrap-Row-Rest) --- */
.person {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: var(--wp--preset--spacing--40);
}
.person > .col-sm-4 {
  flex: 0 0 auto;
  width: 9rem;
}
/* Ohne Beitragsbild bleibt die Bildspalte leer -> keine Lücke reißen */
.person > .col-sm-4:empty {
  display: none;
}
.person > .col-sm-8 {
  flex: 1 1 16rem;
  min-width: 0;
}
/* WordPress-Core floatet `.alignleft` global; im Flex-Layout unerwünscht. */
.person img {
  display: block;
  float: none;
  width: 100%;
  height: auto;
  margin: 0;
  border-radius: 4px;
}
.person .name {
  font-family: var(--wp--preset--font-family--miranda-sans, inherit);
  font-size: var(--wp--preset--font-size--medium);
  font-weight: 600;
  line-height: 1.25;
  margin: 0 0 0.35rem;
}
.person .data {
  font-size: var(--wp--preset--font-size--small);
  line-height: 1.5;
  margin: 0 0 0.6rem;
}
/* Kontaktzeilen (letzter data-Absatz = Mail) etwas gedämpft */
.person .data:last-child {
  margin-bottom: 0;
}

/* --- Team-Übersicht: Karten-Raster (view "compact") --- */
.ff-team-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
  gap: var(--wp--preset--spacing--50);
}
/* Der Flow-Layout-Abstand von WordPress (`:where(.is-layout-flow) > *`) würde
   im Grid zusätzliche Lücken erzeugen – hier neutralisieren. Die Core-Regel hat
   trotz `:where()` die Spezifität 0,1,0 (durch `:not(:first-child)`) und wird
   je nach Reihenfolge NACH blocks.css ausgegeben – daher hier 0,2,0 über die
   zusätzliche `.wp-block-group`-Klasse. */
.wp-block-group.ff-team-grid > * {
  margin-block-start: 0;
  margin-block-end: 0;
}
/* Karte: Bild oben, Text darunter */
.ff-team-grid > .person {
  display: block;
  padding: var(--wp--preset--spacing--30);
  border: 1px solid var(--wp--preset--color--light-grey);
  border-radius: 4px;
  background-color: var(--wp--preset--color--light-color);
}
.ff-team-grid > .person > .col-sm-4 {
  width: 100%;
  margin-bottom: 0.9rem;
}
/* Ohne Portrait bleibt im Raster eine neutrale Fläche stehen, damit die
   Namenszeilen aller Karten einer Reihe auf einer Höhe beginnen. */
.ff-team-grid > .person > .col-sm-4:empty {
  display: block;
  aspect-ratio: 3 / 2;
  border-radius: 4px;
  background-color: var(--wp--preset--color--background-alt);
}
.ff-team-grid > .person > .col-sm-8 {
  width: 100%;
}
/* Alle Mitarbeiterportraits liegen im Querformat 3:2 vor. Fest gesetzt, damit
   eine abweichend beschnittene Neu-Aufnahme das Raster nicht verspringen lässt. */
.ff-team-grid > .person img {
  aspect-ratio: 3 / 2;
  object-fit: cover;
  object-position: top center;
}

/* --- Einzelprofile: breite Karte, Bild links (view "detailed") --- */
.ff-person-profiles {
  display: grid;
  gap: var(--wp--preset--spacing--50);
}
.wp-block-group.ff-person-profiles > * {
  margin-block-start: 0;
  margin-block-end: 0;
}
/* Die Karte trägt die Callout-Optik: Bordeaux-Rahmen, 0.7rem-Radius, gleicher
   Innenabstand und das überhängende &-Signet. Diese Eigenschaften stehen oben
   im CI-Abschnitt bei .is-style-ff-callout (gemeinsame Selektorliste, damit
   beide nicht auseinanderlaufen); hier nur, was die Flex-Struktur braucht. */
.ff-person-profiles > .person {
  gap: var(--wp--preset--spacing--50);
}
.ff-person-profiles > .person > .col-sm-4 {
  width: 12.5rem;
}
.ff-person-profiles > .person .name {
  font-size: var(--wp--preset--font-size--large);
  color: var(--wp--preset--color--primary);
}
/* Erster Absatz nach dem Namen = Ausbildung/Funktionen (mit <br> getrennt) */
.ff-person-profiles > .person > .col-sm-8 > p.name + p {
  font-weight: 600;
  margin-top: 0;
}
.ff-person-profiles > .person > .col-sm-8 > p:last-child {
  margin-bottom: 0;
}

@media (max-width: 599px) {
  .person > .col-sm-4 {
    width: 7rem;
  }
  .ff-person-profiles > .person > .col-sm-4 {
    width: 8rem;
  }
}

/* ============================================================
   Referenz- und Partnerkarten

   Vier Patterns teilen sich diese beiden Karten: `referenz-box` /
   `referenzen-grid-masonry` und `partner-box` /
   `partner-grid-masonry`. Das Block-Markup steht genau einmal in
   `inc/core/pattern-cards.php`.

   Die Optik liegt fast vollständig in Block-Einstellungen, nicht hier:

   | Block Style (inc/core/block-style.php) | trägt als style_data             |
   |----------------------------------------|----------------------------------|
   | .is-style-ff-refcard (core/group)      | Fläche, Rahmen, Radius, Padding  |
   | .is-style-ff-partnercard (core/group)  | dasselbe                         |
   | .is-style-ff-cardlink-download (p)     | Typo, Padding, Linkfarbe + Hover |
   | .is-style-ff-cardlink-extern (p)       | dasselbe                         |

   Der Rest steckt als Block-Attribut im Markup: Ortszeile (`spacing.margin`
   plus Preset `small`), Autorenzeile (`typography.lineHeight`, `textColor`),
   Partnerlogo (`width: 100%`). `height: auto` hängt Core selbst an, sobald
   es die width/height-Attribute für CLS ergänzt.

   Hier steht nur noch, was sich weder als Block-Einstellung noch als
   style_data ausdrücken lässt.
   ============================================================ */

/* --- Karte: Flex-Mechanik + Zustände ---
   Die Karte ist ein Flex-Container, damit der Link am Kartenfuß per
   `margin-top: auto` unten andocken kann: in einer Spalte laufen die Karten
   unterschiedlich hoch, die Links sollen trotzdem auf einer Linie sitzen.
   Dafür gibt es keine Block-Einstellung — `verticalAlignment: space-between`
   wäre der nächste Kandidat, verteilt den Freiraum aber zwischen ALLEN
   Kindern und würde Überschrift und Ortszeile auseinanderziehen. */
.wp-block-group.is-style-ff-refcard,
.wp-block-group.is-style-ff-partnercard {
  display: flex;
  flex-direction: column;
}
/* Das Constrained-Layout der Karte gibt jedem Kind `margin-left/right: auto`
   (mit !important, siehe wp_get_layout_style()). Im normalen Fluss bleibt das
   folgenlos, weil Blockboxen die Breite ohnehin füllen — als Flex-Item
   bemisst sich die Breite dagegen am Inhalt, und die Auto-Ränder zentrieren
   jede Zeile. Die volle Breite nimmt ihnen den Spielraum zurück. */
.wp-block-group.is-style-ff-refcard > *,
.wp-block-group.is-style-ff-partnercard > * {
  width: 100%;
  max-width: none;
}

/* --- Link am Kartenfuß ---
   Typografie und Innenabstand liefern die beiden Block Styles. Hier bleibt,
   was style_data nicht durchsetzen kann:

   Die Ausrichtung am Kartenfuß und die Zeile aus Marker + Text (keine
   Block-Einstellung greift auf das <a> im Absatz). Der Marker steckt im
   Pseudo-Element und nicht im Text — sonst läse ein Screenreader
   „Pfeil nach unten Referenzbericht als PDF".

   Und die Linkfarbe. Über `elements.link` in style_data erzeugt Core
   `:root :where(… a…)` mit Spezifität (0,1,0); das verliert gegen die
   `.wp-elements-*`-Regel, die `page.html` aus dem `elements.link` seines
   `main` erzeugt (0,1,1) — gemessen kam Foreground statt Primary heraus.

   Die Unterstreichung braucht sogar (0,2,1): `style.css` setzt sie über
   `.entry-content.wp-block-post-content a` für alle Links im Seiteninhalt.
   Deshalb hier `.wp-block-paragraph` mit im Selektor (die Klasse hängt Core
   selbst an den Absatz) — gleiche Spezifität, und `blocks.css` lädt nach
   `style.css`. Mit nur einer Klasse blieb der Link unterstrichen. */
.is-style-ff-cardlink-download,
.is-style-ff-cardlink-extern {
  margin-top: auto;
}
.wp-block-paragraph.is-style-ff-cardlink-download a,
.wp-block-paragraph.is-style-ff-cardlink-extern a {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  color: var(--wp--preset--color--primary);
  text-decoration: none;
  transition: color 0.2s ease;
}
.wp-block-paragraph.is-style-ff-cardlink-download a:hover,
.wp-block-paragraph.is-style-ff-cardlink-download a:focus,
.wp-block-paragraph.is-style-ff-cardlink-extern a:hover,
.wp-block-paragraph.is-style-ff-cardlink-extern a:focus {
  text-decoration: underline;
}
.is-style-ff-cardlink-download a::before {
  content: "\2193"; /* ↓ Download */
  font-size: 1.15em;
  line-height: 1;
}
.is-style-ff-cardlink-extern a::after {
  content: "\2197"; /* ↗ fremde Website */
  font-size: 1.15em;
  line-height: 1;
}

/* ============================================================
   Zitat-Kacheln (Utility `ff-zitatkacheln`)

   Raster aus kurzen Stimmen, z. B. die Kununu-Zitate auf 382. Raster,
   Kachelflaeche, Radius und Innenabstand sind Block-Einstellungen; hier steht
   nur das grosse Anfuehrungszeichen, das kein Block-Attribut kann. Als
   Pseudo-Element mit leerem Alternativtext, damit ein Screenreader es nicht
   vorliest — die Zeichen gehoeren deshalb auch nicht in den Text.
   ============================================================ */
.ff-zitatkacheln > * > p:first-child::before {
  content: "\201C" / "";
  display: block;
  margin-bottom: 0.15em;
  color: var(--wp--preset--color--primary);
  font-family: var(--wp--preset--font-family--miranda-sans);
  font-size: 3rem;
  font-weight: 700;
  line-height: 0.6;
}

/* ============================================================
   Google-Bewertungen (Block Styles `ff-reviewcard` und `ff-googlebox`)

   Zwei Bauteile fuer dieselbe Quelle: die Ueberblick-Box mit Note, Sternen
   und Zahl der Rezensionen (`patterns/google-bewertungen.php`) und die
   einzelne Rezension als Karte in der Bahn des Karten-Karussells
   (`patterns/karussell-rezensionen.php`, Markup aus
   `inc/core/pattern-cards.php`).

   Flaeche, Haarlinie und Radius kommen als `style_data` von den beiden Block
   Styles in `inc/core/block-style.php` — hier steht nur, was sich dort nicht
   ausdruecken laesst: Avatarkreis, Sternenreihe und das `inline-flex` der Box.
   ============================================================ */

/* --- Sternenreihe ---
   Utility-Klasse wie `.ff-overline`: die Optik steckt vollstaendig hier, das
   Markup traegt nur `className`. Bewusst keine Block-Attribute fuer Farbe und
   Groesse — das erspart die Frage, in welcher Reihenfolge Gutenberg
   `ff-stars`, `has-secondary-color` und `has-text-color` in die Klasse
   schreibt, und eine falsch geratene Reihenfolge ist im Editor ein
   Validierungsfehler.

   Die Glyphen (★ / ☆) stehen als Text im Absatz und nicht in einem
   Pseudo-Element wie die ↓/↗-Marker der Kartenlinks: ihre Zahl ist Inhalt und
   nicht Dekoration, sie muss sich je Karte aendern lassen. Der Preis ist, dass
   ein Screenreader die Glyphen vorliest. */
.ff-stars {
  color: var(--wp--preset--color--secondary);
  letter-spacing: 0.08em;
  line-height: 1;
}

/* --- Avatarkreis ---
   Ein Absatz mit der Initiale, kein Bild: die Profilbilder von Google liegen
   auf deren Servern und duerfen von hier nicht nachgeladen werden (derselbe
   Grund, aus dem das Rezensions-Widget nicht eingebunden wird), und ein
   `core/image` an dieser Stelle zoege ohnehin die 3:2-Regel der Bahn auf sich.

   Masse in rem wie bei den Icon-Kreisen, damit der Kreis bei vergroesserter
   Browser-Schrift mitwaechst. `flex: none`, weil er in einer Flex-Zeile neben
   zwei Textzeilen steht und sonst schrumpft. */
.ff-avatar {
  flex: none;
  display: grid;
  place-content: center;
  inline-size: 2.75rem;
  block-size: 2.75rem;
  border-radius: 50%;
  background-color: var(--wp--preset--color--primary);
  color: var(--wp--preset--color--light-color);
  font-weight: 700;
  line-height: 1;
}

/* --- Rezensionskarte: waagerechter Innenabstand ---
   Im Karussell setzt ihn die Bahn als `--ff-card-pad` (Abschnitt
   „Karten-Karussell"), deshalb steht er nicht im `style_data` des Block
   Styles — dort kaeme er als Instanz-CSS und schluege die Bahn-Regel, und die
   negativen Raender eines randlosen Kartenbildes gingen nicht mehr auf.

   Hier ist der Rueckfall fuer die freistehende Verwendung: dieselbe Variable
   mit demselben Wert als Vorgabe. In der Bahn gewinnt deren Regel ueber die
   Quellreihenfolge, das Ergebnis ist in beiden Faellen `spacing|60`. */
.wp-block-group.is-style-ff-reviewcard {
  padding-inline: var(--ff-card-pad, var(--wp--preset--spacing--60));
}

/* --- Ueberblick-Box ---
   Hier steht bewusst NICHTS zur Breite. Dass die Box auf ihre Inhaltsbreite
   schrumpft und dabei buendig zur Inhaltsspalte beginnt, loest das Pattern
   ueber eine Flex-Zeile um sie herum — CSS kann es nicht:

   Cores Constrained-Layout gibt jedem Kind `max-width: <contentSize>` und
   `margin-inline: auto !important`. Ein `width: fit-content` zentriert die Box
   damit. Ein `display: inline-flex` entkommt zwar den Auto-Raendern (bei
   inline-level Boxen greifen sie nicht), landet dafuer aber am linken Rand des
   **vollbreiten** `post-content` statt auf der Inhaltsspalte — am 2026-09-20
   nachgemessen: 16 px statt 230 px bei 1440 px Viewport, also 214 px links
   neben der Ueberschrift darueber.

   Als Kind eines Flex-Containers bekommt die Box beides von selbst: keine
   Auto-Raender, und die Zeile ist ein gewoehnliches constrained-Kind und
   beginnt auf der Inhaltsspalte. Der Container ist zugleich der Hebel, mit dem
   die Redaktion die Box im Editor links, mittig oder rechts stellt. */

/* Das G in der Ueberblick-Box ist ein Bildblock und kein Icon aus der
   Bibliothek: deren Sanitizer nimmt jedem Pfad das `fill`, damit die Zeichen
   `currentColor` folgen — die vier Markenfarben ueberlebten das nicht. Als
   Bildblock bleibt es im Editor zudem austauschbar. */
.is-style-ff-googlebox img {
  inline-size: 1.25rem;
  block-size: auto;
}

/* --- Das G vor dem Fusslink der Rezensionskarte ---
   Als Pseudo-Element und nicht als Bildblock im Markup — derselbe Gedanke wie
   bei den ↓/↗-Markern der Kartenlinks: ein Screenreader laese sonst „Grafik
   Google Auf Google ansehen". Und der Fusslink bleibt damit **ein** Absatz,
   behaelt also das `margin-block-start: auto`, mit dem die Bahn ihn am
   Kartenboden andockt; eine Flex-Zeile aus Bild plus Absatz haette das
   verschoben.

   Eingegrenzt auf `.is-style-ff-reviewcard`: `ff-cardlink-extern` traegt auch
   die Partnerkarten und die Ueberblick-Box. In der Box steht das G schon in
   der Kopfzeile, vor ihrem Fusslink waere es eine Dublette.

   `background-image` und **nicht** `mask-image` wie bei den uebrigen
   SVG-Markern des Themes: die sind einfarbig und folgen `currentColor`, das G
   muss seine vier Markenfarben behalten.

   Die Groesse in `em`, damit das Zeichen der Schriftgroesse des Links folgt
   (x-small), so wie das ↗ daneben ueber `font-size: 1.15em` mitwaechst. */
.is-style-ff-reviewcard .is-style-ff-cardlink-extern a::before {
  content: "";
  flex: none;
  inline-size: 1.25em;
  block-size: 1.25em;
  background-image: url(../images/google-g.svg);
  background-repeat: no-repeat;
  background-position: center;
  background-size: contain;
}

/* In der Box steht die Sternenreihe neben der grossen Note und darf daneben
   nicht verschwinden. */
.is-style-ff-googlebox .ff-stars {
  font-size: var(--wp--preset--font-size--medium);
}


/* ============================================================
   Google-Maps-Einbettung (Shortcode [fuf-map])

   Der Shortcode stammt aus dem Plugin `fritzufritz_plugin`
   (`inc/shortcodes/class-shortcode-googlemaps.php`) und gibt sein iframe in
   einem `<div class="embed-responsive embed-responsive-16by9">` aus – dieselbe
   Bootstrap-Erbschaft wie beim Person-Block, deren Grid-/Utility-CSS es im
   2026-Theme nicht mehr gibt. Ohne Ersatz hätte das iframe keine Höhe.

   `embed-privacy` ersetzt das iframe serverseitig durch eine
   Zustimmungs-Ebene; das Original steht bis dahin nur als JSON in einem
   `<script>`. Nach der Zustimmung schreibt das Plugin-JS es per `innerHTML`
   **nicht** an seinen alten Platz zurück, sondern in
   `.embed-privacy-container > .embed-privacy-content` — das iframe ist danach
   also ein Enkel und kein Kind mehr. Deshalb sind es drei Selektoren: ohne den
   letzten stünde die Karte nach dem Zustimmen in der Standardgröße eines
   ersatzlosen iframes (300 × 150 px) in der linken oberen Ecke des Rahmens.

   Höhe und Breite des `.embed-privacy-content` bringt das Plugin selbst mit
   (`height/width: 100%`, `display: none` bis zur Zustimmung), seinem iframe
   gibt es aber nur ein `max-height/max-width: 100%` — eine Obergrenze, keine
   Größe.
   ============================================================ */
.embed-responsive-16by9 {
  position: relative;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  border-radius: 4px;
}
.embed-responsive-16by9 > iframe,
.embed-responsive-16by9 > .embed-privacy-container,
.embed-responsive-16by9 .embed-privacy-content > iframe {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
}

/* ============================================================
   Logo-Slider (Block Style `ff-logoslider` an core/group)

   Zwei Ebenen, weil ein Element sich nicht selbst beschneiden kann, während es
   wandert: `overflow` gilt für Nachkommen, ein `clip-path` säße im
   transformierten Koordinatensystem. Die **Gruppe** ist deshalb der ruhende
   Rahmen (Hintergrund, Innenabstand, Zuschnitt, Positionsbezug für den
   Schalter), das eingesetzte **`.ff-logoslider__track`** das Laufband.

   Editor und Frontend trennt der Track, den `inc/core/logo-slider.php`
   einsetzt: `blocks.css` lädt über `add_editor_style()` auch im Editor, dieses
   Element gibt es dort aber nicht. Alles, was sich bewegt, hängt deshalb an
   `:has(> .ff-logoslider__track)`.

   Kein `gap` in diesem Abschnitt — der Track erbt ihn per `gap: inherit` von
   der Gruppe, wo er als ganz normales `blockGap` steht. Dass ein glattes
   `-50%` trotzdem exakt aufgeht, besorgt `.ff-logoslider__end` (siehe unten).
   ============================================================ */
.wp-block-group.is-style-ff-logoslider:has(> .ff-logoslider__track) {
  display: block;
  position: relative;
  overflow: hidden;
}

.ff-logoslider__track {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  width: max-content;
  gap: inherit;
  will-change: transform;
  animation: ff-logoslider-scroll linear infinite;

  /* `--ff-logoslider-items` setzt der Render-Filter inline auf die Anzahl der
     Logos: so bleibt das Tempo konstant, statt mit jedem weiteren Logo zu
     steigen. Der zweite Wert ist das Tempo je Logo und der Griff, an dem sich
     die Geschwindigkeit ändern lässt. */
  animation-duration: calc(var(--ff-logoslider-items, 8) * var(--ff-logoslider-pace, 3s));
}

/* `-50%` geht exakt auf, weil `.ff-logoslider__end` die Lückenzahl ausgleicht:
   ohne es trägt der Track `2n` Logos, aber nur `2n − 1` Lücken, und die halbe
   Trackbreite wäre um eine halbe Lücke kürzer als eine Satzlänge. */
@keyframes ff-logoslider-scroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

/* --- Anhalten: Schalter, Fokus, Zeigergerät --- */

/* Die Fokus-Pause hängt am Track, nicht am Rahmen: sonst zählte der
   Pause-Schalter mit, und nach einem Klick auf „Fortsetzen" bliebe das Band
   stehen, solange er den Fokus hat. Im Track sind nur die Logos — greift also
   erst, wenn sie verlinkt sind. */
.ff-logoslider__track.is-paused,
.ff-logoslider__track:focus-within {
  animation-play-state: paused;
}

/* Kein Hover auf Touch: dort bleibt der Zustand nach einem Tipper kleben und
   das Band stünde dauerhaft. */
@media (hover: hover) {
  .wp-block-group.is-style-ff-logoslider:hover > .ff-logoslider__track {
    animation-play-state: paused;
  }
}

/* Der Schalter ist WCAG 2.2 SC 2.2.2 („Pause, Stop, Hide") und sitzt im
   ruhenden Rahmen, nicht im Track — dort würde er mitwandern. Zurückhaltend:
   eine kleine Scheibe unten rechts, kein zweiter Blickfang neben den Logos. */
.ff-logoslider__pause {
  position: absolute;
  right: 1rem;
  bottom: 0.75rem;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  padding: 0;
  border: 1px solid var(--wp--preset--color--light-grey);
  border-radius: 50%;
  background-color: var(--wp--preset--color--light-color);
  color: var(--wp--preset--color--foreground);
  cursor: pointer;
}
.ff-logoslider__pause:hover,
.ff-logoslider__pause:focus-visible {
  border-color: var(--wp--preset--color--primary);
  color: var(--wp--preset--color--primary);
}
.ff-logoslider__icon {
  display: block;
  fill: currentColor;
}
/* Ein Zeichen je Zustand; `aria-pressed` trägt die Information ohnehin schon. */
.ff-logoslider__pause .ff-logoslider__icon--play,
.ff-logoslider__pause[aria-pressed="true"] .ff-logoslider__icon--pause {
  display: none;
}
.ff-logoslider__pause[aria-pressed="true"] .ff-logoslider__icon--play {
  display: block;
}
/* Beschriftung nur für Screenreader — das Theme bringt kein globales
   `.screen-reader-text` mit. */
.ff-logoslider__label {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* --- Struktur --- */

/* `display: contents` hängt die Kopien direkt in die Flex-Reihe des Tracks:
   ein Satz Abstände für alle Logos, ohne zweite Ebene. */
.ff-logoslider__clone {
  display: contents;
}

/* Trägt nur die Lücke vor sich — der Ausgleich, der `-50%` exakt macht. */
.ff-logoslider__end {
  width: 0;
}

/* Der erste Selektor greift im Editor, wo es den Track nicht gibt. */
.is-style-ff-logoslider > *,
.ff-logoslider__track > *,
.ff-logoslider__clone > * {
  margin: 0;
  flex-shrink: 0;
}

/* Feste Höhe, Breite nach Seitenverhältnis der Datei. Das setzt voraus, dass
   die Logos einen einheitlichen Zeichenrahmen mitbringen — sonst laufen die
   Breiten weit auseinander (bei den 16 Partnerlogos aus Seite 465 von 35 px
   im Hochformat bis 215 px im Querformat) und einzelne Marken erdrücken im
   Band die anderen. Der Ausgleich gehört in die Bilddatei, nicht hierher —
   derselbe Punkt wie bei den Partnerkarten. */
.is-style-ff-logoslider img {
  /* `!important` ist hier Pflicht, kein Zierrat: der Bildblock schreibt im
     Editor ein Inline-`style="height:auto"` an das `<img>` (dazu `width`/
     `height` als Attribute), und ein Inline-Style schlägt jede Regel aus dem
     Stylesheet. Ohne das lief ein 2560er Logo im Editor auf volle Dateibreite
     auf, während `max-width: none` aus derselben Regel längst griff. Im
     Frontend steht das Attribut nicht im Markup, dort wäre es entbehrlich. */
  height: var(--ff-logoslider-logo-height, 3.5rem) !important;
  width: auto;
  max-width: none;
  /* Monochrom: die Logos bringen sehr unterschiedliche Hausfarben mit,
     entsättigt lesen sie als eine Reihe statt als bunte Sammlung. Bewusst über
     eine Variable, damit sich der Grad je Instanz zurücknehmen lässt.

     Bewusst hier am Band und nicht als Block Style an den einzelnen
     Bildblöcken: der wäre pro Bild opt-in, und ein später im Editor
     ergänztes Logo stünde farbig zwischen den grauen. Die Entsättigung
     gehört zum Band, nicht zum einzelnen Bild. (Bis 2026-09-06 gab es dafür
     `is-style-fritz-fritz-2026-image-grayscale` aus dem Vorlagen-Theme; der
     Style ist mit den übrigen ungenutzten ausgebaut.) Den Übergang stellt
     die globale Transition auf `img` ganz oben in dieser Datei. */
  filter: grayscale(var(--ff-logoslider-grayscale, 1));
}

/* Das überfahrene Logo bekommt seine Farbe zurück — aber ohne den
   `scale(1.03)`, den der ausgebaute Graustufen-Style dabei mitbrachte: in
   einem laufenden, beschnittenen Band wäre das eine zweite Bewegung. Nur
   auf Zeigergeräten, sonst bliebe auf Touch nach einem Tipper ein Logo
   farbig stehen — und dort
   steht das Band ohnehin still, sobald die Maus darauf liegt. */
@media (hover: hover) {
  .is-style-ff-logoslider img:hover {
    filter: grayscale(0);
  }
}

/* Editor: die Reihe steht, bricht nicht um und ist von Hand scrollbar. */
.wp-block-group.is-style-ff-logoslider:not(:has(> .ff-logoslider__track)) {
  flex-wrap: nowrap;
  overflow-x: auto;
}

/* Erste Berücksichtigung von `prefers-reduced-motion` im Theme. Der Klon muss
   weg, sonst stünde jedes Logo doppelt; der Schalter auch, weil es dann nichts
   anzuhalten gibt. */
@media (prefers-reduced-motion: reduce) {
  .wp-block-group.is-style-ff-logoslider:has(> .ff-logoslider__track) {
    overflow-x: auto;
  }
  .ff-logoslider__track {
    animation: none;
    width: auto;
  }
  .ff-logoslider__clone,
  .ff-logoslider__pause {
    display: none;
  }
}

/* Ohne diese Regel ist das `hidden` im Markup des Schalters wirkungslos: die
   UA-Regel `[hidden] { display: none }` hat Spezifität (0,0,1) und verliert
   gegen das `display: flex` der Regel oben (0,1,0). Der Schalter stand damit
   auch ohne JS da — als toter Knopf, genau was das `hidden` verhindern sollte.
   Der Attribut-Selektor kommt auf (0,2,0) und braucht kein `!important`.
   Am 2026-09-06 nachgemessen und behoben. */
.ff-logoslider__pause[hidden] {
  display: none;
}
/* ============================================================
   Slider-Bahn (geteilte Mechanik aller waagerechten Bahnen)

   Was jede Bahn des Themes gemeinsam hat: ein Scroll-Container mit
   Snap-Punkten, eine verborgene Bildlaufleiste und die Bedienleiste davor.
   Was eine Bahn *ausmacht* — wie breit ihre Kinder sind, wie sie senkrecht
   ausgerichtet werden — steht in ihrem eigenen Abschnitt darunter.

   Das bricht bewusst die Konvention „CSS steht geschlossen im Abschnitt X":
   wer die Mechanik anfasst, fasst alle Bahnen an. Der Gegenwert ist, dass es
   Snap-Verhalten und Bedienleiste genau einmal gibt.

   Was Cores Flex-Layout selbst liefert, steht hier NICHT: `display: flex`,
   `flex-wrap: nowrap` und der `gap` aus dem `blockGap` kommen aus dem
   Layout-Attribut der Gruppe
   (`{"type":"flex","flexWrap":"nowrap", …}`).
   Das ist keine Geschmacksfrage: bei `constrained` legte Core den `blockGap`
   als `margin-block-start` an die Kinder — in einer waagerechten Reihe also
   als senkrechten Rand, die Karten stünden ohne Abstand nebeneinander. Und
   jedes Kind bekäme `margin-inline: auto !important`, derselbe Gotcha wie bei
   den Referenzkarten, nur eine Ebene höher.
   ============================================================ */
.wp-block-group.is-style-ff-cardslider,
.wp-block-group.is-style-ff-quoteslider {
  overflow-x: auto;
  overscroll-behavior-x: contain; /* kein Zurück-Wischen der Seite am Bahnende */
  scroll-snap-type: x mandatory;

  /* Keine Bildlaufleiste — Kundenwunsch vom 2026-09-20 für das
     Karten-Karussell, das bis dahin als einzige Bahn eine sichtbare trug.
     Auf Windows ist sie eine klassische, dauerhaft eingeblendete Leiste und
     stand damit als graues Band unter den Karten; macOS blendet dieselbe
     Leiste nur während des Scrollens ein, weshalb es hier lange nicht auffiel.

     Verloren geht damit die einzige Anzeige, die sich beim Wischen mitbewegt.
     Die Punkte der Bedienleiste übernehmen den Stand der Bahn, der Anreißer
     die Affordanz „hier geht es weiter", und WCAG 2.2 SC 2.5.7 („Dragging
     Movements") ist über die Pfeile erfüllt — die Bahn ist also weiterhin
     ohne Ziehen bedienbar. Gescrollt werden kann sie unverändert per
     Wischen, Trackpad und Tabulator.

     `scrollbar-width` trägt Chrome/Edge ab 121, Firefox seit je und Safari ab
     18.2; die `::-webkit-scrollbar`-Regel darunter deckt ältere Fassungen ab.
     Beides gehört zusammen. */
  scrollbar-width: none;
}

.wp-block-group.is-style-ff-cardslider::-webkit-scrollbar,
.wp-block-group.is-style-ff-quoteslider::-webkit-scrollbar {
  display: none;
}

/* Rastpunkt an der linken Kante jedes Kindes. Bewusst hier und nicht bei der
   Kartenbreite: die Kante ist Mechanik, die Breite ist Gestaltung — und beide
   Bahnen rasten gleich ein. */
.is-style-ff-cardslider > *,
.is-style-ff-quoteslider > * {
  scroll-snap-align: start;
}

/* Das weiche Gleiten der Pfeile hängt am CSS, nicht am Script — deshalb
   berücksichtigt es die Media Query hier einmal für beide Wege (Knopfdruck
   und `scrollTo`). */
@media (prefers-reduced-motion: no-preference) {
  .wp-block-group.is-style-ff-cardslider,
  .wp-block-group.is-style-ff-quoteslider {
    scroll-behavior: smooth;
  }
}

/* --- Editor ---
   `blocks.css` lädt über add_editor_style() auch im Editor. Gutenberg klammert
   diese Regeln in `:where(.editor-styles-wrapper)` und lässt Selektoren in
   Ruhe, die die Klasse selbst nennen — das ist hier die Weiche, die es beim
   Logo-Slider als Klon-Element gibt. Im Frontend existiert die Klasse nicht,
   die Regel ist dort tot.

   Das Snapping muss weg: der Editor scrollt bei jeder Blockauswahl den Block
   in den Blick, das Snapping zieht hinterher, und beim Tippen in eine Karte
   springt die Bahn. */
.editor-styles-wrapper .is-style-ff-cardslider,
.editor-styles-wrapper .is-style-ff-quoteslider {
  scroll-snap-type: none;
}

/* ============================================================
   Bedienleiste der Slider-Bahnen (`ff-slider__*`)

   Punkte und Pfeile, gebaut von `fritz_fritz_2026_slider_nav()` in
   `inc/core/slider-nav.php` — dort steht auch, warum es die Knöpfe überhaupt
   gibt (WCAG 2.2 SC 2.5.7) und warum die Leiste VOR der Bahn steht.

   Die Klassen hießen bis zum Herauslösen `ff-cardslider__*`. Sie entstehen
   ausschließlich beim Rendern und kommen in `post_content` nicht vor
   (nachgemessen, inkl. Revisionen) — die Umbenennung erreicht deshalb keine
   Bestandsseite.

   Sie trägt dieselbe Ausrichtungsklasse wie die Bahn (`alignwide`), sonst
   deckelte das Constrained-Layout des `post-content` sie auf Inhaltsbreite
   und die Pfeile stünden nicht über der rechten Kante der Bahn.
   ============================================================ */
.ff-slider__nav {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 0.5rem;
}

/* Die Punkte sind eine Gruppe, die Pfeile eine zweite — der größere Abstand
   dazwischen trennt „wo bin ich" von „weiter". */
.ff-slider__dots {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  margin-inline-end: var(--wp--preset--spacing--40);
}
/* Der Punkt ist ein Knopf, kein Schmuck — die Trefferfläche muss den Kreis
   überragen (WCAG 2.5.8 Target Size, mindestens 24 × 24 px). Der Kreis steckt
   deshalb im Pseudo-Element, der Knopf selbst ist unsichtbar und groß. */
.ff-slider__dot {
  display: grid;
  place-content: center;
  inline-size: 1.5rem;
  block-size: 1.5rem;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}
.ff-slider__dot::before {
  content: "";
  inline-size: 0.5rem;
  block-size: 0.5rem;
  border: 1px solid var(--wp--preset--color--primary);
  border-radius: 50%;
  transition: background-color 0.2s ease;
}
.ff-slider__dot[aria-current="true"]::before,
.ff-slider__dot:hover::before {
  background-color: var(--wp--preset--color--primary);
}

/* Flach und ohne Lift, wie `is-style-ff-cta` und der Pause-Schalter des
   Logo-Sliders: das Theme kennt keine schwebenden Knöpfe. Der Kreis ist hier
   die Ausnahme, weil ein Pfeil in einem Rechteck wie ein zweiter CTA läse. */
.ff-slider__arrow {
  display: grid;
  place-content: center;
  inline-size: 2.75rem;
  block-size: 2.75rem;
  padding: 0;
  border: 1px solid var(--wp--preset--color--primary);
  border-radius: 50%;
  background: none;
  color: var(--wp--preset--color--primary);
  cursor: pointer;
  transition: background-color 0.2s ease, color 0.2s ease;
}
/* Das Zeichen ist ein SVG und keine Glyphe (frueher &lsaquo;/&rsaquo;): ein
   Schriftzeichen bringt seine eigenen Seitenraender und seine Grundlinie mit
   und sitzt dadurch sichtbar aus der Mitte. Das SVG ist quadratisch und
   zentriert sich geometrisch. `display: block` nimmt ihm den Zeilenabstand,
   den es als Inline-Element sonst haette. */
.ff-slider__arrow svg {
  display: block;
  inline-size: 1rem;
  block-size: 1rem;
}
.ff-slider__arrow:hover,
.ff-slider__arrow:focus-visible {
  background-color: var(--wp--preset--color--primary);
  color: var(--wp--preset--color--light-color);
}
/* An den Enden der Bahn setzt das Script `disabled`. Bewusst sichtbar lassen
   statt auszublenden — sonst sprängen die Pfeile beim Scrollen. */
.ff-slider__arrow[disabled] {
  opacity: 0.35;
  cursor: default;
}
.ff-slider__arrow[disabled]:hover {
  background: none;
  color: var(--wp--preset--color--primary);
}

/* --- Pause-Schalter ---
   Gibt es nur an Bahnen mit Autoplay; `fritz_fritz_2026_slider_nav()` baut ihn
   dort in dieselbe Leiste. Er ist WCAG 2.2 SC 2.2.2 („Pause, Stop, Hide") und
   kein Komfort: bewegte Inhalte über fünf Sekunden brauchen ein echtes
   Bedienelement — die Hover- und Fokus-Pause des Scripts ist keins, sie ist auf
   Touch nicht vorhanden und setzt nur vorübergehend aus.

   Dieselbe Form wie die Pfeile, aber 2rem statt 2,75rem: er ist Nebenbedienung,
   nicht Navigation. Im Markup steht er VOR den Punkten und ist damit der erste
   Tab-Stopp der Leiste — wer anhalten will, soll nicht erst durch vier Punkte.
   Unter `prefers-reduced-motion` blendet ihn das Script aus (`pause.hidden`),
   nicht das CSS: dort besitzt JS die Bewegung, und beim Umlegen der
   Systemeinstellung stimmt es so zur Laufzeit. */
.ff-slider__pause {
  display: grid;
  place-content: center;
  inline-size: 2rem;
  block-size: 2rem;
  padding: 0;
  border: 1px solid var(--wp--preset--color--primary);
  border-radius: 50%;
  background: none;
  color: var(--wp--preset--color--primary);
  cursor: pointer;
  transition: background-color 0.2s ease, color 0.2s ease;
}
.ff-slider__pause:hover,
.ff-slider__pause:focus-visible {
  background-color: var(--wp--preset--color--primary);
  color: var(--wp--preset--color--light-color);
}
.ff-slider__icon {
  display: block;
  inline-size: 0.75rem;
  block-size: 0.75rem;
  fill: currentColor;
}
/* Ein Zeichen je Zustand; `aria-pressed` trägt die Information ohnehin schon. */
.ff-slider__pause .ff-slider__icon--play,
.ff-slider__pause[aria-pressed="true"] .ff-slider__icon--pause {
  display: none;
}
.ff-slider__pause[aria-pressed="true"] .ff-slider__icon--play {
  display: block;
}
/* --- `hidden` wirksam machen ---
   **Pflicht, kein Zierrat.** Jedes Teil der Leiste trägt oben eine eigene
   `display`-Regel (`flex` bzw. `grid`) mit Spezifität (0,1,0). Die UA-Regel
   `[hidden] { display: none }` hat nur (0,0,1) und verliert — das
   `hidden`-Attribut ist an diesen Elementen also **wirkungslos**, solange es
   nicht ausdrücklich nachgezogen wird. Nachgemessen am 2026-09-06: mit
   gesetztem `hidden` stand die Leiste weiter 1380 px breit da und der
   Pause-Schalter 32 px.

   Drei Dinge hingen daran und funktionierten nicht:
   - „Ohne JS steht dort keine tote Leiste" — sie stand doch da, mit
     Knöpfen, die nichts tun.
   - `sync()` blendet die Leiste aus, wenn alle Folien nebeneinander passen
     (`nav.hidden = rest <= 1`) — das griff nie.
   - Das Ausblenden des Pause-Schalters unter `prefers-reduced-motion`.

   Der Attribut-Selektor kommt auf (0,2,0) und schlägt die `display`-Regeln
   ohne `!important`. Wer der Leiste ein weiteres Teil mit eigener
   `display`-Regel hinzufügt, ergänzt es hier. */
.ff-slider__nav[hidden],
.ff-slider__dots[hidden],
.ff-slider__dot[hidden],
.ff-slider__arrow[hidden],
.ff-slider__pause[hidden] {
  display: none;
}

/* Unter Reduced Motion läuft kein Autoplay (siehe `assets/js/sliders.js`), es
   gibt also nichts anzuhalten. Bewusst hier im CSS und nicht per
   `pause.hidden` im Script — dieselbe Lösung wie beim Logo-Slider: die Media
   Query reagiert von sich aus zur Laufzeit, trägt auch ohne JS, und es bleibt
   bei einer Quelle der Wahrheit. Der erste Entwurf setzte das Attribut aus
   `arm()` und lief genau in die Falle darüber. */
@media (prefers-reduced-motion: reduce) {
  .ff-slider__pause {
    display: none;
  }
}

/* Beschriftung nur für Screenreader — das Theme bringt kein globales
   `.screen-reader-text` mit. Denselben Regelsatz nutzt der Logo-Slider unter
   `.ff-logoslider__label`; hier steht er ein zweites Mal, weil die beiden
   Bauteile sonst nichts miteinander zu tun haben. */
.ff-slider__label {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ============================================================
   Karten-Karussell (Block Style `ff-cardslider` an core/group)

   Die Gruppe ist selbst die Bahn: ein Scroll-Container mit Snap-Punkten. Die
   Kinder sind gewöhnliche Karten — auf der Startseite die vorhandenen
   `is-style-ff-callout`-Kästen. Ihre Optik fasst der Slider nicht an, nur
   Breite und innere Achse.

   Die gemeinsame Bahn-Mechanik und die Bedienleiste stehen in den beiden
   Abschnitten darüber; hier steht nur, was diese Bahn von anderen
   unterscheidet. Ihre Bedienleiste stellt `inc/core/card-slider.php` voran,
   dort steht auch, warum die Bahn kein `tabindex` bekommt.
   ============================================================ */
.wp-block-group.is-style-ff-cardslider {
  /* Überhang des Karten-Signets über die Kartenkante. Eine Karte kann den
     Callout ODER den Titelkasten tragen, und ihre Signets ragen verschieden
     weit — hier steht deshalb jeweils das GRÖSSERE der beiden, sonst stünde
     die Spitze des größeren jenseits des Paddings.

     | Karte       | rechts                              | unten            |
     |-------------|-------------------------------------|------------------|
     | Callout     | 0.4rem + 22 % von 3.76rem = 1.23rem | 0.29rem          |
     | Titelkasten | `--ff-signet-right` = 1.10rem       | 0.07rem          |

     Der Callout ist in beiden Achsen der größere Fall, weil der Titelkasten
     in der Karte auf Callout-Größe läuft (siehe „Kleineres Signet in der
     Titelkasten-Karte"). Wer an den Signetmaßen dreht, zieht diese beiden
     Werte nach. */
  --ff-cardslider-bleed-inline: 1.23rem;
  --ff-cardslider-bleed-block: 0.29rem;
  /* Der Anreißer: so viel von der nächsten Karte bleibt sichtbar. Er ist die
     eigentliche Affordanz — ohne ihn sähe die Bahn aus wie eine volle Reihe. */
  --ff-cardslider-peek: var(--wp--preset--spacing--50);
  /* Muss mit dem `blockGap` der Gruppe übereinstimmen; geht in die
     Kartenbreite ein. Untergrenze ist der seitliche Signet-Überhang von
     1.23rem — bei kleinerem Abstand läuft das Signet einer Karte in die
     nächste. spacing|60 = 2.25rem hat genug Luft, spacing|40 = 1rem nicht. */
  --ff-cardslider-gap: var(--wp--preset--spacing--60);

  /* Gleiche Kartenhöhe kommt als `verticalAlignment: stretch` aus dem
     Blockattribut. Hier steht sie als Sicherung, falls jemand im Editor die
     vertikale Ausrichtung verstellt: sie ist konstruktiv, nicht dekorativ —
     nur so sitzen die Fuß-Links auf einer Linie.

     Bewusst NICHT in der geteilten Bahn-Mechanik: die Regel hat Spezifität
     (0,2,0), Cores Layout-Attribut liefert `align-items` nur über die
     Instanzklasse `.wp-container-core-group-is-layout-…` mit (0,1,0). Geteilt
     überstimmte dieses `stretch` also das `verticalAlignment` jeder anderen
     Bahn — die könnte ihre senkrechte Ausrichtung dann nicht mehr über den
     Editor bestimmen. */
  align-items: stretch;

  /* `overflow-x: auto` (siehe „Slider-Bahn") macht `overflow-y` laut CSS
     Overflow 3 zu `auto` („a specified value of visible computes to auto").
     Der Signet-Überhang nach unten würde damit zu scrollbarem Überlauf samt
     senkrechter Bildlaufleiste — er wird also nicht beschnitten, sondern
     schiebt eine zweite Scrollachse ins Bild. Das Padding nimmt ihn in die
     Padding-Box auf, bevor er das kann. Nach rechts ist dasselbe Padding
     zugleich der Auslauf am Bahnende.

     Bewusst kein `padding-inline-start`: Karte 1 soll auf einer Linie mit der
     Überschrift darüber beginnen. Käme dort je ein Einzug hinzu, braucht
     `scroll-padding-inline-start` denselben Wert — sonst schnappt Karte 2
     unter das Padding. */
  padding-inline: 0 var(--ff-cardslider-bleed-inline);
  padding-block: 0 var(--ff-cardslider-bleed-block);
}

/* --- Kartenbreite ---
   „Bahnbreite minus Anreißer minus eine Lücke", nach oben gedeckelt auf die
   24rem, die das abgelöste Raster als `minimumColumnWidth` trug. Der
   Prozentwert bezieht sich auf die Content-Box der Bahn, das Padding aus dem
   Signet-Überhang ist also schon abgezogen. Deshalb kommt diese Reihe ohne
   Media Query aus. Nachgemessen im Frontend:

      343px Bahn (375er-Viewport)  → Karte 267px → 1 Karte + 56px Anreißer
     1380px Bahn (alignwide)       → Karte 384px → 3 Karten + Anreißer

   Der Prozentwert löst sich nicht ganz auf die sichtbare Bahnbreite auf,
   die 267px sind gemessen und nicht 343 − 90 gerechnet. Für das Ergebnis ist
   das gleichgültig: gebraucht wird „eine Karte plus sichtbarer Rest", nicht
   ein bestimmter Pixelwert.

   Bei 1380px ist die Bahn 4 × 384 + 3 × 36 = 1644px breit (plus Padding
   gemessene 1664px) — sie bleibt also auch auf dem Desktop scrollbar, sonst
   wäre die Bedienleiste sinnlos.

   `scroll-snap-stop` bleibt `normal`: bei zwei bis drei sichtbaren Karten
   würde `always` das Wischen nur bremsen. Der Rastpunkt selbst steht in der
   geteilten Bahn-Mechanik. */
.is-style-ff-cardslider > * {
  flex: 0 0 clamp(
    15rem,
    100% - var(--ff-cardslider-peek) - var(--ff-cardslider-gap),
    24rem
  );
}

/* --- Die Karte IM Slider ---
   Rollenunabhängig auf `> *` und nicht mehr auf `.is-style-ff-callout`: die
   Bahn soll nicht wissen muessen, welchen Block Style eine Karte traegt. Bis
   zum 2026-09-07 hing das hier am Callout — als der Kunde die Karten auf den
   Titelkasten umstellte, fiel die halbe Mechanik lautlos aus.

   Dieselbe Flex-Spalte wie bei `ff-refcard` (siehe „Referenz- und
   Partnerkarten"), auf den Slider begrenzt: `patterns/callout.php`,
   `parts/newsletter-hinweis.html` und die Bestandsseiten sehen davon nichts. */
.is-style-ff-cardslider > * {
  display: flex;
  flex-direction: column;
}

/* Nur der WAAGERECHTE Innenabstand steht hier — das Bild hebt ihn mit
   negativen Rändern wieder auf, dafür muss der Wert an einer Stelle stehen,
   und ein Inline-Padding könnte das CSS nicht nachrechnen.

   Alle **senkrechten** Abstände der Karte kommen dagegen aus dem Markup:
   `padding.top`/`padding.bottom` als Block-Attribut, und der Rhythmus
   zwischen Bild, Überschrift, Text und Aktion als `blockGap`. Beides ist im
   Editor je Karte einstellbar.

   Das setzt voraus, dass die Karte auf `layout: flex` mit `orientation:
   vertical` steht — nur dort gibt Core den `blockGap` als echtes `gap` am
   Container aus. Im `constrained`-Layout würde daraus ein
   `margin-block-start` an den Kindern, und das verlöre am letzten Kind gegen
   dessen `margin-block-start: auto` (siehe „Aktion am Kartenfuß").

   Links und rechts derselbe Wert: der Titelkasten hält rechts sonst
   spacing|80 (5,06rem) frei, damit Text dem &-Signet ausweicht — auf 980px
   Inhaltsbreite unauffällig, in einer 384px-Karte 21 % der Breite.
   Nachgemessen greift das Signet nur 42px weit und nur im untersten Streifen;
   ausweichen muss allein die letzte Zeile.

   Spezifität (0,2,0) plus Quellreihenfolge schlägt die Grundregel von
   `.wp-block-group.is-style-ff-titlebox` weiter oben. */
.wp-block-group.is-style-ff-cardslider > * {
  --ff-card-pad: var(--wp--preset--spacing--60);
  padding-inline: var(--ff-card-pad);
}

/* Das Constrained-Layout IN der Karte gibt jedem Kind `margin-inline: auto
   !important`. Im Fluss folgenlos, weil Blockboxen die Breite ohnehin fuellen —
   als Flex-Item bemisst sich die Breite am Inhalt, und die Auto-Raender
   zentrieren jede Zeile. Die volle Breite nimmt ihnen den Spielraum. */
.is-style-ff-cardslider > * > * {
  width: 100%;
  max-width: none;
}

/* --- Kleineres Signet in der Titelkasten-Karte ---
   Freistehend trägt der Titelkasten das Hero-Signet (7,5 rem hoch) — in einer
   384 px breiten Karte ist das ein Drittel der Kartenbreite und erschlägt
   sie. Hier läuft es auf Callout-Größe.

   Die Höhe ist der BASIS-Satz des Titelkastens (6 rem, im Abschnitt „Das
   &-Signet an gefüllten Bordeaux-Kästen") mal 0,75, die Breite folgt ihr über
   den viewBox-Faktor: 4,5 / 3,84 rem. Die Callout-Karte daneben ist gleich
   hoch und mit 3,76 rem gut einen Pixel schmaler — sie zieht ihre Breite aus
   ihrem eigenen, anders proportionierten SVG.

   Überstand und Tiefstand skalieren nicht mit: 1,10 und 0,07 rem sind eigene,
   von Hand abgenommene Werte. Wer an der Größe dreht, nimmt sie am Ergebnis
   neu ab und nicht am Faktor.

   Spezifität (0,2,0) gegen die (0,1,0) von `.is-style-ff-titlebox`. */
.is-style-ff-cardslider > .is-style-ff-titlebox {
  --ff-signet-h: 4.5rem;
  --ff-signet-w: calc(var(--ff-signet-h) * 0.854);
  --ff-signet-right: -1.10rem;
  --ff-signet-bottom: -0.06rem;
}

/* --- Bild oben: festes Seitenverhältnis, beide Kartenarten ---
   Damit die Überschriften aller Karten auf einer Linie starten, unabhängig
   vom Ausschnitt des eingesetzten Motivs. */
.is-style-ff-cardslider > * > figure.wp-block-image:first-child img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 3 / 2;
  object-fit: cover;
}

/* --- Nur die Titelkasten-Karte: Bild randlos auf der Kartenkante ---
   Kundenwunsch „Bild groesser, roter Kasten": vorher sass es INNERHALB des
   Innenabstands und war in einer 691px hohen Karte nur 179px hoch. Die
   negativen Raender heben `--ff-card-pad` genau auf, das Bild liegt damit auf
   der Kartenkante und der Bordeaux-Grund beginnt darunter.

   Bewusst **nicht** an `> *`: die Callout-Karte hat eine Haarlinie und
   0,7rem Radius — ein Bild bis an die Kante schnitte dort die Rahmenlinie an.
   Der gefuellte Titelkasten hat das Problem nicht.

   Bewusst kein `overflow: hidden` an der Karte, um die oberen Ecken zu
   runden: das schnitte das &-Signet ab, das unten rechts über die Kante
   ragt. Stattdessen tragen die oberen Ecken des Bildes denselben 4px-Radius
   wie die Karte.

   `width: auto` nimmt der Regel weiter oben ihr `width: 100%` zurueck — mit
   ihm waere die Figur um die beiden negativen Raender zu breit. */
.is-style-ff-cardslider > .is-style-ff-titlebox > figure.wp-block-image:first-child {
  width: auto;
  /* `!important` ist hier Pflicht, nicht Nachdruck: die Karte ist eine
     `constrained`-Gruppe, und Cores Layout-Regel gibt jedem Kind
     `margin-left/right: auto !important` (`wp_get_layout_style()`). Gegen ein
     `!important` kommt keine Spezifität an — nachgemessen blieb das Bild
     ohne diese Zeile um den Innenabstand eingerückt statt randlos.
     Bei den Referenzkarten reicht dafür `width: 100%`, weil dort ein Rand
     von 0 genügt; ein NEGATIVER Rand lässt sich so nicht durchsetzen. */
  margin-inline: calc(-1 * var(--ff-card-pad)) !important;
}

/* --- Aktion am Kartenfuss ---
   Die Karten sind gleich hoch, ihre Texte nicht — ohne den `auto`-Rand
   staenden die Knoepfe auf vier verschiedenen Linien.

   Den **Mindestabstand** darüber liefert der `gap` der Karte, nicht diese
   Regel — und das ist der Grund, warum die Karte ein echtes Flex-Layout
   braucht: `gap` und `margin-block-start: auto` stehen sich nicht im Weg. Ein
   `blockGap` aus dem `constrained`-Layout käme dagegen als
   `margin-block-start` an den Kindern an und würde hier vom `auto`
   überschrieben — auf der längsten Karte fiele der Abstand dann auf 0 und die
   Aktion klebte am Text.

   Bewusst `> :last-child` und nicht `> p:last-child`: die Aktion ist im
   Titelkasten-Karussell ein `core/buttons`, im Callout-Karussell ein Absatz. */
.is-style-ff-cardslider > * > :last-child {
  margin-block-start: auto;
}

/* Zwei Editor-Eigenheiten dieser Bahn bleiben und sind kein Fehler: der
   Einfüge-Appender steht als letztes Flex-Item am Bahnende und muss
   angescrollt werden, und Karten sortiert man über die Listenansicht um — der
   Editor scrollt die waagerechte Bahn beim Ziehen nicht mit. */

/* ============================================================
   Zitat-Karussell (Block Style `ff-quoteslider` an core/group)

   Wie das Karten-Karussell eine Scroll-Snap-Bahn (siehe „Slider-Bahn" und die
   gemeinsame Bedienleiste weiter oben), aber mit **einer** Folie je Blick und
   mit Autoplay. Jede Folie ist eine Hero-Zeile: links ein Zitatkasten
   (`is-style-ff-quotebox`), rechts das Bild — dieselbe Bauart wie die
   `titlebox-hero`-Patterns, weshalb dieser Abschnitt auch die zwei Regeln
   nachliefert, die dem Zitatkasten gegenüber dem Titelkasten fehlen.

   Mechanik in `inc/core/quote-slider.php` und `assets/js/sliders.js`, Pattern
   `patterns/zitat-karussell.php`.
   ============================================================ */

/* Eine Folie je Blick, kein Anreißer — der Unterschied zum Karten-Karussell,
   dessen `clamp()`-Breite absichtlich einen Rest der nächsten Karte stehen
   lässt. Der Rastpunkt selbst kommt aus der geteilten Bahn-Mechanik.

   Die Snap-Rechnung geht dadurch glatt auf: Folienbreite = Content-Box der
   Bahn, also liegt der letzte Rastpunkt bei `(n − 1) × (Breite + Lücke)` und
   damit genau auf dem maximalen Scrollweg. Jede Folie ist erreichbar. Beim
   Karten-Karussell ist das nicht so — dort sind die Karten schmaler als die
   Bahn, und auf `alignwide` liegt schon der zweite Rastpunkt jenseits des
   Scrollwegs (gemessen: 420px Rastpunkt, 284px Weg). Die Bahn rastet dort am
   Ende ein statt an einer Kartenkante, was bei zwei bis drei sichtbaren Karten
   richtig aussieht — bei einer Folie je Blick wäre es ein halber Anschnitt. */
.is-style-ff-quoteslider > * {
  flex: 0 0 100%;
  /* Bei einer Folie je Blick darf ein schneller Wischer keine überspringen.
     Das Karten-Karussell steht bewusst auf `normal` (Default), weil `always`
     dort das Wischen über zwei bis drei sichtbare Karten nur bremste. */
  scroll-snap-stop: always;
}

.wp-block-group.is-style-ff-quoteslider {
  /* Seitlich nichts: Folie 1 beginnt auf einer Linie mit der Überschrift, und
     ein `padding-inline-start` zöge `scroll-padding-inline-start` im selben
     Wert nach sich, sonst schnappte Folie 2 darunter.

     Unten fängt das Padding den Überhang des &-Signets unter der Kante des
     Zitatkastens — die Folie selbst hält dort keinen Innenabstand mehr frei.

     Warum er gefangen werden muss: `overflow-x: auto` macht das
     `overflow-y` laut CSS Overflow 3 zu `auto`. Ein Überhang von zwei Pixeln
     wäre also kein beschnittener Überstand, sondern eine senkrechte
     Bildlaufleiste — und die schrumpft `clientWidth`, womit sich alle
     `flex-basis: 100%`-Folienbreiten samt Snap-Rechnung verschieben.

     Gefangen wird der KASTEN des ::after, nicht die Zeichnung: die Glyphe
     sitzt nahezu bündig auf der Kante, das Pseudo-Element ragt um
     `--ff-signet-bottom` hinaus, und Scroll-Overflow rechnet mit Rändern,
     nicht mit Farbe.

     Nötig sind 0.12rem (1,92px) auf dem Desktop — `--ff-signet-bottom` im
     Abschnitt „Der Zitatkasten als Hero-Kasten" — und mobil 1,5 % der
     Signethöhe, bei deren `clamp()`-Maximum von 120px also 1,8px. Die 0.21rem
     hier sind damit rund 1,4px mehr als nötig: Reserve, kein Fehler. Wer sie
     zurücknimmt, bindet sie an `--ff-signet-bottom` und misst mobil gegen den
     `clamp()`-Höchstwert.

     Das `+ 1px` ist Rundungsreserve und kein Zierrat: auf Subpixel-Gleichstand
     soll das Padding nicht stehen. Ein Zehntelpixel Rundung in die falsche
     Richtung ergibt eine senkrechte Bildlaufleiste, und die schrumpft
     `clientWidth` samt Snap-Rechnung. Ein unsichtbares Pixel ist der billigere
     Preis. */
  padding-inline: 0;
  padding-block: 0 calc(var(--ff-quoteslider-bleed-block, 0.21rem) + 1px);
}

/* --- Der Zitatkasten als Hero-Kasten ---
   `is-style-ff-quotebox` ist auch der inhaltsbreite Kasten aus
   `patterns/highlight-quote.php`. Zwei Dinge fehlen ihm für die Hero-Zeile,
   und beide dürfen **nicht global** gesetzt werden: jener freistehende Kasten
   ragte sonst 3,5rem über die Inhaltsbreite und würde vom `overflow-x: clip`
   des `main` abgeschnitten.

   Eingegrenzt wird deshalb **strukturell** — auf einen Zitatkasten, der als
   direktes Kind einer Spalte in einer Spaltenzeile steht. Genau das ist die
   Hero-Zeile, und `highlight-quote` steht im Fluss und nicht in Spalten
   (nachgesehen: keine einzige `wp-block-column` in dem Pattern).

   Bis zum 2026-09-06 hing die Eingrenzung an `.is-style-ff-quoteslider`, also
   an der Bahn. Das trug nur, solange es die Hero-Zeile ausschließlich *im*
   Slider gab — mit `patterns/zitat-hero.php` gibt es sie auch einzeln, und
   dort wäre der Kasten sonst auf 6rem Signet und ohne Spalten-Overlap
   gelandet, also sichtbar anders als dieselbe Zeile im Slider. Die
   Mobil-Regeln im Abschnitt „Titelkasten-Heroes auf schmalen Viewports"
   grenzen aus demselben Grund schon immer strukturell ein.

   Der Preis ist derselbe wie dort: ein `highlight-quote`, den jemand in eine
   Spalte legt, bekommt die Hero-Optik. Das ist bewusst in Kauf genommen —
   eine eigene Wrapper-Klasse erreichte die bereits gespeicherten Seiten
   nicht. */
.wp-block-columns > .wp-block-column > .is-style-ff-quotebox {
  /* Die Hero-Signetmaße des Titelkastens (dort 7,5rem statt der 6rem des
     Zitatkastens), damit beide Hero-Arten gleich aussehen. Die Breite rechnet
     sich aus der Höhe, die beiden Anker sind eigene Werte — wer die Höhe
     ändert, nimmt sie neu ab. */
  --ff-signet-h: 7.5rem;
  --ff-signet-w: calc(var(--ff-signet-h) * 0.854);
  --ff-signet-right: -1.84rem;
  --ff-signet-bottom: -0.06rem;
}

/* Der Spalten-Overlap: derselbe Wert, mit dem der Titelkasten über die
   Bildkante ragt. Erst dadurch hat das Signet rechts Platz.

   Die Spezifität ist hier nicht beliebig: der Zitatkasten setzt in seinem
   eigenen Abschnitt ausdrücklich `margin-left: 0; margin-right: 0`, und zwar
   als `blockquote.wp-block-quote.is-style-ff-quotebox` mit (0,2,1). Eine
   Zwei-Klassen-Regel kommt dagegen nicht an — nachgemessen blieb
   `margin-right` auf 0, während das `z-index` derselben Regel längst griff.
   Der Struktur-Selektor hier hat drei Klassen, also (0,3,0), und schlägt
   (0,2,1): verglichen wird zuerst die Klassenzahl, 3 gegen 2. Beim
   Titelkasten tritt das gar nicht auf — der ist eine `div`-Gruppe ohne solche
   Regel. */
@media (min-width: 782px) {
  .wp-block-columns > .wp-block-column > .is-style-ff-quotebox {
    z-index: 2;
    margin-right: -3.5rem;
  }
}

/* --- Editor ---
   Hier reicht `scroll-snap-type: none` (Slider-Bahn) NICHT. Bei 100 %
   Folienbreite ist im Canvas immer nur eine Folie zu sehen: Folie 3 wählt man
   über die Listenansicht aus, sieht aber Folie 1 — und bearbeitet blind. Dazu
   belegt der Einfüge-Appender eine ganze Folienbreite und liegt einen
   Bildschirm weit rechts.

   Gestapelt ist das gelöst, und alles Übrige fällt von selbst: `flex: 0 0 100%`
   ist an einem Block-Kind wirkungslos, der Appender wird eine gewöhnliche
   Zeile, jede Folie ist sichtbar und auswählbar, Ziehen funktioniert senkrecht.
   Das Editor-Bild sieht dadurch nicht mehr wie das Frontend aus — bei einem
   Karussell ist es das ohnehin nie (ohne Autoplay und ohne Leiste), und für
   die Bearbeitung ist es eindeutig besser.

   `.wp-block-group` muss in den Selektor: Core gibt `display: flex` als
   `<root> .is-layout-flex` aus, im Editor also mit Spezifität (0,2,0) —
   Gleichstand mit `.editor-styles-wrapper .is-style-ff-quoteslider`, und die
   Ladereihenfolge entschiede. Mit der Blockklasse sind es (0,3,0). */
.editor-styles-wrapper .wp-block-group.is-style-ff-quoteslider {
  display: block;
  overflow-x: visible;
}

/* Gestapelt brauchen die Folien Luft dazwischen. Im Frontend gibt es die
   nicht: der `blockGap` steht bei einer Folie je Blick auf 0, und der
   Innenabstand der Folie ist seit dem 2026-09-06 ebenfalls 0. Also nur hier —
   und nur *zwischen* den Folien, die letzte braucht am Bahnende keinen Rand.

   Bewusst `margin` und nicht `padding`: der Innenabstand der Folie kommt als
   Inline-Style aus den Block-Attributen und schlüge jede Regel aus dem
   Stylesheet. Der Außenabstand ist frei — er muss nur Cores Flex-Layout
   schlagen, das den Kindern `margin: 0` gibt
   (`.wp-container-…-is-layout-flex > *`, Spezifität 0,1,0). Der Selektor hier
   kommt auf (0,3,0). */
.editor-styles-wrapper .wp-block-group.is-style-ff-quoteslider > * + * {
  margin-block-start: var(--wp--preset--spacing--70);
}

/* ============================================================
   Kontaktformular (Contact Form 7)

   Gestaltet nach dem Kontaktformular der Finanzberatung Bierl: eine helle
   Karte auf getöntem Abschnittsgrund, kurze Felder nebeneinander, die
   Auswahlboxen in zwei Spalten, darunter Freitext, Einwilligung und ein
   breiter Knopf. Übersetzt in die CI: Karte in `light-color` auf
   `background-alt`, Haarlinie, 4-px-Radius — dieselbe Formensprache wie
   `ff-post-card`, `ff-refcard` und die Themen-Chips.

   Der Rahmen steht in `patterns/kontaktformular.php`, das Formular selbst
   kommt über CF7s eigenen Shortcode aus der Datenbank. `.ff-kontaktformular` ist — wie `.ff-postfilter` und
   `.ff-post-card` — eine reine Utility und bewusst NICHT über
   `register_block_style()` registriert: sie gehört zu diesem einen Pattern,
   nicht in die Stil-Auswahl jeder Gruppe.

   Zur Spezifität: CF7 bringt ein eigenes Stylesheet mit, das durchweg auf
   einer Klasse steht (`.wpcf7-form-control`, `.wpcf7-not-valid-tip`, …).
   Zwei Klassen genügen hier also überall; `!important` steht nur an den drei
   Stellen, an denen CF7 selbst eins setzt (siehe dort).

   ⚠️ Im Editor ist von alldem nichts zu sehen: `core/shortcode` zeigt dort
   nur den Shortcode-Text. Änderungen an dieser Optik also im Frontend
   abnehmen, nicht im Site-Editor.
   ============================================================ */

/* Die Karte. Padding als Longhand mit (0,2,0): die Gruppe ist zwar
   verschachtelt und trägt kein `.has-global-padding`, aber eine
   Shorthand-Regel auf einer Klasse verlöre gegen jeden im Editor gesetzten
   Abstand — siehe den gleichen Fall bei `.is-style-ff-callout`. */
.wp-block-group.ff-kontaktformular {
  /* Die beiden Abstände, aus denen der Rhythmus des Formulars besteht.
     `row-gap` trennt die Blöcke voneinander, `label-gap` bindet eine
     Beschriftung an ihr Feld — der erste muss deutlich größer sein als der
     zweite, sonst liest sich eine Beschriftung als Schluss des Blocks darüber
     statt als Kopf des eigenen. Wer den Rhythmus ändert, dreht hier. */
  --ff-cf7-row-gap: var(--wp--preset--spacing--60);
  --ff-cf7-label-gap: 0.4rem;

  padding-top: var(--wp--preset--spacing--60);
  padding-right: var(--wp--preset--spacing--60);
  padding-bottom: var(--wp--preset--spacing--60);
  padding-left: var(--wp--preset--spacing--60);

  background-color: var(--wp--preset--color--light-color);
  border: 1px solid var(--wp--preset--color--light-grey);
  border-radius: 4px;
}

/* CF7 setzt an seinen Wrapper nichts, was stören würde — nur der eigene
   Abstand des `<form>` soll weg, damit die Karte ihren Innenabstand allein
   bestimmt. */
.ff-kontaktformular .wpcf7,
.ff-kontaktformular .wpcf7-form {
  margin: 0;
}

/* Abstand zwischen den Zeilen des Formulars. Die Zeilen sind `<p>`/`<div>`/
   `<fieldset>` aus dem Formular-Markup; `> * + *` trifft sie alle und spart
   eine Klasse je Zeile.

   ⚠️ Das erste Kind eines CF7-Formulars ist `<fieldset
   class="hidden-fields-container">` mit den Nonce- und Formular-ID-Feldern.
   Es ist unsichtbar, zählt für den `+`-Kombinator aber mit — die erste
   sichtbare Zeile wäre damit das zweite Kind und bekäme einen Abstand, den
   sie nicht haben soll (nachgemessen: 1,5 rem Luft am oberen Kartenrand).
   Deshalb die zweite Regel. Sie hängt am Klassennamen von CF7; steht dort
   eines Tages ein anderer, fällt das als Leerabstand oben in der Karte auf. */
.ff-kontaktformular .wpcf7-form > * {
  margin-bottom: 0;
}
.ff-kontaktformular .wpcf7-form > * + * {
  margin-top: var(--ff-cf7-row-gap);
}
.ff-kontaktformular .wpcf7-form > .hidden-fields-container {
  display: none;
}
.ff-kontaktformular .wpcf7-form > .hidden-fields-container + * {
  margin-top: 0;
}

/* ⚠️ Die Untergrenzen der Zeilen stehen ausdrücklich als `margin-bottom: 0`
   oben und NICHT als `margin: 0` an den einzelnen Zeilenklassen weiter unten.
   Genau das war am 2026-09-20 der Fehler: `.ff-kontaktformular .ff-cf7__field`
   und die Geschwister haben dieselbe Spezifität (0,2,0) wie die
   Rhythmus-Regel, stehen aber später in der Datei — ihr `margin: 0` hat den
   `margin-top` mitgenommen. Nachgemessen: Feldzeile, Auswahlboxen und
   Freitext standen mit `margin-top: 0px` bündig aneinander, während unter
   jeder Beschriftung 22 bis 26 px klafften. Die Beschriftung las sich dadurch
   als Schluss des Blocks darüber. Wer hier eine Zeilenklasse zurücksetzt,
   setzt `margin-bottom` zurück, nie `margin`. */

/* --- Feldzeile ---
   Kurze Felder stehen nebeneinander, sobald Platz ist. `auto-fit` +
   `minmax` statt einer Media Query: die Karte steht mal auf 980 px
   Inhaltsbreite, mal in einer Spalte, und die Umbruchbreite soll sich danach
   richten und nicht nach dem Viewport. */
.ff-kontaktformular .ff-cf7__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  /* Der Zeilenabstand greift erst, wenn die Felder umbrechen (Tablet). Dann
     trennt er wieder Blöcke voneinander und muss deshalb derselbe sein wie
     zwischen den Zeilen des Formulars. */
  gap: var(--ff-cf7-row-gap) var(--wp--preset--spacing--50);
}
/* Nur die Felder IM Grid — der Grid-Container setzt ihren Abstand. Der
   freistehende `.ff-cf7__field` (der Freitext) ist eine Formularzeile und
   holt seinen Abstand aus dem Rhythmus oben. */
.ff-kontaktformular .ff-cf7__grid > .ff-cf7__field {
  margin: 0;
}

/* Beschriftungen: klein, halbfett, auf eigener Zeile über dem Feld.
   Bewusst sichtbare Labels statt der Placeholder-only-Lösung der Vorlage —
   ein Placeholder verschwindet beim Tippen und ist als Beschriftung nach
   WCAG 2.2 SC 3.3.2 zu wenig. Die Placeholder bleiben trotzdem, als Beispiel
   für das erwartete Format. */
.ff-kontaktformular .ff-cf7__field > label,
.ff-kontaktformular .ff-cf7__legend {
  display: block;
  /* Vollstaendig gesetzt, nicht nur `margin-bottom`: die Beschriftung der
     Auswahlboxen ist ein `<p>` und braechte sonst den UA-Rand oben mit. */
  margin: 0 0 var(--ff-cf7-label-gap);
  padding: 0;
  font-size: var(--wp--preset--font-size--small);
  font-weight: 600;
  line-height: 1.3;
  color: var(--wp--preset--color--foreground);
}

/* Pflichtfeld-Stern in Bordeaux. Er steht zusätzlich zum `aria-required`,
   das CF7 an die Pflichtfelder hängt — sehende Nutzer sollen den Unterschied
   sehen, ohne das Feld anzufassen. */
.ff-kontaktformular .ff-cf7__req {
  color: var(--wp--preset--color--primary);
  font-weight: 700;
}

/* ⚠️ **CF7s Feld-Wrapper ist ein `<span>`, also inline.** Ein Inline-Element
   zieht in einem Block-Kontext eine ganze Zeilenbox auf, und deren
   Zeilenhöhe steht zusätzlich zwischen Beschriftung und Feld: nachgemessen
   26 px unter „Name“ und 22 px unter der Legende, obwohl dort 6,4 px
   `margin-bottom` gesetzt sind. Der Abstand ist damit weder sichtbar noch
   steuerbar — `display: block` macht ihn beides.

   Gilt für alle Wrapper, auch den der Einwilligung: jeder steht dort als
   eigene Zeile, keiner mitten im Fließtext. */
.ff-kontaktformular .wpcf7-form-control-wrap {
  display: block;
}

/* --- Eingabefelder ---
   Getönte Fläche auf der hellen Karte (wie in der Vorlage), Haarlinie,
   derselbe Radius wie beim Knopf. `width: 100%` + `box-sizing`, weil CF7
   seinen Feldern von sich aus keine Breite gibt und ein `<input>` sonst auf
   seiner `size`-Vorgabe stehen bliebe. */
.ff-kontaktformular .wpcf7-form-control:is([type="text"], [type="email"], [type="tel"], textarea) {
  width: 100%;
  box-sizing: border-box;
  /* ⚠️ `margin: 0` ist Pflicht, nicht Kosmetik. `style.css` trägt aus dem
     Vorlagen-Theme noch einen ganzen Satz CF7-Regeln (ab Zeile 109), und die
     erste davon gibt jedem Textfeld `margin-top: 20px`. Radius und Padding
     von dort schlägt dieser Selektor über seine Spezifität (0,3,0 gegen
     0,2,0) — der Außenabstand aber stand in keiner der beiden Regeln und
     lief deshalb durch: nachgemessen 26 px zwischen Beschriftung und Feld
     statt der gesetzten 6,4 px. Siehe `FOLLOW-UPS.md` Nr. 20. */
  margin: 0;
  padding: 0.75em 1em;
  border: 1px solid var(--wp--preset--color--light-grey);
  border-radius: 0.375em;
  background-color: var(--wp--preset--color--background-alt);
  color: var(--wp--preset--color--foreground);
  font-family: inherit;
  font-size: var(--wp--preset--font-size--normal);
  line-height: 1.5;
  transition: border-color 0.2s ease, background-color 0.2s ease;
}
.ff-kontaktformular textarea.wpcf7-form-control {
  min-height: 8rem;
  resize: vertical;
}
.ff-kontaktformular .wpcf7-form-control::placeholder {
  color: var(--wp--preset--color--grey);
  opacity: 1; /* Firefox dämpft Placeholder sonst ein zweites Mal */
}
/* Fokus: derselbe Ring wie beim Suchfeld des Beitragsfilters. Die Fläche
   wechselt dabei auf Weiß, damit das aktive Feld sich abhebt. */
.ff-kontaktformular .wpcf7-form-control:focus-visible {
  outline: 2px solid var(--wp--preset--color--primary);
  outline-offset: 1px;
  border-color: var(--wp--preset--color--primary);
  background-color: var(--wp--preset--color--light-color);
}

/* --- Auswahlboxen ---
   ⚠️ Die Gruppe ist ein `<div role="group" aria-labelledby>` und **kein**
   `<fieldset>` mit `<legend>`. Das ist eine Layout-Entscheidung, keine
   Nachlässigkeit: eine `<legend>` wird im Rahmenbereich des `<fieldset>`
   gerendert, und der Inhalt darunter beginnt nicht dort, wo ihr
   `margin-bottom` endet — nachgemessen 16 px Zugabe, die sich mit
   `display: block`, `padding` oder `margin` nicht wegbekommen ließen. Der
   übliche Ausweg (`float: left; width: 100%`) nimmt die Legende zwar aus dem
   Sonder-Layout, lässt dann aber das Umfließen des Floats durch das
   Grid der Auswahlboxen offen.

   `role="group"` plus `aria-labelledby` ist dieselbe Zusage an Screenreader
   — eine benannte Gruppe — nur mit dem Box-Modell eines gewöhnlichen
   Blocks: die Beschriftung sitzt damit auf demselben Abstand zu ihren
   Kästchen wie jedes andere Label zu seinem Feld. Wer daraus wieder ein
   `<fieldset>` macht, holt sich die 16 px zurück.

   Eigene Randwerte braucht das `<div>` keine: den unteren nimmt ihm die
   Rhythmus-Regel oben, den oberen bekommt es von ihr.

   ⚠️ Flex-Spalte mit `gap` ist ebenfalls Mechanik und nicht Geschmack.
   CF7 schickt den Formularinhalt durch `wpautop`, und das wickelt die
   Kästchen in ein **eigenes, klassenloses `<p>`** — dessen 1-em-UA-Rand legte
   sich zwischen Beschriftung und Kästchen (nachgemessen 22 statt 6 px).
   Dieselbe Sorte Störung bringen die Whitespace-Knoten mit, die CF7 beim
   Einrücken einstreut.

   Beides ist Markup, auf das wir keinen Zugriff haben und das sich mit der
   nächsten CF7-Fassung wieder ändern kann. Ein Flex-Container ist dagegen
   robust: er lässt Whitespace-Knoten von vornherein aus (CSS Flexbox 1, §4),
   und der `gap` ersetzt jeden Rand der Kinder — egal, wie viele Ebenen
   `wpautop` dazwischenschiebt. Deshalb tragen die Kinder hier ausdrücklich
   `margin: 0` und der Abstand kommt allein aus dem `gap`. */
.ff-kontaktformular .ff-cf7__fieldset {
  display: flex;
  flex-direction: column;
  gap: var(--ff-cf7-label-gap);
}
.ff-kontaktformular .ff-cf7__fieldset > * {
  margin: 0;
}
/* Zwei Spalten, sobald Platz ist — wie in der Vorlage. Dieselbe `auto-fit`-
   Rechnung wie bei der Feldzeile, aber mit deutlich größerer Mindestbreite:
   die Spaltenzahl ist hier keine Platzfrage, sondern eine Lesbarkeitsfrage.
   Mit 13 rem passten auf die 980-px-Karte vier Spalten à 208 px, und
   „Terminvereinbarung vor Ort“ brach darin zweizeilig um. 22 rem ergibt auf
   derselben Karte zwei Spalten à rund 440 px — jede Beschriftung einzeilig.
   `min(100%, …)` hält die Rechnung auch auf schmalen Viewports heil: ohne das
   bliebe die Spalte 22 rem breit und liefe aus der Karte heraus. */
.ff-kontaktformular .wpcf7-checkbox {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 22rem), 1fr));
  gap: 0.6rem var(--wp--preset--spacing--50);
}
/* CF7 gibt jedem Listenpunkt ein `margin-left: 1em` (auch dem ersten, über
   `.wpcf7-list-item`), das die Spalten gegeneinander versetzen würde. */
.ff-kontaktformular .wpcf7-list-item {
  margin: 0;
}
.ff-kontaktformular .wpcf7-list-item label {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  cursor: pointer;
  line-height: 1.4;
}
/* Kästchen in CI-Bordeaux statt im Systemblau, und groß genug, um ohne
   Zielen getroffen zu werden. `margin-top` richtet das Kästchen an der
   ersten Textzeile aus, nicht an der Mitte eines mehrzeiligen Labels. */
.ff-kontaktformular input[type="checkbox"] {
  flex: none;
  width: 1.15rem;
  height: 1.15rem;
  margin: 0.15rem 0 0;
  accent-color: var(--wp--preset--color--primary);
  cursor: pointer;
}
.ff-kontaktformular input[type="checkbox"]:focus-visible {
  outline: 2px solid var(--wp--preset--color--primary);
  outline-offset: 2px;
}

/* --- Einwilligung ---
   Steht ohne Trennlinie und ohne eigenen Innenabstand da: die Zeile ist eine
   Formularzeile wie jede andere und hängt am Rhythmus oben. Bis zum
   2026-09-20 rahmte sie eine Haarlinie nach oben ab — auf Kundenwunsch weg,
   zusammen mit dem `padding-top`, das nur den Abstand unter dieser Linie
   hielt. Ohne die Linie wären daraus 36 + 24 px geworden und die Zeile hätte
   weiter unten gestanden als jede andere.

   Die kleinere Schrift bleibt: sie ist Rechtstext, kein Feld.

   Der Datenschutz-Link ist durch die globale Regel aus `style.css` ohnehin
   unterstrichen (siehe Gotcha „Links im Seiteninhalt sind global
   unterstrichen“) — hier steht nur die Farbe. */
.ff-kontaktformular .ff-cf7__consent {
  font-size: var(--wp--preset--font-size--small);
  line-height: 1.5;
}
.ff-kontaktformular .ff-cf7__consent a {
  color: var(--wp--preset--color--primary);
}

/* --- Absende-Knopf ---
   Fläche, Typografie und Hover teilt er sich mit `is-style-ff-cta` (siehe
   den Abschnitt „CTA-Button“ weiter oben); hier steht nur, was dort nicht
   hingehört: die Breite.

   Er füllt die Karte **auf jeder Breite**, wie in der Vorlage. Das ist eine
   Entscheidung und kein Übersehen: der Knopf ist der Abschluss des
   Formulars, und die durchgehende Fläche schliesst die Karte unten ab —
   auf der 980-px-Karte sind das über 900 px. Eine Deckelung auf
   Inhaltsbreite stand hier kurzzeitig und ist auf Kundenwunsch wieder weg.
   Wer sie zurückholt, tut das für alle Breiten oder gar nicht: eine
   Media Query auf den Viewport wäre hier falsch, weil die Breite der Karte
   zählt und nicht die des Fensters. */
.ff-kontaktformular .wpcf7-submit {
  width: 100%;
  cursor: pointer;
}
/* CF7 blendet während des Sendens einen Spinner ein und dimmt den Knopf. */
.ff-kontaktformular .wpcf7-submit:disabled {
  cursor: default;
  opacity: 0.6;
}

/* --- Rückmeldungen ---
   CF7 setzt an `.wpcf7-response-output` Rand und Rahmen per `!important`
   (`style.css` des Plugins), deshalb hier ebenfalls. Die Farbe kommt aus der
   Palette statt aus CF7s Rot/Grün: Fehler in `rust`, Erfolg in `primary` —
   beides trägt auf der hellen Karte. */
.ff-kontaktformular .wpcf7-response-output {
  margin: var(--wp--preset--spacing--50) 0 0 !important;
  padding: 0.75em 1em !important;
  border: 1px solid currentColor !important;
  border-radius: 4px;
  font-size: var(--wp--preset--font-size--small);
  line-height: 1.5;
}
.ff-kontaktformular form.invalid .wpcf7-response-output,
.ff-kontaktformular form.unaccepted .wpcf7-response-output,
.ff-kontaktformular form.failed .wpcf7-response-output,
.ff-kontaktformular form.aborted .wpcf7-response-output {
  color: var(--wp--preset--color--rust);
}
.ff-kontaktformular form.sent .wpcf7-response-output {
  color: var(--wp--preset--color--primary);
}
/* Feldbezogene Fehlermeldung unter dem jeweiligen Feld. */
.ff-kontaktformular .wpcf7-not-valid-tip {
  display: block;
  margin-top: 0.35rem;
  color: var(--wp--preset--color--rust);
  font-size: var(--wp--preset--font-size--x-small);
  line-height: 1.4;
}
/* Zwei Klassen plus Elementklasse (0,3,0), damit die Regel die Feldoptik
   weiter oben schlägt: deren Selektor endet auf `:is([type="text"], …)`, und
   `:is()` zählt mit der Spezifität seines stärksten Arguments — auch (0,3,0).
   Bei Gleichstand entscheidet die Quellreihenfolge, und die steht hier
   richtig. Nachgemessen: mit nur zwei Klassen blieb der Rahmen grau. */
.ff-kontaktformular .wpcf7-form-control.wpcf7-not-valid {
  border-color: var(--wp--preset--color--rust);
}

/* --- Newsletter-Anmeldung (`ff-newsletterform`) ---
   Das CF7-Formular „Newsletter“ im Part `newsletter-hinweis`: ein Feld für
   die E-Mail-Adresse, daneben der Knopf. Die Gruppe trägt BEIDE Klassen —
   `ff-kontaktformular` liefert Felder, Beschriftung, Knopf, Rückmeldungen
   und Fehlermeldungen, hier steht nur, worin sich die Anmeldung
   unterscheidet. Wer die Feldoptik ändert, ändert sie damit für beide.

   Keine Karte: das Formular steht schon im Callout-Kasten, eine zweite
   Fläche darin wäre Kasten im Kasten. (0,3,0) schlägt die Karten-Regel
   (0,2,0). Der Zeilenabstand ist kleiner als im Kontaktformular: hier
   trennt er nur die Feldzeile vom Hinweis darunter, nicht Blöcke. */
.wp-block-group.ff-kontaktformular.ff-newsletterform {
  --ff-cf7-row-gap: var(--wp--preset--spacing--40);

  padding-top: 0;
  padding-right: 0;
  padding-bottom: 0;
  padding-left: 0;
  background-color: transparent;
  border: 0;
  border-radius: 0;
}

/* Beschriftung, Feld und Knopf stehen in EINEM `<p>` des Formular-Markups.
   ⚠️ Das ist Pflicht: CF7 schickt das Formular durch `wpautop`, und jede
   verschachtelte `<div>`-Zeile bekam dabei eigene `<p>` um ihren Inhalt —
   die Flex-Kinder waren dann diese Absätze statt Feld und Knopf
   (nachgemessen). In einen Absatz setzt `wpautop` keinen zweiten.

   Die Beschriftung nimmt sich die ganze erste Zeile (`flex-basis: 100%`),
   Feld und Knopf teilen die zweite und brechen um, sobald das Feld unter
   14 rem fiele. Ihr Abstand zur Zeile darunter ist der `gap`; das
   negative `margin-bottom` zieht ihn auf `--ff-cf7-label-gap` zurück, damit
   die Beschriftung so dicht am Feld steht wie im Kontaktformular.
   `flex-start` statt `end`: erscheint unter dem Feld eine Fehlermeldung,
   bleibt der Knopf auf der Höhe des Feldes stehen. */
.ff-newsletterform .ff-cf7__inline {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 0.75rem;
}
.ff-kontaktformular.ff-newsletterform .ff-cf7__inline > label {
  flex: 0 0 100%;
  margin-bottom: calc(var(--ff-cf7-label-gap) - 0.75rem);
}
.ff-newsletterform .ff-cf7__inline > .wpcf7-form-control-wrap {
  flex: 1 1 14rem;
}
/* Der Knopf füllt die Höhe des Feldes (`align-self: stretch`); seine
   Schrift steht in `small`, die des Feldes in `normal` — über nachgerechnetes
   Padding gingen die beiden nie auf denselben Pixel. Die Breite aus dem
   Kontaktformular (100 %) gilt hier nicht. */
.ff-newsletterform .wpcf7-submit {
  width: auto;
  flex: 0 0 auto;
  align-self: stretch;
}
/* Ist die Zeile zu schmal für Feld und Knopf nebeneinander, steht der Knopf
   allein in der zweiten Reihe und nimmt sie ganz. Container- statt
   Viewport-Abfrage, aus demselben Grund wie beim Raster des
   Kontaktformulars: es zählt die Breite des Kastens.

   ⚠️ Die Beschriftung kurz halten. CF7s Knopf ist ein `<input
   type="submit">`, und dessen Text bricht **nie** um — „Newsletter
   bestellen“ war in Versalien mit Sperrung rund 250 px breit und lief bei
   375 px Viewport 24 px aus dem Kasten (nachgemessen). Deshalb steht dort
   „Bestellen“. */
.ff-newsletterform .ff-cf7__inline {
  container-type: inline-size;
}
@container (max-width: 30rem) {
  .ff-newsletterform .wpcf7-submit {
    flex-basis: 100%;
  }
}
/* CF7 hängt hinter den Knopf einen Spinner (`visibility: hidden`, aber mit
   Breite und Rand). Als Flex-Kind zöge er Lücke plus 24 px Rand rechts
   vom Knopf auf. Absolut gesetzt steht er rechts in der Zeile der
   Beschriftung, die dort ohnehin leer ist — Zeile (18 px) plus
   Label-Abstand ergeben genau seine 24 px. Unter der Feldzeile läge er
   über dem Hinweistext. */
.ff-newsletterform .wpcf7-spinner {
  position: absolute;
  top: 0;
  right: 0;
  margin: 0;
}


/* ============================================================
   Fusszeile: Beschriftung der Gruppen (ff-footer-heading)
   ============================================================ */

/* Block Style an `core/heading`, angemeldet in `inc/core/block-style.php`.
   Dieselbe Geste wie `.ff-overline`, nur in `taupe` statt Primary — Primary
   waere auf dem Bordeaux-Grund der Fusszeile unsichtbar.

   Die uebrige Optik der Fusszeile steht in `style.css`, Abschnitt
   „Fusszeile": Logo-Hoehe, die 2-Spalten-Ausnahme des Rasters und die beiden
   Hover-Zustaende. Alles andere sind Block-Einstellungen im Part.

   Die Elementklasse muss in den Selektor: allein waere `.is-style-…` (0,1,0)
   und damit im Gleichstand mit Cores Flex-Layout-Regel
   `.wp-container-…-is-layout-flex > * { margin: 0 }`, die den Kindern der
   Gruppe ihre Raender nimmt. Der `margin-bottom` haengt dann an der
   Quellreihenfolge; mit zwei Klassen (0,2,0) nicht mehr. */
.wp-block-heading.is-style-ff-footer-heading {
  margin: 0 0 0.25rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  line-height: 1.2;
  color: var(--wp--preset--color--taupe);
}


/* ============================================================
   Stellenanzeigen (Plugin job-postings, Shortcode [job-postings])
   ============================================================ */

/* Das Plugin rendert seine Liste selbst: je Stelle ein
   `article.job-preview` mit Titel (`h5 > a`), einer Angabenzeile (Ort,
   Arbeitszeit) und dem Knopf `.apply-btn`. Ein Block Style ist dort nicht
   zu vergeben, deshalb Klassen-Selektoren auf das Plugin-Markup.

   Farben kommen aus den Plugin-Einstellungen (Jobs → Einstellungen →
   Stileinstellungen: Knopf Bordeaux, Box weiß mit Bordeaux-Rahmen, beide
   Radien 4px) und wirken damit auch auf die Einzelseite `/job/…`. Hier
   steht nur, was die Einstellungen nicht können: Aufbau, Typografie,
   Zustände.

   ⚠️ Alle Selektoren tragen `:root` vorn. Das Plugin lädt sein
   Stylesheet erst aus dem Shortcode heraus (also im Footer) und schreibt
   die Farb-Regeln als `<style>` mitten in den Inhalt — beides steht NACH
   dieser Datei, ein Gleichstand ginge also ans Plugin. Seine Regeln reichen
   bis (0,4,1) (`body .job-listing .job-preview .job-cta .apply-btn`);
   `:root` zählt als Klasse und hebt jede Regel hier um eine Stufe darüber. */

/* Liste: Abstand per `gap` statt des `margin-bottom` je Karte. */
:root .job-listing [role="list"] {
  display: flex;
  flex-direction: column;
  gap: var(--wp--preset--spacing--40);
}
/* Karte: Titel + Angaben links, Knopf rechts. Das Plugin baut das als
   `display: table` mit drei Zellen; ein Grid lässt den Knopf auf seine
   Breite schrumpfen, statt ihm 35 % zu geben. Haarlinie statt der 2 px des
   Plugins. `position: relative` ist der Bezug für den Klickbereich unten. */
:root .job-listing .job-preview {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--wp--preset--spacing--40) var(--wp--preset--spacing--60);
  margin: 0;
  padding: var(--wp--preset--spacing--50) var(--wp--preset--spacing--60);
  border-width: 1px;
  transition: background-color 0.2s ease;
}
:root .job-listing .job-preview:is(:hover, :focus-within) {
  background-color: var(--wp--preset--color--taupe-light);
}
/* `clearfix` am Plugin-Markup hängt ein `::after` an — als Grid-Kind wäre
   das eine dritte, leere Zelle. */
:root .job-listing .job-preview::before,
:root .job-listing .job-preview::after {
  content: none;
}
:root .job-listing .job-preview :is(.job-content, .job-cta) {
  display: block;
  width: auto;
  height: auto;
  padding: 0;
}

/* Titel: das Plugin vergibt `h5` (Ebene ist Plugin-Sache), die Optik
   entspricht dem Kartentitel von `ff-post-card` — Miranda Sans, `large`,
   ohne Unterstreichung, Bordeaux beim Überfahren. */
:root .job-listing .job-preview .job-content h5 {
  margin: 0 0 0.35rem;
  font-family: var(--wp--preset--font-family--miranda-sans, inherit);
  font-size: var(--wp--preset--font-size--large);
  font-weight: 600;
  line-height: 1.25;
}
:root .job-listing .job-preview .job-content h5 a {
  color: var(--wp--preset--color--foreground);
  text-decoration: none;
  transition: color 0.2s ease;
}
:root .job-listing .job-preview:is(:hover, :focus-within) .job-content h5 a {
  color: var(--wp--preset--color--primary);
}
/* Die ganze Karte ist klickbar: das Pseudo-Element des Titel-Links spannt
   sich über die Karte. Ein Link um die ganze Karte geht nicht (das Markup
   ist Plugin-Sache), und der Titel ist ohnehin das Linkziel — für
   Screenreader bleibt es ein Link mit seinem Titel als Namen. */
:root .job-listing .job-preview .job-content h5 a::after {
  content: "";
  position: absolute;
  inset: 0;
}

/* Angabenzeile in der Geste der Overline, aber gedämpft statt Bordeaux
   (Deckkraft statt `grey` — das stünde auf Weiß bei rund 2,7:1):
   sie ergänzt den Titel, statt ihn anzukündigen. */
:root .job-listing .job-preview .job-content .job-additional-information {
  margin: 0;
  font-size: var(--wp--preset--font-size--x-small);
  font-weight: 600;
  line-height: 1.4;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--wp--preset--color--foreground);
  opacity: 0.75;
}

/* Knopf: Optik aus der CTA-Regel (Abschnitt „CTA-Button"). Hier nur, was
   das Plugin zusätzlich setzt — volle Zellenbreite und 50 px Seitenpolster.
   Er liegt über dem Klickbereich der Karte, damit sein eigener Fokusring
   und Hover greifen; das Ziel ist ohnehin dasselbe. */
:root .job-listing .job-preview .job-cta .apply-btn {
  position: relative;
  z-index: 1;
  display: inline-block;
  width: auto;
  margin: 0;
  white-space: nowrap;
}

/* Schmal: Knopf unter den Text, linksbündig (das Plugin setzt die Zelle auf
   `text-align: right`), und weniger Seitenpolster — bei 343 px Karte ließ
   `spacing|60` dem Titel kaum zwei Drittel der Breite. */
@media (max-width: 599px) {
  :root .job-listing .job-preview {
    grid-template-columns: minmax(0, 1fr);
    padding-inline: var(--wp--preset--spacing--50);
  }
  :root .job-listing .job-preview .job-cta {
    text-align: left;
  }
}

/* Leere Liste („Keine Stellen") in der Fläche der Initiativ-Karte. */
:root .job-listing .no-jobs-available {
  padding: var(--wp--preset--spacing--50) var(--wp--preset--spacing--60);
  border: 0;
  border-radius: 4px;
  background-color: var(--wp--preset--color--taupe-light);
  color: var(--wp--preset--color--foreground);
  text-align: left;
}

/* --- Einzelseite einer Stelle (`/job/…`) ---
   Rahmen ist `templates/single-jobs.html`, den Inhalt setzt
   `inc/core/job-postings.php` ein (dort auch, warum aus Titel und
   Abschnittsköpfen h1/h2 werden). Das Plugin baut die beiden Spalten mit
   Floats (65 / 35 %) und einem leeren `.clearfix`-Div; ein Grid ersetzt
   beides. Links der Text, rechts der Kasten mit den Eckdaten und dem
   Bewerbungsknopf — er bleibt beim Scrollen stehen. */
:root .job-post {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(16rem, 22rem);
  align-items: start;
  gap: var(--wp--preset--spacing--70);
  /* Inhaltsbreite der Site (980px, wie auf der Karriere-Seite). Core gibt
     sie dem Kind des post-content schon mit, das Plugin setzt aber 1100px
     mit gleicher Spezifität und lädt später — deshalb hier ausdrücklich.
     Seitlich zentriert Core per `!important`, hier also nur die
     senkrechten Ränder. */
  max-width: var(--wp--style--global--content-size, 980px);
  margin-block: 0;
  padding: 0;
  overflow: visible;
}
:root .job-post::before,
:root .job-post::after,
:root .job-post > .clearfix {
  display: none;
}
/* Hinter den Spalten steht ein `.job-content-wrap` für Teilen-Knöpfe
   anderer Plugins — meist leer, aber dann über die volle Breite. */
:root .job-post > .job-content-wrap {
  grid-column: 1 / -1;
}
:root .job-post :is(.job-content, .job-side) {
  float: none;
  width: auto;
  padding: 0;
}
:root .job-post .job-content-wrap {
  padding: 0;
}
:root .job-post .job-content > .job-content-wrap {
  display: flex;
  flex-direction: column;
  gap: var(--wp--preset--spacing--60);
}
:root .job-post .jobs-row {
  margin: 0;
}

/* Titel: die Beschriftung des Feldes („Stellenbezeichnung") als Overline,
   der Wert als h1 in der Größe der Hero-Überschriften im Fließtext. */
:root .job-post .jobs-row.position_title .jobs-row-label {
  margin: 0 0 0.75rem;
  font-size: var(--wp--preset--font-size--small);
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--wp--preset--color--primary);
}
:root .job-post .jobs-row.position_title .jobs-row-input {
  margin: 0;
  font-family: var(--wp--preset--font-family--miranda-sans, inherit);
  font-size: var(--wp--preset--font-size--xx-large);
  font-weight: 600;
  line-height: 1.15;
}

/* Abschnittsköpfe der Inhaltsspalte (h2). Der Plugin-Unterstrich am
   `span` entfällt, weil es dort keinen `span` mehr gibt. „Beschreibung"
   ist kein Kopf, den man lesen muss — nur für Screenreader. */
:root .job-post .job-content h2.jobs-row-label {
  margin: 0 0 var(--wp--preset--spacing--30);
  font-family: var(--wp--preset--font-family--miranda-sans, inherit);
  font-size: var(--wp--preset--font-size--x-large);
  font-weight: 600;
  line-height: 1.25;
}
:root .job-post .jobs-row.position_description h2.jobs-row-label {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
:root .job-post .jobs-row-input :is(p, ul, ol) {
  margin: 0 0 0.75em;
}
:root .job-post .jobs-row-input :is(ul, ol) {
  padding-left: 1.25em;
  margin-left: 0;
}
:root .job-post .jobs-row-input li + li {
  margin-top: 0.35em;
}

/* Eckdaten-Kasten: warme Fläche wie die Initiativ-Karte auf 382, kein
   Rahmen. Das Arbeitgeber-Logo fällt weg — es ist das Logo der eigenen
   Website und stand dort in 400 px. */
:root .job-post .job-side {
  position: sticky;
  top: var(--wp--preset--spacing--60);
}
:root .job-post .job-side .job-content-wrap {
  display: flex;
  flex-direction: column;
  gap: var(--wp--preset--spacing--40);
  padding: var(--wp--preset--spacing--60);
  border: 0;
  border-radius: 4px;
  background-color: var(--wp--preset--color--taupe-light);
}
:root .job-post .jobs-row.position_logo {
  display: none;
}
:root .job-post .job-side .jobs-row-label {
  margin: 0 0 0.25rem;
  font-size: var(--wp--preset--font-size--x-small);
  font-weight: 700;
  line-height: 1.4;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  opacity: 0.75;
}
/* Den Unterstrich zeichnet das Plugin als Rahmen an den `span`s der
   Beschriftungen (in der Rahmenfarbe aus den Einstellungen). */
:root .job-post .jobs-row-label span {
  padding: 0;
  border: 0;
}
:root .job-post .job-side .jobs-row-input svg {
  width: 1em;
  height: 1em;
  margin: 0 0.35em 0 0;
  vertical-align: -0.125em;
}
:root .job-post .job-pdf-export {
  color: var(--wp--preset--color--primary);
}
:root .job-post .jobs-row-apply {
  padding: var(--wp--preset--spacing--30) 0 0;
}

/* Schmal: eine Spalte, der Kasten unter dem Text und nicht mehr klebend. */
@media (max-width: 781px) {
  :root .job-post {
    grid-template-columns: minmax(0, 1fr);
  }
  :root .job-post .job-side {
    position: static;
  }
}
