/* Evola · Webseite
 *
 * **Die Werte im `:root`-Block sind erzeugt.** Sie stammen aus
 * `tokens.json` im Projektstamm, aus derselben Datei wie die der App.
 * Wer hier einen Wert von Hand ändert, verliert ihn beim nächsten Lauf
 * von `python3 tool/tokens_bauen.py`.
 *
 * Vorher standen sie hier und in `lib/core/design/tokens/` getrennt.
 * Sie stimmten überein — bis auf den Seitenrand, 20 px in der App und
 * 24 px hier. Das ist sogar richtig, nur stand es nirgends. Beim
 * nächsten Farbwechsel wären es zwei Abweichungen gewesen.
 *
 * Aufbau von oben nach unten: Werte, Grundlagen, Kopf, Suche, Karten,
 * Auftritt, Fußzeile. */

:root {
/* >>> aus tokens.json erzeugt — nicht von Hand ändern */
  --bg: #ffffff;
  --bg-soft: #f7f7f8;
  --bg-tief: #f3f3f5;
  --ink: #18181b;
  --ink2: #5c5c66;
  --ink3: #6e6e78;
  --line: #eaeaee;
  --linie-zart: #f0f0f3;
  --brand: #6d28d9;
  --brand-ink: #5b21b6;
  --brand-soft: #f4efff;
  --sand: #faf7f2;
  --sand-tief: #f0e9df;
  --ok: #1f7a4d;
  --ok-soft: #eaf5ef;
  --err: #b3261e;
  --err-soft: #fdecea;
  --warn-ink: #9a6414;
  --warn-soft: #fcf3e6;
  --herz: #e8365d;
  --auf: #ffffff;
  --rahmen-ruhend: #c9c9d0;
  --schalter-aus: #d6d6dc;

  --r-s: 12px;
  --r-m: 16px;
  --r-l: 20px;
  --r-xl: 28px;
  --r-xxl: 32px;
  --r-pille: 999px;

  --sp-xs: 4px;
  --sp-s: 8px;
  --sp-m: 12px;
  --sp-l: 16px;
  --sp-xl: 20px;
  --sp-xxl: 26px;
  --sp-3xl: 40px;

  --marke-von: #7b3fe4;
  --marke-ueber: #c0459c;
  --marke-bis: #f2885b;
  --platzhalter-hell: #efe9f7;
  --platzhalter-dunkel: #cfc0e8;

  --seite: 24px;
  --abschnitt: 44px;
  --schatten-zart: 0 1px 2px rgba(24, 24, 27, 0.04), 0 2px 6px rgba(24, 24, 27, 0.03);
  --schatten: 0 1px 3px rgba(24, 24, 27, 0.04), 0 8px 24px rgba(24, 24, 27, 0.06);
  --schatten-stark: 0 2px 8px rgba(24, 24, 27, 0.06), 0 20px 48px rgba(24, 24, 27, 0.12);
/* <<< Ende der erzeugten Werte */

  /* Von Hand gepflegt: die Schriftfamilie hängt am Betriebssystem und
     lässt sich nicht sinnvoll in einer Tokendatei führen. */
  --schrift: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
    "Helvetica Neue", Arial, sans-serif;
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  font-family: var(--schrift);
  color: var(--ink);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  line-height: 1.5;
  font-size: 15px;
}

a { color: inherit; text-decoration: none; }
img { display: block; }

/* ── Umbruch ────────────────────────────────────────────────────
 *
 * **In diesen 3.900 Zeilen stand bis zum 14.08. kein einziges
 * `overflow-wrap`, `word-break` oder `hyphens`.** Ein Wort ohne
 * Leerzeichen — und Nutzer schreiben so etwas, ob als Tippfehler, als
 * Adresse oder als Test — konnte nirgends umbrechen. Gemessen auf
 * `auftritt.html?betrieb=test404`: die Beschreibung 1.212 Punkte breit
 * in einem 294 Punkte breiten Kasten, der ganze Rumpf 1.348 in einem
 * Fenster von 342. Die Seite liess sich seitwärts schieben.
 *
 * **Die Regel steht hier unten und nicht an einzelnen Klassen.** Es
 * traf nicht eine Stelle, sondern jedes Feld, in das jemand schreibt:
 * Titel, Beschreibung, Ort, Betriebsname, Nachricht. Zwanzig einzelne
 * Regeln waeren zwanzig Stellen, an denen die einundzwanzigste
 * vergessen wird.
 *
 * `overflow-wrap: anywhere` statt `break-word`: `break-word` bricht ein
 * langes Wort erst, wenn es allein in einer Zeile steht — in einem
 * Raster mit fester Spaltenbreite reicht das nicht. `anywhere` bezieht
 * das Wort schon in die Breitenrechnung ein, und genau das fehlte.
 *
 * Ausgenommen bleibt, was nicht umbrechen darf: Preise, Zahlen und
 * Symbole. Ein Betrag, der zwischen Ziffer und Euro-Zeichen umbricht,
 * ist schlechter lesbar als einer, der ueber den Rand geht. */
body,
h1, h2, h3, h4, h5, h6,
p, li, dd, dt, blockquote, figcaption,
td, th,
label, legend,
button, input, textarea, select {
  overflow-wrap: anywhere;
  word-break: normal;
}

/* Was zusammenbleibt. */
.preis, .betrag, .zahl, .sym, [class*="sym-"], time, code, kbd {
  overflow-wrap: normal;
}

/* ── App-Symbole ────────────────────────────────────────────────
 *
 * Dieselbe Schriftdatei, aus der die App ihre Symbole nimmt, auf die
 * hier gebrauchten Zeichen geschnitten (tool/appsymbole_subset.py).
 * Vorher standen hier Unicode-Ersatzzeichen wie ✿ und ♪ — die sehen auf
 * jedem Gerät anders aus und auf keinem wie die App. */

@font-face {
  font-family: "Evola Symbole";
  src: url("schriften/evola-symbole.woff2?v=1786435684") format("woff2");
  font-weight: normal;
  font-style: normal;
  font-display: block;
}

.sym {
  font-family: "Evola Symbole";
  font-weight: normal;
  font-style: normal;
  line-height: 1;
  letter-spacing: normal;
  text-transform: none;
  white-space: nowrap;
  direction: ltr;
  display: inline-block;
  -webkit-font-smoothing: antialiased;
  font-feature-settings: "liga";
}

.sym-alle::before { content: "\e0b7"; }
.sym-hochzeitslocation::before { content: "\f05c8"; }
.sym-eventlocation::before { content: "\f190"; }
.sym-deko::before { content: "\f17b"; }
.sym-catering::before { content: "\f316"; }
.sym-foto::before { content: "\f29b"; }
.sym-dj::before { content: "\f0ed"; }
.sym-torte::before { content: "\ef0f"; }
.sym-makeup::before { content: "\f041"; }
.sym-auto::before { content: "\efc6"; }
.sym-bar::before { content: "\f174"; }
.sym-liveband::before { content: "\f1fb"; }
.sym-fotobox::before { content: "\ef23"; }
.sym-mode::before { content: "\ef4c"; }
.sym-trauung::before { content: "\f2f3"; }
.sym-licht::before { content: "\e37c"; }
.sym-zelt::before { content: "\ef3d"; }
.sym-papeterie::before { content: "\e3c4"; }
.sym-serviceteam::before { content: "\f320"; }
.sym-feuerwerk::before { content: "\ef38"; }
.sym-suche::before { content: "\e567"; }
.sym-merken::before { content: "\e25c"; }
.sym-herz::before { content: "\e25b"; }
.sym-teilen::before { content: "\e34d"; }
.sym-filter::before { content: "\e683"; }
.sym-weiter::before { content: "\e09b"; }
.sym-pfeil::before { content: "\e15f"; }
.sym-zu::before { content: "\e16a"; }
.sym-menue::before { content: "\e3dc"; }
.sym-person::before { content: "\e497"; }
.sym-geprueft::before { content: "\f47c"; }
.sym-schild::before { content: "\f379"; }
.sym-warnung::before { content: "\e238"; }
.sym-haken::before { content: "\ef48"; }
.sym-schloss::before { content: "\e3b1"; }
.sym-auge::before { content: "\e6e8"; }
.sym-kalender::before { content: "\ef11"; }
.sym-ort::before { content: "\f2ac"; }
.sym-stern::before { content: "\e5f9"; }
.sym-apple::before { content: "\f04be"; }
.sym-raster::before { content: "\f0d6"; }
.sym-preisschild::before { content: "\f353"; }
.sym-bewertungen::before { content: "\f31a"; }
.sym-plus::before { content: "\e047"; }
.sym-blitz::before { content: "\e0ee"; }
.sym-euro::before { content: "\e23b"; }
/* Neu am 16.08. fuer die Reiterleiste des Auftritts. */
.sym-liste::before { content: "\e896"; }
.sym-clip::before { content: "\e04b"; }

.bahn { max-width: 1220px; margin: 0 auto; padding: 0 var(--seite); }
.bahn-schmal { max-width: 900px; margin: 0 auto; padding: 0 var(--seite); }

h1, h2, h3 { letter-spacing: -0.4px; text-wrap: balance; }

/* ── Kopfleiste ─────────────────────────────────────────────────
 *
 * Zwei Zeilen, wie bei den großen Buchungsseiten: oben Marke, Suche und
 * Konto, darunter das Kategorienband. Zwei Zeilen, weil die App
 * neunzehn Kategorien hat — in einer Zeile neben der Marke ist dafür
 * kein Platz, und eine Auswahl von fünf davon ist eine Erfindung der
 * Webseite, die in der App niemand wiederfindet. */

.kopf {
  position: sticky;
  top: 0;
  z-index: 30;
  background: rgba(255, 255, 255, 0.92);
  backdrop-filter: saturate(180%) blur(14px);
  border-bottom: 1px solid var(--line);
}

/* Drei Spalten statt schwebender Mitte.
 *
 * Die Suche lag vorher `absolute` auf der halben Seitenbreite — damit
 * sie optisch mittig sitzt. Nur weiß eine absolute Angabe nichts von
 * ihren Nachbarn: auf der Suchseite schob sie sich über „Leistung
 * anbieten", 79 Punkte weit. Als mittlere Spalte eines Rasters bleibt
 * sie mittig **und** hält Abstand; wird es eng, schrumpft sie. */
.kopf-innen {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--sp-l);
  height: 72px;
}

/* Ohne Suche im Kopf (Startseite) sollen Marke und Konto auseinander. */
.kopf-innen > .marke { justify-self: start; }
.kopf-innen > .kopf-rechts { grid-column: 3; justify-self: end; }

.kopf-innen .suche.klein {
  grid-column: 2;
  justify-self: center;
  width: min(520px, 44vw);
}

@media (max-width: 1024px) {
  .kopf-innen .suche.klein { display: none; }
}

.marke {
  display: flex;
  align-items: center;
  gap: 10px;
  font-weight: 800;
  font-size: 20px;
  letter-spacing: -0.7px;
  flex: 0 0 auto;
}

/* Das App-Zeichen, Maß für Maß aus `EvolaLogo`: abgerundetes Quadrat,
 * Verlauf über drei Stopps von unten links nach oben rechts, darin das
 * Kalenderblatt mit Herz in Weiß. Die Rundung 13 ist der Wert, den die
 * App für kleine Größen benutzt. */
.marke .zeichen {
  width: 38px;
  height: 38px;
  border-radius: 13px;
  background: linear-gradient(
    to top right,
    var(--marke-von) 0%,
    var(--marke-ueber) 46%,
    var(--marke-bis) 100%
  );
  box-shadow: 0 5px 13px rgba(192, 69, 156, 0.3);
  display: grid;
  place-items: center;
  flex: 0 0 auto;
}

.marke .zeichen svg { width: 21px; height: 21px; display: block; }

/* Der Markenbalken vom Startbildschirm der App: 44 × 3, derselbe
 * Verlauf. Er taucht auf der Webseite an denselben Stellen auf, an
 * denen die App ihn setzt — unter dem Namen. */
.markenbalken {
  width: 44px;
  height: 3px;
  border-radius: 2px;
  /* Aus tokens.json, siehe --marke-*. Hier standen die drei Werte
     ein zweites Mal von Hand. */
  background: linear-gradient(90deg, var(--marke-von),
                              var(--marke-ueber), var(--marke-bis));
  border: 0;
  margin: 0;
}

.kopf-rechts {
  display: flex;
  align-items: center;
  gap: var(--sp-m);
  flex: 0 0 auto;
  margin-left: auto;
  font-size: 14px;
  font-weight: 600;
  position: relative;
  z-index: 1;
}

.rund {
  width: 40px; height: 40px;
  border-radius: var(--r-pille);
  border: 1px solid var(--line);
  display: grid; place-items: center;
  background: var(--bg);
  color: var(--ink);
  font-size: 20px;
  cursor: pointer;
}

.rund:hover { box-shadow: var(--schatten); }

/* ── Kategorienband ─────────────────────────────────────────────
 *
 * Alle neunzehn Kategorien der App in ihrer Reihenfolge, plus „Alle"
 * davor — genau wie `KategorieLeiste`. Es wischt waagerecht statt zu
 * verschwinden: eine Kategorie, die auf dem Handy nicht erreichbar ist,
 * ist auf dem Handy nicht vorhanden. */

.kategorien-band {
  border-top: 1px solid var(--line);
  position: relative;
}

.kategorien {
  display: flex;
  gap: var(--sp-xxl);
  align-items: stretch;
  overflow-x: auto;
  scrollbar-width: none;
  scroll-behavior: smooth;
}

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

.kategorie {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  padding: 11px 2px 9px;
  font-size: 12px;
  font-weight: 600;
  color: var(--ink3);
  border-bottom: 2px solid transparent;
  white-space: nowrap;
  flex: 0 0 auto;
  opacity: 0.75;
  transition: opacity 0.15s ease, color 0.15s ease;
}

.kategorie .sym { font-size: 23px; }
.kategorie:hover { color: var(--ink); opacity: 1; }
.kategorie.aktiv { color: var(--ink); border-bottom-color: var(--ink); opacity: 1; }

/* Weiche Kanten am Rand des Bandes: sie sagen, dass es weitergeht. */
.kategorien-band::before,
.kategorien-band::after {
  content: "";
  position: absolute;
  top: 0; bottom: 2px;
  width: 46px;
  pointer-events: none;
  z-index: 1;
}

