/* ═══════════════════════════════════════════════════════════════════
   Pojana v2 — Komponenten
   docs/design-spec.md Abschnitt 5.1 Kopf · 5.1a Hauptmenü ·
   5.2 Daumenleiste ·
   5.3 Knopf · 5.4 Auswahlchips · 5.5 Eingabefelder · 5.6 Anfragesatz ·
   5.7 Registereintrag · 5.8 Tafel · 5.9 Zähler · 5.10 Fuß

   Setzt css/base.css voraus (Tokens, Rollen, Skala).
   Seitenspezifisches Raster steht nicht hier, sondern je Seite —
   für die Startseite in css/startseite.css.

   Alles hier steht ohne JavaScript. Die Bewegung aus Abschnitt 6 kommt
   in Schritt 3 und 4 obendrauf und hängt sich an dieselben Klassen; kein
   Zustand, den ein Besucher lesen muss, hängt an einem Skript.
   ═══════════════════════════════════════════════════════════════════ */

/* ── 5.1 Kopf ───────────────────────────────────────────────────────
   Absolut über dem Hero, nicht fixiert: der Hero soll ungeteilt stehen
   und die Leiste beim Weiterscrollen einfach zurückbleiben.
   Links Wortmarke, daneben der Ort (erst ab 75 rem), rechts das
   Hauptmenü und die Telefonnummer als umrandete Pille. Auf Unterseiten
   steht statt des Ortes die Rücknavigation zur Startseite.            */

.kopf {
  position: absolute;
  top: 0; left: 0; right: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  gap: var(--raum-1);
  padding: 1.1rem var(--pad);
}

/* Die Marke ist das Logo B, Querfassung (docs/logo/LOGO-MANUAL.md):
   `dunkel` auf Tintenblau, `hell` auf den Rechtstextseiten. Die Höhe ist
   die der ganzen Datei; eine Versalhöhe (VH) ist knapp die halbe Höhe
   (100 von 200,6 Einheiten). Unter 62 rem steht sie mit 2 rem — über
   den 24 px, ab denen „Pojana" lesbar ist, und so schmal (111 px), dass
   Marke, Nummer und Menüknopf bei 390 px nebeneinander passen. Die
   Unterzeile läuft dort zu; das Manual nimmt das für den Kopf hin.
   Ab 62 rem 3 rem (48 px).

   Unter 370 px ist auch dafür kein Platz: Marke, Menüknopf und die
   ganze Nummer brauchen dort mehr als die Zeile, die Nummer bräche in
   eine zweite Zeile über die Überschrift. Dort steht das Symbol allein
   (<picture> im HTML), wie es das Manual vorsieht, wo kein Platz ist;
   der Name steht auf jeder Seite im Fuß und im Titel. Sein Schutzraum
   ist ein Viertel seiner Höhe.

   Schutzraum 1 VH rundum, gemessen von der sichtbaren Kante: links
   trägt ihn --pad, oben das Kopfpolster und die Mittelung gegen die
   44 px hohe Nummer; rechts hält der Außenabstand ihn frei, denn der
   Abstand im Kopf (--raum-1) allein ist kleiner als 1 VH.
   Die Marke hat keinen eigenen Farbwechsel beim Überfahren: das Logo
   wird nicht umgefärbt (Manual, „Nicht erlaubt"). Den Zustand zeigt
   der Fokusring, und der Zeiger wird ohnehin zur Hand.               */
.kopf__mark {
  --logo-h: 2rem;
  display: block;
  flex: none;
  margin-right: calc(var(--logo-h) / 2 - var(--raum-1));
  text-decoration: none;
}
.kopf__mark picture { display: block; }
.kopf__mark img {
  width: auto;
  height: var(--logo-h);
}
@media (max-width: 23.1rem) {
  .kopf__mark { margin-right: calc(var(--logo-h) / 4 - var(--raum-1)); }
}
@media (min-width: 62rem) {
  .kopf__mark {
    --logo-h: 3rem;
    padding-block: .4rem;
  }
}

/* Ort und Rücknavigation stehen neben der Marke — und Platz dafür gibt
   es erst ab 62 rem (den Ort erst ab 75 rem, siehe unten). Darunter ist
   neben Marke und Nummer keiner: die drei zusammen brauchen 354 px und
   reißen bei 320 px aus dem Bild. Der Weg zur Startseite ist dort die
   Wortmarke selbst, so wie überall. */
.kopf__ort,
.kopf__zurueck { display: none; }
.kopf__ort { margin: 0; font-size: .82rem; color: var(--neben); }
.kopf__zurueck {
  margin: 0 0 0 var(--raum-2);
  font-family: var(--disp);
  font-size: .86rem;
  font-weight: 600;
  font-stretch: 104%;
  white-space: nowrap;
  text-decoration: none;
  text-underline-offset: .25em;
}
.kopf__zurueck:hover { color: var(--signal); text-decoration: underline; }

.kopf__tel {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: .5rem .9rem;
  border: 1px solid var(--rand);
  border-radius: 100px;
  font-family: var(--disp);
  font-size: .92rem;
  font-weight: 600;
  font-stretch: 100%;
  letter-spacing: -.01em;
  text-decoration: none;
  white-space: nowrap;
  transition: background .3s var(--ease), color .3s var(--ease),
              border-color .3s var(--ease);
}
.kopf__tel:hover {
  background: var(--signal);
  border-color: var(--signal);
  color: var(--grund);
}

