/* ── Farben ──────────────────────────────────────────────────────
   Die Palette stammt NICHT aus der Design-Referenz, sondern aus dem
   Produkt: jeder Wert unten ist ein Token aus TveTheme des tveDataGrid-
   Repos, damit Website und Grid dieselben Farben tragen statt zweier
   Auslegungen derselben Marke. Struktur, Radien, Pillen und Karten
   kommen weiter von Wiza — nur die Farbwerte nicht, und die Kopfzeile
   nicht (siehe .site-header).
   Hell = TveTheme.Light(). */
:root {
  --bg:#f4f4f7;            /* Background */
  --bg-soft:#e8e8ee;       /* HeaderFill */
  --surface:#ffffff;       /* RowEven */
  --fg:#1c1c22;            /* Text */
  --muted:#6c6c78;         /* TextDim */
  --line:#d9d9e0;          /* GridLine — Haarlinien im Inhalt */
  --border:#c6c9d3;        /* CardBorder — Karten und Panels */
  --row-hover:#d9e5f5;     /* RowHover */
  --accent:#2e5a8d;        /* Accent */
  --accent-hover:#22446b;  /* AccentDeep */
  --accent-ink:#fafafc;    /* ChipText */
  --accent-soft:#dee8f5;   /* AccentTint */
  --info:#2e5a8d;          /* Blue  — „Offen" */
  --ok:#276b3d;            /* Green — „Erledigt" */
  --warn:#9a6a14;          /* Amber — „In Arbeit" */
  --chip-ink:#fafafc;      /* ChipText */
  /* Wiza: flache Flächen, weiche Schatten für Höhe. */
  --shadow:0 1px 2px rgba(28,28,34,.06), 0 4px 12px rgba(28,28,34,.07);
  --shadow-lg:0 2px 6px rgba(28,28,34,.06), 0 18px 40px rgba(28,28,34,.13);
  --radius:16px;
  /* ── Maße nach der designr-Referenz *Impeccable* ─────────────────
     Dort ist die Seite keine mittige Spalte, sondern eine breite BÜHNE
     (gemessen: ~1300px Inhalt bei 44px Rand), auf der die Blöcke links
     am Rand hängen. Lesbar bleibt es, weil der Text darauf NICHT
     mitwächst: die Fließspalte steht bei ~545px, also unverändert bei
     rund 64 Zeichen. Genau diese Trennung — weite Bühne, schmale
     Spalte — ist der Grund, warum die Seite luftig wirkt, ohne dass
     eine Zeile zu lang würde.
     --page-max deckelt Band UND <main>, damit beide fluchten;
     --content-max ist die Breite der gewöhnlichen Blöcke darunter und
     entspricht der bisherigen Inhaltsbreite (880 minus Rand). */
  --page-max:1360px; --content-max:52rem; --gutter:2.75rem;
  /* Der einzige zweite Schriftstapel der Website, und er ist ebenfalls vom
     System — eine selbst gehostete Datei wäre erlaubt, eine von einem fremden
     Server nicht (siehe DESIGN.md, „Typografie"). Er trägt zwei Dinge in der
     Dokumentation: die Quelltextblöcke, und die kleinen gesperrten
     Großbuchstaben-Beschriftungen (Bandüberschriften, Dateinamen über einem
     Block, „Previous"/„Next"). Beide sind aus *Impeccable* — dort ist das
     Etikett „uppercase mono, tracked" die durchgehende Kleinschrift der Seite.
     Ein Etikett in derselben Schrift wie der Fließtext wäre nur kleiner Text. */
  --mono:"JetBrains Mono",ui-monospace,"Cascadia Mono","SF Mono",Menlo,Consolas,monospace;
  --sans:"Inter",system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
  /* Zeichenketten in Quelltextbloecken. Im Hellen ist das --ok; im Dunkeln liegt
     --ok (#2e7d46) auf --bg-soft bei 3,4:1 und reisst WCAG AA, deshalb dort ein
     eigener, hellerer Ton (7,9:1). Der einzige Farbwert, der nicht aus ArionTheme
     stammt - er traegt keine Flaeche, nur Schrift in einem Codeblock. */
  --code-str:#276b3d;
  /* Höhe des Kopfbands — nur der AUSGANGSWERT. Den wahren Wert misst
     nav-fit.js vor dem ersten Paint und schreibt ihn auf <html>; der Grund
     des Aufmachers steigt genau um Band plus Kopfluft nach oben aus, und
     dieser Abstand hängt an Schriftgröße, Zoom und Umbruch der Leiste.
     Hier steht deshalb nur, was ohne Skript gelten soll: die Höhe, die sich
     aus Polsterung und Wortmarke ergibt (gemessen 71,4px, aufgerundet). */
  --header-h:4.5rem;
}
/* Wizas „gradient mesh" (weiche Farbwolken in den Ecken) ist bewusst NICHT
   übernommen: auf einer Seite, deren Aufmacher ein Datenraster ist, stört
   ein wandernder Farbverlauf hinter den Zeilen mehr, als er trägt. Der
   Grund bleibt eine ruhige Fläche. */
/* Dunkel: automatisch nach System, es sei denn, der Besucher hat explizit
   hell gewählt (data-theme="light" auf <html>, gesetzt vom Umschalter). */
/* Dunkel = TveTheme.Dark(), Token für Token — mit zwei begründeten Ausnahmen.

   ERSTENS die Verlinkungsfarbe: das Produkt setzt Accent = #2E5A8D auch im
   Dunkeln, dort aber als FLÄCHE (Auswahl, Chips). Als Verlinkungsfarbe auf
   dem dunklen Grund käme es auf 2,5:1 und wäre unlesbar. Deshalb steht hier
   FocusBorder (#5B9BE6) als --accent — ebenfalls ein Token des Produkts,
   für genau diese Rolle gedacht, und mit über 6:1 lesbar. Als Fläche bleibt
   #2E5A8D über --info erhalten.

   ZWEITENS --bg-soft: das Produkt setzt HeaderFill = Background (#15151a), die
   Website braucht fuer Mulden und Codebloecke aber eine Stufe UEBER dem Grund,
   sonst verschwinden sie. Deshalb #1f1f27 (+10 Stufen). --bg (#15151a) und
   --surface (#1b1b21, RowEven) sind seit dem Umbau vom 2026-10-03 wieder die
   Werte des Produkts: der Grund aus dem Hintergrundbild, der sie vorher
   dunkler zog, ist mit dem JPG entfallen. Das Datenband ist seitdem eine Maske
   ohne eigenen Grund (siehe .hero-bleed in Components) und zieht nichts nach.

   Text, Linien, Ränder und Akzente bleiben unverändert; auf dem dunkleren
   Grund steigt ihr Kontrast, keiner fällt. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg:#15151a; --bg-soft:#1f1f27; --surface:#1b1b21;
    --fg:#e6e6ea; --muted:#9a9aa6;
    --line:#33333d; --border:#3e3e4a; --row-hover:#303e59;
    --accent:#5b9be6; --accent-hover:#8bb8ee; --accent-ink:#0e0e11; --accent-soft:#1f2c40;
    --info:#2e5a8d; --ok:#2e7d46; --warn:#b07a1e; --chip-ink:#f0f0f4; --code-str:#6fbf85;
    --shadow:0 1px 2px rgba(0,0,0,.35), 0 4px 12px rgba(0,0,0,.30);
    --shadow-lg:0 2px 6px rgba(0,0,0,.40), 0 18px 40px rgba(0,0,0,.45);
  }
}
/* Dunkel erzwungen (Umschalter), unabhängig vom System. */
:root[data-theme="dark"] {
  --bg:#15151a; --bg-soft:#1f1f27; --surface:#1b1b21;
  --fg:#e6e6ea; --muted:#9a9aa6;
  --line:#33333d; --border:#3e3e4a; --row-hover:#303e59;
  --accent:#5b9be6; --accent-hover:#8bb8ee; --accent-ink:#0e0e11; --accent-soft:#1f2c40;
  --info:#2e5a8d; --ok:#2e7d46; --warn:#b07a1e; --chip-ink:#f0f0f4; --code-str:#6fbf85;
  --shadow:0 1px 2px rgba(0,0,0,.35), 0 4px 12px rgba(0,0,0,.30);
  --shadow-lg:0 2px 6px rgba(0,0,0,.40), 0 18px 40px rgba(0,0,0,.45);
}
/* ── Schriften: selbst gehostet ────────────────────────────────────
   Entscheid vom 2026-10-03: Web-Fonts ja, aber nur vom eigenen Server. Die
   Cookiefreiheit bleibt (kein fremder Request); die Dateien liegen unter
   wwwroot/fonts, fingerprintet wie jedes Asset, mit den OFL-Lizenztexten daneben.
   Inter als variable Schrift (wght 300-700, opsz 14-32, Latin-Subset, 66 kB),
   JetBrains Mono in 400 und 600 - dieselbe Schrift, die das Produkt in seinen
   Zellen einbettet. font-display:swap - lieber kurz Systemschrift als leere Zeilen. */
@font-face { font-family:"Inter"; font-style:normal; font-weight:300 700;
             font-display:swap; src:url("/assets/Inter-var.00c2f75e.woff2") format("woff2"); }
@font-face { font-family:"JetBrains Mono"; font-style:normal; font-weight:400;
             font-display:swap; src:url("/assets/JetBrainsMono-Regular.df771492.woff2") format("woff2"); }
@font-face { font-family:"JetBrains Mono"; font-style:normal; font-weight:600;
             font-display:swap; src:url("/assets/JetBrainsMono-SemiBold.f6eaea85.woff2") format("woff2"); }
* { box-sizing:border-box; }
html { -webkit-text-size-adjust:100%; }
/* 16px/1.62 statt 15.5px/1.55 — gemessen aus Impeccables Fließtext
   (16px auf 26px Zeilenabstand). Der eine halbe Punkt mehr fällt kaum
   auf, der offenere Zeilenabstand trägt die luftige Wirkung mit. */
body { margin:0; font-family:var(--sans); font-optical-sizing:auto;
       color:var(--fg); background:var(--bg); line-height:1.62; font-size:16px;
       /* Seite füllt mindestens den Viewport, main wächst — damit kurzer
          Inhalt nicht auf halber Höhe endet. */
       min-height:100vh; min-height:100dvh; display:flex; flex-direction:column;
       /* Der Grund des Aufmachers geht über 100vw von Kante zu Kante, und 100vw
          zählt die Bildlaufleiste mit — ohne diese Zeile bekäme die Seite dadurch
          eine waagerechte Laufleiste. clip statt hidden: hidden machte den body zum
          Scroll-Container und nähme der Kopfzeile ihr sticky. */
       overflow-x:clip; }
/* Wiza ist typografisch bewusst unauffällig — „the interest is entirely
   structural". Die Überschrift ist halbfett und leicht eng, mehr nicht;
   die Wirkung soll aus Karten, Pillen und der Tabelle kommen. */
/* Impeccables Überschrift ist groß, LEICHT und eng geführt (gemessen:
   68px auf 78px Zeilenabstand, Strichstärke light) — nicht halbfett.
   Zwei Dinge werden dabei bewusst nicht 1:1 übernommen:

   - Die Schrift. Die Referenz setzt eine schmallaufende Geometrische;
     eine solche Datei gäbe es hier nur als Fremd-Request, und der ist
     ausgeschlossen (siehe DESIGN.md). Es bleibt beim Systemstapel.
   - Die Größe. 68px gelten für eine SCHMALE Schrift: in Impeccables
     545px-Spalte passen damit rund 24 Zeichen pro Zeile. Dieselben 68px
     in einer normal laufenden Systemschrift ergäben acht. Übernommen
     wird deshalb die Zeichenzahl, nicht die Punktzahl — ~48px treffen
     sie. Wer hier hochdreht, bekommt keine Referenz, sondern Stückwerk. */
/* Seit Inter (2026-10-03) halbfett statt leicht: eine 300er Systemschrift las
   sich duenn, Inter 600 mit enger Laufweite traegt die Ueberschrift wie eine
   Marke. Die Groesse haelt weiter die Zeichenzahl der Referenz, nicht die Punkte. */
h1 { font-size:clamp(2.3rem, 3.6vw, 3.25rem); font-weight:600; letter-spacing:-.035em;
     line-height:1.06; margin:.3rem 0 .7rem; }
/* Der Abschnittsabstand wächst mit: in der Referenz stehen die Blöcke
   deutlich weiter auseinander als der Absatzfluss. */
h2 { font-size:1.5rem; font-weight:600; margin:4rem 0 1rem;
     letter-spacing:-.025em; line-height:1.2; }
h3 { font-size:1rem; margin:1.2rem 0 .4rem; }
/* Verankerte Überschriften (die Dokumentation setzt die Anker beim Bauen, siehe
   DocsOutline) landen sonst UNTER dem klebenden Kopfband: der Sprung scrollt sie
   auf Position 0, und dort liegt das Band. Bandhöhe plus Luft — dieselbe
   gemessene Variable, die auch der Grund des Aufmachers benutzt. */
:where(h2, h3)[id] { scroll-margin-top:calc(var(--header-h) + 1.5rem); }
h1, h2, h3, h4, p, li, dd, dt { overflow-wrap:break-word; }
a { color:var(--accent); }
.muted { color:var(--muted); font-size:.9rem; }
:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }
@media (max-width:560px) { h1 { font-size:1.95rem; } }

/* ── Seiteninhalt ────────────────────────────────────────────────
   Grundtypografie für semantische Elemente. Die Bausteine (Karte,
   Produktvorschau, Pillen) stehen in Components — hier steht nur, wie
   gewöhnliches Markup aussieht. */
main p { max-width:64ch; }
/* ol steht daneben, seit die Dokumentation eine Rangfolge aufzählt. Ohne diese
   Zeile bekäme sie die 40px Browser-Vorgabe und liefe als einzige Liste der
   Website weiter eingerückt als alle anderen. */
main ul, main ol { padding-left:1.1rem; margin:1rem 0; }
main li { margin:.35rem 0; max-width:62ch; }

/* Wizas Menümuster, hier für die Ansichtenliste: halbfettes Label, darunter
   eine graue einzeilige Erklärung. Das ist es, was eine lange Liste
   überhaupt überfliegbar macht. */
main dl { margin:1.1rem 0 0; }
main dt { font-weight:650; margin-top:1.1rem; }
main dd { margin:.15rem 0 0; max-width:62ch; color:var(--muted); }