.kategorien-band::before { left: 0; background: linear-gradient(90deg, #fff, rgba(255, 255, 255, 0)); }
.kategorien-band::after { right: 0; background: linear-gradient(270deg, #fff, rgba(255, 255, 255, 0)); }

@media (max-width: 640px) {
  .kopf-innen { height: 62px; }
  .kopf-rechts .nur-breit { display: none; }
  .marke .wort { display: none; }
  .kategorien { gap: var(--sp-xl); }
}

/* ── Suchleiste ─────────────────────────────────────────────────
 *
 * Segmentiert mit Trennstrichen und rundem Knopf. Sie ist das
 * Versprechen der Startseite — deshalb im Bild und nicht darunter. */

.suche {
  display: flex;
  align-items: stretch;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: var(--r-pille);
  box-shadow: var(--schatten);
  padding: 6px 6px 6px 0;
  max-width: 780px;
}

.suche .feld {
  flex: 1 1 0;
  min-width: 0;
  padding: 10px 22px;
  border-radius: var(--r-pille);
  border-left: 1px solid var(--line);
  cursor: pointer;
}

.suche .feld:first-child { border-left: 0; }
.suche .feld:hover { background: var(--bg-soft); }

.suche label {
  display: block;
  font-size: 12px;
  font-weight: 700;
  color: var(--ink);
  cursor: pointer;
}

/* Echte Eingabefelder, keine Textzeilen.
 *
 * Vorher stand hier `<span>` mit einem Beispielwert. Es sah aus wie eine
 * Suche, ließ sich aber nicht antippen — der auffälligste Platzhalter
 * der ganzen Seite. Der Rahmen sitzt an der Pille außen herum, das Feld
 * selbst bringt keinen mit. */
.suche input {
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  font-size: 14px;
  color: var(--ink);
  min-width: 0;
}

.suche input::placeholder { color: var(--ink3); opacity: 1; }
.suche input:focus { outline: none; }

/* Der ganze Bereich zeigt, dass er dran ist — nicht nur die Textzeile. */
.suche .feld:focus-within { background: var(--bg-soft); }

/* Safari stellt `type=date` und `type=number` eigenwillig dar. */
.suche input[type="date"] { -webkit-appearance: none; appearance: none; }

/* ── Das Datumsfeld ────────────────────────────────────────────────
 *
 * **Warum nicht einfach das native Feld:** es zeigt „tt.mm.jjjj", auch
 * wenn nichts gewählt ist. Das ist keine Angabe, sondern eine Maske —
 * und sie passt zu keiner Schrift und keiner Kante dieser Seite.
 *
 * **Warum nicht ein eigener Kalender:** der Kalender des Browsers ist
 * auf jedem Gerät der, den die Leute kennen, und auf dem Telefon der
 * bequemste. Ihn nachzubauen hieße, ihn schlechter zu machen.
 *
 * Also beides: der eigene Text steht sichtbar da, das native Feld liegt
 * unsichtbar darüber und öffnet beim Antippen seinen Kalender. */
.suche .feld.datum { position: relative; }

.suche .feld.datum input[type="date"] {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  cursor: pointer;
  /* Auf dem Telefon lässt sich das Kalendersymbol sonst nicht treffen. */
  padding: 0;
  margin: 0;
  border: 0;
}

.suche .feld.datum .anzeige {
  display: block;
  font-size: 14px;
  color: var(--ink3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  /* Dieselbe Zeilenhöhe wie ein Eingabefeld, damit die vier Felder der
   * Suchzeile auf einer Linie sitzen. */
  line-height: 22px;
}

/* Gewählt: der Wert steht in derselben Farbe wie eine echte Eingabe. */
.suche .feld.datum.gesetzt .anzeige { color: var(--ink); }

/* ── Eigener Kalender ───────────────────────────────────────────
 *
 * Das native `input[type=date]` lag unsichtbar über dem Feld und öffnete
 * beim Antippen in den meisten Browsern gar nichts. Sichtbar machen half
 * nicht: es sieht in jedem Browser anders aus und passt zu keiner Seite.
 *
 * Sobald JavaScript läuft, nimmt das native Feld keine Klicks mehr an —
 * es trägt nur noch den Wert für das Formular. */
.suche .feld.datum.eigener-kalender input[type="date"] {
  pointer-events: none;
}

.datumknopf {
  display: block;
  width: 100%;
  padding: 0;
  background: none;
  border: 0;
  text-align: left;
  cursor: pointer;
  font: inherit;
  color: inherit;
}

.kalender {
  position: absolute;
  top: calc(100% + 14px);
  left: -14px;
  z-index: 40;
  width: 312px;
  padding: var(--sp-l);
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: var(--r-xl);
  /* Weicher als ein Kasten mit harter Kante: das Blatt soll über der
   * Seite schweben, nicht in sie hineingeschnitten sein. */
  box-shadow: 0 18px 44px rgb(24 24 27 / 14%), 0 2px 8px rgb(24 24 27 / 6%);
  cursor: default;
}

/* Nah am rechten Rand liefe es sonst aus dem Fenster. */
.suche .feld.datum:last-of-type .kalender { left: auto; right: -14px; }

/* Sitzt die Suchzeile am unteren Bildrand — auf der Startseite tut sie
 * das —, klappt das Blatt nach oben. Sonst steht es außerhalb des
 * Fensters: geöffnet und trotzdem unsichtbar. */
.kalender.nach-oben { top: auto; bottom: calc(100% + 14px); }

.kalenderkopf {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--sp-m);
}

.kalenderkopf b { font-size: 15px; }

.kalenderpfeil {
  width: 32px;
  height: 32px;
  border: 0;
  border-radius: var(--r-pille);
  background: none;
  color: var(--ink);
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
  transition: background 0.15s ease;
}

.kalenderpfeil:hover:not(:disabled) { background: var(--bg-soft); }
.kalenderpfeil:disabled { color: var(--line); cursor: default; }

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

.kalenderwt {
  display: grid;
  place-items: center;
  height: 30px;
  font-size: 11.5px;
  font-weight: 700;
  color: var(--ink3);
  letter-spacing: 0.04em;
}

.kalendertag {
  height: 38px;
  border: 0;
  border-radius: var(--r-pille);
  background: none;
  color: var(--ink);
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;
}

.kalendertag:hover:not(:disabled) { background: var(--brand-soft); }

/* Vergangene Tage sind blass und nicht anklickbar — ein Event in der
 * Vergangenheit zu suchen ergibt keinen Sinn. */
.kalendertag:disabled { color: var(--line); cursor: default; }

/* Heute trägt nur einen Ring, keine Fläche: sonst sähe es aus wie
 * gewählt, und man wüsste nicht, was gerade eingestellt ist. */
.kalendertag.heute { box-shadow: inset 0 0 0 1.5px var(--line); }

.kalendertag.gewaehlt {
  background: var(--brand);
  color: #fff;
  box-shadow: none;
}

.kalendertag.gewaehlt:hover { background: var(--brand-ink); }

.kalenderfuss {
  margin-top: var(--sp-m);
  padding-top: var(--sp-m);
  border-top: 1px solid var(--line);
  text-align: center;
}

.kalenderfuss .blank {
  font-size: 13px;
  font-weight: 600;
  color: var(--ink3);
  text-decoration: underline;
}

@media (max-width: 640px) {
  /* Auf dem Telefon hat ein schwebendes Blatt neben dem Feld keinen
   * Platz — es sitzt dann unter der ganzen Suchzeile. */
  .kalender { left: 0; right: 0; width: auto; }
  .suche .feld.datum:last-of-type .kalender { left: 0; right: 0; }
}
.suche input[type="number"] { -moz-appearance: textfield; appearance: textfield; }
.suche input[type="number"]::-webkit-outer-spin-button,
.suche input[type="number"]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }

.suche .los {
  flex: 0 0 auto;
  align-self: center;
  width: 48px; height: 48px;
  border: 0;
  border-radius: var(--r-pille);
  background: var(--brand);
  color: #fff;
  font-size: 19px;
  cursor: pointer;
  display: grid; place-items: center;
}

.suche .los:hover { background: var(--brand-ink); }

/* Schmale Fassung im Kopf der Ergebnisseite. */
.suche.klein { padding: 4px 4px 4px 0; box-shadow: none; }
.suche.klein .feld { padding: 6px 18px; }
.suche.klein .los { width: 36px; height: 36px; font-size: 15px; }

@media (max-width: 1024px) {
  .suche { flex-wrap: wrap; border-radius: var(--r-l); padding: 6px; }
  .suche .feld { flex: 1 1 45%; border-left: 0; }
  .suche .los { width: 100%; height: 44px; border-radius: var(--r-m); }
}

/* ── Filterband ─────────────────────────────────────────────── */

.filter {
  display: flex;
  gap: var(--sp-s);
  overflow-x: auto;
  padding: var(--sp-l) 0;
  scrollbar-width: none;
}

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

.filter a, .filter span {
  flex: 0 0 auto;
  padding: 9px 16px;
  border: 1px solid var(--line);
  border-radius: var(--r-pille);
  font-size: 13.5px;
  font-weight: 600;
  color: var(--ink2);
  background: var(--bg);
  white-space: nowrap;
}

.filter a, .filter span { cursor: pointer; user-select: none; }
.filter a:hover, .filter span:hover { border-color: var(--ink); color: var(--ink); }
.filter .an { background: var(--ink); color: #fff; border-color: var(--ink); }
.filter .an:hover { color: #fff; }

/* Ein Knopf, der wie Text aussieht — für „Teilen" und „Merken" neben
 * einer Überschrift. Vorher standen dort Verweise auf `#`, die nichts
 * taten; ein `<a href="#">` ohne Ziel ist der klassische tote Knopf. */
.blank {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: 0;
  background: none;
  padding: 0;
  font: inherit;
  font-weight: 600;
  color: inherit;
  cursor: pointer;
  text-decoration: underline;
}

.blank:hover { opacity: 0.7; }

/* ── Knöpfe ─────────────────────────────────────────────────── */

.knopf {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-s);
  padding: 13px 22px;
  border-radius: var(--r-pille);
  background: var(--brand);
  color: #fff;
  font-weight: 700;
  font-size: 15px;
  border: 1px solid transparent;
  cursor: pointer;
  white-space: nowrap;
}

.knopf:hover { background: var(--brand-ink); }
.knopf.linie { background: transparent; color: var(--ink); border-color: var(--line); }
.knopf.linie:hover { border-color: var(--ink); background: var(--bg-soft); }
.knopf.klein { padding: 9px 16px; font-size: 13.5px; }
.knopf.voll { width: 100%; }

/* Der große Buchungsknopf: Verlauf statt Fläche, wie bei den Vorbildern.
 * Er kommt genau einmal je Seite vor — sonst wäre er kein Höhepunkt. */
.knopf.gross {
  padding: 16px 24px;
  font-size: 16px;
  background: linear-gradient(120deg, var(--brand) 0%, var(--herz) 140%);
}

.knopf.gross:hover { filter: brightness(0.94); }

/* ── Bühne der Startseite ───────────────────────────────────────
 *
 * Vorher standen Überschrift und Suche untereinander im weißen Raum und
 * fielen auseinander. Jetzt hält ein Bild sie zusammen: der Spruch liegt
 * darauf, die Suchzeile sitzt auf der Unterkante und greift halb ins
 * Bild. Damit ist unmissverständlich, dass das eine zum anderen gehört.
 *
 * Der Bogen über dem Bild ist derselbe Griff wie auf dem
 * Startbildschirm der App: die weiße Fläche legt sich mit runden Ecken
 * über das Foto. */

/* ── Bühne ─────────────────────────────────────────────────────────
 *
 * Links das Versprechen in Worten, rechts drei gestaffelte Bilder.
 *
 * **Warum nicht ein großes Foto:** Evolas Punkt ist, dass mehrere
 * Gewerke an einem Ort zusammenkommen. Ein einzelnes Hochzeitsbild sagt
 * das nicht — es sagt „Hochzeit", wie jede andere Seite auch. Drei
 * Bilder mit Beschriftung zeigen die Behauptung, statt sie zu wiederholen.
 *
 * Der Sandton gibt der Seite Wärme, ohne den Markenton zu verbrauchen:
 * der bleibt für Tappbares reserviert. */

.buehne {
  background: var(--sand);
  padding: var(--sp-xxl) 0 calc(var(--sp-xxl) + 34px);
  border-bottom: 1px solid var(--sand-tief);
}

.buehne-innen {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
  gap: var(--sp-3xl);
  align-items: center;
}

@media (max-width: 1024px) {
  .buehne { padding-bottom: var(--sp-3xl); }
  .buehne-innen { grid-template-columns: 1fr; gap: var(--sp-xxl); }
}

.buehne-wort .oberzeile {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--brand-ink);
  margin: 0 0 var(--sp-m);
}

.buehne-wort h1 {
  /* Nicht größer: auf einem Laptop soll die Suche noch im Bild sein.
   * Eine Bühne, die den ganzen ersten Bildschirm füllt, versteckt den
   * Weg hinein. */
  font-size: clamp(32px, 4.2vw, 48px);
  line-height: 1.06;
  letter-spacing: -0.032em;
  margin: 0;
  text-wrap: balance;
}

.buehne-wort .vor {
  margin: var(--sp-l) 0 0;
  font-size: clamp(16px, 1.4vw, 18px);
  line-height: 1.6;
  color: var(--ink2);
  max-width: 46ch;
}

/* Die drei Zusagen stehen als Liste, nicht als Fließtext: sie werden
 * überflogen, nicht gelesen. */
.buehne-wort .punkte {
  list-style: none;
  margin: var(--sp-l) 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.buehne-wort .punkte li {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-s);
  font-size: 14.5px;
  color: var(--ink2);
  line-height: 1.5;
}

.buehne-wort .punkte .sym {
  font-size: 18px;
  color: var(--brand);
  flex: none;
  margin-top: 1px;
}

/* ── Bühne einer Anlassseite ────────────────────────────────────
 *
 * **Diese Regeln fehlten.** Die Anlassseite benutzte `.buehne-bild` und
 * `.buehne-text` — beides stand nirgends im Stylesheet. Das Bild lief
 * deshalb in seiner vollen Breite ein (1800 Pixel in einem 854 breiten
 * Kasten, 1368 hoch), und die Überschrift stand darunter außerhalb des
 * ersten Bildschirms. Eine Seite, deren Titel man nicht sieht, wirkt
 * kaputt — und war es hier auch.
 *
 * Der Text liegt auf dem Bild, nicht daneben: das ist die Form, die eine
 * Anlassseite trägt. Damit er lesbar bleibt, liegt ein Verlauf darüber
 * und nicht etwa eine halbdurchsichtige Fläche — die nimmt dem Bild
 * überall gleich viel Licht, auch dort, wo kein Text steht. */
.buehne-bild {
  position: relative;
  border-radius: var(--r-xl);
  overflow: hidden;
  background: var(--sand-tief);
  aspect-ratio: 16 / 7;
  /* Auf einem Telefon wäre 16:7 ein Streifen. */
  min-height: 320px;
}

.buehne-bild > img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Der Verlauf sitzt zwischen Bild und Text. */
.buehne-bild::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    to top,
    rgb(24 24 27 / 78%) 0%,
    rgb(24 24 27 / 45%) 38%,
    rgb(24 24 27 / 5%) 72%
  );
}

.buehne-text {
  position: absolute;
  z-index: 1;
  left: 0;
  right: 0;
  bottom: 0;
  padding: var(--sp-xxl);
  color: #fff;
  max-width: 62ch;
}

.buehne-text .oberzeile {
  margin: 0 0 var(--sp-s);
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: rgb(255 255 255 / 82%);
}

.buehne-text h1 {
  margin: 0;
  font-size: clamp(26px, 4vw, 42px);
  line-height: 1.12;
  color: #fff;
  text-wrap: balance;
}

.buehne-text .vor {
  margin: var(--sp-m) 0 0;
  font-size: 16px;
  line-height: 1.6;
  color: rgb(255 255 255 / 90%);
}

@media (max-width: 1024px) {
  .buehne-bild { aspect-ratio: 4 / 5; min-height: 0; }
  .buehne-text { padding: var(--sp-l); }
}

/* Drei Bilder, gestaffelt. Das große links, zwei kleinere rechts
 * versetzt — eine Reihe gleich großer Kacheln sähe aus wie ein
 * Suchergebnis. */
.buehne-bilder {
  display: grid;
  grid-template-columns: 1.25fr 1fr;
  grid-template-rows: repeat(2, minmax(0, 1fr));
  gap: var(--sp-m);
  aspect-ratio: 10 / 8;
  max-width: 100%;
}

.buehne-bilder figure {
  position: relative;
  margin: 0;
  border-radius: var(--r-l);
  overflow: hidden;
  background: var(--sand-tief);
}

.buehne-bilder .b1 { grid-row: 1 / 3; }

.buehne-bilder img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 0.5s ease;
}

.buehne-bilder figure:hover img { transform: scale(1.04); }

/* Die Beschriftung sagt, welches Gewerk das ist — ohne sie sind es drei
 * hübsche Fotos ohne Aussage. */
.buehne-bilder figcaption {
  position: absolute;
  left: var(--sp-m);
  bottom: var(--sp-m);
  background: rgba(255, 255, 255, 0.94);
  color: var(--ink);
  font-size: 12px;
  font-weight: 700;
  padding: 5px 11px;
  border-radius: var(--r-pille);
}

@media (max-width: 1024px) {
  .buehne-bilder { aspect-ratio: 16 / 10; }
}

/* Auf dem Telefon zählt der Weg zur Suche.
 *
 * Die drei Zusagen fallen dort weg: sie fassen zusammen, was der
 * Abschnitt „So läuft eine Buchung" weiter unten ausführlich erklärt —
 * und sie schoben die Suchzeile auf 831 Punkte, also aus dem ersten
 * Bildschirm heraus. Ein Versprechen, das man erst nach dem Scrollen
 * einlösen kann, ist keins. */
@media (max-width: 640px) {
  .buehne { padding-top: var(--sp-l); }
  .buehne-wort .punkte { display: none; }
  .buehne-wort .vor { margin-top: var(--sp-m); font-size: 15.5px; }
  .buehne-innen { gap: var(--sp-l); }
  .buehne-bilder { aspect-ratio: 16 / 9; }
}

@media (prefers-reduced-motion: reduce) {
  .buehne-bilder img { transition: none; }
  .buehne-bilder figure:hover img { transform: none; }
}

/* ── Suchband ──────────────────────────────────────────────────────
 *
 * Die Suche liegt als weiße Karte über der Unterkante der Bühne und
 * gehört damit sichtbar dazu. Losgelöst darunter sah sie aus wie ein
 * Formular, das jemand vergessen hat — und sie steckte vorher *in* der
 * Bühne, was sie beim Verschieben mitnahm.
 *
 * -34px ist die halbe Höhe des runden Knopfes plus Rand: so liegt der
 * Knopf genau auf der Kante. */
.suchband {
  position: relative;
  z-index: 2;
  margin-top: -34px;
  padding: 0 0 var(--sp-3xl);
}

.suchband .suche {
  margin: 0 auto;
  max-width: 940px;
  box-shadow: var(--schatten-stark);
}

/* Ohne Bühne darüber braucht das Band eigenen Abstand — sonst klebt es
 * am Kategorienband. */
.buehne[hidden] + .suchband {
  margin-top: 0;
  padding-top: var(--sp-xxl);
}

.beleg {
  text-align: center;
  color: var(--ink3);
  font-size: 13.5px;
  margin: var(--sp-xl) 0 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  flex-wrap: wrap;
}

.beleg .sym { font-size: 16px; color: var(--ok); }

@media (max-width: 1024px) {
  .suchband { margin-top: var(--sp-l); }
}

