/*
 * Basis-CSS des Baukastens.
 *
 * Zweck: das komplette Aussehen aller Sections, ausgedrückt ausschließlich in
 * Tokens aus `tokens.contract.css`. In dieser Datei steht keine einzige Farbe
 * und keine Schriftart im Klartext – sonst könnte man sie pro Kunde nicht mehr
 * austauschen. `tests/unit/tokens.test.js` prüft das automatisch.
 *
 * Zusammenspiel: wird vor der `tokens.css` des Kunden geladen? Nein, danach:
 * Reihenfolge ist tokens.css → base.css → optional custom.css. Die Tokens
 * müssen bereits stehen, wenn base.css sie benutzt.
 *
 * Klassennamen sind absichtlich generisch (`card`, `media`, `signature-frame`).
 * Branchen- und Kundenbegriffe gehören nicht hierher (Genericity-Regel,
 * CLAUDE.md 2) – sie kommen aus Config und Datenbank.
 */

/* ============================================================
   Zurücksetzen und Grundlagen
   ============================================================ */
*,
*::before,
*::after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
}

body {
  font-family: var(--f-body);
  font-size: var(--fs-base);
  line-height: var(--lh-body);
  color: var(--text);
  background: var(--surface-1);
  -webkit-font-smoothing: antialiased;
}

/*
 * Papierkörnung über der ganzen Seite – nur wenn ein Theme sie einschaltet.
 * Liegt über allem, fängt aber keine Klicks ab. Als Datei aus `styles/`,
 * nicht als data:-Adresse, weil die CSP Bilder nur vom eigenen Server erlaubt.
 */
body::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 9999;
  pointer-events: none;
  background-image: var(--grain-image);
  opacity: var(--grain-opacity);
}

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

a {
  color: inherit;
}

/* Sichtbarer Fokus ist Pflicht (BACKLOG 3.14). Nur :focus-visible, damit
   Mausklicks keinen Ring hinterlassen. */
:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 3px;
  border-radius: 2px;
}

/* Nutzer, die weniger Bewegung wollen, bekommen weniger Bewegung. */
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  *,
  *::before,
  *::after {
    animation: none !important;
    transition: none !important;
  }
}

/* ============================================================
   Layout
   ============================================================ */
.wrap {
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.section {
  padding-block: 72px;
}

/*
 * Flächenwechsel ohne Handarbeit (CLAUDE.md 7.1): die Sections im <main>
 * rotieren automatisch durch die Flächenfarben. Der Kunde muss nie eine
 * Klasse setzen, und das Umsortieren der Sections in der Config verschiebt
 * die Farben einfach mit.
 */
main > .section:nth-of-type(3n + 1) {
  background: var(--surface-1);
}
main > .section:nth-of-type(3n + 2) {
  background: var(--surface-2);
}
main > .section:nth-of-type(3n + 3) {
  background: var(--surface-3);
}

/* Themes mit nur zwei tragfähigen Flächen setzen data-surfaces="2" am <main>. */
main[data-surfaces='2'] > .section:nth-of-type(odd) {
  background: var(--surface-1);
}
main[data-surfaces='2'] > .section:nth-of-type(even) {
  background: var(--surface-2);
}

/*
 * Ornamente (E-057): eine kleine Zeichnung je Abschnitt. Welche und auf
 * welcher Seite, setzt das vom Build erzeugte `styles/ornamente.css` (aus
 * `sections[].ornament` der Config); hier steht nur, wie sie erscheinen.
 *
 * Zwei Formen, je nachdem, ob neben dem Inhalt Platz ist:
 *
 * - Ab 100rem (große Monitore) wie von Anfang an: als Hintergrund unten im
 *   Abschnitt, abwechselnd rechts und links. Dort liegt sie im breiten Rand
 *   neben dem Inhalt und wird von nichts verdeckt. Die Grenze ist an der
 *   üblichen Inhaltsbreite (1100px) und der breitesten Zeichnung gemessen.
 * - Darunter, ab 34rem (Tablet, kleinere Laptops): klein und mittig auf der
 *   Naht zum nächsten Abschnitt, mit zwei feinen Linien – ein Trenner. Lag
 *   sie hier am Rand, verdeckten Karten, Fotos und Formular sie
 *   (Rückmeldung vom 05.10.2026). Auf der Naht ist nur Abstand, kein Inhalt,
 *   und kein Abschnitt wird höher. Nur der letzte Abschnitt grenzt an die
 *   Fußzeile, halb darin ginge die Zeichnung im Dunkeln unter. Er trägt sie
 *   wie auf großen Monitoren am Rand – als Schlussbild – und hält dafür
 *   unter dem Inhalt Platz frei.
 *
 * Am Telefon keine. Mit stil.flaeche: papier auch nicht – beide teilen sich
 * den Hintergrund der Abschnitte, und das Raster soll bleiben.
 *
 * `position: relative` am Abschnitt ohne z-index bildet keinen eigenen
 * Stapelkontext; die fest positionierte Detailansicht der Angebote bleibt
 * davon unberührt.
 */
main > .section {
  --ornament: none;
  --ornament-seite: right;
  --ornament-an: 0;
}

@media (min-width: 34rem) {
  html:not([data-flaeche='papier']) main > .section:not(.hero) {
    position: relative;
  }

  html:not([data-flaeche='papier']) main > .section:not(.hero)::after {
    content: '';
    position: absolute;
    z-index: 1;
    left: 50%;
    bottom: 0;
    width: 340px;
    height: 86px;
    transform: translate(-50%, 50%);
    /* Abschnitte ohne Zeichnung bekommen auch keine Linien. */
    opacity: var(--ornament-an);
    pointer-events: none;
    background:
      var(--ornament) center / auto 100% no-repeat,
      linear-gradient(to right, transparent, var(--ornament-linie)) left center / 33% 1px no-repeat,
      linear-gradient(to left, transparent, var(--ornament-linie)) right center / 33% 1px no-repeat;
  }

  /* Der letzte Abschnitt: Zeichnung am Rand wie auf großen Monitoren, mit
     eigenem Platz unter dem Inhalt, damit sie auch bei gestapeltem Inhalt
     frei steht. */
  html:not([data-flaeche='papier']) main > .section:not(.hero):last-child {
    background-image: var(--ornament);
    background-repeat: no-repeat;
    background-position: var(--ornament-seite) var(--ornament-abstand) bottom 0;
    background-size: auto var(--ornament-hoehe);
  }

  html:not([data-flaeche='papier']) main > .section:not(.hero):last-child::after {
    position: static;
    display: block;
    width: auto;
    height: calc(var(--ornament-an) * max(0px, var(--ornament-hoehe) - 64px));
    transform: none;
    background: none;
  }
}

@media (min-width: 100rem) {
  html:not([data-flaeche='papier']) main > .section:not(.hero) {
    background-image: var(--ornament);
    background-repeat: no-repeat;
    background-position: var(--ornament-seite) var(--ornament-abstand) bottom 0;
    background-size: auto var(--ornament-hoehe);
  }

  html:not([data-flaeche='papier']) main > .section:not(.hero)::after,
  html:not([data-flaeche='papier']) main > .section:not(.hero):last-child::after {
    display: none;
  }
}

.section-head {
  max-width: 60ch;
  margin-bottom: 2.6rem;
  text-align: var(--head-align);
  margin-inline: var(--head-margin);
}

/* Die Einleitung zentriert sich mit, wenn der Kopf mittig steht. */
.section-head .lead {
  margin-inline: var(--head-margin);
}

/* ============================================================
   Typografie
   ============================================================ */
h1,
h2,
h3 {
  font-family: var(--f-display);
  font-weight: var(--heading-weight);
  color: var(--heading);
  line-height: 1.12;
}

/* Hervorgehobenes Wort in einer Überschrift (im Portal mit *Sternchen*). */
h1 em {
  font-style: italic;
  font-weight: 400;
  color: var(--accent);
}

h1 {
  font-size: clamp(2.4rem, 5.5vw, 4.2rem);
  letter-spacing: -0.01em;
}

h2 {
  font-size: clamp(1.7rem, 3.4vw, 2.5rem);
}

h3 {
  font-size: 1.25rem;
  font-weight: 500;
}

/* Kleine Zeile über einer Überschrift – Gestalt aus den --eyebrow-Tokens. */
.eyebrow {
  display: block;
  font-family: var(--eyebrow-font);
  font-style: var(--eyebrow-style);
  font-weight: var(--eyebrow-weight);
  font-size: var(--eyebrow-size);
  text-transform: var(--eyebrow-transform);
  letter-spacing: var(--eyebrow-tracking);
  color: var(--eyebrow-color);
  margin-bottom: 0.6rem;
}

/* Der Strich davor. Bei --eyebrow-line: 0px ist er samt Abstand weg. */
.eyebrow::before {
  content: '';
  display: inline-block;
  vertical-align: middle;
  width: var(--eyebrow-line);
  height: 1.5px;
  margin-right: calc(var(--eyebrow-line) / 2);
  background: var(--detail);
}

.lead {
  font-size: 1.12rem;
  font-weight: 300;
  max-width: 56ch;
}

blockquote {
  font-family: var(--f-display);
  font-style: italic;
  font-weight: 300;
  font-size: 1.35rem;
  color: var(--heading);
  line-height: 1.4;
  margin-block: 1.3rem;
  border-left: var(--quote-border);
  padding-left: var(--quote-indent);
}

.muted {
  color: var(--text-muted);
  font-size: 0.85rem;
}

/* Feiner Trenner mit Linien links und rechts. */
.divider {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  padding-block: 8px;
  color: var(--detail);
}
.divider::before,
.divider::after {
  content: '';
  height: 1px;
  width: 64px;
  background: var(--detail);
  opacity: 0.5;
}

/* ============================================================
   Schaltflächen
   ============================================================ */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  font-family: var(--f-body);
  font-weight: 600;
  font-size: 0.95rem;
  text-decoration: none;
  /* Mindestens 44 px hoch: Touch-Ziel auf dem Smartphone (CLAUDE.md 8). */
  min-height: 44px;
  padding: 0.85rem 1.7rem;
  border: 1px solid var(--btn-border);
  border-radius: var(--btn-radius);
  background: var(--btn-quiet-bg);
  color: var(--btn-quiet-color);
  cursor: pointer;
  transition: background 0.2s, color 0.2s, transform 0.15s;
}

.btn:hover {
  transform: translateY(-1px);
}

.btn-solid {
  background: var(--btn-solid-bg);
  border-color: var(--btn-solid-bg);
  color: var(--btn-solid-color);
}
.btn-solid:hover {
  background: var(--btn-solid-hover-bg);
  border-color: var(--btn-solid-hover-bg);
}

.btn-quiet:hover {
  /* Vorgabe aus dem Akzent gemischt statt fest hinterlegt – bleibt pro Theme
     richtig. Ein Theme mit gefüllter stiller Schaltfläche setzt hier seine
     dunklere Fläche, sonst würde sie beim Überfahren fast durchsichtig. */
  background: var(--btn-quiet-hover-bg);
}

/* Schlichter Textverweis mit Linie darunter – für einen dritten Weg im Hero. */
.btn-link {
  border: none;
  border-bottom: 1.5px solid var(--border);
  border-radius: 0;
  background: none;
  color: var(--text-muted);
  padding-inline: 0.3rem;
}
.btn-link:hover {
  color: var(--accent);
  border-color: var(--accent);
}

.btn-accent {
  background: var(--accent-2);
  border-color: var(--accent-2);
  color: var(--on-accent-2);
}
.btn-accent:hover {
  background: var(--accent-2-hover);
  border-color: var(--accent-2-hover);
}

/* ============================================================
   Karten und Raster
   ============================================================ */
.card-grid {
  display: grid;
  gap: 26px;
  /* Passt sich selbst an: keine Media Query pro Kartenanzahl nötig. */
  grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr));
}

.card {
  display: flex;
  flex-direction: column;
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  overflow: hidden;
  transition: transform 0.2s, box-shadow 0.2s;
}

/* ---- Karussell: waagerechte Kartenspur ----------------------
   Gewischt wird mit Scroll-Snap, also ohne JavaScript. Wie viele Karten
   nebeneinander stehen, sagt allein `--karussell-sichtbar`; das Skript für die
   Pfeile liest den Wert nie und muss deshalb bei einer Änderung hier nicht
   angepasst werden.

   Der Wert ist das Kleinere aus zwei Zahlen:
     `--karussell-platz`   wie viele Karten bei dieser Breite lesbar
                           nebeneinander passen – setzen die Media Queries
     `--karussell-anzahl`  wie viele es überhaupt gibt – setzt das Markup über
                           `data-anzahl`, weil der Build die Zahl kennt

   Ohne die zweite Zahl reserviert die Spur Plätze für Karten, die es nicht
   gibt: Bei drei Angeboten auf einem breiten Schirm standen sie links und
   rechts blieb ein Viertel leer. Das Raster daneben streckt sich, die Spur tat
   es nicht – und dieser Unterschied fiel als Fehler auf, nicht als Absicht. */