@media (min-width: 62rem) {
  .kopf__zurueck { display: inline-block; }
}
/* Der Ort erst ab 75 rem. Seit das Hauptmenü mit im Kopf steht, ist bei
   62 rem die Zeile voll: Marke, Ort, drei Wege und die Nummer brauchen
   zusammen 885 px, der Kopf hat bei 992 px aber nur 908 px — das wäre
   ein Umbruch bei einem Fenster, das jemand nur ein Stück zugezogen
   hat. Zwischen 62 und 75 rem tritt deshalb der Ort zurück und das
   Menü nimmt seinen Platz; genannt wird Stephanskirchen auf jeder
   Seite ohnehin im Fuß, auf der Startseite zusätzlich im Hero.       */
@media (min-width: 75rem) {
  .kopf__ort { display: block; margin-left: var(--raum-2); }
}

/* ── 5.1a Hauptmenü (`.menue`) ───────────────────────────────────────
   Drei Wege: Leistungen, Über uns, Kontakt. Die Startseite steht nicht
   in der Liste — dorthin führt auf jeder Seite die Wortmarke, und die
   Rücknavigation daneben sagt es noch einmal.

   Was hier steht, ist der Zustand ohne JavaScript: die drei Links
   liegen offen im Kopf, auf jeder Breite. Unter 62 rem ist neben Marke
   und Nummer keine Zeile mehr frei, also bricht der Kopf um und die
   Links stehen darunter. Das ist keine Notfassung, nur eine zweite
   Zeile.

   Das Vollbild-Menü mit dem Menüknopf gibt es erst mit Skript; es
   steht in css/bewegung.css und hängt dort an `html.js`. Ein Knopf,
   der ein Vollbild öffnen soll und es ohne Skript nicht kann, wird
   deshalb gar nicht gezeigt.                                          */

.kopf { flex-wrap: wrap; }

/* Menüknopf, Schließer, Nummernvorsatz und die Rufzeile gehören
   ausschließlich dem Vollbild. Ohne Skript existiert keines davon. */
.menue__auf,
.menue__zu,
.menue__nr,
.menue__ruf { display: none; }

.menue__liste {
  display: flex;
  flex-wrap: wrap;
  gap: var(--raum-1) var(--raum-2);
  margin: 0;
  padding: 0;
  list-style: none;
}
.menue__liste a {
  font-family: var(--disp);
  font-size: .86rem;
  font-weight: 600;
  font-stretch: 104%;
  white-space: nowrap;
  text-decoration: none;
  text-underline-offset: .25em;
  transition: color .3s var(--ease);
}
.menue__liste a:hover { color: var(--signal); text-decoration: underline; }

/* Die laufende Seite: Farbe und Gewicht, nie Deckkraft — derselbe
   Griff wie beim stehenden Index des Registers (css/bewegung.css).
   Den gleichen Zustand trägt `aria-current="page"` im HTML; die Farbe
   ist nie die einzige Quelle. */
.menue__liste a.is-an {
  color: var(--signal);
  font-weight: 800;
}

/* Das Menü rückt nach rechts und die Nummer schließt die Zeile ab —
   auf jeder Breite dieselbe Folge: Marke, Ort, Wege, Nummer. Kein
   `order` und kein zweiter Quelltext dafür: was die Tastatur
   nacheinander erreicht, muss auch nebeneinander stehen. Die Nummer
   gibt ihren auto-Rand ab, sonst teilten sich zwei auto-Ränder den
   freien Platz und das Menü stünde in der Luft.

   Damit liegt unter 62 rem der Menüknopf links neben der Nummer und
   nicht in der Ecke. Das ist die richtige Reihenfolge: die Nummer ist
   die Handlung, und sie gehört an den Daumen. */
.menue { margin-left: auto; }
.menue ~ .kopf__tel { margin-left: 0; }

/* Ohne Skript nimmt das Menü die zweite Kopfzeile ein — unter 62 rem
   ist neben Marke und Nummer keine Zeile mehr frei. */
@media (max-width: 61.99rem) {
  html:not(.js) .menue { flex-basis: 100%; margin-top: .2rem; }
}

/* ── 5.2 Daumenleiste ───────────────────────────────────────────────
   Nur unter 62 rem, dafür auf jeder Seite — auch auf Impressum und
   Datenschutz. Zwei gleich große Flächen, beide mit dem Daumen
   erreichbar: anrufen oder anfragen, ohne zu scrollen.
   Sie ist bewusst dunkel, auch über der hellen Fassung: ein Balken, der
   über der Seite liegt, nicht ein Teil von ihr.                       */

.daumen { display: none; }

@media (max-width: 61.99rem) {
  :root { --daumen-h: calc(3.5rem + 1px); }

  .daumen {
    position: fixed;
    inset: auto 0 0 0;
    z-index: 90;
    display: grid;
    grid-template-columns: 1fr 1fr;
    background: color-mix(in srgb, var(--ink) 86%, transparent);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    border-top: 1px solid var(--haze);
  }
  .daumen a {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 3.5rem;
    padding: .8rem;
    font-family: var(--disp);
    font-size: .96rem;
    font-weight: 600;
    font-stretch: 100%;
    text-align: center;
    text-decoration: none;
  }
  .daumen__ruf {
    color: var(--cream);
    border-right: 1px solid var(--haze);
  }
  .daumen__form {
    background: var(--aqua);
    color: var(--ink);
  }
  /* Der Fokusring liegt innen, sonst schneidet ihn der Viewportrand ab. */
  .daumen a:focus-visible { outline-offset: -4px; }
}

/* ── 5.3 Knopf ──────────────────────────────────────────────────────
   Pille, zwei Ausprägungen: umrandet und gefüllt. Beim Überfahren fährt
   eine Fläche von links über den Knopf — die Bewegung eines Wischers,
   nicht ein Aufleuchten. 450 ms auf der einen Kurve der Seite.
   Tippfläche nie kleiner als 44 px.
   Ab 62 rem mit feinem Zeiger kommt in Schritt 3 der Magnet dazu; er
   greift an .knopf an, deshalb liegt das transform-Ziel schon hier.    */