/* ── Quelltext ───────────────────────────────────────────────────
   Gewöhnliches Markup, also der Rahmen und nicht der Baukasten: `pre` und
   `code` stehen hier neben `p`, `ul` und `table`. Was die Dokumentation
   darum herum baut (das Etikett mit dem Dateinamen, der Merkkasten), steht
   als Klasse in Components.

   OHNE FARBIGE HERVORHEBUNG, und das ist eine Entscheidung. Sie kostete
   entweder ein Skript beim Besucher (die Seite lädt bewusst nichts nach)
   oder einen C#-Tokenizer im Generator — beides für einen Effekt, den
   *Impeccable* gar nicht kennt: die Referenz führt genau einen Akzent, und
   ihre Codezeilen sind einfarbige Mono-Etiketten. Fünf Farben in einem
   Block wären hier der lauteste Fleck der ganzen Website, auf einer Seite,
   die sonst mit zwei Tönen und einer Haarlinie auskommt.

   Waagerecht gescrollt statt umgebrochen: eine umbrechende Signatur liest
   sich als zwei Anweisungen. overflow-x auf dem Block selbst, damit die
   Seite dabei stehen bleibt (body klippt waagerecht, siehe oben). */
main pre { margin:1.15rem 0 0; padding:1rem 1.15rem; overflow-x:auto;
           background:var(--bg-soft); border:1px solid var(--line);
           border-radius:10px; }
main pre, main code { font-family:var(--mono); font-size:.85rem;
                      line-height:1.62;
                      /* Keine Programmier-Ligaturen: aus => wuerde ein Pfeil, und
                         ein Codeblock zeigt Zeichen, nicht Glyphen. Das Produkt
                         schaltet sie in seinen Zellen aus demselben Grund ab. */
                      font-variant-ligatures:none; }
/* Im Fließtext ist `code` ein Wort und kein Block: getönt und knapp gefasst,
   damit es in der Zeile stehen bleibt statt sie aufzureißen. `em` statt
   `rem`, weil es sich der Größe seiner Umgebung anpassen soll — in einer
   Bildunterschrift ist der Fließtextwert zu groß. */
main :not(pre) > code { font-size:.88em; padding:.1em .36em;
                        border:1px solid var(--line); border-radius:4px;
                        background:var(--bg-soft); }
/* Tasten in der Doku (Strg+C, F2): wie `code` getönt, unten eine Spur kräftiger
   gerahmt - die eine Andeutung einer Taste, die ohne Schatten und Verlauf auskommt. */
main kbd { font-family:var(--mono); font-size:.82em; padding:.05em .38em;
           border:1px solid var(--line); border-bottom-width:2px; border-radius:4px;
           background:var(--bg-soft); white-space:nowrap; }
/* Im Block trägt der Block schon Fläche und Rahmen — das Wort darin braucht
   beides nicht noch einmal. */
main pre code { padding:0; border:0; background:none; font-size:inherit; }
/* Hervorhebung, beim Bauen gesetzt (CodeHighlighter): DREI Farben, nicht fuenf.
   Schluesselwoerter im Akzent, Zeichenketten in --code-str, Kommentare gedaempft;
   Zahlen und Typnamen bleiben Tinte. Das ist die Grenze, ab der ein Block lauter
   wuerde als die Seite um ihn herum. */
.tok-k { color:var(--accent); }
.tok-s { color:var(--code-str); }
.tok-c { color:var(--muted); font-style:italic; }

/* Messwerte-Tabelle: helle Haarlinien, keine harten Kanten — sie sitzt in
   einer Karte und soll deren Ruhe nicht zerschneiden. */
main table { width:100%; border-collapse:collapse; margin:1rem 0 0; }
main th, main td { text-align:left; padding:.62rem .1rem; vertical-align:top;
                   border-bottom:1px solid var(--line); }
main thead th { font-size:.72rem; font-weight:600; color:var(--muted);
                text-transform:uppercase; letter-spacing:.06em; }
main tbody th { font-weight:400; }
main tbody td { font-variant-numeric:tabular-nums; font-weight:600; }
main tbody tr:last-child th, main tbody tr:last-child td { border-bottom:0; }

/* Die Bühne. Sie ist breit, ihr Inhalt ist es nicht: die Blöcke hängen
   linksbündig am Rand und hören bei --content-max auf. Impeccable
   zentriert nichts — alles fluchtet an derselben linken Kante, von der
   Wortmarke im Band über die Überschrift bis zum letzten Absatz. Das
   ist der eigentliche Unterschied zur bisherigen mittigen Spalte, und
   wer statt dessen wieder `margin-inline:auto` setzt, bekommt die alte
   Seite auf einer breiteren Bühne zurück. */
main { max-width:var(--page-max); margin:0 auto;
       padding:4.5rem var(--gutter) 5rem;
       flex:1 0 auto; width:100%; }
/* Gilt für die gewöhnlichen Blöcke jeder Seite. Was breiter sein soll —
   der zweispaltige Aufmacher samt seinem Grund — setzt sich per Klasse
   darüber hinweg (höhere Spezifität, siehe .hero-bleed und .hero-split
   in Components). */
main > * { max-width:var(--content-max); }

/* Sprungmarke für Tastatur und Screenreader — sichtbar nur bei Fokus. */
.skip-link { position:absolute; left:-9999px; top:0; z-index:100;
             background:var(--accent); color:var(--accent-ink);
             padding:.6rem 1rem; border-radius:var(--radius); text-decoration:none; }
.skip-link:focus { left:0; }

/* ── Kopfzeile ──────────────────────────────────────────────────── */
/* Bewusst gegen Wizas schwebende Pille — und das ist eine Abweichung von
   der Referenz, keine Nachlässigkeit. Eine Pille in Inhaltsbreite ist
   dasselbe Gebilde wie die Karten und der Produktumschalter darunter:
   gerundeter Kasten, 1px Rand, mittig auf dem Grund. Sie wird damit zur
   obersten Karte statt zur Navigation, und auf /pricing standen zwei
   solche Pillen mit gefüllter Auswahl direkt übereinander.

   Die Kopfzeile ist deshalb keine Fläche mehr, sondern Struktur: ein Band
   über die volle Breite, unten von einer Haarlinie begrenzt, ohne Rundung,
   ohne Rahmen, ohne Schatten. Nichts in der Inhaltsspalte darf so aussehen
   — daran erkennt man sie als Seitenrahmen. Das Prinzip stammt aus der
   designr-Referenz *Primora*: Hierarchie entsteht dort aus gezeichneten
   Linien statt aus weiteren Behältern.

   Am Seitenanfang ist die Linie allerdings gegenstandslos: darunter beginnt
   unmittelbar der Aufmacher auf demselben Grund, es gibt nichts abzugrenzen.
   Sie ist deshalb transparent gesetzt — nicht weggelassen, sonst spränge die
   Seite um 1px, sobald sie erscheint.

   Dasselbe gilt seit dem Datenband für die FLÄCHE: am Seitenanfang ist das Band
   durchsichtig, damit der Grund des Aufmachers bis an die Oberkante durchläuft
   (siehe .hero-bleed in Components). Ein Kopfband in --bg schnitte dort einen
   hellen Streifen aus dem Bild. Auf jeder anderen Seite ändert das nichts: --bg
   liegt hinter dem Band ohnehin. */
/* Die FLÄCHE ist kein Zustand mehr, sondern eine Strecke: --header-fill läuft von
   0 (ganz oben) bis 1 (ab --header-fill-dist Pixeln), gesetzt von layout.js auf
   jedem Scroll-Frame. Vorher schaltete .scrolled sie an einem einzigen Pixel um und
   der Übergang blendete sie in einer festen Zeit ein — das las sich als Zuschnappen,
   das man abwartet, statt als etwas, das man selbst tut. Am Scrollweg festgemacht
   gehört das Zuziehen dem Besucher: er hält an, und es hält mit an.

   Deshalb liegt background-color NICHT mehr in der transition. Ein Übergang auf
   einem Wert, der sich ohnehin jeden Frame ändert, schleppt nur hinterher.
   Haarlinie und Schatten bleiben dagegen Zustand — sie sagen "da liegt etwas unter
   dem Band", und das ist eine Ja/Nein-Aussage, kein Maß; sie blenden weiter über
   --header-fade ein.

   color-mix statt zweier Farben: --bg bleibt die eine Quelle, die Deckung kommt als
   Prozentsatz dazu. Ohne Skript legt das <noscript> in Shell.razor die Farbe direkt
   auf das Band — nicht über --header-fill, denn die Variable wirkt erst durch dieses
   color-mix hier, und genau das ist im Rückfall unten ja weg. Lesbarkeit vor
   Verzierung, wie bisher. */
.site-header { --header-fade:.55s; --header-fill:0;
               position:sticky; top:0; z-index:10;
               background-color:color-mix(in srgb,
                                          var(--bg) calc(var(--header-fill) * 100%),
                                          transparent);
               border-bottom:1px solid transparent;
               transition:box-shadow var(--header-fade) ease,
                          border-color var(--header-fade) ease; }
/* Erst wenn Inhalt unter das Band wegscrollt, wird die Abgrenzung wahr: Haarlinie
   und flacher Schatten belegen, dass da noch etwas liegt. Die Fläche kommt nicht
   mehr hier dazu, sondern über --header-fill (oben) — sie ist zu diesem Zeitpunkt
   ohnehin erst angefangen. */
.site-header.scrolled { border-bottom-color:var(--line); box-shadow:var(--shadow); }
/* Ohne color-mix wäre die background-color-Deklaration oben ungültig und das Band
   bliebe beim Scrollen durchsichtig — dann lieber wieder die harte Umschaltung am
   ersten Scrollpixel als Menüpunkte, durch die der Inhalt läuft. */
@supports not (background-color:color-mix(in srgb, red 50%, transparent)) {
  .site-header.scrolled { background-color:var(--bg); }
}
/* Auf jeder Seite OHNE Aufmacher steht die Haarlinie dagegen von Anfang an: dort
   beginnt unter dem Band kein durchlaufender Grund, sondern der Inhalt einer Seite,
   und die Linie ist der Schnitt zwischen Rahmen und Inhalt. Was oben über die
   gegenstandslose Linie steht, gilt nur für die Startseite — sie ist die einzige
   Seite, unter der es nichts abzugrenzen gibt. Schatten und Fläche bleiben am
   Scrollen hängen: dass etwas UNTER dem Band liegt, ist eine andere Aussage als
   dass das Band aufhört.

   .has-hero und nicht :has(.hero-bleed): der Aufmacher steht in <main> und ist noch
   nicht da, während das Kopfband schon gerendert wird. :has() sah in dieser Zeit
   keinen Aufmacher, diese Regel griff also auch auf der Startseite — die Linie
   blitzte bei jedem Laden auf und blendete weg, sobald <main> ankam. Die Klasse
   setzt Shell.razor ans <body>; sie steht vor dem Kopfband und ist ab dem ersten
   Byte wahr. */
body:not(.has-hero) .site-header { border-bottom-color:var(--line); }
/* Umgekehrt bekommt die Startseite dafür etwas, das keine andere Seite hat: eine
   Milchscheibe, solange das Band WEDER durchsichtig NOCH deckend ist. Nur dort liegt
   hinter dem Band ein Bild (siehe .hero-bleed in Components), und nur solange man
   durch das Band hindurchsieht, ist da überhaupt etwas zu beruhigen: ein halb
   durchsichtiges Band vor einem Bild ist genau die Stelle, an der die Menüpunkte
   unruhig werden. Die Scheibe nimmt dem Bild dann die Schärfe, nicht die Anwesenheit;
   saturate zieht die Farbe nach, die die Unschärfe auswäscht.

   An BEIDEN Enden gibt es sie nicht, und das ist derselbe Gedanke zweimal: ganz oben
   ist das Band klar, weil der Grund des Aufmachers ungebrochen bis an die Oberkante
   laufen soll; ganz zugezogen ist es deckend, und hinter einer deckenden Fläche gibt
   es nichts mehr zu verwischen. --header-frost ist deshalb ein Dach über der
   Strecke — von layout.js als min(fill, 1-fill)*2 gesetzt, also 0 an beiden Enden
   und 1 in der Mitte. Die Scheibe gehört dem Weg, nicht den Haltestellen.

   .frosting ist derselbe Sachverhalt als Klasse, damit backdrop-filter an den Enden
   nicht bloß auf blur(0) steht, sondern GAR nicht: ein Filter mit Radius null kostet
   auf jedem Scroll-Frame trotzdem Compositing.

   Erkannt wird die Seite auch hier an dem, was den Unterschied ausmacht, und nicht
   an ihrem Pfad — .has-hero heißt "hinter diesem Band liegt ein Bild" und wird beim
   Bauen aus dem Markup abgelesen (siehe Shell.razor). Fehlt backdrop-filter, fällt
   die Verzierung weg und die Regeln oben bleiben stehen; getragen wird die
   Lesbarkeit von der Fläche, nicht von der Scheibe. */
@supports ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))) {
  body.has-hero .site-header.frosting {
    -webkit-backdrop-filter:blur(calc(8px * var(--header-frost, 0)))
                            saturate(calc(1 + .3 * var(--header-frost, 0)));
            backdrop-filter:blur(calc(8px * var(--header-frost, 0)))
                            saturate(calc(1 + .3 * var(--header-frost, 0)));
  }
}
/* Das Band läuft von Kante zu Kante, sein Inhalt fluchtet mit der
   Inhaltsspalte — gleiche Deckelung und Polsterung wie <main>. */
/* Impeccables Band ist deutlich höher als das bisherige (gemessen: rund
   80px statt 54) und die Polsterung ist dieselbe wie die der Bühne —
   Wortmarke und Überschrift stehen dadurch auf derselben Kante.
   Der gap hier ist der ENGE Abstand der Bedienknöpfe rechts (~18px);
   die weiten 40px zwischen den Menüpunkten stehen weiter unten an den
   Punkten selbst. */
.header-inner { max-width:var(--page-max); margin:0 auto;
                display:flex; align-items:center; gap:1.15rem;
                padding:1rem var(--gutter); flex-wrap:wrap; }
.brand { display:flex; align-items:center; gap:.55rem; font-weight:700;
         font-size:1.06rem; color:var(--fg); text-decoration:none; letter-spacing:-.01em; }
/* Die Wortmarke ist ein Bild, kein Text: Hoehe gesetzt, Breite frei — so
   bestimmt das Band die Groesse und nicht die Bilddatei. width/height stehen
   trotzdem im Markup, damit der Platz vor dem Laden schon steht und die
   Leiste nicht springt (nav-fit misst sie direkt danach aus).

   Die Datei ist vorbereitet, nicht roh uebernommen: die Vorlage lag als
   Zeichen auf REINEM Schwarz in einem 1536x1024-Rahmen und fuellte davon
   rund ein Fuenftel. Zwei Schritte daher vor dem Ablegen — Schwarz zu
   Transparenz freigestellt (sonst steht im hellen Schema ein schwarzer
   Kasten im Band) und auf das Zeichen beschnitten (sonst kaeme von jeder
   hier gesetzten Hoehe nur ein Bruchteil beim Zeichen an). */
