/* ══════════════════════════════════════════════════════════════════════════
   DAS HANDY-SYSTEM DER STARTSEITE (18.08.2026)
   ══════════════════════════════════════════════════════════════════════════

   WAS DAS IST
   Unter 721 px ist index.html ein EIGENES Interface, kein verkleinerter
   Desktop. Die Regel dahinter heißt „LISTE STATT BÜHNE": eine Spalte,
   linksbündig, Haarlinien statt Kästen — Karten nur dort, wo man wirklich
   tippt (Modelle, Portfolio). Der Hero bleibt als einziges zentriert; er
   ist die Eröffnung, keine Liste.

   Dazu, seit dem 18.08. abends, die zweite Regel: „ABTEIL STATT BAHN".
   Jede Sektion ist ein eigener Körper mit Kante, Rundung und Fuge zum
   Nachbarn (Abschnitt 1b) — der Ersatz für den Stationsflug, den es am
   Rechner gibt und auf dem Handy nicht. Vorher lag alles als eine
   einzige dunkle Bahn hintereinander.

   WARUM ÜBERSTIMMEN UND NICHT ERSETZEN
   Die Modul-Blätter (engine/modelle/*.css, anfrage.css, ablauf.css,
   fragen.css, welt.css, stationen.css) werden mit dem Labor GETEILT und
   tragen Struktur, Zustände und FLIP-Logik. Sie umzubauen bräche
   labor/hero-vanilla3.html und labor/hero-vanilla4.html; sie zu ersetzen
   hieße, funktionierendes Verhalten neu zu schreiben. Dieses Blatt liegt
   deshalb als LETZTES im <head> und ändert nur Aussehen und Maße — und
   nur innerhalb seiner einen Media Query. Klasse weg = alter Zustand.

   DIE SPEZIFITÄTS-REGEL: `:root` STATT `!important`
   Eine Media Query erhöht keine Spezifität. premium.css schreibt
   `.modelle.premium .mk-name` (0,2,1) — ein blankes `.mk-name` (0,1,0)
   verlöre. Jede Regel hier trägt deshalb `:root ` als Präfix; das ist
   dasselbe Element wie `html`, kostet aber eine Klassenstufe und hängt —
   anders als `html.kompakt` — an KEINEM Skript. `:root .modelle .mk-name`
   ist (0,3,1) und gewinnt ohne ein einziges `!important`.
   Ausnahme siehe unten bei `.ab-mehr` — dort steht `!important` in der
   Quelle, und nur dagegen steht hier eines.

   DER VERTRAG — welche fremden Klassen dieses Blatt kennt
     Abteile   main > [data-station] — das Attribut trägt die Abteile
               (Abschnitt 1b) und ist zugleich das, woran engine/
               stationen/ die Stationen findet. Fällt es an einer Sektion
               weg, verliert sie hier ihren Körper und drüben ihren Platz.
     Kopf      .kopf · .kopf-glas(.offen) · #kopfSchalter · .kopf-liste ·
               .kopf-punkt · .kopf-lang · .hero-ecke · .sozial
               Dazu die eigene Klasse `kopf-fort` am <html> (mobil.mjs
               6b): die Pille fährt beim Lesen aus dem Bild.
     Modelle   .modelle(.ist-offen) · .mo-kopf/.mo-kicker/.mo-hinweis/
               .mo-unsicher/.mo-ust · .mo-buehne · .mo-reihe ·
               (.mo-blaettern/.mo-pfeil/.mo-strich baut mobil.mjs 6d —
               sie stehen in keinem Markup) ·
               .mk-platz(.ist-auf) · .mk · .mk-rand · .mk-badge · .mk-zu ·
               .mk-spalte · .mk-schau/.mk-koerper · .mk-name · .mk-verspr ·
               .mk-fuer · .mk-anlass · .mk-preis(b, .mk-zahl, .mk-waehrung,
               .mk-ab, i) · .mk-strich · .mk-dauer · .mk-passt · .mk-more ·
               .mk-mehr · .mk-fuss · .mk-cta · .mk-nachbar
     Ablauf    .ablauf · .ab-kopf/.ab-kicker/.ab-sub · .ab-buehne ·
               .ab-reihe · .ab-schritt · .ab-platz · .ab-text · .ab-nr ·
               .ab-fuss
     Anfrage   .anfrage · .an-raster · .an-links · .an-kicker/.an-sub ·
               .an-strich · .an-wege/.an-weg/.an-weg-t/.an-weg-still ·
               .an-versprechen · .an-paneel · .an-schritte/.an-schritt ·
               .an-stand (.an-vitrine, .an-stand-nr/-name/-preis/-fit) ·
               .an-lauf · .an-frage · .an-kacheln/.an-wahl/.an-wahl-nr ·
               .an-zelle/.an-info-knopf · .an-extra · .an-felder/.an-feld ·
               .an-nav/.an-zurueck · .an-fuss-note
               ACHTUNG: `.an-links` steht hier auf `display: contents`
               und die Kinder werden per `order` sortiert (Abschnitt 6).
               Kommt im Markup ein Kind dazu, bekommt es keine Ordnung
               und landet vor allem anderen.
     Portfolio .portfolio · .pf-welt · .pf-kopf/.pf-kicker · .pf-textplatz ·
               .pf-raum/.pf-faecher/.pf-karte/.pf-innen
               .pf-klapp/.pf-klapp-t/.pf-klapp-z und die Klasse `pf-zu`
               baut mobil.mjs (6c) — sie stehen in keinem Markup.
     Fragen    .fragen · .fq-raum · .fq-platz · .fq-liste · .fq-frage ·
               .fq-knopf/.fq-nr/.fq-text/.fq-zeichen · .fq-antwort
     Fußzeile  .fuss · .fuss-glas · .fuss-logo · .fuss-gruppe · .fuss-klein
   Ändert eines dieser Module seine Klassennamen, fällt hier eine Regel
   lautlos aus. Das ist der Preis des Überstimmens — dafür bleibt drüben
   alles unangetastet.

   WAS BEWUSST NICHT GEÄNDERT WURDE
     · Das CIRCUIT-NETZ. Es wird auf dem Handy gar nicht mehr geladen
       — die Entscheidung fällt in index.html beim Start des Moduls,
       nicht hier. Eine CSS-Regel hätte den WebGL-Pass nur unsichtbar
       gemacht, nicht gespart.
     · Der HERO. Titel, Unterzeile, Knöpfe und das Laufband haben ihre
       eigene Handy-Fassung in index.html (620-/420-px-Blöcke, einzeilig
       nach Jordans Ansage). Der Überstand des Laufbands ist gewollt.
     · Alle TEXTE, `data-value` und Modellnamen — der Wizard ist ein
       Vertrag mit content-server.mjs (CLAUDE.md).
     · Die MECHANIK: kein Modul-JS wird umgebogen. engine/mobil/mobil.mjs
       ergänzt nur, was CSS nicht kann (Scroll-Sperre, Menü schließen,
       Fragezeichen-Wesen gar nicht erst laden).
     · Der STATIONSMODUS (≥ 961 px) und alles unter `html.stationen`.

   MESSEN
     node tools/screenshot.mjs http://localhost:8081/ 390 844 x.png voll
     (mit DURCHROLLEN=1; KLICK='#kopfSchalter' bzw. KLICK='.mk[data-i="2"]')
   ────────────────────────────────────────────────────────────────────── */

/* Der Scroll-Hinweis des Heros existiert nur auf dem Handy — am Rechner
   ist der Hero eine Station mit eigener Regie. Diese eine Regel steht
   deshalb AUSSERHALB der Media Query. */
.hero-scroll { display: none; }