.knopf {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 0;
  border: 1px solid var(--rand);
  border-radius: 100px;
  background: transparent;
  color: var(--schrift);
  font: inherit;
  text-align: center;
  text-decoration: none;
  overflow: hidden;
  cursor: pointer;
  transition: border-color .45s var(--ease);
}

.knopf__in {
  position: relative;
  z-index: 2;
  display: block;
  padding: .95rem 1.7rem;
  font-family: var(--disp);
  font-size: .96rem;
  font-weight: 600;
  font-stretch: 100%;
  letter-spacing: -.005em;
  transition: color .35s var(--ease);
}
/* Zweizeilig: Handlung oben, die Nummer darunter — damit man weiß, wen
   man anruft, bevor man tippt. */
.knopf__in b {
  display: block;
  font-weight: 700;
  font-size: 1.12rem;
  letter-spacing: -.02em;
}

.knopf::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: var(--signal);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform .45s var(--ease);
}
.knopf:hover::after { transform: scaleX(1); }
.knopf:hover .knopf__in { color: var(--grund); }
/* Sonst bleibt über der gefüllten Fläche ein heller Ring stehen. */
.knopf:hover { border-color: var(--signal); }

/* Gefüllt: steht schon in --signal, also wischt die Fläche in --schrift
   darüber. Die Schrift bleibt --grund und behält ihre 16,7:1. */
.knopf--voll {
  background: var(--signal);
  border-color: var(--signal);
  color: var(--grund);
}
.knopf--voll::after { background: var(--schrift); }
.knopf--voll:hover .knopf__in { color: var(--grund); }

.knopf--gross .knopf__in { padding: 1.1rem 2.4rem; font-size: 1.08rem; }

/* Gesperrt, solange die Anfrage unterwegs ist: derselbe Knopf, nur
   nicht mehr im Signalton — sonst sähe er aus, als warte er noch auf
   einen Klick. --neben auf --grund sind 7,3:1 (Spec 2); keine
   Halbtransparenz, die Farbe wechselt wirklich. Was gerade passiert,
   steht daneben im Klartext (.blatt__stand). */
.knopf:disabled { cursor: progress; }
.knopf--voll:disabled { background: var(--neben); border-color: var(--neben); }
.knopf--voll:disabled .knopf__in { color: var(--grund); }

/* ── 5.4 Auswahlchips ───────────────────────────────────────────────
   Echte <input type="radio"> in <fieldset>/<legend>. Versteckt werden
   sie über clip-path: inset(50%), nicht über display:none — sonst
   fallen sie aus der Tastaturreihenfolge und das Formular ist nur noch
   mit der Maus bedienbar. Sichtbar ist das <label>.
   Das ist zugleich der Motor des Anfragesatzes (5.6): welche Variante
   dort steht, entscheidet allein der angehakte Radio, ohne Skript.     */

.waehl { display: grid; gap: var(--raum-2); }
.waehl fieldset { margin: 0; padding: 0; border: 0; min-width: 0; }
/* float, damit die legend die volle Breite ihres fieldsets bekommt —
   ein <legend> ist sonst nur so breit wie sein Text und die Chips
   rutschen daneben. */
.waehl legend {
  float: left;
  width: 100%;
  padding: 0 0 .6rem;
  font-family: var(--disp);
  font-size: var(--t-etikett);
  font-weight: 700;
  font-stretch: 104%;
  letter-spacing: .06em;
  color: var(--neben);
}

.chips { clear: both; display: flex; flex-wrap: wrap; gap: .45rem; }
.chips input {
  position: absolute;
  width: 1px; height: 1px;
  margin: 0; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.chips label {
  display: flex;
  align-items: center;
  min-height: 2.75rem;
  padding: .6rem 1.1rem;
  border: 1px solid var(--rand);
  border-radius: 100px;
  font-size: .95rem;
  cursor: pointer;
  transition: background .3s var(--ease), color .3s var(--ease),
              border-color .3s var(--ease);
}
.chips input:checked + label {
  background: var(--signal);
  border-color: var(--signal);
  color: var(--grund);
  font-weight: 600;
}
/* Der Radio selbst ist unsichtbar — der Ring muss also am Label sitzen,
   sonst sieht man beim Tabben nicht, wo man ist. */
.chips input:focus-visible + label {
  outline: 2px solid var(--signal);
  outline-offset: 3px;
}
@media (hover: hover) {
  .chips input:not(:checked) + label:hover {
    border-color: var(--signal);
    color: var(--signal);
  }
}

/* ── 5.5 Eingabefelder ──────────────────────────────────────────────
   Label immer sichtbar darüber, nie nur ein Placeholder: ein Feld, das
   sein Label verliert, sobald man tippt, ist kein Formular, das jemand
   in Ruhe ausfüllt.                                                   */

.feld { margin: 0; }
.feld label {
  display: block;
  margin-bottom: .35rem;
  font-size: .84rem;
  color: var(--neben);
  /* Ein Label, das sein Feld anspringt, ist anklickbar — dann soll der
     Zeiger das auch sagen. */
  cursor: pointer;
}
.feld input,
.feld textarea,
.feld select {
  width: 100%;
  padding: .8rem .9rem;
  min-height: 44px;
  border: 1px solid var(--haze);
  border-radius: 4px;
  background: var(--grund);
  color: var(--schrift);
  font: inherit;
  transition: border-color .25s var(--ease), box-shadow .25s var(--ease);
}
.feld input:hover,
.feld textarea:hover,
.feld select:hover { border-color: color-mix(in srgb, var(--aqua) 45%, transparent); }
.feld input:focus,
.feld textarea:focus,
.feld select:focus {
  outline: none;
  border-color: var(--aqua);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--aqua) 16%, transparent);
}
/* Spec 9 steht über Spec 5.5: der Fokusring wird nie entfernt. Der
   Rahmen mit dem Schein darunter ist der Zustand für den Zeiger — wer
   ins Feld klickt, weiß, wo er ist. Sobald aber die Tastatur führt,
   kommt der Ring aus Abschnitt 9 dazu; der Schein fällt dann weg, sonst
   lägen zwei Ringe ineinander und keiner wäre der deutlichere.
   Die helle Fassung steht mit dabei, weil sonst ihre eigene
   Fokusregel (weiter unten, eine Klasse spezifischer) gewönne und den
   Ring wieder gegen den Schein tauschte.                               */