.brand-logo { display:block; height:2.4rem; width:auto; }
@media (max-width:560px) { .brand-logo { height:2rem; } }
/* EINE Datei fuer beide Schemata. Vorher lagen zwei im Markup und die
   verborgene wurde per display:none weggeschaltet — Browser laden ein
   solches Bild trotzdem, jeder Besucher im hellen Schema zog also 159 kB
   fuer ein Zeichen, das er nie zu sehen bekam.
   Im Dunkeln wird die helle Fassung deshalb gerechnet statt geladen:

   - invert dreht die Tinte #121b28 nach #ede4d7 — eine warme Creme, denn
     invert dreht mit der Helligkeit auch den Farbton (Marineblau -> Sand);
   - grayscale nimmt ihn wieder heraus (#e5e5e5). Das hue-rotate(180deg),
     das beim Hintergrundbild den Blaustich zurueckholt, ist hier FALSCH:
     der Grund dort ist fast neutral und bewegt sich kaum, die Tinte hier
     ist gesaettigt und landete bei #dde6f3, also sichtbar blau;
   - brightness(1.055) hebt das Ergebnis auf #f2f2f2 — das ist der Ton der
     abgeloesten Datei (#f1f3f5), auf ein Pixel genau neutral statt leicht
     kuehl. In Wortmarkengroesse ist das nicht zu unterscheiden.

   Die Rechnung gilt fuer eine ZWEITONIGE Marke. Bekommt die Wortmarke je
   eine zweite Farbe, faellt sie mit grayscale in sich zusammen — dann
   gehoert die dunkle Fassung als eigene Datei zurueck. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .brand-logo {
    filter:invert(1) grayscale(1) brightness(1.055);
  }
}
:root[data-theme="dark"] .brand-logo { filter:invert(1) grayscale(1) brightness(1.055); }
:root[data-theme="light"] .brand-logo { filter:none; }
/* Der kurze Strich hinter der Marke ist mit Impeccables Aufteilung
   entfallen — dort steht neben der Wortmarke gar nichts mehr, was zu
   trennen wäre: die Menüpunkte sind ans andere Ende gerückt. Eine
   Trennung, die nichts trennt, ist nur noch ein Strich. (In der
   Referenz sieht man im Band eine senkrechte Linie; sie gehört zum
   Fadenkreuz des Hintergrundbildes, nicht zur Navigation.) */
/* Die Steuerknöpfe bleiben rund, weil sie Knöpfe sind — die Struktur um
   sie herum ist eckig, und der Gegensatz ist gewollt: Band und Haarlinie
   sind Rahmen, alles Rundgelutschte darin ist Bedienung. */
.theme-toggle, .icon-link, .nav-burger, .lang-menu summary { border-radius:999px; }
.site-header .nav-list a, .nav-menu-panel a, .lang-list a { border-radius:10px; }
.site-header nav { display:flex; align-items:center; gap:1.35rem; flex-wrap:wrap; }
.site-header nav a { color:var(--fg); text-decoration:none; font-size:.92rem; }
.site-header nav a:hover { color:var(--accent); }
/* Im Burger-Blatt bleibt der aktive Punkt eine Fläche — dort ist die Liste
   tatsächlich ein Menü, und eine getönte Zeile ist die richtige Antwort.
   In der Leiste dagegen nicht: die gefüllte Pille ist das Zeichen des
   Produktumschalters auf /pricing, und zwei davon übereinander waren der
   Grund, warum die Kopfzeile wie Inhalt aussah. Dort markiert ein Strich
   (siehe unten). Bewusst ohne font-weight — fett änderte die Breite des
   Labels, und die Leiste müsste bei jedem Seitenwechsel anders vermessen
   werden (siehe NAV_FIT_JS). Auf .nav-list eingegrenzt, damit die
   Sprachliste ihre eigene Auszeichnung behält. */
.site-header .nav-list a.active { background:var(--accent-soft); color:var(--accent); }
/* Der Auslöser des Untermenüs trägt dieselbe Auszeichnung wie die Textlinks
   — er ist ein Menüpunkt und darf nicht als einziger aus der Reihe fallen. */
.nav-expanded .nav-menu-trigger { padding:.85rem 0; border-radius:0;
                                  border-bottom:2px solid transparent;
                                  color:var(--muted);
                                  transition:color .12s, border-color .12s; }
/* Beim Überfahren passiert genau das, was auch bei jedem anderen Menüpunkt
   passiert: das Wort geht auf volle Tinte. Mehr nicht — das Blatt hängt am
   Klick (siehe .open weiter unten). Offen bleibt das Wort hell, damit man
   sieht, woran das Blatt hängt. */
.nav-expanded .nav-menu-trigger:hover,
.nav-expanded .nav-menu.open .nav-menu-trigger { color:var(--fg); }
/* Schema-, Sprach- und Quelltextsteuerung optisch zurücknehmen. */
.site-header .lang-menu summary, .site-header .theme-toggle,
.site-header .icon-link { color:var(--muted); }
.site-header .lang-menu summary:hover, .site-header .theme-toggle:hover,
.site-header .icon-link:hover { color:var(--accent); }

/* Icon-Link (GitHub) — gleiche Schaltflächenform wie der Schema-Umschalter.
   Bewusst ohne Rahmen: umrandet waren die beiden Knöpfe das am stärksten
   ausgezeichnete Element der Leiste, und das Auge landete auf Werkzeugen
   statt auf der Navigation. Die Fläche kommt jetzt vom Hover der
   Menüpunkte, die Knöpfe bleiben bloße Zeichen. */
/* Wirklich rund, nicht 16px-gerundet: die Regel weiter oben sagte das
   schon, wurde von diesem var(--radius) aber überschrieben. Impeccables
   Schemaknopf ist ein Kreis, und der Widerspruch war ohnehin ein
   Versehen. */
.icon-link { display:inline-flex; align-items:center; justify-content:center;
             width:2.2rem; height:2.2rem; border:0;
             border-radius:999px; text-decoration:none;
             transition:color .12s; }
.icon-link svg { width:1.15rem; height:1.15rem; }

/* Schema-Umschalter: zeigt das Symbol des Schemas, in das er wechselt. */
.theme-toggle { display:inline-flex; align-items:center; justify-content:center;
                width:2.2rem; height:2.2rem; border:0;
                border-radius:999px; background:transparent; color:var(--fg);
                cursor:pointer; transition:color .12s; }
.theme-icon { width:1.15rem; height:1.15rem; }
.theme-icon .ico-moon { display:none; }
.theme-icon .ico-sun { display:inline; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-icon .ico-sun { display:none; }
  :root:not([data-theme="light"]) .theme-icon .ico-moon { display:inline; }
}
:root[data-theme="dark"] .theme-icon .ico-sun { display:none; }
:root[data-theme="dark"] .theme-icon .ico-moon { display:inline; }
:root[data-theme="light"] .theme-icon .ico-sun { display:inline; }
:root[data-theme="light"] .theme-icon .ico-moon { display:none; }

/* Sprachmenü */
.flag { width:1.25rem; height:.85rem; border-radius:2px; display:inline-block;
        vertical-align:-.1em; box-shadow:0 0 0 1px var(--line); }
.lang-menu { position:relative; }
.lang-menu summary { list-style:none; display:inline-flex; align-items:center; gap:.4rem;
                     cursor:pointer; padding:.3rem .55rem; border:1px solid var(--line);
                     border-radius:var(--radius); font-size:.82rem; color:var(--fg); user-select:none; }
.lang-menu summary::-webkit-details-marker { display:none; }
.lang-menu summary:hover { border-color:var(--accent); color:var(--accent); }
/* nowrap: mehrteilige Codes ("DE-AT") brächen sonst im Band um und
   machten die Kopfzeile dadurch eine Zeile höher. */
.lang-code { font-weight:600; letter-spacing:.03em; white-space:nowrap; }
.lang-list { position:absolute; right:0; top:calc(100% + 6px); z-index:30; min-width:13rem;
             background:var(--surface); border:1px solid var(--line); border-radius:var(--radius);
             box-shadow:var(--shadow); padding:.35rem; display:flex; flex-direction:column; }
.lang-list a { display:flex; align-items:center; gap:.55rem; padding:.45rem .6rem;
               border-radius:var(--radius); text-decoration:none; color:var(--fg); font-size:.9rem; }
.lang-list a:hover { background:var(--accent-soft); color:var(--accent); }
.lang-list a.active { font-weight:700; color:var(--accent); }

/* ── Burger-Navigation ────────────────────────────────────────────
   Bewusst ohne Breakpoint: ob die volle Leiste in eine Zeile passt, hängt
   an der Textlänge der Labels und damit an der Sprache — und ändert sich mit
   jedem neuen Menüpunkt. Ein fester Pixelwert wäre bei jedem geänderten
   Label oder jeder neuen Sprache wieder falsch.

   Stattdessen ist der Burger der Normalzustand, und ein Skript misst nach
   dem Aufbau der Kopfzeile, ob die Leiste einzeilig unterkommt; nur dann
   setzt es .nav-expanded (siehe NAV_FIT_JS). Ohne JavaScript bleibt es beim
   Burger — der funktioniert per CSS-Checkbox auf jeder Breite. */
.site-header nav { position:relative; gap:.6rem; flex-wrap:nowrap; }
/* In der nowrap-Zeile sonst von 2.2rem auf ~1.9rem gequetscht. */
.nav-burger, .theme-toggle, .icon-link, .lang-menu summary { flex:0 0 auto; }
/* Standard-"sr-only": optisch weg, aber fokussierbar und verlässlich im
   Accessibility-Tree. Bewusst nicht opacity:0 — damit galt das Control
   als unsichtbar und fehlte für Screenreader komplett. */
.nav-toggle { display:block; position:absolute; width:1px; height:1px;
              margin:0; padding:0; border:0; overflow:hidden;
              clip:rect(0 0 0 0); clip-path:inset(50%); white-space:nowrap; }
.nav-burger { display:inline-flex; align-items:center; justify-content:center;
              width:2.2rem; height:2.2rem; border:1px solid var(--line);
              border-radius:999px; color:var(--fg); cursor:pointer; order:5;
              transition:border-color .12s, color .12s; }
.nav-burger:hover { border-color:var(--accent); color:var(--accent); }
.nav-toggle:checked ~ .nav-burger { border-color:var(--accent); color:var(--accent); }
.nav-toggle:focus-visible ~ .nav-burger { outline:2px solid var(--accent); outline-offset:2px; }
.burger-icon { width:1.3rem; height:1.3rem; }
.nav-list { display:none; position:absolute; right:0; top:calc(100% + 10px); z-index:30;
            min-width:min(15rem, calc(100vw - 2rem)); background:var(--surface);
            border:1px solid var(--line); border-radius:var(--radius); box-shadow:var(--shadow-lg);
            padding:.35rem; flex-direction:column; align-items:stretch; }
.nav-toggle:checked ~ .nav-list { display:flex; }
/* Am jeweiligen Icon verankert ragte das Panel (13rem) links aus dem
   Viewport; hier richten sich alle Panels an der Navigationskante aus. */
.lang-menu { position:static; }
.lang-list { right:0; left:auto; top:calc(100% + 10px); max-width:calc(100vw - 2rem); }
.site-header .nav-list a { display:block; padding:.55rem .7rem;
                           border-radius:var(--radius); font-size:.95rem; }
.site-header .nav-list a:hover { background:var(--accent-soft); color:var(--accent); }

/* Gemessen: die Leiste passt einzeilig — zurück auf die volle Navigation.
   .nav-list löst per display:contents auf, die Links werden wieder direkte
   Flex-Kinder der Navigation. */
/* flex:1 gibt der Navigation die Restbreite der Zeile; erst dadurch lässt
   sich innerhalb überhaupt etwas verschieben. Der gap ist der ENGE der
   Bedienknöpfe (~18px, gemessen). */
.nav-expanded .site-header nav { position:static; gap:1.15rem; flex-wrap:wrap; flex:1; }
/* Impeccables Aufteilung — und das ist die eigentliche Änderung am Band:
   die Marke steht allein links, ALLE Menüpunkte rücken als geschlossene
   Gruppe nach rechts und stehen dort unmittelbar vor den Bedienknöpfen.
   Bisher standen sie links neben der Marke und die Knöpfe wurden per
   margin-left:auto ans andere Ende geschoben — eine Dreiteilung mit
   einer großen Lücke in der Mitte. Jetzt gibt es nur eine Lücke, und
   die liegt zwischen Marke und Navigation.

   Genau ein auto-Rand darf es dafür geben: zwei (hier und am
   Schemaknopf, wie früher) teilten den freien Platz unter sich auf und
   die Gruppe landete wieder in der Mitte. Deshalb ist er dort entfernt. */
.nav-expanded .site-header .nav-list > :first-child { margin-left:auto; }
/* Zwischen den Punkten 40px, gemessen in der Referenz — deutlich weiter
   als die 18px der Knöpfe rechts. Der Abstand steht am Punkt und nicht
   als gap an der Navigation, weil beide Distanzen in derselben Flex-Zeile
   nebeneinander vorkommen. Der letzte Punkt hält zusätzlich Abstand zum
   ersten Knopf. */
.nav-expanded .site-header .nav-list > * { margin-right:1.35rem; }
.nav-expanded .site-header .nav-list > :last-child { margin-right:.35rem; }
.nav-expanded .nav-toggle, .nav-expanded .nav-burger { display:none; }
/* Zweiter Selektor nötig: `.nav-toggle:checked ~ .nav-list` (drei Klassen)
   schlüge `.nav-expanded .nav-list` (zwei) sonst in der Spezifität, und
   die Liste bliebe beim offenen Burger das absolute Panel. */
.nav-expanded .nav-list,
.nav-expanded .nav-toggle:checked ~ .nav-list { display:contents; }
.nav-expanded .lang-menu { position:relative; }
.nav-expanded .lang-list { top:calc(100% + 6px); max-width:none; }
/* Ausgeklappt sind die Punkte Beschriftungen, keine Pillen: gedämpft, bei
   Hover und im aktiven Zustand in voller Tinte. Ausgezeichnet wird mit
   einem 2px-Strich unter dem Label — dieselbe Sprache wie die Haarlinie
   unter dem Band, nur in Akzentfarbe. Der Strich liegt immer da und ist
   nur durchsichtig, damit die Zeile beim Seitenwechsel nicht springt.
   (Die Einträge des Mega-Menüs liegen ebenfalls in .nav-list und werden
   weiter unten wieder ausgenommen.)

   Von Impeccable kommt der ABSTAND: dort steht der Strich rund 14px
   unter der Grundlinie und liest dadurch als eigene Marke unter dem
   Wort, nicht als Unterstreichung daran. Die Polsterung von .55rem auf
   .85rem zu heben ist alles, was dafür nötig war — und sie ist zugleich
   der Grund, warum das Band seine ~80px Höhe hält. */
.nav-expanded .site-header .nav-list a { display:inline-flex; align-items:center;
                                        padding:.85rem 0; border-radius:0;
                                        border-bottom:2px solid transparent;
                                        color:var(--muted); font-size:.95rem;
                                        transition:color .12s, border-color .12s; }
.nav-expanded .site-header .nav-list a:hover { background:none; color:var(--fg); }
.nav-expanded .site-header .nav-list a.active { background:none; color:var(--fg);
                                                border-bottom-color:var(--accent); }
@media (prefers-reduced-motion:reduce) {
  .nav-expanded .site-header .nav-list a { transition:none; }
}

