/*
 * hand-e.de -- das Aussehen der Firmenseite.
 * Richtung "Nachtblau", gewaehlt von Max am 2026-09-04.
 *
 * ⚠ DAS IST NICHT DAS THEME DER APP, und das ist der Punkt.
 *
 * Die App liegt auf `#F1F1F1` mit Petrol `#0B7285`, weil sie
 * eingebettet im Shopify-Admin laeuft und sich dort einfuegen muss.
 * Diese Seite hat diese Auflage nicht. Sie ist der Absender, nicht der
 * Gast, und traegt deshalb eine eigene Farbe: elektrisches Blau auf
 * Nachtblau-Schwarz.
 *
 * ⚠ EIN THEMA FUER DIE GANZE SEITE. Kein Abschnitt kippt ins Helle.
 * Eine halb dunkle, halb helle Seite fuehlt sich an, als waere man
 * mitten im Scrollen auf einer anderen Website gelandet.
 *
 * ⚠ WARUM DUNKEL FESTGENAGELT UND NICHT `prefers-color-scheme`:
 * Die Farbe IST hier die Marke. Ein heller Umschaltzustand waere eine
 * zweite Marke, und die zu pflegen kostet doppelt, solange es genau
 * eine Website und ein Produkt gibt. Die Tokens unten sind semantisch
 * benannt (`--h-grund`, `--h-tinte`), ein zweites Set liesse sich
 * spaeter also ergaenzen, ohne eine einzige Regel anzufassen.
 *
 * ⚠ WARUM NICHT VIOLETT, GRUEN ODER ORANGE:
 *   Violett  ist Shopifys eigene KI (Polaris "magic") UND der
 *            haeufigste KI-Standardton ueberhaupt.
 *   Gruen    ist Shopifys Erfolgszustand und seine Markenfarbe.
 *   Orange   liest Polaris als "in Arbeit".
 * Blau bei Hue 222 ist keins davon und liegt weit genug von Petrol.
 *
 * KONTRASTE, gerechnet und nicht geschaetzt (WCAG 2.1, gegen #060a14):
 *   --h-tinte  #eef2f8   17.4 : 1   AAA
 *   --h-leise  #93a0b8    7.3 : 1   AAA fuer Fliesstext
 *   --h-akzent #6e9bff    7.1 : 1   AAA
 * Wer einen Ton aendert, rechnet nach. Ein zu leiser Grauton ist der
 * haeufigste Barrierefreiheitsfehler auf dunklen Seiten.
 */

/* ------------------------------------------------------------------ */
/* Schriften: lokal, nie von fonts.googleapis.com                      */
/* Begruendung in src/schriften/HERKUNFT.md                            */
/* ------------------------------------------------------------------ */

@font-face {
  font-family: "Geist";
  src: url("/assets/geist.woff2") format("woff2");
  font-weight: 400 600;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Schibsted Grotesk";
  src: url("/assets/schibsted-grotesk.woff2") format("woff2");
  font-weight: 700 800;
  font-style: normal;
  font-display: swap;
}

/* ------------------------------------------------------------------ */
/* Tokens                                                              */
/* ------------------------------------------------------------------ */

:root {
  /* Flaechen, von tief nach hoch */
  --h-grund: #060a14;
  --h-grund-2: #0b1220;
  --h-grund-3: #111b2e;

  /* Linien */
  --h-linie: #1a2540;
  --h-linie-hell: #26324d;

  /* Schrift */
  --h-tinte: #eef2f8;
  --h-leise: #93a0b8;
  --h-still: #6b7794;

  /* Marke */
  --h-akzent: #6e9bff;
  --h-akzent-hell: #9dbaff;
  --h-akzent-tief: #06122e;

  /*
   * Zustaende. Wie in der App: nur in Abzeichen und Bannern, nie als
   * Flaeche. Sie sind KEIN zweiter Akzent.
   */
  --h-gut: #4ade9b;
  --h-warn: #f0c063;

  /* Schriftfamilien */
  --h-font: "Geist", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --h-font-display: "Schibsted Grotesk", var(--h-font);

  /*
   * ⚠ EIN RADIUS-SYSTEM, DOKUMENTIERT.
   * Gemischte Radien ohne Regel sehen aus wie ein Versehen. Die Regel
   * hier: Flaechen und Knoepfe 14px, kleine Dinge 10px, Abzeichen und
   * runde Knoepfe voll. Mehr gibt es nicht.
   */
  --h-r: 14px;
  --h-r-klein: 10px;

  --h-breite: 1240px;
  /* Die Hoehe der Kopfzeile. Sie steht an vier Stellen -- der Zeile
     selbst, der Blende des Menues, der Oberkante des Blattes und
     dessen Hoehenbegrenzung. Vier Aufschreibungen einer Zahl laufen
     auseinander, deshalb hier EINE. */
  --h-kopf-h: 68px;
  --h-breite-text: 40rem;
  --h-luft: clamp(20px, 5vw, 56px);
  --h-ease: cubic-bezier(0.16, 0.84, 0.24, 1);

  /*
   * Die Oberkante jeder Flaeche bekommt einen Punkt Licht, wie eine
   * Kante, auf die von oben Licht faellt. Es ist der Unterschied
   * zwischen einem grauen Rechteck und einem Gegenstand, und es kostet
   * eine Zeile je Flaeche.
   */
  --h-kante: inset 0 1px 0 rgb(255 255 255 / 0.07);
}

/* ------------------------------------------------------------------ */
/* Grundlage                                                           */
/* ------------------------------------------------------------------ */

*,
*::before,
*::after { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  /* Damit ein Sprungziel nicht unter der klebenden Kopfzeile landet. */
  scroll-padding-top: 6rem;
  -webkit-text-size-adjust: 100%;
  color-scheme: dark;
}

/*
 * ⚠ NICHT VERHANDELBAR: Wer Bewegung abbestellt hat, bekommt keine.
 * Alle Eintritte, das Schweben und die Neigung fallen hier weg. Die
 * Inhalte sind ohne Animation sofort vollstaendig da; es geht nichts
 * verloren ausser der Bewegung selbst.
 */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

body {
  margin: 0;
  background: var(--h-grund);
  color: var(--h-tinte);
  font-family: var(--h-font);
  font-size: 1.0625rem;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}

/*
 * ⚠ DAS KORN IST TECHNIK, KEINE DEKORATION.
 *
 * Auf einem dunkelblauen Grund zeigen weiche Verlaeufe Stufen
 * (Banding), weil 8 Bit je Kanal fuer die feinen Abstufungen nicht
 * reichen. Ein Hauch Rauschen bricht die Stufen auf; das Auge sieht
 * dann eine Flaeche statt Streifen. Es liegt FEST ueber dem Fenster
 * auf einem Element ohne Zeigerereignisse, damit es nie neu gemalt
 * wird, waehrend die Seite scrollt.
 *
 * Das Rauschen ist ein SVG-Filter als Daten-URL, also kein Bild, das
 * geladen werden muesste.
 */
body::after {
  content: ""; position: fixed; inset: 0; z-index: 60; pointer-events: none;
  opacity: 0.055;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.55 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 180px 180px;
}

img, svg, video { max-width: 100%; height: auto; display: block; }

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

.h-skip {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  padding: 0.8rem 1.3rem;
  background: var(--h-akzent); color: var(--h-akzent-tief);
  font-weight: 600; border-radius: 0 0 var(--h-r-klein) 0;
}
.h-skip:focus { left: 0; }

.h-sr {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ------------------------------------------------------------------ */
/* Typografie                                                          */
/* ------------------------------------------------------------------ */

h1, h2, h3, h4 {
  font-family: var(--h-font-display);
  font-weight: 800;
  line-height: 1.04;
  letter-spacing: -0.038em;
  margin: 0 0 0.55em;
  text-wrap: balance;
  color: var(--h-tinte);
}

/*
 * ⚠ DIE GROESSEN SIND GEDECKELT, UND ZWAR NIEDRIGER ALS ES REIZT.
 * Eine Ueberschrift, die ueber drei Zeilen laeuft, ist immer ein
 * Groessenfehler und nie ein Textfehler.
 */
h1 { font-size: clamp(34px, 4.1vw, 58px); }
h2 { font-size: clamp(26px, 2.8vw, 38px); margin-top: 0; }
h3 { font-size: clamp(18px, 1.5vw, 21px); font-weight: 700; letter-spacing: -0.02em; }
h4 { font-size: 1rem; font-weight: 600; letter-spacing: -0.01em; }

p, li { text-wrap: pretty; }
p { margin: 0 0 1.15em; }

/* Der graue Blitz, den Mobil-Browser beim Antippen ueber Links legen,
   passt zu nichts auf dieser Seite. Rueckmeldung geben die Elemente
   selbst (Knopf drueckt sich ein, Frage wechselt den Grund). */
a, button, summary { -webkit-tap-highlight-color: transparent; }

a { color: var(--h-akzent); text-decoration-thickness: 1px; text-underline-offset: 0.2em; }
a:hover { color: var(--h-akzent-hell); }

strong { font-weight: 600; color: var(--h-tinte); }

code {
  font-family: ui-monospace, "SFMono-Regular", "Cascadia Mono", Menlo, monospace;
  font-size: 0.92em;
  background: var(--h-grund-2);
  border: 1px solid var(--h-linie);
  border-radius: 6px;
  padding: 0.12em 0.4em;
}

.h-lede {
  font-size: clamp(16.5px, 1.35vw, 19px);
  line-height: 1.58;
  color: var(--h-leise);
  max-width: 44ch;
}

/* ------------------------------------------------------------------ */
/* Aufbau                                                              */
/* ------------------------------------------------------------------ */

.h-bahn {
  width: 100%;
  max-width: var(--h-breite);
  margin-inline: auto;
  padding-inline: var(--h-luft);
}

.h-text { max-width: var(--h-breite-text); }

/*
 * ⚠⚠ DIESE ZAHL VERDOPPELT SICH AN JEDER NAHT.
 *
 * Sie steht oben UND unten. Zwischen zwei benachbarten Abschnitten
 * liegt deshalb immer das Doppelte -- und genau das hat bis zum
 * 2026-09-09 hier gestanden:
 *
 *   alt   clamp(64px, 9vw, 128px)  ->  bei 1440 px: 128 + 128 = 256 px
 *   neu   clamp(48px, 5.5vw, 84px) ->  bei 1440 px:  79 +  79 = 158 px
 *
 * Max: *"Teilweise sind die Abstaende zu den Sektionen viel zu gross."*
 * Er hat recht, und niemand hat 256 Punkte entworfen: 128 sieht als
 * Polsterung vernuenftig aus, und die Summe sieht keiner, weil sie
 * nirgends aufgeschrieben ist.
 *
 * ⚠ WER DIESE ZAHL WIEDER ERHOEHT, WEIL EIN ABSCHNITT "ZU ENG" WIRKT,
 * erhoeht den Abstand zum Nachbarn um das Doppelte. Ein einzelner
 * Abschnitt, der mehr Luft braucht, bekommt sie an SICH -- nicht hier.
 */
.h-abschnitt { padding-block: clamp(48px, 5.5vw, 84px); position: relative; }
.h-abschnitt--eng { padding-block: clamp(32px, 3.5vw, 56px); }

/*
 * Eine leicht gehobene Flaeche statt eines zweiten Themas. So bekommt
 * die Seite Rhythmus, ohne dass irgendwo ins Helle gekippt wird.
 */
.h-abschnitt--hoch { background: var(--h-grund-2); }

/* Die gehobene Flaeche hat oben und unten dieselbe Haarlinie wie die
   Kopfzeile, und oben ein wenig Licht, als kaeme es von der Kante. */
.h-abschnitt--hoch::before, .h-abschnitt--hoch::after {
  content: ""; position: absolute; left: 0; right: 0; height: 1px; pointer-events: none;
  background: linear-gradient(90deg, transparent, var(--h-linie-hell) 25%, var(--h-linie-hell) 75%, transparent);
}
.h-abschnitt--hoch::before {
  top: 0;
  box-shadow: 0 1px 60px 10px color-mix(in srgb, var(--h-akzent) 5%, transparent);
}
.h-abschnitt--hoch::after { bottom: 0; }

/* ------------------------------------------------------------------ */
/* Bewegung                                                            */
/* ------------------------------------------------------------------ */

/*
 * ⚠ JEDE BEWEGUNG HIER HAT EINE AUFGABE.
 *   `h-auf`     Hierarchie: der Blick wird in der Lesereihenfolge
 *               gefuehrt, einmal beim Erscheinen.
 *   `h-zeigt`   dasselbe beim Hereinscrollen, ueber die
 *               Scroll-Zeitachse. KEIN Scroll-Listener.
 *   `h-hebt`    Erzaehlung: die Szene kommt NACH der Ueberschrift,
 *               von unten, einmal. Erst die Aussage, dann der Beweis.
 *   `h-schweb`  Tiefe: die Szene lebt, damit die Perspektive lesbar
 *               wird. Sehr langsam, sehr klein.
 *   `h-treibt`  Tiefe: das Licht hinter dem Hero wandert, wie Licht
 *               durch ein Fenster. Sehr langsam, nur Transform.
 *   `h-kreis`   Hierarchie: der empfohlene Plan traegt einen Ring,
 *               der langsam umlaeuft. Einer je Seite.
 *   Neigung     Rueckmeldung: die Szene folgt dem Zeiger mit
 *               Traegheit. Gerechnet im Skript unten, nicht hier.
 *   Spotlight   Rueckmeldung: Rand und Flaeche einer Karte leuchten
 *               dort auf, wo der Zeiger steht. Keine Animation, nur
 *               eine Position.
 * Was keine Aufgabe hat, bewegt sich nicht.
 *
 * ⚠ ALLES DAVON RESPEKTIERT prefers-reduced-motion. Der Block ganz
 * oben stellt jede Animation auf einen Durchlauf von 0,01 ms, und das
 * Skript prueft dieselbe Einstellung, bevor es die Neigung anfasst.
 */

@keyframes h-auf {
  from { opacity: 0; transform: translateY(18px); }
  to { opacity: 1; transform: none; }
}

.h-auf > * { animation: h-auf 0.8s var(--h-ease) both; }
.h-auf > :nth-child(1) { animation-delay: 0.04s; }
.h-auf > :nth-child(2) { animation-delay: 0.12s; }
.h-auf > :nth-child(3) { animation-delay: 0.2s; }
.h-auf > :nth-child(4) { animation-delay: 0.28s; }
.h-auf > :nth-child(5) { animation-delay: 0.36s; }

/*
 * Scroll-getriebene Animation ueber `animation-timeline: view()`.
 *
 * ⚠ DER STARTZUSTAND STEHT NUR IN DEN KEYFRAMES, nie an der Regel.
 * Ein Browser, der `view()` nicht kennt, ignoriert dann beides und
 * zeigt den Inhalt sofort. Stuende `opacity: 0` an der Regel, bliebe
 * der Abschnitt dort fuer immer unsichtbar.
 */
/*
 * ⚠ GEFUNDEN AM 2026-09-04, UND ES WAR EIN ECHTER FEHLER.
 *
 * Ohne die Klasse .h-scrollt stand die Regel frei da. Auf einem sehr
 * hohen Fenster passt die ganze Seite ins Bild, es gibt nichts zu
 * scrollen, die Zeitachse "view()" wird nie aktiv -- und der Inhalt
 * blieb bei "opacity: 0" haengen. Sichtbar war nur der Hero.
 *
 * Die Fehlerrichtung ist die teuerste: kein Absturz, keine Meldung,
 * nur eine leere Seite fuer jeden mit einem grossen Bildschirm.
 *
 * Die Klasse setzt das Skript unten nur dann, wenn das Dokument
 * hoeher ist als das Fenster. Ohne JavaScript, ohne Scrollbalken oder
 * bei abbestellter Bewegung ist der Inhalt schlicht sofort da.
 */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .h-scrollt .h-zeigt {
      animation: h-auf 1s var(--h-ease) both;
      animation-timeline: view();
      animation-range: entry 5% cover 26%;
    }

    /*
     * Die Zellen eines Rasters kommen NACHEINANDER, in Leserichtung.
     * Eine Zeitverzoegerung gibt es an einer Scroll-Zeitachse nicht,
     * also beginnt jede Zelle ein Stueck spaeter im Sichtfenster.
     */
    .h-scrollt .h-bento > *,
    .h-scrollt .h-plaene > * {
      animation: h-auf 1s var(--h-ease) both;
      animation-timeline: view();
      animation-range: entry 6% cover 24%;
    }
    .h-scrollt .h-bento > :nth-child(2), .h-scrollt .h-plaene > :nth-child(2) { animation-range: entry 12% cover 30%; }
    .h-scrollt .h-bento > :nth-child(3) { animation-range: entry 18% cover 36%; }
    .h-scrollt .h-bento > :nth-child(4) { animation-range: entry 24% cover 42%; }
    .h-scrollt .h-bento > :nth-child(5) { animation-range: entry 30% cover 48%; }
    .h-scrollt .h-bento > :nth-child(6) { animation-range: entry 36% cover 54%; }
  }
}