.marke-wort {
  background: linear-gradient(100deg, var(--brand), var(--herz));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* Bildmosaik: ein großes Bild links, vier kleine rechts. Dieselbe
 * Aufteilung wie auf der Detailseite — der Auftritt wiederholt sich,
 * statt jedes Mal neu erfunden zu werden. */
.mosaik {
  display: grid;
  grid-template-columns: 1.6fr 1fr 1fr;
  grid-template-rows: repeat(2, 1fr);
  gap: 8px;
  border-radius: var(--r-xl);
  overflow: hidden;
  aspect-ratio: 16 / 8;
}

.mosaik img { width: 100%; height: 100%; object-fit: cover; }
.mosaik img:first-child { grid-row: span 2; }
.mosaik img { transition: transform 0.4s ease; }
.mosaik a:hover img { transform: scale(1.03); }
.mosaik a { overflow: hidden; display: block; }
.mosaik a:first-child { grid-row: span 2; }

@media (max-width: 1024px) {
  .mosaik { grid-template-columns: 1fr 1fr; aspect-ratio: 4 / 3; }
  .mosaik a:first-child { grid-column: span 2; grid-row: span 1; }
  .mosaik a:nth-child(n + 4) { display: none; }
}

/* Ein einzelnes Bild ist kein Mosaik.
 *
 * Das Raster oben ist für fünf Bilder gebaut: erstes links groß, vier
 * kleine daneben. Steht dort nur eines — der Normalfall bei einer
 * Leistung aus der App, die genau ein Titelbild hat —, dann fiel es in
 * die erste Spalte über zwei Zeilen: ein überhohes Hochkantbild auf
 * halber Breite, rechts daneben nichts. Es sah aus, als fehle etwas.
 *
 * `:only-child` greift genau dann, und nur dann. */
.mosaik a:only-child { grid-column: 1 / -1; grid-row: 1 / -1; }
.mosaik:has(a:only-child) { aspect-ratio: 16 / 9; }

@media (max-width: 1024px) {
  .mosaik:has(a:only-child) { aspect-ratio: 4 / 3; }
}

/* ── Abschnitte und Reihen ──────────────────────────────────── */

/* Mehr Luft zwischen den Abschnitten.
 *
 * 40 Pixel waren zu wenig: die Reihen liefen ineinander, und die Seite
 * las sich als eine lange Kette statt als Kapitel. Auf einem Telefon
 * bleibt es enger — dort ist Weißraum teuer. */
section { padding: clamp(36px, 5vw, 68px) 0; }

.reihenkopf {
  display: flex;
  align-items: baseline;
  gap: var(--sp-s);
  margin-bottom: var(--sp-l);
}

.reihenkopf h2 {
  font-size: clamp(21px, 2.6vw, 30px);
  letter-spacing: -0.022em;
  margin: 0;
}
.reihenkopf .pfeil { color: var(--ink3); font-size: 18px; }
.reihenkopf a:hover .pfeil { color: var(--ink); }

/* **Ein Knopf im Reihenkopf gehört ans andere Ende.**
 *
 * „Zuletzt angesehen" trägt „Verlauf löschen" — anders als der Pfeil ist
 * das eine Handlung, keine Fortsetzung der Überschrift. Direkt daneben
 * gelesen wirkt sie wie ein Teil des Titels; ganz rechts ist sie das,
 * was sie ist: eine Möglichkeit, nicht der Inhalt. */
.reihenkopf > .knopf { margin-left: auto; align-self: center; }

.unterzeile { color: var(--ink2); margin: -8px 0 var(--sp-xl); max-width: 62ch; }

.raster {
  display: grid;
  gap: var(--sp-xl) var(--sp-l);
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
}

/* **Zwei Karten nebeneinander, nicht vier kleine.**
 *
 * Die Empfehlungen am Ende der Startseite sind der einzige Abschnitt,
 * der etwas empfiehlt statt aufzuzählen. Im selben Raster wie die
 * Anlasskacheln säßen sie in derselben Größe daneben und wären keine
 * Empfehlung mehr, sondern vier weitere Kacheln.
 *
 * Unter 700 px wird daraus eine Spalte: zwei halbe Karten nebeneinander
 * sind auf einem Telefon zwei Briefmarken. */
.raster.zweispaltig {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

/* **Ein breites Bild braucht ein breites Seitenverhaeltnis.**
 *
 * Die Karten des Rasters sind fuer rund 230 px gebaut und tragen ein
 * fast quadratisches Bild (20/19). Auf 580 px wird daraus ein Klotz von
 * 550 px Hoehe — die zwei Empfehlungen fuellen dann allein zwei
 * Bildschirme, und der Rest der Startseite ruecht dahinter. */
.raster.zweispaltig .karte .bild { aspect-ratio: 3 / 2; }

@media (max-width: 700px) {
  .raster.zweispaltig { grid-template-columns: 1fr; }
}

/* Waagerechte Reihe mit Wischen — für Startseite und Auftritt. */
.reihe {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(230px, 1fr);
  gap: var(--sp-l);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  padding-bottom: var(--sp-s);
  scrollbar-width: none;
}

/* **Eine Reihe mit wenigen Karten darf sie nicht dehnen.**
 *
 * `1fr` teilt die Bahn unter den Karten auf — bei fünf ergibt das die
 * gewollte Reihe, bei zwei zwei Kacheln über die halbe Seite, mit
 * Bildern in doppelter Hoehe. Es sieht dann nicht nach „zwei Stueck"
 * aus, sondern nach einem Raster, das nicht fertig geladen hat.
 *
 * Die Klasse setzt `reiheFuellen`, weil erst dort feststeht, wie viele
 * Karten es sind. **Nur dann**: die bestehenden Reihen mit fuenf Karten
 * bleiben, wie sie waren. */
.reihe.wenige { grid-auto-columns: minmax(230px, 300px); }

.reihe::-webkit-scrollbar { display: none; }
.reihe > * { scroll-snap-align: start; }

/* ── Karte ──────────────────────────────────────────────────── */

.karte { display: block; }

.karte .bild {
  position: relative;
  border-radius: var(--r-m);
  overflow: hidden;
  aspect-ratio: 20 / 19;
  background: var(--bg-soft);
}

/* **Video steht hier neben img, seit dem 16.08.**
 *
 * Ohne die zweite Auswahl nimmt ein <video> seine eigene Groesse an:
 * gemessen wurden 1920 Punkte Hoehe in einer Karte, die 200 hoch sein
 * soll. Der Rahmen schneidet zwar ab, aber die Karte selbst wird
 * auseinandergerissen — und es faellt erst auf, wenn ein Betrieb
 * wirklich einen Clip hochlaedt. */
.karte .bild img,
.karte .bild video {
  width: 100%; height: 100%; object-fit: cover;
  transition: transform 0.45s ease;
  display: block;
}

.karte:hover .bild img,
.karte:hover .bild video { transform: scale(1.045); }

/* Auszeichnung links oben, Herz rechts oben — beides auf dem Bild,
 * damit die Textzeilen darunter ruhig bleiben. */
.karte .auszeichnung {
  position: absolute;
  top: 10px; left: 10px;
  background: rgba(255, 255, 255, 0.94);
  border-radius: var(--r-pille);
  padding: 5px 11px;
  font-size: 11.5px;
  font-weight: 700;
  color: var(--ink);
  box-shadow: 0 2px 8px rgba(24, 24, 27, 0.12);
}

.karte .herz-knopf {
  position: absolute;
  top: 8px; right: 8px;
  width: 30px; height: 30px;
  display: grid; place-items: center;
  color: #fff;
  font-size: 17px;
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.5);
  cursor: pointer;
}

.karte .herz-knopf:hover { transform: scale(1.12); }

.karte .zeile {
  display: flex;
  align-items: baseline;
  gap: var(--sp-s);
  margin-top: var(--sp-m);
}

.karte h3 {
  margin: 0;
  font-size: 15px;
  font-weight: 600;
  flex: 1 1 auto;
  min-width: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

.karte .meta { margin: 1px 0 0; font-size: 14px; color: var(--ink3); }
.karte .preis {
  margin: 6px 0 0;
  font-size: 14.5px;
  color: var(--ink3);
}
.karte .preis b { color: var(--ink); }
.karte .preis b { font-weight: 700; }
.karte .vorher { color: var(--ink3); text-decoration: line-through; margin-right: 5px; }

.note { display: inline-flex; align-items: center; gap: 4px; font-size: 14px; flex: 0 0 auto; }

/* Das Herz ist überall rot, nicht nur in der Notenzeile — sonst steht in
 * den Zahlen des Auftritts ein schwarzes Herz neben einem roten. */
.herz { color: var(--herz); }

.pille {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 5px 11px;
  border-radius: var(--r-pille);
  background: var(--bg-soft);
  color: var(--ink2);
  font-size: 12px;
  font-weight: 600;
}

.pille.ok { background: var(--ok-soft); color: var(--ok); }
.pille.marke { background: var(--brand-soft); color: var(--brand-ink); }

/* ── Schrittfolge ───────────────────────────────────────────── */

.schritte { display: grid; gap: var(--sp-xl); grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); }

.schritt {
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: var(--r-l);
  padding: var(--sp-xxl);
}

.schritt .zahl {
  width: 34px; height: 34px;
  border-radius: var(--r-pille);
  background: var(--brand-soft);
  color: var(--brand-ink);
  display: grid; place-items: center;
  font-weight: 800; font-size: 15px;
  margin-bottom: var(--sp-l);
}

.schritt h3 { margin: 0 0 var(--sp-xs); font-size: 17px; }
.schritt p { margin: 0; color: var(--ink2); font-size: 14.5px; }

/* ── Zweispalter: Inhalt links, mitlaufender Kasten rechts ──── */

.zweispalt {
  display: grid;
  grid-template-columns: 1fr 372px;
  gap: var(--sp-3xl);
  align-items: start;
}

.klebt { position: sticky; top: 104px; }

@media (max-width: 1024px) {
  .zweispalt { grid-template-columns: 1fr; }
  .klebt { position: static; }
}

.kasten {
  border: 1px solid var(--line);
  border-radius: var(--r-l);
  padding: var(--sp-xxl);
  box-shadow: var(--schatten);
  background: var(--bg);
}

.kasten .gross-preis { font-size: 24px; font-weight: 800; letter-spacing: -0.6px; }

.feldpaar {
  display: grid;
  grid-template-columns: 1fr 1fr;
  border: 1px solid var(--line);
  border-radius: var(--r-m);
  overflow: hidden;
  margin: var(--sp-l) 0;
}

.feldpaar div { padding: 10px 14px; }
.feldpaar div + div { border-left: 1px solid var(--line); }
.feldpaar span { display: block; font-size: 10.5px; font-weight: 800; letter-spacing: 0.4px; color: var(--ink); }
.feldpaar b { font-weight: 500; font-size: 14px; color: var(--ink2); }

/* ── Ergebnisliste mit Karte ────────────────────────────────── */

.ergebnis { display: grid; grid-template-columns: 1fr 1fr; gap: 0; }

.ergebnis .liste { padding: 0 var(--seite) var(--sp-3xl); overflow-y: auto; }

/* Der Kopf ist auf der Ergebnisseite zweizeilig: 72 px Marke plus rund
 * 56 px Kategorienband. Die Kartenfläche beginnt darunter und füllt den
 * Rest des Fensters. */
.karte-flaeche {
  position: sticky;
  top: 128px;
  height: calc(100vh - 128px);
  background:
    linear-gradient(0deg, rgba(109, 40, 217, 0.04), rgba(109, 40, 217, 0.04)),
    repeating-linear-gradient(0deg, #eef2ea 0 38px, #e7ece2 38px 39px),
    repeating-linear-gradient(90deg, #eef2ea 0 38px, #e7ece2 38px 39px);
  display: grid;
  place-items: center;
  border-left: 1px solid var(--line);
}

.karte-flaeche .hinweis-mitte {
  background: rgba(255, 255, 255, 0.94);
  border-radius: var(--r-m);
  padding: var(--sp-l) var(--sp-xl);
  font-size: 13.5px;
  color: var(--ink2);
  box-shadow: var(--schatten);
  max-width: 260px;
  text-align: center;
}

/* Die Preisnadel auf der Karte.
 *
 * **Steht gerade in keiner Seite** — am 14.08. sind die sechs
 * erfundenen Nadeln aus `suche.html` geflogen, weil sie Beträge ohne
 * Anbieter zeigten. Die Regel bleibt: sobald ein Kartendienst
 * angebunden ist, tragen die echten Nadeln denselben Stil. Wer sie für
 * toten Code hält und löscht, baut sie in zwei Wochen nach. */
.preisnadel {
  position: absolute;
  background: var(--bg);
  border-radius: var(--r-pille);
  padding: 6px 13px;
  font-size: 13px;
  font-weight: 700;
  box-shadow: var(--schatten);
}

@media (max-width: 1024px) {
  .ergebnis { grid-template-columns: 1fr; }
  .karte-flaeche { display: none; }
  /* **Der Seitenrand bleibt.** Vorher stand hier `padding: 0` — ohne
   * Kartenfläche daneben sollte die Liste die Breite nutzen. Sie nutzte
   * sie bis zum Anschlag: die Ergebniskarten klebten am linken
   * Fensterrand, und die Überschrift begann bei null. */
  .ergebnis .liste { padding: 0 var(--seite) var(--sp-3xl); }
}

/* ── Auftritt eines Betriebs ────────────────────────────────── */

.auftritt-kopf { display: flex; gap: var(--sp-3xl); align-items: center; flex-wrap: wrap; }

/* Ohne `min-width: 0` bestimmt der breiteste Inhalt die Mindestbreite
 * der Spalte — auf 375 px stand die Zahlenreihe dann über den Rand
 * hinaus und die ganze Seite ließ sich seitlich schieben. */
.auftritt-kopf > * { min-width: 0; }

.ring {
  width: 128px; height: 128px;
  border-radius: var(--r-pille);
  padding: 4px;
  background: linear-gradient(135deg, var(--brand), var(--herz));
  flex: 0 0 auto;
}

.ring img {
  width: 100%; height: 100%;
  border-radius: var(--r-pille);
  object-fit: cover;
  border: 3px solid var(--bg);
}

.zahlen { display: flex; gap: var(--sp-3xl); flex-wrap: wrap; }
.zahlen b { display: block; font-size: 21px; letter-spacing: -0.5px; }
.zahlen span { font-size: 12.5px; color: var(--ink3); }

.kennung { color: var(--ink3); font-size: 14.5px; }

.sammlungen { display: flex; gap: var(--sp-xl); overflow-x: auto; padding: var(--sp-xxl) 0; scrollbar-width: none; min-width: 0; }
.sammlungen::-webkit-scrollbar { display: none; }
.sammlung { text-align: center; flex: 0 0 auto; width: 88px; }

/* **Auch ein `video`.** Seit dem 16.08. kann ein Highlight ohne eigenes
 * Titelbild einen Clip als Deckel haben — sonst blieben Kreise leer, in
 * denen nur Clips liegen. */
.sammlung img,
.sammlung video {
  width: 72px; height: 72px;
  border-radius: var(--r-pille);
  object-fit: cover;
  border: 2px solid var(--line);
  padding: 3px;
  transition: border-color 0.2s ease;
}

.sammlung:hover img,
.sammlung:hover video { border-color: var(--ink3); }
.sammlung span { display: block; font-size: 12px; color: var(--ink2); margin-top: 6px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* **Warum hier ein `button` mitgedacht ist.**
 *
 * Es gab diese Klasse schon — auf `studio-lumen.html`, wo eine Sammlung
 * ein Link zum Raster ist. Auf `auftritt.html` filtert sie stattdessen
 * die Leistungen, und dafür braucht es einen Knopf: ein Link, der die
 * Seite nicht wechselt, ist für Tastatur und Sprachausgabe eine Lüge.
 *
 * Ich hatte dafür zuerst eine zweite Fassung mit eigenen Klassen
 * geschrieben — und damit `.sammlung` doppelt im CSS stehen gehabt, mit
 * verschiedenen Massen. Die spätere hätte die frühere überschrieben und
 * studio-lumen.html still verändert. Ein Bauteil, eine Definition. */
button.sammlung {
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  cursor: pointer;
}

/* Der Ring in Markenfarbe zeigt, wonach gerade gefiltert wird. Ohne ihn
   sieht man nach dem Klick nicht, warum plötzlich weniger dasteht. */
.sammlung.an img { border-color: var(--brand); }
.sammlung.an span { color: var(--brand-ink); font-weight: 600; }

.sammlung-leer {
  margin: var(--sp-l) 0 0;
  color: var(--ink3);
  font-size: 14.5px;
}

/* Reiter wie in der App. Der Strich sagt, wo man ist.
 *
 * Waagerecht rollbar, weil „Bewertungen“ und „Leistungen“ zusammen auf
 * einem 320er Bildschirm nicht nebeneinander passen. Verschwinden darf
 * kein Reiter — dann wäre ein Teil des Auftritts unerreichbar. */
.reiter {
  display: flex;
  gap: var(--sp-3xl);
  border-bottom: 1px solid var(--line);
  overflow-x: auto;
  scrollbar-width: none;
}

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

.reiter a {
  flex: 0 0 auto;
  white-space: nowrap;
  padding: var(--sp-m) 2px;
  font-size: 13px;
  font-weight: 700;
  color: var(--ink3);
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  display: flex; align-items: center; gap: 7px;
}

.reiter a.aktiv { color: var(--ink); border-bottom-color: var(--ink); }
.reiter a:hover { color: var(--ink); }

/* Die Beiträge beginnen direkt unter der Leiste — mit Luft dazwischen
 * wirkt das Raster wie ein eigener Abschnitt statt wie der Inhalt des
 * Reiters. Leicht abgerundet, nicht scharfkantig. */
.arbeiten {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 6px;
  margin-top: var(--sp-m);
}

.arbeiten a { display: block; overflow: hidden; border-radius: var(--r-s); aspect-ratio: 1; }
.arbeiten img { width: 100%; height: 100%; object-fit: cover; transition: transform 0.45s ease, filter 0.2s ease; }
.arbeiten a:hover img { transform: scale(1.05); filter: brightness(0.94); }

@media (max-width: 640px) {
  .arbeiten { gap: 4px; }
  .auftritt-kopf { gap: var(--sp-xl); }
  .ring { width: 92px; height: 92px; }
  .zahlen { gap: var(--sp-xxl); }
  .zahlen b { font-size: 18px; }
  .reiter { gap: var(--sp-xxl); }
}

.hinweis {
  background: var(--brand-soft);
  color: var(--brand-ink);
  border-radius: var(--r-m);
  padding: var(--sp-l) var(--sp-xl);
  font-size: 14.5px;
}

/* ── Streifen zum Schluss ───────────────────────────────────── */

.streifen {
  background: linear-gradient(120deg, var(--brand) 0%, #8b2fb8 55%, var(--herz) 130%);
  color: #fff;
  border-radius: var(--r-xl);
  padding: var(--sp-3xl);
  display: flex;
  gap: var(--sp-xl);
  align-items: center;
  flex-wrap: wrap;
}

.streifen h2 { margin: 0 0 6px; font-size: clamp(20px, 2.6vw, 28px); }
.streifen p { margin: 0; opacity: 0.92; max-width: 52ch; }
.streifen .knopf { background: #fff; color: var(--brand-ink); }
.streifen .knopf:hover { background: rgba(255, 255, 255, 0.88); }

/* ── Fußzeile ───────────────────────────────────────────────── */

footer { border-top: 1px solid var(--line); padding: var(--sp-3xl) 0 56px; color: var(--ink3); font-size: 13.5px; margin-top: var(--sp-3xl); }
footer .spalten { display: grid; gap: var(--sp-xxl); grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); margin-bottom: var(--sp-3xl); }
footer h4 { margin: 0 0 var(--sp-m); font-size: 13px; color: var(--ink); }
footer ul { list-style: none; margin: 0; padding: 0; }
footer li { margin-bottom: 8px; }
footer a:hover { color: var(--ink); text-decoration: underline; }
footer .schluss { border-top: 1px solid var(--line); padding-top: var(--sp-xl); }

/* ── Leistungsseite ─────────────────────────────────────────────
 *
 * Aufbau wie `DetailScreen` in der App, Block für Block in derselben
 * Reihenfolge: Titel, Ort, Bewertung, Anbieterzeile, Beschreibung, was
 * dabei ist, Extras, Gegend, Stornoregel, Bewertungen, Preis.
 *
 * Die Anbieterzeile ist der einzige Weg zum Auftritt des Betriebs. Vorher
 * stand der ganze Auftritt direkt unter den Bildern — dann liest niemand
 * mehr, was die Leistung überhaupt enthält. */

.trenner { border: 0; border-top: 1px solid var(--line); margin: var(--sp-xxl) 0; }

.abschnitt h2 { font-size: 18px; margin: 0 0 var(--sp-m); }

.anbieterzeile {
  display: flex;
  align-items: center;
  gap: var(--sp-l);
  padding: var(--sp-l);
  margin: 0 calc(var(--sp-l) * -1);
  border-radius: var(--r-m);
  transition: background 0.15s ease;
}

.anbieterzeile:hover { background: var(--bg-soft); }

.anbieterzeile img {
  width: 54px; height: 54px;
  border-radius: var(--r-pille);
  object-fit: cover;
  flex: 0 0 auto;
}

.anbieterzeile .wer { flex: 1 1 auto; min-width: 0; }
.anbieterzeile .wer b { display: block; font-size: 15.5px; }
.anbieterzeile .wer span { font-size: 13.5px; color: var(--ink3); }
.anbieterzeile .sym-pfeil { font-size: 22px; color: var(--ink3); flex: 0 0 auto; }

/* Aufzählung mit Haken — „Was ist dabei". */
.punkte { list-style: none; margin: 0; padding: 0; }

.punkte li {
  display: flex;
  gap: var(--sp-m);
  padding: 9px 0;
  font-size: 14.5px;
  color: var(--ink2);
}

.punkte .sym { font-size: 19px; color: var(--ok); flex: 0 0 auto; }

/* Zusatzleistungen: ankreuzbar wirkend, aber mit Preis rechts. */
.extra {
  display: flex;
  align-items: center;
  gap: var(--sp-m);
  padding: var(--sp-m) var(--sp-l);
  border: 1px solid var(--line);
  border-radius: var(--r-m);
  margin-bottom: var(--sp-s);
  font-size: 14.5px;
}

.extra .preis { margin-left: auto; font-weight: 700; white-space: nowrap; }

/* Preisaufstellung, wie die App sie zeigt: jede Zeile einzeln, die
 * Servicegebühr benannt, unten die Summe. */
.rechnung { font-size: 14.5px; }
.rechnung div { display: flex; justify-content: space-between; padding: 7px 0; color: var(--ink2); }
.rechnung div.summe { border-top: 1px solid var(--line); margin-top: var(--sp-s); padding-top: var(--sp-m); color: var(--ink); font-weight: 800; font-size: 16px; }

/* ── Bewertung eines Kunden ─────────────────────────────────── */

.stimmen { display: grid; gap: var(--sp-l); grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }

.stimme {
  border: 1px solid var(--line);
  border-radius: var(--r-m);
  padding: var(--sp-l) var(--sp-xl);
}

.stimme .kopfzeile { display: flex; align-items: center; gap: var(--sp-m); margin-bottom: var(--sp-s); }
.stimme .kopfzeile img { width: 34px; height: 34px; border-radius: var(--r-pille); object-fit: cover; }

/* Ein Kreis mit Initialen, wo kein Bild da ist.
 *
 * Die von Hand geschriebenen Seiten setzten dort Fotos aus dem Netz ein.
 * Aus den Daten kommen aber nur Initialen — ein Bild zu erfinden hiesse,
 * einem echten Menschen ein fremdes Gesicht zu geben. Der Kreis sagt
 * dasselbe und behauptet nichts. */
.kreis {
  display: grid;
  place-items: center;
  flex: none;
  width: 34px;
  height: 34px;
  border-radius: var(--r-pille);
  background: var(--brand-soft);
  color: var(--brand-ink);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.02em;
}

.kreis.gross { width: 68px; height: 68px; font-size: 24px; }
.stimme b { font-size: 14px; }
.stimme .wann { font-size: 12.5px; color: var(--ink3); }
.stimme p { margin: 0; font-size: 14.5px; color: var(--ink2); }

/* ── Anmeldung ──────────────────────────────────────────────────
 *
 * Derselbe Aufbau wie `WelcomeScreen`: Zeichen, Name, Versprechen,
 * Markenbalken, drei Wege. Apple und Google sind in der App sichtbar,
 * aber noch nicht eingerichtet — hier gilt dasselbe, und es steht dabei.
 * Ein Knopf, der so tut, als täte er etwas, ist schlimmer als keiner. */

/* Das Foto über der Anmeldung. Dieselbe Falle wie bei `.buehne-bild`:
 * ohne `max-width` treibt die Mindesthöhe über das Seitenverhältnis die
 * Breite hoch. */
.anmeldebild {
  position: relative;
  border-radius: var(--r-xl);
  overflow: hidden;
  aspect-ratio: 21 / 8;
  min-height: 200px;
  max-width: min(960px, 100%);
  margin: 0 auto;
}

.anmeldebild img { width: 100%; height: 100%; object-fit: cover; }

.anmeldebild::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(0, 0, 0, 0.05), rgba(0, 0, 0, 0.45));
}

.anmeldeflaeche {
  position: relative;
  max-width: min(960px, 100%);
  margin: -26px auto 0;
  background: var(--bg);
  border-radius: 26px 26px 0 0;
  padding: 30px 24px 34px;
}

.anmeldekasten {
  max-width: 420px;
  margin: 0 auto;
  text-align: center;
}

.anmeldekasten .zeichen {
  width: 74px; height: 74px;
  border-radius: 21px;
  margin: 0 auto var(--sp-l);
  background: linear-gradient(to top right, var(--marke-von) 0%,
                              var(--marke-ueber) 46%, var(--marke-bis) 100%);
  box-shadow: 0 9px 22px rgba(192, 69, 156, 0.3);
  display: grid; place-items: center;
}

.anmeldekasten .zeichen svg { width: 41px; height: 41px; }
.anmeldekasten h1 { font-size: 28px; margin: 0 0 var(--sp-xs); }
.anmeldekasten .anspruch { color: var(--ink3); font-size: 13px; letter-spacing: 0.6px; margin: 0 0 var(--sp-m); }
.anmeldekasten .markenbalken { margin: 0 auto var(--sp-xl); }
.anmeldekasten .welcome { color: var(--ink2); margin: 0 0 var(--sp-xxl); }
.anmeldekasten .oder { color: var(--ink3); font-size: 13.5px; margin: var(--sp-xl) 0 var(--sp-m); }

.wegknopf {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-m);
  width: 100%;
  padding: 14px 20px;
  border-radius: var(--r-pille);
  border: 1px solid var(--line);
  background: var(--bg);
  color: var(--ink);
  font: inherit;
  font-weight: 700;
  font-size: 15px;
  cursor: pointer;
  margin-bottom: var(--sp-m);
}

.wegknopf:hover { border-color: var(--ink); background: var(--bg-soft); }
.wegknopf.dunkel { background: var(--ink); color: #fff; border-color: var(--ink); }
.wegknopf.dunkel:hover { background: #000; }
.wegknopf.weich { background: var(--brand-soft); color: var(--brand-ink); border-color: transparent; }
.wegknopf.weich:hover { background: #ece1ff; }
.wegknopf .sym { font-size: 20px; }

/* Der Weg, der wirklich anmeldet.
 *
 * Er steht als Erster und in der Markenfarbe: die Webseite hat kein
 * eigenes Anmeldeverfahren, Evola läuft im Browser unter `/app/`. Zwei
 * Anmeldungen für dasselbe Konto wären zwei Stellen, an denen etwas
 * schiefgehen kann. */
.wegknopf.voll {
  background: var(--brand);
  color: #fff;
  border-color: transparent;
  text-decoration: none;
}
.wegknopf.voll:hover { background: var(--brand-ink); border-color: transparent; }

.wegzeile {
  font-size: 13px;
  color: var(--ink3);
  margin: 0 0 var(--sp-xl);
  line-height: 1.5;
}

.eingabe {
  width: 100%;
  padding: 14px 18px;
  border: 1px solid var(--line);
  border-radius: var(--r-m);
  font: inherit;
  font-size: 15px;
  color: var(--ink);
  background: var(--bg);
}

.eingabe:focus { outline: 2px solid var(--brand); outline-offset: 1px; border-color: transparent; }

/* Die ehrliche Meldung: sichtbar erst, wenn jemand einen der noch nicht
 * angeschlossenen Wege benutzt. */
.sperre {
  display: none;
  text-align: left;
  background: var(--bg-soft);
  border-radius: var(--r-m);
  padding: var(--sp-l) var(--sp-xl);
  font-size: 14px;
  color: var(--ink2);
  margin-top: var(--sp-l);
}

.sperre.an { display: block; }
.sperre b { color: var(--ink); }

.vier-bilder { display: grid; grid-template-columns: repeat(4, 1fr); gap: 7px; margin-top: var(--sp-xl); }
.vier-bilder img { width: 100%; height: 56px; object-fit: cover; border-radius: 10px; }

:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; border-radius: 4px; }

/* ── Gemerkt ────────────────────────────────────────────────── */

.herz-knopf.an { color: var(--herz); text-shadow: 0 1px 4px rgba(0, 0, 0, 0.35); }

.gemerkt-zahl {
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: var(--r-pille);
  background: var(--herz);
  color: #fff;
  font-size: 11px;
  font-weight: 800;
  display: inline-grid;
  place-items: center;
}

/* ── Menü im Kopf ───────────────────────────────────────────── */

.menue {
  position: absolute;
  right: 0;
  top: calc(100% + 8px);
  z-index: 40;
  min-width: 220px;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: var(--r-m);
  box-shadow: var(--schatten-stark);
  padding: var(--sp-s) 0;
}

/* Der Abmelden-Knopf sieht aus wie die Zeilen daneben — er ist nur
   deshalb ein `button`, weil er kein Ziel hat, sondern eine Handlung
   auslöst. Für Tastatur und Sprachausgabe ist der Unterschied wichtig;
   für das Auge soll es keinen geben. */
.menue a,
.menue button {
  display: block;
  width: 100%;
  text-align: left;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  cursor: pointer;
  padding: 10px var(--sp-l);
  font-size: 14.5px;
  font-weight: 500;
}

.menue a:hover,
.menue button:hover { background: var(--bg-soft); }

/* **Wie viele Anbieter gemerkt sind.**
 *
 * Die Zahl wurde bei jeder Änderung gerechnet (`zaehlerZeichnen` in
 * `evola.js`) und nirgends hingeschrieben: `[data-gemerkt-zahl]` stand
 * in genau einer Datei — in der, die danach sucht. Ein Zähler ohne Ort
 * ist Arbeit ohne Ergebnis.
 *
 * Er steht im Menü und nicht als Punkt an der Schaltfläche: ein Punkt
 * sagt „da ist etwas", eine Zahl sagt, wie viel — und beim Merken ist
 * genau die Zahl die Auskunft, die man sucht. */
.menue a { display: flex; align-items: center; gap: 8px; }

.menuezahl {
  margin-left: auto;
  min-width: 20px;
  padding: 0 6px;
  border-radius: 999px;
  background: var(--brand-soft);
  color: var(--brand-ink);
  font-size: 12.5px;
  font-weight: 700;
  line-height: 19px;
  text-align: center;
}
.menue button:disabled { color: var(--ink3); cursor: default; }
.menue hr { border: 0; border-top: 1px solid var(--line); margin: var(--sp-s) 0; }

/* ── Bild groß ──────────────────────────────────────────────── */

.lupe {
  position: fixed;
  inset: 0;
  z-index: 100;
  background: rgba(12, 12, 14, 0.92);
  display: grid;
  grid-template-columns: 72px 1fr 72px;
  align-items: center;
  justify-items: center;
}

.lupe[hidden] { display: none; }

.lupe img {
  grid-column: 2;
  max-width: 100%;
  max-height: 86vh;
  border-radius: var(--r-m);
  object-fit: contain;
}

.lupe-zu {
  position: absolute;
  top: 18px; right: 18px;
  width: 44px; height: 44px;
  border: 0;
  border-radius: var(--r-pille);
  background: rgba(255, 255, 255, 0.14);
  color: #fff;
  font-size: 22px;
  cursor: pointer;
  display: grid; place-items: center;
}

.lupe-pfeil {
  width: 48px; height: 48px;
  border: 0;
  border-radius: var(--r-pille);
  background: rgba(255, 255, 255, 0.14);
  color: #fff;
  font-size: 26px;
  line-height: 1;
  cursor: pointer;
}

.lupe-zu:hover, .lupe-pfeil:hover { background: rgba(255, 255, 255, 0.26); }

.lupe-zaehler {
  position: absolute;
  bottom: 22px;
  margin: 0;
  color: rgba(255, 255, 255, 0.8);
  font-size: 13px;
}

@media (max-width: 640px) {
  .lupe { grid-template-columns: 0 1fr 0; }
  .lupe-pfeil { position: absolute; bottom: 60px; }
  .lupe-pfeil.links { left: 20px; }
  .lupe-pfeil.rechts { right: 20px; }
}

/* ── Kurze Meldung ──────────────────────────────────────────── */

.meldung {
  position: fixed;
  left: 50%;
  bottom: 24px;
  transform: translate(-50%, 20px);
  z-index: 120;
  background: var(--ink);
  color: #fff;
  padding: 12px 20px;
  border-radius: var(--r-pille);
  font-size: 14px;
  font-weight: 600;
  box-shadow: var(--schatten-stark);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease, transform 0.2s ease;
}

.meldung.an { opacity: 1; transform: translate(-50%, 0); }

/* Der Weg zurueck in der Meldung.
 *
 * Er muss sich vom Satz abheben, ohne ihn zu ueberschreien — hell auf
 * dunkel, unterstrichen, mit genug Flaeche zum Treffen. */
.meldung button {
  margin-left: var(--sp-m);
  padding: 2px 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  font-weight: 700;
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}

.meldung button:focus-visible { outline: 2px solid #fff; outline-offset: 3px; }

/* ── Merkzettel verwalten ───────────────────────────────────── */

/* Die Zeile über einem Zettel: Name links, die zwei Wörter daneben.
 *
 * Sie stand vorher nur als Überschrift da. Mit dem Umbenennen und
 * Löschen daneben ist sie eine Zeile, an der man arbeitet — deshalb
 * die gemeinsame Grundlinie und der Abstand dazwischen. */
.zettelkopf {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--sp-m);
}

/* Die Wörter stehen **neben** dem Namen, nicht am rechten Rand.
 *
 * Hier stand `margin-right: auto`, was sie ans Ende der Zeile geschoben
 * hätte — auf einem breiten Bildschirm einen halben Meter vom Namen
 * entfernt, zu dem sie gehören. Gesehen und geändert. */
.zettelkopf h2 { margin: 0; }

.zettelknopf {
  color: var(--brand-ink);
  font-size: 13.5px;
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}

.zettelknopf:hover { text-decoration-thickness: 2px; }
.zettelknopf:focus-visible { outline: 2px solid var(--brand); outline-offset: 3px; }

/* Die Auswahl unter einer Karte.
 *
 * Sie sitzt **in** der Karte, und die Karte ist ein Verweis — deshalb
 * fängt das Skript den Klick darauf ab. Optisch soll sie eine Fußzeile
 * sein und nicht mit dem Preis darüber konkurrieren. */
.verschieben {
  display: flex;
  align-items: center;
  gap: var(--sp-s);
  margin-top: var(--sp-s);
  color: var(--ink3);
  font-size: 12.5px;
}

.verschieben select {
  flex: 1;
  min-width: 0;
  padding: 6px 8px;
  border: 1px solid var(--line);
  border-radius: var(--r-s);
  background: var(--bg);
  color: var(--ink);
  font: inherit;
  font-size: 12.5px;
}

/* ── Warten ─────────────────────────────────────────────────── */

/* Ein Skelett, kein Kreisel.
 *
 * Dieselbe Entscheidung wie in der App (Phase D, `evola_skelett.dart`):
 * ein Kreisel sagt „es passiert etwas", ein Skelett sagt „hier kommt
 * eine Liste, und so wird sie aussehen". Der Sprung beim Ankommen
 * entfaellt, weil die Form schon steht.
 *
 * 1400 ms, deutlich langsamer als jede Bedienung — ein Schimmern im
 * Takt eines Fingertipps wirkt hektisch, und Warten soll ruhig
 * aussehen. Der Wert steht so in `design/system.md`. */
.skelett {
  border-radius: var(--r-m);
  background: linear-gradient(
    100deg,
    var(--bg-soft) 30%,
    #ffffff 50%,
    var(--bg-soft) 70%
  );
  background-size: 300% 100%;
  animation: schimmern 1400ms linear infinite;
}

@keyframes schimmern {
  from { background-position: 150% 0; }
  to   { background-position: -50% 0; }
}

/* ── Nichts gefunden ────────────────────────────────────────── */

.nichts {
  border: 1px dashed var(--line);
  border-radius: var(--r-m);
  padding: var(--sp-3xl) var(--sp-xl);
  text-align: center;
  color: var(--ink2);
  font-size: 14.5px;
}

/* **Der Ausweg muss als Ausweg zu erkennen sein.**
 *
 * `a { color: inherit; text-decoration: none }` gilt global — richtig
 * fuer Karten und Kacheln, die als Ganzes ein Verweis sind. In einem
 * Leerzustand hiess es: „Nochmal versuchen", „Anlass zuruecknehmen"
 * und „Anbieter suchen" standen in derselben grauen Schrift wie der
 * Satz davor und lasen sich als dessen Ende.
 *
 * Ein Leerzustand ohne sichtbaren Weg hinaus ist eine Sackgasse mit
 * Beschriftung — gefunden am 14.08. beim Bauen der Merklistenseite,
 * dagewesen war es auf der Suchseite schon lange. */
.nichts a {
  display: inline-block;
  margin-top: var(--sp-m);
  color: var(--brand-ink);
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 3px;
}

.nichts a:hover { text-decoration-thickness: 2px; }

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
  html { scroll-behavior: auto; }
}

/* ── Drucken ─────────────────────────────────────────────────
 *
 * „Als PDF sichern" ist das Drucken des Browsers. Damit dabei ein
 * brauchbares Dokument herauskommt, fliegt alles raus, was nur auf dem
 * Bildschirm einen Zweck hat. */

@media print {
  .kopf, footer, .knopf, .filter, .lupe, .meldung, .menue { display: none !important; }
  body { font-size: 11pt; color: #000; }
  main { padding: 0 !important; }
  a { color: #000; text-decoration: none; }
  .rechtstext { max-width: none; }
  .rechtstext h2 { break-after: avoid; }
  .luecke { background: none; border: 1px solid #000; }
}

/* ── Anmeldung: zweispaltig ──────────────────────────────────────
 *
 * Die erste Fassung war der Telefonbildschirm der App, mittig auf einer
 * weißen Seite. Das war ehrlich, aber es sah aus wie ein Handy in einem
 * Browser — auf einem 27-Zoll-Schirm eine schmale Säule in viel Nichts.
 *
 * Wie es die großen Anmeldeseiten machen: links das Versprechen mit
 * einem Bild und einem Beleg, rechts der Vorgang. Links liest man
 * einmal, rechts arbeitet man — und rechts ist bei den meisten die
 * Maushand. Auf schmalen Fenstern fällt die linke Spalte weg; sie ist
 * Beiwerk, das Formular ist es nicht. */

.anmeldeseite {
  display: grid;
  grid-template-columns: 1.05fr 1fr;
  min-height: calc(100vh - 72px);
}

.anmelde-bild {
  position: relative;
  overflow: hidden;
  display: flex;
  align-items: flex-end;
  padding: clamp(28px, 4vw, 56px);
}

.anmelde-bild > img {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
}

.anmelde-bild::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    200deg,
    rgba(123, 63, 228, 0.36) 0%,
    rgba(24, 24, 27, 0.5) 55%,
    rgba(24, 24, 27, 0.82) 100%
  );
}

.anmelde-text { position: relative; z-index: 1; color: #fff; max-width: 30ch; }

.anmelde-text h2 {
  font-size: clamp(26px, 3vw, 40px);
  line-height: 1.06;
  letter-spacing: -1.2px;
  margin: 0 0 var(--sp-m);
}

.anmelde-text p { margin: 0; opacity: 0.92; font-size: 16px; }

/* Drei Belege statt eines Werbespruchs: sie sagen, was man bekommt. */
.anmelde-punkte { list-style: none; margin: var(--sp-xxl) 0 0; padding: 0; }

.anmelde-punkte li {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  margin-bottom: 10px;
  font-size: 14.5px;
  opacity: 0.94;
}

.anmelde-punkte .sym { font-size: 18px; flex: 0 0 auto; margin-top: 1px; }

.anmelde-form {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(28px, 4vw, 56px) var(--seite);
}

@media (max-width: 1024px) {
  .anmeldeseite { grid-template-columns: 1fr; min-height: 0; }
  /* Das Bild bleibt, aber als schmales Band über dem Formular: der
   * Auftakt gehört dazu, die halbe Bildschirmhöhe nicht. */
  .anmelde-bild { min-height: 220px; align-items: flex-end; }
  .anmelde-punkte { display: none; }
}

/* Eine Trennzeile mit Wort in der Mitte — ordnet die Wege, ohne einen
 * zweiten Kasten aufzumachen. */
.trennzeile {
  display: flex;
  align-items: center;
  gap: var(--sp-m);
  margin: var(--sp-xl) 0 var(--sp-l);
  color: var(--ink3);
  font-size: 12.5px;
}

.trennzeile::before,
.trennzeile::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--line);
}

/* ── Abschnitt „So läuft eine Buchung" ─────────────────────────────
 *
 * Sandton statt Grau: der Abschnitt erklärt das Versprechen und soll
 * einladend wirken, nicht wie ein Hinweiskasten. Die Ziffern werden
 * groß und ruhig — sie ordnen, sie schmücken nicht. */
#ablauf { background: var(--sand); }

#ablauf .zahl {
  width: 40px;
  height: 40px;
  border-radius: var(--r-pille);
  background: var(--bg);
  color: var(--brand-ink);
  border: 1px solid var(--sand-tief);
  display: grid;
  place-items: center;
  font-weight: 800;
  font-size: 16px;
  margin-bottom: var(--sp-m);
}

/* Der Block für Dienstleister bekommt den Markenton als Fläche.
 * Er ist die einzige Stelle der Startseite, die etwas verkauft — und
 * damit die einzige, an der ein farbiger Grund gerechtfertigt ist. */
#anbieter {
  background: var(--brand-soft);
}

#anbieter h2 { color: var(--brand-ink); }

/* Überschriften und Kleintext der Abschnitte.
 *
 * Sie standen als `style=`-Angaben in den Tags — und haben damit jede
 * Regel aus dieser Datei überstimmt. Der graue Grund des Ablaufs blieb
 * grau, obwohl hier längst Sand stand. Was die Seite gestaltet, gehört
 * in die Datei, die die Seite gestaltet. */
.abschnitt-titel {
  font-size: clamp(22px, 3vw, 32px);
  letter-spacing: -0.022em;
  margin: 0 0 var(--sp-s);
}

.punkt-titel { margin: 10px 0 4px; font-size: 16px; }
.punkt-text { margin: 0; color: var(--ink2); font-size: 14.5px; }

/* ── `hidden` muss verstecken ──────────────────────────────────────
 *
 * **Ein Fehler, der die Suche unbrauchbar machte.** Das Skript setzt
 * `hidden`, wenn die Beispieldaten eine gewählte Kategorie nicht
 * abdecken. Nur gewinnt jede Klassenregel mit eigenem `display` gegen
 * die Browser-Vorgabe für `[hidden]` — `.raster { display: grid }`
 * zeigte das Raster weiter an. Auf dem Bildschirm stand dann
 * „6 Hochzeitslocations" und darunter sechs Fotografen.
 *
 * `!important` ist hier richtig: `hidden` ist keine Gestaltung, sondern
 * eine Aussage über den Inhalt. Sie darf nicht überstimmbar sein. */
[hidden] { display: none !important; }

/* ── Anmelden und Konto anlegen ────────────────────────────────────
 *
 * **Die Webseite hat ihre eigene Anmeldemaske.** Vorher führte sie in
 * die App im Browser — eine Handy-Ansicht in einem Fensterrahmen. Wer im
 * Browser sitzt, will eine Webseite bedienen.
 *
 * Dasselbe Konto bleibt es trotzdem: es liegt nicht in der Oberfläche,
 * sondern dahinter. Beide sprechen mit demselben Dienst. */

.reiterpaar {
  display: grid;
  /* Nicht fest auf zwei: der Name stammt von der Anmeldung, wo es zwei
   * sind. Anfragen und Auftraege haben drei — mit `1fr 1fr` brach der
   * dritte in eine zweite Zeile und sah aus wie ein Fehler. */
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  gap: 4px;
  background: var(--bg-soft);
  border-radius: var(--r-pille);
  padding: 4px;
  margin-bottom: var(--sp-l);
}

.reiterpaar .reiter {
  border: 0;
  background: transparent;
  border-radius: var(--r-pille);
  padding: 10px 12px;
  font: inherit;
  font-weight: 700;
  font-size: 14px;
  color: var(--ink2);
  cursor: pointer;
}

.reiterpaar .reiter.an {
  background: var(--bg);
  color: var(--ink);
  box-shadow: 0 1px 3px rgba(24, 24, 27, 0.1);
}

.feldpaar-hoch {
  text-align: left;
  margin-bottom: var(--sp-m);
}

.feldpaar-hoch label {
  display: block;
  font-size: 12.5px;
  font-weight: 700;
  margin-bottom: 6px;
}

/* Das Auge sitzt im Feld, nicht daneben: daneben verschiebt es die
 * Breite des Eingabefeldes gegenüber den anderen. */
.wortfeld { position: relative; }
.wortfeld .eingabe { padding-right: 46px; }

.wortzeigen {
  position: absolute;
  right: 6px;
  top: 50%;
  transform: translateY(-50%);
  width: 34px;
  height: 34px;
  border: 0;
  border-radius: var(--r-pille);
  background: transparent;
  color: var(--ink3);
  cursor: pointer;
  display: grid;
  place-items: center;
  font-size: 18px;
}

.wortzeigen:hover { background: var(--bg-soft); color: var(--ink); }

/* Fehler stehen am Feld, nicht in einem Kasten am Ende.
 *
 * Ein Formular, das erst unten sagt „drei Felder sind falsch", lässt
 * suchen. Wer den Fehler dort liest, wo er entstanden ist, sieht ihn
 * beim Korrigieren. */
/* Der Zeichenzaehler unter der Beschreibung.
 *
 * Die Pruefung verlangt 120 Zeichen. Diese Zahl stand bisher nirgends
 * im Formular — man reichte ein und erfuhr es durch eine Ablehnung.
 * Rot, solange es nicht reicht; danach unauffaellig grau, damit die
 * Warnung nicht bleibt, wenn sie erledigt ist. */
/* Die Anlasswahl beim Anlegen einer Leistung.
 *
 * Antippbare Pillen statt Kaestchen: es sind sechs, sie sind kurz, und
 * eine Reihe Kaestchen untereinander braucht dreimal so viel Platz fuer
 * dieselbe Aussage. Dasselbe Bild wie in der App, wo dort
 * `EvolaChoiceChip` steht. */
.anlasswahl {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.anlassknopf {
  padding: 7px 14px;
  border: 1px solid var(--linie);
  border-radius: 999px;
  background: var(--bg);
  color: var(--ink2);
  font: inherit;
  font-size: 13.5px;
  cursor: pointer;
}

.anlassknopf:hover {
  border-color: var(--ink3);
}

.anlassknopf.an {
  border-color: var(--brand-ink);
  background: var(--brand-soft, var(--bg-soft));
  color: var(--brand-ink);
  font-weight: 600;
}

.zaehler {
  margin: 6px 0 0;
  font-size: 12.5px;
  color: var(--ink3);
}

.zaehler.knapp {
  color: var(--err, #b3261e);
}

.feldfehler {
  margin: 6px 0 0;
  font-size: 12.5px;
  color: var(--err, #b3261e);
  display: flex;
  align-items: flex-start;
  gap: 6px;
}

.eingabe.falsch {
  border-color: var(--err, #b3261e);
  background: #fdf6f5;
}

.wortstaerke {
  margin: 6px 0 0;
  font-size: 12.5px;
  color: var(--ink3);
}

.wortstaerke.gut { color: var(--ok); }

/* Der angemeldete Zustand im Kopf. */
.kopf .konto {
  display: flex;
  align-items: center;
  gap: var(--sp-s);
  padding: 6px 14px 6px 6px;
  border: 1px solid var(--line);
  border-radius: var(--r-pille);
  font-size: 14px;
  font-weight: 700;
  color: var(--ink);
  text-decoration: none;
  white-space: nowrap;
}

.kopf .konto:hover { border-color: var(--ink); }

.kopf .konto .kreis {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--brand-soft);
  color: var(--brand-ink);
  display: grid;
  place-items: center;
  font-size: 12px;
  font-weight: 800;
}

/* ── Formularfelder außerhalb der Suchzeile ─────────────────────
 *
 * `.feld` allein ist für die Suchleiste gebaut: randlos, weil dort die
 * ganze Zeile den Rahmen trägt. In einem Formular steht ein Feld für
 * sich und braucht seinen eigenen — sonst schwimmt die Eingabe auf der
 * Seite und niemand sieht, wo er klicken soll. */
.feld.eingerahmt {
  border: 1px solid var(--line);
  border-radius: var(--r-m);
  padding: 10px var(--sp-l);
  background: var(--bg);
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.feld.eingerahmt:focus-within {
  border-color: var(--brand);
  box-shadow: 0 0 0 3px var(--brand-soft);
}

.feld.eingerahmt label {
  display: block;
  font-size: 12px;
  font-weight: 700;
  color: var(--ink3);
  margin-bottom: 2px;
}

.feld.eingerahmt input,
.feld.eingerahmt textarea {
  width: 100%;
  border: 0;
  padding: 0;
  background: none;
  font: inherit;
  color: var(--ink);
  outline: none;
  resize: vertical;
}

/* Zwei Felder nebeneinander, auf dem Telefon untereinander. */
.paarfeld {
  display: grid;
  gap: var(--sp-m);
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}

/* Eine Zeile zum Anhaken — Extras, Zahlungswege.
 *
 * Das ganze Feld ist anklickbar, nicht nur das kleine Kästchen: ein
 * Ziel von 13 Pixeln trifft auf dem Telefon niemand zuverlässig. */
.wahlzeile {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-m);
  padding: var(--sp-m) var(--sp-l);
  border: 1px solid var(--line);
  border-radius: var(--r-m);
  margin-bottom: var(--sp-s);
  cursor: pointer;
  transition: border-color 0.15s ease, background 0.15s ease;
}

.wahlzeile:hover { border-color: var(--ink3); }

.wahlzeile:has(input:checked) {
  border-color: var(--brand);
  background: var(--brand-soft);
}

.wahlzeile input { margin-top: 3px; flex: none; accent-color: var(--brand); }

.wahlzeile .wahltext {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: 14.5px;
}

.wahlzeile .wahltext span { color: var(--ink3); font-size: 13px; }
.wahlzeile .preis { font-weight: 700; white-space: nowrap; }
.wahlzeile.schmal { padding: 10px var(--sp-l); }

.wahlreihe {
  display: grid;
  gap: var(--sp-s);
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
}

.wahlreihe .wahlzeile { margin: 0; align-items: center; }

/* ── Meine Anfragen ─────────────────────────────────────────────
 *
 * Liste und Detail nebeneinander, solange Platz ist. Auf einem Telefon
 * wäre das zweispaltig unleserlich — dort steht erst die Liste, und die
 * gewählte Anfrage ersetzt sie. */
.anfrageraster {
  display: grid;
  gap: var(--sp-xl);
  grid-template-columns: minmax(0, 1fr) minmax(300px, 380px);
  align-items: start;
}

.anfragekarte {
  display: block;
  width: 100%;
  text-align: left;
  padding: var(--sp-l) var(--sp-xl);
  margin-bottom: var(--sp-m);
  border: 1px solid var(--line);
  border-radius: var(--r-l);
  background: var(--bg);
  cursor: pointer;
  font: inherit;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.anfragekarte:hover { border-color: var(--ink3); }

/* Die gewählte trägt die Markenfarbe — ohne sie sieht man im Detail
 * rechts nicht, wozu es gehört. */
.anfragekarte.an {
  border-color: var(--brand);
  box-shadow: 0 0 0 1px var(--brand);
}

.anfragekarte .zeile {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--sp-m);
  margin-bottom: 4px;
}

.anfragekarte h3 { margin: 0; font-size: 15.5px; }
.anfragekarte .meta { margin: 0; font-size: 13.5px; color: var(--ink2); }
.anfragekarte .meta.klein { font-size: 12px; color: var(--ink3); margin-top: 4px; }

/* Zwei Stände brauchen eine eigene Farbe: Warten ist kein Erfolg, und
 * Storniert ist kein Fehler — es ist beendet. */
.pille.warten { background: var(--sand-tief); color: var(--ink2); }
.pille.aus { background: var(--bg-soft); color: var(--ink3); }

/* Abgelehnt ist nicht dasselbe wie pausiert und darf nicht so aussehen.
 * Pausiert hat der Anbieter selbst entschieden — grau, ruhend, jederzeit
 * umkehrbar. Abgelehnt haben wir, und er muss etwas tun. Als graue Pille
 * hat er den Grund darunter gar nicht gesucht. */
.pille.fehler {
  background: color-mix(in srgb, var(--err) 12%, transparent);
  color: var(--err);
}

.angabe {
  display: flex;
  justify-content: space-between;
  gap: var(--sp-m);
  padding: 6px 0;
  font-size: 14px;
}

.angabe span { color: var(--ink3); }

.nur-schmal { display: none; }

@media (max-width: 1024px) {
  .anfrageraster { grid-template-columns: minmax(0, 1fr); }

  /* Solange eine Anfrage gewählt ist, tritt die Liste zurück. Beides
   * untereinander hiesse: scrollen, um zu sehen, was man angetippt hat. */
  .anfrageraster.zeigt-detail [data-liste] { display: none; }
  .anfrageraster .kasten.klebt { position: static; }
  .nur-schmal { display: inline-flex; align-items: center; gap: 6px; }
}

/* ── Gespräch ───────────────────────────────────────────────────
 *
 * Der Verlauf hat eine feste Höhe und scrollt in sich. Sonst wächst die
 * Seite mit jeder Nachricht, und das Eingabefeld wandert nach unten aus
 * dem Bild — man müsste zum Schreiben erst scrollen. */
.gespraech {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--line);
  border-radius: var(--r-l);
  background: var(--bg);
  overflow: hidden;
  height: min(70vh, 620px);
  position: sticky;
  top: 96px;
}

.gespraechkopf {
  display: flex;
  align-items: center;
  gap: var(--sp-m);
  padding: var(--sp-m) var(--sp-l);
  border-bottom: 1px solid var(--line);
  flex: none;
}

.gespraechkopf b { font-size: 14.5px; display: block; }
.gespraechkopf .wann { font-size: 12.5px; color: var(--ink3); }

.verlauf {
  flex: 1;
  overflow-y: auto;
  padding: var(--sp-l);
  display: flex;
  flex-direction: column;
  gap: var(--sp-s);
}

.blase {
  max-width: 82%;
  align-self: flex-start;
  padding: 10px var(--sp-l);
  border-radius: var(--r-l);
  background: var(--bg-soft);
  font-size: 14.5px;
  line-height: 1.5;
}

/* Die eigenen rechts und in der Markenfarbe — die Seite allein reicht
 * nicht, wenn zwei kurze Nachrichten untereinander stehen. */
.blase.meine {
  align-self: flex-end;
  background: var(--brand);
  color: #fff;
}

.blase p { margin: 0; }
.blase .zeit {
  display: block;
  margin-top: 4px;
  font-size: 11.5px;
  color: var(--ink3);
}
.blase.meine .zeit { color: rgb(255 255 255 / 75%); }

/* Eventgruppe: über einer fremden Nachricht steht, wer sie geschrieben
 * hat. In einer Runde von sechs Betrieben weiss man sonst nicht, wer
 * gemeint ist — anders als im Einzelgespräch, wo der Kopf der Seite
 * das schon sagt. */
.blase-wer {
  display: block;
  margin-bottom: 3px;
  font-size: 12px;
  font-weight: 700;
  color: var(--brand-ink);
}

/* Ein verbindliches Angebot sieht anders aus als eine Nachricht. Wer das
 * überliest, nimmt womöglich etwas an, ohne es zu merken. */
.blase.angebot {
  background: var(--bg);
  border: 1.5px solid var(--brand);
  color: var(--ink);
  max-width: 92%;
  align-self: stretch;
}

.blase.angebot.meine { background: var(--brand-soft); }
.blase.angebot b { display: block; font-size: 15px; margin-bottom: 4px; }
.blase.angebot p { color: var(--ink2); font-size: 14px; margin-bottom: var(--sp-s); }
.blase.angebot .zeit { color: var(--ink3); }

.angebotpreis {
  font-size: 20px;
  font-weight: 700;
  margin: var(--sp-s) 0 2px;
}

.tagestrenner {
  align-self: center;
  font-size: 12px;
  font-weight: 700;
  color: var(--ink3);
  padding: var(--sp-s) 0;
}

.senderei {
  display: flex;
  align-items: flex-end;
  gap: var(--sp-s);
  padding: var(--sp-m) var(--sp-l);
  border-top: 1px solid var(--line);
  flex: none;
}

.senderei textarea {
  flex: 1;
  border: 1px solid var(--line);
  border-radius: var(--r-l);
  padding: 10px var(--sp-l);
  font: inherit;
  resize: none;
  max-height: 120px;
  outline: none;
}

.senderei textarea:focus {
  border-color: var(--brand);
  box-shadow: 0 0 0 3px var(--brand-soft);
}

.senderei .rund.voll {
  background: var(--brand);
  color: #fff;
  border: 0;
  flex: none;
}

@media (max-width: 1024px) {
  .gespraech { position: static; height: min(75vh, 560px); }
}

/* ── Listenzeilen im Leistungsformular ──────────────────────────
 *
 * „Was ist dabei" und die Zusatzleistungen sind beliebig viele Zeilen
 * mit zwei bis drei Feldern. Nebeneinander, solange Platz ist — der
 * Wegknopf bleibt immer am Ende. */
.listenzeile {
  display: grid;
  grid-template-columns: 1fr 1fr auto;
  gap: var(--sp-s);
  align-items: end;
  margin-bottom: var(--sp-s);
}

.listenzeile:has(.schmal) {
  grid-template-columns: 1fr 1fr 130px auto;
}

.listenzeile .feld.eingerahmt { margin: 0; }

/* **Hiess vorher `.wegknopf` — und das war schon vergeben.**
 *
 * Die Anmeldeseite nennt ihre grossen Knoepfe („Weiter mit Apple",
 * „Weiter mit Google") seit jeher so. Meine spaetere Regel fuer das
 * kleine Kreuz im Leistungsformular hat sie auf 42 Pixel
 * zusammengequetscht — auf einer Seite, die ich beim Bauen des Formulars
 * nie angesehen habe.
 *
 * Ein Klassenname ist ein globaler Name. Wer einen neuen einfuehrt,
 * muss vorher nachsehen, ob es ihn schon gibt: `grep -n "\.name" stil.css` */
.zeilenweg {
  width: 40px;
  height: 44px;
  font-size: 22px;
  line-height: 1;
  color: var(--ink3);
  border-radius: var(--r-m);
  background: none;
  border: 0;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;
}

.zeilenweg:hover { background: var(--bg-soft); color: var(--err); }

/* Auswahlfelder sehen sonst in jedem Browser anders aus und passen zu
 * keinem der gerahmten Felder daneben. */
.feld.eingerahmt select {
  width: 100%;
  border: 0;
  padding: 0;
  background: none;
  font: inherit;
  color: var(--ink);
  outline: none;
  appearance: none;
  cursor: pointer;
}

@media (max-width: 640px) {
  .listenzeile,
  .listenzeile:has(.schmal) { grid-template-columns: 1fr auto; }
  .listenzeile .feld.eingerahmt:nth-child(2) { grid-column: 1 / -1; }
}

/* ── Kennzahlen des Anbieters ───────────────────────────────────
 *
 * Drei Kacheln nebeneinander, auf dem Telefon untereinander. Die Zahl
 * trägt die Kachel — die Zeile darunter erklärt sie, statt sie zu
 * wiederholen. */
.zahlenreihe {
  display: grid;
  gap: var(--sp-m);
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
}

.zahlkachel {
  border: 1px solid var(--line);
  border-radius: var(--r-l);
  padding: var(--sp-l) var(--sp-xl);
  background: var(--bg);
}

.zahlkachel b {
  display: block;
  font-size: clamp(24px, 3vw, 30px);
  line-height: 1.1;
  /* Ziffern in gleicher Breite: sonst springen die Kacheln, sobald sich
   * eine Zahl ändert. */
  font-variant-numeric: tabular-nums;
}

.zahlkachel span {
  display: block;
  margin-top: 4px;
  font-size: 13.5px;
  color: var(--ink3);
}

/* Ein Knopf, der nur so breit ist wie sein Text.
 *
 * `.knopf.voll` ist für eine ganze Spalte gedacht und dehnt sich in
 * einem Flexcontainer entsprechend aus. In einer Zeile mit mehreren
 * Knöpfen ist das falsch: dort lief „Zusagen" über die ganze Karte. */
.knopf.schmal {
  display: inline-flex;
  width: auto;
  flex: none;
}

/* ---------------------------------------------------------------------------
   Kontoliste
   ---------------------------------------------------------------------------
   Die Zeilenliste, die es auf der Webseite bisher nicht gab.

   **Warum sie fehlte und was das anrichtete.** Die Kontoseite hatte vier
   Abschnitte untereinander: Name, Rollenwahl, Passwort, Abmelden. Alles
   andere, was die App an dieser Stelle anbietet — Auftritt, Leistungen,
   Aufträge, Nachweise, Paket, Anfragen, Nachrichten — war von hier aus
   nicht erreichbar. Man sah seinen Namen und einen Abmeldeknopf und
   hielt das für das ganze Konto.

   Eine Zeile hat drei Teile: ein Zeichen links, Titel mit Beiwort, ein
   Winkel rechts. Der Winkel ist wichtig — ohne ihn sieht eine Zeile aus
   wie Text und wird nicht angetippt. */

.kontoliste {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--line);
  border-radius: var(--r-l);
  overflow: hidden;
  background: var(--bg);
}

.kontozeile {
  display: flex;
  align-items: center;
  gap: var(--sp-m);
  padding: 14px var(--sp-l);
  border-bottom: 1px solid var(--line);
  color: var(--ink);
  text-decoration: none;
  background: none;
  border-left: 0;
  border-right: 0;
  border-top: 0;
  width: 100%;
  text-align: left;
  font: inherit;
  cursor: pointer;
  transition: background .12s ease;
}

.kontozeile:last-child { border-bottom: 0; }
.kontozeile:hover      { background: var(--bg-soft); }

.kontozeile:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: -2px;
}

/* Das Zeichen sitzt in einem ruhigen Kreis. Ohne ihn stehen die Symbole
   verschieden weit vom Text weg, je nachdem wie breit sie sind. */
.kontozeile .kz-zeichen {
  flex: none;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: var(--bg-soft);
  display: grid;
  place-items: center;
  color: var(--ink2);
}

.kontozeile .kz-zeichen svg { width: 18px; height: 18px; }

.kontozeile .kz-text { flex: 1; min-width: 0; }

.kontozeile .kz-titel {
  display: block;
  font-size: 15px;
  font-weight: 600;
  line-height: 1.3;
}

.kontozeile .kz-bei {
  display: block;
  font-size: 13px;
  color: var(--ink3);
  margin-top: 2px;
}

/* Der Winkel rechts. Reines CSS statt eines weiteren SVG je Zeile. */
.kontozeile .kz-winkel {
  flex: none;
  width: 8px;
  height: 8px;
  border-right: 2px solid var(--ink3);
  border-top: 2px solid var(--ink3);
  transform: rotate(45deg);
  margin-right: 4px;
}

/* Eine Zeile kann rechts eine Angabe tragen — ein Betrag, eine Anzahl,
   ein Stand. Sie steht vor dem Winkel. */
.kontozeile .kz-wert {
  flex: none;
  font-size: 13.5px;
  color: var(--ink2);
  font-variant-numeric: tabular-nums;
}

/* Eine Zeile, die etwas verlangt, sagt es hier — nicht erst dahinter. */
.kontozeile .pille { flex: none; }

.kontoteil { margin-top: var(--sp-xl); }

.kontoteil > h2 {
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--ink3);
  margin: 0 0 var(--sp-s);
  font-weight: 600;
}