/* ── Untermenü (Products) ─────────────────────────────────────────
   Wizas Mega-Menü: fällt als eigenes, gerundetes Blatt aus dem Band, in
   zwei Spalten, und jeder Eintrag ist ein Symbol plus halbfettes Label mit
   einer grauen Zeile darunter. Diese Zeile ist der eigentliche Trick der
   Vorlage — sie macht ein Menü überfliegbar, statt es nur aufzulisten. */
.nav-menu { position:relative; }
.nav-menu-trigger { display:inline-flex; align-items:center; gap:.25rem; border:0;
                    margin:0; padding:0; background:none; cursor:pointer; font:inherit;
                    font-size:.95rem; color:var(--fg); }
.nav-menu-trigger .caret { width:.85rem; height:.85rem; opacity:.55; }
/* Der Haken dreht sich beim Öffnen mit — dieselbe .12s wie die Farbe des
   Auslösers daneben, damit Wort und Zeichen als eine Bewegung lesen. Er
   dreht beim ÖFFNEN, nicht beim Überfahren: die Drehung ist die Anzeige
   des Zustands, und ein Zustand, der beim Vorbeifahren entsteht, ist
   keiner. */
.nav-expanded .nav-menu-trigger .caret { transition:transform .12s ease-out, opacity .12s; }
.nav-expanded .nav-menu.open .nav-menu-trigger .caret { transform:rotate(180deg);
                                                        opacity:.85; }

/* Im Burger-Zustand steht das Untermenü einfach eingerückt in der Liste:
   auf einem Telefon gibt es kein Überfahren, und ein Blatt im Blatt wäre
   eine Falltür. */
.nav-menu-panel { display:block; }
.nav-sheet { display:flex; flex-direction:column; padding:.15rem 0 .3rem .55rem; }

/* Ausgeklappte Leiste: jetzt erst wird daraus das schwebende Blatt. */
/* padding-top, nicht margin/top: der Auslöser sitzt im Band, und das Blatt
   muss unter dessen Haarlinie sichtbar abgesetzt beginnen. Als Polsterung
   bleibt die Strecke überfahrbar, als Abstand wäre sie tot. */
/* Geschlossen wird über visibility und nicht über display:none — display
   kennt keinen Zwischenzustand, und genau daran gab es vorher nichts zu
   animieren. visibility nimmt das Blatt ebenso vollständig aus Zeiger- und
   Tabreihenfolge, lässt sich aber schalten: beim Öffnen sofort (0s), beim
   Schließen erst nach dem Ausblenden (0s linear .12s), sonst wäre das Blatt
   weg, bevor es verblasst ist. */
.nav-expanded .nav-menu-panel { position:absolute; left:0; top:100%;
                                z-index:30; padding-top:1rem;
                                width:max-content; max-width:min(34rem, calc(100vw - 2rem));
                                opacity:0; visibility:hidden;
                                transform:translateY(-.35rem);
                                transition:opacity .12s ease-out, transform .12s ease-out,
                                           visibility 0s linear .12s; }
/* Die Bewegung ist knapp 6px nach unten, und die Richtung ist die Aussage:
   das Blatt tritt am unteren Bandrand hervor, statt an seinem Platz
   aufzuploppen — dieselbe Lesart wie „fällt aus dem Band" oben. Kein
   Maßstabssprung, kein Nachfedern, keine eigene Kurve: die Seite kennt für
   Zustandswechsel nur .12s, und ein Menü ist einer. Der Weg bleibt deutlich
   kürzer als die 16px Polsterung darüber, damit das Blatt den Auslöser
   unterwegs nicht erreicht. */
/* Geöffnet wird per Klick — .open setzt layout.js. Das Blatt ist schwer
   genug, dass es niemand im Vorbeifahren auslösen soll: es verdeckt zwei
   weitere Menüpunkte, und wer nur zu "Documentation" wollte, bekäme es
   unterwegs vor die Nase. Deshalb kein :hover mehr; und kein
   :focus-within, weil die Tastatur den Auslöser ohnehin per Enter
   betätigt und ein Blatt, das beim Durchtabben aufspringt, denselben
   Unfall in langsam wäre. */
.nav-expanded .nav-menu.open > .nav-menu-panel { opacity:1; visibility:visible;
                                transform:none;
                                transition:opacity .12s ease-out, transform .12s ease-out,
                                           visibility 0s; }

/* Notöffner. Der Klick hängt an layout.js, die ausgeklappte Leiste dagegen am
   INLINE-Skript hinter dem Header — zwei Dateien, und nur eine davon kann
   ausbleiben. Kommt layout.js nicht an (veraltete Fingerprint-URL, Blocker,
   abgerissener Request), stünde sonst eine ausgeklappte Leiste da, deren
   "Products" auf nichts reagiert: kein Klick, kein Enter, und im Band kein
   anderer Weg zu /products/*.

   Deshalb setzt layout.js als Erstes .nav-js an <html>. Solange die Klasse
   fehlt, gilt wieder, was vor der Umstellung galt — Überfahren und
   Tastaturfokus öffnen das Blatt. Läuft layout.js, greift keine der beiden
   Regeln je, und der Klick behält das Menü ganz für sich. */
.nav-expanded:not(.nav-js) .nav-menu:hover > .nav-menu-panel,
.nav-expanded:not(.nav-js) .nav-menu:focus-within > .nav-menu-panel {
                                opacity:1; visibility:visible; transform:none;
                                transition:opacity .12s ease-out, transform .12s ease-out,
                                           visibility 0s; }
.nav-expanded:not(.nav-js) .nav-menu:hover .nav-menu-trigger .caret,
.nav-expanded:not(.nav-js) .nav-menu:focus-within .nav-menu-trigger .caret {
                                transform:rotate(180deg); opacity:.85; }
@media (prefers-reduced-motion:reduce) {
  .nav-expanded .nav-menu-panel,
  .nav-expanded .nav-menu.open > .nav-menu-panel,
  .nav-expanded .nav-menu-trigger .caret { transition:none; transform:none; }
}
.nav-expanded .nav-sheet { display:grid; grid-template-columns:repeat(2, minmax(0, 1fr));
                           gap:.15rem; padding:.5rem;
                           background:var(--surface); border:1px solid var(--line);
                           border-radius:16px; box-shadow:var(--shadow-lg); }

/* Ein Eintrag: Symbol in getöntem Quadrat, Label, Beschreibung. */
.site-header .nav-sheet a { display:flex; align-items:flex-start; gap:.6rem;
                            padding:.55rem .6rem; border-radius:10px; }
.site-header .nav-sheet a:hover { background:var(--accent-soft); }
.nav-ico { flex:0 0 auto; display:inline-flex; align-items:center; justify-content:center;
           width:1.9rem; height:1.9rem; border-radius:9px;
           background:var(--accent-soft); color:var(--accent); }
.nav-ico svg { width:1.05rem; height:1.05rem; }
.site-header .nav-sheet a:hover .nav-ico { background:var(--surface); }
.nav-entry { display:flex; flex-direction:column; min-width:0; }
.nav-entry-label { font-weight:650; font-size:.9rem; color:var(--fg); line-height:1.3; }
.nav-entry-desc { font-size:.78rem; color:var(--muted); line-height:1.35; }
.site-header .nav-sheet a:hover .nav-entry-label { color:var(--accent); }
/* Der dritte Eintrag (Board & Styling) nimmt im ausgeklappten Blatt die ganze Breite,
   statt allein in der linken Spur einer zweiten Zeile zu stehen. Die Marke "Preview" ist
   dieselbe Mono-Etikette wie .zone in den Bausteinen, nur kleiner und ohne Rahmenfarbe. */
.nav-expanded .site-header .nav-sheet a.nav-wide { grid-column:1 / -1; }
.nav-badge { margin-left:.35rem; padding:.05rem .4rem; border:1px solid var(--border);
             border-radius:999px; font-family:var(--mono); font-size:.6rem; font-weight:600;
             letter-spacing:.06em; text-transform:uppercase; color:var(--muted);
             vertical-align:middle; }
/* Die Einträge liegen in .nav-list und würden sonst von dessen Regeln für
   den ausgeklappten Zustand flachgedrückt (display:inline, padding:0).
   Gleiche Spezifität, später notiert — deshalb hier noch einmal. */
.nav-expanded .site-header .nav-sheet a { display:flex; padding:.55rem .6rem;
                                         border-radius:10px; font-size:.9rem;
                                         border-bottom:0; }
.nav-expanded .site-header .nav-sheet a:hover { background:var(--accent-soft); }
/* Zwei Spalten brauchen Platz; darunter untereinander. */
@media (max-width:560px) { .nav-expanded .nav-sheet { grid-template-columns:1fr; } }

/* Der Rand der Bühne wandert an EINER Stelle — Band und <main> lesen
   beide --gutter und können deshalb nicht auseinanderlaufen. */
@media (max-width:900px) { :root { --gutter:1.6rem; } }
@media (max-width:560px) { :root { --gutter:1.15rem; } }
@media (max-width:720px) {
  main { padding-top:2.5rem; }
  .header-inner { gap:.7rem; padding:.6rem var(--gutter); flex-wrap:nowrap; }
  /* Nur hier, wo die Zeilen kurz sind: lange Komposita passen sonst nicht.
     Auf breiten Schirmen wäre Silbentrennung eine Typografie-Änderung ohne
     Anlass. Trennt sprachrichtig, weil html[lang] gesetzt ist. */
  h1, h2, h3, h4, p, li, dd, dt { hyphens:auto; }
}
/* Bei 320px reicht die Kopfzeile nicht für Marke, Sprachcode und zwei Icons.
   Die Flagge benennt die Sprache weiterhin, die vollen Namen stehen im
   aufgeklappten Menü. */
@media (max-width:400px) {
  .lang-code { display:none; }
  .lang-menu summary { padding:.3rem .4rem; }
}

/* ── Fußzeile ─────────────────────────────────────────────────────
   Nach der designr-Referenz *Launch UI Footer*: Wortmarke, drei Listen und
   darunter der Rechtsstreifen. Die Vorlage kennt genau drei Farbwerte (Grund,
   Tinte, gedämpfte Tinte), zwei Schriftgrößen und KEINE Linie — kein Rahmen,
   kein Schatten, kein Trenner, kein Akzent. Das ist übernommen.

   Abgesetzt wird die Fußzeile deshalb durch Weißraum statt durch eine Linie.
   Das ist dieselbe Haltung wie oben, wo die Haarlinie erst erscheint, sobald
   es etwas abzugrenzen gibt: eine Linie ohne Gegenstand macht aus dem Rahmen
   eine Fläche.

   NICHT übernommen ist ihre Aufteilung. Die Referenz drängt die Listen eng
   nach links und räumt selbst ein, dass die leere rechte Hälfte auf breiten
   Schirmen unfertig wirkt. Hier steht stattdessen ein Raster aus vier gleichen
   Spuren über die volle Bühne — die Begründung dafür steht bei .footer-cols
   weiter unten, samt der beiden verworfenen Anordnungen. Ein Deckel auf
   --content-max gehört ausdrücklich NICHT dazu: er war eine Zwischenstufe und
   ist wieder raus.

   Ebenfalls nicht übernommen: der Schema-Umschalter im Streifen — der
   eigentliche Kniff der Vorlage. Er bleibt in der Kopfzeile, siehe DESIGN.md. */
/* Deckel UND Polsterung liegen auf demselben Element — genau wie bei <main>
   und .header-inner. Andersherum (Polsterung außen, Deckel innen) fluchtet
   die Fußzeile auf Schirmen über 1360px nicht mehr mit der Bühne: außen
   gepolstert bleibt der Innenkasten unter dem Deckel und rutscht nach links
   weg. Getestet bei 1440px — Wortmarke oben und unten stehen dann auf
   verschiedenen Kanten, und das ist die eine Fluchtlinie, die diese Seite
   nicht verlieren darf.

   Das vertikale Maß ist Impeccables: dort stehen ~136px über der ersten
   Zeile eines Abschnitts. Die trägt hier nicht die Fußzeile allein — <main>
   bringt schon 80px Polsterung mit, also bleiben 56px. Die Summe ist die
   Referenzgröße, nicht der Einzelwert; wer an main's padding-bottom dreht,
   muss hier mitziehen. Unten 64px als Boden der Seite. */
.footer-inner { max-width:var(--page-max); margin:0 auto;
                padding:3.5rem var(--gutter) 4rem; }
/* Volle Bühne, gleichmäßig aufgeteilt: VIER gleich breite Spuren, die
   Wortmarke in der ersten, die drei Listen in den übrigen. Der freie Platz
   liegt damit zwischen allen vieren statt an einer Kante — die Fußzeile
   nutzt die Breite, statt sich an einem Ende zu sammeln.

   Bewusst anders als das Band oben, und das ist der Unterschied zwischen
   Navigation und Fußzeile: oben sind Marke und Menü zwei Gruppen mit EINER
   Lücke, weil die Leiste geführt werden soll. Hier stehen vier
   gleichrangige Blöcke nebeneinander, und ein Raster mit gleichen Spuren
   ist genau das. Ein margin-left:auto gibt es hier deshalb NICHT — es
   schöbe die Listen wieder an die rechte Kante zusammen.

   Zwei Versuche davor, damit sie nicht wiederkommen: die Listen eng
   aneinander links (die Fußzeilen-Referenz selbst) ließen die rechte Hälfte
   leer, dieselbe Gruppe rechts ließ die linke leer. Gleiche Spuren lassen
   keine Hälfte leer.

   40px in den Rinnen — dasselbe Maß wie zwischen den Menüpunkten, beides
   aus Impeccable. minmax(0,1fr) statt 1fr: sonst setzt die längste
   Beschriftung („Documentation") die Mindestbreite ihrer Spur und die vier
   liefen ungleich. */
.footer-cols { display:grid; grid-template-columns:repeat(4, minmax(0, 1fr));
               gap:2.5rem; }
.footer-brand { align-self:start; justify-self:start; }
/* Etwas kleiner als im Band: hier ist die Wortmarke Absender, nicht Weg. */
.footer-brand .brand-logo { height:1.9rem; }
.footer-col { display:flex; flex-direction:column; gap:.3rem; }
/* Zwei Schriftgrößen im ganzen Baustein, mehr nicht: Überschrift in voller
   Tinte und halbfett, Verweise eine Spur kleiner und gedämpft. Der globale
   h2 (1.35rem, 4rem Vorlauf) gilt der Fließspalte und wäre hier ein Bruch —
   deshalb vollständig zurückgesetzt.

   Unter der Überschrift stehen 18px — Impeccables engstes Maß, dasselbe wie
   zwischen den Bedienknöpfen im Band. Notiert sind aber nur .825rem (13.2px):
   der Flex-Abstand der Spalte (.3rem = 4.8px) liegt zwischen JEDEM Geschwister-
   paar, also auch zwischen Überschrift und erstem Verweis, und addiert sich
   auf den Rand statt mit ihm zu verschmelzen. 13.2 + 4.8 = 18. Wer den Rand
   auf 1.125rem stellt, bekommt 22.8px und verfehlt das Maß. */