@keyframes h-schweb {
  from { translate: 0 -8px; }
  to { translate: 0 8px; }
}

@keyframes h-hebt {
  from { opacity: 0; transform: translateY(48px); }
  to { opacity: 1; transform: none; }
}

/*
 * ⚠ NUR TRANSFORM, KEIN HINTERGRUND. Das Licht ist ein Element mit
 * einem Unschaerfefilter. Aendert man seinen Hintergrund, rechnet der
 * Browser die Unschaerfe in jedem Bild neu. Verschiebt man es nur,
 * bleibt das gerechnete Bild stehen und der Kompositor schiebt es.
 */
@keyframes h-treibt {
  from { transform: translate3d(-4%, -3%, 0) scale(1); }
  to { transform: translate3d(4%, 4%, 0) scale(1.1); }
}

/*
 * Ein Winkel als eigene Eigenschaft, damit ein konischer Verlauf
 * animierbar wird. Kennt ein Browser `@property` nicht, steht der
 * Ring still bei 0 Grad. Nichts geht kaputt.
 */
@property --h-winkel { syntax: "<angle>"; inherits: false; initial-value: 0deg; }
@keyframes h-kreis { to { --h-winkel: 360deg; } }

/* ------------------------------------------------------------------ */
/* Kopfzeile                                                           */
/* ------------------------------------------------------------------ */

/*
 * ⚠⚠ DIE UNSCHAERFE LIEGT AUF EINER EIGENEN SCHICHT, NICHT AUF DEM KOPF.
 *
 * Bis zum 2026-09-08 stand `backdrop-filter` direkt auf `.h-kopf`, und
 * das hat zwei Dinge gekostet:
 *
 *   1. Ein Element mit Backdrop-Filter wird zum BEZUGSRAHMEN fuer alles
 *      Fixierte darin. Ein `position: fixed; inset: 0` im Menue haette
 *      sich am 68 Punkte hohen Kopf ausgerichtet statt am Schirm --
 *      ein Vollbild-Blatt war so nicht zu bauen.
 *   2. `-webkit-backdrop-filter` fehlte. Safari kennt die Eigenschaft
 *      ohne Praefix erst seit Version 18; davor lief der Kopf ohne
 *      Unschaerfe und mit 78 Prozent Deckkraft, der Text darunter also
 *      lesbar hindurch. Genau das Geraet, auf dem Max die Seite
 *      ansieht.
 *
 * Auf einer eigenen Schicht tut der Filter dasselbe und faengt nichts.
 * `z-index: -1` bleibt im Stapel des Kopfes (der hat z-index 40), also
 * ueber der Seite und unter allem im Kopf.
 */
.h-kopf { position: sticky; top: 0; z-index: 40; }

.h-kopf::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: color-mix(in srgb, var(--h-grund) 78%, transparent);
  -webkit-backdrop-filter: saturate(160%) blur(16px);
  backdrop-filter: saturate(160%) blur(16px);
}

/* Eine Haarlinie, die zu den Raendern hin verlaeuft, statt einer
   Kante von Rand zu Rand. Dasselbe Motiv trennt unten die Abschnitte. */
.h-kopf::after {
  content: ""; position: absolute; inset: auto 0 0 0; height: 1px;
  background: linear-gradient(90deg, transparent, var(--h-linie-hell) 20%, var(--h-linie-hell) 80%, transparent);
}

/* ⚠ Hoehe gedeckelt. Eine Navigation, die 15 Prozent des Bildes
   frisst, ist ein Fehler und kein Auftritt. */
.h-kopf__bahn { display: flex; align-items: center; gap: 1rem; min-height: var(--h-kopf-h); }

/*
 * Die Marke: Zeichen und Schriftzug, einzeilig.
 *
 * ⚠ DER SCHRIFTZUG IST BEWUSST DER URSPRUENGLICHE. Zwischendurch stand
 * er gestapelt ("Hand-E" ueber gesperrtem "SOLUTIONS") und in Geist 500
 * gesperrt. Beides sah fuer sich gut aus; Max wollte den einzeiligen
 * zurueck. Was bleibt, ist das ZEICHEN an der Stelle, an der frueher
 * das Prozentzeichen der Rabatt-App stand.
 *
 * ⚠ DAS ZEICHEN HAT KEINE PLATTE MEHR. Es ist breiter als hoch; in
 * einem 30er-Quadrat waere es klein und haette oben und unten viel
 * Luft. Freistehend und in currentColor traegt es auf Nachtblau wie auf
 * Weiss. Die Platte lebt weiter im Favicon, wo sie noetig ist.
 */
.h-marke {
  display: inline-flex; align-items: center; gap: 0.6rem;
  font-family: var(--h-font-display); font-weight: 800; font-size: 1.05rem;
  letter-spacing: -0.03em; color: var(--h-tinte); text-decoration: none;
  margin-right: auto;
}

/*
 * ⚠ DER SCHRIFTZUG MUSS EIN EINZIGES ELEMENT SEIN.
 *
 * `.h-marke` ist ein Flex-Container, und dort wird JEDER Textknoten zu
 * einem eigenen Flex-Item. Stand der Name roh im Link, waren "Hand",
 * der Bindestrich-Span und "E Solutions" drei Items -- und `gap` legte
 * zwischen alle drei 0,6 rem. Im Bild las sich das als "Hand - E
 * Solutions", also drei Woerter statt eines Namens.
 *
 * Der Bindestrich braucht deshalb KEINE eigene Luft; die Ursache war
 * nie die Laufweite. Wer hier ein weiteres Element einhaengt, packt es
 * mit in diesen Span.
 */
.h-marke__wort { white-space: nowrap; }

/*
 * Die Breite folgt der Hoehe ueber das viewBox-Verhaeltnis -- keine
 * zweite Zahl, die auseinanderlaufen kann.
 */
.h-marke__zeichen {
  height: 24px; width: auto; display: block; flex: none;
  color: var(--h-akzent);
}

 /*
  * ⚠ DER BINDESTRICH BEKOMMT HIER KEINE EXTRA-LUFT.
  * Im gestapelten Schriftzug (Schibsted 800, 1,15rem, -0,042em) klebte
  * er an beiden Buchstaben und brauchte 0,05 em. Im einzeiligen wirkt
  * dieselbe Zahl wie eine Trennung: "Hand - E Solutions" liest sich als
  * drei Woerter. Im Bild verglichen, nicht gerechnet.
  *
  * Die Klasse bleibt, damit der Bindestrich ansprechbar ist -- wer ihm
  * doch Luft geben will, aendert eine Zahl.
  */
 .h-marke__strich { margin: 0; }

.h-nav { display: flex; align-items: center; gap: 0.2rem; }

.h-nav > a, .h-nav__gruppe > a {
  display: inline-flex; align-items: center; gap: 0.3rem;
  color: var(--h-leise); text-decoration: none; font-size: 0.95rem;
  font-weight: 500; padding: 0.5rem 0.75rem; border-radius: var(--h-r-klein);
  transition: color 0.18s var(--h-ease), background 0.18s var(--h-ease);
}
.h-nav > a:hover, .h-nav__gruppe > a:hover { color: var(--h-tinte); background: var(--h-grund-2); }
.h-nav a[aria-current="page"] { color: var(--h-tinte); }

/* ------------------------------------------------------------------ */
/* Der Flug: die Apps unter dem Eintrag "Apps"                         */
/* ------------------------------------------------------------------ */
/*
 * ⚠ ER OEFFNET AUF :hover UND :focus-within, NICHT AUF KLICK.
 * "Apps" bleibt ein Link auf die Uebersicht. Ein Aufklapp-Knopf haette
 * ihn ersetzt, und dann fuehrte der Weg zur Uebersicht nur noch ueber
 * den Umweg durch das eigene Untermenue. Mit `:focus-within` haelt der
 * Flug auch mit der Tastatur, sobald ein Link darin den Fokus hat.
 *
 * ⚠ DIE LUECKE ZWISCHEN LINK UND BLATT IST GEFUELLT. Der Flug beginnt
 * direkt an der Unterkante des Links (`top: 100%`) und schiebt sein
 * sichtbares Blatt mit `padding-top` nach unten. Ohne das faellt der
 * Zeiger auf dem Weg nach unten durch ein totes Stueck, der Flug
 * schliesst, und man kommt nie an.
 */
.h-nav__gruppe { position: relative; }

/*
 * ⚠ AM RECHTEN RAND AUSGERICHTET, NICHT AM LINKEN.
 * Mit `left: 0` haengt das Blatt an der linken Kante von "Apps" und
 * ragt 21 rem nach rechts -- und die Navigation steht rechts oben.
 * Gemessen im Bild: Es lief aus dem Fenster hinaus und war
 * abgeschnitten. Rechts ausgerichtet waechst es nach innen.
 */