.feld input:focus-visible,
.feld textarea:focus-visible,
.feld select:focus-visible,
.hell .feld input:focus-visible,
.hell .feld textarea:focus-visible,
.hell .feld select:focus-visible {
  outline: 2px solid var(--signal);
  outline-offset: 3px;
  box-shadow: none;
}
/* Der Systemcursor bleibt in Formularen erhalten (Spec 9). */
.feld input, .feld textarea { cursor: auto; }
.feld textarea { resize: vertical; }
.feld input::placeholder, .feld textarea::placeholder { color: var(--neben); }

/* In der hellen Fassung ist der Rahmen auf --cream sonst unsichtbar. */
.hell .feld input,
.hell .feld textarea,
.hell .feld select { border-color: color-mix(in srgb, var(--ink) 28%, transparent); }
.hell .feld input:focus,
.hell .feld textarea:focus,
.hell .feld select:focus {
  border-color: var(--aqua-d);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--aqua-d) 18%, transparent);
}

@media (min-width: 48rem) {
  .feld--weit { grid-column: 1 / -1; }
  .waehl { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--raum-2) var(--raum-3); }
  /* Name und Kontakt nebeneinander, sobald zwei Felder in eine Zeile
     passen. Steht hier, weil .blatt__wer aus denselben Feldern besteht. */
  .blatt__wer { grid-template-columns: 1fr 1fr; gap: var(--raum-1) var(--raum-2); }
}

/* ── 5.6 Anfragesatz ────────────────────────────────────────────────
   „Ich brauche X für Y, Z." Alle Varianten stehen im HTML; welche
   sichtbar ist, entscheidet :has() über den angehakten Radio aus 5.4.
   Damit ist der Satz ohne eine Zeile JavaScript bedienbar — das Skript
   in Schritt 3 trägt den fertigen Satz nur noch ins Textfeld nach.

   Zwei Fallen beim Nachbauen, beide stehen so in der Spec:
   · Zwischen den Varianten-Spans darf im HTML kein Leerraum stehen
     (</span\n><span …>), sonst bleiben beim Ausblenden Leerzeichen im
     Satz stehen und er hat plötzlich Lücken.
   · Der Marker liegt als background-image im Span selbst mit
     box-decoration-break: clone, nicht als Pseudo-Element — sonst
     bricht er beim Zeilenumbruch ab.                                  */

.satz {
  isolation: isolate;
  margin: 0 0 var(--raum-3);
  max-width: 24ch;
  font-family: var(--disp);
  font-size: var(--t-satz);
  font-weight: 500;
  font-stretch: 92%;
  line-height: 1.24;
  letter-spacing: -.03em;
  color: var(--schrift);
}
/* Satzzeichen rücken an die Variante heran, sonst steht vor Komma und
   Punkt die Lücke des ausgeblendeten Spans. */
.satz__k { margin-left: -.1em; }

.slot > span {
  display: none;
  padding: 0 .12em;
  font-weight: 700;
  color: var(--grund);
  background-image: linear-gradient(var(--signal), var(--signal));
  background-repeat: no-repeat;
  background-position: 0 0;
  background-size: 100% 100%;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
  animation: streichen .3s var(--ease) both;
}
@keyframes streichen {
  from { background-size: 0% 100%; }
  to   { background-size: 100% 100%; }
}