.footer-head { margin:0 0 .825rem; font-size:.88rem; font-weight:600;
               letter-spacing:0; color:var(--fg); }
.site-footer a { color:var(--muted); text-decoration:none; font-size:.85rem; }
/* Auf volle Tinte, nicht auf den Akzent: die Vorlage hat keinen, und die
   ausgeklappten Menüpunkte oben verhalten sich schon genauso. */
.site-footer a:hover { color:var(--fg); }
/* Der Streifen teilt sich wie das Band oben — Marke links, Verweis rechts —
   und nimmt dieselbe volle Bühne wie die Spalten darüber. 64px Vorlauf, das
   Abschnittsmaß aus Impeccable: er ist eine eigene Zeile unter der Gruppe,
   kein Anhängsel an sie. */
.footer-legal { display:flex; flex-wrap:wrap; align-items:center;
                justify-content:space-between; gap:.5rem 1.5rem;
                margin-top:4rem; }
.footer-copy { margin:0; font-size:.85rem; color:var(--muted); }
/* Vier Spuren brauchen Platz. Darunter nimmt die Wortmarke eine eigene Zeile
   über die volle Breite und die drei Listen teilen sich die nächste zu
   dritt — gleichmäßig wie oben, nur eine Zeile tiefer. */
@media (max-width:820px) {
  .footer-cols { grid-template-columns:repeat(3, minmax(0, 1fr)); }
  .footer-brand { grid-column:1 / -1; }
}
@media (max-width:560px) {
  .footer-inner { padding-top:2.5rem; }
  /* Untereinander statt nebeneinander: drei gequetschte Spalten sind auf
     einem Telefon schlechter zu treffen als drei volle Blöcke. */
  .footer-cols { grid-template-columns:1fr; gap:1.75rem; }
  .footer-legal { margin-top:2.5rem; }
}

/* ── Bausteine der Startseite (Fassung 2026-10-03) ──────────────────
   Die Startseite ist seit dem visuellen Umbau eine Folge von Abschnitten
   ueber die volle Buehne (.band): Aufmacher mit echter Produktaufnahme,
   Messwerte als Balken, Galerie der Ansichten, Renderer-Diagramm, Core
   gegen Pro, Schlussaufruf. Jeder Abschnitt setzt max-width:none und
   hebt damit den Deckel aus main > * auf - die Bloecke darin halten ihre
   eigene Lesebreite (.band-copy bei --content-max). Was vorher galt
   (vier Ausnahmen, Grund aus einem Hintergrundbild, nachgebautes Grid in
   HTML) steht in DESIGN.md unter "Verworfen". */
.band { max-width:none; padding:4.5rem 0 0; }
.band + .band { padding-top:5.5rem; }
.band-head { max-width:var(--content-max); }
.band-head h2 { margin-top:0; }
.band-head .lead { font-size:1.08rem; margin:.6rem 0 0; }
.eyebrow { margin:0 0 .9rem; font-family:var(--mono); font-size:.7rem; font-weight:600;
           letter-spacing:.11em; text-transform:uppercase; color:var(--muted); }

/* ── Zwei Fassungen eines Bildes, eine sichtbar ──────────────────────
   Jede Produktaufnahme liegt in Dunkel UND Hell vor; gezeigt wird die, die
   zum Schema der Seite passt. Umgeschaltet wird per CSS, weil der Umschalter
   data-theme setzt und <picture media=prefers-color-scheme> nur das System
   lesen koennte. Beide <img> tragen loading="lazy": ein Bild ohne Box wird
   dann NICHT geladen, der Besucher zieht also nur seine Fassung. */
/* html-Praefix fuer die Spezifitaet: .shot-frame img und .tile-img img setzen
   display:block und stuenden sonst ueber der Klasse (gleiche Spezifitaet, spaeter
   notiert) - dann waeren beide Fassungen zu sehen. */
html img.theme-dark, html .theme-dark { display:none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-dark { display:block; }
  :root:not([data-theme="light"]) .theme-light { display:none; }
}
:root[data-theme="dark"] .theme-dark { display:block; }
:root[data-theme="dark"] .theme-light { display:none; }

/* ── Grund des Aufmachers: das Datenband ─────────────────────────────
   Zurueck seit 2026-10-03 (abends), nach dem Umbau zunaechst verworfen: Michael
   wollte es wieder. Es ist aber kein Foto mehr, sondern eine SVG-MASKE
   (hero-bg.svg, 7,7 kB statt 92 kB JPG): Linien, Punkte und zwei Balkenfelder auf
   durchsichtigem Grund, Farbe aus --accent, Deckkraft als einziger Regler.
   Deshalb entfaellt alles, was das Bild frueher brauchte - brightness auf --bg,
   invert/hue-rotate im Dunkeln, der an das Bild gekoppelte dunklere Grund: der
   Grund IST die Seite, es gibt keinen Schnitt und keine Kante, in keinem Schema.

   Von Kante zu Kante ueber 100vw (margin/padding-Trick; overflow-x:clip am body
   faengt die Laufleistenbreite), und um Kopfband plus Kopfluft nach oben, damit
   das Band hinter dem durchsichtigen Kopfband am Seitenanfang beginnt. --header-h
   misst nav-fit.js vor dem ersten Paint; ohne Skript gilt der Ausgangswert und das
   Kopfband steht ohnehin deckend (noscript in Shell.razor).

   mask-size 100% 100% ab 1151px wie frueher background-size: zwei Wellen, oben
   rechts und unten links, sollen beide zu sehen sein, und weiche Linien vertragen
   die ungleiche Streckung; darunter cover. Die Deckkraft ist niedrig gehalten,
   damit das Band hinter Ueberschrift und Aufnahme zuruecktritt: im Hellen ergibt
   --accent bei .13 auf --bg etwa #dfe5ee, darauf bleibt --fg bei ueber 12:1; im
   Dunkeln .2 mit dem helleren --accent - dort tragen die Linien gegen den Grund
   wie frueher die invertierten. ::after blendet die Linien unten in --bg aus,
   damit sie nicht an einer Zeile aufhoeren.

   Keine Bewegung, also auch nichts fuer prefers-reduced-motion. */
.hero-bleed { position:relative; max-width:none;
              margin-inline:calc(50% - 50vw); padding-inline:calc(50vw - 50%);
              --hero-rise:calc(var(--header-h) + 4.5rem); --hero-ink:.3; }
.hero-bleed::before, .hero-bleed::after {
  content:""; position:absolute; z-index:-1; left:0; right:0; pointer-events:none; }
.hero-bleed::before {
  /* Fest am Fenster (Michael, 2026-10-03): das Band bleibt beim Scrollen stehen, die
     Seite gleitet darueber. Deshalb auch kein Ausblenden nach unten mehr (::after). */
  position:fixed; top:0; height:100vh; height:100lvh;
  background-color:var(--accent); opacity:var(--hero-ink);
  -webkit-mask:url("/assets/hero-bg.fea9c949.svg") center bottom / cover no-repeat;
          mask:url("/assets/hero-bg.fea9c949.svg") center bottom / cover no-repeat; }
.hero-bleed::after { display:none; }
@media (min-width:1151px) {
  .hero-bleed::before { -webkit-mask-size:100% 100%; mask-size:100% 100%; }
}
/* Hochkant (Aufmacher untereinander) laeuft cover mit der Bildmitte durch die
   Ueberschrift. Deshalb das Motiv auf 230 % Breite gezogen und oben rechts
   verankert: die obere Welle und das Eckfeld liegen dann hinter dem Kopfband und
   der Kopfluft, von der unteren bleibt ein flacher Auslauf hinter dem Absatz, und
   die Tinte ist leiser. Der untere Teil des Rahmens bleibt frei (no-repeat). */
@media (max-width:1150px) {
  .hero-bleed { --hero-ink:.15; }
  .hero-bleed::before { -webkit-mask-position:right top; mask-position:right top;
                        -webkit-mask-size:230% auto; mask-size:230% auto; }
  @media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .hero-bleed { --hero-ink:.2; }
  }
  :root[data-theme="dark"] .hero-bleed { --hero-ink:.2; }
}
/* Ohne Masken (sehr alte Browser) bleibt der Grund eine ruhige Flaeche - das Band
   ist eine Verzierung, keine Aussage. */
@supports not ((mask:url("")) or (-webkit-mask:url(""))) {
  .hero-bleed::before, .hero-bleed::after { display:none; }
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .hero-bleed { --hero-ink:.38; }
}
:root[data-theme="dark"] .hero-bleed { --hero-ink:.38; }

/* ── Aufmacher ─────────────────────────────────────────────────────── */
.hero { max-width:none; display:grid; grid-template-columns:minmax(0, 33rem) minmax(0, 1fr);
        gap:3.5rem 4rem; align-items:center; padding:2.5rem 0 1rem; }
.hero-copy h1 { margin:0; max-width:none; }
.hero-copy h1 .accent { color:var(--accent); }
.hero-lead { font-size:1.1rem; color:var(--fg); margin:1.6rem 0 0; }
.hero-copy .hero-lead { max-width:none; }
.hero-sub { color:var(--muted); font-size:.92rem; margin:.9rem 0 0; max-width:none; }
.hero-actions { display:flex; flex-wrap:wrap; align-items:center; gap:.8rem 1.1rem;
                margin:1.8rem 0 0; }
/* Drei knappe Tatsachen unter den Schaltflaechen - Mono-Etikett wie ueberall. */
.hero-facts { list-style:none; display:flex; flex-wrap:wrap; gap:.4rem 1.4rem;
              margin:1.6rem 0 0; padding:0; font-family:var(--mono); font-size:.72rem;
              letter-spacing:.04em; color:var(--muted); }
.hero-facts li { margin:0; max-width:none; display:flex; align-items:center; gap:.45rem; }
.hero-facts li::before { content:""; width:6px; height:6px; border-radius:50%;
                         background:var(--accent); flex:0 0 auto; }

/* Der Installationsbefehl: eine Zeile Mono in einer flachen Mulde, daneben der
   Kopierknopf. Der Knopf erscheint nur mit Skript (html.nav-js setzt layout.js);
   ohne Skript ist die Zeile markierbarer Text, und das reicht. */
.cmd { display:flex; align-items:stretch; margin:1.6rem 0 0; max-width:none;
       background:var(--bg-soft); border:1px solid var(--line); border-radius:10px;
       overflow:hidden; }
.cmd > code { flex:1 1 auto; min-width:0; padding:.7rem .95rem; font-size:.8rem;
              white-space:normal; overflow-wrap:break-word; line-height:1.5;
              border:0; background:none; border-radius:0; }
.cmd > code .tok-k { color:var(--accent); }
.cmd > code .nobr { white-space:nowrap; }
.cmd-copy { display:none; flex:0 0 auto; border:0; border-left:1px solid var(--line);
            background:var(--surface); color:var(--muted); font:inherit; font-size:.8rem;
            font-weight:600; padding:0 .9rem; cursor:pointer; transition:color .12s, background .12s; }
.cmd-copy:hover { color:var(--accent); }
.cmd-copy[data-done] { color:var(--ok); }
html.nav-js .cmd-copy { display:inline-flex; align-items:center; gap:.35rem; }
.cmd-copy svg { width:.95rem; height:.95rem; }

/* Schaltflaechen: gefuellt (Hauptweg), umrandet (Download), blank (Verweis).
   Radius 8px fuer alle - die 2px-Ecke der Impeccable-Vorlage ist mit dem
   Umbau weg, die Pille (999px) der Preisseite bleibt deren Bedienelement. */
.btn { display:inline-flex; align-items:center; gap:.5rem; border-radius:8px;
       padding:.72rem 1.3rem; font-size:.95rem; font-weight:600; line-height:1.2;
       text-decoration:none; border:1px solid transparent;
       transition:transform .12s ease, box-shadow .12s ease, background .12s, color .12s, border-color .12s; }
.btn svg { width:1.05rem; height:1.05rem; flex:0 0 auto; }
.btn small { font-weight:500; font-size:.78rem; color:inherit; opacity:.75; }
.btn-primary { background:var(--accent); color:var(--accent-ink); box-shadow:var(--shadow); }
.btn-primary:hover { background:var(--accent-hover); }
.btn-outline { background:var(--surface); color:var(--fg); border-color:var(--border); }
.btn-outline:hover { border-color:var(--accent); color:var(--accent); }
.btn-secondary { background:none; color:var(--fg); padding-left:.4rem; padding-right:.4rem; }
.btn-secondary:hover { color:var(--accent); }
.btn:hover { transform:translateY(-1px); }
@media (prefers-reduced-motion:reduce) { .btn { transition:none; } .btn:hover { transform:none; } }

/* ── Produktaufnahme ───────────────────────────────────────────────────
   Ein echter Bildschirmfoto des Showcase (Avalonia-Host), beschnitten auf das
   Fenster ohne Titelleiste, als WebP. Rahmen und Schatten wie eine Karte; das
   Bild fuellt den Rahmen, width/height im Markup halten den Platz vor dem Laden.
   Die Bildunterschrift sagt, WAS zu sehen ist (Szene, Host, Thema) - sie ersetzt
   den frueheren Hinweis "not a running demo" und darf nicht wegfallen. */
.shot { margin:0; max-width:none; }
.shot-frame { position:relative; background:var(--surface); border:1px solid var(--border);
              border-radius:14px; box-shadow:var(--shadow-lg); overflow:hidden; }
.shot-frame img { display:block; width:100%; height:auto; }
.shot figcaption { margin:.7rem .15rem 0; font-size:.8rem; color:var(--muted); line-height:1.45; }
/* Die Hero-Aufnahme laeuft rechts ueber die Buehnenkante hinaus - ein Fenster, das
   groesser ist als die Spalte, liest sich als Anwendung und nicht als Bild. */
.shot-hero { position:relative; }
@media (min-width:1151px) {
  .shot-hero .shot-frame { width:calc(100% + 6rem); max-width:none; }
}

/* ── Messwerte als Balken ────────────────────────────────────────────────
   Zwei Hosts, je zwei Zeilenzahlen. Die Balkenlaenge ist die Bildkosten (ms);
   die Breite in Prozent steht im Markup (style="--w:..") und ist aus den vier
   gemessenen Werten gerechnet, 1,33 ms = 100 %. Dass vier Balken fast gleich
   lang sind, IST die Aussage. Daneben drei Kennzahlen als Kacheln. */
.stats { display:grid; grid-template-columns:minmax(0, 1.4fr) minmax(0, 1fr); gap:2rem 3rem;
         align-items:start; margin-top:2rem; }
.bars { background:var(--surface); border:1px solid var(--border); border-radius:14px;
        padding:1.4rem 1.6rem 1.2rem; box-shadow:var(--shadow); }