.h-flug {
  position: absolute; top: 100%; right: 0; padding-top: 0.5rem;
  min-width: 21rem; z-index: 3;
  opacity: 0; visibility: hidden; transform: translateY(-6px);
  transition:
    opacity 0.18s var(--h-ease), transform 0.18s var(--h-ease),
    visibility 0s linear 0.18s;
}
.h-nav__gruppe:hover .h-flug,
.h-nav__gruppe:focus-within .h-flug {
  opacity: 1; visibility: visible; transform: none; transition-delay: 0s;
}

.h-flug__blatt {
  background: var(--h-grund-2); border: 1px solid var(--h-linie);
  border-radius: var(--h-r); padding: 0.4rem;
  box-shadow: var(--h-kante), 0 28px 60px -24px #000;
  display: grid; gap: 0.1rem;
}

.h-flug__alle {
  display: inline-flex; align-items: center; gap: 0.4rem;
  margin: 0.25rem 0.2rem 0.1rem; padding: 0.4rem 0.6rem;
  border-radius: var(--h-r-klein);
  font-size: 0.85rem; font-weight: 600; color: var(--h-akzent-hell);
  text-decoration: none;
}
.h-flug__alle:hover { background: var(--h-grund-3); }
.h-flug__alle svg { width: 14px; height: 14px; flex: none; }

/* ------------------------------------------------------------------ */
/* Eine App als Navigationszeile (Flug wie Blatt)                      */
/* ------------------------------------------------------------------ */
.h-navapp {
  display: flex; align-items: center; gap: 0.7rem;
  padding: 0.6rem 0.65rem; border-radius: var(--h-r-klein);
  text-decoration: none; color: var(--h-tinte);
  transition: background 0.16s var(--h-ease);
}
.h-navapp:hover { background: var(--h-grund-3); }

/* ⚠ Die Groesse gehoert INS CSS, nicht nur in die Attribute des
   Bildes. Ein 192 Punkte grosses Icon ohne CSS-Groesse fuellt sonst
   beim naechsten Umbau die halbe Zeile. */
/* ------------------------------------------------------------------ */
/* DAS APP-ICON -- eine Regel fuer alle drei Orte                      */
/* ------------------------------------------------------------------ */
/*
 * ⚠⚠ ES GAB DREI REGELN FUER DASSELBE BILD, UND ZWEI WAREN FALSCH.
 *
 * Bis zum 2026-09-08 war das App-Zeichen ein Inline-SVG. `appIcon()`
 * liefert seitdem ein `<img>` -- aber `.h-regal__z` und `.h-kat__z`
 * standen unveraendert da, geschrieben fuer ein SVG: `color:
 * var(--h-akzent)` (wirkungslos auf ein PNG), `svg { width: 100% }`
 * (findet nichts) und **kein `border-radius`**. Nur die Regel im Menue
 * war neu und hatte einen. Ergebnis: im Menue rund, in Regal und
 * Katalog scharfkantig. Max: *"die App Icons haben nicht immer runde
 * Ecken."*
 *
 * Die PNG-Datei ist ein scharfkantiges Quadrat; die Rundung MUSS vom
 * CSS kommen. 22 Prozent ist das Verhaeltnis, mit dem iOS seine Icons
 * rundet -- damit sieht das Icon in jeder Groesse aus wie im App Store.
 *
 * ⚠ WER EIN ELEMENT AUSTAUSCHT, PRUEFT DIE REGELN, DIE FUER DAS ALTE
 * GESCHRIEBEN WAREN. Sie verschwinden nicht, sie werden nur still
 * wirkungslos -- und was daran fehlte, faellt keinem Compiler auf.
 *
 * `appIcon()` in layout.mjs baut die Klassenliste selbst und nimmt nur
 * noch den ORT entgegen. Ein Icon ohne Radius laesst sich damit gar
 * nicht mehr ausliefern.
 */
.h-appicon {
  display: block; flex: none; border-radius: 22%;
  /* Eine Haarlinie, damit die Kachel auf Nachtblau eine Kante hat und
     nicht als Farbfleck schwebt. */
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.07);
}
.h-appicon--regal { width: 34px; height: 34px; }
.h-appicon--kat { width: 30px; height: 30px; }
.h-appicon--nav { width: 32px; height: 32px; }
.h-appicon--promo { width: 52px; height: 52px; }

.h-navapp__text { display: grid; gap: 1px; min-width: 0; }
.h-navapp__name { font-weight: 600; font-size: 0.9rem; letter-spacing: -0.01em; }
.h-navapp__sub { font-size: 0.78rem; color: var(--h-leise); }
.h-navapp[aria-current="page"] { background: var(--h-grund-3); }

.h-nav__winkel { flex: none; opacity: 0.75; transition: transform 0.18s var(--h-ease); }
.h-nav__gruppe:hover .h-nav__winkel,
.h-nav__gruppe:focus-within .h-nav__winkel { transform: rotate(180deg); }

/* ------------------------------------------------------------------ */
/* Mobil: das Menue als Bogen                                          */
/* ------------------------------------------------------------------ */
/*
 * Ein <details>, damit die Navigation ohne JavaScript traegt. Das
 * Skript setzt nur `aria-expanded` und schliesst bei Escape, beim
 * Tippen daneben und beim Wechsel auf die breite Ansicht.
 */
.h-menue { display: none; }

@media (max-width: 54rem) {
  .h-nav { display: none; }
  .h-menue { display: block; }

  /* ⚠ Der Knopf muss ueber der Blende liegen: Sie ist positioniert, er
     ist es sonst nicht -- und dann liesse sich das offene Menue nicht
     mehr mit demselben Knopf schliessen. */
  .h-menue__knopf {
    list-style: none; cursor: pointer; position: relative; z-index: 1;
    width: 44px; height: 44px; margin-right: -8px;
    display: flex; align-items: center; justify-content: center;
    border-radius: var(--h-r-klein); color: var(--h-tinte);
  }
  .h-menue__knopf::-webkit-details-marker { display: none; }
  .h-menue__knopf:hover { background: var(--h-grund-2); }

  /*
   * DIE DREI STRICHE. Beim Oeffnen wandern der obere und der untere in
   * die Mitte und drehen sich zum Kreuz, der mittlere verschwindet.
   * Das Kreuz sagt "das hier schliesst wieder", und die Bewegung
   * dorthin sagt, dass es derselbe Knopf ist.
   */
  .h-burger {
    width: 18px; height: 12px; position: relative; display: block;
  }
  .h-burger i {
    position: absolute; left: 0; width: 100%; height: 1.8px;
    border-radius: 2px; background: currentColor;
    transition: transform 0.26s var(--h-ease), opacity 0.16s var(--h-ease);
  }
  .h-burger i:nth-child(1) { top: 0; }
  .h-burger i:nth-child(2) { top: 5.1px; }
  .h-burger i:nth-child(3) { top: 10.2px; }
  .h-menue[open] .h-burger i:nth-child(1) { transform: translateY(5.1px) rotate(45deg); }
  .h-menue[open] .h-burger i:nth-child(2) { opacity: 0; }
  .h-menue[open] .h-burger i:nth-child(3) { transform: translateY(-5.1px) rotate(-45deg); }

  /* Die Blende ueber der Seite. Fixiert am Schirm, nicht am Kopf --
     das geht nur, weil die Unschaerfe des Kopfes auf einer eigenen
     Schicht liegt (siehe .h-kopf::before).

     ⚠ SIE BEGINNT UNTER DER KOPFZEILE, nicht bei 0.
     Mit `inset: 0` lag sie ueber der ganzen Seite -- also auch ueber
     dem Firmenzeichen und dem Schriftzug, und die standen bei offenem
     Menue unscharf da. Im Bild gesehen. Der Kopf bringt seine eigene
     Unschaerfe mit; er braucht diese hier nicht. */
  .h-menue[open]::before {
    content: ""; position: fixed; inset: var(--h-kopf-h) 0 0 0;
    background: color-mix(in srgb, var(--h-grund) 62%, transparent);
    -webkit-backdrop-filter: blur(6px);
    backdrop-filter: blur(6px);
    animation: h-blende 0.2s var(--h-ease) both;
  }

  .h-menue__blatt {
    position: fixed; left: 0; right: 0; top: var(--h-kopf-h);
    max-height: calc(100dvh - var(--h-kopf-h)); overflow-y: auto;
    background: var(--h-grund-2);
    border-top: 1px solid var(--h-linie);
    border-bottom: 1px solid var(--h-linie);
    box-shadow: 0 30px 70px -24px #000;
    animation: h-blatt 0.24s var(--h-ease) both;
  }
  .h-menue__bahn {
    display: grid; gap: 0.1rem;
    /* Dieselbe Bahn wie der Rest der Seite, damit die Eintraege unter
       der Marke stehen und nicht daneben. */
    padding: 0.5rem var(--h-luft) 1.1rem;
    max-width: var(--h-breite); margin-inline: auto;
  }

  /* Eine Beschriftung, kein Abzeichen: klein, leise, ohne Kasten. */
  .h-menue__titel {
    margin: 0.9rem 0 0.35rem; padding: 0 0.65rem;
    font-size: 0.7rem; font-weight: 600; letter-spacing: 0.14em;
    text-transform: uppercase; color: var(--h-leise);
  }
  .h-menue__bahn > .h-menue__titel:first-child { margin-top: 0.35rem; }

  .h-menue__alle, .h-menue__zeile {
    display: flex; align-items: center; gap: 0.5rem;
    padding: 0.75rem 0.65rem; border-radius: var(--h-r-klein);
    color: var(--h-tinte); text-decoration: none; font-weight: 500;
  }
  .h-menue__alle { color: var(--h-akzent-hell); font-weight: 600; }
  .h-menue__alle svg { width: 15px; height: 15px; flex: none; }
  .h-menue__alle:hover, .h-menue__zeile:hover { background: var(--h-grund-3); }
  .h-menue__zeile[aria-current="page"] { background: var(--h-grund-3); }
}

/* Solange das Blatt offen ist, scrollt die Seite darunter nicht mit. */
.h-menue-auf body { overflow: hidden; }

@keyframes h-blende { from { opacity: 0; } to { opacity: 1; } }
@keyframes h-blatt {
  from { opacity: 0; transform: translateY(-10px); }
  to { opacity: 1; transform: none; }
}

/* ------------------------------------------------------------------ */
/* Knoepfe                                                             */
/* ------------------------------------------------------------------ */

.h-knopf {
  display: inline-flex; align-items: center; justify-content: center; gap: 0.55rem;
  padding: 0.85rem 1.5rem; border-radius: var(--h-r);
  border: 1px solid transparent; font-family: var(--h-font);
  font-size: 1rem; font-weight: 600; line-height: 1.2;
  text-decoration: none; cursor: pointer; white-space: nowrap;
  transition: background 0.2s var(--h-ease), border-color 0.2s var(--h-ease),
              transform 0.2s var(--h-ease), box-shadow 0.25s var(--h-ease);
}

/* Ein Knopf ist ein Link: Er darf sich beim Zeigen heben, weil der
   Klick irgendwohin fuehrt. Karten heben sich NICHT (siehe Bento). */
.h-knopf:hover { transform: translateY(-1px); }

/* Taktile Rueckmeldung: der Knopf gibt beim Druecken nach. */
.h-knopf:active { transform: translateY(1px); }

.h-knopf svg { width: 17px; height: 17px; flex: none; transition: transform 0.2s var(--h-ease); }
.h-knopf:hover svg { transform: translateX(3px); }

/*
 * Kontrast gerechnet: #06122e auf #6e9bff ergibt 7.0 : 1; der Verlauf
 * wird nach oben nur HELLER, also steigt der Kontrast dort.
 * Der Schatten traegt die Farbe des Knopfes, kein Schwarz: Ein blauer
 * Gegenstand wirft auf dunklem Grund blaues Streulicht.
 */
.h-knopf--haupt {
  background: linear-gradient(180deg, var(--h-akzent-hell), var(--h-akzent) 55%);
  color: var(--h-akzent-tief);
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / 0.32),
    0 10px 28px -14px color-mix(in srgb, var(--h-akzent) 70%, transparent);
}
.h-knopf--haupt:hover {
  background: linear-gradient(180deg, #b7cdff, var(--h-akzent-hell) 60%);
  color: var(--h-akzent-tief);
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / 0.4),
    0 16px 36px -14px color-mix(in srgb, var(--h-akzent) 80%, transparent);
}

/* Glas, nicht Loch: leicht gefuellt, mit Kante, damit der zweite Knopf
   ein Gegenstand neben dem ersten ist und kein Rahmen im Nichts. */
.h-knopf--zweit {
  background: color-mix(in srgb, var(--h-grund-3) 55%, transparent);
  border-color: var(--h-linie-hell); color: var(--h-tinte);
  box-shadow: var(--h-kante);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
}
.h-knopf--zweit:hover { border-color: var(--h-leise); background: var(--h-grund-3); color: var(--h-tinte); }

.h-knopfreihe { display: flex; flex-wrap: wrap; gap: 0.8rem; margin-top: 2rem; }

/* ------------------------------------------------------------------ */
/* Hero                                                                */
/* ------------------------------------------------------------------ */