/* ---------------------------------------------------------------------------
   Pakete
   ---------------------------------------------------------------------------
   Drei Stufen nebeneinander, auf dem Telefon untereinander. */

.pakete {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: var(--sp-l);
  align-items: start;
}

.paketkarte {
  border: 1px solid var(--line);
  border-radius: var(--r-l);
  padding: var(--sp-xl);
  display: flex;
  flex-direction: column;
  gap: var(--sp-s);
  background: var(--bg);
}

/* Die eigene Stufe hebt sich ab — sonst sucht man sie jedes Mal. */
.paketkarte.meine {
  border-color: var(--brand);
  box-shadow: 0 0 0 1px var(--brand);
}

.paketkarte h2 { margin: 0; font-size: 19px; }

.paketpreis {
  margin: 0;
  font-size: 30px;
  font-weight: 800;
  letter-spacing: -0.8px;
}

.paketpreis span {
  font-size: 14px;
  font-weight: 500;
  color: var(--ink3);
  letter-spacing: 0;
}

/* Die Gebühr ist bei einem Auftrag über 2.000 € die grössere Zahl als
   der Monatspreis. Sie darf nicht in der Liste untergehen. */
.paketgebuehr {
  margin: 0;
  font-size: 15px;
  font-weight: 600;
  color: var(--brand-ink);
}