.bars-host { font-weight:600; font-size:.95rem; margin:0 0 .4rem; }
.bars-host + .bars-host { margin-top:1.4rem; }
.bar { display:grid; grid-template-columns:7.5rem minmax(0, 1fr) 4.5rem; align-items:center;
       gap:.9rem; margin:.45rem 0; }
.bar-label { font-size:.85rem; color:var(--muted); font-variant-numeric:tabular-nums; white-space:nowrap; }
.bar-track { height:12px; border-radius:6px; background:var(--bg-soft); overflow:hidden; }
.bar-fill { height:100%; width:var(--w); border-radius:6px; background:var(--accent); }
.bar-million .bar-fill { background:var(--accent-hover); }
.bar-value { font-family:var(--mono); font-size:.85rem; font-weight:600; text-align:right;
             font-variant-numeric:tabular-nums; }
.bars-foot { margin:1.2rem 0 0; font-size:.78rem; color:var(--muted); max-width:none; }
.kpis { display:grid; grid-template-columns:repeat(2, minmax(0, 1fr)); gap:.9rem; }
.kpi { background:var(--surface); border:1px solid var(--border); border-radius:14px;
       padding:1.1rem 1.2rem; box-shadow:var(--shadow); }
.kpi-value { font-family:var(--mono); font-size:1.9rem; font-weight:600; letter-spacing:-.03em;
             line-height:1.1; margin:0; font-variant-numeric:tabular-nums; }
.kpi-label { margin:.35rem 0 0; font-size:.82rem; color:var(--muted); line-height:1.4; max-width:none; }
.kpi-wide { grid-column:1 / -1; }

/* ── Galerie: eine Engine, viele Ansichten ──────────────────────────────
   Kacheln 4:3 aus den Szenen des Showcase, jede mit Beschriftung und einer
   Marke Core oder Pro. Die Bilder sind 800x600 und werden im Raster rund 400px
   breit gezeigt - also fuer 2x-Bildschirme scharf, ohne zweite Datei. */
.gallery { display:grid; grid-template-columns:repeat(3, minmax(0, 1fr)); gap:1.4rem;
           margin-top:2rem; }
.tile { margin:0; background:var(--surface); border:1px solid var(--border); border-radius:14px;
        overflow:hidden; box-shadow:var(--shadow); display:flex; flex-direction:column;
        transition:transform .12s ease, box-shadow .12s ease; }
.tile:hover { transform:translateY(-2px); box-shadow:var(--shadow-lg); }
@media (prefers-reduced-motion:reduce) { .tile { transition:none; } .tile:hover { transform:none; } }
.tile-img { display:block; aspect-ratio:4 / 3; overflow:hidden; border-bottom:1px solid var(--line); }
.tile-img img { display:block; width:100%; height:100%; object-fit:cover; object-position:left top; }
.tile figcaption { display:flex; align-items:baseline; justify-content:space-between; gap:.8rem;
                   padding:.75rem .95rem .85rem; }
.tile-title { font-weight:600; font-size:.95rem; }
.tile-desc { display:block; font-weight:400; font-size:.8rem; color:var(--muted); margin-top:.1rem; }
/* Die Zonenmarke: Core im Rahmen, Pro gefuellt im Akzent. Dieselben zwei Woerter
   wie in den Tabellenkoepfen der Preisseite. */
.zone { flex:0 0 auto; font-family:var(--mono); font-size:.64rem; font-weight:600;
        letter-spacing:.1em; text-transform:uppercase; padding:.22rem .5rem; border-radius:999px;
        border:1px solid var(--border); color:var(--muted); white-space:nowrap; }
.zone-pro { background:var(--accent); color:var(--accent-ink); border-color:transparent; }

/* ── Ein Renderer, drei Hosts ─────────────────────────────────────────── */
.arch { display:grid; grid-template-columns:minmax(0, 1.15fr) minmax(0, 1fr); gap:2rem 3.5rem;
        align-items:start; margin-top:2rem; }
.diagram { margin:0; max-width:none; }
.diagram svg { display:block; width:100%; height:auto; }
/* Das Diagramm liest seine Farben aus den Variablen - es ist Markup, kein Bild. */
.diagram .d-box { fill:var(--surface); stroke:var(--border); }
.diagram .d-box-soft { fill:var(--bg-soft); stroke:var(--line); }
.diagram .d-box-accent { fill:var(--accent-soft); stroke:var(--accent); }
.diagram .d-text { fill:var(--fg); font-family:var(--sans); font-size:13px; font-weight:600; }
.diagram .d-sub { fill:var(--muted); font-family:var(--mono); font-size:10.5px; letter-spacing:.06em; }
.diagram .d-line { stroke:var(--border); stroke-width:1.5; fill:none; }
.diagram .d-arrow { fill:var(--border); }
.diagram figcaption { margin:.7rem 0 0; font-size:.8rem; color:var(--muted); }
.layers { list-style:none; margin:0; padding:0; counter-reset:layer; }
.layers li { margin:0; max-width:none; display:grid; grid-template-columns:auto minmax(0, 1fr);
             gap:.2rem .9rem; padding:.8rem 0; border-top:1px solid var(--line); }
.layers li:last-child { border-bottom:1px solid var(--line); }
.layers code { grid-column:1; align-self:start; font-size:.78rem; }
.layers .layer-what { grid-column:2; font-size:.9rem; color:var(--muted); }
.layers .layer-what strong { color:var(--fg); font-weight:600; }

/* ── Core gegen Pro ─────────────────────────────────────────────────────── */
.tiers { display:grid; grid-template-columns:repeat(2, minmax(0, 1fr)); gap:1.4rem; margin-top:2rem; }
.tier { background:var(--surface); border:1px solid var(--border); border-radius:14px;
        padding:1.5rem 1.6rem 1.6rem; box-shadow:var(--shadow); display:flex; flex-direction:column; }
.tier-pro { border-color:var(--accent); }
.tier-head { display:flex; align-items:baseline; justify-content:space-between; gap:1rem; }
.tier-head h3 { margin:0; font-size:1.2rem; font-weight:600; letter-spacing:-.02em; }
.tier-price { font-family:var(--mono); font-size:.78rem; color:var(--muted); }
.tier-sum { margin:.6rem 0 0; font-size:.92rem; color:var(--muted); max-width:none; }
.tier ul { margin:1rem 0 0; padding:0; list-style:none; }
.tier li { margin:.3rem 0; max-width:none; font-size:.9rem; padding-left:1.35rem; position:relative; }
.tier li::before { content:""; position:absolute; left:0; top:.52em; width:.75rem; height:.4rem;
                   border-left:2px solid var(--accent); border-bottom:2px solid var(--accent);
                   transform:rotate(-45deg); }
.tier li code { font-size:.78rem; }
.tier .tier-actions { margin-top:auto; padding-top:1.3rem; display:flex; flex-wrap:wrap; gap:.7rem; }

/* ── Schlussaufruf ─────────────────────────────────────────────────────── */
.cta-band { max-width:none; margin-top:5.5rem; padding:2.6rem 2.2rem; border-radius:18px;
            background:var(--bg-soft); border:1px solid var(--line);
            display:grid; grid-template-columns:minmax(0, 1fr) auto; gap:1.6rem 3rem;
            align-items:center; }
.cta-band h2 { margin:0; font-size:1.6rem; }
.cta-band p { margin:.5rem 0 0; color:var(--muted); max-width:none; }
.cta-band .hero-actions { margin:0; justify-content:flex-end; flex-wrap:nowrap; }

/* ── Schmal ────────────────────────────────────────────────────────────── */
@media (max-width:1150px) {
  .hero { grid-template-columns:minmax(0, 1fr); gap:2.5rem; padding-top:.5rem; }
  .hero-copy { max-width:36rem; }
  .stats, .arch, .cta-band { grid-template-columns:minmax(0, 1fr); }
  .cta-band .hero-actions { justify-content:flex-start; flex-wrap:wrap; }
  .gallery { grid-template-columns:repeat(2, minmax(0, 1fr)); }
}
@media (max-width:720px) {
  .band { padding-top:3.5rem; }
  .band + .band { padding-top:4rem; }
  .gallery, .tiers, .kpis { grid-template-columns:minmax(0, 1fr); }
  .bar { grid-template-columns:auto minmax(0, 1fr) auto; gap:.6rem; }
  .bar-label { font-size:.78rem; }
  .cta-band { padding:1.8rem 1.3rem; border-radius:14px; }
  /* Unter 720px skaliert das Diagramm auf unter 400px, die Mono-Unterzeilen fielen
     unter 7px. Sie fallen weg; die Liste daneben traegt dieselben Angaben. */
  .diagram .d-sub { display:none; }
  .shot-frame, .tile, .bars, .kpi, .tier { border-radius:10px; }
}

/* ── Preisstaffel ────────────────────────────────────────────────
   Die Seite traegt ein Bedienelement - eine getoente Mulde, darin die beiden
   Stufen als erhabene Tasten - und darunter die Vergleichstabelle ueber die
   volle Buehne. Begruendung und die Regeln, die zusammenhaengen, stehen in
   DESIGN.md. (Der fruehere Produktumschalter Grid/Chart/Buendel ist mit dem
   Open-Core-Schnitt entfallen; sein CSS ist weg.) */
.plans { max-width:none; }

/* Die Mulde: ein zurückgesetzter Grund, in dem Umschalter und beide
   Stufen zusammen liegen. Sie ist der Grund, warum die Seite als EIN
   Bedienelement liest — nicht eine Kontur um alles, sondern eine Fläche
   unter allem. Wer sie auf --surface stellt, verliert genau das: dann
   schweben drei weiße Flächen auf weißem Grund. */
/* Die Mulde behält ihre Breite (--content-max), steht darin aber mittig
   auf der Bühne — die einzige zentrierte Stelle der Website. Das
   widerspricht der linken Kante NICHT: die Mulde ist kein Textblock,
   sondern ein Gerät, und ein Gerät steht vor einem, nicht neben einem.
   Die Vergleichstabelle darunter nimmt dagegen die volle Bühne und hängt
   weiter an der linken Kante — dieser Unterschied ist die Aussage:
   erst wählen (mittig, gefasst), dann vergleichen (breit, offen).
   Nicht schmaler machen: unter --content-max wird der Umschalter enger
   als die Tabelle, die er steuert, und liest dann wie ein Beiwerk.
   Auf schmalen Schirmen greift max-width ohnehin nicht mehr, die Mulde
   füllt dann wieder alles. */
.plan-well { max-width:var(--content-max); margin-inline:auto;
             background:var(--bg-soft); border:1px solid var(--line);
             border-radius:var(--radius); padding:.5rem; }
/* Keine Lücke mehr, eine Fuge: "zwei Tasten eines Geräts" wörtlich
   genommen. Bei .65rem waren es zwei Karten, die nebeneinander lagen;
   bei 1px ist es EINE Platte, die geteilt ist — und das ist die Aussage,
   denn geteilt wird hier nicht das Angebot, sondern die Entscheidung.
   Der Abstand wächst mit den Tasten NICHT mit: eine Fuge hat keine
   Größe, sie hat nur eine Lage. Wer ihn wieder öffnet, bekommt zwei
   Karten zurück und muss dann auch die Eckenteilung unten rückgängig
   machen — die beiden Zeilen gehören zusammen. */
.plan-keys { display:grid; grid-template-columns:repeat(2, minmax(0, 1fr));
             gap:1px; align-items:stretch; }
/* Flach statt hoch: die Taste trägt nur noch Name, Preis und Schaltfläche.
   "Flach" heißt knapp gebaut, nicht klein gesetzt — die Taste ist das
   erste, was auf der Seite gelesen wird, und trägt deshalb ihre Schrift
   in voller Größe. Was sie NICHT wieder tun darf: in die Höhe wachsen und
   die Merkmalstabelle unter die Falzkante schieben. Dort wird entschieden.
   Erhaben statt umrandet: in der Mulde trägt der Schatten die Trennung,
   eine Kontur wäre die zweite Linie neben der der Mulde. An der Fuge
   liegen jetzt zwei Schatten aneinander, und genau das zeichnet sie:
   die Trennlinie ist nirgends gemalt, sie entsteht.
   Nur die ÄUSSEREN Ecken sind gerundet, die inneren nicht — sonst
   stünden an der 1px-Fuge vier Radien gegeneinander und die Platte
   fiele wieder in zwei Karten auseinander. */
.plan-key { display:flex; flex-wrap:wrap; align-items:baseline; gap:.45rem 1rem;
            background:var(--surface); border-radius:11px 0 0 11px;
            padding:1rem 1.15rem; box-shadow:var(--shadow); }
/* Die Empfehlung trägt KEINE Kontur mehr. Die 2px in --fg waren die
   einzige schwarze Linie der Seite und zogen als Kasten um die rechte
   Hälfte genau die Fuge wieder auf, die die Tasten zusammenhält — die
   Platte fiel damit optisch doch in zwei Karten. Ausgezeichnet wird die
   Stufe weiter, nur nicht doppelt: die gefüllte Akzent-Schaltfläche
   steht ohnehin nur hier, und sie ist die Farbe, die die Website für
   Hauptaktionen führt. Keine invertierte Fläche, kein Abzeichen: das
   wären Aussagen über das Angebot, nicht über die Empfehlung. */
.plan-key-featured { border-radius:0 11px 11px 0; }

/* Der Name steht auf eigener Zeile über Preis und Schaltfläche — keine
   Haarlinie mehr darunter: in der flachen Taste wäre sie die dritte Linie
   auf zwei Zentimetern. */
.plan-name { font-size:1.05rem; font-weight:650; letter-spacing:-.01em;
             color:var(--fg); margin:0; flex:1 0 100%; }
/* Der Preis bleibt das größte Element der Taste, aber er ist nicht mehr der
   Aufmacher der Seite. tabular-nums, weil die beiden Preise nebeneinander
   stehen — sonst tanzt €1.199 gegen €999.
   Was an Polsterung und Abstand gespart wurde, steht hier: 2.7rem statt
   2.35, halbfett statt mittel, enger gesetzt. Das ist der ganze Handel —
   die Mulde wird dichter UND lauter, und sie wird dabei flacher als
   vorher, statt die Merkmalstabelle unter die Falzkante zu schieben.
   Wer den Preis weiter aufdreht, muss die Polsterung erst wieder
   hergeben; das Höhenmaß ist die Grenze, nicht die Punktzahl. */
.plan-price { font-size:2.7rem; font-weight:600; letter-spacing:-.04em;
              line-height:1.1; margin:0; font-variant-numeric:tabular-nums; }
.plan-period { color:var(--muted); font-size:.95rem; margin:0; flex:1 1 auto; }

/* Volle Breite auf eigener Zeile, Geisterschaltfläche als Standard, gefüllt
   nur auf der empfohlenen Stufe. */
.plan-cta { margin:.8rem 0 0; flex:1 0 100%; display:block; text-align:center;
            padding:.72rem 1rem; border-radius:9px; font-size:.98rem;
            font-weight:600; text-decoration:none; background:var(--bg-soft);
            color:var(--fg); border:1px solid var(--line);
            transition:background .12s, color .12s; }