/* Am Telefon liegen die Pfeile UNTER der Spur, erst ab 34rem flankieren sie
   sie. Grund: Bei 390px nehmen zwei 44px-Knöpfe samt Abstand rund 150px weg –
   die Karte wäre schmaler als zwei Drittel des Schirms. Gemessen, nicht
   geschätzt: vorher 234px von 390px. */
.karussell {
  display: grid;
  grid-template-columns: auto auto;
  justify-content: center;
  align-items: center;
  gap: 12px;
}

.karussell-spur {
  --karussell-platz: 1;
  /* Vorgabe hoch genug, dass sie nie begrenzt: Ab fünf Karten deckelt die
     Breite, nicht die Zahl. */
  --karussell-anzahl: 99;
  --karussell-sichtbar: min(var(--karussell-platz), var(--karussell-anzahl));
  --karussell-luecke: 26px;
  /*
   * Gibt es mehr Karten als Plätze, lugt die nächste angeschnitten hervor –
   * das zeigt ohne Worte, dass es weitergeht (Rückmeldung vom 06.10.2026).
   * `--karussell-mehr` ist dann 1, sonst 0; `--karussell-anschnitt` ist der
   * Anteil einer Karte, der zu sehen ist.
   */
  --karussell-mehr: clamp(0, var(--karussell-anzahl) - var(--karussell-platz), 1);
  --karussell-anschnitt: 0.28;

  grid-row: 1;
  grid-column: 1 / -1;
  /* Ohne min-width bricht ein Flex-Container in einer 1fr-Spalte aus. */
  min-width: 0;
  width: 100%;

  display: flex;
  gap: var(--karussell-luecke);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  /* Keine Scrollleiste: Anschnitt, Punkte und Pfeile zeigen genug. */
  scrollbar-width: none;
  /*
   * Nur senkrecht Luft für den Fokusring. Waagerechtes Padding verschiebt die
   * Snap-Position: Mit `padding: 4px` startete `scrollLeft` bei 4 statt 0, und
   * der Zurück-Pfeil war dadurch von Anfang an aktiv.
   */
  padding-block: 4px;
  margin-block: -4px;
}

.karussell-spur::-webkit-scrollbar {
  display: none;
}

/*
 * Weicher Rand, wo es weitergeht (BACKLOG 5.36): Die Karten laufen aus,
 * statt hart abgeschnitten zu werden. Welche Seite, setzt
 * `scripts-client/karussell.js` – am Anfang links kein Verlauf, am Ende
 * rechts keiner. Die Maske braucht nur Deckkraft, die Farbe ist egal.
 */
.karussell-spur {
  --karussell-rand: clamp(24px, 6%, 64px);
}

.karussell-spur.kann-weiter {
  mask-image: linear-gradient(90deg, var(--text) calc(100% - var(--karussell-rand)), transparent);
}

.karussell-spur.kann-zurueck {
  mask-image: linear-gradient(90deg, transparent, var(--text) var(--karussell-rand));
}

.karussell-spur.kann-zurueck.kann-weiter {
  mask-image: linear-gradient(
    90deg,
    transparent,
    var(--text) var(--karussell-rand),
    var(--text) calc(100% - var(--karussell-rand)),
    transparent
  );
}

/*
 * Am Telefon keine Pfeile: Dort wischt man, und die angeschnittene nächste
 * Karte und die Punkte zeigen, dass es geht. Die Pfeile kosteten eine eigene
 * Zeile unter der Spur.
 */
.karussell-pfeil {
  display: none;
}

/* Die Punkte setzt `scripts-client/karussell.js`; ohne Skript gibt es keine. */
.karussell-punkte {
  grid-row: 2;
  grid-column: 1 / -1;
  display: flex;
  justify-content: center;
  gap: 10px;
  margin-top: 18px;
}

/* Wie bei den Pfeilen: `display: flex` schlüge sonst `hidden`. */
.karussell-punkte[hidden] {
  display: none;
}

.karussell-punkte span {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--border);
  transition: background 0.2s, transform 0.2s;
}

.karussell-punkte span.is-active {
  background: var(--accent);
  transform: scale(1.25);
}

@media (min-width: 34rem) {
  .karussell {
    grid-template-columns: auto minmax(0, 1fr) auto;
  }

  .karussell-spur {
    grid-row: 1;
    grid-column: 2;
  }

  .karussell-pfeil {
    display: grid;
  }

  .karussell-vorher {
    grid-row: 1;
    grid-column: 1;
  }

  .karussell-naechste {
    grid-row: 1;
    grid-column: 3;
  }
}

/*
 * Breite einer Karte: Die Spur teilt sich auf die sichtbaren Karten, ihre
 * Lücken und – wenn es mehr gibt – den Anschnitt der nächsten samt Lücke.
 */
.karussell-spur > .card,
.karussell-spur > .leine-platz {
  flex: 0 0
    calc(
      (100% - (var(--karussell-sichtbar) - 1 + var(--karussell-mehr)) * var(--karussell-luecke)) /
        (var(--karussell-sichtbar) + var(--karussell-mehr) * var(--karussell-anschnitt))
    );
  scroll-snap-align: start;
}

/* Am Telefon eine Karte und nur ein schmaler Rand der nächsten; die Lücke
   enger, damit die Karte breit bleibt. */
@media (max-width: 33.99rem) {
  .karussell-spur {
    --karussell-anschnitt: 0.16;
    --karussell-luecke: 16px;
  }
}

/* Die Schwellen folgen der Kartenbreite aus dem Raster (280px), nicht
   Gerätenamen: entscheidend ist, ab wann eine weitere Karte lesbar bleibt.
   Höchstens drei: Mit vier oder fünf wirkten die Karten gequetscht
   (Rückmeldung vom 06.10.2026). */
@media (min-width: 34rem) {
  .karussell-spur { --karussell-platz: 2; }
}

@media (min-width: 52rem) {
  .karussell-spur { --karussell-platz: 3; }
}

/*
 * Weniger Karten als Plätze: Dann bestimmt die Zahl, und die Karten füllen die
 * Breite. Eine Regel je Zahl, weil CSS aus einem Attributwert nichts rechnen
 * kann. Vier Regeln genügen – darüber deckelt ohnehin die Breite.
 *
 * Diese Selektoren sind spezifischer als die Media Queries oben, aber das
 * schadet nicht: `min()` nimmt die kleinere der beiden Zahlen, egal welche
 * Regel zuletzt gewonnen hat. Bei drei Karten auf dem Telefon bleibt es
 * deshalb bei einer sichtbaren.
 */
.karussell-spur[data-anzahl='1'] { --karussell-anzahl: 1; }
.karussell-spur[data-anzahl='2'] { --karussell-anzahl: 2; }
.karussell-spur[data-anzahl='3'] { --karussell-anzahl: 3; }
.karussell-spur[data-anzahl='4'] { --karussell-anzahl: 4; }

.karussell-pfeil {
  flex: 0 0 auto;
  /* 44px ist das kleinste Touch-Ziel, das die E2E-Tests durchlassen. */
  width: 44px;
  height: 44px;
  place-items: center;
  font-size: 1.6rem;
  line-height: 1;
  color: var(--heading);
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: 50%;
  cursor: pointer;
  transition: background 0.2s, opacity 0.2s;
}

/*
 * Muss sein: `display: grid` ab 34rem überschreibt die Regel des Browsers für
 * `[hidden]`. Ohne diese Zeile stehen die Pfeile ohne JavaScript sichtbar da
 * und tun nichts – genau der tote Knopf, den das Markup vermeiden soll. Im
 * Browser gemessen: `display` war `grid`, obwohl `hidden` gesetzt war.
 */
.karussell-pfeil[hidden] {
  display: none;
}

.karussell-pfeil:hover:not(:disabled) {
  background: var(--surface-2);
}

/* Sichtbar bleiben, aber erkennbar aus: ein verschwindender Knopf verschiebt
   das Layout genau in dem Moment, in dem der Finger darauf liegt. */
.karussell-pfeil:disabled {
  opacity: 0.35;
  cursor: default;
}

/* ---- Karussell läuft von selbst (E-069, BACKLOG 5.12) -------
   Alles hier setzt `scripts-client/karussell.js` voraus: Es legt die Leiste
   mit Punkten und Pause-Knopf an und setzt `laeuft` bzw. `steht`. Der aktive
   Punkt wird zum Balken; solange das Karussell läuft, füllt er sich in
   `--karussell-takt`. Ist er voll, rückt das Skript eine Karte weiter. */
.karussell {
  /* Vorgabe; das Skript setzt den Takt, den es selbst benutzt. */
  --karussell-takt: 6s;
}

.karussell-leiste {
  grid-row: 2;
  grid-column: 1 / -1;
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 6px;
  margin-top: 8px;
}

/* Passt alles nebeneinander, gibt es weder Punkte noch etwas anzuhalten. */
.karussell-leiste:has(> .karussell-punkte[hidden]) {
  display: none;
}

.karussell-leiste .karussell-punkte {
  margin-top: 0;
}

.karussell-punkte.mit-takt span {
  position: relative;
  overflow: hidden;
  transition: width 0.4s, background 0.2s;
}

.karussell-punkte.mit-takt span.is-active {
  width: 30px;
  border-radius: 4px;
  transform: none;
}

/* Die Füllung des Balkens. Steht das Karussell, ist er voll: Er zeigt dann
   nur noch, wo man ist. */
.karussell-punkte.mit-takt span::after {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left;
}

.karussell.steht .karussell-punkte.mit-takt span.is-active::after {
  transform: scaleX(1);
}

.karussell.laeuft .karussell-punkte.mit-takt span.is-active {
  background: var(--border);
}

.karussell.laeuft:not(.gleitet) .karussell-punkte.mit-takt span.is-active::after {
  animation: karussell-takt var(--karussell-takt) linear forwards;
}

/* Kurz anhalten: Maus über der Spur, oder das Karussell ist nicht im Bild.
   So spezifisch wie die Regel darüber und mehr – deren `animation` setzt den
   Zustand sonst auf „läuft“ zurück. */
.karussell.laeuft:not(.gleitet) .karussell-spur:hover ~ .karussell-leiste .karussell-punkte.mit-takt span.is-active::after,
.karussell.laeuft.ausser-sicht:not(.gleitet) .karussell-punkte.mit-takt span.is-active::after {
  animation-play-state: paused;
}

/* Während das Skript gleitet, darf Scroll-Snap nicht an jeder Karte einrasten. */
.karussell-spur.gleitet {
  scroll-snap-type: none;
}

@keyframes karussell-takt {
  to {
    transform: scaleX(1);
  }
}

.karussell-pause {
  /* 44px: das kleinste Touch-Ziel, wie bei den Pfeilen. */
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  padding: 0;
  color: var(--heading);
  background: transparent;
  border: 0;
  border-radius: 50%;
  cursor: pointer;
}

.karussell-pause:hover {
  background: var(--surface-2);
}

.karussell-pause svg {
  width: 18px;
  height: 18px;
  fill: currentColor;
}

/* ---- Wäscheleine (E-070, BACKLOG 5.29) ----------------------
   Dieselbe Spur wie das Karussell; in ihr hängen Abzüge an einer Leine.
   Die Plätze stoßen ohne Lücke aneinander, damit sich das Seil fortsetzt –
   den Abstand zwischen den Abzügen macht der Innenrand jedes Platzes. Am
   Telefon ein Abzug und ein gutes Stück des nächsten, darüber zwei oder
   drei – mit zwei bzw. vier waren sie zu klein (Rückmeldung vom 08.10.2026). */
.leine {
  /* Weite und Richtung des Nachschwingens; setzt das Skript. */
  --schwung: 0deg;
}

.leine-spur {
  --karussell-luecke: 0px;
  --karussell-anschnitt: 0.4;
  --karussell-platz: 1;
  /* Platz über dem Seil für die Klammern, darunter für Schatten und die
     schräg hängenden Ecken – die Spur schneidet sonst ab. */
  padding-block: 4px 30px;
  margin-block: -4px -30px;
}

@media (min-width: 34rem) {
  .leine-spur { --karussell-platz: 2; --karussell-anschnitt: 0.3; }
}

@media (min-width: 52rem) {
  .leine-spur { --karussell-platz: 3; }
}

.leine-platz {
  position: relative;
  padding: 0 10px;
  scroll-snap-align: start;
}

/* Ein Stück Seil je Platz; die Enden liegen alle auf derselben Höhe. */
.leine-seil {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 50px;
  overflow: visible;
  fill: none;
  stroke: var(--text-muted);
  stroke-width: 1.5;
  stroke-linejoin: round;
  stroke-linecap: round;
  transform-origin: 50% 0;
}

/* Ein zweiter, dünner Faden dicht daneben: liest sich wie gedrehte Kordel
   statt wie ein gezeichneter Strich. */
.leine-faden {
  stroke-width: 0.7;
  opacity: 0.45;
}

/* Abzug samt Klammer. Gedreht wird um den Punkt, an dem die Klammer am Seil
   sitzt – so hängt er, statt sich um seine Mitte zu drehen. */
.leine-haenger {
  --neigung: -2deg;
  position: relative;
  margin-top: 11px;
  transform-origin: 50% 0;
  rotate: var(--neigung);
}

/* Wo die Klammer am Seil sitzt und wie schräg der Abzug hängt, würfelt der
   Build je Platz (`seilStueck()` in `sections/catalog.js`). */