.paketjahr { margin: 0; font-size: 13px; color: var(--ink3); }

.paketliste {
  margin: var(--sp-m) 0 var(--sp-l);
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.paketliste li {
  font-size: 14px;
  color: var(--ink2);
  padding-left: 22px;
  position: relative;
  line-height: 1.5;
}

/* Der Haken als Rahmen statt als Zeichen: er sitzt auf jeder Zeile
   gleich, unabhängig von der Schriftart. */
.paketliste li::before {
  content: "";
  position: absolute;
  left: 3px;
  top: 5px;
  width: 5px;
  height: 9px;
  border-right: 2px solid var(--ok);
  border-bottom: 2px solid var(--ok);
  transform: rotate(45deg);
}

.paketkarte .pille { align-self: flex-start; }

/* ---------------------------------------------------------------------------
   Leerzustand
   ---------------------------------------------------------------------------
   Gemeldet: „Nachrichten — noch keine Nachrichten. Selbst da fehlt der
   Screen." Der Text stand da und ein Weg auch. Was fehlte, war alles
   andere: eine Überschrift und ein Satz auf einer weissen Fläche sehen
   aus wie eine Seite, die nicht fertig geladen hat.

   Drei Dinge ändern das:
     * Der Block steht in der Mitte statt links oben.
     * Ein Zeichen gibt ihm einen Anker fürs Auge.
     * Die **Skizze** darunter zeigt, was hier erscheinen wird.

   Die Skizze ist bewusst inhaltsleer — graue Balken, keine erfundenen
   Namen. Wer echte Beispieldaten in eine echte Liste stellt, baut sich
   dieselbe Falle wie beim Auftritt („Studio Lumen") und bei der Prüfung:
   es sieht nach Daten aus und ist keine. Ein Umriss lügt nicht, zeigt
   aber trotzdem den Aufbau. */

.leerzustand {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: var(--sp-3xl) var(--sp-l);
  max-width: 46ch;
  margin: 0 auto;
}

.leerzustand .lz-zeichen {
  width: 64px;
  height: 64px;
  border-radius: 50%;
  background: var(--bg-soft);
  display: grid;
  place-items: center;
  color: var(--ink3);
  margin-bottom: var(--sp-l);
}

.leerzustand .lz-zeichen svg { width: 28px; height: 28px; }

.leerzustand h1,
.leerzustand h2 {
  margin: 0 0 var(--sp-s);
  font-size: clamp(20px, 2.6vw, 25px);
  line-height: 1.25;
}

.leerzustand p {
  margin: 0 0 var(--sp-xl);
  color: var(--ink2);
  line-height: 1.65;
  font-size: 15px;
}

.leerzustand .knopf { display: inline-flex; }

/* Die Skizze: was hier stehen wird, als Umriss.
   `aria-hidden` gehört ins Markup — für eine Vorlesesoftware ist sie
   nichts als Rauschen. */
.leerskizze {
  width: 100%;
  max-width: 420px;
  margin: var(--sp-xxl) auto 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-m);
  /* Deutlich zurückgenommen: sie soll den Aufbau andeuten, nicht mit
     dem gelesen werden, was darüber steht. */
  opacity: .4;
  pointer-events: none;
  user-select: none;
}