/* ⚠ `100dvh`, nie `100vh`: Auf dem iPhone springt die Seite sonst,
   sobald die Adressleiste ein- oder ausfaehrt. */
/*
 * ⚠ GEDECKELT, NICHT VOLLE FENSTERHOEHE (2026-09-09).
 *
 * Vorher `100dvh`. Der Inhalt sitzt mittig (`align-content: center`),
 * also verteilt sich der Ueberschuss oben UND unten -- und der untere
 * Teil addiert sich zur Polsterung des naechsten Abschnitts. Auf der
 * Startseite waren das gemessene 357 Punkte bis zur naechsten
 * Ueberschrift, waehrend zwei gewoehnliche Abschnitte 158 auseinander
 * liegen. Der Hero fuellt mit 46rem auf einem Laptop immer noch gut
 * vier Fuenftel des ersten Bildschirms -- und der naechste Abschnitt
 * schaut herein, was besser ist als eine Kante: Er sagt, dass es
 * weitergeht.
 */
.h-hero {
  min-height: min(100dvh, 46rem);
  display: grid; align-content: center;
  /*
   * Oben knapper als es reizt. Mit 12vh stand die Ueberschrift auf
   * einem Laptop 150 Punkte unter der Kopfzeile, und Max hat den Platz
   * als Luecke gelesen, nicht als Ruhe. Seit die Szene groesser ist,
   * traegt sie die Hoehe des Heros ohnehin.
   */
  padding-block: clamp(48px, 7vh, 84px) clamp(40px, 6vh, 72px);
  position: relative; overflow: hidden;
}

/*
 * Die Szene laeuft unten aus dem Hero heraus. Statt einer harten
 * Schnittkante loest sie sich in den Grund auf. Nur dort, wo eine
 * Szene steht; ein kurzer Hero hat unten Knoepfe, keine Bilder.
 */
.h-hero::after {
  content: ""; position: absolute; inset: auto 0 0 0; height: 17%;
  z-index: 3; pointer-events: none;
  background: linear-gradient(to bottom, transparent, var(--h-grund));
}
/*
 * Auch der kurze Hero laeuft aus. Ohne Auslauf endeten Licht und Raster
 * an einer harten Kante ueber dem ersten Abschnitt (Max: "der uebergang
 * ist nicht so smooth"). Er bleibt innerhalb des unteren Abstands,
 * damit er die Knoepfe nicht eintruebt.
 */
/* ⚠ KLEINER ALS DIE POLSTERUNG DARUEBER. Der Auslauf bleibt innerhalb
   des unteren Abstands, sonst truebt der Verlauf die Knoepfe ein. Wer
   die eine Zahl senkt, senkt diese mit. */
.h-hero--kurz::after { height: clamp(36px, 4vh, 52px); }
/* Auf dem Telefon endet die Karte 40 Punkte vor dem Rand; ein kurzer
   Auslauf darunter beruehrt sie nicht. */
@media (max-width: 40rem) {
  .h-hero::after { height: 36px; }
}

/*
 * Die Ueberschrift des Heros ist nicht weiss, sondern ein Verlauf von
 * Weiss nach Silber, wie gebuerstetes Metall. Der dunkelste Ton
 * (#a9b5cf) hat auf dem Grund noch 10 : 1. Ausdruecklich NUR der
 * Hero: Ein Verlauf auf jeder Ueberschrift waere Effekt statt Akzent.
 */