.leine-tiefe-4 { margin-top: 4px; }
.leine-tiefe-6 { margin-top: 6px; }
.leine-tiefe-8 { margin-top: 8px; }
.leine-tiefe-10 { margin-top: 10px; }
.leine-tiefe-12 { margin-top: 12px; }
.leine-tiefe-14 { margin-top: 14px; }
.leine-tiefe-16 { margin-top: 16px; }
.leine-tiefe-18 { margin-top: 18px; }
.leine-tiefe-20 { margin-top: 20px; }
.leine-tiefe-22 { margin-top: 22px; }
.leine-tiefe-24 { margin-top: 24px; }
.leine-tiefe-26 { margin-top: 26px; }
.leine-tiefe-28 { margin-top: 28px; }
.leine-tiefe-30 { margin-top: 30px; }
.leine-tiefe-32 { margin-top: 32px; }
.leine-tiefe-34 { margin-top: 34px; }
.leine-tiefe-36 { margin-top: 36px; }
.leine-tiefe-38 { margin-top: 38px; }
.leine-tiefe-40 { margin-top: 40px; }
.leine-tiefe-42 { margin-top: 42px; }
.leine-tiefe-44 { margin-top: 44px; }

.leine-neigung-0 { --neigung: -3deg; }
.leine-neigung-1 { --neigung: -1.2deg; }
.leine-neigung-2 { --neigung: 2.2deg; }
.leine-neigung-3 { --neigung: 0.6deg; }
.leine-neigung-4 { --neigung: -2.2deg; }
.leine-neigung-5 { --neigung: 3deg; }

/* Eine Holzklammer, nur aus CSS. */
.leine-klammer {
  position: absolute;
  z-index: 1;
  top: -9px;
  left: 50%;
  width: 9px;
  height: 26px;
  translate: -50% 0;
  background: var(--surface-3);
  border: 1px solid color-mix(in srgb, var(--text) 30%, transparent);
  border-radius: 2px;
}

.leine-klammer::after {
  content: '';
  position: absolute;
  top: 9px;
  left: -2px;
  right: -2px;
  height: 3px;
  background: var(--text-muted);
  border-radius: 2px;
}

/* Der Abzug baut auf dem aus der Collage auf (`.abzug`), ist hier aber ein
   Link zur Detailansicht und quadratisch wie ein Sofortbild. */
.leine .abzug {
  gap: 8px;
  padding: 8px 8px 12px;
  color: inherit;
  text-decoration: none;
}

.leine .abzug .media {
  aspect-ratio: 1;
}

.abzug-rand {
  display: grid;
  gap: 2px;
  text-align: center;
}

.leine .abzug-titel {
  margin: 0;
  font-family: var(--f-display);
  font-size: 1rem;
  font-weight: 400;
  line-height: 1.25;
  color: var(--heading);
}

.abzug-preis {
  font-size: 0.8rem;
  color: var(--text-muted);
}

.leine .abzug:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 3px;
}

/*
 * Nachschwingen: `schwingt` setzt das Skript, wenn die Leine bewegt wird,
 * `--schwung` ist die Weite mit Richtung. Eine gedämpfte Schwingung, das
 * Seil wippt mit und der Abzug sinkt dabei kurz ein Stück mit ihm ab.
 * Ohne Skript und bei „weniger Bewegung“ hängt alles still.
 */
.leine.schwingt .leine-haenger {
  animation:
    leine-schwingen var(--schwing-dauer) ease-in-out var(--schwing-verzug),
    leine-sinken 2.2s ease-out;
}

/*
 * Jeder Abzug schwingt anders (Rückmeldung vom 08.10.2026: „jedes Bild muss
 * doch anders wackeln“): ein schwerer langsamer und weniger weit, ein
 * leichter schneller und weiter, und keiner genau im selben Augenblick. Die
 * Art würfelt der Build je Platz; Nachbarn bekommen nie dieselbe. Die
 * längste Dauer samt Verzug muss in `SCHWINGEN_MS` passen
 * (`scripts-client/karussell.js`), sonst bricht die Bewegung ab.
 */
.leine-haenger {
  --schwing-weite: 1;
  --schwing-dauer: 2.2s;
  --schwing-verzug: 0s;
}

.leine-schwung-0 { --schwing-weite: 1.25; --schwing-dauer: 1.9s; --schwing-verzug: 0s; }
.leine-schwung-1 { --schwing-weite: 0.75; --schwing-dauer: 2.5s; --schwing-verzug: 0.12s; }
.leine-schwung-2 { --schwing-weite: 1.05; --schwing-dauer: 2.2s; --schwing-verzug: 0.06s; }
.leine-schwung-3 { --schwing-weite: 0.9; --schwing-dauer: 2.05s; --schwing-verzug: 0.2s; }

.leine.schwingt .leine-seil {
  animation: leine-wippen 2.2s ease-out;
}

@keyframes leine-schwingen {
  0% { rotate: var(--neigung); }
  12% { rotate: calc(var(--neigung) + var(--schwung) * var(--schwing-weite)); }
  30% { rotate: calc(var(--neigung) - var(--schwung) * var(--schwing-weite) * 0.6); }
  48% { rotate: calc(var(--neigung) + var(--schwung) * var(--schwing-weite) * 0.35); }
  66% { rotate: calc(var(--neigung) - var(--schwung) * var(--schwing-weite) * 0.18); }
  84% { rotate: calc(var(--neigung) + var(--schwung) * var(--schwing-weite) * 0.07); }
  100% { rotate: var(--neigung); }
}
}

@keyframes leine-wippen {
  0%, 100% { scale: 1 1; }
  15% { scale: 1 1.45; }
  35% { scale: 1 0.85; }
  55% { scale: 1 1.12; }
  75% { scale: 1 0.97; }
}

/* Passend zu `leine-wippen`: Das Seil wippt um seine Aufhängung oben; die
   Abzüge sinken dabei ein paar Pixel mit. */
@keyframes leine-sinken {
  0%, 100% { translate: 0 0; }
  15% { translate: 0 5px; }
  35% { translate: 0 -1.5px; }
  55% { translate: 0 1.3px; }
  75% { translate: 0 -0.3px; }
}

@media (prefers-reduced-motion: reduce) {
  .leine.schwingt .leine-haenger,
  .leine.schwingt .leine-seil {
    animation: none;
  }
}

/* Auf --surface-2 würde eine Karte in derselben Farbe verschwinden. */
main > .section:nth-of-type(3n + 2) .card {
  background: var(--card-bg-alt);
}

.card:hover {
  transform: translateY(-4px);
  box-shadow: 0 14px 34px color-mix(in srgb, var(--text) 12%, transparent);
}

.card-body {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  padding: 22px 24px 26px;
  flex: 1;
}

.card-body p {
  font-size: 0.95rem;
  font-weight: 300;
  flex: 1;
}

.card-price {
  font-family: var(--f-display);
  color: var(--heading);
  font-size: 1.05rem;
}

/*
 * Höchstzahl der Personen: klein und gesperrt wie eine Etikettzeile, damit
 * sie neben Titel und Preis nicht um Aufmerksamkeit konkurriert. In der
 * Textfarbe für Nebensächliches – eine Akzentfarbe wäre in dieser Größe auf
 * hellen Karten zu blass zum Lesen.
 */
/* Personen und Anzahl (E-067): zwei kleine Etikettzeilen unter dem Preis. */
.card-personen,
.card-verfuegbar {
  display: flex;
  align-items: center;
  gap: 0.4em;
  font-size: 0.74rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.card-personen-symbol {
  width: 1.25em;
  height: 1.25em;
  flex: none;
}

/* Was es noch gibt, ist die gute Nachricht – eine Spur kräftiger als die
   Personen. „Zurzeit vergeben“ bleibt leise. */
.card-verfuegbar {
  color: var(--heading);
}

.card-verfuegbar.ist-vergeben {
  color: var(--text-muted);
}

.card-personen + .card-verfuegbar {
  margin-top: -0.2rem;
}

.card .btn {
  align-self: flex-start;
  margin-top: 0.6rem;
  padding: 0.6rem 1.2rem;
  font-size: 0.85rem;
}

/* ============================================================
   Bildflächen
   ============================================================ */
.media {
  aspect-ratio: 4 / 3;
  /* Zuschneiden statt verzerren: Der Rahmen hat ein festes Format, das Foto
     nicht. Ohne diese Zeile zieht der Browser ein Hochformat in die Breite –
     auf dem Tablet sahen die Angebotsfotos dadurch gestaucht aus. */
  object-fit: cover;
  background: var(--surface-3);
}

/*
 * Fokuspunkt (E-066): Wo ein Foto zugeschnitten wird, bleibt die Stelle im
 * Bild, die die Kundin im Portal angetippt hat – statt immer die Mitte. Der
 * Build hängt dafür zwei Klassen ans Foto (`sections/shared.js`,
 * `fokusKlassen`); ohne sie gilt 50 % 50 %, also wie bisher.
 *
 * Für alle Fotos und nicht an jeder der Zuschnitt-Regeln einzeln: So muss
 * eine neue Variante nichts davon wissen. Wo ein Foto ganz gezeigt wird
 * (`contain`, die Großansicht), steht die Mitte ausdrücklich – sonst
 * rutschte es dort an den Rand.
 *
 * Klassen statt Stil-Angabe im HTML: Die CSP lässt nur Stylesheets zu. Das
 * Raster von 5 % ist feiner, als ein Finger tippen kann.
 */
img {
  object-position: var(--fokus-x, 50%) var(--fokus-y, 50%);
}

.fx-0 {
  --fokus-x: 0%;
}
.fx-5 {
  --fokus-x: 5%;
}
.fx-10 {
  --fokus-x: 10%;
}
.fx-15 {
  --fokus-x: 15%;
}
.fx-20 {
  --fokus-x: 20%;
}
.fx-25 {
  --fokus-x: 25%;
}
.fx-30 {
  --fokus-x: 30%;
}
.fx-35 {
  --fokus-x: 35%;
}
.fx-40 {
  --fokus-x: 40%;
}
.fx-45 {
  --fokus-x: 45%;
}
.fx-50 {
  --fokus-x: 50%;
}
.fx-55 {
  --fokus-x: 55%;
}
.fx-60 {
  --fokus-x: 60%;
}
.fx-65 {
  --fokus-x: 65%;
}
.fx-70 {
  --fokus-x: 70%;
}
.fx-75 {
  --fokus-x: 75%;
}
.fx-80 {
  --fokus-x: 80%;
}
.fx-85 {
  --fokus-x: 85%;
}
.fx-90 {
  --fokus-x: 90%;
}
.fx-95 {
  --fokus-x: 95%;
}
.fx-100 {
  --fokus-x: 100%;
}

.fy-0 {
  --fokus-y: 0%;
}
.fy-5 {
  --fokus-y: 5%;
}
.fy-10 {
  --fokus-y: 10%;
}
.fy-15 {
  --fokus-y: 15%;
}
.fy-20 {
  --fokus-y: 20%;
}
.fy-25 {
  --fokus-y: 25%;
}
.fy-30 {
  --fokus-y: 30%;
}
.fy-35 {
  --fokus-y: 35%;
}
.fy-40 {
  --fokus-y: 40%;
}
.fy-45 {
  --fokus-y: 45%;
}
.fy-50 {
  --fokus-y: 50%;
}
.fy-55 {
  --fokus-y: 55%;
}
.fy-60 {
  --fokus-y: 60%;
}
.fy-65 {
  --fokus-y: 65%;
}
.fy-70 {
  --fokus-y: 70%;
}
.fy-75 {
  --fokus-y: 75%;
}
.fy-80 {
  --fokus-y: 80%;
}
.fy-85 {
  --fokus-y: 85%;
}
.fy-90 {
  --fokus-y: 90%;
}
.fy-95 {
  --fokus-y: 95%;
}
.fy-100 {
  --fokus-y: 100%;
}

/*
 * Signature-Rahmen: trägt die Form aus --radius-signature – je Theme ein Bogen,
 * eine weiche Rundung oder eine Kante. Der einzige Ort, an dem das
 * Signature-Element (Hebel 4 in CLAUDE.md 7.2) definiert ist.
 */
.signature-frame {
  position: relative;
  overflow: hidden;
  border: var(--signature-border);
  border-radius: var(--radius-signature);
  background: var(--surface-2);
  box-shadow: var(--signature-shadow);
}

.signature-frame .media {
  aspect-ratio: 3 / 4;
}

/*
 * Platzhalter, solange noch keine Fotos geliefert sind. Bewusst gestaltet und
 * nicht „kaputt": eine Site muss vor dem Fototermin vorzeigbar sein.
 */
.media-placeholder {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  padding: 24px;
  text-align: center;
  color: var(--text-muted);
  background: linear-gradient(160deg, var(--surface-3), var(--surface-2));
}

.media-placeholder span {
  font-size: 0.8rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

/* ============================================================
   Smartphone-Feinschliff (CLAUDE.md 8: Smartphone first)
   ============================================================ */
@media (max-width: 560px) {
  body {
    font-size: 16px;
  }
  .section {
    padding-block: 52px;
  }
  .section-head {
    margin-bottom: 1.8rem;
  }
  blockquote {
    font-size: 1.15rem;
  }
  /* Auf schmalen Geräten sind volle Breiten leichter zu treffen. */
  .card .btn,
  .btn-block {
    width: 100%;
    justify-content: center;
  }
}

/* ============================================================
   Nur für Screenreader
   ============================================================ */
/*
 * Sichtbar für Screenreader, unsichtbar auf dem Schirm. Wird gebraucht, wo eine
 * Information sonst allein über Farbe transportiert würde – etwa der Zustand
 * einer Kalenderzelle.
 */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ============================================================
   Kopfzeile
   ============================================================ */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: color-mix(in srgb, var(--surface-1) 92%, transparent);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--border);
}

.nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding-block: 14px;
}

/* Die Kopfzeile darf breiter sein als der Inhalt: Logo mit Namen, sechs
   Menüpunkte und Kontaktwege brauchen mehr Platz als ein Textabsatz (E-056). */
.site-header .wrap {
  max-width: var(--header-maxw);
}

.logo {
  font-family: var(--f-display);
  font-size: 1.3rem;
  color: var(--heading);
  text-decoration: none;
  line-height: 1.15;
}

/* Liegt ein Logo im Kundenrepo, zeigt die Kopfzeile nur das Bild.
   Die Höhe ist begrenzt, die Breite folgt dem Seitenverhältnis – sonst
   bestimmt die hochgeladene Datei, wie hoch die Kopfzeile wird. */
.logo-bild img {
  display: block;
  height: 44px;
  width: auto;
  max-width: 220px;
  object-fit: contain;
}

@media (min-width: 60rem) {
  .logo-bild img {
    height: 52px;
    max-width: 280px;
  }
}

/* Logo als Zeichen, Name als Text daneben (E-033).
   Seit die Kontaktwege nur noch Symbole sind (E-036), ist in der Zeile Platz
   für ein Zeichen, das man auch erkennt – vorher war es kaum größer als ein
   Menüpunkt hoch. */
.logo-mit-name {
  display: flex;
  align-items: center;
  gap: 12px;
}

/* Der Name bricht nicht um. Zweizeilig neben einem runden Zeichen sieht er
   aus wie ein Versehen, und die Kopfzeile wird dabei höher als nötig. */
.logo-schrift {
  white-space: nowrap;
}

.logo-mit-name img {
  display: block;
  height: 48px;
  width: auto;
  max-width: 72px;
  object-fit: contain;
  /* Ein rundes Zeichen neben einer Schriftlinie wirkt sonst, als stünde es
     zu tief – der optische Schwerpunkt eines Kreises liegt über der Grundlinie. */
  flex: 0 0 auto;
}

/* Auf schmalen Schirmen zählt jeder Pixel neben dem Menü-Knopf. Weil der Name
   nicht umbrechen darf, wird er hier etwas kleiner statt zweizeilig. Die Grenze
   liegt unter 390 px, der Breite der meisten Telefone: Dort passt alles in
   voller Größe, erst bei 360 px nicht mehr. */
@media (max-width: 23.5rem) {
  .logo-mit-name {
    gap: 8px;
  }

  .logo-mit-name img {
    height: 42px;
  }

  .logo-mit-name .logo-schrift {
    font-size: 1.12rem;
  }
}

@media (min-width: 60rem) {
  .nav {
    padding-block: 10px;
  }

  .logo-mit-name img {
    height: 64px;
    max-width: 96px;
  }
}

.logo em {
  display: block;
  font-family: var(--f-body);
  font-style: normal;
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--detail);
}

.nav-links {
  display: flex;
  align-items: center;
  gap: 26px;
}

.nav-links ul {
  display: flex;
  align-items: center;
  gap: 26px;
  list-style: none;
}

.nav-links .nav-kontaktwege {
  gap: 8px;
}

.nav-links a {
  text-decoration: none;
  font-size: var(--nav-size);
  font-weight: 500;
  text-transform: var(--nav-transform);
  letter-spacing: var(--nav-tracking);
  color: var(--nav-color);
  /* Ein Menüpunkt bricht nicht um. Mit zwei Kontaktknöpfen wurde die Zeile
     enger, und „Über mich" stand plötzlich zweizeilig zwischen einzeiligen
     Punkten. Umbrechen darf die Liste, nicht der einzelne Punkt. */
  white-space: nowrap;
}

.nav-links a:hover {
  color: var(--heading);
}

/* Nur das Symbol, rund umrandet (E-036). 44 px ist die kleinste Fläche, die
   man mit dem Daumen sicher trifft – das Symbol selbst ist kleiner. */
.nav-social {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  color: var(--heading);
  border: 1px solid var(--detail);
  border-radius: 50%;
}

.nav-social:hover {
  background: color-mix(in srgb, var(--detail) 14%, transparent);
}

/* Die Schaltfläche erscheint erst, wenn JavaScript das Menü einklappbar
   gemacht hat – sonst wäre sie ohne Funktion. */
.nav-toggle {
  display: none;
  min-width: 44px;
  min-height: 44px;
  font-size: 1.6rem;
  line-height: 1;
  background: none;
  border: none;
  color: var(--heading);
  cursor: pointer;
}

/*
 * Eingeklappt wird nicht ab einer festen Breite, sondern sobald die Zeile
 * nicht mehr passt (E-056). Wie breit sie ist, hängt am Kunden: Logo mit
 * Namen, Zahl und Länge der Menüpunkte (die Kundin kann sie im Portal
 * umbenennen), Zahl der Kontaktwege. Mit fester Grenze lief die Zeile auf
 * dem Tablet hochkant über den Rand, und die ganze Seite wurde breiter als
 * der Schirm. `scripts-client/nav.js` misst und setzt `nav-eng` an <html>;
 * unter 860 px immer.
 *
 * Ohne JavaScript stehen die Menüpunkte unter 860 px untereinander und
 * darüber nebeneinander – umbrechen darf die Liste dann, damit nichts über
 * den Rand ragt.
 */
html:not(.nav-collapsible) .nav-links ul {
  flex-wrap: wrap;
}

@media (max-width: 860px) {
  .nav-links {
    flex-direction: column;
    align-items: flex-start;
    gap: 0;
  }

  .nav-links ul {
    flex-direction: column;
    align-items: flex-start;
    gap: 14px;
  }

  .nav-links .nav-kontaktwege {
    flex-direction: row;
    margin-top: 18px;
  }
}

.nav-eng .nav-toggle {
  display: block;
}

.nav-eng .nav-links {
  display: none;
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  flex-direction: column;
  align-items: flex-start;
  gap: 0;
  background: var(--surface-2);
  padding: 22px;
  border-bottom: 1px solid var(--border);
}

.nav-eng .nav-links ul {
  flex-direction: column;
  align-items: flex-start;
  gap: 14px;
}

.nav-eng .nav-links.is-open {
  display: block;
}

/* Im aufgeklappten Menü: Menüpunkte untereinander, Symbole nebeneinander
   darunter – untereinander sähen einzelne Kreise verloren aus. */
.nav-eng .nav-links .nav-kontaktwege {
  flex-direction: row;
  margin-top: 18px;
}

/* Ohne Menüpunkte (E-073) stehen nur die Symbole neben dem Logo – auch am
   Telefon in einer Zeile, ohne den Abstand, der sie im Menü absetzt. */
.nav-links.nav-nur-wege .nav-kontaktwege {
  flex-direction: row;
  margin-top: 0;
}

/* ============================================================
   Hero
   ============================================================ */
.hero {
  padding-block: 72px 56px;
}

.hero-grid {
  display: grid;
  grid-template-columns: 1.15fr 0.85fr;
  gap: 56px;
  align-items: center;
}

.hero-motto {
  font-family: var(--f-display);
  font-style: italic;
  font-weight: 300;
  font-size: 1.3rem;
  color: var(--detail);
  margin: 1.4rem 0 0.4rem;
}

.hero-ctas {
  display: flex;
  gap: 14px;
  flex-wrap: wrap;
  margin-top: 1.8rem;
}

.hero-note {
  margin-top: 1rem;
}

.hero-bogen .signature-frame {
  max-width: var(--hero-frame-max);
  margin-left: auto;
  animation: var(--signature-motion);
}

/*
 * „Schweben“: Die Form wechselt langsam zwischen drei Rundungen und wandert
 * dabei ein paar Pixel. Eingeschaltet über --signature-motion; wer weniger
 * Bewegung eingestellt hat, sieht das Bild still (Regel oben).
 */
@keyframes signatur-schweben {
  0%,
  100% {
    border-radius: var(--radius-signature);
    transform: translate(0, 0);
  }
  33% {
    border-radius: var(--radius-signature-2);
    transform: translate(-5px, 8px);
  }
  66% {
    border-radius: var(--radius-signature-3);
    transform: translate(5px, -5px);
  }
}

/* --- Variante slider --- */
.hero-slider {
  position: relative;
  overflow: hidden;
  min-height: 70vh;
  display: flex;
  align-items: center;
}

.hero-slider-media {
  position: absolute;
  inset: 0;
}

.hero-slide {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 1.2s ease;
}

.hero-slide.is-active {
  opacity: 1;
}

/* Kontrast-Overlay: der Text muss über jedem Foto lesbar bleiben. */
.hero-slider-overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(
    to right,
    color-mix(in srgb, var(--heading) 78%, transparent),
    color-mix(in srgb, var(--heading) 35%, transparent)
  );
}

.hero-slider-inner {
  position: relative;
  padding-block: 72px;
  /*
   * Muss sein, sonst rückt der Text nach rechts: `.hero-slider` ist ein
   * Flex-Container, und ein Flex-Element schrumpft von sich aus auf seine
   * Inhaltsbreite. Der Inhaltsbereich war dadurch nur 624px breit, und sein
   * `margin-inline: auto` zentrierte diesen schmalen Block – der Text begann
   * bei 352px statt bei 114px wie alles andere auf der Seite.
   *
   * Mit `flex: 1` füllt er die Breite, und erst dann greifen `--maxw` und der
   * Seitenabstand so, wie sie in jeder anderen Section greifen: Der Starttext
   * beginnt an derselben Kante wie das Bild bei „Über mich".
   */
  flex: 1;
}

.hero-slider .hero-text {
  max-width: 44rem;
}

.hero-slider h1,
.hero-slider .hero-motto,
.hero-slider .lead,
.hero-slider .eyebrow,
.hero-slider .muted {
  color: var(--on-accent);
}

/* Auf dem Foto: Eine nur umrandete Schaltfläche braucht einen hellen Rand,
   sonst verschwindet sie im Bild. Ein Theme mit gefüllter stiller
   Schaltfläche setzt den Rand auf ihre Füllung (E-055). */
.hero-slider .btn-quiet {
  border-color: var(--btn-quiet-foto-border);
  color: var(--btn-quiet-foto-color);
}

/* --- Variante video (E-053) --------------------------------------------------
   Film über die ganze Breite, Text davor. Am breiten Schirm läuft der Film
   links in die Grundfläche aus, der Text steht dunkel auf hell. Am Telefon
   steht der Text unten, hell auf einem dunklen Verlauf – dort ist der Film
   schmal, und ein heller Streifen links ließe von ihm nichts übrig. */
.hero-video {
  position: relative;
  display: flex;
  align-items: center;
  min-height: clamp(560px, calc(100svh - 72px), 790px);
  overflow: hidden;
  isolation: isolate;
}

.hero-video-buehne {
  position: absolute;
  inset: 0;
  z-index: -1;
}

.hero-video-standbild,
.hero-film {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Der Film liegt über dem Standbild, erscheint aber erst, wenn er läuft –
   sonst stünde während des Ladens ein schwarzes Rechteck da. */
.hero-film {
  opacity: 0;
  transition: opacity 0.6s ease;
}

.film-laeuft .hero-film {
  opacity: 1;
}

.hero-film[data-fassung='hoch'] {
  display: none;
}

.hero-video-verlauf {
  position: absolute;
  inset: 0;
  background: linear-gradient(
    90deg,
    var(--surface-1) 0%,
    var(--surface-1) 25%,
    color-mix(in srgb, var(--surface-1) 96%, transparent) 37%,
    color-mix(in srgb, var(--surface-1) 76%, transparent) 49%,
    color-mix(in srgb, var(--surface-1) 28%, transparent) 63%,
    color-mix(in srgb, var(--heading) 12%, transparent) 100%
  );
}

.hero-video-inhalt {
  position: relative;
  flex: 1;
  padding-block: 62px 74px;
}

.hero-video .hero-text {
  max-width: 32rem;
}

.hero-plakette {
  position: absolute;
  right: max(24px, calc((100vw - var(--maxw)) / 2));
  bottom: 8%;
  margin: 0;
  padding: 13px 16px;
  border: 1px solid color-mix(in srgb, var(--surface-1) 66%, transparent);
  border-radius: 18px;
  background: color-mix(in srgb, var(--surface-1) 76%, transparent);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  box-shadow: 0 9px 32px color-mix(in srgb, var(--heading) 10%, transparent);
  color: var(--text-muted);
  font-size: 0.8rem;
}

.hero-plakette strong {
  display: block;
  margin-bottom: 2px;
  font-family: var(--f-display);
  font-size: 1.15rem;
  font-weight: 400;
  color: var(--heading);
}

/* Der Knopf zum Anhalten: klein, aber eine volle Tippfläche (WCAG 2.2.2). */
.hero-film-knopf {
  position: absolute;
  left: max(16px, calc((100vw - var(--maxw)) / 2));
  bottom: 14px;
  min-height: 44px;
  padding: 0 14px;
  border: 0;
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--surface-1) 80%, transparent);
  color: var(--text);
  font: inherit;
  font-size: 0.82rem;
  cursor: pointer;
}