.plan-cta:hover { background:var(--accent-soft); color:var(--accent); }
/* Gefüllt in --accent, nicht in Schwarz: --accent ist die Hauptaktions-
   farbe der ganzen Website, eine schwarze Schaltfläche nur auf dieser
   Seite wäre eine zweite Schaltflächensprache. */
.plan-cta-filled { background:var(--accent); color:var(--accent-ink);
                   border-color:var(--accent); }
.plan-cta-filled:hover { background:var(--accent-hover); color:var(--accent-ink); }

/* ── Vergleichstabelle ─────────────────────────────────────────────
   Mehr Abstand zur Mulde als zwischen den Teilen darin: erst wird
   gewählt, dann verglichen, und die Lücke ist das, was die beiden
   Schritte trennt. */
.compare-wrap { margin-top:2.4rem; }
/* Der Abstand steckt schon im Abschnitt — die h2-Vorgabe aus dem Rahmen
   würde ihn verdoppeln. Kleiner als eine gewöhnliche h2, weil sie hier
   eine Tabelle benennt und nicht ein Kapitel eröffnet. */
.compare-title { font-size:1.05rem; margin:0 0 .6rem; }
.compare { width:100%; }
/* Ohne Karte darum: die Zeilen-Haarlinien tragen die Tabelle allein. Etwas
   mehr Zeilenhöhe als in der Karte, weil die Tabelle jetzt direkt auf dem
   Grund steht und keine Kante mehr hat, die sie zusammenhält. */
.compare th, .compare td { padding:.55rem 0; }
.compare .tier-col { text-align:center; width:7.5rem; }
.compare tbody th { font-weight:400; padding-right:1rem; }
.compare .check { width:1.15rem; height:1.15rem; color:var(--fg);
                  vertical-align:-.2em; }
.compare .dash { color:var(--muted); }
/* Optisch weg, im Accessibility-Tree vorhanden — dieselbe Technik wie bei
   der Burger-Checkbox. Ohne das wären Haken und Strich stumme Zellen. */
.sr-only { position:absolute; width:1px; height:1px; margin:0; padding:0;
           border:0; overflow:hidden; clip:rect(0 0 0 0); clip-path:inset(50%);
           white-space:nowrap; }
@media (max-width:620px) {
  /* Einspaltig gibt es keine Fuge mehr, die man teilen könnte: die beiden
     Tasten stehen untereinander, bekommen ihre vier Radien zurück und
     einen echten Abstand. Eine 1px-Fuge über die Waagerechte läse als
     Fehler, nicht als Teilung. */
  .plan-keys { grid-template-columns:1fr; gap:.5rem; }
  .plan-key, .plan-key-featured { border-radius:11px; }
  /* Auf dem Finger statt auf der Maus: die flache Taste kommt sonst auf 41px
     und bleibt unter dem üblichen Mindestmaß von 44px. */
  .plan-cta { padding:.62rem 1rem; }
  .compare .tier-col { width:4.2rem; }
  .compare { font-size:.85rem; }
}

/* ── Dokumentation: Kapitel links, Text, Gliederung rechts ────────
   Die VIERTE Stelle, die über --content-max hinausdarf — die drei anderen
   sind der Aufmacher, sein Grund und die Preisseite.

   Sie kostet mehr als die drei, und der Preis gehört benannt: die Textspalte
   hängt hier NICHT mehr an der linken Bühnenkante. Die Fluchtlinie
   Wortmarke → Überschrift → letzter Absatz (siehe DESIGN.md) gilt auf den
   Doku-Seiten also nicht mehr. Was die Kante hält, ist stattdessen das
   Kapitelverzeichnis: links steht weiter etwas, und es steht auf demselben
   Pixel wie die Wortmarke darüber. Wer die Reihenfolge wieder umdreht,
   bekommt die Fluchtlinie zurück und verliert die Leserichtung, in der eine
   Dokumentation gesucht wird — das ist der Handel, und er ist bewusst so
   herum entschieden.

   Zwei Verzeichnisse mit verschiedener Reichweite: links WO IN DER DOKU,
   rechts WO AUF DIESER SEITE. Beide tragen deshalb dieselbe Marke (2px
   Akzentstrich links neben der Zeile) — es ist zweimal dieselbe Aussage auf
   zwei Maßstäben, nicht zwei verschiedene.

   minmax auf beiden Verzeichnissen, 1fr in der Mitte: der Text bekommt, was
   übrig ist, und die Spuren geben unterwegs nach, statt an einer Schwelle
   umzuklappen. Bei 1360px Bühne bleiben rund 775px für den Text — mehr als
   die 64 Zeichen, bei denen die Fließspalte ohnehin aufhört. */
.docs-shell { max-width:none; display:grid;
              grid-template-columns:minmax(11rem, 13rem)
                                    minmax(0, 1fr)
                                    minmax(10rem, 12rem);
              gap:3rem; align-items:start; }
/* Ohne Gliederung nur zwei Spuren. Das Raster merkt das nicht von selbst — eine
   leere dritte Spur ist trotzdem eine Spur, und die Textspalte bliebe schmal,
   während rechts 192px nichts stünde. Die Klasse setzt DocsPage beim Bauen (nicht
   :has(.docs-toc): die Gliederung ist das letzte Kind, und während das Dokument
   ankommt, gibt es sie noch nicht — dieselbe Falle wie beim Kopfband). */
.docs-shell-flat { grid-template-columns:minmax(11rem, 13rem) minmax(0, 1fr); }
.docs-body { min-width:0; }

/* Beide Verzeichnisse bleiben stehen, während der Text läuft: sie beantworten
   „wo bin ich", und diese Frage stellt sich unterwegs, nicht am Seitenanfang.
   Der Abstand nach oben ist die gemessene Bandhöhe plus Luft — --header-h
   schreibt nav-fit.js vor dem ersten Paint auf <html> (siehe base.css), ein
   fester Wert stimmte nur für eine Schriftgröße.
   Der Deckel ist eine Vorsorge und kein Normalfall: sieben Kapitel und ein
   Dutzend Überschriften passen auf jeden Schirm. Wächst eines davon, soll es
   in sich scrollen statt unter den Seitenrand zu laufen. */
.docs-rail, .docs-toc { position:sticky; top:calc(var(--header-h) + 2.5rem);
                        max-height:calc(100svh - var(--header-h) - 5rem);
                        overflow-y:auto; }
/* 40px zwischen den Gruppen — dasselbe Maß wie zwischen den Menüpunkten im
   Band oben und in den Rinnen der Fusszeile. */
.docs-rail-group + .docs-rail-group { margin-top:2.5rem; }
/* Impeccables Etikett: klein, gesperrt, Versalien, Mono. Es ist in der
   Referenz die durchgehende Kleinschrift, und es ist der Teil von ihr, der
   sich ohne die Goldpalette übertragen lässt. Der globale h2 (1.35rem, 4rem
   Vorlauf) gilt der Fließspalte und wäre hier ein Bruch — deshalb ganz
   zurückgesetzt, wie schon bei .footer-head.
   18px unter die Überschrift, Impeccables engstes Maß. */
.docs-rail-head, .docs-toc-head { margin:0 0 1.125rem; font-family:var(--mono);
                  font-size:.7rem; font-weight:600; letter-spacing:.11em;
                  text-transform:uppercase; color:var(--muted); }
/* Gedämpft, bei Hover in voller Tinte — dieselbe Rückmeldung wie bei den
   Menüpunkten oben und in der Fusszeile. Der Einzug hält den Platz für den
   Strich frei, damit die Zeile beim Wechsel nicht springt. */
.docs-rail a, .docs-toc a { display:block; padding:.2rem 0 .2rem .9rem;
               border-left:2px solid transparent;
               color:var(--muted); text-decoration:none; font-size:.9rem;
               line-height:1.45;
               transition:color .12s, border-color .12s; }
.docs-rail a:hover, .docs-toc a:hover { color:var(--fg); }
/* Die aktuelle Stelle trägt einen 2px-Strich in --accent — dieselbe Sprache
   wie der Strich unter dem aktiven Menüpunkt im Kopfband, nur um 90° gedreht
   (Hierarchie aus gezeichneten Linien, *Primora*). KEINE gefüllte Pille: die
   bleibt den Bedienelementen der Seite vorbehalten. Bewusst ohne font-weight
   — fett änderte die Breite, und rechts läuft die Marke beim Scrollen mit:
   eine Zeile, die dabei breiter wird, schöbe ihre Nachbarn um.

   Links steht sie auf aria-current="page" (welche SEITE), rechts auf
   aria-current="true" (welcher ABSCHNITT, gesetzt von layout.js). Zwei
   Attributwerte, weil es zwei Reichweiten sind — dasselbe Zeichen, weil es
   dieselbe Aussage ist. */
.docs-rail a[aria-current], .docs-toc a[aria-current] {
    color:var(--fg); border-left-color:var(--accent); }
/* Eine Spur kleiner als die Kapitel links: die Gliederung ist die feinere
   Ebene, und in der Referenz staffelt sich Hierarchie über die Größe der
   Kleinschrift, nicht über eine weitere Fläche. */
.docs-toc a { font-size:.85rem; }
@media (prefers-reduced-motion:reduce) {
  .docs-rail a, .docs-toc a { transition:none; }
}

/* Zurück/weiter am Fuss. Eine Haarlinie darüber, anders als bei der
   Fusszeile: dort grenzt Weißraum den Rahmen vom Inhalt ab, hier stehen zwei
   Sorten Inhalt übereinander, und der Schnitt ist derselbe wie zwischen zwei
   Tabellenzeilen. 64px Vorlauf, das Abschnittsmaß. */
.docs-seq { display:flex; flex-wrap:wrap; align-items:start;
            justify-content:space-between; gap:1.5rem 2.5rem;
            margin-top:4rem; padding-top:1.5rem;
            border-top:1px solid var(--line); }
.docs-seq a { display:flex; flex-direction:column; gap:.2rem;
              color:var(--fg); text-decoration:none; font-size:.95rem; }
.docs-seq a:hover .seq-label { color:var(--accent); }
/* Dasselbe Etikett wie über den Gruppen im Band und über den Codeblöcken —
   drei Stellen, eine Figur. */
.docs-seq .seq-dir { font-family:var(--mono); font-size:.68rem; font-weight:600;
                     letter-spacing:.11em; text-transform:uppercase;
                     color:var(--muted); }
.docs-seq .seq-label { transition:color .12s; }
/* margin-left:auto, damit „Next" auch dann rechts steht, wenn es allein
   dasteht — auf der ersten Seite gibt es kein „Previous", das es dorthin
   schöbe. */
.docs-seq .seq-next { margin-left:auto; text-align:right; }
@media (prefers-reduced-motion:reduce) { .docs-seq .seq-label { transition:none; } }

/* Der Dateiname über einem Block. Kein Kasten, kein Reiter: dasselbe
   Mono-Etikett wie im Band, damit die Seite eine Kleinschrift kennt und
   nicht drei. */
.code { margin:1.75rem 0 0; }
.code > figcaption { margin:0 0 .5rem; font-family:var(--mono); font-size:.68rem;
                     font-weight:600; letter-spacing:.11em; text-transform:uppercase;
                     color:var(--muted); }
.code > pre { margin:0; }

/* Merkkasten. Bewusst OHNE Akzent: den führt diese Seite an genau zwei
   Stellen — Verweise und die aktuelle Seite im Band —, und ein dritter
   Gebrauch nähme dem Strich im Band seine Aussage. Die Fläche allein setzt
   den Kasten ab, den Rest trägt das Etikett. */
.note { margin:1.75rem 0 0; padding:.9rem 1.15rem;
        background:var(--bg-soft); border:1px solid var(--line);
        border-left-width:2px; border-radius:0 10px 10px 0; }
.note > :first-child { margin-top:0; }
.note > :last-child { margin-bottom:0; }
/* Als einziges der drei Mono-Etiketten in voller Tinte und nicht gedämpft, und
   zwar gemessen: --muted auf --bg-soft ergibt im Hellen 4,24:1 und reißt WCAG AA
   (4,5:1). Auf --bg reicht derselbe Ton (4,72:1), und dort stehen die beiden
   anderen Etiketten auch — nur dieses sitzt auf der getönten Fläche.
   Es ist zugleich die richtige Gewichtung: das Etikett BENENNT den Kasten, die
   beiden anderen begleiten etwas, das schon da ist. In *Impeccable* ist die
   Annotation das lauteste Element der Seite (gefülltes Gelb); volle Tinte auf
   sechs Buchstaben in 11px ist davon die leise Übersetzung. */
.note-head { display:block; margin:0 0 .3rem; font-family:var(--mono);
             font-size:.68rem; font-weight:600; letter-spacing:.11em;
             text-transform:uppercase; color:var(--fg); }
/* Im Kasten ist die Zeile ohnehin schon eingerückt — die 64ch des Rahmens
   ergäben dort eine zweite, engere Spalte in einer schmalen Fläche. */
.note p { max-width:none; font-size:.95rem; }

/* Drei Spuren brauchen Platz. Die Grenze ist 1150px — dieselbe Zahl, bei der
   der Aufmacher untereinander fällt (siehe .hero-split): eine dritte Schwelle
   machte aus einer Regel eine Sammlung.

   Darunter steht alles untereinander, und zwar in DIESER Reihenfolge:
   Text, zurück/weiter, Kapitel. Das ist die Rangfolge auf einem schmalen
   Schirm — man ist wegen des Textes hier, die Nachbarseite ist der häufige
   Weg, das Kapitelverzeichnis der seltene. Im Dokument steht es weiterhin
   VOR dem Text (dort ist es der äußere der beiden Wege); order dreht nur die
   Darstellung.

   Die Gliederung rechts entfällt ganz. Sie ist die Abkürzung durch eine
   Seite, die man auf einem schmalen Schirm ohnehin scrollt, und als vierter
   Block unter dem Text wäre sie eine zweite Inhaltsangabe hinter dem Inhalt.
   Deshalb display:none und nicht bloß umsortiert — was nichts mehr leistet,
   soll auch nicht mehr geladen aussehen. */
@media (max-width:1150px) {
  .docs-shell { grid-template-columns:minmax(0, 1fr); gap:3.5rem; }
  .docs-body { order:1; }
  .docs-toc { display:none; }
  /* Aus dem Verzeichnis werden drei gleiche Spuren wie in der Fusszeile —
     dort haben sie schon bewiesen, dass sie auf jeder Breite aufgehen. */
  .docs-rail { order:2; position:static; max-height:none; overflow:visible;
               display:grid; grid-template-columns:repeat(3, minmax(0, 1fr));
               gap:2.5rem; }
  .docs-rail-group + .docs-rail-group { margin-top:0; }
}
@media (max-width:560px) {
  .docs-rail { grid-template-columns:1fr; gap:1.75rem; }
  .code > pre, main pre { border-radius:8px; }
}