.leerskizze .lsk-zeile {
  display: flex;
  align-items: center;
  gap: var(--sp-m);
  border: 1px solid var(--line);
  border-radius: var(--r-m);
  padding: var(--sp-m) var(--sp-l);
}

.leerskizze .lsk-kreis {
  flex: none;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: var(--bg-soft);
}

.leerskizze .lsk-bild {
  flex: none;
  width: 44px;
  height: 44px;
  border-radius: var(--r-s);
  background: var(--bg-soft);
}

.leerskizze .lsk-text {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 7px;
}

.leerskizze .lsk-balken {
  height: 9px;
  border-radius: 5px;
  background: var(--bg-soft);
}

.leerskizze .lsk-balken.kurz { width: 45%; }
.leerskizze .lsk-balken.mittel { width: 72%; }

/* Die Skizze verblasst nach unten — sonst sieht die letzte Zeile aus
   wie ein abgeschnittener Inhalt statt wie eine Andeutung. */
.leerskizze .lsk-zeile:nth-child(2) { opacity: .6; }
.leerskizze .lsk-zeile:nth-child(3) { opacity: .3; }

@media (prefers-reduced-motion: no-preference) {
  .leerzustand .lz-zeichen { transition: transform .2s ease; }
}

/* ---------------------------------------------------------------------------
   Rollenwahl
   ---------------------------------------------------------------------------
   Zwei grosse Karten zum Antippen, beide zusammen möglich.

   **Kein Radiofeld.** Ein Paar Radioknöpfe würde bedeuten: entweder —
   oder. Genau das stimmt hier nicht, und viele Anbieter buchen selbst.
   Karten, die sich einzeln an- und abschalten lassen, sagen das ohne
   Erklärung. */

.rollenwahl {
  display: flex;
  flex-direction: column;
  gap: var(--sp-m);
}

.rollenkarte {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-l);
  text-align: left;
  width: 100%;
  padding: var(--sp-l) var(--sp-xl);
  border: 1.5px solid var(--line);
  border-radius: var(--r-l);
  background: var(--bg);
  font: inherit;
  color: var(--ink);
  cursor: pointer;
  transition: border-color .14s ease, background .14s ease;
}

.rollenkarte:hover { border-color: var(--ink3); }

.rollenkarte.an {
  border-color: var(--brand);
  background: var(--brand-soft);
}

.rollenkarte:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
}

.rollenkarte .rk-zeichen {
  flex: none;
  width: 42px;
  height: 42px;
  border-radius: 12px;
  background: var(--bg-soft);
  display: grid;
  place-items: center;
  color: var(--ink2);
}

.rollenkarte.an .rk-zeichen {
  background: var(--brand);
  color: #fff;
}

.rollenkarte .rk-zeichen svg { width: 21px; height: 21px; }

.rollenkarte .rk-text { flex: 1; min-width: 0; }

.rollenkarte .rk-titel {
  display: block;
  font-size: 16.5px;
  font-weight: 700;
  margin-bottom: 3px;
}

.rollenkarte .rk-bei {
  display: block;
  font-size: 14px;
  color: var(--ink2);
  line-height: 1.55;
}

.rollenkarte.an .rk-bei { color: var(--brand-ink); }

/* Der Haken rechts: ein leerer Kreis, bis gewählt ist. Ohne ihn sieht
   man einer angetippten Karte den Zustand nur an der Farbe an — und das
   ist für jemanden mit Farbsehschwäche kein Unterschied. */
.rollenkarte .rk-haken {
  flex: none;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: 1.5px solid var(--line);
  margin-top: 10px;
  position: relative;
}

.rollenkarte.an .rk-haken {
  border-color: var(--brand);
  background: var(--brand);
}

.rollenkarte.an .rk-haken::after {
  content: "";
  position: absolute;
  left: 7px;
  top: 3px;
  width: 5px;
  height: 10px;
  border-right: 2px solid #fff;
  border-bottom: 2px solid #fff;
  transform: rotate(45deg);
}

@media (min-width: 641px) {
  .rollenwahl { gap: var(--sp-l); }
}

/* ---------------------------------------------------------------------------
   Gesperrte Knöpfe
   ---------------------------------------------------------------------------
   Ein `disabled`-Knopf sah aus wie jeder andere: volle Farbe, Zeiger als
   Hand. Man tippt darauf, es passiert nichts, und man hält die Seite für
   kaputt statt zu merken, dass oben noch eine Angabe fehlt.

   Gilt für alle Knöpfe der Webseite, nicht nur für die Rollenwahl —
   dasselbe Muster steckt in jedem Formular mit Pflichtfeld. */

.knopf:disabled,
.knopf[disabled] {
  opacity: .45;
  cursor: not-allowed;
  /* Kein Hover-Wechsel: er würde Reaktion versprechen, wo keine kommt. */
  filter: grayscale(.35);
}

.knopf:disabled:hover,
.knopf[disabled]:hover { background: inherit; }

/* ---------------------------------------------------------------------------
   Einrichtungsstrecke
   ---------------------------------------------------------------------------
   Fortschrittsbalken und Schrittliste für `start.html`. */

.fortschritt {
  height: 6px;
  border-radius: 3px;
  background: var(--bg-soft);
  overflow: hidden;
  margin-bottom: 8px;
}

.fs-fuellung {
  display: block;
  height: 100%;
  border-radius: 3px;
  background: linear-gradient(90deg, var(--brand), var(--herz));
  transition: width .35s ease;
}

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

/* Die Zahl in Worten. Ein Balken allein lässt sich nicht vorlesen, und
   „wie weit bin ich" ist genau die Frage, die diese Seite beantwortet. */
.fs-zahl {
  margin: 0 0 var(--sp-xl);
  font-size: 13px;
  color: var(--ink3);
  font-variant-numeric: tabular-nums;
}

.schrittliste {
  display: flex;
  flex-direction: column;
  gap: var(--sp-m);
}

.schrittkarte {
  display: flex;
  align-items: center;
  gap: var(--sp-l);
  padding: var(--sp-l) var(--sp-xl);
  border: 1px solid var(--line);
  border-radius: var(--r-l);
  background: var(--bg);
}

/* Der erste offene Schritt hebt sich ab. Ohne das sucht man in einer
   Liste aus fünf gleich aussehenden Kästen, wo man weitermacht. */
.schrittkarte.dran {
  border-color: var(--brand);
  box-shadow: 0 0 0 1px var(--brand);
}

.schrittkarte.fertig { background: var(--bg-soft); }

/* Was noch gar nicht geht, tritt zurück — aber es verschwindet nicht.
   Ein Schritt, den man nicht sieht, fehlt später überraschend. */
.schrittkarte.wartet { opacity: .6; }

.schrittkarte .sk-nummer {
  flex: none;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  border: 1.5px solid var(--line);
  display: grid;
  place-items: center;
  font-size: 13.5px;
  font-weight: 700;
  color: var(--ink3);
}

.schrittkarte.dran .sk-nummer {
  border-color: var(--brand);
  background: var(--brand);
  color: #fff;
}

/* Erledigt: Haken statt Ziffer. Die Nummer ist dann uninteressant. */
.schrittkarte.fertig .sk-nummer {
  border-color: var(--ok);
  background: var(--ok);
  position: relative;
}

.schrittkarte.fertig .sk-nummer::after {
  content: "";
  position: absolute;
  left: 11px;
  top: 7px;
  width: 5px;
  height: 10px;
  border-right: 2px solid #fff;
  border-bottom: 2px solid #fff;
  transform: rotate(45deg);
}

.schrittkarte .sk-text { flex: 1; min-width: 0; }

.schrittkarte .sk-titel {
  display: block;
  font-size: 15.5px;
  font-weight: 600;
  margin-bottom: 2px;
}

.schrittkarte .sk-bei {
  display: block;
  font-size: 13.5px;
  color: var(--ink3);
  line-height: 1.5;
}

@media (max-width: 640px) {
  .schrittkarte { flex-wrap: wrap; }
  .schrittkarte .sk-text { flex-basis: calc(100% - 46px); }
  .schrittkarte .knopf { margin-left: 46px; }
}

/* ---------------------------------------------------------------------------
   Kontomenü in der Kopfzeile
   ---------------------------------------------------------------------------
   Vorher stand hier ein Verweis auf die Kontoseite. Zum Abmelden waren
   das vier Handgriffe; die Vorgabe sind zwei von jeder Seite aus. */

.kontomenue { position: relative; }

/* Der Knopf war ein `a`, jetzt ist er ein `button`. Ohne diese drei
   Zeilen bringt er die Vorgaben des Browsers mit und sieht auf jeder
   Plattform anders aus. */
button.konto {
  border: 0;
  background: none;
  font: inherit;
  cursor: pointer;
}

.km-blatt {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  min-width: 232px;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: var(--r-l);
  box-shadow: 0 12px 32px rgb(0 0 0 / .10), 0 2px 6px rgb(0 0 0 / .05);
  padding: 6px;
  z-index: 60;
}

.km-kopf {
  padding: 10px 12px 12px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  border-bottom: 1px solid var(--line);
  margin-bottom: 6px;
}

.km-kopf b { font-size: 14.5px; }

.km-kopf span {
  font-size: 12.5px;
  color: var(--ink3);
  /* Lange Adressen dürfen das Menü nicht breiter machen. */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 210px;
}

.km-zeile {
  display: flex;
  align-items: center;
  /* 44 px Mindesthöhe für den Finger — CLAUDE.md, Frontend-Regeln. */
  min-height: 44px;
  padding: 0 12px;
  border-radius: var(--r-m);
  color: var(--ink);
  text-decoration: none;
  font-size: 14.5px;
  width: 100%;
  border: 0;
  background: none;
  text-align: left;
  font-family: inherit;
  cursor: pointer;
}