@media (max-width: 780px) {
  .hero-video {
    align-items: flex-end;
    min-height: clamp(540px, calc(100svh - 64px), 790px);
  }

  .hero-film[data-fassung='breit'] {
    display: none;
  }

  .hero-film[data-fassung='hoch'] {
    display: block;
  }

  .hero-video-verlauf {
    background: linear-gradient(
      180deg,
      color-mix(in srgb, var(--heading) 20%, transparent) 0%,
      color-mix(in srgb, var(--heading) 4%, transparent) 24%,
      color-mix(in srgb, var(--heading) 20%, transparent) 44%,
      color-mix(in srgb, var(--heading) 88%, transparent) 100%
    );
  }

  .hero-video-inhalt {
    padding-block: 0 38px;
  }

  .hero-video h1,
  .hero-video .hero-motto,
  .hero-video .lead,
  .hero-video .eyebrow,
  .hero-video .muted,
  .hero-video .btn-link {
    color: var(--surface-1);
  }

  .hero-video .btn-link {
    border-color: color-mix(in srgb, var(--surface-1) 80%, transparent);
  }

  .hero-video .btn-solid {
    background: var(--surface-1);
    border-color: var(--surface-1);
    color: var(--heading);
  }

  .hero-video .btn-quiet {
    border-color: var(--surface-1);
    color: var(--surface-1);
  }

  .hero-plakette {
    top: 20px;
    right: 19px;
    bottom: auto;
    border-color: color-mix(in srgb, var(--surface-1) 46%, transparent);
    /* Dunkles Glas: Heller Text muss auf jedem Film lesbar sein, auch auf
       einem hellen. */
    background: color-mix(in srgb, var(--heading) 34%, transparent);
    color: color-mix(in srgb, var(--surface-1) 90%, transparent);
  }

  .hero-plakette strong {
    color: var(--surface-1);
  }

  .hero-film-knopf {
    top: 14px;
    bottom: auto;
    left: 16px;
  }
}

/* Ohne Unschärfe (alter Browser, „Transparenz reduzieren“) wird die
   Plakette voll hinterlegt, damit sie auf jedem Film lesbar bleibt. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .hero-plakette {
    background: var(--surface-1);
    color: var(--text-muted);
  }
}

@media (prefers-reduced-transparency: reduce) {
  .hero-plakette {
    background: var(--surface-1);
    color: var(--text-muted);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }

  .hero-plakette strong {
    color: var(--heading);
  }
}

@media (max-width: 860px) {
  .hero-grid {
    grid-template-columns: 1fr;
    gap: 36px;
  }

  .hero-bogen .signature-frame {
    margin: 0 auto;
    max-width: 300px;
  }
}

/* ============================================================
   Über mich
   ============================================================ */
.about-grid {
  display: grid;
  grid-template-columns: 0.7fr 1.3fr;
  gap: 56px;
  align-items: center;
}

.about-grid .signature-frame {
  max-width: var(--about-frame-max);
  border-radius: var(--radius-about);
  animation: var(--about-motion);
}

/*
 * Wie „Schweben“ im Hero, nur mit den Formen des Fotos „Über mich“ – eine
 * Site kann dort ein Oval oder eine weiche, unregelmäßige Form wollen, im
 * Hero aber den Bogen behalten (E-055). Steht still bei „weniger Bewegung“
 * und bei stil.bewegung: ruhig (Regeln oben bzw. stil-bewegung.css).
 */
@keyframes about-schweben {
  0%,
  100% {
    border-radius: var(--radius-about);
    transform: translate(0, 0);
  }
  33% {
    border-radius: var(--radius-about-2);
    transform: translate(-4px, 6px);
  }
  66% {
    border-radius: var(--radius-about-3);
    transform: translate(4px, -4px);
  }
}

@media (max-width: 860px) {
  .about-grid {
    grid-template-columns: 1fr;
    gap: 32px;
  }

  .about-grid .signature-frame {
    margin: 0 auto;
  }
}

/* ============================================================
   Karten-Raster: Verweis auf die Detailansicht
   ============================================================ */
.card-link {
  display: flex;
  flex-direction: column;
  flex: 1;
  text-decoration: none;
  color: inherit;
}

.card-more {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--heading);
  margin-top: 0.4rem;
}

/*
 * Ein einzelner Eintrag im Raster (E-074): Das Raster füllt seine eine Spalte
 * über die ganze Breite – eine Karte allein wurde so zum seitenbreiten Foto,
 * ohne Foto zur großen leeren Fläche. Gedacht ist der Fall für einen Abschnitt
 * mit genau einem Angebot (etwa ein Gerät zum Leihen). Allein steht die Karte
 * deshalb begrenzt und mittig, ab Tablet-Breite mit dem Foto neben dem Text
 * wie ein kleines Schaufenster. Am Telefon bleibt sie, wie jede Karte, ein
 * Stapel.
 *
 * Nur CSS über `:only-child`: Das Markup weiß nicht, wie viele Einträge
 * sichtbar sind, und muss es so auch nicht – kommt ein zweiter dazu, wird
 * ohne Build-Änderung wieder das gewohnte Raster daraus.
 */
.card-grid > .card:only-child {
  width: 100%;
  max-width: 56rem;
  justify-self: center;
}

@media (min-width: 40rem) {
  .card-grid > .card:only-child .card-link {
    flex-direction: row;
  }

  .card-grid > .card:only-child .card-link > .media {
    flex: 0 0 48%;
    align-self: stretch;
    aspect-ratio: auto;
    min-height: 18rem;
  }

  .card-grid > .card:only-child .card-body {
    justify-content: center;
    padding: 32px 36px;
  }

  /* Im Raster schiebt der Text Preis und Verweis an den Kartenfuß, damit
     nebeneinanderstehende Karten unten bündig sind. Allein gibt es nichts
     zum Angleichen – ohne das bliebe mitten im Text eine Lücke. */
  .card-grid > .card:only-child .card-body p {
    flex: none;
  }

  .card-grid > .card:only-child .card-body h3 {
    font-size: 1.5rem;
  }
}

/* ============================================================
   Detailansicht
   ============================================================ */
/*
 * Sichtbar wird sie auf zwei Wegen: über `:target` (ohne JavaScript) und über
 * `.is-open` (mit JavaScript, dann als echter Dialog mit Fokus-Falle).
 */
.modal {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 100;
  align-items: center;
  justify-content: center;
  padding: var(--gutter);
}

.modal:target,
.modal.is-open {
  display: flex;
}

.modal-backdrop {
  position: absolute;
  inset: 0;
  background: color-mix(in srgb, var(--text) 62%, transparent);
}

.modal-panel {
  position: relative;
  width: min(680px, 100%);
  max-height: 88vh;
  /* dvh rechnet mit den Leisten des Browsers, vh mit eingeklappten (5.22). */
  max-height: 88dvh;
  overflow-y: auto;
  background: var(--surface-1);
  border-radius: var(--radius-card);
  border: 1px solid var(--border);
}

.modal-close {
  position: absolute;
  top: 10px;
  right: 14px;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  font-size: 1.6rem;
  line-height: 1;
  text-decoration: none;
  color: var(--heading);
  background: var(--surface-1);
  border-radius: var(--radius-pill);
}

/* Wischbare Bildergalerie – braucht kein JavaScript, nur Scroll-Snap.
   Keine Scrollleiste: Pfeile und Punkte zeigen, dass es weitergeht (E-065). */
.modal-gallery {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
}

.modal-gallery::-webkit-scrollbar {
  display: none;
}

/*
 * Pfeile und Punkte der Fotos (E-065). Dieselben Bausteine wie die
 * Kartenspur (`scripts-client/karussell.js`), aber auf dem Foto statt
 * daneben: Neben dem Bild kosteten sie Breite, die das Foto braucht. Pfeile
 * erst ab 34rem – am Telefon wischt man, die Punkte zeigen „2 von 3“.
 */
.modal-bilder {
  position: relative;
}

.modal-bilder .karussell-pfeil {
  position: absolute;
  top: 50%;
  z-index: 1;
  transform: translateY(-50%);
  background: color-mix(in srgb, var(--surface-1) 88%, transparent);
}

.modal-bilder .karussell-vorher {
  left: 10px;
}

.modal-bilder .karussell-naechste {
  right: 10px;
}

@media (min-width: 34rem) {
  .modal-bilder .karussell-pfeil {
    display: grid;
  }
}

/* Spezifischer als die Regel darüber – sonst stünden tote Pfeile da. */
.modal-bilder .karussell-pfeil[hidden] {
  display: none;
}

.modal-bilder .karussell-punkte {
  position: absolute;
  inset: auto 0 12px;
  margin: 0;
  pointer-events: none;
}

.modal-bilder .karussell-punkte span {
  background: color-mix(in srgb, var(--surface-1) 75%, transparent);
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--text) 25%, transparent);
}

.modal-bilder .karussell-punkte span.is-active {
  background: var(--accent);
}

/* Jedes Foto ist ein Knopf zur Großansicht (setzt scripts-client/modal.js). */
.modal-foto {
  display: block;
  padding: 0;
  border: none;
  background: none;
  cursor: zoom-in;
}

.modal-foto img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/*
 * Großansicht (5.23): die Fotos über die ganze Fläche, ungeschnitten. Es ist
 * dieselbe Spur, nur groß – so bleibt das Foto, bei dem man war, und
 * Wischen, Pfeile und Punkte gehen weiter.
 */
.modal.is-gross .modal-bilder {
  position: fixed;
  inset: 0;
  z-index: 3;
  display: flex;
  align-items: center;
  /* Deckend: Durchscheinender Text lenkt vom Foto ab. */
  background: var(--text);
}

.modal.is-gross .modal-gallery {
  width: 100%;
  height: 100%;
}

.modal.is-gross .modal-gallery > * {
  aspect-ratio: auto;
  height: 100%;
}

.modal.is-gross .modal-foto {
  cursor: default;
}

.modal.is-gross .modal-foto img {
  object-fit: contain;
  /* Ganz zeigen heißt mittig zeigen – der Fokuspunkt gilt nur fürs Zuschneiden. */
  object-position: 50% 50%;
}

.modal-gross-zu {
  display: none;
}

.modal.is-gross .modal-gross-zu {
  position: fixed;
  top: calc(12px + env(safe-area-inset-top, 0px));
  right: 12px;
  z-index: 4;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  font-size: 1.6rem;
  line-height: 1;
  color: var(--heading);
  background: var(--surface-1);
  border: none;
  border-radius: var(--radius-pill);
  cursor: pointer;
}

.modal-gallery > * {
  flex: 0 0 100%;
  scroll-snap-align: start;
  aspect-ratio: 4 / 3;
  object-fit: cover;
}

.modal-body {
  padding: 22px 24px 26px;
  display: flex;
  flex-direction: column;
  gap: 0.7rem;
  align-items: flex-start;
}

/* Aufzählung in Beschreibungen (5.13): Zeilen mit „- “ im Portal. */
.aufzaehlung {
  margin: 0;
  padding-left: 1.2em;
  display: grid;
  gap: 0.2em;
}

.aufzaehlung li::marker {
  color: var(--accent);
}

/*
 * Ab 60rem stehen Bilder und Text nebeneinander. Untereinander füllte das
 * Bild auf einem Laptop schon die ganze Höhe, und vom Text war nichts zu
 * sehen – dass man im Fenster scrollen kann, merkt niemand (Rückmeldung vom
 * 05.10.2026). Der Text scrollt jetzt für sich, die Bilder bleiben stehen.
 * Nur im Angebot: Die Großansicht der Galerie hat keinen Text.
 */
@media (min-width: 60rem) {
  .catalog .modal-panel {
    width: min(1040px, 100%);
    height: min(88vh, 760px);
    display: grid;
    grid-template-columns: 3fr 2fr;
    overflow: hidden;
  }

  .catalog .modal-bilder,
  .catalog .modal-gallery {
    height: 100%;
    min-height: 0;
  }

  .catalog .modal-gallery > * {
    aspect-ratio: auto;
    height: 100%;
  }

  .catalog .modal-body {
    overflow-y: auto;
    padding-top: 26px;
  }

  /* Platz für den Schließen-Knopf, der jetzt über dem Text liegt. */
  .catalog .modal-body h3 {
    padding-right: 44px;
  }
}

/*
 * Am Telefon ein ganzes Blatt statt eines schwebenden Fensters (5.22, E-065).
 * Als Fenster stieß es oben und unten an die Leisten von Safari, und daneben
 * schien die Seite unabgedunkelt durch. Der Hintergrund reicht deshalb weit
 * über den Bildschirm hinaus – auch unter die Leisten – und ist deckend.
 */