body:has(#a-l1:checked) [data-slot="leistung"] > [data-v="unterhalt"],
body:has(#a-l2:checked) [data-slot="leistung"] > [data-v="treppe"],
body:has(#a-l3:checked) [data-slot="leistung"] > [data-v="fenster"],
body:has(#a-l4:checked) [data-slot="leistung"] > [data-v="sonder"],
body:has(#a-o1:checked) [data-slot="objekt"]   > [data-v="buero"],
body:has(#a-o2:checked) [data-slot="objekt"]   > [data-v="praxis"],
body:has(#a-o3:checked) [data-slot="objekt"]   > [data-v="laden"],
body:has(#a-o4:checked) [data-slot="objekt"]   > [data-v="wohn"],
body:has(#a-o5:checked) [data-slot="objekt"]   > [data-v="privat"],
body:has(#a-t1:checked) [data-slot="takt"]     > [data-v="regel"],
body:has(#a-t2:checked) [data-slot="takt"]     > [data-v="einmal"] { display: inline; }

/* Ohne :has() bleibt die Voreinstellung stehen — ein vollständiger,
   richtiger Satz, nur eben unveränderlich. Die Chips wählen trotzdem
   weiter, und abgeschickt wird, was angehakt ist. */
@supports not selector(:has(*)) {
  .slot > span:first-child { display: inline; }
  .slot > span { animation: none; }
}

/* ── 5.7 Registereintrag ────────────────────────────────────────────
   Fünf Flächen, die wir anfassen. Jeder Eintrag bringt sein eigenes
   Bild mit — kein sticky Bild, über das Text läuft, und kein grauer
   Textstapel.

   Hier steht die Fassung ohne Bewegung: die fünf Einträge laufen
   untereinander, auf breiten Schirmen jeder ganzflächig mit Bild
   randlos an der linken Viewportkante. Schritt 3 legt sie am Desktop
   übereinander und scrubt sie am Pin durch; das ist eine Schicht
   obendrauf und wird dort an .js gehängt, damit ohne Skript weiterhin
   alle fünf lesbar sind (Spec 9: Bewegung ist nie die einzige Quelle
   einer Information).                                                 */

.reg { position: relative; }

.reg__bild {
  position: relative;
  overflow: hidden;
  background: var(--ink);
  aspect-ratio: var(--ar-register);
}
.reg__bild img {
  width: 100%; height: 100%;
  object-fit: cover;
  filter: var(--grade-ruhig);
}
.reg__text { padding: var(--raum-2) var(--pad) 0; }
.reg__name {
  margin: 0 0 .6rem;
  font-size: var(--t-register);
  line-height: .92;
  letter-spacing: -.04em;
}
.reg__zeile { margin: 0; max-width: 34ch; color: var(--neben); }

@media (min-width: 62rem) {
  /* Spec 5.7 nennt 46 % Bildbreite — das gilt für die angepinnte Fassung
     aus Schritt 3, in der rechts noch der stehende Index der fünf
     Flächen steht. Solange der fehlt, stünden drei Zeilen Text in einer
     halben leeren Bildschirmbreite; hier bekommt das Bild deshalb die
     52 %, und der Eintrag eine Spalte statt einer Fläche. */
  .reg {
    --reg-h: clamp(34rem, 84svh, 52rem);
    display: grid;
    grid-template-columns: var(--reg-bild, 52%) minmax(0, 1fr);
    gap: var(--reg-spalt, clamp(2rem, 4vw, 4.5rem));
    align-items: center;
    min-height: var(--reg-h);
  }
  /* aspect-ratio weicht am Desktop der vollen Höhe (Spec 7): das Bild
     läuft randlos an die Viewportkante, der Eintrag steht daneben. */
  .reg__bild { aspect-ratio: auto; height: var(--reg-h); }
  .reg__text { max-width: 36rem; padding: 0 var(--pad) 0 0; }
}

/* Wie die Einträge zueinander liegen, gehört seit der zweiten Seite mit
   Register (Leistungen, Spec 8.2) ebenfalls zum Baustein und nicht mehr
   in eine Seitendatei: die Anordnung ist dieselbe, nur die Inhalte sind
   andere. Die gefahrene Fassung in bewegung.css hängt ohnehin schon an
   .register und nicht an einer Seite. */
.register {
  background: var(--deep);
  /* Bildanteil und Spalt stehen als Variablen, weil die gefahrene
     Fassung in bewegung.css denselben Schnitt noch ein zweites Mal
     braucht: die Fortschrittsspur beginnt an der Innenkante des
     Bildes. Zwei Zahlen, die auseinanderlaufen, wären ein Balken,
     der nicht zur Spalte passt. */
  --reg-bild: 52%;
  --reg-spalt: clamp(2rem, 4vw, 4.5rem);
}
.register__liste {
  list-style: none;
  margin: 0;
  padding: 0 0 var(--luft);
}
.register .reg { padding-bottom: clamp(2.5rem, 7vh, 4rem); }

@media (min-width: 62rem) {
  /* Am Desktop trägt jeder Eintrag seine eigene volle Höhe, der Abstand
     dazwischen wäre ein Loch im Bild. */
  .register__liste { padding: 0; }
  .register .reg { padding-bottom: 0; }
}

/* ── 5.8 Tafel ──────────────────────────────────────────────────────
   Keine Karte mit Rahmen und Icon — das Bild ist die Fläche, der Text
   liegt darauf auf einem Schleier von unten. Genau die Reihe aus
   gleichen Kacheln, die v1 hatte, soll hier nicht entstehen.          */

.karte {
  position: relative;
  flex: 0 0 min(86vw, 27rem);
  height: clamp(24rem, 62vh, 34rem);
  scroll-snap-align: start;
  overflow: hidden;
  background: var(--ink);
}
.karte__bild { position: absolute; inset: 0; overflow: hidden; }
/* Der Schleier trägt den Text. Aus --ink in Transparenz, kein Farbträger. */
.karte__bild::after {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(to top,
    color-mix(in srgb, var(--ink) 95%, transparent) 4%,
    color-mix(in srgb, var(--ink) 55%, transparent) 38%,
    color-mix(in srgb, var(--ink) 12%, transparent) 72%);
}
/* 112 % Breite mit −6 % Versatz: der Spielraum, in dem das Bild in
   Schritt 3 gegen die Fahrtrichtung laufen kann, ohne eine Kante zu
   zeigen. Ohne Skript sieht man davon nichts. */
/* max-width muss hier ausdrücklich zurückgenommen werden: base.css
   deckelt jedes Bild auf 100 % seiner Fläche, und dieser Deckel schlägt
   die 112 %. Solange er galt, stand rechts an jeder Tafel ein nackter
   Streifen Grund — 20 px am Handy, 69 px an der gefahrenen Reihe. */
.karte__bild img {
  width: 112%; height: 100%;
  max-width: none;
  margin-left: -6%;
  object-fit: cover;
  filter: var(--grade-stark);
}
/* Spec 7 nennt --grade-hell ausdrücklich als Hover-Stufe, Spec 10 warnt
   vor animiertem filter auf großen Flächen. Beides zusammen: nur mit
   feinem Zeiger, wo immer nur eine Tafel gleichzeitig läuft. */
@media (hover: hover) and (pointer: fine) {
  .karte__bild img { transition: filter .6s var(--ease); }
  .karte:hover .karte__bild img { filter: var(--grade-hell); }
}
.karte__nr {
  position: relative; z-index: 2;
  margin: var(--raum-2) 1.5rem 0;
}
.karte__h3 {
  position: absolute; z-index: 2;
  left: 1.5rem; right: 1.5rem; bottom: 6.2rem;
  margin: 0;
}
.karte__text {
  position: absolute; z-index: 2;
  left: 1.5rem; right: 1.5rem; bottom: 1.5rem;
  margin: 0;
  font-size: .95rem;
  color: var(--neben);
}

@media (min-width: 62rem) {
  .karte { flex: 0 0 31rem; height: 74vh; }
}

/* ── 5.9 Zähler ─────────────────────────────────────────────────────
   Kasten über dem Bild, nicht mix-blend-mode: auf einem Foto ergibt
   Blending unberechenbare Farben, ein eigener dunkler Grund nicht.
   Die Fortschrittsleiste derselben Komponente kommt mit Schritt 3 —
   ohne Scrub hätte sie nichts anzuzeigen.                             */

.zaehler {
  position: absolute;
  left: 1rem; bottom: .9rem;
  padding: .3rem .75rem .25rem;
  background: color-mix(in srgb, var(--ink) 72%, transparent);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  font-family: var(--disp);
  font-size: .84rem;
  font-stretch: 110%;
  color: var(--mute);
}
.zaehler b {
  font-size: clamp(1.8rem, 5vw, 3rem);
  font-weight: 700;
  letter-spacing: -.05em;
  color: var(--aqua);
}

@media (min-width: 62rem) {
  .zaehler { left: 1.4rem; bottom: 2.4rem; }
}

/* ── Unterseiten-Aufmacher (.auf) ───────────────────────────────────
   Der Einstieg jeder Unterseite (Spec 8): voller Bildschirm, links der
   Satz, rechts das Bild, das randlos an der rechten Viewportkante
   endet. Am Handy erst der Satz, darunter das Bild über die volle
   Breite.

   Stand zuerst in css/leistungen.css. Seit „Über uns" (Spec 8.3)
   tragen ihn zwei Seiten, und css/bewegung.css kennt ihn ohnehin schon
   als Baustein („Aufmacher der Unterseiten") — also gehört er hierher.

   Das Bild hält das feste Verhältnis --ar-breit (16/10, Spec 7) auf
   jeder Breite. Ein neues Foto verschiebt damit nichts — es füllt
   denselben Kasten.                                                   */

.auf {
  position: relative;
  /* Die Daumenleiste liegt fest über der Seite, also gehört ihre Höhe
     nicht zum Bildschirm, den der Aufmacher füllen darf — sonst
     verschwindet die Unterkante des Bildes hinter ihr. Ab 62 rem ist
     --daumen-h null und der Ausdruck wieder 100svh. */
  min-height: calc(100svh - var(--daumen-h));
  display: grid;
  align-content: center;
  gap: var(--raum-3);
  /* oben Platz für den Kopf, der absolut darüber liegt */
  padding: 7rem 0 var(--luft);
}

.auf__satz { padding: 0 var(--pad); }
.auf__vor { margin: 0 0 var(--raum-1); }
.auf__h1 { margin: 0 0 var(--raum-2); }
.auf__lead { margin: 0 0 var(--raum-3); max-width: var(--spalte); }
.auf__tun { display: flex; flex-wrap: wrap; gap: .7rem; }

.auf__bild {
  position: relative;
  aspect-ratio: var(--ar-breit);
  overflow: hidden;
  background: var(--ink);
}
.auf__bild img {
  width: 100%; height: 100%;
  object-fit: cover;
  filter: var(--grade-ruhig);
}

@media (min-width: 62rem) {
  /* Zwei Spalten ohne rechten Rand: das Bild läuft an die Kante. Volle
     Breite ist die Voreinstellung (Spec 4), eine mittige Spalte wäre
     hier nicht zu begründen. */
  .auf {
    grid-template-columns: minmax(0, 1fr) 52%;
    align-items: center;
    gap: clamp(2rem, 4vw, 4rem);
    padding: 8rem 0 var(--luft);
  }
  .auf__satz { padding: 0 0 0 var(--pad); }
  .auf__lead { max-width: 38rem; }
}

/* ── Band (Spec 6.1) ────────────────────────────────────────────────
   Ein Satz, der für sich steht, über einer Messingkante. Auf der
   Startseite sagt er, wer das hier macht; auf „Über uns" (Spec 8.3)
   trägt ihn die H2. Dieselbe Kante, dasselbe wortweise Aufdecken am
   Scroll (css/bewegung.css) — nur der Satz ist ein anderer, deshalb
   steht der Baustein hier und nicht in einer Seitendatei.

   Die Linie liegt ohne Skript sofort da; mit Skript zieht sie sich
   beim Aufdecken mit auf.                                             */

.band {
  position: relative;
  padding: var(--luft) var(--pad);
}
.band__linie {
  position: absolute;
  top: 0; left: var(--pad); right: var(--pad);
  height: 1px;
  background: var(--signal);
}
.band__mehr {
  margin: var(--raum-2) 0 0;
  font-family: var(--disp);
  font-size: .96rem;
  font-weight: 600;
  font-stretch: 104%;
}
.band__mehr a { text-underline-offset: .3em; }
.band__mehr a:hover { color: var(--signal); }

/* ── Kontaktschluss (.schluss) ──────────────────────────────────────
   Wie jede Unterseite endet: kein zweites Formular — das steht auf der
   Kontaktseite — sondern der Weg dorthin und die Nummer, unter der ein
   Mensch rangeht. Die große Nummer in --sun ist die eine Stelle der
   Seite in dieser Farbe (Spec 2).                                     */

.schluss {
  display: grid;
  gap: var(--raum-3);
  padding: var(--luft) var(--pad);
  background: var(--deep);
  border-top: 1px solid var(--haze);
}
.schluss__h2 { margin: 0 0 var(--raum-2); }
.schluss__text { margin: 0 0 var(--raum-3); max-width: var(--spalte); color: var(--neben); }
.schluss__tun { display: flex; flex-wrap: wrap; gap: .7rem; }
.schluss__ruf { border-top: 1px solid var(--haze); padding-top: var(--raum-3); }

@media (min-width: 62rem) {
  .schluss {
    grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr);
    gap: clamp(2.5rem, 6vw, 6rem);
    align-items: center;
  }
  /* Die Kante zwischen Weg und Nummer steht am Desktop senkrecht. */
  .schluss__ruf {
    border-top: 0;
    border-left: 1px solid var(--haze);
    padding: var(--raum-1) 0 var(--raum-1) clamp(2rem, 4vw, 4rem);
  }
}

/* ── Anfragebereich (.anfrage) ──────────────────────────────────────
   Die zweigeteilte Fläche: links der Anfragesatz mit Chips und Formular
   (.blatt), rechts der Weg für die, die lieber sprechen (.ruf). Am
   Desktop zwei Hälften ohne Naht — das Blatt auf --deep, der Rufbereich
   auf --ink; der Farbwechsel ist die Kante und kein Rahmen.

   Stand zuerst in css/startseite.css. Seit der Kontaktseite (Spec 8.4)
   tragen ihn zwei Seiten, und was zwei Seiten tragen, gehört nicht in
   eine Seitendatei. Wo der Bereich auf der Seite liegt — mittendrin wie
   auf der Startseite oder als ganzer Einstieg wie auf der Kontaktseite —
   entscheidet weiterhin die Seite.                                     */

.anfrage {
  display: grid;
  gap: var(--raum-3);
  padding: var(--luft) var(--pad);
  background: var(--deep);
  border-top: 1px solid var(--haze);
}
.anfrage__h2 { margin: 0 0 var(--raum-2); }

/* Der Aufmacher im Blatt — nur die Kontaktseite bringt ihn mit, weil
   der Anfragebereich dort der Einstieg ist und die H1 trägt. Dieselben
   Abstände wie im Unterseiten-Aufmacher. */
.blatt__vor  { margin: 0 0 var(--raum-1); }
.blatt__h1   { margin: 0 0 var(--raum-2); }
.blatt__lead { margin: 0 0 var(--raum-3); max-width: var(--spalte); }

.blatt__wer { display: grid; gap: var(--raum-1); margin: var(--raum-3) 0 var(--raum-2); }
.blatt__hinweis {
  margin: var(--raum-1) 0 0;
  max-width: 42ch;
  font-size: .86rem;
  color: var(--neben);
}
/* Fallenfeld gegen Spam (12.11.2026): aus dem Bild geschoben statt
   display:none, weil manche Bots versteckte Felder auslassen. */
.blatt__falle {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}
.blatt__hinweis a { text-underline-offset: .25em; }
.blatt__hinweis a:hover { color: var(--signal); }

/* ── Rückmeldung des Formulars ──────────────────────────────────────
   Was nach dem Absenden passiert, muss man sehen — und zwar hier, nicht
   auf einer fremden Bestätigungsseite. Solange nichts zu sagen ist, ist
   der Absatz leer und nimmt keinen Platz weg (:empty). Sobald etwas
   drinsteht, steht links die Kante, die auf dieser Seite überall das
   Freigelegte markiert: in --signal, wenn es angekommen ist, in --sun, wenn
   es schiefging. Rot gibt es im Farbsystem nicht (Spec 2), und die
   Aussage trägt ohnehin der Satz — Farbe ist nie die einzige Quelle
   einer Information (Spec 9).                                         */

/* Solange nichts drinsteht, nimmt der Absatz keinen Platz — aber er
   bleibt im Baum. `display: none` wäre hier falsch: ein Live-Bereich,
   den es beim Laden der Seite nicht gibt, meldet bei manchen
   Bildschirmlesern später nichts. */
.blatt__stand:empty { margin: 0; padding: 0; border: 0; }
.blatt__stand {
  margin: var(--raum-2) 0 0;
  max-width: 42ch;
  padding: .85rem 0 .85rem 1rem;
  border-left: 2px solid var(--signal);
  font-size: .98rem;
  line-height: 1.5;
}
.blatt__stand b { font-weight: 600; }
.blatt__stand a { text-underline-offset: .25em; }
.blatt__stand a:hover { color: var(--signal); }
.blatt__stand--fehler { border-left-color: var(--sun); }
/* Während gesendet wird, tritt die Zeile zurück: es ist eine Auskunft
   über den Zwischenstand, keine Nachricht. */
.blatt__stand--laeuft { border-left-color: var(--neben); color: var(--neben); }

/* Gestapelt trennt eine Haarlinie die beiden Hälften; am Desktop tut
   das der Farbwechsel. */
.ruf { border-top: 1px solid var(--haze); padding-top: var(--raum-3); }

@media (min-width: 62rem) {
  .anfrage {
    grid-template-columns: minmax(0, 1.55fr) minmax(0, .9fr);
    gap: 0;
    padding: 0;
    align-items: stretch;
  }
  .blatt {
    padding: clamp(3.5rem, 9vh, 7rem) clamp(2.5rem, 5vw, 6rem)
             clamp(3.5rem, 9vh, 7rem) var(--pad);
  }
  .ruf {
    display: flex;
    flex-direction: column;
    justify-content: center;
    border-top: 0;
    padding: clamp(3.5rem, 9vh, 7rem) var(--pad)
             clamp(3.5rem, 9vh, 7rem) clamp(2.5rem, 5vw, 5rem);
    background: var(--ink);
  }
  .satz { max-width: 22ch; }
}

/* ── Rufblock (Spec 8.4) ────────────────────────────────────────────
   Die große Telefonnummer in --sun, darunter die zweite Nummer, die
   E-Mail und das Einsatzgebiet. Sie steht auf der Startseite, auf jeder
   Unterseite als Kontaktschluss und auf der Kontaktseite als halbe
   Fläche — also hier und nicht in einer Seitendatei. Wie der Block auf
   der Seite liegt, entscheidet weiterhin die Seite.

   --sun erscheint genau einmal je Seite: an dieser Nummer (Spec 2).    */

.ruf__nr {
  display: block;
  font-family: var(--disp);
  font-size: clamp(2rem, 7vw, 3.4rem);
  font-weight: 700;
  font-stretch: 86%;
  line-height: .92;
  letter-spacing: -.04em;
  text-decoration: none;
  color: var(--sun);
  transition: color .3s var(--ease);
}
.ruf__nr:hover { color: var(--cream); }
.ruf__nr--zwei {
  margin-top: .5rem;
  font-size: clamp(1.2rem, 3.4vw, 1.6rem);
  color: var(--cream);
}
.ruf__nr--zwei:hover { color: var(--signal); }
.ruf__mail {
  display: inline-block;
  margin-top: var(--raum-1);
  font-size: .95rem;
  color: var(--neben);
  text-underline-offset: .25em;
}
.ruf__mail:hover { color: var(--signal); }
.ruf__wo {
  margin: var(--raum-3) 0 0;
  padding-top: var(--raum-2);
  border-top: 1px solid var(--haze);
  max-width: 30ch;
  font-size: .95rem;
  color: var(--neben);
}

/* ── 5.10 Fuß ───────────────────────────────────────────────────────
   Der Schriftzug ist echter Text, nicht Dekoration — er steht in
   --wortmarke mit 3,7:1 und wird nie dunkler gesetzt. Deshalb auch das
   feste Gewicht 700 und eine Größe, die nie unter 24 px fällt: erst
   dadurch ist der Wert zulässig.                                      */

.fuss {
  display: grid;
  gap: var(--raum-2);
  padding: clamp(3rem, 9vh, 6rem) var(--pad) var(--luft);
  border-top: 1px solid var(--haze);
}

/* Im Fuß steht das Logo B gestapelt (docs/logo/LOGO-MANUAL.md),
   `dunkel` auf Tintenblau, `hell` auf den Rechtstextseiten. Mindestens
   120 px hoch, darunter ist die Unterzeile im Stapel nicht mehr lesbar.
   Eine Versalhöhe ist hier 0,23 der Dateihöhe; den Schutzraum rundum
   halten Fußpolster, --pad und — nur solange alles gestapelt steht —
   der Außenabstand nach unten, weil --raum-2 allein kleiner ist.    */
.fuss__marke { --logo-h: clamp(7.5rem, 14vw, 12rem); }
.fuss__logo {
  width: auto;
  height: var(--logo-h);
  margin-bottom: max(0px, calc(var(--logo-h) * .23 - var(--raum-2)));
}
.fuss__block { margin: 0; }
.fuss__block p { margin: 0 0 .5rem; font-size: .92rem; color: var(--neben); }
.fuss__block a { text-underline-offset: .25em; }
.fuss__block a:hover { color: var(--signal); }
.fuss__jahr { color: var(--fuss); }

.hell .fuss { border-top-color: color-mix(in srgb, var(--ink) 18%, transparent); }
.hell .fuss__jahr { color: var(--ink); }

/* Anschrift und Links nehmen sich, was sie brauchen, das Logo den
   ganzen Rest (minmax(0, 1fr)) — bei gleich großen fr-Spalten bekäme er
   nur einen Bruchteil und wäre auf dem Tablet kleiner als auf dem Handy.
   minmax(0, …) statt nackter fr, damit keine Spalte an ihrer
   min-content-Breite hängen bleibt und das Raster sprengt.
   grid-auto-flow: column, weil nicht jede Seite gleich viele Blöcke hat:
   die Startseite trägt Anschrift, Seiten und Rechtliches, die
   Rechtstextseiten weniger. Jeder weitere Block macht seine eigene
   Spalte auf, statt dass hier eine feste Zahl steht. */
@media (min-width: 48rem) {
  .fuss {
    grid-template-columns: minmax(0, 1fr);
    grid-auto-flow: column;
    grid-auto-columns: auto;
    gap: var(--raum-3);
    align-items: end;
  }
  .fuss__logo { margin-bottom: 0; }
}

/* ── Die ruhige Fassung ─────────────────────────────────────────────
   Spec 6.5 greift voll erst ab Schritt 3, wenn es Bewegung gibt. Was
   das Fundament schon bewegt, nimmt hier jetzt Rücksicht: Zustände
   wechseln sofort, sie wechseln nur nicht mehr gefahren.               */

@media (prefers-reduced-motion: reduce) {
  .knopf,
  .knopf::after,
  .knopf__in,
  .kopf__tel,
  .chips label,
  .karte__bild img,
  .ruf__nr,
  .feld input, .feld textarea, .feld select {
    transition-duration: 1ms;
  }
  /* Der Marker im Anfragesatz streicht nicht mehr, er liegt sofort da —
     die Auswahl bleibt genauso deutlich zu sehen. */
  .slot > span { animation: none; }
  * { scroll-behavior: auto !important; }
}