/* ── API-Referenz ──────────────────────────────────────────────────
   Erzeugte Seiten (ApiReference, Pages/Api*.razor) im Doku-Rahmen: sie erben
   .docs-shell, .docs-rail und .docs-toc und bringen hier nur mit, was eine
   Referenz zusaetzlich hat - Signaturen, Etiketten, Typlisten, die Suche.
   Dieselben Mittel wie die Doku: Mono-Etikett in Versalien, Haarlinien, --bg-soft
   als Mulde. Der Akzent bleibt bei Verweisen; die Zonenmarke ist ein Rahmen, keine
   gefuellte Pille (die gehoert den Bedienelementen). */
.api-body h1 { font-size:clamp(1.9rem, 2.8vw, 2.5rem); }
.api-h1-kind { font-size:.5em; font-weight:500; letter-spacing:0; color:var(--muted); }
.api-crumbs { margin:0 0 .4rem; font-family:var(--mono); font-size:.72rem;
              letter-spacing:.06em; color:var(--muted); }
.api-crumbs a { color:var(--muted); text-decoration:none; }
.api-crumbs a:hover { color:var(--accent); text-decoration:underline; }
.api-lead { font-size:1.05rem; }
.api-badge { display:inline-block; vertical-align:middle; margin-left:.4rem;
             padding:.15rem .5rem; font-family:var(--mono); font-size:.68rem;
             font-weight:600; letter-spacing:.11em; text-transform:uppercase;
             line-height:1.4; color:var(--muted); border:1px solid var(--border);
             border-radius:6px; }
/* Pro in Akzent: --accent auf --bg haelt in beiden Schemata AA. */
.api-badge-pro { color:var(--accent); border-color:var(--accent); }
.api-facts { margin:.6rem 0 0; font-size:.88rem; color:var(--muted); }
.api-facts-sep { color:var(--muted); }

/* Signatur: dieselbe Mulde wie ein Codeblock, aber umbrechend - eine Deklaration
   mit zehn Parametern liest sich umbrochen besser als in einer Zeile, die man
   waagerecht schieben muss, und auf dem Telefon waere sie sonst unerreichbar.
   Umbrochen wird bevorzugt an Leerzeichen (pre-wrap). */
main pre.api-decl { white-space:pre-wrap; overflow-wrap:anywhere; margin:1.15rem 0 0; }
.api-decl a { color:inherit; text-decoration:underline; text-decoration-color:var(--border);
              text-underline-offset:.18em; }
.api-decl a:hover { color:var(--accent); text-decoration-color:currentColor; }
.api-code { font-family:var(--mono); font-size:.85rem; }
.api-code a, .api-facts-list a { text-decoration:none; }
.api-code a:hover, .api-facts-list a:hover { text-decoration:underline; }

/* Eckdaten unter der Signatur: zwei Spalten, Etikett links. */
main dl.api-facts-list { display:grid; grid-template-columns:max-content minmax(0, 1fr);
                         gap:.35rem 1.25rem; margin:1.25rem 0 0; font-size:.92rem; }
main .api-facts-list dt { margin:0; font-weight:500; color:var(--muted); }
main .api-facts-list dd { margin:0; max-width:none; color:var(--fg); }
@media (max-width:560px) {
  main dl.api-facts-list { grid-template-columns:minmax(0, 1fr); gap:.1rem; }
  main .api-facts-list dd { margin-bottom:.5rem; }
}

/* Ein Member: Name (h3, verankert), Signatur, Text. Eine Haarlinie trennt die
   Member wie Tabellenzeilen; der Name steht in Mono, er ist ein Bezeichner. */
.api-member { margin:0; padding:1.5rem 0 .25rem; border-top:1px solid var(--line); }
.api-member > h3 { margin:0; font-family:var(--mono); font-size:.95rem; font-weight:600; }
.api-member > p, .api-member > ul, .api-member > ol { margin-top:.75rem; }
.api-label { margin:1.1rem 0 .2rem; font-family:var(--mono); font-size:.68rem;
             font-weight:600; letter-spacing:.11em; text-transform:uppercase;
             color:var(--muted); }
.api-label + p { margin-top:0; }
main dl.api-params { margin:.2rem 0 0; }
main .api-params dt { margin-top:.5rem; font-weight:400; }
main .api-params dd { margin:.1rem 0 0 1rem; color:var(--fg); }
.api-params dd > p { margin:0; }

/* Typlisten der Namespace-Seiten: Name, darunter der erste Absatz der Doku. */
main dl.api-types dt { margin-top:1.1rem; font-weight:600; font-family:var(--mono); font-size:.92rem; }
main dl.api-types dt a { text-decoration:none; }
main dl.api-types dt a:hover { text-decoration:underline; }
.api-kind, .api-obsolete-tag { margin-left:.5rem; font-family:var(--mono); font-size:.7rem;
                               font-weight:400; color:var(--muted); }
.api-obsolete-tag { color:var(--warn); }
.api-typelist { columns:2 16rem; column-gap:2.5rem; padding-left:0; list-style:none; }
main .api-typelist { padding-left:0; }
main .api-typelist li { margin:.2rem 0; break-inside:avoid; font-family:var(--mono); font-size:.85rem; }
.api-typelist a { text-decoration:none; }
.api-typelist a:hover { text-decoration:underline; }

/* Paketliste der Uebersicht: Name und Zahl in einer Zeile, Beschreibung darunter. */
main .api-index { list-style:none; padding:0; margin:1.25rem 0 0; }
main .api-index li { max-width:none; margin:0; padding:.9rem 0; border-top:1px solid var(--line);
                     display:grid; grid-template-columns:minmax(0, 1fr) auto; gap:.15rem 1rem; }
.api-index-name { font-family:var(--mono); font-weight:600; text-decoration:none; }
.api-index-name:hover { text-decoration:underline; }
.api-index-meta { font-size:.85rem; color:var(--muted); }
.api-index-desc { grid-column:1 / -1; font-size:.92rem; color:var(--muted); }

/* Enum-Werte als Tabelle; die Messwerte-Optik aus base (fett, Ziffern) gilt hier nicht. */
main .api-enum tbody td { font-weight:400; }
.api-enum tr[id] { scroll-margin-top:calc(var(--header-h) + 1.5rem); }
.api-enum td > p { margin:0; }
.api-seealso { padding-left:1.1rem; }
.api-obsolete { margin-top:1rem; }

/* Die Suche. Ohne Skript verborgen (hidden), mit Skript ein Feld und eine Liste. */
.api-search { margin:2rem 0 0; }
.api-search[hidden] { display:none; }
.api-search-label { display:block; margin:0 0 .45rem; font-family:var(--mono); font-size:.68rem;
                    font-weight:600; letter-spacing:.11em; text-transform:uppercase; color:var(--fg); }
.api-search-input { width:100%; max-width:32rem; padding:.65rem .85rem; font:inherit;
                    color:var(--fg); background:var(--surface); border:1px solid var(--border);
                    border-radius:10px; }
.api-search-input:focus-visible { outline:2px solid var(--accent); outline-offset:1px; }
main .api-search-status { margin:.5rem 0 0; font-size:.85rem; color:var(--muted); min-height:1.4em; }
main .api-search-results { list-style:none; padding:0; margin:.25rem 0 0; }
main .api-search-results li { max-width:none; margin:0; padding:.4rem 0;
                              border-bottom:1px solid var(--line); }
.api-search-results a { font-family:var(--mono); font-size:.88rem; text-decoration:none; }
.api-search-results a:hover { text-decoration:underline; }
.api-search-meta { margin-left:.6rem; font-size:.8rem; color:var(--muted); }

/* Lange Paket- und Typnamen (ArionUI.Rendering.Avalonia, CellContextMenuEventArgs)
   brechen im Band um statt die Spur zu sprengen - sonst bekaeme das klebende Band
   eine waagerechte Laufleiste und schnitte die Namen ab. Die Bruchstellen (nach dem
   Punkt, vor dem Binnenversal) setzt ApiPage als <wbr>; break-word ist nur der Notnagel. */
.api-shell .docs-rail { overflow-x:hidden; }
.api-shell .docs-rail a { overflow-wrap:break-word; }

/* ── Abschnittskarte ─────────────────────────────────────────────── */
/* Weiße Karte auf dem Farbwasch — Wizas Grundfigur: der Grund trägt die
   Stimmung, die Karte trägt den Inhalt. */
.card { background:var(--surface); border:1px solid var(--border);
        border-radius:16px; padding:1.4rem 1.5rem; margin:1.2rem 0;
        box-shadow:var(--shadow); }
.card > :first-child { margin-top:0; }
.card > :last-child { margin-bottom:0; }
@media (max-width:560px) {
  .card { padding:1.1rem 1rem; border-radius:12px; }
}

/* ── Doku-Bausteine ──────────────────────────────────────────────── */
/* Die Zonenzeile unter einer Pro-Seitenüberschrift: dieselbe Marke wie in der
   Galerie der Startseite (.zone / .zone-pro), dazu ein gedämpfter Satz. Eine
   zweite Pro-Marke zu erfinden hiesse, dieselbe Aussage in zwei Zeichen zu sagen. */
.doc-zone { display:flex; flex-wrap:wrap; align-items:center; gap:.4rem .75rem;
            margin:.9rem 0 0; font-size:.88rem; color:var(--muted); }

/* Mitgliedertabelle: Name links, Erklärung rechts. Setzt die Messwerte-Tabelle aus
   base.css zurück (dort ist jede Zelle halbfett und tabellarisch, hier wäre das
   zwanzig Zeilen Fettdruck). Der Kasten scrollt waagerecht statt die Seite, wie
   ein Codeblock - eine umbrochene Signatur liest sich als zwei. */
.table-scroll { overflow-x:auto; margin:1rem 0 0; }
.table-scroll > table { margin:0; }
main .members tbody td { font-weight:400; font-variant-numeric:normal; color:var(--muted); }
main .members tbody th { padding-right:1.25rem; width:38%; }
main .members tbody th code { white-space:nowrap; }
main .members thead th:first-child { padding-right:1.25rem; }
@media (max-width:560px) {
  main .members tbody th { width:auto; }
}

/* Eine Produktaufnahme in der Doku: dieselbe Fassung wie auf den Produktseiten,
   aber schmaler - die Kacheln sind 800x600 und füllten sonst die halbe Höhe. */
.shot.doc-shot { max-width:36rem; margin-top:1.75rem; }

/* ── Board & Styling, Roadmap (2026-10-04) ───────────────────────────
   Geplantes muss auf den ersten Blick anders aussehen als Gebautes: gestrichelter Rand,
   kein Schatten, die Marke "Planned" ebenfalls gestrichelt. Keine neue Farbe - dieselben
   Tokens wie .zone und .note. */
.zone-planned { border-style:dashed; background:none; }
.planned { margin:1.75rem 0 0; padding:1.1rem 1.25rem 1rem; border:1px dashed var(--border);
           border-radius:14px; max-width:none; }
.planned-head { margin:0; display:flex; align-items:center; gap:.7rem; font-weight:600; max-width:none; }
.planned-list { margin:.9rem 0 0; padding:0; list-style:none; display:grid; column-gap:2.2rem;
                grid-template-columns:repeat(auto-fill, minmax(min(100%, 24rem), 1fr)); }
.planned-list li { margin:.55rem 0 0; max-width:none; padding-left:1.1rem; position:relative; font-size:.93rem; }
.planned-list li::before { content:""; position:absolute; left:0; top:.6em; width:.45rem; height:.45rem;
                           border:1.5px dashed var(--muted); border-radius:50%; }
.planned-why { display:block; color:var(--muted); font-size:.88rem; }
.planned-foot { margin:1rem 0 0; font-size:.82rem; color:var(--muted); max-width:none; }

/* Zwei Kacheln nebeneinander (breit gegen schmal) und eine hochkant stehende Kachel, die
   ihr eigenes Seitenverhaeltnis behaelt statt auf 4:3 beschnitten zu werden. */
.gallery-pair { grid-template-columns:minmax(0, 1.3fr) minmax(0, 1fr); margin-top:1.6rem; align-items:start; }
.tile-img-tall { aspect-ratio:608 / 784; }

/* Roadmap: vier Spalten Gebautes, darunter Listen mit Marke vorne. */
.roadmap-jump { margin:1.2rem 0 0; font-family:var(--mono); font-size:.78rem; color:var(--muted); }
.roadmap-cols { display:grid; grid-template-columns:repeat(2, minmax(0, 1fr)); gap:1.2rem 2.4rem; max-width:none; margin-top:1rem; }
.roadmap-cols h3 { display:flex; align-items:center; gap:.6rem; margin:1rem 0 .2rem; font-size:1.05rem; }
.roadmap-list { padding-left:1.1rem; }
.roadmap-list li { margin:.5rem 0; }
.roadmap-planned { list-style:none; padding:0; }
.roadmap-planned .zone { margin-right:.4rem; vertical-align:.1em; }

/* Startseite: Abschnitt "the rest of the window" - Aufnahme links, Code rechts - und die
   drei Zielgruppen als Karten in derselben Sprache wie die Core/Pro-Karten. */
.board-split { display:grid; grid-template-columns:minmax(0, 1.45fr) minmax(0, 1fr); gap:2rem 2.6rem;
               margin-top:2rem; align-items:start; max-width:none; }
.board-split .code { margin-top:0; }
.board-split .code pre { font-size:.78rem; }
.board-points { margin:1.2rem 0 0; padding-left:1.1rem; font-size:.92rem; }
.board-points li { margin:.35rem 0; }
.audiences { display:grid; grid-template-columns:repeat(3, minmax(0, 1fr)); gap:1.4rem; margin-top:2rem; max-width:none; }
.audience { margin:0; display:flex; flex-direction:column; background:var(--surface); border:1px solid var(--border);
            border-radius:14px; overflow:hidden; }
.audience .tile-img { border-bottom:1px solid var(--line); }
.audience-body { padding:1.1rem 1.25rem 1.3rem; }
.audience h3 { margin:0; font-size:1.05rem; letter-spacing:-.01em; }
.audience p { margin:.5rem 0 0; font-size:.9rem; color:var(--muted); max-width:none; }
.audience .tile-cap { margin-top:.6rem; font-size:.75rem; }
@media (max-width:1150px) {
  .board-split { grid-template-columns:minmax(0, 1fr); }
  .audiences { grid-template-columns:minmax(0, 1fr); }
}
@media (max-width:720px) {
  .gallery-pair, .roadmap-cols { grid-template-columns:minmax(0, 1fr); }
  .planned { padding:1rem; border-radius:10px; }
  .audience { border-radius:10px; }
}
/* Die Unterzeile der H1 (seit 2026-10-04): die drei Tatsachen, die die H1 traegt, in der
   Schrift des Aufmachers, eine Stufe ueber dem Fliesstext. Die Messwert-Ueberschrift traegt
   den Akzent wie frueher die H1. */
.hero-tagline { margin:1.1rem 0 0; font-size:1.18rem; font-weight:600; letter-spacing:-.015em; color:var(--fg); max-width:none; }
.band-head h2 .accent { color:var(--accent); }
.cta-modernise { margin-top:2.6rem; }