@media (max-width: 599px) {
  .catalog .modal {
    padding: 0;
    align-items: stretch;
  }

  .catalog .modal-backdrop {
    inset: -50vh 0;
    background: var(--surface-1);
  }

  .catalog .modal-panel {
    width: 100%;
    height: 100vh;
    height: 100dvh;
    max-height: none;
    border: none;
    border-radius: 0;
  }

  /* Beim Lesen weit unten bleibt das Kreuz erreichbar. */
  .catalog .modal-close {
    position: fixed;
    top: calc(10px + env(safe-area-inset-top, 0px));
    box-shadow: 0 2px 10px color-mix(in srgb, var(--text) 18%, transparent);
  }

  /* Der Knopf darunter klebt nicht an der Leiste des Browsers. */
  .catalog .modal-body {
    padding-bottom: calc(48px + env(safe-area-inset-bottom, 0px));
  }
}

/* Hintergrund nicht mitscrollen, solange der Dialog offen ist. */
body.modal-offen {
  overflow: hidden;
}

/* ============================================================
   Kategorien
   ============================================================ */
/* ============================================================
   Galerie: Impressionen
   ============================================================

   Ein Betrieb, dessen Ware man ansieht, verkauft über Bilder. Deshalb hier
   keine Karten mit Text, sondern nur Fotos – dicht genug, dass man die Menge
   sieht, groß genug, dass man etwas erkennt.

   `auto-fill` statt `auto-fit`: Bei drei Fotos sollen es drei Kacheln
   bleiben und nicht drei auf volle Breite gezogene Riesen. */
.galerie-raster {
  display: grid;
  gap: 12px;
  grid-template-columns: repeat(auto-fill, minmax(min(220px, 100%), 1fr));
}

.galerie-kachel {
  display: block;
  overflow: hidden;
  border-radius: var(--radius-card);
  background: var(--surface-2);
  /* Gleiche Höhe für alle, egal welches Format hochgeladen wurde – sonst wird
     das Raster zum Flickenteppich. */
  aspect-ratio: 4 / 3;
}

.galerie-kachel img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 0.4s ease;
}

.galerie-kachel:hover img,
.galerie-kachel:focus-visible img {
  transform: scale(1.04);
}

/* Bildunterschrift auf dem Foto (Migration 0011): ein kleines Schild unten
   links, hell hinterlegt, damit es auf jedem Foto lesbar bleibt. */
.galerie-kachel {
  position: relative;
}

.galerie-unterschrift {
  position: absolute;
  left: 10px;
  bottom: 9px;
  max-width: calc(100% - 20px);
  padding: 6px 11px;
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--surface-1) 88%, transparent);
  color: var(--text);
  font-size: 0.78rem;
  line-height: 1.3;
}

/* ============================================================
   Fotoband: laufende Bildspur (E-053)
   ============================================================
   Zwei gleiche Sätze nebeneinander; die Animation schiebt um genau die
   Hälfte, dann beginnt es nahtlos von vorn. Ohne `laeuft` (kein Skript,
   weniger Bewegung, `stil.bewegung: ruhig`) lässt sich das Band wischen. */
.section.fotoband {
  padding-block: 16px;
  overflow: hidden;
}

.fotoband-spur {
  display: flex;
  width: max-content;
}

.fotoband-spur:not(.laeuft) {
  width: auto;
  overflow-x: auto;
  scroll-snap-type: x proximity;
}

/* Der zweite Satz ist nur für die nahtlose Schleife da. */
.fotoband-spur:not(.laeuft) .fotoband-satz[aria-hidden='true'] {
  display: none;
}

.fotoband-satz {
  display: flex;
  gap: 14px;
  padding-inline: 7px;
}

.fotoband-kachel {
  flex: 0 0 auto;
  width: var(--fotoband-breite);
  height: var(--fotoband-hoehe);
  margin: 0;
  overflow: hidden;
  border-radius: var(--radius-card);
  background: var(--surface-3);
  scroll-snap-align: start;
}

.fotoband-kachel:nth-child(2n) {
  width: calc(var(--fotoband-breite) * 0.82);
}

.fotoband-kachel:nth-child(3n) {
  width: calc(var(--fotoband-breite) * 1.16);
}

.fotoband-kachel img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.fotoband-platzhalter {
  width: 100%;
  height: var(--fotoband-hoehe);
}

.fotoband-spur.laeuft {
  animation: fotoband-lauf var(--fotoband-dauer) linear infinite;
}

.fotoband-spur.laeuft:hover {
  animation-play-state: paused;
}

@keyframes fotoband-lauf {
  to {
    transform: translateX(-50%);
  }
}

/* Der Knopf zum Anhalten: klein, aber eine volle Tippfläche. */
.fotoband-knopf {
  display: block;
  min-height: 44px;
  margin: 6px auto 0;
  padding: 0 14px;
  border: 0;
  background: none;
  color: var(--text-muted);
  font: inherit;
  font-size: 0.85rem;
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}

@media (max-width: 860px) {
  .fotoband-satz {
    gap: 10px;
    padding-inline: 5px;
  }

  .fotoband-kachel {
    width: calc(var(--fotoband-breite) * 0.75);
    height: calc(var(--fotoband-hoehe) * 0.74);
  }

  .fotoband-kachel:nth-child(2n) {
    width: calc(var(--fotoband-breite) * 0.65);
  }

  .fotoband-kachel:nth-child(3n) {
    width: calc(var(--fotoband-breite) * 0.87);
  }
}

.galerie-hinweis {
  margin-top: 16px;
}

/* In der Großansicht zählt das Bild, nicht der Rahmen. */
.galerie-gross .modal-panel {
  background: transparent;
  border: none;
  padding: 0;
  max-width: min(92vw, 1100px);
}

.galerie-gross .modal-panel img {
  width: 100%;
  height: auto;
  max-height: 86vh;
  object-fit: contain;
  border-radius: var(--radius-card);
}

@media (prefers-reduced-motion: reduce) {
  .galerie-kachel img {
    transition: none;
  }

  .galerie-kachel:hover img,
  .galerie-kachel:focus-visible img {
    transform: none;
  }
}

.category-grid {
  display: grid;
  gap: 26px;
  grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr));
}

.category {
  position: relative;
  display: flex;
  align-items: flex-end;
  min-height: 300px;
  border-radius: var(--radius-card);
  overflow: hidden;
  border: 1px solid var(--border);
}

.category-media {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  aspect-ratio: auto;
  object-fit: cover;
}

.category-body {
  position: relative;
  width: 100%;
  padding: 26px;
  color: var(--on-accent);
  background: linear-gradient(to top, color-mix(in srgb, var(--heading) 88%, transparent), transparent);
}

.category-body h3 {
  color: var(--on-accent);
  font-size: 1.6rem;
}

.category-body p {
  font-size: 0.95rem;
  font-weight: 300;
  max-width: 44ch;
  margin: 0.3rem 0 0.9rem;
}

.category-body a {
  color: var(--on-accent);
  font-weight: 600;
  font-size: 0.9rem;
}

/* --- Variante bogen: ein Band pro Anlass (E-038) --- */
.anlass-liste {
  display: flex;
  flex-direction: column;
  gap: clamp(64px, 9vw, 120px);
}

.anlass-bogen {
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr);
  gap: clamp(32px, 6vw, 72px);
  align-items: center;
}

/* Jedes zweite Band spiegelt: Bild rechts, Text links. Sonst stehen die
   Bänder wie ein Stapel gleicher Karteikarten untereinander. */
.anlass-bogen:nth-child(even) {
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
}

.anlass-bogen:nth-child(even) .anlass-bilder {
  order: 2;
  flex-direction: row-reverse;
}

.anlass-bilder {
  display: flex;
  gap: 20px;
  align-items: flex-end;
  justify-content: center;
}

.anlass-haupt {
  flex: 0 1 400px;
  /* Ein ruhiger Rand um das Hauptbild – wie ein Passepartout. */
  border: 10px solid var(--surface-3);
}

.anlass-details {
  flex: 0 0 150px;
  display: flex;
  flex-direction: column;
  gap: 16px;
  margin: 0;
  padding: 0 0 40px;
  list-style: none;
}

.anlass-detail {
  overflow: hidden;
  border-radius: var(--radius-signature);
}

.anlass-detail .media {
  display: block;
  width: 100%;
  aspect-ratio: 3 / 4;
  object-fit: cover;
}

.anlass-haupt .media {
  display: block;
  width: 100%;
  object-fit: cover;
}

.anlass-text {
  display: flex;
  flex-direction: column;
  gap: 1.1rem;
  align-items: flex-start;
}

.anlass-text h3 {
  font-size: clamp(2.2rem, 4.5vw, 3.6rem);
  font-weight: 400;
  line-height: 1.04;
}

.anlass-text p {
  font-size: 1.08rem;
  max-width: 46ch;
}

/* --- Variante vollbild: Foto über die ganze Breite, Text auf einer Karte --- */
.categories-vollbild .anlass-liste {
  gap: 0;
}

.anlass-vollbild {
  position: relative;
  display: flex;
  align-items: flex-end;
  min-height: min(82vh, 760px);
  overflow: hidden;
  background: var(--surface-3);
}

.anlass-vollbild-bilder {
  position: absolute;
  inset: 0;
}

/* Wie im Hero: alle Bilder übereinander, sichtbar ist eines. */
.anlass-slide {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  aspect-ratio: auto;
  object-fit: cover;
  opacity: 0;
  transition: opacity 1.2s ease;
}

.anlass-slide.is-active {
  opacity: 1;
}

/* Dieselbe Rechnung wie `.wrap`: Die Karte beginnt an derselben Kante wie die
   Überschrift der Section, obwohl das Foto bis an den Rand läuft. */
.anlass-vollbild-rahmen {
  position: relative;
  box-sizing: border-box;
  width: 100%;
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 72px var(--gutter);
  display: flex;
}

/* Jedes zweite Band: Karte rechts. */
.anlass-vollbild:nth-child(even) .anlass-vollbild-rahmen {
  justify-content: flex-end;
}

/* Die Karte hat eine volle Fläche statt eines Verlaufs übers Foto: Der Text ist
   so über jedem Bild lesbar, egal wie hell es ist. */
.anlass-karte {
  width: min(460px, 100%);
  box-sizing: border-box;
  padding: 40px;
  background: var(--surface-1);
  border-radius: var(--radius-card);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1rem;
}

.anlass-karte h3 {
  font-size: clamp(2rem, 4vw, 3.2rem);
  font-weight: 400;
  line-height: 1.04;
}

/* --- Variante collage: Stimmungsbild und Abzüge wie auf einem Moodboard ---
   Das Stimmungsbild steht neben dem Text (BACKLOG 5.24), die Abzüge liegen
   darunter als Reihe über die ganze Breite, alle gleich groß. Standen sie
   in der Textspalte, wurde diese viel höher als das Bild und links blieb
   eine Lücke – wirkte unharmonisch. */
.anlass-collage {
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  grid-template-areas:
    'haupt text'
    'abzuege abzuege';
  gap: 40px clamp(24px, 4vw, 48px);
  align-items: center;
}

.anlass-collage:nth-child(even) {
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  grid-template-areas:
    'text haupt'
    'abzuege abzuege';
}

.anlass-collage .anlass-text {
  grid-area: text;
}

.collage-haupt {
  grid-area: haupt;
  overflow: hidden;
  border-radius: var(--radius-card);
}

.collage-haupt .media {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
}

/* Flex statt Raster, damit ein oder zwei Abzüge mittig stehen statt links.
   Die Breite ist begrenzt: Über 1200 px gestreckt würden Abzüge so groß wie
   das Stimmungsbild. */
.collage-abzuege {
  --abzug-luecke: 22px;
  grid-area: abzuege;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--abzug-luecke);
  width: min(100%, 760px);
  justify-self: center;
  margin: 0;
  padding: 0 8px 20px;
  list-style: none;
}

.collage-abzuege li {
  width: calc((100% - 2 * var(--abzug-luecke)) / 3);
}

/* Abzüge wie aus dem Fotolabor: weißer Rand, ein Hauch Schatten, leicht
   schräg gelegt. Die Drehung ist statisch – nichts bewegt sich. */
.abzug {
  margin: 0;
  padding: 10px 10px 14px;
  background: var(--card-bg);
  box-shadow: 0 8px 20px color-mix(in srgb, var(--text) 12%, transparent);
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.collage-abzuege li:nth-child(1) .abzug {
  transform: rotate(-2.5deg);
}

.collage-abzuege li:nth-child(2) .abzug {
  transform: rotate(1.8deg) translateY(20px);
}

.collage-abzuege li:nth-child(3) .abzug {
  transform: rotate(-1.4deg) translateY(6px);
}

.abzug .media {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
}

.abzug figcaption {
  font-family: var(--f-display);
  font-style: italic;
  font-size: 1rem;
  text-align: center;
  color: var(--text);
}

/* ============================================================
   Ablauf-Schritte
   ============================================================ */
.steps-list {
  display: grid;
  gap: 22px;
  grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr));
  list-style: none;
  counter-reset: none;
}

/*
 * Vier Schritte: zwei mal zwei oder vier in einer Reihe, nie drei plus einer
 * allein darunter (E-056). Das freie Raster brach auf dem Tablet hochkant
 * genau so um – der vierte Schritt sah aus wie vergessen.
 */