@media (max-width: 720px) {

  /* ══ 1 · DAS RASTER ═══════════════════════════════════════════════════
     Ein Abstandsraster für die ganze Seite: 8 · 16 · 24 · 40 · 64.
     Alles, was hier eine Zahl bekommt, bekommt eine aus dieser Reihe.
     Der Abstand ÜBER einer Überschrift ist immer größer als der darunter
     — sonst gehört die Überschrift optisch zum Vorherigen. */
  :root {
    --m-rand:   24px;   /* Seitenrand der Seite                           */
    --m-sekt:   52px;   /* padding-block jeder Sektion                    */
    --m-kopf:   40px;   /* Sektionskopf → erster Inhalt                   */
    --m-zeile:  16px;   /* Abstand zwischen Listenzeilen                  */
    --m-blatt:  40;     /* z-index der Blätter (Menü, Modell) — Kopf ist 20 */
    /* Die Abteile (siehe 1b): Außenrand, Fuge, und der Innenrand, der
       sich daraus ergibt — Text steht weiter 24 px vom Fensterrand. */
    --m-abt:    10px;
    --m-fuge:   26px;
    --m-innen:  calc(var(--m-rand) - var(--m-abt));
    /* Wo ein Ankerlink landet. Die Kopf-Pille steht zwischen 20 und
       78 px; 88 px lassen ihre Unterkante frei, damit ein Sprung ins
       Menü nicht hinter dem Menü endet. Sie fährt beim Weiterlesen zwar
       weg (mobil.mjs 6b) — aber im Moment der Ankunft steht sie noch. */
    --m-anker:  88px;
  }

  /* Tippen: gilt für ALLES Klickbare, auch für das, was die Module
     selbst bauen. Doppeltipp-Zoom aus, Browser-Blau durch die eigene
     Farbe ersetzt. */
  :root a, :root button, :root [role="button"], :root summary,
  :root input, :root select, :root textarea {
    touch-action: manipulation;
    -webkit-tap-highlight-color: rgba(255, 255, 255, .1);
  }

  /* ══ 1b · DIE ABTEILE ═════════════════════════════════════════════════
     Am Rechner ist jede Sektion eine STATION: die Kamera fliegt hin, die
     vorige tritt ab, und dass man den Ort gewechselt hat, sagt die
     Bewegung. Auf dem Handy gibt es diesen Flug nicht — dort lagen die
     sechs Sektionen bis zum 18.08. abends als eine einzige dunkle Bahn
     hintereinander, getrennt nur durch Luft. Jordans Befund: „alles
     sieht aus wie eine Seite".

     Also bekommt jede Sektion einen KÖRPER: eine eigene Fläche, 10 px
     vom Fensterrand eingerückt, mit Kante, Rundung und einer Lichtnaht
     an der Oberkante. Zwischen zwei Abteilen bleibt eine Fuge offen, in
     der der lebende Grund (Circuit-Netz + Lichter) unverdeckt
     durchscheint — Kammer, Fuge, Kammer. Das ist dieselbe Erzählung wie
     am Rechner, nur in Material statt in Bewegung: Module, die auf der
     Platine sitzen.

     ── DIE DREI DINGE, DIE HIER NICHT PASSIEREN DÜRFEN ──
     1. KEIN `transform`, `filter`, `backdrop-filter`, `perspective`,
        `contain: paint` und kein `will-change` auf der Sektion. Jede
        dieser Eigenschaften macht sie zum Bezugsrahmen für `fixed` —
        und das offene Modell-Blatt (`.mk-platz.ist-auf .mk`, weiter
        unten) ist genau das. Es klebte dann an der Sektion statt am
        Fenster. Background, Rand und Schatten sind frei.
     2. KEIN `overflow: hidden/clip`. Aus demselben Grund (es
        beschnitte das Blatt), und weil der Portfolio-Monitor
        darüberliegt.
     3. `--m-rand` bleibt bei 24 px. Der Innenrand der Abteile ist eine
        EIGENE Variable (`--m-innen`), denn `--m-rand` benutzen auch die
        fensterbreiten fixed-Teile des Modell-Blatts; die würden sonst
        mit einrücken.

     Die Fläche ist absichtlich halbdurchlässig: der Himmel ist hinter
     dem Abteil gedämpft und in der Fuge voll da. Genau dieser
     Helligkeitswechsel macht den Rhythmus — eine deckende Fläche wäre
     ein Kasten, keine Kammer. */
  :root main > [data-station]:not(.buehne) {
    position: relative;
    margin: var(--m-fuge) var(--m-abt) 0;
    /* Ankerlinks landen unter der Kopf-Pille, nicht hinter ihr. Das galt
       vorher je Sektion einzeln (0 bei den Modellen, 16 px bei Anfrage
       und Portfolio) und stimmte an keiner Stelle: die Pille ist 78 px
       hoch. */
    scroll-margin-top: var(--m-anker);
    border: 1px solid rgba(255, 255, 255, .075);
    /* Die Oberkante fängt das Licht — sie ist die Kante, die man beim
       Hereinrollen zuerst sieht, und trägt die Trennung über die ganze
       Breite. Die Naht darunter setzt nur den Glanzpunkt. */
    border-top-color: rgba(255, 255, 255, .15);
    border-radius: 28px;
    /* Zwei Lagen: oben ein weicher Lichtabfall — das Deckenlicht des
       Abteils, das unter der Naht hereinfällt und nach 140 px weg ist
       — darüber die eigentliche, halbdurchlässige Fläche. */
    background:
      linear-gradient(180deg, rgba(255, 255, 255, .055) 0, rgba(255, 255, 255, 0) 140px),
      linear-gradient(180deg,
        rgba(26, 28, 35, .62) 0%,
        rgba(12, 13, 17, .52) 26%,
        rgba(12, 13, 17, .52) 74%,
        rgba(6, 6, 9, .64) 100%);
    box-shadow: 0 22px 46px -30px rgba(0, 0, 0, .95);
  }
  /* Das letzte Abteil braucht unten dieselbe Fuge wie oben, sonst
     schließt die Seite bündig mit der Fußzeile ab. */
  :root main > [data-station]:last-child { margin-bottom: var(--m-fuge); }

  /* Die Lichtnaht: eine Haarlinie auf der Oberkante, in der Mitte hell,
     zu den Seiten aus. Sie sitzt auf dem Rand (`top: -1px`) und ist das
     einzige Ornament des Abteils — sie sagt „hier beginnt etwas Neues"
     und spricht die Sprache der Leiterbahnen darunter. */
  :root main > [data-station]:not(.buehne)::before {
    content: '';
    position: absolute;
    top: -1px;
    left: 26px; right: 26px;
    height: 1px;
    border-radius: 1px;
    background: linear-gradient(90deg,
      transparent,
      rgba(226, 232, 240, .30) 18%,
      rgba(255, 255, 255, .95) 42%,
      rgba(255, 255, 255, .95) 58%,
      rgba(226, 232, 240, .30) 82%,
      transparent);
    pointer-events: none;
  }

  /* Ein Sektionskopf, fünf Mal derselbe. Die Bausteine heißen in jedem
     Modul anders — die Gestalt ist dieselbe: Kicker (Space Mono),
     Überschrift (Clash Display), eine Zeile Erklärung.

     JEDE Zeile trägt zusätzlich ihre Sektionsklasse. Nicht der Ordnung
     halber: premium.css schreibt `.modelle.premium .mo-kopf h2` (0,2,2),
     und ein `:root .mo-kopf h2` (0,2,1) verliert. Gemessen am 18.08. —
     der Leitsatz stand danach immer noch in gesperrten Versalien. */
  :root .modelle .mo-kicker,
  :root .ablauf  .ab-kicker,
  :root .anfrage .an-kicker,
  :root .pf-welt .pf-kicker {
    display: block;
    margin: 0 0 16px;
    padding: 0;
    font: 400 .68rem/1.2 'Space Mono', ui-monospace, monospace;
    letter-spacing: .22em;
    text-indent: 0;
    text-transform: uppercase;
    color: var(--ink-dim);
    opacity: 1;
  }
  /* Die Zierlinien der Kicker sind Bühne, nicht Information. */
  :root .modelle .mo-kicker::before, :root .modelle .mo-kicker::after,
  :root .ablauf  .ab-kicker::before, :root .ablauf  .ab-kicker::after,
  :root .anfrage .an-kicker::after,  :root .pf-welt .pf-kicker::after { display: none; }

  :root .modelle .mo-kopf h2,
  :root .ablauf  .ab-kopf h2,
  :root .anfrage .an-links h2,
  :root .pf-welt .pf-kopf h2 {
    margin: 0;
    font-family: 'Clash Display', 'Space Grotesk', sans-serif;
    font-weight: 400;
    font-size: clamp(1.9rem, 8vw, 2.3rem);
    line-height: 1.05;
    letter-spacing: -.022em;
    text-align: left;
    text-wrap: balance;
    color: var(--ink);
  }
  :root .modelle .mo-hinweis {
    max-width: none;
    margin: 16px 0 0;
    font-size: .95rem;
    line-height: 1.5;
    letter-spacing: 0;
    text-transform: none;
    color: var(--ink-dim);
    opacity: 1;
    text-align: left;
  }

  /* DIE ZWEI ERKLÄRZEILEN UNTER DER ÜBERSCHRIFT SIND WEG (18.08. abends,
     Jordan). Am Rechner stehen sie neben viel Luft und tragen den Ton;
     auf 390 px stehen sie zwischen der Überschrift und dem, was man tun
     will, und kosten drei Zeilen und eine halbe Wischbewegung. Was sie
     sagen, sagt die Sektion ohnehin: „In drei Schritten online" hat
     darunter die drei Schritte, und der Wizard beginnt mit „Was
     brauchst du?" — kostenlos und unverbindlich steht an seinem Fuß.

     `display: none` und nicht gelöscht: der Wortlaut gehört zum
     Rechner, index.html bleibt eine Quelle für beide (und en/index.html
     wird daraus erzeugt). */
  :root .ablauf .ab-sub,
  :root .anfrage .an-sub { display: none; }

  /* ══ 2 · DER KOPF UND SEIN MENÜ-BLATT ═════════════════════════════════
     Der Kopf ist auf dem Handy von Anfang an die kompakte Pille links
     (`html.kompakt`, gesetzt vor dem ersten Bild). Aus dem kleinen,
     halbdurchsichtigen Dropdown wird hier ein BLATT: deckend, über die
     ganze Breite, Einträge von 56 px.

     Warum `position: absolute` und nicht `fixed`: `.kopf-glas` trägt
     `backdrop-filter`, und ein Element mit Backdrop-Filter ist
     Bezugsrahmen auch für `fixed` — ein `left: 0; right: 0` läge dann an
     der Pille an, nicht am Fenster. Also absolut, und die Strecke zum
     linken Fensterrand als negatives `left` (dieselbe Zahl, mit der der
     Kopf in der Ecke sitzt). */
  :root .kopf { max-width: none; }

  :root.kompakt .kopf-liste {
    left: calc(-1 * max(var(--kopf-rand), env(safe-area-inset-left)));
    width: 100vw;
    min-width: 0;
    top: calc(100% + 8px);
    padding: 8px 0 8px;
    /* Deckend: das Blatt liegt über Karten und Wizard, und der Blur
       allein hat das am 16.08. schon einmal nicht gerichtet. */
    background: rgb(11, 11, 14);
    -webkit-backdrop-filter: blur(18px) saturate(1.4);
            backdrop-filter: blur(18px) saturate(1.4);
    border: 0;
    border-bottom: 1px solid var(--linie);
    border-radius: 0 0 22px 22px;
    box-shadow: 0 26px 60px -20px rgba(3, 3, 5, .8);
    /* EIN Bewegungsmoment: das Blatt gleitet herunter. Kein Skalieren,
       kein zweiter Effekt an den Einträgen. */
    transform-origin: top center;
    scale: 1;
    translate: 0 -8px;
    transition: opacity .28s var(--ease), translate .28s var(--ease);
    /* Wird das Blatt einmal länger als das Fenster (mehr Punkte), rollt
       es in sich statt die Seite mitzunehmen. */
    max-height: calc(100dvh - 96px);
    overflow-y: auto;
    overscroll-behavior: contain;
  }
  :root.kompakt .kopf-glas.offen .kopf-liste { translate: 0 0; scale: 1; }
  /* Reflex und Specular-Bogen des Blatts sind Deko auf einer deckenden
     Fläche — auf dem Handy trägt Glas nur der Kopf selbst. */
  :root.kompakt .kopf-liste::before,
  :root.kompakt .kopf-liste::after { display: none; }

  :root.kompakt .kopf-liste .kopf-punkt {
    position: relative;
    min-height: 56px;
    padding: 0 20px 0 24px;
    border: 0;
    border-radius: 0;
    justify-content: flex-start;
    font: 500 1.05rem/1.2 'Space Grotesk', sans-serif;
    letter-spacing: 0;
    text-transform: none;
    color: var(--ink);
  }
  /* Haarlinie zwischen den Einträgen — nicht vor dem ersten.
     Als BORDER, nicht als ::before: der Sprachpunkt weiter unten braucht
     sein ::before für die Flagge, und beide säßen sonst auf demselben
     Pseudo-Element. (Genau das ist am 18.08. passiert — die Flagge fehlte
     wortlos, weil die Trennlinie sie überschrieb.) */
  :root.kompakt .kopf-liste .kopf-punkt + .kopf-punkt {
    border-top: 1px solid var(--linie);
  }
  /* Der Chevron rechts: zwei Haarlinien, wie der Pfeil am Schalter —
     kein Zeichen aus der Schrift (sitzt je Schnitt anders auf der
     Grundlinie). */
  :root.kompakt .kopf-liste .kopf-punkt::after {
    content: '';
    position: absolute;
    top: 50%; right: 22px;
    width: 7px; height: 7px;
    border-top: 1.5px solid var(--ink-dim);
    border-right: 1.5px solid var(--ink-dim);
    rotate: 45deg;
    translate: 0 -50%;
    opacity: .7;
  }
  @media (hover: hover) {
    :root.kompakt .kopf-liste .kopf-punkt:hover { background: rgba(255, 255, 255, .05); }
  }
  :root.kompakt .kopf-liste .kopf-punkt:active { background: rgba(255, 255, 255, .07); }

  /* ── Der Sprachpunkt ───────────────────────────────────────────────
     Er ist kein siebter Weg, sondern ein Schalter: abgesetzt durch 16 px
     mehr Luft und eine Trennlinie, davor die Flagge des ZIELS.

     Das sichtbare Kürzel („EN" bzw. „DE") wird auf font-size 0 gesetzt
     und durch das ganze Wort ersetzt — bei 56 px Zeilenhöhe ist ein
     Zwei-Buchstaben-Kürzel neben einer Flagge kein Ziel, das man
     erkennt. Der Name für Vorleser hängt am `aria-label` des Links
     („English version" / „Deutsche Fassung") und bleibt unberührt;
     `hreflang`, `lang` und `rel` fasst hier nichts an.

     Die Fahne ist ein Inline-SVG als data:-URI — kein Bild, keine
     zusätzliche Anfrage. Das `#` der Clip-Path-Referenz MUSS `%23`
     heißen, sonst schneidet der Browser die URL dort ab. */
  :root.kompakt .kopf-liste .kopf-lang {
    margin-top: 16px;
    padding-left: 24px;
    border-left: 0;
    border-top: 1px solid var(--linie);
    border-radius: 0;
    opacity: 1;
    gap: 12px;
    font-size: 0;
    letter-spacing: 0;
  }
  :root.kompakt .kopf-liste .kopf-lang::after {
    font: 500 1.05rem/1.2 'Space Grotesk', sans-serif;
    letter-spacing: 0;
    text-transform: none;
    color: var(--ink);
    /* Der Chevron des Nachbarn gilt hier nicht — dieser Punkt verlässt
       die Seite, er führt nicht in sie hinein. */
    position: static;
    width: auto; height: auto;
    border: 0;
    rotate: none;
    translate: none;
    opacity: 1;
  }
  :root.kompakt .kopf-liste .kopf-lang[lang="en"]::after { content: 'English'; }
  :root.kompakt .kopf-liste .kopf-lang[lang="de"]::after { content: 'Deutsch'; }

  :root.kompakt .kopf-liste .kopf-lang::before {
    content: '';
    display: block;
    flex: none;
    width: 22px; height: 15px;
    border-radius: 3px;
    border: 1px solid var(--linie-hell);
    background-size: cover;
    background-position: center;
  }
  /* Union Jack */
  :root.kompakt .kopf-liste .kopf-lang[lang="en"]::before {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 60 30'%3E%3CclipPath id='t'%3E%3Cpath d='M30,15 h30 v15 z v15 h-30 z h-30 v-15 z v-15 h30 z'/%3E%3C/clipPath%3E%3Cpath d='M0,0 v30 h60 v-30 z' fill='%23012169'/%3E%3Cpath d='M0,0 L60,30 M60,0 L0,30' stroke='%23fff' stroke-width='6'/%3E%3Cpath d='M0,0 L60,30 M60,0 L0,30' clip-path='url(%23t)' stroke='%23c8102e' stroke-width='4'/%3E%3Cpath d='M30,0 v30 M0,15 h60' stroke='%23fff' stroke-width='10'/%3E%3Cpath d='M30,0 v30 M0,15 h60' stroke='%23c8102e' stroke-width='6'/%3E%3C/svg%3E");
  }
  /* Schwarz-Rot-Gold braucht kein SVG — drei Balken sind ein Verlauf. */
  :root.kompakt .kopf-liste .kopf-lang[lang="de"]::before {
    background-image: linear-gradient(180deg,
      #000000 0 33.34%, #dd0000 33.34% 66.67%, #ffce00 66.67% 100%);
  }

  /* Der Schalter selbst: 44 px sind Pflicht, 48 sind angenehm. */
  :root.kompakt .kopf-schalter { min-height: 48px; }

  /* ── Die Pille fährt beim Lesen weg (18.08. abends) ────────────────
     `.kopf` ist `fixed` und stand damit dauerhaft in der linken oberen
     Ecke — auf jedem Sektionskopf, den man gerade ansteuert. „ANFRAGE",
     „PORTFOLIO" und die Schrittanzeige des Wizards lagen zur Hälfte
     hinter Glas (Jordans Screenshots). Die Entscheidung, WANN sie geht
     und wann sie kommt, trifft mobil.mjs (6b); hier steht nur die
     Bewegung.

     Sie fährt nach OBEN aus dem Bild, nicht in eine kleinere Form: eine
     Pille, die schrumpft, ist immer noch da. `translate` (nicht
     `transform`) ist bewusst gewählt — der FLIP des Kopfschalters in
     index.html benutzt `transform`, und beide zugleich auf demselben
     Element wären ein Kampf um dieselbe Matrix.

     `visibility` nach der Fahrt, nicht `display`: das Blatt darunter
     hat einen Übergang, und ein `display: none` bräche ihn ab. */
  :root.kompakt .kopf {
    transition: translate .32s var(--ease-aus), opacity .22s var(--ease-aus);
  }
  /* Wenn sie zurückkommt, steht sie ÜBER etwas — anders als am Rechner,
     wo links neben ihr Luft ist. Halbdurchsichtiges Glas ließ dort
     „PREMIUM · 1.990 €" durch den Schriftzug „MENÜ" scheinen. Also
     deckender Grund plus Blur, wie beim Menü-Blatt darunter (dort
     16.08. aus demselben Grund entschieden): das Glas bleibt Glas, aber
     es trägt seine eigene Schrift. */
  :root.kompakt .kopf-glas {
    background:
      linear-gradient(180deg, rgba(255, 255, 255, .07), rgba(255, 255, 255, .015)),
      rgba(12, 12, 16, .84);
    box-shadow:
      inset 0 1px 0 rgba(255, 255, 255, .13),
      inset 0 -1px 0 rgba(0, 0, 0, .18),
      0 16px 38px rgba(3, 3, 5, .58);
  }
  :root.kompakt.kopf-fort .kopf {
    translate: 0 calc(-100% - max(var(--kopf-rand), env(safe-area-inset-top)) - 8px);
    opacity: 0;
    pointer-events: none;
  }
  @media (prefers-reduced-motion: reduce) {
    :root.kompakt .kopf { transition: opacity .2s linear; }
    :root.kompakt.kopf-fort .kopf { translate: 0 0; }
  }

  /* ── Scroll-Sperre bei offenem Blatt ──────────────────────────────
     Setzt mobil.mjs (`.sperre` am <html>). Ohne sie rollt die Seite
     unter dem Blatt weg, und der Kopf steht plötzlich über einer
     anderen Sektion. */
  :root.sperre, :root.sperre body { overflow: hidden; }

  /* ══ 2b · KEIN SCROLL-RASTER MEHR ═════════════════════════════════════
     Bis zum 18.08. abends blätterte die Seite sektionsweise: innen
     normal scrollen, an der Unterkante anhalten, erst ein zweiter Wisch
     springt weiter. Zwei Wege dorthin wurden gebaut und beide sind raus:

       · CSS (`scroll-snap-type: y mandatory` + `scroll-snap-stop:
         always`, 18.08. mittags, zwei Stunden live) ließ sich am iPhone
         durchscrollen — die Regel für Sektionen, die höher sind als das
         Fenster, greift dort nicht verlässlich.
       · JavaScript (mobil.mjs, Punkt 6) hakte am wandernden
         `innerHeight` der iOS-Adressleiste; die Begründung steht dort
         ausführlich.

     Es bleibt normales Scrollen. Den Wechsel erzählen die ABTEILE
     (Abschnitt 1b) — Kante, Fuge, Kante. Wer es erneut versucht, prüft
     am echten Gerät, nicht headless, und liest vorher beide Absagen. */

  /* ── Der Hero misst sich in svh, nicht dvh (18.08. nachts) ──────────
     index.html gibt `.buehne` 100 dvh. Auf dem Handy ändert sich dvh mit
     der Adressleiste — der Hero wuchs und schrumpfte also BEIM SCROLLEN,
     alles darunter rutschte unter dem Finger weg, und weil der <body>
     dabei seine Höhe änderte, feuerten die ResizeObserver von rund zehn
     Modulen (Circuit-Routing, Modelle, Ablauf, Anfrage, FAQ, Partikel,
     Welt) und maßen mitten im Wisch alles neu. svh ist stabil: der Hero
     füllt das Fenster mit sichtbarer Leiste exakt, und wenn die Leiste
     einklappt, ist längst gescrollt. Das Laufband sitzt weiter an seiner
     Unterkante — lichter.mjs liest genau diese Kante. */
  :root .buehne { height: 100svh; }

  /* ══ 3 · HERO — nur die Ecke und eine Lücke ═══════════════════════════
     Titel, Unterzeile, Knöpfe und Laufband bleiben, wie index.html sie
     für das Hochformat setzt. Hier steht nur, was die obere Zeile
     braucht: WhatsApp auf gleicher Höhe wie die Pille, 48 px groß. */
  :root .hero-ecke .sozial { width: 48px; height: 48px; }
  :root .hero-ecke .sozial svg { width: 21px; height: 21px; }

  /* ── DIE LÜCKE ZWISCHEN 421 UND 560 px ────────────────────────────
     Gemessen am 18.08.: bei 430 px (iPhone Pro Max!) steht der Titel
     von −10 bis 440 — er ragt auf BEIDEN Seiten aus dem Fenster.

     Der Grund ist derselbe, für den es den 420-px-Block in index.html
     gibt, nur eine Etage höher: `clamp(2.1rem, 6.2vw, 6rem)` bleibt bis
     542 px auf seinem MINIMUM von 33,6 px stehen, die Zeile ist damit
     konstant 451 px breit — und passt erst ab rund 500 px Fensterbreite
     hinein. Der Block unter 421 px fängt das ab, darüber fing es bisher
     niemand.

     Also dieselbe Rechnung wie dort, nur für dieses Band: Größe an die
     Breite gebunden (7,38vw ≈ 86 % Zeilenbreite bei .085em Sperrung),
     gedeckelt bei 2,4 rem — darüber übernimmt wieder die Formel der
     Seite, und der Sprung an der Nahtstelle beträgt 20 px.

     Jordans Regel bleibt unangetastet: die Zeile BRICHT NICHT (das
     `nowrap` steht in index.html), sie wird nur so groß gesetzt, wie sie
     einzeilig sein darf. */
  @media (min-width: 421px) and (max-width: 560px) {
    :root h1 {
      font-size: clamp(1.4rem, 7.38vw, 2.4rem);
      letter-spacing: .085em;
      text-indent: .085em;
    }
    :root #titel.weit { letter-spacing: .15em; text-indent: .15em; }
    :root .unter { line-height: 1.3; }
  }

  /* ── Der Scroll-Hinweis (18.08. spät) ────────────────────────────────
     Eine kleine, leicht durchsichtige weiße Pille über dem Laufband:
     „SCROLL" + ein Pfeil, der ruhig nickt. Sie ist zugleich Schaltfläche
     (Tipp = Sprung zu den Modellen, mobil.mjs Punkt 6 — das Einzige,
     was vom Raster geblieben ist). Geht, sobald
     man den Hero verlässt. Sitzt über dem Laufband (dessen Höhe ≈ 42 px
     + safe-area) — der Abstand ist gemessen, keine Rasterzahl. */
  :root .hero-scroll {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    position: absolute;
    left: 50%;
    bottom: calc(60px + env(safe-area-inset-bottom));
    z-index: 5;
    translate: -50% 0;
    min-height: 34px;
    padding: 0 14px 0 16px;
    border: 1px solid rgba(255, 255, 255, .22);
    border-radius: 999px;
    background: rgba(255, 255, 255, .13);
    color: var(--ink);
    font: 400 .62rem/1 'Space Mono', ui-monospace, monospace;
    letter-spacing: .22em;
    text-transform: uppercase;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    touch-action: manipulation;
    opacity: .9;
    transition: opacity .35s var(--ease, ease), translate .35s var(--ease, ease);
  }
  :root .hero-scroll.weg { opacity: 0; translate: -50% 8px; pointer-events: none; }
  /* Der Pfeil: zwei Striche als Winkel, nickt 6 px — EIN Bewegungsmoment */
  :root .hero-scroll i {
    width: 8px; height: 8px;
    border-right: 1.5px solid currentColor;
    border-bottom: 1.5px solid currentColor;
    rotate: 45deg;
    translate: 0 -2px;
    animation: hero-scroll-nick 1.8s ease-in-out infinite;
  }
  @keyframes hero-scroll-nick {
    0%, 100% { translate: 0 -3px; opacity: .55; }
    50%      { translate: 0  3px; opacity: 1; }
  }
  @media (prefers-reduced-motion: reduce) {
    :root .hero-scroll i { animation: none; }
  }

  /* ══ 3b · DIE LICHTER ═════════════════════════════════════════════════
     Ein Himmel aus steigenden Linien hinter ALLEN Sektionen außer dem
     Hero — eine feste Canvas im `.grund`, gerechnet von lichter.mjs mit
     dem Shader der Fall-Welten. Der Hero bleibt frei: lichter.mjs
     schiebt die Canvas per translateY an die Hero-Unterkante, der
     Shader macht die weiche Kante (uSchnitt). KEINE Maske, keine
     Deckkraft hier — die erste Fassung hatte beides, und auf dem Handy
     blieb alles schwarz (WebKit, Maske auf WebGL-Ebene). Auch die
     halbe Helligkeit ist ein Shader-Wert (brightness), kein opacity.

     Über dem Circuit-Netz (z 2), unter dem Inhalt (main z 1 im eigenen
     Kontext). Die Blätter (Menü, Modell) liegen fixed über allem — sie
     decken die Lichter wie alles andere. */
  :root .grund .mobil-lichter {
    position: absolute;
    inset: 0;
    z-index: 3;
    display: block;
    width: 100%; height: 100%;
    pointer-events: none;
  }

  /* Die zwei Fall-Welten geben ihren eigenen Grund ab: kein deckender
     Verlauf, kein Horizont, keine eigene Himmel-Canvas — der feste
     Himmel scheint durch, und die Naht zwischen Portfolio und Fragen
     (zwei Kästen mit je eigenem Horizont) ist weg. Die Canvas bleibt
     im DOM — welt.mjs braucht ihren Kontext, sonst gibt es keinen
     Monitor beim Kartenklick (mobil.mjs, Punkt 5); `display: none`
     macht sie 1×1 px klein, der Burst läuft dort unsichtbar. */
  :root .pf-welt { background: none; }
  :root .pf-welt .pf-horizont,
  :root .pf-welt .pf-himmel { display: none; }

  /* ══ 4 · MODELLE — EINE DIASHOW, FÜNF KÄSTEN ══════════════════════════
     Dritte Fassung dieser Sektion auf dem Handy, und die zweite Absage
     an einer Stelle, an der beide Vorgänger vernünftig klangen:

       1. FÜNF TÜRME (bis 18.08. früh). Die Rechner-Karten untereinander:
          2.000 px Scrollweg, auf denen man nichts vergleichen kann.
       2. FÜNF ZEILEN (18.08. früh bis spät). Signet · Name+Zusage ·
          Preis, 84 px hoch, mit gemeinsamer Preisspalte — die fünf
          Zahlen standen exakt untereinander. Gut zum Vergleichen,
          aber: fünf Zeilen sind fünf Zeilen. Kein Modell hatte ein
          Gesicht, das Signet war 48 px groß, und was ein Modell
          eigentlich IST, stand hinter einem Tipp.
       3. DIASHOW (18.08. spät, Jordan: „die 5 Modelle quasi in einer
          Diashow, man kann wie in einem Videospiel einfach
          weiterblättern … das System spart Platz und ist schöner").

     Jetzt steht EIN Kasten im Bild, und man blättert. Das ist die
     Auswahlmaske eines Spiels: ein Gegenstand, groß, mit allem, was ihn
     ausmacht — Nummer, Körper, Name, Zusage, für wen, Preis, Dauer —
     und daneben die Zusicherung, dass es noch vier andere gibt.

     WAS DER VERGLEICH DAFÜR KOSTET, und warum das aufgeht: die fünf
     Preise stehen nicht mehr untereinander. Sie stehen dafür GROSS, an
     immer derselben Stelle des Kastens, eine Wischbewegung
     auseinander — man vergleicht sie jetzt in der Zeit statt im Raum.
     Die Reihenfolge (300 → 490 → 990 → 1.990 → ab 2.990) macht daraus
     eine Leiter, die man hinaufblättert.

     WIE ES TECHNISCH GEHT: nativer Scroll-Container mit CSS-Snap in der
     WAAGERECHTEN. Kein selbstgebautes Wischen — das läuft im
     Compositor, während ein `touchmove`-Hörer den Haupt-Thread bräuchte
     (siehe mobil.mjs Punkt 6, warum das hier ein Thema ist). Und anders
     als das gescheiterte SEITEN-Snapping (Abschnitt 2b) ist ein
     waagerechtes Karussell mit fensterbreiten Kacheln genau der Fall,
     für den `scroll-snap` gebaut wurde: ein eigener Scroller, dessen
     Kinder breiter sind als er, ohne Konkurrenz zum Seiten-Scroll
     (`touch-action` erlaubt weiter senkrechtes Wischen).

     Die Leiste darunter (`.mo-blaettern`) baut mobil.mjs — Pfeile,
     Striche, Zähler. Sie ist die zweite Hälfte der Geste: wischen KANN
     man, tippen MUSS man können. */
  :root .modelle {
    padding-block: var(--m-sekt);
    padding-inline: var(--m-innen);
  }
  :root .modelle .mo-kopf {
    max-width: none;
    margin: 0;
    padding: 0 0 var(--m-kopf);
    text-align: left;
  }
  :root .modelle .mo-unsicher {
    min-height: 48px;
    margin-top: 8px;
    padding: 0;
    font-size: .9rem;
  }

  /* Die Bühne bricht aus dem Innenrand der Sektion aus: die Kacheln
     sollen bis an die Abteilkante wischen können, sonst wirkt der
     Scroller wie ein Kasten im Kasten. Der Innenrand kommt als
     `padding` des Scrollers zurück — und als `scroll-padding`, damit
     die Kachel an DERSELBEN Linie einrastet, an der auch die
     Überschrift beginnt. */
  :root .modelle .mo-buehne {
    margin-inline: calc(-1 * var(--m-innen));
    padding-inline: 0;
  }
  :root .modelle .mo-reihe {
    display: flex;
    grid-template-columns: none;
    align-items: stretch;
    /* modelle.css zentriert die Reihe (`justify-content: center`) — am
       Rechner richtig, hier fatal: ein Flex-Container zentriert auch
       das, was ÜBERLÄUFT, und der Überlauf nach links ist dann nicht
       erreichbar. Gemessen am 18.08.: Karte 3 stand in der Mitte, die
       Karten 1 und 2 lagen bei −581 und −271 px, und `scrollLeft` war
       trotzdem 0. Ein Karussell, das bei Modell 3 beginnt und nicht
       zurück kann. */
    justify-content: flex-start;
    gap: 12px;
    max-width: none;
    margin-inline: 0;
    padding-inline: var(--m-innen);
    scroll-padding-inline: var(--m-innen);
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x mandatory;
    overscroll-behavior-x: contain;
    /* KEIN `touch-action: pan-y` hier — das stand in der ersten Fassung
       (18.08. spät) und hat genau das verboten, wofür der Scroller da
       ist: `pan-y` erlaubt NUR senkrechtes Wischen, das waagerechte
       ging nicht mehr, und die Modelle ließen sich nur über die Pfeile
       wechseln (Jordan: „mach auch eine Zieh-Geste"). Die Vorgabe
       `auto` lässt beide Richtungen zu; der Browser entscheidet beim
       ersten Ruck, ob der Finger die Reihe oder die Seite bewegt. */
    touch-action: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
    counter-reset: modell 0;
  }
  :root .modelle .mo-reihe::-webkit-scrollbar { display: none; }

  /* ── SOLANGE EIN MODELL OFFEN IST, IST DIE REIHE KEIN SCROLLER ────
     Das Detail-Blatt (`.mk-platz.ist-auf .mk`, weiter unten) ist
     `position: fixed; inset: 0` — und lag mit der Diashow zum ersten
     Mal IN einem Scroll-Container. WebKit auf iOS behandelt `fixed`
     in einem Element mit `overflow: auto` wie `absolute` gegen diesen
     Scroller: das Blatt war 316 × 487 px groß, der Text darin
     abgeschnitten, und es rollte mit den Kacheln mit (Jordan, 18.08.
     spät: „das Fenster sehr verbuggt und der Text komplett
     abgeschnitten"). Headless Chrome zeigt den Fehler NICHT — dort
     stand das Blatt 390 × 844, deshalb ist er durchgerutscht.

     Also: sobald `.ist-offen` steht, verliert die Reihe ihren Überlauf
     und ihr Snapping — sie ist dann eine gewöhnliche Flex-Zeile, in
     der das Blatt frei zum Fenster steht. Die vier anderen Kacheln
     ragen dabei rechts über die Seite hinaus; das sieht niemand, weil
     `html.sperre` (mobil.mjs setzt sie bei jedem offenen Blatt) den
     Seitenüberlauf ohnehin sperrt — und sie werden zusätzlich
     unsichtbar, damit sie nicht durch den Aufbau des Blatts schimmern.
     `visibility` und nicht `display`: koerper.mjs vermisst die Karten
     weiter, und die Reihe behält ihre Höhe.

     Der Scrollstand geht dabei verloren (ein Element ohne Überlauf hat
     `scrollLeft` 0); mobil.mjs (Punkt 3) merkt ihn sich beim Öffnen
     und stellt ihn beim Schließen wieder her. */
  :root .modelle.ist-offen .mo-reihe {
    overflow: visible;
    scroll-snap-type: none;
  }
  :root .modelle.ist-offen .mk-platz:not(.ist-auf) { visibility: hidden; }

  /* Die Kachel lässt rechts rund 26 px des Nachbarn stehen (die
     Prozentangabe misst die Inhaltsbox des Scrollers, also OHNE seinen
     Innenrand — deshalb steht hier 24 und nicht 38). Das ist die
     ganze Wisch-Affordanz: ein angeschnittener Kasten sagt „hier geht
     es weiter", ohne dass ein Pfeil es behaupten muss. */
  :root .modelle .mk-platz {
    display: block;
    flex: 0 0 calc(100% - 24px);
    perspective: none;
    scroll-snap-align: start;
    scroll-snap-stop: always;
    counter-increment: modell;
  }
  :root .modelle .mk-platz:has(.ist-beliebt) { margin-block: 0; }
  /* Das letzte bekommt rechts denselben Rand wie das erste links —
     `padding-inline-end` am Flex-Scroller ist der Fall, den ältere
     WebKit-Fassungen verschlucken. */
  :root .modelle .mk-platz:last-child { margin-right: var(--m-innen); }

  /* ── DER KASTEN ───────────────────────────────────────────────────
     Eine Spalte, unten schwer: Körper und Name oben, dann die Zusage,
     dann für wen — und ab dem Preis sitzt alles am Boden (`margin-top:
     auto` auf `.mk-strich`). So stehen Preis, Dauer und der Aufruf bei
     allen fünf Kacheln auf DERSELBEN Höhe, obwohl die Branchenlisten
     verschieden lang sind. Das ist der Rest des Vergleichs, der im
     Raum möglich bleibt. */
  :root .modelle .mk-platz:not(.ist-auf) .mk {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    height: 100%;
    min-height: 0;
    padding: 20px 18px 18px;
    border-radius: 22px;
    background:
      linear-gradient(180deg, rgba(255, 255, 255, .055) 0, rgba(255, 255, 255, 0) 120px),
      rgba(255, 255, 255, .022);
    box-shadow: none;
  }
  /* Haarlinien-Rand statt Verlaufskante: die Kante ist auf 342 px
     Breite nur noch ein Schimmer, die Linie eine Aussage. */
  :root .modelle .mk-platz:not(.ist-auf) .mk-rand {
    background: none;
    -webkit-mask: none;
            mask: none;
    padding: 0;
    border: 1px solid var(--linie);
    border-radius: 22px;
    opacity: 1;
  }
  :root .modelle .mk-platz:not(.ist-auf) .mk.ist-beliebt {
    background:
      linear-gradient(180deg, rgba(255, 255, 255, .085) 0, rgba(255, 255, 255, 0) 140px),
      rgba(255, 255, 255, .045);
  }
  :root .modelle .mk-platz:not(.ist-auf) .mk.ist-beliebt .mk-rand {
    border-color: var(--linie-hell);
  }

  /* Die Stufennummer. Sie steht im Markup nicht (modelle.mjs baut sie
     nicht), ist aber genau das, was eine Auswahlmaske braucht: „welcher
     von fünf?". Ein Zähler auf dem Platz macht daraus 01…05, ohne dass
     ein Skript sie schreiben oder eine Übersetzung sie kennen müsste.
     `.mk-spalte` ist in der Übersicht `display: contents` und kann kein
     Pseudo-Element tragen — deshalb hängt sie an der Karte. */
  :root .modelle .mk-platz:not(.ist-auf) .mk::before {
    content: counter(modell, decimal-leading-zero);
    position: absolute;
    top: 18px; left: 18px;
    z-index: 2;
    font: 400 .62rem/1 'Space Mono', ui-monospace, monospace;
    letter-spacing: .18em;
    color: var(--ink-dim);
    opacity: .7;
  }
  /* Das Etikett gegenüber der Nummer, auf derselben Linie. */
  :root .modelle .mk-platz:not(.ist-auf) .mk-badge {
    top: 12px; left: auto; right: 14px;
    translate: none;
    padding: .2rem .5rem;
    font-size: .5rem;
    letter-spacing: .16em;
    box-shadow: none;
  }
  :root .modelle .mk-platz:not(.ist-auf) .mk-badge i { display: none; }

  /* Der Drahtkörper ist auf dem Handy zum ersten Mal groß genug, dass
     man ihn als Gegenstand liest statt als Symbol. Er sitzt rechts
     unter dem Etikett und links neben nichts — die Schrift beginnt
     darunter, damit die Zeilen die volle Breite haben. */
  :root .modelle .mk-platz:not(.ist-auf) .mk-schau {
    align-self: center;
    width: 120px; height: 120px;
    margin: 10px 0 4px;
  }
  :root .modelle .mk-platz:not(.ist-auf) .mk-name {
    margin: 0;
    font-family: 'Clash Display', 'Space Grotesk', sans-serif;
    font-weight: 400;
    font-size: 1.6rem;
    line-height: 1.05;
    letter-spacing: .02em;
    text-indent: 0;
    text-align: left;
    color: var(--ink);
  }
  :root .modelle .mk-platz:not(.ist-auf) .mk-verspr {
    margin: 6px 0 0;
    font-size: 1rem;
    line-height: 1.3;
    letter-spacing: 0;
    text-align: left;
    color: var(--ink-dim);
    opacity: 1;
  }
  /* Für wen: die drei Betriebe, gesperrt und gedimmt. Sie beantworten
     „ist das meins?" — auf einer Kachel, die man ganz sieht, ist das
     die wichtigste Zeile nach dem Preis.

     Der Trennpunkt steht am ENDE eines Begriffs (::after), nicht am
     Anfang des nächsten wie in modelle.css: bricht „Mitgliederportal ·
     Konfigurator · Live-Buchung" um, eröffnet sonst ein Punkt die
     zweite Zeile. */
  :root .modelle .mk-platz:not(.ist-auf) .mk-fuer {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-start;
    gap: 0 .5rem;
    margin: 12px 0 0;
    font-size: .58rem;
    line-height: 1.5;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--ink-dim);
    opacity: .78;
  }
  :root .modelle .mk-platz:not(.ist-auf) .mk-fuer li { gap: .5rem; white-space: nowrap; }
  :root .modelle .mk-platz:not(.ist-auf) .mk-fuer li + li::before { display: none; }
  :root .modelle .mk-platz:not(.ist-auf) .mk-fuer li:not(:last-child)::after {
    content: '';
    width: 3px;
    height: 3px;
    border-radius: 50%;
    background: currentColor;
    opacity: .5;
  }

  /* Ab hier der Fuß der Kachel — er wird nach unten gedrückt.
     Im MARKUP steht der Preis vor dem Strich (modelle.mjs, geteilt mit
     dem Rechner); hier soll der Strich den Fuß eröffnen. Das macht
     `order` — vier Zahlen statt eines Eingriffs in ein Modul, das drei
     Seiten benutzen. Vorleser lesen weiter die DOM-Ordnung, und die ist
     unverändert richtig: der Strich ist Dekoration. */
  :root .modelle .mk-platz:not(.ist-auf) .mk-strich {
    order: 1;
    display: block;
    width: 100%;
    margin: auto 0 0;
    padding-top: 16px;
    height: 1px;
    background: none;
    border-top: 1px solid var(--linie);
  }
  :root .modelle .mk-platz:not(.ist-auf) .mk-preis {
    order: 2;
    display: flex;
    align-items: baseline;
    gap: .5rem;
    margin: 14px 0 0;
    padding: 0;
    text-align: left;
  }
  :root .modelle .mk-platz:not(.ist-auf) .mk-preis b {
    font-size: 2rem;
    letter-spacing: -.015em;
  }
  :root .modelle .mk-platz:not(.ist-auf) .mk-ab { font-size: .42em; }
  :root .modelle .mk-platz:not(.ist-auf) .mk-waehrung { font-size: .56em; }
  /* „netto · einmalig" stand in der Zeilenfassung nicht — auf einer
     Kachel mit 2-rem-Zahl fehlt es sofort. Es steht NEBEN der Zahl auf
     der Grundlinie, nicht darunter: eine Zeile weniger. */
  :root .modelle .mk-platz:not(.ist-auf) .mk-preis i {
    display: block;
    font-style: normal;
    font-size: .62rem;
    line-height: 1.4;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--ink-dim);
    opacity: .8;
  }
  :root .modelle .mk-platz:not(.ist-auf) .mk-dauer {
    order: 3;
    display: block;
    margin: 10px 0 0;
    text-align: left;
    font-size: .78rem;
  }
  :root .modelle .mk-platz:not(.ist-auf) .mk-dauer span {
    display: inline;
    margin: 0 .4rem 0 0;
    font-size: .58rem;
    letter-spacing: .14em;
  }
  /* Der Aufruf. In der Zeilenfassung war er weg (die Zeile selbst war
     der Knopf) — auf einer Kachel, die man wischt, muss er stehen:
     wischen und tippen sind zwei Gesten, und der Kasten soll nicht
     raten lassen, welche was tut. */
  :root .modelle .mk-platz:not(.ist-auf) .mk-more {
    order: 4;
    display: flex;
    width: 100%;
    min-height: 48px;
    margin-top: 16px;
    border-color: var(--linie);
    font-size: .68rem;
    letter-spacing: .16em;
    color: var(--ink);
  }
  /* Beim ausgezeichneten Modell ist der Knopf GEFÜLLT (modelle.css:
     `.ist-beliebt .mk-more`) und trägt dort dunkle Schrift auf hellem
     Grund. Die Zeile darüber setzt `color: var(--ink)` und gewänne mit
     ihrer höheren Spezifität — heller Text auf hellem Knopf, gemessen
     am 18.08. Also die dunkle Farbe hier noch einmal, mit demselben
     Wert wie drüben. Die Füllung ist in dieser Fassung entfärbt
     (entfaerbt.css), sie bleibt hell. */
  :root .modelle .mk-platz:not(.ist-auf) .mk.ist-beliebt .mk-more { color: #042220; }
  :root .modelle .mk-platz:not(.ist-auf) .mk-anlass { display: none; }

  /* ── DIE BLÄTTERLEISTE (baut mobil.mjs, Punkt 6d) ─────────────────
     Zwei 44-px-Knöpfe und dazwischen fünf Striche — keine Punkte: ein
     Strich, der beim aktiven Modell länger und hell wird, ist dieselbe
     Sprache wie die Leiterbahnen und die Lichtnaht der Abteile. Die
     Striche sind selbst Ziele (44 px hoch über ein Pseudo-Element),
     denn das dritte Modell ist von außen zwei Wischer weit weg. */
  :root .modelle .mo-blaettern {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    margin: 20px 0 0;
  }
  :root .modelle .mo-pfeil {
    flex: none;
    display: grid;
    place-items: center;
    width: 44px; height: 44px;
    padding: 0;
    border: 1px solid var(--linie);
    border-radius: 50%;
    background: rgba(255, 255, 255, .03);
    color: var(--ink);
    cursor: pointer;
    transition: opacity .25s var(--ease), border-color .25s var(--ease);
  }
  :root .modelle .mo-pfeil[disabled] { opacity: .3; pointer-events: none; }
  :root .modelle .mo-pfeil:active { background: rgba(255, 255, 255, .08); }
  /* Der Winkel aus zwei Haarlinien — dasselbe Zeichen wie im Menü-Blatt
     und am Scroll-Hinweis, nur gedreht. Kein Zeichen aus der Schrift. */
  :root .modelle .mo-pfeil i {
    width: 9px; height: 9px;
    border-top: 1.5px solid currentColor;
    border-right: 1.5px solid currentColor;
    rotate: 45deg;
    translate: -2px 0;
  }
  :root .modelle .mo-pfeil.zurueck i { rotate: -135deg; translate: 2px 0; }

  :root .modelle .mo-striche {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    min-width: 0;
  }
  /* Der Strich behält seine BREITE und wird gestaucht — nicht
     umgekehrt. Eine `width`-Animation wäre hier zweimal falsch: sie
     lässt den Browser bei jedem Bild neu umbrechen, und die vier
     Nachbarn rutschen dabei seitlich, weil die Reihe zentriert ist.
     Mit `scale` bleibt das Raster stehen und nur der Balken wächst. */
  :root .modelle .mo-strich {
    position: relative;
    width: 34px; height: 2px;
    padding: 0;
    border: 0;
    border-radius: 2px;
    background: var(--linie-hell);
    opacity: .45;
    scale: .47 1;
    cursor: pointer;
    transition: scale .32s var(--ease), opacity .32s var(--ease), background .32s var(--ease);
  }
  /* 2 px sind kein Tippziel — die Fläche wächst unsichtbar auf 44. */
  :root .modelle .mo-strich::after {
    content: '';
    position: absolute;
    inset: -21px 0;
  }
  :root .modelle .mo-strich[aria-current="true"] {
    scale: 1 1;
    background: var(--ink);
    opacity: 1;
  }

  :root .modelle .mo-ust {
    margin: 24px 0 0;
    text-align: left;
    font-size: .74rem;
    line-height: 1.5;
  }

  /* ── DAS MODELL-BLATT (offene Karte) ──────────────────────────────
     Vorher ein Blatt von unten mit 88 svh: darüber blieben rund 100 px
     Seite stehen, in denen der Kopf („MENÜ") und die Karte dahinter
     durchschienen — ein halb aufgezogener Vorhang, kein Blatt.

     Jetzt DECKT es: fixed über das ganze Fenster, z-index über dem Kopf
     (der ist 20), eigene Kopfleiste, ein Scroller, und der Aufruf liegt
     fest in der Daumenzone. */
  /* ── ERST DIE STAPELUNG, DANN DAS BLATT ──────────────────────────
     Ein `z-index: 40` an der Karte allein reicht NICHT, und der Grund
     ist zweimal derselbe: die Karte liegt in `.modelle`, und `.modelle`
     ist selbst ein Stapelkontext (`z-index: 1; isolation: isolate` in
     index.html) innerhalb von `main` (ebenfalls `z-index: 1`). Innerhalb
     eines Kontexts kann kein Kind über dessen Nachbarn hinaus.

     Gemessen am 18.08. an zwei sichtbaren Fehlern:
       · Die Kopf-Pille („MENÜ", z-index 20, außerhalb von `main`) stand
         auf dem Blatt.
       · Am unteren Rand las man „In drei Schritten online." DURCH das
         Blatt — `.ablauf` hat denselben z-index 1 wie `.modelle` und
         steht später im Baum, malt also darüber.

     Also: die Sektion steigt, solange eine Karte offen ist, und der Kopf
     tritt ab. `:has()` statt einer Klasse aus mobil.mjs — der Zustand
     steht schon im DOM, ein zweiter wäre einer zu viel. */
  :root .modelle.ist-offen { z-index: 40; }
  :root:has(.modelle.ist-offen) .kopf { opacity: 0; pointer-events: none; }

  :root .modelle .mk-platz.ist-auf .mk {
    position: fixed;
    inset: 0;
    z-index: 40;
    width: auto;
    height: 100dvh;
    max-height: none;
    margin: 0;
    padding: 0 0 calc(148px + env(safe-area-inset-bottom));
    border-radius: 0;
    display: block;
    background: var(--void);
    box-shadow: none;
    overflow-y: auto;
    overscroll-behavior: contain;
  }
  :root .modelle .mk-platz.ist-auf .mk-rand { display: none; }

  /* Die Kopfleiste. Sie ist kein eigenes Element (das Markup baut
     modelle.mjs und bleibt unangetastet) — der MODELLNAME übernimmt sie:
     als erstes Kind der Spalte (`order: -1`) und `sticky` am oberen
     Rand. Rechts daneben der Weg zurück, fest im Fenster. */
  :root .modelle .mk-platz.ist-auf .mk-spalte {
    display: flex;
    flex-direction: column;
    overflow: visible;
    min-height: auto;
    padding: 0 var(--m-rand) 0;
  }
  :root .modelle .mk-platz.ist-auf .mk-name {
    order: -1;
    position: sticky;
    top: 0;
    z-index: 6;
    height: calc(56px + env(safe-area-inset-top));
    margin: 0 calc(-1 * var(--m-rand)) 24px;
    padding: env(safe-area-inset-top) 68px 0 var(--m-rand);
    display: flex;
    align-items: center;
    font-family: 'Clash Display', 'Space Grotesk', sans-serif;
    font-weight: 400;
    font-size: 1.05rem;
    letter-spacing: .12em;
    text-indent: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    color: var(--ink);
    background: var(--void);
    border-bottom: 1px solid var(--linie);
  }
  /* Der Rest der Spalte beginnt unter der Leiste; das Signet zuerst —
     linksbündig wie alles andere, nicht als zentriertes Titelbild. */
  :root .modelle .mk-platz.ist-auf .mk-schau {
    align-self: flex-start;
    width: 88px;
    height: 88px;
    margin: 0 0 16px;
  }
  :root .modelle .mk-platz.ist-auf .mk-verspr {
    margin: 0;
    font-size: 1.35rem;
    line-height: 1.2;
    letter-spacing: 0;
    color: var(--ink);
  }
  :root .modelle .mk-platz.ist-auf .mk-anlass { font-size: .92rem; }
  :root .modelle .mk-platz.ist-auf .mk-preis { margin-top: 24px; }
  :root .modelle .mk-platz.ist-auf .mk-preis b { font-size: 2.4rem; }
  :root .modelle .mk-platz.ist-auf .mk-passt { margin-top: 24px; }
  /* Der Detailteil ist im Blatt keine zweite SPALTE mehr, sondern die
     Fortsetzung der ersten — er braucht deshalb einen Absatz, sonst
     klebt „Enthält alles aus …" an der letzten Zeile von „Passt zu dir". */
  :root .modelle .mk-platz.ist-auf .mk-mehr {
    overflow: visible;
    min-height: auto;
    margin-top: 24px;
    padding: 24px var(--m-rand) 0;
    border-top: 1px solid var(--linie);
  }
  :root .modelle .mk-platz.ist-auf .mk-erbt { margin-top: 0; }
  /* Das Etikett wandert unter die Leiste, sonst läge es darauf. */
  :root .modelle .mk-platz.ist-auf .mk-badge {
    top: calc(64px + env(safe-area-inset-top));
    left: var(--m-rand);
    right: auto;
    translate: none;
  }
  :root .modelle .mk-platz.ist-auf .mk:has(.mk-badge) .mk-spalte { padding-top: 0; }
  :root .modelle .mk-platz.ist-auf .mk:has(.mk-badge) .mk-schau { margin-top: 28px; }

  /* ── DAS BLATT SAGT WENIGER (18.08. spät, Jordan: „reduzier die Info
     deutlich … bei einem Gespräch wird das eh geklärt") ─────────────
     Am Rechner ist die Tafel ein Prospekt: Anlass, drei Leistungsblöcke
     mit je vier bis sechs Punkten, die volle Branchenliste, der
     Zuschnitt-Satz. Auf dem Handy war das ein Blatt von 1.720 px, das
     man dreimal durchwischt, bevor der Aufruf kommt. Was bleibt, ist
     die Antwort auf zwei Fragen — „ist das meins?" und „was kostet
     es, wann ist es fertig?" — und der Weg zur Anfrage:

        Körper · Name · Zusage · für wen · Preis · Dauer ·
        „Passt zu dir, wenn" (drei Zeilen) · „Enthält alles aus …" ·
        Nachbarstufe · Anfragen

     Weg sind: Anlass-Satz, Leistungsblöcke, Branchenliste, Zuschnitt.
     `display: none`, nicht gelöscht — modelle.mjs baut die Tafel für
     drei Seiten, und am Rechner bleibt sie der Prospekt. */
  :root .modelle .mk-platz.ist-auf .mk-anlass,
  :root .modelle .mk-platz.ist-auf .mk-felder,
  :root .modelle .mk-platz.ist-auf .mk-branchen,
  :root .modelle .mk-platz.ist-auf .mk-zuschnitt { display: none; }
  /* Ohne die Blöcke ist `.mk-mehr` nur noch die eine Zeile „Enthält
     alles aus …" — sie rückt an „Passt zu dir" heran, die Trennlinie
     bleibt als Absatz. */
  :root .modelle .mk-platz.ist-auf .mk-mehr { padding-bottom: 8px; }
  :root .modelle .mk-platz.ist-auf .mk-passt { margin-top: 20px; }

  /* Zurück: runder 44-px-Knopf, fest im Fenster oben rechts — er darf
     nicht mit dem Inhalt wegrollen. `font-size: 0` blendet nur das Wort
     aus; als Name für Vorleser bleibt es im Baum. */
  :root .modelle .mk-platz.ist-auf .mk-zu {
    position: fixed;
    top: calc(env(safe-area-inset-top) + 6px);
    right: 12px;
    z-index: 41;
    width: 44px; height: 44px;
    min-height: 44px;
    padding: 0;
    justify-content: center;
    gap: 0;
    border-radius: 50%;
    border: 1px solid var(--linie);
    background: rgba(255, 255, 255, .06);
    color: var(--ink);
    font-size: 0;
  }
  :root .modelle .mk-platz.ist-auf .mk-zu i { width: 15px; height: 15px; }

  /* Der Fuß: fest in der Daumenzone. Oben der Sprung zur Nachbarstufe
     (eine Zeile), darunter der Aufruf (eine Fläche) —
     `column-reverse`, weil im Markup der Aufruf zuerst steht und das
     Markup nicht angefasst wird. Die Höhe dieses Kastens steckt oben im
     `padding-bottom` der Karte; wer hier etwas hinzufügt, zählt sie
     dort mit. */
  :root .modelle .mk-platz.ist-auf .mk-fuss {
    position: fixed;
    left: 0; right: 0; bottom: 0;
    z-index: 8;
    display: flex;
    flex-direction: column-reverse;
    flex-wrap: nowrap;
    align-items: stretch;
    gap: 8px;
    margin: 0;
    padding: 12px var(--m-rand) calc(12px + env(safe-area-inset-bottom));
    border-top: 1px solid var(--linie);
    background: rgba(5, 5, 6, .96);
    -webkit-backdrop-filter: blur(18px);
            backdrop-filter: blur(18px);
  }
  :root .modelle .mk-platz.ist-auf .mk-cta {
    min-height: 52px;
    margin: 0;
    padding: 0 24px;
    font-size: .74rem;
    letter-spacing: .2em;
  }
  :root .modelle .mk-platz.ist-auf .mk-nachbar {
    justify-content: center;
    min-height: 44px;
    font-size: .8rem;
  }

  /* ══ 5 · ABLAUF ═══════════════════════════════════════════════════════
     Die Sektion trug oben und unten je rund 100 px Luft und zwischen
     Kopf und Reihe noch einmal 60 — im Blätterbetrieb ist das ein Loch,
     kein Atem. Sektion auf das Raster, Wesen 72 px links, Text rechts,
     32 px zwischen den Schritten. */
  :root .ablauf {
    padding-block: var(--m-sekt);
    padding-inline: var(--m-innen);
  }
  :root .ablauf .ab-kopf {
    max-width: none;
    margin: 0 0 var(--m-kopf);
    padding: 0;
    text-align: left;
  }
  :root .ablauf .ab-buehne {
    max-width: none;
    margin: 0;
    padding: 0;
  }
  /* Die Reihe ist ein <ol>. Ohne diese Zeile trägt sie die 40 px
     Aufzählungs-Einzug des Browsers, und die drei Schritte stünden als
     Einzige der Seite bei x = 64 statt bei x = 24 (gemessen 18.08.). */
  :root .ablauf .ab-reihe {
    margin: 0;
    padding: 0;
    list-style: none;
    gap: 32px;
  }
  /* Oben ausgerichtet, nicht mittig: das Wesen gehört zur Nummer und zur
     Überschrift. Mittig hinge es bei einem vierzeiligen Absatz
     irgendwo in dessen Mitte. */
  :root .ablauf .ab-schritt { gap: 16px; align-items: flex-start; }
  :root .ablauf .ab-platz { width: 72px; margin: 0; }
  :root .ablauf .ab-text { padding-top: 0; }
  :root .ablauf .ab-nr {
    font-family: 'Space Mono', ui-monospace, monospace;
    font-size: .64rem;
    letter-spacing: .2em;
  }
  :root .ablauf .ab-schritt h3 {
    margin-top: 4px;
    font-size: 1.2rem;
  }
  :root .ablauf .ab-schritt p {
    margin-top: 8px;
    max-width: none;
    font-size: .9rem;
    line-height: 1.5;
  }
  /* `.ab-mehr` steht in ablauf.css mit `!important` — der einzige Ort,
     an dem hier ebenfalls eines steht. Ohne es bliebe die Zeile
     außerhalb des Rasters. */
  :root .ablauf .ab-mehr { margin-top: 8px !important; }

  /* Der Bezahlhinweis: zwei ruhige Zeilen, kein gesperrter Versalblock.
     Ein Satz in Versalien wird nicht gelesen, er wird angesehen. */
  :root .ablauf .ab-fuss {
    max-width: none;
    margin: 40px 0 0;
    padding: 24px 0 0;
    border-top: 1px solid var(--linie);
    text-align: left;
    font-size: .88rem;
    line-height: 1.5;
    letter-spacing: 0;
    text-transform: none;
    opacity: 1;
    color: var(--ink-dim);
  }
  :root .ablauf .ab-fuss b { display: block; color: var(--ink); font-weight: 500; }

  /* ══ 6 · ANFRAGE ══════════════════════════════════════════════════════
     DIE REIHENFOLGE IST EINE ANDERE ALS AM RECHNER (18.08. abends,
     Jordan). Dort stehen links Text und Kontakt, rechts das Paneel —
     zwei Spalten, beide gleichzeitig im Blick. Auf 390 px wurde daraus
     ein Stapel, und in dem stand VOR dem Formular: eine Erklärzeile,
     eine Trennlinie, drei Kontaktzeilen und ein Versprechen. Wer auf
     „Anfrage" tippt, wischt also erst durch eine halbe Seite, bevor er
     das findet, wofür er getippt hat.

     Jetzt:  Kicker · Überschrift · WIZARD · Trennlinie · Kontakt ·
             „Antwort innerhalb von 24 Stunden".
     Die Kontaktwege bleiben — sie sind der zweite Weg für den, dem ein
     Formular zu viel ist, und der gehört hinter das Formular, nicht
     davor.

     WIE: `.an-links` wird zu `display: contents`. Seine Kinder werden
     damit selbst zu Kindern des Rasters, und die Reihenfolge lässt sich
     mit `order` legen — ohne das Markup anzufassen (index.html ist die
     Quelle, aus der en/index.html erzeugt wird). Die Box von
     `.an-links` verschwindet dabei; sie trägt nichts als `min-width: 0`,
     also geht nichts verloren. Der Fokus- und Vorleserlauf folgt der
     DOM-Ordnung, nicht `order` — bei sieben Blöcken ohne Reihenfolge-
     Bedeutung ist das vertretbar; der Wizard ist ein eigenes <form> und
     bleibt in sich geordnet. */
  :root .anfrage {
    padding-block: var(--m-sekt);
    padding-inline: var(--m-innen);
  }
  :root .anfrage .an-raster {
    display: flex;
    flex-direction: column;
    gap: 0;
    align-items: stretch;
  }
  :root .anfrage .an-links { display: contents; }
  :root .anfrage .an-kicker      { order: 1; }
  :root .anfrage .an-links h2    { order: 2; margin-bottom: 0; }
  :root .anfrage .an-paneel      { order: 3; margin-top: 24px; }
  /* Der Strich war am Rechner ein kurzer Akzent unter der Überschrift.
     An seiner neuen Stelle — zwischen Formular und Kontaktwegen — hat er
     eine Aufgabe: er trennt „ausfüllen" von „oder ruf einfach an". Also
     über die ganze Breite, in derselben Haarlinie wie die Listenzeilen
     darunter, und nur in der Mitte hell. */
  :root .anfrage .an-strich {
    order: 4;
    width: auto;
    margin: 40px 0 0;
    background: linear-gradient(to right,
      var(--linie), var(--linie-hell) 50%, var(--linie));
  }
  :root .anfrage .an-wege        { order: 5; gap: 0; }
  :root .anfrage .an-versprechen { order: 6; }
  /* „Deutschlandweit tätig" ist keine Handlung, sondern eine Fußnote —
     zwischen zwei Zeilen, die man antippen kann, liest sie sich wie eine
     dritte, die nicht reagiert (Jordan, 18.08. abends). Am Rechner
     bleibt sie: dort trägt die Spalte sie mühelos. */
  :root .anfrage .an-weg-still { display: none; }
  /* Kontaktzeilen: 48 px hoch, Symbol 40, Haarlinie dazwischen — eine
     Liste, keine drei Kästen. */
  :root .anfrage .an-weg {
    min-height: 48px;
    padding: 8px 0;
    border-radius: 0;
    gap: 16px;
  }
  :root .anfrage .an-weg + .an-weg { border-top: 1px solid var(--linie); }
  :root .anfrage .an-weg i { width: 40px; height: 40px; }
  :root .anfrage .an-weg svg { width: 17px; height: 17px; }
  :root .anfrage .an-weg-t b { font-size: .95rem; }
  :root .anfrage .an-weg-t span { font-size: .76rem; }
  :root .anfrage .an-versprechen { margin-top: 24px; }

  :root .anfrage .an-paneel {
    padding: 16px;
    border-radius: 18px;
  }
  :root .anfrage .an-schritte { margin-bottom: 16px; }

  /* Der Prüfstand: aus dem hohen Kasten mit Vitrine, Kicker, Name, Preis
     und Erklärung wird EINE Zeile. Bis ein Modell gewählt ist, stand
     dort ein 236 px hoher Kasten mit dem Wort „OFFEN" — Fläche ohne
     Aussage. Was verschwindet, ist nur Wiederholung: die Nummer steht
     in der Schrittanzeige darüber, der Zusatzsatz in der Frage
     darunter. */
  :root .anfrage .an-stand {
    grid-template-columns: 40px minmax(0, 1fr);
    align-items: center;
    gap: 12px;
    margin-bottom: 16px;
    padding: 10px 12px;
    border-radius: 12px;
  }
  :root .anfrage .an-vitrine { width: 40px; }
  :root .anfrage .an-stand-nr,
  :root .anfrage .an-stand-fit { display: none; }
  :root .anfrage .an-stand-name { margin: 0; font-size: 1rem; }
  :root .anfrage .an-stand-preis { margin: 2px 0 0; font-size: .82rem; }

  /* ── DIE KACHELN: ZWEI SPALTEN, DREI REIHEN ────────────────────────
     anfrage.css schaltet unter 421 px auf EINE Spalte. Sechs Modelle
     wurden damit zu sechs vollbreiten Zeilen — 700 px Wizard, und man
     sah nie mehr als zwei Angebote gleichzeitig. Ein Angebot, das man
     nicht neben das andere halten kann, ist keine Auswahl, sondern eine
     Liste (Jordan, 18.08. abends: „2x2x2").

     Sechs Modelle in zwei Spalten sind genau drei Reihen; die vier
     Care-Stufen sind zwei; das Extra bleibt eine breite Kachel. Der
     Wizard hat damit auf jeder Stufe dieselbe Form.

     Die Kachel wird dafür schmaler UND ruhiger: das Etikett rechts oben
     („i") sitzt in der Zeile der Nummer statt über dem Namen, und die
     Kachel behält links wie rechts denselben Innenrand. Sonst stünde
     der Modellname auf 100 px Breite und bräche in drei Zeilen. */
  :root .anfrage .an-frage { margin-bottom: 12px; }
  :root .anfrage .an-kacheln {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px;
  }
  :root .anfrage .an-extra .an-kacheln { grid-template-columns: minmax(0, 1fr); }
  :root .anfrage .an-wahl {
    min-height: 0;
    align-content: start;
    gap: 4px;
    padding: 11px 12px 13px;
    border-radius: 14px;
  }
  /* Platz für das Schild „Beliebteste", das über der Kante hängt. */
  :root .anfrage .an-wahl:has(.an-schild) { padding-top: 17px; }
  :root .anfrage .an-wahl b { font-size: .96rem; line-height: 1.12; }
  :root .anfrage .an-wahl em { font-size: .78rem; }
  :root .anfrage .an-wahl span { font-size: .7rem; line-height: 1.35; }
  :root .anfrage .an-wahl-nr { font-size: .55rem; }
  /* Das „i" rückt in die Ecke der Nummernzeile (`top/right: 6px`), und
     die Kachel darunter darf wieder bis an den rechten Innenrand
     schreiben: `.an-zelle .an-wahl` hält am Rechner 2,2 rem frei, damit
     das „i" nicht auf dem Preis liegt — auf 150 px Kachelbreite wären
     das 23 % der Zeile. In der ersten Zeile steht nur die zweistellige
     Nummer, links; rechts ist Platz. Sichtbare Größe und die 44-px-
     Trefferfläche (::before) bleiben, wie sie sind. */
  :root .anfrage .an-zelle .an-wahl { padding-right: 12px; }
  :root .anfrage .an-info-knopf { top: 6px; right: 6px; }
  /* Der Hinweis der Extra-Kachel darf breit bleiben — sie ist die
     einzige in ihrer Reihe. */
  :root .anfrage .an-extra .an-wahl span { font-size: .76rem; }
  /* Das Schild „Beliebteste" ist ein span in der Kachel und erbte die
     .78rem der Zeile darüber — auf 342 px ein Etikett so groß wie der
     Modellname (Jordan, 18.08. spät). anfrage.css hat für genau diesen
     Fall eine eigene Regel (.an-wahl .an-schild), aber (0,2,0) verliert
     gegen (0,3,1). Hier also nochmal, mit dem Handy-Maß. */
  :root .anfrage .an-wahl .an-schild {
    top: -7px; left: 12px;
    padding: .12rem .42rem;
    font-size: .5rem;
    line-height: 1.5;
    letter-spacing: .12em;
  }
  /* Die Info-Tafel im Wizard ist dieselbe Prospektseite wie das
     Modell-Blatt und wird hier genauso gekürzt (Jordan, 18.08. spät):
     die Leistungsblöcke fallen, „Passt zu dir, wenn“ bleibt — das ist
     die Zeile, die die Wahl entscheidet. 1.200 → ~600 px. */
  :root .anfrage .an-info-block:not(.an-info-passt) { display: none; }
  :root .anfrage .an-felder { gap: 16px; }
  /* 16 px Schrift ist Pflicht, sonst zoomt iOS beim Fokus hinein.
     anfrage.css setzt das bereits — hier nur die Höhe. */
  :root .anfrage .an-feld input { min-height: 48px; }
  :root .anfrage .an-feld textarea { min-height: 104px; }
  :root .anfrage .an-nav { margin-top: 24px; padding-top: 16px; }
  :root .anfrage .an-nav .knopf { min-height: 52px; }
  :root .anfrage .an-zurueck { min-height: 48px; }
  :root .anfrage .an-fuss-note { text-align: left; margin-top: 12px; }

  /* ══ 7 · PORTFOLIO ════════════════════════════════════════════════════
     Der Partikel-Text („UNSERE DESIGNS") ist Bühne: ein gepunkteter
     Schriftzug, den WebGL in den Platz `.pf-textplatz` rechnet. Auf dem
     Handy tritt an seine Stelle die ECHTE Überschrift — dieselbe Gestalt
     wie in allen anderen Sektionen.

     Der Platz wird dafür auf Höhe 0 gesetzt, und das genügt: text.mjs
     rastert bei `hoehe < 10` gar nichts (`n = 0`), es wird also kein
     Punkt gezeichnet. Kein Eingriff in die Engine nötig. Gleichzeitig
     wird der h2 aus seiner Vorleser-Verkleidung geholt (welt.css
     versteckt ihn, solange WebGL läuft). */
  :root .pf-welt {
    padding: var(--m-sekt) var(--m-innen);
    row-gap: 0;
    min-height: 0;
  }
  :root .pf-welt .pf-textplatz { height: 0; }
  :root .pf-welt:not(.ohne-gl) .pf-kopf h2 {
    position: static;
    width: auto; height: auto;
    overflow: visible;
    clip-path: none;
    white-space: normal;
  }
  :root .pf-welt .pf-kopf { margin-bottom: var(--m-kopf); }
  :root .portfolio .pf-faecher { gap: 16px; }
  :root .portfolio .pf-karte { min-height: 48px; }

  /* ── ZUGEKLAPPT (18.08. abends) ────────────────────────────────────
     Vier Welten mit großem Startseitenbild sind hier 1.200 px — eine
     Strecke, kein Überblick. Also erst der Kopf und EINE Zeile; die
     Karten kommen auf Wunsch. Den Schalter baut mobil.mjs (6c), er
     existiert nur unter 721 px.

     Die Zeile ist absichtlich zeichengleich mit den Fragen-Zeilen
     darunter: dieselbe Höhe, dieselbe Haarlinie, dasselbe Pluszeichen
     im Kreis. Zwei verschiedene Gesten für „hier ist mehr" auf einer
     Seite wären zwei Sprachen. */
  :root .portfolio .pf-klapp {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    width: 100%;
    min-height: 56px;
    margin: 0;
    padding: 14px 0;
    border: 0;
    border-top: 1px solid var(--linie);
    border-bottom: 1px solid var(--linie);
    border-radius: 0;
    background: none;
    color: var(--ink);
    font: 500 1rem/1.35 'Space Grotesk', sans-serif;
    text-align: left;
    cursor: pointer;
  }
  :root .portfolio .pf-klapp:active { background: rgba(255, 255, 255, .04); }
  /* Das Zeichen: 30 px sichtbar wie bei den Fragen, 44 px tippbar über
     die Zeile selbst — die ganze Zeile ist der Knopf. */
  :root .portfolio .pf-klapp-z {
    position: relative;
    flex: none;
    width: 30px; height: 30px;
    border: 1px solid var(--linie);
    border-radius: 50%;
  }
  :root .portfolio .pf-klapp-z::before,
  :root .portfolio .pf-klapp-z::after {
    content: '';
    position: absolute;
    left: 50%; top: 50%;
    width: 11px; height: 1px;
    background: var(--ink);
    translate: -50% -50%;
    transition: rotate .36s var(--ease), opacity .3s var(--ease);
  }
  :root .portfolio .pf-klapp-z::after { rotate: 90deg; }
  :root .portfolio:not(.pf-zu) .pf-klapp-z::after { rotate: 0deg; opacity: 0; }
  :root .portfolio:not(.pf-zu) .pf-klapp-z {
    border-color: var(--linie-hell);
    background: rgba(255, 255, 255, .06);
  }
  /* Zugeklappt verschwindet der ganze Raum — nicht nur optisch: die vier
     `loading="lazy"`-Bilder werden dann gar nicht erst geholt. Das ist
     der zweite Grund für diese Zeile. */
  :root .portfolio.pf-zu .pf-raum { display: none; }
  /* Aufgeklappt braucht der Raum Luft zur Zeile — und die Karten treten
     einmal auf, damit die Zeile sichtbar etwas ausgelöst hat. */
  :root .portfolio:not(.pf-zu) .pf-raum { margin-top: 24px; }
  :root .portfolio:not(.pf-zu) .pf-karte { animation: pf-auftritt .42s var(--ease-aus) backwards; }
  :root .portfolio:not(.pf-zu) .pf-karte:nth-child(2) { animation-delay: .05s; }
  :root .portfolio:not(.pf-zu) .pf-karte:nth-child(3) { animation-delay: .1s; }
  :root .portfolio:not(.pf-zu) .pf-karte:nth-child(4) { animation-delay: .15s; }
  @media (prefers-reduced-motion: reduce) {
    :root .portfolio:not(.pf-zu) .pf-karte { animation: none; }
  }

  /* ══ 8 · FRAGEN ═══════════════════════════════════════════════════════
     Das Fragezeichen-Wesen ist eine eigene three.js-Bühne und stand mit
     rund 600 px Luft über einer Liste, die man auf dem Handy sofort
     lesen will. Es entfällt hier ganz — mobil.mjs nimmt dazu den
     Platzhalter aus dem Baum, damit das Modul three.js gar nicht erst
     lädt (fragen.mjs steigt ohne `.fq-platz` aus). Diese Regel ist die
     Sicherung für den Fall, dass das Skript nicht läuft. */
  :root .fragen .fq-platz,
  :root .fragen .fq-wesen { display: none; }
  :root .fragen .fq-raum { gap: 0; }
  :root .fragen .fq-liste { border-top: 1px solid var(--linie); }
  :root .fragen .fq-knopf {
    min-height: 56px;
    column-gap: 12px;
    padding: 14px 0;
    font-size: 1rem;
    line-height: 1.35;
  }
  :root .fragen .fq-nr {
    font-size: .64rem;
    letter-spacing: .16em;
  }
  /* Der Plus-Knopf ist ein Zeichen im Knopf, kein eigenes Ziel — die
     ganze Zeile schaltet. 44 px, damit er als Marke trotzdem trägt. */
  :root .fragen .fq-zeichen { width: 44px; height: 44px; }
  :root .fragen .fq-zeichen::before,
  :root .fragen .fq-zeichen::after { width: 13px; }
  :root .fragen .fq-antwort p {
    padding: 0 44px 20px 32px;
    font-size: .92rem;
  }

  /* ══ 9 · FUSSZEILE ════════════════════════════════════════════════════
     Kein Glaskasten, kein Stapel. Die erste Handy-Fassung (18.08. früh)
     legte Logo, zwei Kontaktzeilen, ein Zweispalten-Raster und eine
     Linkreihe untereinander — 430 px, vier Haarlinien, und nichts davon
     hatte eine Kante, an der das Auge sich festhalten konnte.

     Jetzt ein RASTER mit zwei Spalten und drei Registern:

        SPARWEB AGENCY ················· © 2026
        ─────────────────────────────────────
        info@sparweb-agentur.de ············ →
        0175 6601136 ······················· →
        ─────────────────────────────────────
        Care  Warum  Kosten  Empfehlen
        Impressum  Datenschutz  AGB  Widerruf

     Logo und © teilen sich die erste Zeile (das © wandert damit von ganz
     unten nach oben — der Fuß endet mit den Pflichtlinks, nicht mit einer
     Fußnote unter der Fußnote). Kontakt bekommt zwei volle Tippzeilen à
     48 px, weil sie die einzigen zwei Handlungen hier sind; der Pfeil am
     rechten Rand sagt „tippbar", ohne dass die Zeile zur Schaltfläche
     werden muss. Seiten und Rechtliches sind je EINE Reihe, die zweite
     kleiner und gedimmt — vier Wörter, die man selten sucht.

     Die Gruppen werden über ihr `aria-label` angesprochen — und das
     übersetzt en-index-erzeugen.mjs (Kontakt→Contact, Seiten→Pages,
     Rechtliches→Legal). Deshalb steht jede Gruppe mit BEIDEN Namen in
     `:is()`; die erste Fassung kannte nur die deutschen, und en/ zeigte
     den rohen Stapel.

     Das Raster braucht `grid-template-areas`, weil Logo und © nicht
     nebeneinander im DOM stehen — `order` reicht dafür nicht. */
  /* Die Fußzeile ist der BODEN des letzten Abteils, kein weiterer
     Absatz darin: sie rückt bis an dessen Kanten aus, wird eine Spur
     dunkler und nimmt unten die Rundung der Sektion auf (28 px minus
     der 1 px Rand). So endet die Seite mit einer Platte statt mit einer
     Liste, die im Nichts aufhört. */
  :root .fragen .fuss {
    margin: var(--m-sekt) calc(-1 * var(--m-innen)) calc(-1 * var(--m-sekt));
    padding: 0 var(--m-innen);
    border-top: 1px solid rgba(255, 255, 255, .06);
    border-radius: 0 0 27px 27px;
    background: rgba(0, 0, 0, .22);
  }
  :root .fragen .fuss-glas {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas:
      'logo   klein'
      'kontakt kontakt'
      'seiten seiten'
      'recht  recht';
    align-items: center;
    gap: 0;
    min-height: 0;
    padding: 20px 0 calc(16px + env(safe-area-inset-bottom));
    border: 0;
    border-top: 1px solid var(--linie);
    border-radius: 0;
    background: none;
    -webkit-backdrop-filter: none;
            backdrop-filter: none;
    box-shadow: none;
  }
  /* Der Schriftzug richtet seine zwei Wörter auf der Grundlinie aus
     (fragen.css) — in einem 44-px-Kasten steht die Zeile dann oben, das
     © daneben aber mittig. `flex-wrap` + `align-content` holen die
     Zeile in die Mitte, ohne die Grundlinie zwischen SPARWEB und AGENCY
     aufzugeben (derselbe Griff wie in fragen.css bei 640 px). */
  :root .fragen .fuss-logo {
    grid-area: logo;
    flex-wrap: wrap;
    align-content: center;
    min-height: 44px;
    margin: 0;
    font-size: .8rem;
    letter-spacing: .16em;
  }
  :root .fragen .fuss-klein {
    grid-area: klein;
    margin: 0;
    font-size: .68rem;
    letter-spacing: .04em;
    white-space: nowrap;
    color: var(--ink-dim);
    opacity: .8;
  }
  :root .fragen .fuss-gruppe::before { display: none; }

  /* Kontakt: zwei Zeilen, jede voll tippbar, mit Pfeil am rechten Rand.
     Ein Register mit Linie oben und unten — die einzige Stelle im Fuß,
     die HANDELN will, und deshalb die einzige mit Rahmen. */
  :root .fragen .fuss-gruppe:is([aria-label="Kontakt"], [aria-label="Contact"]) {
    grid-area: kontakt;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    margin: 12px 0 8px;
    border-top: 1px solid var(--linie);
    border-bottom: 1px solid var(--linie);
  }
  :root .fragen .fuss-gruppe:is([aria-label="Kontakt"], [aria-label="Contact"]) a {
    display: flex;
    align-items: center;
    justify-content: space-between;
    min-height: 48px;
    font-size: .98rem;
    letter-spacing: 0;
    color: var(--ink);
    -webkit-tap-highlight-color: transparent;
    touch-action: manipulation;
  }
  :root .fragen .fuss-gruppe:is([aria-label="Kontakt"], [aria-label="Contact"]) a + a {
    border-top: 1px solid var(--linie);
  }
  :root .fragen .fuss-gruppe:is([aria-label="Kontakt"], [aria-label="Contact"]) a::after {
    content: '→';
    margin-left: 12px;
    font-size: .95em;
    color: var(--ink-dim);
    opacity: .7;
  }

  /* Seiten: EINE Reihe. Vier kurze Wörter passen in 342 px; die
     Trefferfläche kommt aus der Zeilenhöhe (44 px), nicht aus Rändern,
     damit die Reihe optisch schlank bleibt. Bricht sie doch um, bricht
     sie sauber (row-gap 0). */
  :root .fragen .fuss-gruppe:is([aria-label="Seiten"], [aria-label="Pages"]) {
    grid-area: seiten;
    display: flex;
    flex-wrap: wrap;
    gap: 0 22px;
    margin: 0;
    padding: 0;
    border: 0;
  }
  :root .fragen .fuss-gruppe:is([aria-label="Seiten"], [aria-label="Pages"]) a {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    font-size: .88rem;
    color: var(--ink);
    -webkit-tap-highlight-color: transparent;
    touch-action: manipulation;
  }
  /* Rechtliches: dieselbe Reihe, kleiner und gedimmt. Vier Pflichtlinks,
     die man selten sucht und nie vergleicht — sie tragen den Fuß aus,
     sie tragen ihn nicht. */
  :root .fragen .fuss-gruppe:is([aria-label="Rechtliches"], [aria-label="Legal"]) {
    grid-area: recht;
    display: flex;
    flex-wrap: wrap;
    gap: 0 18px;
    margin: 0;
    padding: 0;
    border: 0;
  }
  :root .fragen .fuss-gruppe:is([aria-label="Rechtliches"], [aria-label="Legal"]) a {
    min-height: 40px;
    display: inline-flex;
    align-items: center;
    font-size: .74rem;
    color: var(--ink-dim);
    -webkit-tap-highlight-color: transparent;
    touch-action: manipulation;
  }
  /* ══ 10 · BEWEGUNG ════════════════════════════════════════════════════
     Genau EIN Bewegungsmoment je Handlung — das Blatt gleitet. Wer
     Bewegung abbestellt hat, bekommt das Ziel ohne den Weg. */
  @media (prefers-reduced-motion: reduce) {
    :root.kompakt .kopf-liste { transition: none; translate: none; }
  }
}

/* Der Auftritt der Portfolio-Karten beim Aufklappen. Die Keyframes
   stehen AUSSERHALB der Media Query — drinnen definiert wären sie
   in manchen Browsern an sie gebunden, und ein `@keyframes`, das nur
   unter Bedingungen existiert, ist eine Falle, keine Regel. Benutzt
   werden sie ohnehin nur von einer Klasse, die es nur hier gibt. */
@keyframes pf-auftritt {
  from { opacity: 0; translate: 0 14px; }
  to   { opacity: 1; translate: 0 0; }
}