.h-hero h1 {
  background: linear-gradient(180deg, #ffffff 0%, var(--h-tinte) 46%, #a9b5cf 100%);
  -webkit-background-clip: text; background-clip: text;
  color: transparent;
  padding-bottom: 0.06em; /* Unterlaengen (g, p, y) nicht anschneiden */
  margin-bottom: 0.49em;
}

/*
 * ⚠ AUF DEM TELEFON KEINE VOLLE BILDSCHIRMHOEHE.
 *
 * Dort zeigt die Szene nur EINEN Schirm statt drei, der Hero-Inhalt
 * ist also kuerzer als das Fenster. Mit "100dvh" sammelt sich der
 * Rest als Leere unter dem Knopf, und darunter kommt noch der
 * Abstand des naechsten Abschnitts. Gemessen waren das rund 460
 * Punkte Nichts, bevor die naechste Ueberschrift auftauchte.
 *
 * Auf dem Telefon zaehlt jede Bildschirmhoehe. Die Hoehe richtet
 * sich deshalb nach dem Inhalt.
 */
@media (max-width: 40rem) {
  .h-hero { min-height: 0; padding-block: 56px 40px; }
}

/* Ein Hero ohne Bild darunter braucht die volle Hoehe nicht.
   ⚠ Die untere Zahl zaehlt zur Polsterung des naechsten Abschnitts
   dazu -- auf der Apps-Seite standen so 88 + 116 = rund 200 Punkte
   Nichts zwischen Lede und Katalog. */
.h-hero--kurz { min-height: 0; padding-block: clamp(40px, 6vh, 72px) clamp(44px, 5vh, 64px); }

.h-hero__kopf { max-width: 46rem; position: relative; z-index: 2; }

/* ------------------------------------------------------------------ */
/* DAS REGAL -- die Apps als Kacheln im Hero                            */
/*                                                                      */
/* ⚠ ES ERSETZT DIE DREI GENEIGTEN SCHIRME (2026-09-08). Max: "das mit  */
/* den Bildern sieht doof aus". Der tiefere Grund war aber die          */
/* Skalierung: Drei Schirme fuer zwei Apps sind eine Komposition, die   */
/* bei jeder neuen App von Hand neu entschieden werden muss. Das Regal  */
/* waechst aus den Daten.                                              */
/* ------------------------------------------------------------------ */
.h-hero__zwei {
  position: relative; z-index: 2;
  display: grid; grid-template-columns: 1.05fr .95fr;
  gap: clamp(32px, 5vw, 72px); align-items: center;
}
.h-hero__zwei .h-hero__kopf { max-width: none; }

.h-regal {
  display: grid; grid-template-columns: repeat(2, 1fr);
  gap: 16px; width: 100%; max-width: 34rem; margin-left: auto;
}
/*
 * Der Ausblick liegt ueber die ganze Breite und ist flach: Er ist kein
 * Produkt, also bekommt er auch nicht die Form eines Produkts.
 */
.h-regal > .h-regal__platz--offen {
  grid-column: 1 / -1; aspect-ratio: auto; padding: 20px; gap: 6px;
  border-style: dashed; border-color: rgba(255, 255, 255, .10);
}
/*
 * ⚠ BEI DREI APPS BLEIBT ES BEIM ZWEISPALTIGEN RASTER, die dritte
 * Kachel rueckt in die zweite Reihe und der Ausblick darunter. Ab
 * fuenf wird es dreispaltig -- das steht hier und nicht im Markup,
 * damit eine neue App keine Layout-Entscheidung ausloest.
 */
.h-regal[data-apps="5"], .h-regal[data-apps="6"] { grid-template-columns: repeat(3, 1fr); }

.h-regal__platz {
  aspect-ratio: 1; border-radius: var(--h-r);
  border: 1px solid rgba(255, 255, 255, .07);
  background: rgba(255, 255, 255, .014);
  display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 10px;
  text-decoration: none;
}
.h-regal__platz--app {
  border-color: rgba(110, 155, 255, .34);
  background:
    linear-gradient(160deg, rgba(110, 155, 255, .16), rgba(110, 155, 255, .03)),
    rgba(11, 18, 32, .7);
  box-shadow:
    var(--h-kante),
    0 22px 50px -28px rgba(110, 155, 255, .55);
}
/* Ein Hover-Zustand ist ein Versprechen: Die Kachel IST ein Link, also
   darf sie sich heben. Der Ausblick ist keiner und bleibt liegen. */
.h-regal__platz--app:hover {
  transform: translateY(-2px);
  border-color: rgba(110, 155, 255, .55);
}
/* ⚠ Die Farben stehen hier mit `a.`-Vorrang, weil die Kachel ein Link
   ist und sonst die Akzentfarbe des Themes erbt. Beim Ansehen der
   Entwurfsseite standen Name und Untertitel blau. */
.h-regal__name,
a.h-regal__platz .h-regal__name {
  font-size: .875rem; font-weight: 600; line-height: 1.3;
  color: var(--h-tinte); text-align: center; padding-inline: .75rem;
}
.h-regal__sub,
a.h-regal__platz .h-regal__sub {
  font-size: .8rem; line-height: 1.35;
  color: var(--h-leise); text-align: center; padding-inline: .9rem;
}

/* Schmal: Text ueber Kacheln, und die Kacheln nebeneinander. */
@media (max-width: 62rem) {
  .h-hero__zwei { grid-template-columns: 1fr; gap: 40px; }
  .h-regal { margin-inline: 0; max-width: none; }
}

/* ------------------------------------------------------------------ */
/* DER KATALOG -- eine Karte je App auf der Uebersichtsseite            */
/*                                                                      */
/* ⚠ `auto-fit` und NICHT `auto-fill`: Bei zwei Apps sollen zwei Karten */
/* die Breite teilen, nicht zwei schmale links kleben und rechts eine   */
/* leere Spalte stehen. Genau dieser Fehler ist in der App schon        */
/* einmal an den Plan-Kacheln passiert.                                 */
/* ------------------------------------------------------------------ */
.h-katalog {
  display: grid; gap: 20px;
  grid-template-columns: repeat(auto-fit, minmax(min(20rem, 100%), 1fr));
}
.h-kat {
  display: flex; flex-direction: column; gap: 14px;
  padding: clamp(20px, 2.4vw, 30px);
  border: 1px solid var(--h-linie); border-radius: var(--h-r);
  background: var(--h-grund-2);
  box-shadow: var(--h-kante);
}
.h-kat__kopf { display: flex; align-items: center; gap: 14px; }
.h-kat__name { font-size: 1.25rem; margin: 0; }
.h-kat__art { font-size: .85rem; color: var(--h-leise); margin: .15rem 0 0; }
.h-kat__text { margin: 0; color: var(--h-leise); }
.h-kat__punkte { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.h-kat__punkte li {
  position: relative; padding-left: 1.4rem;
  font-size: .925rem; color: var(--h-tinte);
}
/* Der Haken als Pseudo-Element: ein eigenes SVG je Punkt waere
   dreimal dieselbe Zeichnung in jeder Karte. */
.h-kat__punkte li::before {
  content: ""; position: absolute; left: 0; top: .42em;
  width: .7rem; height: .38rem;
  border-left: 2px solid var(--h-akzent);
  border-bottom: 2px solid var(--h-akzent);
  transform: rotate(-45deg);
}
/* `margin-top: auto` haelt den Fuss unten, auch wenn eine Karte kuerzer
   ist als ihre Nachbarin -- sonst stehen die Knoepfe auf verschiedenen
   Hoehen und das Raster wirkt schief. */
.h-kat__fuss {
  margin-top: auto; padding-top: 6px;
  display: flex; align-items: center; justify-content: space-between;
  gap: 14px; flex-wrap: wrap;
}
.h-kat__preis { font-size: .9rem; color: var(--h-leise); }
/*
 * DIE VERWEISE -- Karten, die auf andere Seiten fuehren (Ratgeber-
 * Uebersicht und "Verwandte Probleme").
 *
 * ⚠ DIE GANZE KARTE IST DER LINK, deshalb darf sie sich beim Zeigen
 * heben (Regel "Ein Hover-Zustand ist ein Versprechen"). Klassenname
 * vorher gesucht: `.h-verweis` war frei.
 */
/* ⚠ ZWEI SPALTEN AUF DER UEBERSICHT, DREI BEI "VERWANDT". Zehn Karten
   in drei Spalten liessen die zehnte allein in ihrer Reihe stehen (am
   2026-09-15 im Standbild gesehen); zehn in zwei gehen auf. Drei
   verwandte Seiten passen dagegen genau in eine Reihe. */
.h-verweise {
  display: grid; gap: 16px;
  grid-template-columns: repeat(auto-fit, minmax(min(24rem, 100%), 1fr));
}
.h-verweise--drei { grid-template-columns: repeat(auto-fit, minmax(min(17rem, 100%), 1fr)); }
.h-verweis {
  display: flex; flex-direction: column; gap: 8px;
  padding: clamp(18px, 2vw, 24px);
  border: 1px solid var(--h-linie); border-radius: var(--h-r);
  background: var(--h-grund-2); box-shadow: var(--h-kante);
  color: var(--h-leise); text-decoration: none;
  transition: transform .2s var(--h-ease), border-color .2s var(--h-ease);
}
.h-verweis:hover { transform: translateY(-2px); border-color: var(--h-linie-hell); }
.h-verweis__titel { font-size: 1.05rem; font-weight: 600; color: var(--h-tinte); margin: 0; }
.h-verweis__text { margin: 0; font-size: .93rem; }
/*
 * DER APP-KASTEN (Ratgeber, oben und als Schluss).
 *
 * ⚠ ER IST KEIN LINK, also hebt er sich beim Zeigen nicht ("Ein
 * Hover-Zustand ist ein Versprechen"). Klickbar sind die Knoepfe.
 *
 * ⚠ DER GRUND IST NICHT `--h-grund-2` ALLEIN. Der Kasten steht einmal
 * auf dunklem und einmal auf gehobenem Band; mit derselben Flaeche wie
 * das gehobene Band waere er dort nur noch ein Rahmen. Der Akzent-Schein
 * oben links traegt ihn auf beiden. Name `.h-promo` vorher gesucht, frei.
 */
.h-promo {
  display: grid; gap: clamp(20px, 3vw, 40px); align-items: center;
  grid-template-columns: minmax(0, 1fr) auto;
  padding: clamp(22px, 3vw, 40px);
  border: 1px solid color-mix(in srgb, var(--h-akzent) 38%, transparent);
  border-radius: var(--h-r);
  background:
    radial-gradient(70% 90% at 0% 0%, color-mix(in srgb, var(--h-akzent) 16%, transparent), transparent 65%),
    var(--h-grund-3);
  box-shadow: var(--h-kante), 0 30px 70px -40px color-mix(in srgb, var(--h-akzent) 45%, transparent);
}
.h-promo__kopf { display: flex; align-items: center; gap: 14px; margin-bottom: 1.1rem; }
.h-promo__name { margin: 0; font-weight: 700; color: var(--h-tinte); font-size: 1.05rem; }
.h-promo__art { margin: 0.1rem 0 0; font-size: 0.88rem; color: var(--h-leise); }
.h-promo__titel { margin: 0 0 0.6rem; font-size: clamp(1.45rem, 2.4vw, 2rem); }
.h-promo__text { margin: 0 0 1rem; color: var(--h-leise); max-width: 42rem; }
.h-promo__punkte { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 0.5rem 1.6rem; }
.h-promo__punkte li { position: relative; padding-left: 1.4rem; font-size: 0.93rem; color: var(--h-tinte); }
.h-promo__punkte li::before {
  content: ""; position: absolute; left: 0; top: 0.42em;
  width: 0.7rem; height: 0.38rem;
  border-left: 2px solid var(--h-akzent); border-bottom: 2px solid var(--h-akzent);
  transform: rotate(-45deg);
}
.h-promo__aktion { display: flex; flex-direction: column; gap: 0.7rem; min-width: 15rem; }
.h-promo__aktion .h-knopf { justify-content: center; text-align: center; }
@media (max-width: 52rem) {
  .h-promo { grid-template-columns: 1fr; }
  .h-promo__aktion { min-width: 0; }
}

/* Die Marke bricht nicht am Bindestrich um ("Hand-" / "E Discounts").
   Gesetzt in ratgeber.mjs. */
.h-marke-wort { white-space: nowrap; }
.h-verweis__weiter { margin-top: auto; padding-top: 4px; font-size: .9rem; color: var(--h-akzent); }

/* Zwei Knoepfe, sobald die App im Store ist (Store und Details). */
.h-kat__knoepfe { display: flex; gap: 10px; flex-wrap: wrap; }
@media (max-width: 30rem) {
  .h-kat__fuss { flex-direction: column; align-items: stretch; }
  .h-kat__knopf { text-align: center; }
  .h-kat__knoepfe { flex-direction: column; }
  .h-kat__knoepfe .h-knopf { justify-content: center; text-align: center; }
}

/*
 * Die Brotkrumen sitzen oben im Hero, ueber Licht und Raster. Der
 * Hero bekommt dafuer oben etwas mehr Luft, sonst klebten sie an der
 * Marke der Ueberschrift.
 */
.h-hero .h-krumen {
  position: absolute; top: 1rem; left: 0; right: 0; z-index: 2;
  padding-top: 0;
}
/*
 * ⚠ EIN HERO MIT BROTKRUMEN IST NIEDRIGER ALS EINER OHNE.
 *
 * Die Startseite darf den ersten Bildschirm ganz fuellen -- dort ist
 * der Hero die Aussage. Eine Produktseite hat darunter acht
 * Abschnitte, und ihr Hero traegt zusaetzlich eine Brotkrumenzeile
 * ganz oben. Bei `min-height: 100dvh` und mittiger Ausrichtung standen
 * zwischen Brotkrumen und Ueberschrift knapp 400 Punkte Nichts --
 * gemessen auf 1440 x 900, nachdem die Szene neben den Text
 * gewandert ist und der Textblock damit kuerzer wurde.
 *
 * `min()` und nicht einfach 40rem: Auf einem niedrigen Fenster gilt
 * weiter die Fensterhoehe, sonst waere der Hero hoeher als der Schirm.
 *
 * ⚠⚠ `:not(.h-hero--kurz)` IST DER TEURE TEIL DIESER ZEILE.
 *
 * Ohne ihn hat diese Regel am 2026-09-08 den KURZEN Hero wieder
 * aufgeblasen: `.h-hero--kurz { min-height: 0 }` steht 160 Zeilen
 * weiter oben, und `:has()` gewinnt sowohl nach Spezifitaet als auch
 * nach Reihenfolge. Betroffen war die Apps-Seite -- ein Hero, der
 * ausdruecklich kurz sein soll, stand mit 640 Punkten da und schob
 * seinen mittig gesetzten Inhalt in die Mitte. Gemessen: 682 Punkte
 * zwischen Brotkrumen und Katalog. Genau das hat Max als "viel zu
 * grosse Abstaende" gesehen.
 *
 * Es ist derselbe Fehler, vor dem die CLAUDE.md des Hauses warnt: Eine
 * CSS-Regel wirkt erst, wenn sie an der richtigen Stelle steht -- und
 * eine spaetere, spezifischere Regel nimmt einer frueheren still ihre
 * Wirkung. Im Code sah beides richtig aus.
 */
.h-hero:has(.h-krumen):not(.h-hero--kurz) {
  padding-top: clamp(72px, 9vh, 104px);
  min-height: min(100dvh, 40rem);
}
/* Der kurze Hero braucht die Brotkrumen-Polsterung oben trotzdem,
   sonst klebt die Ueberschrift daran. Nur die Hoehe bleibt seine. */
.h-hero--kurz:has(.h-krumen) { padding-top: clamp(64px, 8vh, 92px); }

/*
 * Das Licht hinter dem Hero. Zwei sehr weiche radiale Verlaeufe, sonst
 * nichts. Es traegt die Tiefe der Szene, ohne wie ein Farbklecks
 * auszusehen.
 */
.h-licht {
  position: absolute; inset: -18% -22% auto -22%; height: 130%;
  z-index: 0; pointer-events: none;
}

/*
 * Zwei Lichter auf getrennten Ebenen, jedes mit eigener Unschaerfe.
 * Getrennt, weil sie sich gegeneinander bewegen: Das eine treibt nach
 * rechts unten, das andere nach links oben. Ein einzelnes Bild, das
 * sich verschiebt, saehe aus wie ein Aufkleber.
 */
.h-licht::before, .h-licht::after {
  content: ""; position: absolute; inset: 0;
  filter: blur(46px);
}
.h-licht::before {
  background: radial-gradient(38% 42% at 44% 30%, color-mix(in srgb, var(--h-akzent) 14%, transparent), transparent 72%);
}
.h-licht::after {
  background:
    radial-gradient(30% 34% at 76% 58%, color-mix(in srgb, var(--h-akzent) 8%, transparent), transparent 70%),
    radial-gradient(22% 26% at 18% 72%, color-mix(in srgb, #3b63d6 12%, transparent), transparent 70%);
}

/* Auf dem Telefon steht das Licht still: zwei unscharfe Ebenen in
   Bewegung kosten dort Akku, und man sieht es auf dem kleinen Bild
   kaum. */
@media (prefers-reduced-motion: no-preference) and (min-width: 40rem) {
  .h-licht::before { animation: h-treibt 26s ease-in-out infinite alternate; }
  .h-licht::after { animation: h-treibt 34s ease-in-out infinite alternate-reverse; }
}

/*
 * Das Licht, das dem Zeiger folgt. Ein weicher Kreis, der ueber
 * transform verschoben wird (Kompositor, kein Neuzeichnen). Position
 * und Deckkraft setzt das Skript; ohne Skript bleibt er unsichtbar.
 */
.h-zeiger-licht {
  position: absolute; left: 0; top: 0; z-index: 1; pointer-events: none;
  width: 58vmax; height: 58vmax; border-radius: 50%;
  background: radial-gradient(circle, color-mix(in srgb, var(--h-akzent) 13%, transparent), transparent 60%);
  opacity: var(--zl, 0);
  transform: translate3d(calc(var(--px, 0px) - 50%), calc(var(--py, 0px) - 50%), 0);
  will-change: transform, opacity;
}

/*
 * Das Punktraster, gezeichnet vom Skript (siehe NEIGEN in layout.mjs).
 * Ueber den Lichtern, unter dem Inhalt. Die Maske laesst es zu den
 * Raendern hin ausklingen, sonst stuende ein hartes Gitter bis an die
 * Kante, und der Auslauf unten (::after) haette gegen ein Muster zu
 * arbeiten.
 */
.h-raster {
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  width: 100%; height: 100%;
  -webkit-mask-image: radial-gradient(120% 100% at 50% 30%, #000 20%, transparent 72%);
  mask-image: radial-gradient(120% 100% at 50% 30%, #000 20%, transparent 72%);
}

/* Abzeichen ueber der Ueberschrift. Genau eins je Seite. */
.h-marker {
  display: inline-flex; align-items: center; gap: 0.5rem;
  font-size: 0.8rem; font-weight: 600; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--h-akzent);
  margin: 0 0 1.4rem;
}

/* ------------------------------------------------------------------ */
/* Schirme und die 3D-Szene                                            */
/* ------------------------------------------------------------------ */

/*
 * ⚠⚠ DIESER KOMMENTAR STAND HIER FALSCH HERUM.
 *
 * Er lautete: *"Das sind ECHTE SCREENSHOTS der App, keine nachgebauten
 * Oberflaechen aus Divs."* Am 2026-09-08 war das schon nicht mehr wahr
 * -- seit der Umstellung auf `scripts/website-bilder.mjs` ist JEDES
 * Bild dieser Seite gerendert, und zwar ausdruecklich, weil Screenshots
 * unscharf waren (Max: *"all die Screenshots dort sind sehr schlecht zu
 * erkennen"*, dann *"auf der gesamten Website auf Screenshots
 * verzichten"*).
 *
 * Was am alten Kommentar richtig BLEIBT: Ein Nachbau veraltet, sobald
 * das Produkt sich aendert. Die Gegenmassnahme ist keine Aufnahme,
 * sondern die Herkunft der Vorlagen -- `scripts/bilder-*.html` binden
 * das ECHTE `theme.css` der jeweiligen App ein. Wer dort eine Farbe
 * oder einen Radius aendert, aendert diese Bilder mit.
 *
 * Ein Kommentar, der das Gegenteil des Codes behauptet, ist teurer als
 * gar keiner: Der naechste Mensch haette daraus geschlossen, er duerfe
 * hier keine Vorlage anfassen.
 */
.h-schirm {
  overflow: hidden; position: relative;
  border-radius: var(--h-r);
  border: 1px solid var(--h-linie);
  background: var(--h-grund-2);
  box-shadow: var(--h-kante), 0 40px 90px -44px #000;
  margin: 0;
}

/* height: auto, weil das Markup width und height traegt (Platz
   reservieren, bevor das Bild da ist) und die Hoehe trotzdem der
   Breite folgen soll. */
.h-schirm img { width: 100%; height: auto; display: block; }

/*
 * Die Reihe aus drei Schirmen unter dem Hero. Der mittlere steht vorn.
 *
 * ⚠ DIE NEIGUNG RECHNET DAS CSS, DAS SKRIPT LIEFERT NUR ZWEI ZAHLEN.
 * `--mx` und `--my` laufen von -1 bis 1 und sagen, wo der Zeiger ueber
 * der FLAECHE steht, also ueber dem ganzen Hero und nicht nur ueber den
 * Bildern. Alles andere (Winkel, Tiefe je Schirm, Glanz) steht hier.
 * Ohne Skript bleiben beide auf 0, und die Szene steht in ihrer
 * Ruhelage.
 *
 * Die erste Fassung hoerte NUR auf die Bilder und schrieb bei jeder
 * Zeigerbewegung eine CSS-Transition von 120 ms. Folge: Der Rest des
 * Heros war tot, und beim Eintreten in die Bilder sprang die Szene um
 * sechs Grad. Jetzt fuehrt das Skript die Werte mit Traegheit nach
 * (siehe NEIGEN in layout.mjs), und hier gibt es keine Transition mehr.
 *
 * Die Ruhelage (`--rx0`, `--ry0`) kommt aus dem Markup, weil sie je
 * Szene verschieden ist.
 */
.h-szene {
  perspective: 1500px;
  margin-top: clamp(32px, 4vw, 48px);
  position: relative; z-index: 2;
  --mx: 0; --my: 0;
  animation:
    h-hebt 1.3s var(--h-ease) 0.3s both,
    h-schweb 9s ease-in-out 1.6s infinite alternate;
}

.h-szene__raum {
  display: grid;
  /*
   * Der vordere Schirm bekommt gut die Haelfte der Breite. Die Bilder
   * sind AUSSCHNITTE (siehe scripts/schirme.mjs), und der vordere soll
   * mit rund 80 Prozent seiner Originalgroesse stehen, damit die
   * Schrift der App lesbar ist. Die seitlichen sind Kontext.
   */
  grid-template-columns: 0.9fr 2fr 0.9fr;
  gap: clamp(12px, 1.8vw, 24px);
  align-items: center;
  transform-style: preserve-3d;
  transform:
    rotateX(calc(var(--rx0, 11deg) + var(--my) * -5deg))
    rotateY(calc(var(--ry0, 0deg) + var(--mx) * 8deg));
}

/*
 * Je Schirm eine eigene Tiefe UND eine eigene Bewegung. Der vordere
 * folgt dem Zeiger, die hinteren weichen ihm leicht aus. So entsteht
 * Parallaxe, und die drei sind kein starrer Block mehr.
 *
 * ⚠ Nur fuer die Szene mit DREI Schirmen. Die Regel ohne diese
 * Einschraenkung traf auch den einzelnen Schirm der Produktseite und
 * stellte ihn nach hinten, gedreht und auf 78 Prozent Deckkraft.
 */
.h-szene:not(.h-szene--eins) .h-szene__raum > :nth-child(1) {
  transform: translate3d(calc(var(--mx) * -9px), calc(var(--my) * -5px), -70px) rotateY(13deg);
}
.h-szene:not(.h-szene--eins) .h-szene__raum > :nth-child(2) {
  transform: translate3d(calc(var(--mx) * 16px), calc(var(--my) * 9px), 40px);
  border-color: color-mix(in srgb, var(--h-akzent) 26%, transparent);
  box-shadow:
    var(--h-kante),
    0 30px 80px -30px color-mix(in srgb, var(--h-akzent) 38%, transparent),
    0 40px 90px -44px #000;
}
.h-szene:not(.h-szene--eins) .h-szene__raum > :nth-child(3) {
  transform: translate3d(calc(var(--mx) * -9px), calc(var(--my) * -5px), -70px) rotateY(-13deg);
}

/*
 * ⚠ DIE HINTEREN SCHIRME SIND DECKEND UND WERDEN ABGEDUNKELT, NICHT
 * DURCHSICHTIG. Bis zum 2026-09-05 standen sie auf opacity 0.78, damit
 * sie zuruecktreten. Seit das Punktraster im Hero liegt, schien es
 * durch die Bilder hindurch (Max: "der effekt ist hinter den zwei
 * bildern zu sehen"). Eine duenne Schicht in der Grundfarbe ueber dem
 * Bild dunkelt genauso ab, laesst aber nichts durch.
 */
.h-szene:not(.h-szene--eins) .h-szene__raum > :nth-child(1)::before,
.h-szene:not(.h-szene--eins) .h-szene__raum > :nth-child(3)::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: color-mix(in srgb, var(--h-grund) 26%, transparent);
}

/*
 * Ein Glanz, der ueber den vorderen Schirm wandert, wenn der Zeiger
 * sich bewegt. Glas reflektiert; ein flaches Bild tut das nicht.
 */
.h-szene:not(.h-szene--eins) .h-szene__raum > :nth-child(2)::after,
.h-szene--eins .h-schirm::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(105deg, transparent 36%, rgb(255 255 255 / 0.085) 50%, transparent 64%);
  transform: translateX(calc(var(--mx) * 45%));
}

/* Eine einzelne Szene, etwa auf der Produktseite. */
/*
 * ⚠ `margin-top: 0` IST FUER DEN SPLIT RICHTIG UND FUER DEN HERO FALSCH.
 *
 * Im Split sitzt die Szene in einer eigenen Rasterzelle neben dem Text;
 * dort waere ein Abstand nach oben nur Schieflage. Im Hero steht sie
 * UNTER der Knopfreihe -- und dort hat die Null 2026-09-08 dazu
 * gefuehrt, dass das Bild die Knoepfe ueberlappt: Die Szene schwebt
 * (`h-schweb`, plus/minus 8 Punkte), und ohne Abstand faehrt sie in
 * ihrer Ruhelage acht Punkte in die Knoepfe hinein. Gemessen, nicht
 * geschaetzt: `szene.top - knoepfe.bottom === -8`.
 *
 * Max: *"Produktseiten sehen im Hero auch noch weird aus (Abstand
 * unstimmig)."*
 *
 * Der Abstand ist derselbe wie bei der Szene mit drei Schirmen -- er
 * kommt aus derselben Zeile weiter oben, hier nur zurueckgeholt.
 */
.h-szene--eins { perspective: 1600px; margin-top: 0; }
.h-hero .h-szene--eins { margin-top: clamp(40px, 4.5vw, 56px); }
/* Nebeneinander sorgt der `gap` des Rasters fuer den Abstand, in beide
   Richtungen -- ein zusaetzlicher Rand waere ein zweiter Abstand. */
.h-hero__zwei .h-szene--eins { margin-top: 0; }
.h-szene--eins .h-szene__raum {
  display: block;
  transform:
    rotateY(calc(var(--ry0, -13deg) + var(--mx) * 8deg))
    rotateX(calc(var(--rx0, 6deg) + var(--my) * -5deg));
}
.h-szene--eins .h-schirm {
  box-shadow:
    var(--h-kante),
    0 30px 80px -30px color-mix(in srgb, var(--h-akzent) 30%, transparent),
    0 40px 90px -44px #000;
}

/* Ein ruhiger Schirm ohne Neigung, fuer Abschnitte mitten auf der Seite. */
.h-schirm--flach { box-shadow: var(--h-kante), 0 30px 70px -40px #000; }

/* Schmal: ein Schirm, flach. Eine Neigung ohne Zeiger ist nur schief. */
@media (max-width: 62rem) {
  .h-szene__raum, .h-szene--eins .h-szene__raum { grid-template-columns: 1fr; transform: none; }
  .h-szene:not(.h-szene--eins) .h-szene__raum > :nth-child(1),
  .h-szene:not(.h-szene--eins) .h-szene__raum > :nth-child(3) { display: none; }
  .h-szene:not(.h-szene--eins) .h-szene__raum > :nth-child(2) { transform: none; }
  .h-szene:not(.h-szene--eins) .h-szene__raum > :nth-child(2)::after,
  .h-szene--eins .h-schirm::after { display: none; }
}

/* ------------------------------------------------------------------ */
/* Bento                                                               */
/* ------------------------------------------------------------------ */

/*
 * ⚠ KEINE DREI GLEICHEN KARTEN NEBENEINANDER. Das ist das haeufigste
 * Muster generierter Seiten. Die Zellen hier sind ungleich gross, und
 * mindestens eine traegt ein Bild oder eine Flaeche statt nur Text.
 *
 * ⚠ SO VIELE ZELLEN WIE INHALTE. Eine leere Kachel am Ende heisst,
 * dass das Raster falsch geplant war, nicht dass Inhalt fehlt.
 */
.h-bento {
  display: grid;
  gap: clamp(12px, 1.4vw, 18px);
  grid-template-columns: repeat(6, 1fr);
}

.h-zelle {
  grid-column: span 2;
  background: var(--h-grund-2);
  border: 1px solid var(--h-linie);
  border-radius: var(--h-r);
  padding: clamp(20px, 2.2vw, 30px);
  display: flex; flex-direction: column; gap: 0.55rem;
  position: relative; overflow: hidden;
  box-shadow: var(--h-kante);
}

/*
 * ⚠ SPOTLIGHT: Rand und Flaeche leuchten dort, wo der Zeiger steht.
 *
 * Zwei Pseudo-Elemente je Karte. `::before` ist der weiche Lichtfleck
 * auf der Flaeche, `::after` derselbe Fleck als Ring, per Maske auf
 * einen Punkt Randbreite beschnitten. Die Position kommt als
 * `--x`/`--y` in Pixeln aus dem Skript (ein Zuhoerer je Raster, kein
 * rAF).
 *
 * Die Karte hebt sich NICHT. Sie ist kein Link; ein Hover, der
 * Bewegung verspricht, ohne dass ein Klick etwas tut, ist ein
 * gebrochenes Versprechen (CLAUDE.md, "Ein Hover-Zustand ist ein
 * Versprechen").
 */
.h-zelle::before, .h-zelle::after,
.h-plan::before, .h-plan::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  opacity: 0; transition: opacity 0.45s var(--h-ease);
}
.h-zelle::before, .h-plan::before {
  background: radial-gradient(460px circle at var(--x, 50%) var(--y, 50%),
    color-mix(in srgb, var(--h-akzent) 9%, transparent), transparent 62%);
}
.h-zelle::after, .h-plan::after {
  padding: 1px;
  background: radial-gradient(320px circle at var(--x, 50%) var(--y, 50%),
    color-mix(in srgb, var(--h-akzent) 62%, transparent), transparent 70%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
}
.h-zelle:hover::before, .h-zelle:hover::after,
.h-plan:hover::before, .h-plan:hover::after { opacity: 1; }

.h-zelle--breit { grid-column: span 3; }
.h-zelle--gross { grid-column: span 4; }
.h-zelle--voll { grid-column: 1 / -1; }

.h-zelle h3 { margin: 0; }
.h-zelle p { color: var(--h-leise); margin: 0; font-size: 0.97rem; }

/* Eine Zelle mit Bild: das Bild sitzt unten und laeuft aus der Zelle. */
.h-zelle--bild { padding-bottom: 0; }
/*
 * ⚠ DAS BILD IST GEDECKELT UND LAEUFT UNTEN AUS DER ZELLE.
 * Ungedeckelt machte ein 700 Punkte hohes Bild seine Zelle 480 Punkte
 * hoch, und die Nachbarzelle in derselben Reihe wurde auf dieselbe
 * Hoehe gestreckt: eine grosse, leere Karte neben einer vollen. Max:
 * "das sieht auf desktop weird aus". Gedeckelt zeigt die Zelle den
 * oberen Teil des Bildes, der Rest ist angeschnitten, und das ist hier
 * richtig, weil das Bild ein Fenster in die App ist, kein Foto.
 * Auf dem Telefon (eine Spalte, eigener kleiner Ausschnitt) braucht es
 * den Deckel nicht.
 */
.h-zelle__bild {
  margin-top: auto; padding-top: 1.5rem;
  max-height: clamp(220px, 22vw, 300px); overflow: hidden;
}
@media (max-width: 40rem) {
  .h-zelle__bild { max-height: none; }
}
.h-zelle__bild img {
  width: 100%; height: auto; display: block;
  border-radius: var(--h-r-klein) var(--h-r-klein) 0 0;
  border: 1px solid var(--h-linie); border-bottom: 0;
}

/* Eine Zelle mit Akzentflaeche, damit das Raster nicht sechsmal
   dasselbe Grau ist. */
.h-zelle--licht {
  background:
    radial-gradient(80% 120% at 12% 0%, color-mix(in srgb, var(--h-akzent) 16%, transparent), transparent 62%),
    var(--h-grund-2);
  border-color: color-mix(in srgb, var(--h-akzent) 22%, transparent);
}

.h-zeichen {
  width: 40px; height: 40px; border-radius: var(--h-r-klein);
  background: linear-gradient(180deg, var(--h-grund-3), color-mix(in srgb, var(--h-grund-3) 55%, var(--h-grund-2)));
  color: var(--h-akzent);
  box-shadow: var(--h-kante), 0 0 0 1px var(--h-linie);
  display: grid; place-items: center; margin-bottom: 0.3rem;
}
.h-zeichen svg { width: 20px; height: 20px; }

@media (max-width: 62rem) {
  .h-bento { grid-template-columns: repeat(2, 1fr); }
  .h-zelle, .h-zelle--breit, .h-zelle--gross { grid-column: span 2; }
}
@media (max-width: 40rem) {
  .h-bento { grid-template-columns: 1fr; }
  .h-zelle, .h-zelle--breit, .h-zelle--gross, .h-zelle--voll { grid-column: 1 / -1; }
}

/* ------------------------------------------------------------------ */
/* Split: Text neben Bild                                              */
/* ------------------------------------------------------------------ */

.h-split {
  display: grid;
  grid-template-columns: 0.92fr 1.08fr;
  gap: clamp(32px, 5vw, 72px);
  align-items: center;
}

/* Umgedreht: Bild links, Text rechts. Hoechstens zweimal je Seite,
   sonst wird die Seite zum Zickzack. */
.h-split--um > :first-child { order: 2; }

@media (max-width: 62rem) {
  .h-split { grid-template-columns: 1fr; gap: 28px; }
  .h-split--um > :first-child { order: 0; }
}

/* ------------------------------------------------------------------ */
/* Listen, Tabellen, Hinweise                                          */
/* ------------------------------------------------------------------ */

.h-liste { margin: 0 0 1.3em; padding-left: 1.3em; color: var(--h-leise); }
.h-liste li { margin-bottom: 0.45em; }

/*
 * DIE SCHRITTE -- eine nummerierte Anleitung (Ratgeber, "So loest du es").
 * Die Zahl sitzt in einem Kreis im Akzent, gezaehlt ueber einen
 * CSS-Zaehler: Die Nummer steht damit nicht im Text, und ein Screenreader
 * liest trotzdem eine geordnete Liste vor, weil es ein <ol> bleibt.
 */
.h-liste--schritte { list-style: none; padding-left: 0; counter-reset: schritt; }
.h-liste--schritte li {
  position: relative; padding-left: 2.6em; margin-bottom: 0.85em;
  counter-increment: schritt; min-height: 1.8em;
}
.h-liste--schritte li::before {
  content: counter(schritt);
  position: absolute; left: 0; top: 0;
  width: 1.8em; height: 1.8em; border-radius: 50%;
  display: grid; place-items: center;
  font-size: 0.85em; font-weight: 700; color: var(--h-tinte);
  background: color-mix(in srgb, var(--h-akzent) 22%, var(--h-grund-2));
  border: 1px solid color-mix(in srgb, var(--h-akzent) 55%, transparent);
}

.h-liste--haken { list-style: none; padding-left: 0; }
.h-liste--haken li { position: relative; padding-left: 1.9em; }
.h-liste--haken li::before {
  content: ""; position: absolute; left: 0.2em; top: 0.58em;
  width: 0.62em; height: 0.34em;
  border-left: 2px solid var(--h-akzent);
  border-bottom: 2px solid var(--h-akzent);
  transform: rotate(-45deg);
}

/* ------------------------------------------------------------------ */
/* Der Schieber (USPs)                                                 */
/* ------------------------------------------------------------------ */
/*
 * Breit: eine gewoehnliche Hakenliste, unveraendert.
 * Schmal: dieselben Punkte als Karten nebeneinander.
 *
 * ⚠ DIE KARTE IST 82 PROZENT BREIT, NICHT 100. Die naechste guckt
 * damit ins Bild, und genau das sagt "hier geht es weiter". Eine
 * bildschirmbreite Karte sieht aus wie ein Abschnitt, und niemand
 * wischt.
 */
.h-schieber__band { margin: 0; }

/*
 * ⚠ DIE PUNKTE ENTSTEHEN IMMER, GEBRAUCHT WERDEN SIE NUR SCHMAL.
 *
 * Das Skript haengt sie an jeden Schieber, unabhaengig von der Breite
 * -- es kennt keine Medienabfrage. Ihre Gestaltung stand dagegen NUR
 * im Mobil-Block, und ausserhalb davon standen sie als nackte
 * <button>-Elemente da: ein grauer Balken unter der Hakenliste, auf
 * dem Desktop, wo es gar keinen Schieber gibt. Im Bild gesehen.
 *
 * Deshalb hier die Grundregel: aus. Sichtbar werden sie erst dort, wo
 * das Band wirklich schiebt.
 */
.h-schieber__punkte { display: none; }

@media (max-width: 48rem) {
  /* ⚠ Der Schieber bricht aus der Textbahn aus, damit die erste Karte
     am Rand beginnt und die letzte dort endet. Ohne das steht links
     und rechts ein Streifen, in dem nichts passiert, und die
     Wischgeste hoert vor dem Bildrand auf. */
  .h-schieber {
    margin-inline: calc(-1 * var(--h-luft));
    /* Der Schatten der Karten darf nicht abgeschnitten werden. */
    padding-block: 4px 2px;
  }

  .h-schieber__band {
    display: flex; gap: 0.85rem;
    overflow-x: auto; overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory;
    padding-inline: var(--h-luft);
    scrollbar-width: none;
    list-style: none;
  }
  .h-schieber__band::-webkit-scrollbar { display: none; }

  .h-schieber__band > .h-usp {
    flex: 0 0 82%; scroll-snap-align: center;
    margin: 0; padding: 1.15rem 1.15rem 1.25rem;
    background: var(--h-grund-2);
    border: 1px solid var(--h-linie);
    border-radius: var(--h-r);
    box-shadow: var(--h-kante);
  }

  /* ⚠ Der Haken sitzt in der Karte OBEN, nicht neben der ersten Zeile.
     Die Regel darueber setzt ihn auf `top: 0.58em`, also auf die Hoehe
     einer Textzeile -- in einer Karte mit Ueberschrift steht er damit
     im Nichts. */
  .h-schieber__band > .h-usp { padding-left: 1.15rem; }
  .h-schieber__band > .h-usp::before {
    position: static; display: block;
    margin: 0 0 0.85rem 0.2em;
    width: 0.8em; height: 0.44em;
    border-width: 2.5px;
  }

  .h-usp__titel { display: block; margin-bottom: 0.35rem; }
  .h-usp__text { color: var(--h-leise); font-size: 0.95rem; }

  /* Die Punkte kommen aus dem Skript; ohne es scrollt das Band
     trotzdem. Deshalb steht hier keine Hoehe, die sonst leer bliebe. */
  .h-schieber__punkte {
    display: flex; justify-content: center; gap: 0.4rem;
    margin-top: 0.9rem;
  }
  .h-schieber__punkt {
    width: 7px; height: 7px; padding: 0; border: 0; border-radius: 50%;
    background: var(--h-linie-hell); cursor: pointer;
    transition: background 0.2s var(--h-ease), width 0.2s var(--h-ease);
  }
  .h-schieber__punkt.ist { background: var(--h-akzent); width: 18px; border-radius: 4px; }
}

/* ⚠ Tabellen scrollen in SICH. Ohne das schiebt eine breite Tabelle
   auf dem Telefon die ganze Seite seitlich. */
.h-tabelle-huelle {
  overflow-x: auto; margin: 0 0 1.5em;
  border: 1px solid var(--h-linie); border-radius: var(--h-r);
  background: var(--h-grund-2);
}
.h-tabelle-huelle--breit {
  max-width: none;
  width: min(58rem, calc(100vw - 2 * var(--h-luft)));
}

table { border-collapse: collapse; width: 100%; font-size: 0.97rem; }

th, td {
  text-align: left; padding: 0.8rem 1rem;
  border-bottom: 1px solid var(--h-linie); vertical-align: top;
}
th { font-weight: 600; color: var(--h-tinte); background: var(--h-grund-3); white-space: nowrap; }
td { color: var(--h-leise); }
td:first-child { color: var(--h-tinte); }
tbody tr:last-child td { border-bottom: 0; }

.h-hinweis {
  border: 1px solid var(--h-linie);
  border-left: 2px solid var(--h-akzent);
  border-radius: var(--h-r-klein);
  background: var(--h-grund-2);
  padding: 1.1rem 1.3rem;
  margin: 0 0 1.5em;
  color: var(--h-leise);
}
.h-hinweis > :last-child { margin-bottom: 0; }

/* ------------------------------------------------------------------ */
/* Plaene                                                              */
/* ------------------------------------------------------------------ */

.h-plaene { display: grid; gap: clamp(14px, 1.6vw, 20px); grid-template-columns: repeat(auto-fit, minmax(min(19rem, 100%), 1fr)); }
/* Was auf die Plaene folgt (der Preishinweis), klebte an den Kacheln. */
.h-plaene + * { margin-top: clamp(20px, 2.4vw, 28px); }

.h-plan {
  background: var(--h-grund-2);
  border: 1px solid var(--h-linie);
  border-radius: var(--h-r);
  padding: clamp(22px, 2.4vw, 32px);
  display: flex; flex-direction: column; gap: 0.35rem;
  position: relative;
  box-shadow: var(--h-kante);
}

.h-plan--wahl {
  border-color: color-mix(in srgb, var(--h-akzent) 34%, transparent);
  background:
    radial-gradient(90% 60% at 50% 0%, color-mix(in srgb, var(--h-akzent) 12%, transparent), transparent 60%),
    var(--h-grund-2);
}

/*
 * Der empfohlene Plan traegt einen Ring, der langsam umlaeuft. Das ist
 * Hierarchie, nicht Schmuck: Von zwei Kacheln soll das Auge zuerst auf
 * dieser landen. Er ersetzt bei dieser Karte den Spotlight-Ring, auch
 * beim Zeigen, sonst spraenge der Rand beim Hover in ein anderes Bild.
 */
.h-plan--wahl::after, .h-plan--wahl:hover::after {
  opacity: 1;
  background: conic-gradient(from var(--h-winkel),
    transparent 0 58%, color-mix(in srgb, var(--h-akzent) 78%, transparent) 78%, transparent 92%);
  animation: h-kreis 9s linear infinite;
}

.h-plan__preis { font-family: var(--h-font-display); font-size: 2.4rem; font-weight: 800; letter-spacing: -0.04em; }
.h-plan__preis span { font-family: var(--h-font); font-size: 0.95rem; font-weight: 500; color: var(--h-leise); letter-spacing: 0; }
.h-plan ul { list-style: none; padding: 0; margin: 1.1rem 0 0; display: grid; gap: 0.55rem; }
.h-plan li { position: relative; padding-left: 1.7em; color: var(--h-leise); font-size: 0.96rem; }
.h-plan li::before {
  content: ""; position: absolute; left: 0.15em; top: 0.55em;
  width: 0.58em; height: 0.32em;
  border-left: 2px solid var(--h-akzent); border-bottom: 2px solid var(--h-akzent);
  transform: rotate(-45deg);
}

/* ------------------------------------------------------------------ */
/* FAQ                                                                 */
/* ------------------------------------------------------------------ */

.h-faq { border: 1px solid var(--h-linie); border-radius: var(--h-r); overflow: hidden; background: var(--h-grund-2); box-shadow: var(--h-kante); }
.h-faq details + details { border-top: 1px solid var(--h-linie); }

.h-faq summary {
  list-style: none; cursor: pointer;
  padding: 1.1rem 3rem 1.1rem 1.3rem;
  font-family: var(--h-font-display); font-weight: 700; font-size: 1.02rem;
  letter-spacing: -0.015em; position: relative;
}
.h-faq summary::-webkit-details-marker { display: none; }
.h-faq summary:hover { background: var(--h-grund-3); }

.h-faq summary::after {
  content: ""; position: absolute; right: 1.4rem; top: 1.5rem;
  width: 0.58rem; height: 0.58rem;
  border-right: 2px solid var(--h-leise); border-bottom: 2px solid var(--h-leise);
  transform: rotate(45deg); transition: transform 0.2s var(--h-ease);
}
.h-faq details[open] summary::after { transform: rotate(-135deg); }
/* Waehrend des Zuklappens ist `open` noch gesetzt (siehe Skript); der
   Pfeil soll trotzdem sofort nach unten zeigen. */
.h-faq details.h-faq--zu summary::after { transform: rotate(45deg); }

/*
 * ⚠ DER FOKUSRING LIEGT INNEN. Der globale Ring steht 3 Punkte
 * AUSSERHALB des Elements. Die Frage fuellt die Karte in voller Breite,
 * und die Karte schneidet ueber `overflow: hidden` ab: Uebrig blieb
 * vom Ring genau die Unterkante, eine blaue Linie unter der Frage, die
 * wie ein Fehler aussah (Max: "das sieht unordentlich aus").
 */
.h-faq summary:focus-visible { outline-offset: -4px; border-radius: 10px; }

.h-faq__text { padding: 0 1.3rem 1.35rem; color: var(--h-leise); }
.h-faq__text > :last-child { margin-bottom: 0; }

/* ------------------------------------------------------------------ */
/* Formular                                                            */
/* ------------------------------------------------------------------ */

.h-form { display: grid; gap: 1.2rem; max-width: 34rem; }
.h-feld { display: grid; gap: 0.4rem; }
.h-feld label { font-weight: 600; font-size: 0.95rem; }
.h-feld__opt { font-weight: 400; color: var(--h-still); }

/*
 * ⚠ 1rem SIND HIER 17px UND DAS IST DIE UNTERGRENZE.
 * Unter 16px zoomt Safari auf dem iPhone beim Antippen in die Seite
 * hinein und kommt nicht wieder ganz heraus.
 */
.h-feld input,
.h-feld textarea {
  font-family: inherit; font-size: 1rem; color: var(--h-tinte);
  background: var(--h-grund-2); border: 1px solid var(--h-linie-hell);
  border-radius: var(--h-r-klein); padding: 0.75rem 0.9rem; width: 100%;
  transition: border-color 0.16s var(--h-ease);
}
.h-feld input::placeholder, .h-feld textarea::placeholder { color: var(--h-still); }
.h-feld input:hover, .h-feld textarea:hover { border-color: var(--h-leise); }
.h-feld textarea { resize: vertical; min-height: 8.5rem; }

.h-form__recht { font-size: 0.88rem; color: var(--h-still); margin: 0; }

/*
 * Der Honigtopf gegen Spam.
 * ⚠ NICHT `display: none` UND NICHT `hidden`: Beides erkennen viele
 * Bots und lassen das Feld dann in Ruhe. Aus dem Bild geschoben ist es
 * im DOM ganz normal vorhanden, und genau das ist der Sinn.
 */
.h-honig { position: absolute; left: -9999px; top: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* ------------------------------------------------------------------ */
/* Brotkrumen                                                          */
/* ------------------------------------------------------------------ */

.h-krumen { font-size: 0.88rem; color: var(--h-still); padding-top: 1.4rem; }
.h-krumen ol { list-style: none; display: flex; flex-wrap: wrap; gap: 0.45rem; margin: 0; padding: 0; }
.h-krumen li::after { content: "/"; margin-left: 0.45rem; color: var(--h-linie-hell); }
.h-krumen li:last-child::after { content: ""; }
.h-krumen a { color: var(--h-still); }
.h-krumen a:hover { color: var(--h-leise); }

/* ------------------------------------------------------------------ */
/* Fusszeile                                                           */
/* ------------------------------------------------------------------ */

.h-fuss {
  position: relative;
  padding-block: clamp(48px, 6vw, 72px) 40px;
  font-size: 0.95rem; color: var(--h-leise);
}
.h-fuss::before {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 1px;
  background: linear-gradient(90deg, transparent, var(--h-linie-hell) 25%, var(--h-linie-hell) 75%, transparent);
}

.h-fuss__raster { display: grid; gap: 2.5rem; grid-template-columns: repeat(auto-fit, minmax(min(13rem, 100%), 1fr)); }

.h-fuss h2 {
  font-family: var(--h-font); font-size: 0.78rem; font-weight: 600;
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--h-still);
  margin-bottom: 0.9rem;
}

.h-fuss ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.5rem; }
.h-fuss a { color: var(--h-leise); text-decoration: none; }
.h-fuss a:hover { color: var(--h-tinte); }
.h-fuss address { font-style: normal; line-height: 1.75; }

.h-fuss__schluss {
  margin-top: 2.75rem; padding-top: 1.4rem; border-top: 1px solid var(--h-linie);
  display: flex; flex-wrap: wrap; gap: 0.6rem 1.5rem; justify-content: space-between;
  color: var(--h-still); font-size: 0.86rem;
}

/* ------------------------------------------------------------------ */
/* Rechtstexte                                                         */
/* ------------------------------------------------------------------ */

/*
 * ⚠ DER INHALT IST ANWALTLICH GEPRUEFT. Hier steht ausschliesslich,
 * wie er aussieht.
 *
 * Auf dunklem Grund ist langer Fliesstext anstrengender als auf
 * hellem. Deshalb hier: etwas groesser, etwas mehr Zeilenabstand, und
 * der Text steht dichter an `--h-tinte` als am leiseren Grau.
 */
.h-recht { max-width: var(--h-breite-text); font-size: 1.02rem; line-height: 1.72; }
.h-recht p, .h-recht li { color: color-mix(in srgb, var(--h-tinte) 86%, var(--h-leise)); }
.h-recht h2 { margin-top: 2.8rem; font-size: 1.4rem; }
.h-recht h3 { margin-top: 2rem; font-size: 1.12rem; }
.h-recht ul, .h-recht ol { padding-left: 1.3em; }
.h-recht li { margin-bottom: 0.4em; }
.h-recht table { font-size: 0.94rem; }

.h-stand { color: var(--h-still); font-size: 0.92rem; margin-bottom: 2.4rem; }

/* ------------------------------------------------------------------ */
/* Telefon                                                             */
/* ------------------------------------------------------------------ */

/*
 * ⚠ OHNE ZEIGER TRAEGT DER SCROLL DIE TIEFE.
 *
 * Auf dem Telefon gibt es keine Neigung zum Zeiger, und ein flacher
 * Schirm ist nur ein Bild. Stattdessen kippt jede Szene mit dem
 * Scrollen: Kommt sie von unten, lehnt sie nach hinten; in der Mitte
 * steht sie gerade; geht sie oben hinaus, kippt sie nach vorn. Die
 * Perspektive kommt vom Elternelement, die Zeitachse vom Sichtfenster.
 * Kein Skript, kein Scroll-Listener, und ohne `view()` steht der
 * Schirm einfach flach.
 *
 * Nur fuer Geraete OHNE Zeiger (`hover: none`). Auf dem Desktop
 * fuehrt das Skript die Neigung, und zwei Quellen fuer dieselbe
 * Transformation wuerden sich ueberschreiben.
 */
@keyframes h-kippt {
  from { transform: rotateX(16deg) scale(0.97); }
  50% { transform: none; }
  to { transform: rotateX(-14deg) scale(0.97); }
}

@supports (animation-timeline: view()) {
  @media (hover: none) and (prefers-reduced-motion: no-preference) {
    .h-scrollt .h-szene__raum {
      animation: h-kippt linear both;
      animation-timeline: view();
      animation-range: entry 0% exit 100%;
    }
  }
}

@media (max-width: 40rem) {
  /*
   * ⚠ KEIN ANSCHNITT DES SCHIRMS. Hier stand kurz: Schirm 132 Prozent
   * breit, laeuft rechts aus dem Bild, "wie ein Geraet, das ueber den
   * Rand reicht". Max: "hero auf mobil ist abgeschnitten." Er hat
   * recht. Anschnitt funktioniert bei einem Geraeterahmen, dessen
   * Kante man kennt; ein Eingabefeld, das am Bildrand endet, ist ein
   * Bild, das nicht passt. Stattdessen bekommt das Telefon einen
   * eigenen, schmaleren Ausschnitt (bildMobil), der ganz sichtbar ist.
   */

  /*
   * ⚠ TABELLEN MIT KOPFZEILE WERDEN ZU KARTEN.
   * Drei Spalten auf 350 Punkten heisst seitlich scrollen, und die
   * dritte Spalte (die mit unserer App) war abgeschnitten. Jede Zeile
   * wird eine Karte: der Vergleichspunkt als Ueberschrift, darunter
   * beide Werte nebeneinander mit dem Spaltennamen als Beschriftung
   * (aus data-spalte, siehe layout.mjs).
   */
  .h-tabelle-huelle--karten { overflow: visible; border: 0; background: none; width: auto; max-width: none; }
  .h-tabelle-huelle--karten table,
  .h-tabelle-huelle--karten tbody,
  .h-tabelle-huelle--karten td { display: block; }
  .h-tabelle-huelle--karten thead { display: none; }
  .h-tabelle-huelle--karten tr {
    display: grid; grid-template-columns: 1fr 1fr; gap: 0.3rem 1rem;
    padding: 0.95rem 1.05rem; margin-bottom: 0.6rem;
    border: 1px solid var(--h-linie); border-radius: var(--h-r-klein);
    background: var(--h-grund-2); box-shadow: var(--h-kante);
  }
  .h-tabelle-huelle--karten td { border: 0; padding: 0; font-size: 0.95rem; }
  .h-tabelle-huelle--karten td:first-child { grid-column: 1 / -1; font-weight: 600; margin-bottom: 0.15rem; }
  .h-tabelle-huelle--karten td:not(:first-child)::before {
    content: attr(data-spalte); display: block;
    font-size: 0.72rem; letter-spacing: 0.05em; text-transform: uppercase; color: var(--h-still);
    margin-bottom: 0.1rem;
  }

  /* Die Fusszeile in zwei Spalten statt vier untereinander; die
     Anschrift braucht die ganze Breite. */
  .h-fuss__raster { grid-template-columns: 1fr 1fr; gap: 2rem 1.25rem; }
  .h-fuss__raster > :last-child { grid-column: 1 / -1; }
}

/* ------------------------------------------------------------------ */
/* Druck                                                               */
/* ------------------------------------------------------------------ */

@media print {
  .h-kopf, .h-fuss, .h-knopfreihe, .h-skip, .h-licht, .h-zeiger-licht, body::after { display: none; }
  body { color: #000; background: #fff; font-size: 11pt; }
  /* Die Silber-Ueberschrift ist auf Papier sonst unsichtbar (color: transparent). */
  .h-hero h1 { background: none; -webkit-text-fill-color: #000; color: #000; }
  .h-recht p, .h-recht li, td, .h-lede { color: #000; }
  a::after { content: " (" attr(href) ")"; font-size: 9pt; color: #555; }
}

/* Der Zusatz unter dem Preis, etwa der Jahrespreis. */
.h-plan__text { color: var(--h-leise); margin: 0.2rem 0 0; font-size: 0.94rem; }

/* ------------------------------------------------------------------ */
/* Einwilligung fuer die Reichweitenmessung                            */
/* ------------------------------------------------------------------ */

/*
 * ⚠ BEIDE KNOEPFE SEHEN GLEICH AUS, UND ZWAR ABSICHTLICH.
 * Gleiche Groesse, gleiche Farbe, gleiches Gewicht, nebeneinander. Ein
 * hervorgehobenes "Einverstanden" neben einem blassen "Ablehnen" waere
 * nach staendiger Aufsichtspraxis keine freie Einwilligung -- und damit
 * die ganze Messung rechtswidrig. Wer hier einen der beiden Knoepfe
 * auffaelliger macht, kippt die Rechtsgrundlage.
 *
 * ⚠ KEINE SPERRE. Der Kasten sitzt unten, verdeckt die Seite nicht und
 * hat keinen Ueberzug. Die Seite bleibt ohne Entscheidung vollstaendig
 * benutzbar; alles andere waere eine Cookie-Wall.
 */
.h-consent {
  position: fixed; inset: auto 0 0 0; z-index: 60;
  padding: 0 var(--h-luft) max(var(--h-luft), 16px);
  display: flex; justify-content: center;
  pointer-events: none;
}

/* ⚠ OHNE DIESE ZEILE VERSCHWINDET DER KASTEN NIE.
 *
 * Das Skript blendet ihn ueber das Attribut "hidden" aus. Die
 * Browser-Vorgabe dafuer ist [hidden] { display: none } -- und die hat
 * dieselbe Spezifitaet wie .h-consent { display: flex } eine Zeile
 * darueber. Bei Gleichstand gewinnt die SPAETERE Regel, also unsere:
 * Das Attribut steht da und tut nichts.
 *
 * Gefunden am 2026-09-07 von Max, im Betrieb auf hand-e.de. Mein Test
 * hat es NICHT gefunden, weil er element.hidden ausgelesen hat -- also
 * das Attribut, das ja korrekt gesetzt war -- statt getComputedStyle
 * oder die gemessene Hoehe. Ein Test, der die ABSICHT prueft statt der
 * WIRKUNG, ist keiner.
 *
 * Gilt fuer JEDES kuenftige Element, das ueber "hidden" geschaltet
 * wird und ein eigenes display traegt. */
.h-consent[hidden] { display: none; }

.h-consent__kasten {
  pointer-events: auto;
  width: min(100%, 42rem);
  display: flex; align-items: center; gap: 24px;
  padding: 18px 20px;
  background: color-mix(in srgb, var(--h-grund-2) 88%, transparent);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  border: 1px solid var(--h-linie-hell);
  border-radius: var(--h-r);
  box-shadow: var(--h-kante), 0 24px 60px -28px #000;
}

.h-consent__titel {
  font-family: var(--h-font-display); font-weight: 800; font-size: 0.95rem;
  letter-spacing: -0.02em; color: var(--h-tinte); margin: 0 0 5px;
}
.h-consent__text p:last-child {
  margin: 0; color: var(--h-leise); font-size: 0.84rem; line-height: 1.55;
}
.h-consent__text a { color: var(--h-akzent); }

.h-consent__knoepfe { display: flex; gap: 10px; flex: none; }

/* ⚠ BEIDE KNOEPFE SIND DASSELBE GLAS.
 *
 * Sie tragen das Idiom von .h-knopf--zweit, nur kompakter -- damit
 * sehen sie aus wie die Knoepfe der uebrigen Seite, statt wie ein
 * fremdes Bauteil am unteren Rand. Was sie NICHT tragen duerfen, ist
 * .h-knopf--haupt: Ein hervorgehobenes "Akzeptieren" neben einem
 * blassen "Ablehnen" ist nach staendiger Aufsichtspraxis keine freie
 * Einwilligung, und dann ist die ganze Messung rechtswidrig.
 * Der Akzent ist hier also nicht Geschmack, sondern verboten. */
.h-consent__knopf {
  font-family: var(--h-font); font-weight: 600; font-size: 0.88rem;
  line-height: 1.2; color: var(--h-tinte);
  background: color-mix(in srgb, var(--h-grund-3) 55%, transparent);
  border: 1px solid var(--h-linie-hell);
  border-radius: var(--h-r-klein);
  box-shadow: var(--h-kante);
  padding: 11px 20px; cursor: pointer; white-space: nowrap;
  transition: background 0.2s var(--h-ease), border-color 0.2s var(--h-ease),
              transform 0.2s var(--h-ease);
}
.h-consent__knopf:hover {
  background: var(--h-grund-3); border-color: var(--h-leise);
  transform: translateY(-1px);
}
.h-consent__knopf:active { transform: translateY(1px); }

@media (max-width: 44rem) {
  .h-consent__kasten { flex-direction: column; align-items: stretch; gap: 16px; }
  .h-consent__knoepfe > * { flex: 1; }
}