.steps-list:has(> .step:nth-child(4):last-child) {
  grid-template-columns: 1fr;
}

@media (min-width: 34rem) {
  .steps-list:has(> .step:nth-child(4):last-child) {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 70rem) {
  .steps-list:has(> .step:nth-child(4):last-child) {
    grid-template-columns: repeat(4, 1fr);
  }
}

/*
 * Nummer und Titel in einer Zeile: Die Nummer allein in der ersten Zeile
 * ließ jede Karte höher und leerer wirken (Rückmeldung vom 05.10.2026). Ein
 * zweizeiliger Titel läuft bündig unter sich weiter, nicht unter der Nummer.
 */
.step {
  display: grid;
  grid-template-columns: auto 1fr;
  column-gap: 0.55rem;
  align-items: baseline;
  padding: 26px 22px;
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
}

.step > :not(.step-number, h3) {
  grid-column: 1 / -1;
}

main > .section:nth-of-type(3n + 1) .step {
  background: var(--surface-2);
}

.step-number {
  font-family: var(--f-display);
  font-style: italic;
  font-size: 1.4rem;
  color: var(--accent-2);
}

.step h3 {
  font-size: 1.05rem;
  margin: 0 0 0.35rem;
}

.step p {
  font-size: 0.9rem;
  font-weight: 300;
}

/* ============================================================
   Kalender
   ============================================================ */
.calendar-nav {
  display: none;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 1rem;
}

/* Die Pfeile erscheinen erst, wenn JavaScript das Umschalten übernimmt. */
.calendar-widget.is-interactive .calendar-nav {
  display: flex;
}

.calendar-arrow {
  min-width: 44px;
  min-height: 44px;
  font-size: 1.4rem;
  line-height: 1;
  background: var(--surface-1);
  color: var(--heading);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  cursor: pointer;
}

.calendar-arrow:disabled {
  opacity: 0.4;
  cursor: default;
}

.calendar-current {
  font-family: var(--f-display);
  font-size: 1.15rem;
  color: var(--heading);
}

/*
 * Ohne JavaScript stehen die ersten drei Monate untereinander; mit JavaScript
 * ist genau einer sichtbar und die Pfeile schalten um.
 */
.calendar-month {
  margin-bottom: 1.6rem;
}

.calendar-month:nth-of-type(n + 4) {
  display: none;
}

.calendar-widget.is-interactive .calendar-month {
  display: none;
  margin-bottom: 0;
}

.calendar-widget.is-interactive .calendar-month.is-active {
  display: block;
}

/* Der Monatstitel wiederholt die Beschriftung der Navigation – im
   interaktiven Zustand deshalb ausblenden. */
.calendar-widget.is-interactive .calendar-month-title {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
}

/*
 * Breite begrenzt: über die volle Textbreite gezogen werden die Tageszellen auf
 * dem Desktop handtellergroß und der Kalender wirkt wie ein Tabellenkalkulat.
 * 34rem entsprechen etwa der Breite eines gedruckten Monatskalenders.
 *
 * Mittig statt linksbündig: Ein schmaler Block am linken Rand ließ auf dem
 * Desktop die rechte Hälfte der Section leer, als fehle dort etwas. Überschrift,
 * Legende und Hinweis ziehen mit, sonst stünde der Titel über einer Lücke.
 */
.calendar-widget {
  max-width: 34rem;
  margin-inline: auto;
}

.calendar .section-head,
.calendar .section-head .lead {
  margin-inline: auto;
  text-align: center;
}

.calendar-legend {
  justify-content: center;
}

.calendar .wrap > .muted {
  text-align: center;
}

.calendar-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 4px;
}

.calendar-weekday {
  text-align: center;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
  padding-bottom: 4px;
}

.calendar-cell {
  display: flex;
  align-items: center;
  justify-content: center;
  aspect-ratio: 1;
  font-size: 0.9rem;
  border-radius: 8px;
  border: 1px solid transparent;
}

.calendar-cell.is-empty {
  border: none;
}

.calendar-cell.is-free {
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  color: var(--heading);
  border-color: color-mix(in srgb, var(--accent) 26%, transparent);
}

.calendar-cell.is-booked {
  background: color-mix(in srgb, var(--accent-2) 28%, transparent);
  color: var(--text);
  /* Nicht nur Farbe: ein Muster unterscheidet belegt auch ohne Farbwahrnehmung. */
  background-image: repeating-linear-gradient(
    45deg,
    transparent 0 4px,
    color-mix(in srgb, var(--accent-2) 45%, transparent) 4px 6px
  );
}

/* Ein freier Tag als Link zum Formular (E-037): füllt die ganze Zelle, damit
   die Trefferfläche so groß ist wie das Kästchen, das man sieht. */
.calendar-link {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  color: inherit;
  text-decoration: none;
  border-radius: inherit;
}

.calendar-link:hover,
.calendar-cell.is-selected {
  background: color-mix(in srgb, var(--accent) 30%, transparent);
}

.calendar-cell.is-selected {
  border-color: var(--accent);
  font-weight: 700;
}

.calendar-cell.is-past {
  color: var(--text-muted);
  opacity: 0.45;
}

/*
 * Kalender zum Antippen (E-061): alle kommenden Tage gleich, ohne Farbe für
 * frei oder belegt. Der Zustand erscheint erst in der Zeile unter dem Raster.
 */
.calendar-cell.is-neutral {
  color: var(--heading);
  border-color: var(--border);
}

/* Der Knopf füllt die Zelle, damit die Trefferfläche so groß ist wie das
   Kästchen – am Telefon sind das bei 390 px gut 44 px. */
.calendar-tag {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  padding: 0;
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  border-radius: inherit;
  cursor: pointer;
}

.calendar-tag:hover,
.calendar-cell.is-angetippt {
  background: color-mix(in srgb, var(--accent) 22%, transparent);
}

.calendar-cell.is-angetippt {
  border-color: var(--accent);
  font-weight: 700;
}

.calendar-tag:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/*
 * Antwort auf das Antippen (E-071, BACKLOG 5.28). Ohne Skript steht hier
 * der Link zur Anfrage unter dem Raster. Mit Skript ist sie leer, bis
 * jemand tippt – dann ist sie am Laptop eine Sprechblase über dem Tag und
 * am Telefon ein Blatt am unteren Rand. Sie liegt über der Seite, statt
 * Platz unter dem Raster zu belegen: Vorher standen dort drei Zeilen, und
 * alles darunter sprang bei jedem Antippen.
 */
.calendar-antwort {
  margin-top: 1rem;
  text-align: center;
}

.calendar-antwort p {
  margin: 0;
}

.calendar-tipp {
  margin: 0.8rem 0 0;
  font-size: 0.85rem;
  text-align: center;
  color: var(--text-muted);
}

.calendar-widget.is-interactive {
  position: relative;
}

.calendar-widget.is-interactive .calendar-antwort {
  /* Wo die Blase steht; setzt das Skript nach dem angetippten Tag. */
  --blase-links: 0px;
  --blase-oben: 0px;
  --blase-spitze: 50%;
  display: none;
}

.calendar-widget.is-interactive .calendar-antwort.is-offen {
  display: grid;
  justify-items: center;
  gap: 0.35rem;
  position: absolute;
  z-index: 5;
  left: var(--blase-links);
  top: var(--blase-oben);
  translate: 0 calc(-100% - 12px);
  width: max-content;
  max-width: min(17rem, 100%);
  margin: 0;
  padding: 0.75rem 1rem 0.9rem;
  font-size: 0.9rem;
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: 14px;
  box-shadow: 0 10px 26px -12px color-mix(in srgb, var(--heading) 45%, transparent);
}

/* Die Spitze zeigt auf den Tag, auch wenn die Blase am Rand zur Seite rückt. */
.calendar-antwort.is-offen::after {
  content: '';
  position: absolute;
  left: var(--blase-spitze);
  bottom: -7px;
  width: 12px;
  height: 12px;
  background: inherit;
  border-right: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  translate: -50% 0;
  rotate: 45deg;
}

.calendar-antwort-tag {
  font-weight: 700;
  color: var(--heading);
}

.calendar-antwort .btn {
  margin-top: 0.3rem;
  padding: 0.45rem 1.1rem;
  font-size: 0.85rem;
}

/* Schließen gibt es als Knopf nur am Telefon; die Blase schließt Daneben-
   Tippen und Escape. */
.calendar-antwort-zu {
  display: none;
}

/* Am Telefon: ein Blatt von unten, wie die Detailansicht der Angebote. */
@media (max-width: 599px) {
  .calendar-widget.is-interactive .calendar-antwort.is-offen {
    position: fixed;
    inset: auto 0 0;
    translate: none;
    width: auto;
    max-width: none;
    gap: 0.3rem;
    padding: 1.4rem 1.4rem calc(1.4rem + env(safe-area-inset-bottom));
    font-size: 1rem;
    border-width: 1px 0 0;
    border-radius: 22px 22px 0 0;
    box-shadow: 0 -16px 40px -20px color-mix(in srgb, var(--heading) 55%, transparent);
    animation: calendar-blatt 0.25s ease-out;
  }

  .calendar-antwort.is-offen::after {
    display: none;
  }

  .calendar-antwort-tag {
    font-family: var(--f-display);
    font-size: 1.3rem;
    font-weight: 400;
  }

  .calendar-antwort .btn {
    justify-self: stretch;
    margin-top: 0.8rem;
    padding: 0.85rem 1rem;
    font-size: 1rem;
  }

  .calendar-antwort-zu {
    display: grid;
    place-items: center;
    position: absolute;
    top: 6px;
    right: 6px;
    width: 44px;
    height: 44px;
    padding: 0;
    font-size: 1.6rem;
    line-height: 1;
    color: var(--text-muted);
    background: none;
    border: 0;
    cursor: pointer;
  }
}

@keyframes calendar-blatt {
  from {
    translate: 0 100%;
  }
}

@media (prefers-reduced-motion: reduce) {
  .calendar-widget.is-interactive .calendar-antwort.is-offen {
    animation: none;
  }
}

.calendar-legend {
  display: flex;
  gap: 10px;
  margin-top: 1rem;
}

.chip {
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 0.15rem 0.65rem;
  border-radius: var(--radius-pill);
}

.chip-frei {
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  color: var(--heading);
}

.chip-belegt {
  background: color-mix(in srgb, var(--accent-2) 28%, transparent);
  color: var(--text);
}

/* ============================================================
   Kontakt
   ============================================================ */
.contact-grid {
  display: grid;
  grid-template-columns: 0.9fr 1.1fr;
  gap: 56px;
}

.contact-info p {
  font-weight: 300;
  margin-bottom: 1rem;
}

.contact-info strong {
  color: var(--heading);
}

.contact-form {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.form-row,
.form-felder {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}

/* Freitext über die ganze Breite, alle anderen Felder zu zweit nebeneinander. */
.field-breit {
  grid-column: 1 / -1;
}

/* Zwei Wege, eine Nachricht abzuschicken (E-037), übereinander – als volle
   Knöpfe sind sie auf dem Telefon am leichtesten zu treffen. */
.anfrage-knoepfe {
  display: grid;
  gap: 10px;
}

.anfrage-ersatz {
  display: grid;
  gap: 10px;
  justify-items: start;
  font-size: 0.9rem;
}

.anfrage-ersatz[hidden],
.contact-form[hidden] {
  display: none;
}

/*
 * Mehrfachauswahl als antippbare Kärtchen (BACKLOG 5.17). Die Checkbox
 * bleibt im Dokument – unsichtbar, aber fokussierbar –, damit Tastatur und
 * Screenreader sie wie gewohnt bedienen; das Kärtchen zeigt ihren Zustand.
 */
.wahl-feld {
  border: none;
  margin: 0;
  padding: 0;
  min-width: 0;
}

.wahl-feld legend {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--heading);
  margin-bottom: 0.4rem;
  padding: 0;
}

.wahl-feld legend small {
  font-weight: 400;
  color: var(--text-muted);
}

.wahl-gruppe {
  font-size: 0.72rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin: 0.6rem 0 0.35rem;
}

.wahl-liste {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 8px;
}

.wahl {
  position: relative;
  margin: 0;
  font-weight: 400;
}

.wahl input {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
}

.wahl span {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0.4rem 1rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  background: var(--surface-1);
  color: var(--text);
  font-size: 0.92rem;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s;
}

.wahl input:checked + span {
  background: color-mix(in srgb, var(--accent) 22%, var(--surface-1));
  border-color: var(--accent);
  color: var(--heading);
}

.wahl input:checked + span::before {
  content: "✓";
  margin-right: 0.4em;
}