.km-zeile:hover { background: var(--bg-soft); }

.km-zeile:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: -2px;
}

.km-trenner {
  height: 1px;
  background: var(--line);
  margin: 6px 8px;
}

/* Abmelden hebt sich ab, ohne zu warnen: es ist die einzige Zeile, die
   den Zustand ändert statt zu navigieren. */
.km-aus { color: var(--err); font-weight: 500; }
.km-aus:hover { background: color-mix(in srgb, var(--err) 8%, transparent); }
.km-aus:disabled { opacity: .5; cursor: default; }

/* Auf dem Telefon von rechts an den Rand, nicht darüber hinaus. */
@media (max-width: 640px) {
  .km-blatt {
    right: -8px;
    min-width: min(260px, calc(100vw - 32px));
  }
}

/* ---------------------------------------------------------------------------
   Katalog
   ---------------------------------------------------------------------------
   Nur für `bausteine.html`. Diese Regeln erscheinen auf keiner Seite,
   die ein Besucher sieht — sie gestalten die Werkstatt, nicht das Haus. */

.kat-nav {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-s);
  padding: var(--sp-l) 0 var(--sp-xxl);
  border-bottom: 1px solid var(--line);
  margin-bottom: var(--sp-xxl);
}

.kat-nav a {
  padding: 7px 14px;
  border-radius: var(--r-pille);
  background: var(--bg-soft);
  color: var(--ink2);
  text-decoration: none;
  font-size: 13.5px;
}

.kat-nav a:hover { background: var(--brand-soft); color: var(--brand-ink); }

.kat-teil { padding-bottom: var(--sp-3xl); scroll-margin-top: 90px; }

.kat-teil > h2 {
  font-size: 21px;
  margin: 0 0 var(--sp-s);
  padding-bottom: var(--sp-s);
  border-bottom: 2px solid var(--ink);
  display: inline-block;
}

.kat-teil > h3 {
  font-size: 15px;
  margin: var(--sp-xxl) 0 var(--sp-m);
  color: var(--ink2);
}

.kat-bei {
  margin: 0 0 var(--sp-l);
  color: var(--ink2);
  font-size: 14px;
  line-height: 1.6;
  max-width: 62ch;
}

/* Die Probe steht auf einem leicht abgesetzten Grund. Auf reinem Weiss
   verschwimmt ein weisser Baustein mit der Seite, und genau dann sieht
   man seinen Rand nicht. */
.kat-probe {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-m);
  padding: var(--sp-xl);
  background: var(--sand);
  border-radius: var(--r-l);
}

/* Der Klassenname darunter — damit man ihn abschreiben kann, statt in
   stil.css zu suchen. */
.kat-code {
  margin: var(--sp-s) 0 0;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12.5px;
  color: var(--ink3);
}

.kat-teil code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.92em;
  background: var(--bg-soft);
  padding: 1px 5px;
  border-radius: 5px;
}

/* ---------------------------------------------------------------------------
   Netzband
   ---------------------------------------------------------------------------
   Der vierte Zustand jeder Ansicht: ohne Netz. Er steht als Band am
   unteren Rand, nicht als Bildschirm — wer im Tunnel das Netz verliert,
   soll weiterlesen können, was schon geladen ist.

   Unten und nicht oben: oben sitzt die Kopfzeile, und ein Band, das sie
   verschiebt, lässt die ganze Seite springen. */

.netzband {
  position: fixed;
  left: 50%;
  bottom: 20px;
  transform: translate(-50%, 12px);
  z-index: 90;
  max-width: min(440px, calc(100vw - 32px));
  padding: 12px 18px;
  border-radius: var(--r-l);
  background: var(--ink);
  color: #fff;
  font-size: 14px;
  line-height: 1.45;
  box-shadow: var(--schatten-stark);
  opacity: 0;
  transition: opacity .22s ease, transform .22s ease;
  pointer-events: none;
}

.netzband.an {
  opacity: 1;
  transform: translate(-50%, 0);
}

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

/* ── Schalter ───────────────────────────────────────────────────
 *
 * EV-021. Für Einstellungen, die **sofort** gelten — nicht für eine
 * Auswahl, die man später abschickt. Genau daran hängt der Unterschied
 * zum Kästchen: ein Kästchen sagt „ich merke mir das für den
 * Absenden-Knopf", ein Schalter sagt „das ist jetzt an".
 *
 * Die Rollenzeilen unter „Konto" sind Schalter: die Änderung geht direkt
 * in die Datenbank, es gibt keinen Knopf darunter. Als Kästchen sahen
 * sie aus, als würde man noch etwas bestätigen müssen.
 *
 * Gebaut auf einer echten Checkbox. Sie bleibt im Baum, nur unsichtbar —
 * damit Tastatur, Sprachausgabe und Formular sich verhalten wie immer.
 * Ein Schalter aus zwei divs mit Klick-Handler ist für eine Sprachausgabe
 * nichts. */
.schalter {
  position: relative;
  flex: none;
  width: 46px;
  height: 28px;
  margin-top: 1px;
}

.schalter input {
  /* Nicht display:none — das nähme ihr den Fokus. */
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}

.schalter .spur {
  display: block;
  width: 100%;
  height: 100%;
  border-radius: var(--r-pille, 999px);
  background: var(--schalter-aus);
  transition: background 0.18s ease;
  pointer-events: none;
}

.schalter .knauf {
  position: absolute;
  top: 3px;
  left: 3px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--auf);
  box-shadow: 0 1px 3px rgba(24, 24, 27, 0.28);
  transition: transform 0.18s ease;
  pointer-events: none;
}

.schalter input:checked ~ .spur { background: var(--brand); }
.schalter input:checked ~ .knauf { transform: translateX(18px); }

/* Der Fokusring gehört um den ganzen Schalter, nicht um die
 * unsichtbare Checkbox — sonst sieht man beim Durchtabben nichts. */
.schalter input:focus-visible ~ .spur {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
}

.schalter input:disabled ~ .spur { opacity: 0.5; }
.schalter input:disabled { cursor: not-allowed; }

/* Eine Zeile mit Schalter rechts. Der Text steht links und trägt die
 * Beschriftung — deshalb umschließt das <label> beides. */
.schaltzeile {
  display: flex;
  align-items: center;
  gap: var(--sp-l);
  padding: var(--sp-m) var(--sp-l);
  border: 1px solid var(--line);
  border-radius: var(--r-m);
  margin-bottom: var(--sp-s);
  cursor: pointer;
}

.schaltzeile:hover { border-color: var(--ink3); }

/* **Kein Farbwechsel im Hintergrund, wenn er an ist.** Anders als bei
 * der Wahlzeile: dort heißt „an" ausgewählt, hier heißt es eingeschaltet.
 * Eine eingefärbte Zeile für jede aktive Einstellung macht eine Liste
 * aus zehn Zeilen unlesbar. Der Schalter selbst zeigt es deutlich genug. */
.schaltzeile .schalttext {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: 14.5px;
}

.schaltzeile .schalttext span { color: var(--ink3); font-size: 13px; }

/* Ein gesperrter Schalter sagt es auch in der Zeile, nicht nur am
 * Knauf: die Beschriftung ist das, was gelesen wird. */
.schaltzeile:has(input:disabled) { cursor: default; opacity: 0.62; }
.schaltzeile:has(input:disabled):hover { border-color: var(--line); }

/* ── Ueberschrift innerhalb einer Schalterliste ─────────────────
 *
 * Neun Schalter am Stueck sind eine Wand. Vier Gruppen mit je zwei bis
 * drei Zeilen liest man; dieselbe Einteilung wie in der App. */
.schaltkopf {
  margin: var(--sp-l) 0 var(--sp-s);
  font-size: 12.5px;
  font-weight: 650;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--ink3);
}
.schaltkopf:first-of-type { margin-top: 0; }

/* Der Hinweis ueber gesperrten Werbeschaltern. Warum sie aus sind,
 * steht damit an ihnen und nicht irgendwo weiter unten. */
.werbesperre {
  margin: 0 0 var(--sp-s);
  padding: var(--sp-m) var(--sp-l);
  border-radius: var(--r-m);
  background: var(--bg-soft);
  color: var(--ink2);
  font-size: 13px;
  line-height: 1.55;
}

/* ── Bewertung schreiben ────────────────────────────────────────
 *
 * Seit dem 18.08. auch im Browser. Bis dahin ging Bewerten nur in der
 * App — und wer am Schreibtisch bucht, konnte danach nichts sagen. */

.sternewahl {
  display: flex;
  align-items: center;
  gap: 2px;
  margin: 0 0 var(--sp-m);
}

.stern {
  background: none;
  border: 0;
  padding: 2px 3px;
  font-size: 26px;
  line-height: 1;
  cursor: pointer;
  color: var(--rahmen-ruhend);
  transition: color 0.12s ease, transform 0.12s ease;
}
.stern.an { color: #e8a53a; }
.stern:hover { transform: scale(1.08); }
.stern:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
  border-radius: 4px;
}

/* Die abgegebene Note wird gezeigt, nicht bedient. */
.sternewahl.fest .stern { cursor: default; padding: 0 1px; font-size: 20px; }
.sternewahl.fest .stern:hover { transform: none; }
.sternezahl {
  margin-left: var(--sp-s);
  font-size: 13px;
  color: var(--ink3);
}

.bewertungsfeld {
  width: 100%;
  padding: var(--sp-m) var(--sp-l);
  border: 1px solid var(--line);
  border-radius: var(--r-m);
  background: var(--auf);
  color: var(--ink);
  font: inherit;
  font-size: 14.5px;
  line-height: 1.6;
  resize: vertical;
  margin-bottom: var(--sp-m);
}
.bewertungsfeld:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 1px;
  border-color: var(--brand);
}

.bewertungshinweis {
  margin: 0 0 var(--sp-m);
  font-size: 13px;
  line-height: 1.55;
  color: var(--ink3);
}

.bewertungstext {
  margin: 0 0 var(--sp-s);
  font-size: 14.5px;
  line-height: 1.65;
  color: var(--ink2);
}

/* Die Antwort des Betriebs gehoert sichtbar zur Bewertung, aber
 * eingerueckt: sie ist die zweite Stimme, nicht die erste. */
.bewertungsantwort {
  margin: 0;
  padding: var(--sp-m) var(--sp-l);
  border-left: 3px solid var(--line);
  font-size: 13.5px;
  line-height: 1.6;
  color: var(--ink3);
}

/* Warum der Betrag nicht mehr wandert. */
.betragfest {
  margin: var(--sp-m) 0 0;
  font-size: 12.5px;
  line-height: 1.6;
  color: var(--ink3);
}

/* Wenn zu einer Buchung kein Betrag gespeichert ist.
 *
 * Sie stillschweigend als 0 mitzuzaehlen waere eine falsche Summe, die
 * richtig aussieht — also steht es da. */
.betragfehlt {
  margin: var(--sp-m) 0 0;
  color: var(--ink3);
  font-size: 13px;
  line-height: 1.55;
}

/* Was nach einem Antrag nach Art. 15 oder 17 DSGVO dasteht. */
.rechtstand {
  margin: var(--sp-m) 0 0;
  padding: var(--sp-m) var(--sp-l);
  border-left: 3px solid var(--brand);
  color: var(--ink2);
  font-size: 13.5px;
  line-height: 1.6;
}

/* ── Zahlenwähler ───────────────────────────────────────────────
 *
 * EV-021. Für Gästezahl und Stückzahl.
 *
 * **Warum nicht das Zahlenfeld allein.** Die Pfeilchen, die der Browser
 * an `type="number"` hängt, sind rund 10 px hoch und auf dem Telefon gar
 * nicht da. Wer die Gästezahl von 80 auf 90 ändern will, muss dort die
 * Tastatur öffnen, markieren, tippen. Mit − und + ist es ein Tipp.
 *
 * Das Feld bleibt trotzdem ein echtes Zahlenfeld: wer 250 eingeben will,
 * tippt 250 und drückt nicht 250-mal auf Plus. */
.zahlwahl {
  display: inline-flex;
  align-items: stretch;
  border: 1px solid var(--line);
  border-radius: var(--r-m);
  overflow: hidden;
  background: var(--auf);
}

.zahlwahl button {
  flex: none;
  width: 44px;
  min-height: 44px;
  border: 0;
  background: transparent;
  color: var(--ink);
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
  transition: background 0.15s ease;
}

.zahlwahl button:hover:not(:disabled) { background: var(--bg-soft); }
.zahlwahl button:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px; }

/* Am Anschlag ausgegraut statt weggeblendet: ein Knopf, der verschwindet,
 * lässt die Leiste springen. */
.zahlwahl button:disabled { color: var(--rahmen-ruhend); cursor: not-allowed; }

.zahlwahl input {
  width: 78px;
  border: 0;
  border-left: 1px solid var(--line);
  border-right: 1px solid var(--line);
  text-align: center;
  font: inherit;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
  background: transparent;
}

.zahlwahl input:focus { outline: 2px solid var(--brand); outline-offset: -2px; }

/* Die Browserpfeilchen weg — sie sind hier doppelt gemoppelt und
 * verengen das Feld. */
.zahlwahl input::-webkit-outer-spin-button,
.zahlwahl input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

.zahlwahl input[type="number"] { -moz-appearance: textfield; appearance: textfield; }

/* ── Gesprächszeile ─────────────────────────────────────────────
 *
 * Die Liste im Nachrichtenbereich. Sie war bis zum 10.08. eine Reihe
 * von `.anfragekarte` — Rahmen, Radius, Abstand darunter, und darin nur
 * Name und Anlass.
 *
 * **Zwei Gründe für eine eigene Klasse.** Erstens ist eine
 * Gesprächszeile keine Anfragekarte: sie trägt ein Bild, eine
 * Vorschauzeile und eine Uhrzeit, und sie steht in einer Liste, die
 * lang wird. Zweitens hängt an `.anfragekarte` die Anfragenseite — dort
 * ist die Karte richtig.
 *
 * Flach statt gerahmt, wie in der App: bei vier Gesprächen sieht eine
 * Reihe von Kästen aufgeräumt aus, bei zwanzig findet man nichts mehr.
 * Der ausgewählte behält einen Hinweis, denn hier steht rechts daneben
 * der Verlauf — ohne Markierung sieht man nicht, wozu er gehört. */
.chatzeile {
  display: flex;
  align-items: center;
  gap: var(--sp-m);
  width: 100%;
  text-align: left;
  padding: var(--sp-m) var(--sp-l);
  border: 0;
  border-radius: var(--r-m);
  background: transparent;
  cursor: pointer;
  font: inherit;
  transition: background 0.15s ease;
}

.chatzeile:hover { background: var(--bg-soft); }

/* Nicht der volle Rahmen wie früher: eine Fläche reicht, um zu zeigen,
   welches Gespräch rechts offen ist. */
.chatzeile.an { background: var(--brand-soft); }

/* Der Kreis trägt sonst dieselbe Farbe wie die ausgewählte Zeile und
   verschwindet darin. Auf Weiß bleibt er sichtbar. */
.chatzeile.an .kreis { background: var(--auf); }

.chatzeile .kreis {
  flex: none;
  width: 52px;
  height: 52px;
  font-size: 15px;
}

.chatzeile .cz-text {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.chatzeile .cz-wer {
  font-size: 14.5px;
  font-weight: 600;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.chatzeile .cz-bei {
  font-size: 13px;
  color: var(--ink3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}


/* ── Ablauf in Schritten ────────────────────────────────────────
 *
 * Steht im leeren Zustand der Anfragenseite, wo vorher eine Skizze der
 * späteren Liste stand.
 *
 * **Warum die Skizze dort weichen musste.** Sie deutet an, wie es
 * aussehen wird — eine gute Antwort auf „ist die Seite kaputt?", aber
 * keine auf die drei Fragen, die jemanden vor der ersten Anfrage
 * bremsen: kostet das was, binde ich mich, wann wird bezahlt. Auf
 * Seiten, die nur warten (Aufträge, Nachrichten), bleibt die Skizze
 * richtig. Hier nicht. */
.ablauf {
  max-width: 640px;
  margin: var(--sp-3xl) auto 0;
}

.ablauf h2 {
  font-size: 19px;
  margin: 0 0 var(--sp-l);
}

.zusicherung {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-m);
  margin-top: var(--sp-xl);
  padding: var(--sp-l);
  border-radius: var(--r-xl);
  background: var(--ok-soft);
  color: var(--ok);
}

.zusicherung .sym { flex: none; font-size: 20px; line-height: 1.2; }
.zusicherung > span { display: flex; flex-direction: column; gap: 2px; }
.zusicherung b { font-size: 15px; }
.zusicherung > span > span { font-size: 14px; }

/* ── Erste Leistung ─────────────────────────────────────────────
 *
 * Die Einladung im leeren Zustand von „Meine Leistungen". Dort stand
 * ein graues Zeichen mit zwei Zeilen — bei einem Marktplatz für
 * Fotografen, Floristen und Locations ist das die falsche Sprache. Hier
 * wird mit Bildern verkauft, und der Bildschirm, der zum ersten Angebot
 * führt, sollte danach aussehen. Gleiche Karte wie in der App. */
.erstekarte {
  max-width: 560px;
  margin: var(--sp-xl) auto 0;
  border: 1px solid var(--line);
  border-radius: var(--r-xl);
  overflow: hidden;
  background: var(--auf);
  box-shadow: var(--schatten);
  text-align: left;
}

.erstekarte .ek-bild {
  display: grid;
  place-items: center;
  height: 132px;
  background: linear-gradient(140deg, var(--platzhalter-hell),
                                      var(--platzhalter-dunkel));
}

.erstekarte .ek-plus {
  display: grid;
  place-items: center;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: var(--auf);
  color: var(--brand);
  font-size: 28px;
  line-height: 1;
}

.erstekarte .ek-text { padding: var(--sp-l); }
.erstekarte .ek-text h3 { margin: 0; font-size: 18px; }
.erstekarte .ek-text p {
  margin: var(--sp-xs) 0 var(--sp-m);
  color: var(--ink2);
  font-size: 14.5px;
}

/* ── Ratkarte ───────────────────────────────────────────────────
 *
 * Ein Rat in der Markenfarbe. **Ohne Zahl:** die Vorlage schlug hier
 * „Anbieter mit mehreren Angeboten erhalten deutlich mehr Anfragen" vor
 * — eine Messung, die Evola nicht hat. Der Rat selbst lässt sich
 * begründen, ohne etwas zu behaupten. */
.ratkarte {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-m);
  max-width: 560px;
  margin: var(--sp-l) auto 0;
  padding: var(--sp-l);
  border-radius: var(--r-xl);
  background: var(--brand-soft);
  color: var(--brand-ink);
  text-align: left;
}

.ratkarte .sym { flex: none; font-size: 20px; line-height: 1.2; }
.ratkarte > span { display: flex; flex-direction: column; gap: 2px; }
.ratkarte b { font-size: 15px; }
.ratkarte > span > span { font-size: 14px; }

/* ── Warnkarte ──────────────────────────────────────────────────
 *
 * Sagt, warum etwas nicht passiert — im Nachrichtenbereich eines
 * Anbieters ohne freigegebene Leistung.
 *
 * **Zwei Farbstände.** Wer noch keine Leistung hat, muss etwas tun:
 * Warnfarbe und ein Knopf. Wer schon wartet, hat alles getan, was er
 * kann — dann Markenfarbe und kein Knopf. Beides warnfarbig zu machen
 * hiesse, jemandem einen Fehler vorzuwerfen, den er nicht gemacht hat. */
.warnkarte {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-m);
  max-width: 560px;
  margin: var(--sp-l) auto 0;
  padding: var(--sp-l);
  border-radius: var(--r-xl);
  background: var(--warn-soft);
  color: var(--warn-ink);
  text-align: left;
}