.wahl input:focus-visible + span {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/*
 * Mehrfachauswahl als Liste (`"darstellung": "liste"`, E-072): eine Zeile je
 * Angebot mit Häkchen links, feine Linie dazwischen – ruhiger als Kärtchen.
 * Das Kästchen ist gezeichnet (`::before`), die echte Checkbox bleibt wie
 * bei den Kärtchen unsichtbar und bedienbar. Jede Zeile ist mindestens 44 px
 * hoch, damit der Finger trifft.
 */
.wahl-feld-liste {
  /* Die Linie aus der Textfarbe gemischt: Die Rahmenfarbe eines Themes ist
     oft fast so hell wie eine Karte und verschwände darauf. */
  --wahl-linie: color-mix(in srgb, var(--text) 16%, transparent);
}

.wahl-feld-liste .wahl-liste {
  display: block;
  margin-bottom: 0;
}

.wahl-feld-liste .wahl + .wahl {
  border-top: 1px solid var(--wahl-linie);
}

.wahl-feld-liste .wahl span {
  display: flex;
  gap: 0.75rem;
  min-height: 44px;
  padding: 0.5rem 0.1rem;
  border: 0;
  border-radius: 0;
  background: transparent;
}

.wahl-feld-liste .wahl span::before {
  content: "";
  flex: 0 0 auto;
  width: 1.1rem;
  height: 1.1rem;
  margin: 0;
  border: 1.5px solid color-mix(in srgb, var(--text) 35%, transparent);
  border-radius: 4px;
  background: var(--surface-1);
}

.wahl-feld-liste .wahl input:checked + span {
  background: transparent;
  color: var(--heading);
}

.wahl-feld-liste .wahl input:checked + span::before {
  content: "✓";
  display: grid;
  place-items: center;
  margin: 0;
  font-size: 0.8rem;
  line-height: 1;
  /* Dieselbe Farbe wie der Hauptknopf darunter – das Häkchen gehört zur
     Anfrage, nicht zur Schrift. */
  color: var(--btn-solid-color);
  background: var(--btn-solid-bg);
  border-color: var(--btn-solid-bg);
}

/* „Sonstiges“ steht als eigene Liste am Ende – mit Linie wie die anderen. */
.wahl-feld-liste .wahl-liste:last-of-type {
  border-top: 1px solid var(--wahl-linie);
}

label {
  display: block;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--heading);
  margin-bottom: 0.3rem;
}

input,
select,
textarea {
  width: 100%;
  padding: 0.75rem 0.9rem;
  font-family: var(--f-body);
  font-size: 0.95rem;
  color: var(--text);
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: 10px;
}

textarea {
  resize: vertical;
}

/* Honeypot: unsichtbar, aber nicht display:none – manche Ausfüller überspringen
   versteckte Felder, und genau die will man erwischen. */
.honeypot {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.form-status:empty {
  display: none;
}

.form-status {
  font-size: 0.9rem;
  font-weight: 600;
}

.form-status[data-state='ok'] {
  color: var(--heading);
}

.form-status[data-state='fehler'] {
  color: var(--accent-2-hover);
}

/*
 * Zugeklappte „Weitere Angaben“ (E-068). Die Zeile ist ein großes Ziel
 * zum Antippen; Plus und Minus sagen, dass sich etwas öffnet.
 */
.form-weitere {
  border: 1px dashed var(--border);
  border-radius: 14px;
  padding: 0 16px;
  background: color-mix(in srgb, var(--surface-2) 45%, transparent);
}

.form-weitere summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  min-height: 52px;
  list-style: none;
  cursor: pointer;
  font-weight: 600;
  color: var(--heading);
}

.form-weitere summary::-webkit-details-marker {
  display: none;
}

.form-weitere summary small {
  font-weight: 400;
  color: var(--text-muted);
  margin-right: auto;
}

.form-weitere summary::after {
  content: "+";
  font-size: 1.4rem;
  font-weight: 300;
  line-height: 1;
  color: var(--accent-2);
}

.form-weitere[open] summary::after {
  content: "–";
}

.form-weitere > .form-felder {
  padding: 4px 0 16px;
}

::placeholder {
  color: var(--text-muted);
  opacity: 0.7;
}

/*
 * Variante `karte` (E-068): rechts im gewohnten Raster, das Formular als
 * ruhige Karte. Die Knöpfe stehen ab dem Laptop nebeneinander, der erste –
 * WhatsApp oder der einzige Weg – breiter: Er ist der Hauptweg.
 */
.contact-karte .contact-form {
  padding: 30px 32px;
  background: var(--card-bg, var(--surface-1));
  border: 1px solid var(--border);
  border-radius: 22px;
  box-shadow: 0 18px 40px -26px color-mix(in srgb, var(--heading) 45%, transparent);
}

.contact-karte .anfrage-knoepfe {
  grid-template-columns: 1.4fr 1fr;
  align-items: center;
}

.contact-karte .anfrage-knoepfe .btn {
  justify-content: center;
  text-align: center;
}

/* Der zweite Weg nimmt die „stille“ Schaltfläche des Themes, wie überall
   sonst (E-072). Bis v0.30 stand hier ein eigener Rahmen-Knopf; Themes, die
   ihre stille Schaltfläche gefüllt haben (Altrosa), wollten ihn auch hier
   gefüllt. Die Vorgabe des Vertrags ist ohnehin ein Rahmen-Knopf. */

/* Beide Spalten beginnen oben; die linke bleibt am Laptop beim Scrollen
   neben der längeren Karte stehen, statt eine leere Fläche zu lassen. */
.contact-karte .contact-grid {
  align-items: start;
}

.contact-karte .contact-info .section-head {
  margin-bottom: 1.4rem;
}

@media (min-width: 861px) {
  .contact-karte .contact-info {
    position: sticky;
    top: 110px;
  }
}

.contact-karte .form-hinweis {
  text-align: center;
  font-size: 0.85rem;
}

@media (max-width: 599px) {
  .contact-karte .contact-form {
    padding: 22px 18px;
    border-radius: 18px;
  }

  .contact-karte .anfrage-knoepfe {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 860px) {
  .contact-grid {
    grid-template-columns: 1fr;
    gap: 36px;
  }

  .form-row,
  .form-felder {
    grid-template-columns: 1fr;
  }

  /* Anlass-Bänder am Telefon: Bild oben, Details als Streifen zum Wischen,
     Text darunter. Die Spiegelung entfällt – untereinander gibt es kein
     links und rechts. */
  .anlass-bogen,
  .anlass-bogen:nth-child(even) {
    grid-template-columns: minmax(0, 1fr);
  }

  .anlass-bilder,
  .anlass-bogen:nth-child(even) .anlass-bilder {
    order: 0;
    flex-direction: column;
    align-items: stretch;
  }

  .anlass-haupt {
    flex: none;
    width: 100%;
    max-width: 420px;
    align-self: center;
    box-sizing: border-box;
  }

  .anlass-details {
    flex: none;
    flex-direction: row;
    gap: 12px;
    padding: 0 0 4px;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    /* Der Streifen darf bis an den Bildschirmrand laufen – so sieht man, dass
       es weitergeht. */
    margin-right: calc(-1 * var(--gutter));
  }

  .anlass-detail {
    flex: 0 0 42%;
    scroll-snap-align: start;
  }

  /* Vollbild am Telefon: Foto oben, Karte schiebt sich etwas darüber. */
  .anlass-vollbild {
    display: block;
    min-height: 0;
    background: none;
  }

  .anlass-vollbild-bilder {
    position: relative;
    height: 62vh;
    min-height: 320px;
  }

  .anlass-vollbild-rahmen {
    padding-block: 0 48px;
    margin-top: -56px;
  }

  .anlass-karte {
    padding: 28px 24px;
  }

  /* Collage am Tablet: Bild und Text gleich breit nebeneinander, Abzüge
     weniger schräg. Untereinander erst am Telefon (unten). */
  .anlass-collage,
  .anlass-collage:nth-child(even) {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  }

  .collage-abzuege li:nth-child(1) .abzug {
    transform: rotate(-1.5deg);
  }

  .collage-abzuege li:nth-child(2) .abzug {
    transform: rotate(1.2deg) translateY(12px);
  }
}

/* Collage am Telefon: untereinander – Bild, Text, Abzüge. Nebeneinander
   wären beide Spalten zu schmal zum Lesen; drei Abzüge in einer Reihe
   wären briefmarkengroß, deshalb zwei je Reihe. */
@media (max-width: 599px) {
  .anlass-collage,
  .anlass-collage:nth-child(even) {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas:
      'haupt'
      'text'
      'abzuege';
  }

  .collage-abzuege li {
    width: calc((100% - var(--abzug-luecke)) / 2);
  }
}

/* ============================================================
   Fußzeile
   ============================================================ */
.site-footer {
  background: var(--footer-bg);
  color: var(--footer-text);
  border-top: var(--footer-border);
  padding: 52px 0 32px;
}

.footer-grid {
  display: flex;
  justify-content: space-between;
  gap: 32px;
  flex-wrap: wrap;
  margin-bottom: 2rem;
}

.site-footer .logo {
  color: var(--footer-text);
}

.site-footer .logo em {
  color: var(--footer-logo-note);
}

.footer-links {
  display: flex;
  gap: 22px;
  flex-wrap: wrap;
  list-style: none;
  font-size: 0.9rem;
}

.footer-links a {
  text-decoration: none;
  color: var(--footer-link);
  opacity: 0.85;
}

.footer-links a:hover {
  opacity: 1;
  text-decoration: underline;
}

.footer-legal {
  font-size: 0.78rem;
  opacity: 0.6;
  border-top: 1px solid color-mix(in srgb, var(--footer-text) 18%, transparent);
  padding-top: 1.4rem;
}

/* Fotonachweis über dem Copyright: dieselbe kleine Schrift. Die Trennlinie
   trägt nur die obere der beiden Zeilen, sonst stünden zwei Linien da. */
.footer-fotonachweis + .footer-legal {
  border-top: none;
  padding-top: 0.35rem;
}

/* ============================================================
   Rechtstext-Seiten
   ============================================================ */
/* Lange Fließtexte: engere Spalte, damit die Zeilen lesbar bleiben. */
.legal {
  max-width: 70ch;
}

.legal h2 {
  font-size: 1.4rem;
  margin: 2rem 0 0.6rem;
}

.legal p,
.legal ul {
  margin-bottom: 1rem;
}

.legal ul {
  padding-left: 1.4rem;
}

@media (max-width: 560px) {
  .hero {
    padding-block: 44px 36px;
  }

  .hero-ctas {
    flex-direction: column;
    align-items: stretch;
  }

  .hero-ctas .btn {
    justify-content: center;
  }

  .hero-bogen .signature-frame,
  .about-grid .signature-frame {
    max-width: 240px;
  }

  .category {
    min-height: 240px;
  }

  .footer-grid {
    flex-direction: column;
    gap: 22px;
  }
}

/* ============================================================
   Kontakt als dunkler Abschluss (Variante `abschluss`, E-053)
   ============================================================
   Steht am Ende der Seite, deshalb dunkel wie ein Schlusspunkt – unabhängig
   davon, welche Fläche im Wechsel an der Reihe wäre. Mit `[data-surfaces]`,
   weil der Wechsel bei zwei Flächen (`main[data-surfaces='2'] > …`) sonst
   spezifischer wäre: Das Band wurde hell, die Schrift darauf unlesbar
   (gefunden bei der ersten Kundenseite damit). Gleiche Spezifität, steht später,
   gewinnt also. */
main[data-surfaces] > .section.contact-abschluss {
  background: var(--heading);
  color: var(--surface-1);
  padding-block: 66px 59px;
}

.contact-abschluss-inhalt {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 40px;
}

.contact-abschluss h2 {
  margin: 0 0 0.4rem;
  color: var(--surface-1);
}

.contact-abschluss p {
  margin: 0.2rem 0 0;
  color: color-mix(in srgb, var(--surface-1) 82%, transparent);
  font-size: 0.95rem;
}

.contact-abschluss a:not(.btn) {
  color: inherit;
  text-underline-offset: 3px;
}

/* Mit Zusatz `main > .section`, damit auch die Etiketten-Stufe `archiv`
   (graue Schrift, styles/stil-etiketten.css) hier hell bleibt. */
main[data-surfaces] > .section.contact-abschluss .eyebrow {
  color: color-mix(in srgb, var(--surface-1) 82%, transparent);
}

.contact-abschluss-knoepfe {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  flex-shrink: 0;
}

.contact-abschluss .btn-solid {
  background: var(--surface-1);
  border-color: var(--surface-1);
  color: var(--heading);
}

.contact-abschluss .btn-quiet {
  border-color: color-mix(in srgb, var(--surface-1) 70%, transparent);
  background: transparent;
  color: var(--surface-1);
}

@media (max-width: 780px) {
  .contact-abschluss-inhalt {
    display: block;
  }

  .contact-abschluss-knoepfe {
    margin-top: 22px;
  }
}

/* ============================================================
   Stage-Vorschau (E-062)
   ============================================================ */
/*
 * Schild in der Ecke, nur in der Vorschau eines Template-Stands vor dem
 * Release. Fest unten links, über allem, aber durchlässig für Antippen und
 * Klicks – es soll nichts verdecken, was man in der Vorschau prüfen will.
 */
.vorschau-schild {
  position: fixed;
  left: 12px;
  bottom: 12px;
  z-index: 1000;
  margin: 0;
  padding: 0.3rem 0.8rem;
  font-family: var(--f-body);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  background: var(--heading);
  color: var(--surface-1);
  border-radius: var(--radius-pill);
  box-shadow: 0 2px 8px color-mix(in srgb, var(--text) 25%, transparent);
  pointer-events: none;
}