.warnkarte.wartet { background: var(--brand-soft); color: var(--brand-ink); }

.warnkarte .sym { flex: none; font-size: 20px; line-height: 1.2; }

.warnkarte .wk-text {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
}

.warnkarte b { font-size: 15px; }
.warnkarte .wk-text > span { font-size: 14px; }

/* Der Knopf trägt die Warnfarbe, nicht die Marke: er gehört zur
   Meldung, nicht zur Seite. */
.warnkarte .knopf {
  margin-top: var(--sp-m);
  background: var(--warn-ink);
  border-color: var(--warn-ink);
}

/* ── Einrichtung ────────────────────────────────────────────────
 *
 * Die Fortschrittsliste im leeren Auftragsbereich eines Anbieters.
 * Gleiche Karte wie in der App, nur mit drei Punkten statt vier: den
 * vierten („Arbeitsproben") kann die Webseite nicht messen, weil Bilder
 * an der App hängen. Er steht als Hinweis unter der Liste. */
.einrichtung {
  max-width: 560px;
  margin: var(--sp-xl) auto 0;
  padding: var(--sp-xl);
  border: 1.5px solid var(--brand);
  border-radius: var(--r-xl);
  background: var(--auf);
  text-align: left;
}

.einrichtung .ei-kopf {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-m);
  margin-bottom: var(--sp-s);
}

.einrichtung .ei-kopf b { font-size: 16px; }
.einrichtung .ei-zaehler { color: var(--brand-ink); font-weight: 600; font-size: 15px; }
.einrichtung .ei-bei { margin: var(--sp-s) 0 var(--sp-l); color: var(--ink3); font-size: 13.5px; }

.einrichtung .ei-liste {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-m);
}

.einrichtung .ei-liste li {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-m);
}

.einrichtung .ei-haken {
  flex: none;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: 1.5px solid var(--rahmen-ruhend);
}

/* Erledigtes bleibt stehen und wird durchgestrichen — eine Liste, die
   kürzer wird, nimmt einem das Gefühl, etwas geschafft zu haben. */
.einrichtung .fertig .ei-haken {
  border-color: var(--brand);
  background: var(--brand);
  position: relative;
}

.einrichtung .fertig .ei-haken::after {
  content: "";
  position: absolute;
  left: 7px;
  top: 3px;
  width: 5px;
  height: 10px;
  border: solid #fff;
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}

.einrichtung .ei-text { flex: 1; display: flex; flex-direction: column; gap: 2px; }
.einrichtung .ei-text b { font-size: 15px; }
.einrichtung .ei-text span { color: var(--ink3); font-size: 13px; }
.einrichtung .fertig .ei-text b { color: var(--ink3); text-decoration: line-through; }

.einrichtung .ei-weg { flex: none; font-size: 13.5px; color: var(--brand-ink); font-weight: 600; }

.einrichtung .ei-fuss {
  margin: var(--sp-xl) 0 0;
  padding-top: var(--sp-l);
  border-top: 1px solid var(--line);
  color: var(--ink3);
  font-size: 13.5px;
}

.einrichtung .ei-fuss a { color: var(--brand-ink); font-weight: 600; }

/* ── Titelband über dem Auftritt (16.08.) ─────────────────────────────
 *
 * Gemeldet: „Bei der App Version haben wir hier oben den Banner. Bei
 * der Website Version gibt's das auch, aber bei beiden gibt es nicht
 * den Bereich, wo man's hochlädt." Die Stelle zum Hochladen steht jetzt
 * in der App; hier ist die Fläche, die das Ergebnis zeigt.
 *
 * `aspect-ratio` statt fester Höhe: derselbe Ausschnitt wie in der App
 * (16:9), und auf dem Telefon wird er von allein flacher statt zu
 * überlaufen. `object-fit: cover` fängt Bilder ab, die nicht genau
 * passen — ohne es steht ein Hochkantfoto verzerrt im Band. */
.titelband {
  margin: 0 0 var(--sp-xl);
  border-radius: var(--r-l);
  overflow: hidden;
  background: var(--bg-soft);
  aspect-ratio: 16 / 5;
}

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

/* Auf schmalen Geräten wird das Band höher, sonst bleibt vom Motiv ein
 * Streifen. Dasselbe Verhältnis wie in der App. */
@media (max-width: 720px) {
  .titelband { aspect-ratio: 16 / 9; }
}

/* ── Was der Betrieb über sich schreibt (16.08.) ──────────────────────
 *
 * Bis dahin stand davon auf der Auftrittsseite keine Zeile: der Text
 * war gespeichert und für keinen Besucher zu sehen.
 *
 * `max-width` in Zeichen statt Pixeln: eine Zeile über die ganze Breite
 * eines Bildschirms liest sich schlecht, egal wie breit er ist. */
.ueber-betrieb { padding: 0; margin: var(--sp-xl) 0 0; }

.ueber-betrieb .ueber-kurz {
  margin: 0 0 var(--sp-s);
  font-size: 16px;
  font-weight: 600;
  max-width: 62ch;
}

.ueber-betrieb .ueber-lang {
  margin: 0;
  color: var(--ink2);
  font-size: 15px;
  line-height: 1.65;
  max-width: 62ch;
  white-space: pre-wrap;
}

/* ═══════════════════════════════════════════════════════════════════
 * Der Auftritt eines Betriebs (16.08.)
 *
 * Gemeldet: „hier sieht man den Aufbau der Profilseite, die stimmt
 * nicht mit der App Version überein. Ich hätte gesagt, halte dich an
 * die Webversion vom Instagram-Profil."
 *
 * **Die Vorlage lag schon da.** `studio-lumen.html` ist von Hand nach
 * genau diesem Vorbild gebaut und abgenommen: Ring links, Zahlen in
 * einer Reihe, Kennungszeile, Text, Pillen, Höhepunkte als Kreise,
 * Reiterleiste, Raster. Was fehlte, war, dass der **echte** Auftritt
 * das auch tut — er hatte einen eigenen, ärmeren Aufbau.
 *
 * Deshalb steht hier fast nichts Neues: `.auftritt-kopf`, `.ring`,
 * `.zahlen`, `.kennung`, `.sammlungen`, `.reiter` und `.arbeiten`
 * gibt es alle schon. Ergänzt wird nur, was der echte Auftritt
 * zusätzlich kann — Knöpfe statt Verweise in der Leiste, Clips im
 * Raster, und die Lupe mit Kommentaren.
 * ═══════════════════════════════════════════════════════════════════ */

/* **Schmaler als die Seite.** Instagram begrenzt das Profil auf gut
 * neunhundert Pixel — nicht aus Sparsamkeit: drei Kacheln über 1220 px
 * sind vierhundert Pixel breit, und ein Raster aus solchen Klötzen
 * liest sich nicht mehr als Reihe. */
.auftritt-bahn { max-width: 935px; margin: 0 auto; }

/* Der Kreis mit den Initialen im Ring — für Betriebe ohne Profilbild.
 * `.ring img` gibt es schon; hier steht das Gegenstück. */
.ring .kreis {
  width: 100%; height: 100%;
  border-radius: var(--r-pille);
  display: grid; place-items: center;
  background: var(--bg);
  font-size: 30px;
  font-weight: 700;
  color: var(--brand);
}

/* **Knöpfe in der Reiterleiste.** `.reiter a` gibt es seit
 * `studio-lumen.html`; dort wechseln die Reiter über Anker die Stelle
 * auf der Seite. Hier blenden sie Blätter um — und ein Verweis, der
 * die Seite nicht wechselt, ist für Tastatur und Sprachausgabe eine
 * Lüge. Gleiches Aussehen, andere Bauart. */
.reiter button {
  appearance: none;
  background: none;
  border: 0;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  flex: 0 0 auto;
  white-space: nowrap;
  padding: var(--sp-m) 2px;
  font: inherit;
  font-size: 13px;
  font-weight: 700;
  color: var(--ink3);
  cursor: pointer;
  display: flex; align-items: center; gap: 7px;
}

.reiter button[aria-selected="true"] {
  color: var(--ink);
  border-bottom-color: var(--ink);
}

.reiter button:hover { color: var(--ink); }
.reiter button:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }

/* Ein Blatt der Reiterleiste. Der Abstand nach unten steht hier und
 * nicht an den drei Listen darin: sonst hätte jede ihren eigenen, und
 * beim Wechsel des Reiters spränge die Seite. */
.reiterblatt { padding-bottom: var(--sp-3xl); }
.reiterblatt[hidden] { display: none; }

.blatt-leer {
  margin: var(--sp-3xl) 0;
  text-align: center;
  color: var(--ink3);
  font-size: 15px;
}

/* **Knöpfe im Raster.** `.arbeiten a` gibt es schon — dort führt eine
 * Kachel zu einer Bilddatei. Hier öffnet sie die Lupe, also ist sie
 * ein Knopf. */
.arbeiten button {
  display: block;
  overflow: hidden;
  border-radius: var(--r-s);
  aspect-ratio: 1;
  position: relative;
  padding: 0;
  border: 0;
  background: var(--bg-soft);
  cursor: pointer;
  width: 100%;
}

.arbeiten button img,
.arbeiten button video {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 0.45s ease, filter 0.2s ease;
}

.arbeiten button:hover img,
.arbeiten button:hover video { transform: scale(1.05); filter: brightness(0.94); }
.arbeiten button:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px; }

/* Das Clipzeichen: heller Kreis mit violettem Dreieck, wie in der App
 * seit dem 16.08. Ein dunkler Schleier über dem ganzen Bild macht
 * jedes Foto grau. */
.arbeiten .clipzeichen {
  position: absolute;
  top: 8px; right: 8px;
  width: 22px; height: 22px;
  border-radius: var(--r-pille);
  background: rgba(255, 255, 255, 0.94);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.22);
  display: grid; place-items: center;
  color: var(--brand);
  font-size: 12px;
  pointer-events: none;
}

/* Die Bildunterschrift erscheint beim Darüberfahren. Auf Geräten ohne
 * Zeiger passiert nichts — dort öffnet ein Tipp ohnehin die Lupe. */
.arbeiten .unterschrift {
  position: absolute;
  inset: auto 0 0 0;
  padding: 22px 8px 7px;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.62), transparent);
  color: #fff;
  font-size: 12.5px;
  text-align: left;
  opacity: 0;
  transition: opacity 0.16s ease;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

@media (hover: hover) {
  .arbeiten button:hover .unterschrift { opacity: 1; }
}

/* ── Die Lupe, mit Seitenspalte ────────────────────────────────────
 *
 * **Auf `.lupe` von oben aufgesetzt.** Die gibt es seit der
 * Bildergalerie auf `leistung.html`: dunkler Grund, drei Spalten, das
 * Bild in der Mitte. Hier kommt eine Spalte mit Bildunterschrift und
 * Kommentaren dazu — wie ein Beitrag bei Instagram im Web. Alles
 * andere bleibt, wie es ist. */
.lupe-inhalt {
  grid-column: 2;
  justify-self: stretch;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 340px;
  max-width: 1100px;
  max-height: 86vh;
  width: 100%;
  margin: 0 auto;
  background: var(--bg);
  border-radius: var(--r-l);
  overflow: hidden;
}

@media (max-width: 860px) {
  .lupe-inhalt { grid-template-columns: 1fr; max-height: 92vh; }
}

.lupe-bild {
  background: #000;
  display: grid;
  place-items: center;
  min-height: 0;
}

.lupe-bild img,
.lupe-bild video {
  max-width: 100%;
  max-height: 86vh;
  display: block;
}

.lupe-seite {
  padding: var(--sp-xl);
  overflow-y: auto;
  border-left: 1px solid var(--line);
}

@media (max-width: 860px) {
  .lupe-seite {
    border-left: 0;
    border-top: 1px solid var(--line);
    max-height: 34vh;
  }
}

.lupe-text {
  margin: 0 0 var(--sp-l);
  font-size: 15px;
  line-height: 1.6;
  white-space: pre-wrap;
}

.lupe-kommentare { display: flex; flex-direction: column; gap: var(--sp-m); }

.lupe-kommentar p { margin: 0; font-size: 14px; color: var(--ink2); }

.lupe-leer { color: var(--ink3); font-size: 14px; margin: 0; }

/* ── Mein Profil (17.08.) ─────────────────────────────────────────────
 *
 * Gemeldet: „Viele Funktionen, die wir auf der App haben … hast Du
 * nicht auf der Webseite eingerichtet." Über mich, Titelbild,
 * Highlights und Portfolio gab es nur in der App — wer am Schreibtisch
 * sitzt, konnte sein Profil nicht anfassen. Und genau am Schreibtisch
 * schreibt man einen Vorstellungstext. */

/* Der Satz unter einem Feld: Zeichenzähler, Hinweis zur Eingabe.
 * Kleiner und ruhiger als eine Fehlermeldung — er sagt nichts Schlimmes,
 * er hilft nur. */
.feldhinweis {
  margin: 4px 0 0;
  color: var(--ink3);
  font-size: 13px;
}

/* Die kurze Bestätigung neben einem Knopf. Sie verschwindet wieder:
 * ein Hinweis, der stehen bleibt, sagt beim nächsten Blick nicht mehr,
 * worauf er sich bezieht. */
.gesichert {
  color: var(--ok);
  font-size: 14px;
  font-weight: 600;
}

/* Ein Verweis mitten im Fliesstext. Ohne eigene Regel steht er dort in
 * Textfarbe und sieht nicht aus wie einer — „Ansehen" las sich als Teil
 * des Satzes. */
.weiter {
  color: var(--brand-ink);
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* Der Platzhalter im leeren Titelband. */
.titelband .band-leer {
  margin: 0;
  display: grid;
  place-items: center;
  height: 100%;
  color: var(--ink3);
  font-size: 14.5px;
}

/* ── Verfügbarkeit (17.08.) ───────────────────────────────────────────
 *
 * Aus dem Abgleich App/Webseite: Tage sperren ging nur in der App. Das
 * passiert wöchentlich — wer woanders gebucht ist, nimmt den Tag
 * heraus —, und am Schreibtisch war es gar nicht möglich.
 *
 * **Auf `.kalender` aufgesetzt, nicht danebengestellt.** Die Klasse
 * gibt es seit der Suchzeile; dort schwebt sie als Blatt über dem Feld.
 * Hier steht sie fest auf der Seite. Zwei Blöcke gleichen Namens hätten
 * sich gegenseitig überschrieben. */
.kalender.fest {
  position: static;
  width: auto;
  max-width: 560px;
  box-shadow: none;
}

.kalender.fest .kalendertag { height: 46px; }

/* **Belegt heisst: ein bestätigter Auftrag.** Voll gefüllt, weil der
 * Tag wirklich weg ist — und nicht anklickbar: ihn hier freizugeben
 * hiesse, den Auftrag zu verleugnen. */
.kalendertag.belegt {
  background: var(--brand);
  color: #fff;
  opacity: 1;
}

.kalendertag.belegt:disabled { color: #fff; }

/* Gesperrt heisst: selbst herausgenommen. Gedeckt, nicht laut — es ist
 * eine eigene Entscheidung und kein Ereignis. */
.kalendertag.gesperrt {
  background: var(--bg-soft);
  color: var(--ink3);
  box-shadow: inset 0 0 0 1.5px var(--line);
}

.legende {
  display: flex;
  gap: var(--sp-l);
  flex-wrap: wrap;
  margin: var(--sp-l) 0 var(--sp-s);
  font-size: 13.5px;
  color: var(--ink2);
}

.legende .punkt {
  display: inline-block;
  width: 11px;
  height: 11px;
  border-radius: var(--r-pille);
  margin-right: 6px;
  vertical-align: -1px;
}

.legende .punkt.belegt { background: var(--brand); }
.legende .punkt.gesperrt { background: var(--bg-soft); box-shadow: inset 0 0 0 1.5px var(--line); }
.legende .punkt.frei { background: transparent; box-shadow: inset 0 0 0 1.5px var(--line); }

/* Eine Zeile in der Liste der Sperren: Zeitraum links, Freigeben
 * rechts. */
.sperrzeile {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-m);
  padding: var(--sp-m) 0;
  border-bottom: 1px solid var(--line);
  font-size: 14.5px;
  flex-wrap: wrap;
}

/* Ein Schalter mit Beschriftung darunter. Ohne die zweite Zeile steht
 * „Wochenenden buchbar" allein da, und niemand weiss, ob Samstag und
 * Sonntag beide gemeint sind. */
.schalterzeile {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-m);
  padding: var(--sp-m) 0;
  border-bottom: 1px solid var(--line);
  cursor: pointer;
}

/* `accent-color` färbt das Häkchen des Browsers, ohne es nachzubauen.
 * Ohne diese Zeile steht dort das Systemblau — auf einer Seite, die
 * sonst durchgehend violett ist, sieht das aus wie ein Fremdkörper. */
.schalterzeile input {
  margin-top: 3px;
  flex: none;
  accent-color: var(--brand);
  width: 18px;
  height: 18px;
}
.schalterzeile > span { display: flex; flex-direction: column; gap: 2px; }
.schalterzeile b { font-size: 15px; }
.schalterzeile > span > span { color: var(--ink3); font-size: 13.5px; }

/* ── Übersicht (17.08.) ───────────────────────────────────────────────
 *
 * Die erste Seite, die ein Betrieb öffnet. Aus dem Abgleich
 * App/Webseite: sie gab es nur in der App, und am Schreibtisch landete
 * ein Anbieter direkt in einer Liste. */
.kennzahlen {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: var(--sp-m);
}

.kennzahl {
  padding: var(--sp-l);
  border: 1px solid var(--line);
  border-radius: var(--r-l);
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.kennzahl b {
  font-size: 26px;
  letter-spacing: -0.02em;
  line-height: 1.1;
}

.kennzahl .kz-name { font-size: 14px; font-weight: 600; }

/* **Jede Zahl mit Bezug.** Eine nackte „3" sagt nicht, ob das viel ist
 * oder wovon — dieselbe Regel wie in der App. */
.kennzahl .kz-bezug { font-size: 13px; color: var(--ink3); }
