/* d:picto – Grundoptik nach dem Entwurf d.picto.ai.
   Die Farben sind aus dem Layout abgenommen; sie stehen hier als Tokens,
   damit eine spaetere Korrektur an EINER Stelle passiert. */

/* Inter – dieselbe Schrift wie designstudios.ch (dort gemessen: Gewichte
   300 und 600). Selbst ausgeliefert statt von Google Fonts: der Shop soll
   bei jedem Seitenaufruf keinen Drittanbieter aufrufen, und Inter steht
   unter der SIL Open Font License. */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url('/schriften/inter-v12-latin-300.woff2') format('woff2');
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/schriften/inter-v12-latin-600.woff2') format('woff2');
}

:root {
  /* ZWEI Blautöne, nach der Vorgabe des Owners vom 02.10.2026 – vorher
     waren es drei, die sich überlappten (--blau-dunkel stand für sechs
     Flächen UND elf Schriften).

       Flächen  100C / 050M / 000Y / 060K
       Schrift  100C / 050M / 000Y / 040K

     Dritter Anlauf am selben Abend, und der Weg dahin steht hier, damit
     niemand ihn nochmals geht: 40K/20K waren am Schirm zu grell und die
     Schrift verfehlte mit 4,43:1 die Lesbarkeitsmarke; 60K/50K gerieten
     zu schwarz. Die Fläche bleibt bei 60K, die Schrift steht auf 40K.

     Der Flächenwert ist GEMESSEN, nicht gerechnet: #2259a2 stammt aus
     dem Export des Owners. Die naive CMYK-Formel ergäbe #004c99 und
     liegt sichtbar daneben – sie kennt kein Farbprofil.

     Die SCHRIFT ist damit der gemessene Anker selbst (#2259a2, 6,96:1
     auf Weiss). Die FLÄCHE ist daraus abgeleitet: bei gleicher Buntfarbe
     skaliert RGB mit (1−K), also Faktor 0,40/0,60 (11,18:1). Ändert sich
     ein K-Wert, ist hier nachzurechnen – nicht zu schätzen. */
  --blau-flaeche: #173b6c;
  --blau-schrift: #2259a2;
  --grau:        #eef0f1;   /* Kacheln, Teaserflaechen */
  --grau-linie:  #c9ced1;
  --schwarz:     #1a1a1a;
  --grau-text:   #6b7276;
  --weiss:       #ffffff;

  /* Inter kennt nur diese zwei Gewichte – 400 oder 700 wuerde der Browser
     rechnerisch faelschen und die Schrift verzerren. */
  --schrift: 'Inter', system-ui, sans-serif;

  --gasse: 16px;            /* Seitenrand auf dem Telefon */
  --breite: 1120px;
  /* EIN Abstand fuer alles im Raster – Kacheln wie Teaser, auf jeder
     Schirmbreite derselbe Wert. Unterschiedliche Abstaende bei gleich
     aussehenden Flaechen lesen sich als Fehler. */
  --abstand: 12px;
  --logo-hoehe: 34px;
  --menue-unterlaenge: 3.02px;   /* »g« in Inter 600/14px, gemessen */
  /* Das Warenkorb-Symbol: Kastengrösse und der Versatz, der das
     GEZEICHNETE auf die Schriftgrundlinie der Menüpunkte setzt
     (Owner 03.10.2026: 120 % von 26 px, und tiefer).

     GEMESSEN bei 1440 px für 22/26/28/31.2/32 px: die Unterkante des
     `<img>` liegt bei JEDER dieser Grössen exakt auf der Grundlinie der
     Menüschrift (Differenz 0.00 px). Das besorgt `align-self: baseline`
     am Korb schon allein. Der frühere Hub von 3.8 px kam aus der Messung,
     BEVOR `align-self` dazukam – er schob das Symbol seither um ebenso
     viel nach OBEN, statt es zu setzen.

     Was bleibt, ist die Leere IM SVG: die unterste Ink-Kante (Unterkante
     des Rades, y = 160,88 in der Gruppe, mal deren scale 0.36284836)
     liegt bei 58,375 von 72 Einheiten. Unter dem Gezeichneten stehen also
     18,92 % der Kastenhöhe Luft – genau darum muss das Bild TIEFER, damit
     das Rad auf der Linie steht. Bei 26 px schwebte es 4,92 px darüber,
     plus 3,8 px Hub = 8,72 px; gemessen, und genau das war zu sehen.

     Der Versatz ist deshalb aus der Grösse GERECHNET statt gemessen: wer
     die Grösse ändert, muss nichts nachmessen. Von der Ink-Grenze im SVG
     weiss ohnehin kein Layout-Algorithmus – dafür gibt es kein
     `align-self`. */
  --korb-groesse: 31.2px;
  --korb-ink-luft-unten: 0.18924;   /* 1 − 58,375/72, aus der SVG-Geometrie */
  --korb-hub: calc(var(--korb-groesse) * var(--korb-ink-luft-unten));
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--weiss);
  color: var(--schwarz);
  font-family: var(--schrift);
  font-weight: 300;
  -webkit-text-size-adjust: 100%;
}

b, strong { font-weight: 600; }

main, .kopf, .fuss {
  max-width: var(--breite);
  margin: 0 auto;
  padding-left: var(--gasse);
  padding-right: var(--gasse);
}

/* ---------- Kopf ---------- */

.kopf {
  display: flex;
  /* An der GRUNDLINIE, nicht mittig: Die Menüpunkte sollen auf derselben
     Fusslinie sitzen wie das Logo (Owner 29.09.2026). Mittig ausgerichtet
     sässen sie je nach Logohöhe mal höher, mal tiefer. */
  align-items: baseline;
  /* KEIN `space-between`: Das verteilt den Rest auch zwischen Menü und
     Korb, sobald die Kopfzeile breiter ist als ihr Inhalt – bei 820 px
     gemessene 154 px Abstand statt 24, das Menü hing in der Mitte. Der
     ganze Freiraum gehört links neben das Logo, dann steht alles Übrige
     als Block rechts. */
  justify-content: flex-start;
  padding-top: 28px;
  padding-bottom: 28px;
}

/* Das Logo ist eine SVG-Datei, kein Schriftnachbau: Helvetica Neue liegt
   auf Macs, aber nicht auf Windows und Android – dort waere die Marke auf
   Arial zurueckgefallen. Die Farbe steckt IM SVG (#105ba7) und wird hier
   bewusst nicht ueberschrieben. Das Verhaeltnis ist genau 3:1
   (viewBox 170.08 x 56.69), width und height im HTML halten den Platz frei,
   damit beim Laden nichts springt. */
/* Der ganze Freiraum landet hier – damit steht das Logo links und alles
   Übrige rechtsbündig beisammen, auf JEDER Breite. */
.marke {
  display: block;
  line-height: 0;
  margin-right: auto;
}

/* Die Menüpunkte sollen mit ihrer UNTERLÄNGE dort enden, wo das Logo
   endet – das »g« in »Piktogramme« auf derselben Linie wie das »p« in
   »d:picto« (Owner-Präzisierung 29.09.2026). Nicht Grundlinie auf
   Grundlinie: Das sass 2 px zu hoch, weil die Unterlänge des Logos tiefer
   reicht als seine Schriftlinie.

   Im SVG gemessen (viewBox 0 0 170.08 56.69): Grundlinie y = 42.43,
   Unterlänge des »p« y = 50.84. Die Unterlänge liegt also
   (56.69 − 50.84) / 56.69 = 10,31 % der Bildhöhe über der Bildunterkante.

   Die Baseline eines <img> ist seine Unterkante. Ein negativer unterer
   Aussenabstand hebt sie an, und `align-items: baseline` am Kopf richtet
   die Menüschrift daran aus. Nötig ist:

       10,31 % der Logohöhe   (Unterlänge des Logos über der Bildkante)
     + Unterlänge der Menüschrift

   Der zweite Summand hängt an der Schrift, nicht am Logo, und steht
   deshalb als eigene Variable: 3,02 px, am »g« in Inter 600/14 px im
   Browser gemessen. Wer die Menüschrift ändert, misst ihn neu –
   `scratchpad/fuss.mjs` tut genau das. */
.marke img {
  height: var(--logo-hoehe);
  width: auto;
  margin-bottom: calc(var(--logo-hoehe) * -0.1031 - var(--menue-unterlaenge));
}

/* Das Menü steht ab 1000 px in der Zeile; darunter übernimmt der
   Hamburger. Die Kopfzeile wird dafür zu vier Feldern: Marke, Menü,
   Warenkorb, Hamburger. */
/* Das Menü ist der NORMALFALL und steht sichtbar da. Bis 29.09.2026 war
   es umgekehrt (`display:none`, erst ab 1000 px sichtbar) – mit einem
   Hamburger, der keine Funktion hatte: Auf jedem Telefon waren die drei
   Punkte damit unerreichbar. Wann umgeschaltet wird, MISST jetzt
   `kopf.js`; ohne Skript bleibt das Menü sichtbar. */
.menue {
  display: flex;
  gap: 24px;
  font-size: 14px;
  font-weight: 600;
  margin-right: 24px;
  white-space: nowrap;
}
.menue a {
  color: var(--blau-schrift);
  text-decoration: none;
}
.menue a:hover { text-decoration: underline; }
.menue a[aria-current="page"] { color: var(--schwarz); }

/* Der Hamburger erscheint NUR, wenn gemessen zu wenig Platz ist. */
.burger { display: none; }
.kopf.eng .burger { display: block; }

/* Eng: Das Menü verlässt die Zeile und klappt unter der Kopfzeile auf.
   `position: absolute` statt eines Umbruchs, damit die Kopfhöhe gleich
   bleibt – eine Kopfzeile, die beim Öffnen wächst, schiebt die Seite. */
.kopf.eng .menue {
  display: none;
  position: absolute;
  top: 100%;
  /* Rechtsbündig unter dem Korb, nicht über die volle Breite: Das Menü
     gehört optisch zum Knopf, der es geöffnet hat. */
  right: var(--gasse);
  left: auto;
  min-width: 13em;
  z-index: 20;
  flex-direction: column;
  gap: 0;
  margin: 0;
  padding: 4px 16px 12px;
  background: var(--weiss);
  border: 1px solid var(--grau-linie);
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.10);
}
.kopf.eng.menue-offen .menue { display: flex; }
/* Grosse Trefferflächen: Auf dem Telefon wird mit dem Daumen gezielt. */
.kopf.eng .menue a {
  padding: 11px 0;
  border-top: 1px solid var(--grau-linie);
}
.kopf.eng .menue a:first-child { border-top: 0; }

/* Die Kopfzeile trägt das aufgeklappte Menü und muss es verankern. */
.kopf { position: relative; }

/* Im aufgeklappten Zustand werden aus den zwei Strichen ein Kreuz – der
   Knopf sagt damit, was der nächste Klick tut. */
.kopf.menue-offen .burger span:first-child {
  transform: translateY(3.5px) rotate(45deg);
}
.kopf.menue-offen .burger span:last-child {
  transform: translateY(-3.5px) rotate(-45deg);
}
.burger span { transition: transform 0.15s; }

.korb {
  /* An der Fusslinie der Menüpunkte (Owner 02.10.2026), nicht mehr an der
     Mitte des Logos. Vorher stand hier `center` mit der Begründung,
     Symbole hätten keine Grundlinie – sie haben eine: Für ein ersetztes
     Element wie ein `<img>` IST die Unterkante die Grundlinie, und
     `baseline` legt sie damit genau auf die Schriftlinie daneben.
     Gemessen bei 1440px: mit `center` sass die Unterkante auf 54.2, die
     Schriftgrundlinie auf 51.7 – 2.5px zu tief. */
  align-self: baseline;
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  text-decoration: none;
  color: var(--blau-schrift);
  font-size: 13px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
/* Das Symbol ist SS103 «Warenkorb» aus der eigenen Serie – kein
   Unicode-Emoji: das wird auf jeder Plattform anders gezeichnet und wäre
   in einem Piktogramm-Shop ein Fremdkörper. */
/* 31.2px = 120 % von 26 (Owner 03.10.2026). Das KOSTET diesmal Kopfhöhe:
   gemessen wächst sie von 86.5 auf 90.2 px, weil das Symbol damit höher
   ist als das Logo (34px), das sie bis 26px allein bestimmt hat. Bis 26px
   war sie gratis, ab 28px nicht mehr (87.0), bei 32px 91.0.
   Vom Kasten ist nur gut die Hälfte gezeichnet: die Ink misst 71 % der
   Breite und 62 % der Höhe, bei 31.2px also 22.1 x 19.5px statt 18.4 x
   16.2 bei 26px. Das ist der Zuwachs, den man sieht.
   Die Strichstärke gewinnt mit: 6,80 von 198,43 Einheiten sind bei 31.2px
   1,07px statt 0,89 – jetzt über einem Pixel und damit ohne Glättung.
   `top` verschiebt nur optisch: die Kopfhöhe hängt an der Bildhöhe, nicht
   am Versatz. */
.korb-symbol {
  display: block;
  width: var(--korb-groesse);
  height: var(--korb-groesse);
  position: relative;
  top: var(--korb-hub);
}
@media (max-width: 999px) {
  /* Auf dem Telefon steht der Korb links vom Hamburger.
     KEIN `margin-left: auto` mehr: Das war ein ZWEITER automatischer
     Aussenabstand neben dem am Logo, und zwei davon TEILEN SICH den
     Freiraum. Gemessen bei 960 px: 200 px links vom Menü, 224 px
     rechts davon – das Menü hing in der Mitte, obwohl sein Abstand zum
     Korb auf 24 px stand. Den ganzen Freiraum nimmt jetzt allein das
     Logo, und alles Übrige steht als Block rechts. */
  .korb { margin-right: 14px; }
}

.burger {
  align-self: center;
  background: none;
  border: 0;
  padding: 6px 0;
  cursor: pointer;
  width: 34px;
}
.burger span {
  display: block;
  height: 2px;
  background: var(--blau-flaeche);
  margin: 5px 0;
}

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

/* EINE Höhe auf allen Seiten (Owner-Vorgabe 28.09.2026), abgeleitet von
   der Einstiegsseite. Seit 07.10.2026 240 px (Telefon 189 px), Owner-
   Vorgabe: Platz für den Hinweis bei geschlossener Kasse mit Abstand unter
   dem Teasertext. Auf Katalog- und Suchseiten ist der Block leer, die Mindesthöhe
   hält ihn trotzdem auf demselben Mass. `aria-hidden` bekommt er dort,
   weil er noch keinen Inhalt trägt – ein Screenreader soll keine leere
   Region ansagen. */
.hero {
  background: var(--blau-flaeche);
  color: var(--weiss);
  min-height: 240px;
  padding: 28px;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  font-size: 17px;
  line-height: 1.5;
}
.hero p { margin: 0; }
.hero-zahl { font-weight: 600; margin-bottom: 2px !important; }
/* Hinweis bei geschlossener Kasse, etwas kleiner als der Text und mit
   Abstand darunter (Owner 07.10.2026). EINE Zeile, auch am Telefon –
   sonst wächst die Startseite über die 189 px. */
.hero .hero-hinweis {
  margin-top: 7px;
  font-size: 14px;
  line-height: 18.5px;
}


/* ---------- Suche ---------- */

.suche {
  display: flex;
  margin-top: 8px;
  max-width: 660px;
}
.suche input {
  flex: 1 1 auto;
  min-width: 0;
  font: inherit;
  font-weight: 600;
  color: var(--blau-schrift);
  background: var(--grau);
  border: 1px solid var(--grau-linie);
  border-right: 0;
  padding: 9px 12px;
}
.suche input::placeholder { color: var(--blau-schrift); opacity: 1; }

/* Der hellblaue Ring des Browsers bringt hier nichts – das Feld ist als
   Eingabe erkennbar, und der Ring liegt als Fremdkörper über der eigenen
   Gestaltung.
   ABER: Er wird ERSETZT, nicht entfernt. Wer mit der Tastatur arbeitet,
   muss sehen, wo er steht; ein ersatzloses `outline: none` macht das Feld
   für Tastaturnutzer unsichtbar. Statt des Rings wird der Rahmen des
   Feldes dunkel – ruhiger, aber eindeutig. */
.suche input:focus,
.suche button:focus {
  outline: none;
}
.suche:focus-within input,
.suche:focus-within button {
  border-color: var(--blau-flaeche);
}
.suche:focus-within input {
  background: var(--weiss);
}
/* DER INNENABSTAND STAMMT AUS DEM ENTWURF (Owner 04.10.2026: «das Feld ist
   vielleicht etwas zu breit»). In `d.picto.ai` steht der Pfeil (40,13 breit)
   in einem Rahmen von 60 – also rund 9,9 Rand je Seite. Hier standen 20 px,
   doppelt so viel, und der Knopf geriet auf 82 px statt auf 60.

   9 px samt dem 1-px-Rahmen ergeben 59,7 px: Verhältnis Fläche zu Pfeil
   1,503 gegen 1,495 in der Datei.

   Waagrecht und senkrecht derselbe Wert, aber aus verschiedenen Gründen:
   waagrecht, weil der Entwurf es so zeigt – senkrecht, weil die Zeilenhöhe
   am Eingabefeld daneben hängt (dessen `padding: 9px 12px`). Die beiden
   stehen in derselben Flex-Zeile und müssen gleich hoch bleiben. */
.suche button {
  flex: 0 0 auto;
  font-size: 17px;
  line-height: 1;
  color: var(--weiss);
  background: var(--blau-flaeche);
  border: 1px solid var(--blau-flaeche);
  padding: 9px;
  cursor: pointer;
}

/* ---------- Familien ---------- */

.familien { margin-top: 34px; }
.familien h2 {
  font-size: 13px;
  font-weight: 600;
  margin: 0 0 6px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--grau-linie);
}

/* Auf breiten Schirmen alle neun Familien auf einmal – sie sind der
   Haupteinstieg in den Katalog, und was man wegblaettern muss, wird
   seltener gefunden. Platz ist dort genug. */
/* `minmax(0, 1fr)` statt `1fr`: Ein blosses `1fr` bedeutet
   `minmax(auto, 1fr)`, und `auto` als Minimum ist die min-content-Breite.
   Die längste Beschriftung ("Orientierung &") dehnt damit ihre Spalte, das
   Raster wird breiter als sein Container und läuft rechts aus dem Bild –
   was aussieht, als stimmte die Spaltenzahl nicht. Die 0 erlaubt das
   Schrumpfen. */
.kacheln {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: var(--abstand);
}
@media (min-width: 1000px) { .kacheln { grid-template-columns: repeat(9, minmax(0, 1fr)); } }

/* Auf dem Telefon drei Spalten, vertikal gescrollt – das ist die
   Grundform, und sie gilt für die FAMILIENSEITEN mit ihren bis zu 47
   Motiven. Dort ist ein Streifen falsch: zu viele Elemente, und man
   vergleicht sie miteinander. */
@media (max-width: 699px) {
  .kacheln { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* Die STARTSEITE wischt dagegen (Owner-Entscheid 28.09.2026, am Gerät
   erprobt – das Auswählen funktioniert). Sie hat genau neun Familien:
   überschaubar, einmal durchgewischt, und der Gewinn ist gross. Gerechnet
   für 390 px: eine Reihe statt drei spart über 300 px und holt die Teaser
   ("Vektor", "Pro") in den ersten Bildschirm, wo sie sonst bei 866 px
   liegen und nie gesehen werden.

   Der Anschnitt ist der tragende Teil: 2.2 Kacheln passen ins Bild, die
   dritte ragt herein. Ein Streifen, der glatt am Rand endet, sieht
   vollständig aus – dann sucht niemand weiter. */
@media (max-width: 699px) {
  .kacheln--streifen {
    display: flex;
    grid-template-columns: none;
    overflow-x: auto;
    scroll-snap-type: x proximity;
    scrollbar-width: none;
  }
  .kacheln--streifen::-webkit-scrollbar { display: none; }

  .kacheln--streifen .kachel {
    flex: 0 0 calc((100% - 2 * var(--abstand)) / 2.2);
    scroll-snap-align: start;
  }
}

/* `min-width: 0` durch die ganze Kette: Item -> Link -> Beschriftung
   -> Name. VORSORGE, kein behobener Fehler – gemessen passt das Raster
   (scrollWidth 468 = Containerbreite 468). Der Grund, es trotzdem zu
   setzen: `minmax(0, 1fr)` löst nur die SPALTE; Grid-Items und Flex-Kinder
   behalten `min-width: auto` (= min-content) und würden bei einem langen
   Motivnamen über ihre Spalte hinauslaufen. Der Katalog wächst noch, und
   dieser Fehler fällt erst beim längsten Namen auf. */
.kachel {
  min-width: 0;
}
.kachel a {
  display: block;
  min-width: 0;
  text-decoration: none;
  color: inherit;
}
.kachel .bild {
  background: var(--grau);
  /* IMMER quadratisch (Owner-Vorgabe 28.09.2026), auf jeder Schirmbreite.
     Das entspricht dem Gegenstand: Piktogramme sind auf einem Raster von
     72 x 72 konstruiert. Ein flacheres Feld auf dem Telefon hätte Höhe
     gespart, aber ein Piktogramm in einem liegenden Rahmen sieht aus wie
     ein Fehler im Beschnitt. */
  aspect-ratio: 1 / 1;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 22px;
  font-weight: 300;
  color: var(--blau-schrift);
}

/* Beschriftung: Name links (immer zweizeilig, umgebrochen nach dem &),
   Anzahl rechtsbuendig daneben, darunter eine 1px-Linie. Der Umbruch ist
   fest und nicht dem Zufall der Spaltenbreite ueberlassen – sonst stehen
   die Linien je Kachel auf anderer Hoehe und das Raster zerfaellt. */
/* Die Schriftgroesse steht HIER, nicht erst auf .name – sonst rechnen die
   em-Werte unten gegen die geerbten 16px des body statt gegen die 11px der
   Bezeichnung. Genau das war der Fehler: min-height ergab 45 px statt 30 px
   und liess die Linie 17.5 px zu tief stehen. */
.kachel .beschriftung {
  display: flex;
  min-width: 0;
  align-items: flex-start;
  justify-content: space-between;
  gap: 6px;
  font-size: 11px;
  line-height: 1.25;
  margin-top: 5px;
  /* 0.25em = 2.75 px, genau der Durchschuss zwischen zwei Textzeilen
     (13.75 px Zeilenhoehe minus 11 px Schriftgroesse). Der Abstand bis zur
     Linie ist damit derselbe wie der Abstand der beiden Namenszeilen. */
  padding-bottom: 0.25em;
  border-bottom: 1px solid var(--grau-linie);
  /* Zwei Zeilen plus derselbe Abstand – damit alle Linien auf einer Hoehe
     liegen, auch wenn ein Name einmal nur eine Zeile braucht. */
  min-height: calc(2 * 1.25em + 0.25em);
}
.kachel .name {
  font-weight: 600;
  /* Bei schmalen Kacheln darf ein langes Wort umbrechen statt die Spalte
     zu sprengen. */
  overflow-wrap: break-word;
  min-width: 0;
}
.kachel .anzahl {
  font-weight: 300;
  color: var(--grau-text);
  text-align: right;
  flex: 0 0 auto;
  /* Ziffern gleicher Breite: sonst tanzen die Zahlen in der Spalte. */
  font-variant-numeric: tabular-nums;
}

.kachel--laedt { background: var(--grau); aspect-ratio: 1 / 1; }


/* ---------- Katalogseite ---------- */

/* Strukturwechsel bei 1000 px (Spec 25.09.2026): darüber Filterspalte
   links, darunter liegt die Familienliste über dem Raster. Der Wert liegt
   knapp unter dem iPad im Querformat (1024 px), damit ein Tablet noch das
   zweispaltige Layout bekommt. */
.katalog-raster {
  display: grid;
  grid-template-columns: 1fr;
  gap: 24px;
  margin-top: 26px;
}
@media (min-width: 1000px) {
  .katalog-raster {
    grid-template-columns: 280px minmax(0, 1fr);
    gap: 32px;
  }
  /* Bleibt beim Scrollen stehen – sonst verliert man beim Auswählen den
     Überblick, welche Familien offen sind. `sticky` wirkt nur, wenn kein
     Vorfahr `overflow` beschneidet. */
  .filter {
    position: sticky;
    top: 20px;
    align-self: start;
  }
}

.familienliste {
  list-style: none;
  margin: 0 0 20px;
  padding: 0;
  font-size: 12px;
  font-weight: 600;
}
.familienliste li {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  padding: 4px 0;
  border-bottom: 1px solid var(--grau-linie);
}
.familienliste li.alle { margin-bottom: 10px; }
.familienliste a {
  color: var(--blau-schrift);
  text-decoration: none;
}
.familienliste a:hover { text-decoration: underline; }
/* Offene Familien stehen schwarz.
   Die Farbe MUSS auch auf dem `a` stehen, nicht nur auf dem `li`: Beim
   Aufklappen per Skript bleibt der Name ein Link, und `.familienliste a`
   überschreibt die Vererbung – der Eintrag blieb blau, obwohl die Familie
   offen war. Serverseitig fiel das nicht auf, weil die offene Familie dort
   überhaupt kein Link ist. */
.familienliste li.offen,
.familienliste li.offen a { color: var(--schwarz); }
/* Und die Unterstreichung weg: ein schwarzer Eintrag ist kein Ziel mehr,
   der Klick schliesst ihn nur. */
.familienliste li.offen a:hover { text-decoration: none; }
.familienliste .zahl {
  font-weight: 300;
  color: var(--grau-text);
  font-variant-numeric: tabular-nums;
}

.auswahlblock {
  font-size: 12px;
  border-top: 1px solid var(--grau-linie);
  padding-top: 10px;
}
.auswahl-kopf {
  display: flex;
  justify-content: space-between;
  font-weight: 600;
  margin: 0 0 6px;
}
.auswahl-hinweis {
  color: var(--grau-text);
  font-weight: 300;
  line-height: 1.35;
  margin: 0 0 10px;
}
.auswahlblock p { margin: 0 0 8px; }
.auswahlblock a { color: var(--blau-schrift); text-decoration: none; }

.btn {
  font: inherit;
  font-weight: 600;
  color: var(--weiss);
  background: var(--blau-flaeche);
  border: 0;
  padding: 9px 16px;
  cursor: pointer;
  width: 100%;
}
.btn:hover { background: var(--blau-flaeche); }

.familienblock { margin-bottom: 30px; }

/* Die Kachelgrösse ist FEST (120 px, schmal 104 px) und die Spaltenzahl
   ergibt sich daraus – nicht umgekehrt. Mit fester Spaltenstaffel
   schwankte die Kachel zwischen 46 und 214 px und sprang an den
   Umschaltpunkten; so bleibt sie bei 120–144 px (Spec 25.09.2026, dort
   durchgerechnet). Der Deckel verhindert, dass sie bei 1100 px
   Fensterbreite auf 153 px aufgeblasen wird. */
.kacheln-bereich .kacheln {
  grid-template-columns: repeat(auto-fill, minmax(104px, 144px));
}
@media (min-width: 700px) {
  .kacheln-bereich .kacheln {
    grid-template-columns: repeat(auto-fill, minmax(120px, 144px));
  }
}

/* Auf dem Telefon DREI Kacheln nebeneinander (Owner 03.10.2026) – das
   sieht die Grundregel für `.kacheln` oben ohnehin vor, der Katalog war
   die Ausnahme.

   Dass hier bisher ZWEI standen, lag NICHT an der Kachelgrösse, sondern
   an `auto-fill`: Die Wiederholungszahl rechnet der Browser mit der
   OBEREN Schranke des `minmax`, sobald die definit ist (CSS Grid
   § 7.2.3.1), also mit 144px. Die 104px-Untergrenze erzeugt deshalb NIE
   eine zusätzliche Spalte – sie lässt die vorhandenen nur schrumpfen, und
   dazu kam es nie. Gemessen bei 390px: (358 + 12) / (144 + 12) = 2,37 →
   zwei Spalten zu 144px, 58px blieben ungenutzt.

   Feste Spaltenzahl statt `auto-fill` ist hier auch das Richtige: Drei
   sollen es auf JEDER Telefonbreite sein, die Kachel folgt daraus. Mit
   `auto-fill` hinge die Zahl an der Gerätebreite und spränge zwischen
   einem iPhone SE und einem Pro Max – und ein Vierter käme ohnehin
   zurück, sobald das Gerät breit genug ist.

   Der Deckel von 144px bleibt derselbe wie oben: Der Telefonbereich
   reicht bis 699px, und drei ungedeckelte Spalten wären dort 214px breit
   (gemessen) – grösser als auf dem Schreibtisch. So wachsen sie von 88px
   bei 320px Gerätebreite auf 144px und dann nicht weiter. */
@media (max-width: 699px) {
  .kacheln-bereich .kacheln {
    grid-template-columns: repeat(3, minmax(0, 144px));
  }
}

.kachelknopf {
  display: block;
  width: 100%;
  font: inherit;
  text-align: left;
  background: none;
  border: 0;
  padding: 0;
  min-width: 0;
  cursor: pointer;
  color: inherit;
}
/* Der Auswahlzustand liegt auf dem Bildfeld, nicht auf der ganzen Kachel:
   der Rahmen soll das Piktogramm einfassen, nicht die Legende. */
.kachelknopf .bild {
  /* Eckig, überall (Owner-Vorgabe 28.09.2026) – der Layout-Entwurf zeigt
     abgerundete Kacheln, das ist verworfen. */
  border: 1px solid transparent;
  transition: border-color 0.12s;
}
.kachelknopf:hover .bild { border-color: var(--grau-linie); }
.kachelknopf.gewaehlt .bild { border-color: var(--blau-flaeche); }
.kachelknopf:focus-visible .bild { outline: 2px solid var(--blau-flaeche); outline-offset: 2px; }

/* Legende im Katalog: kleiner als auf der Startseite und OHNE Trennlinie –
   sie kostet dort nur Höhe und gewinnt nichts, weil die Kacheln in einem
   dichten Raster stehen und der Rahmen schon die Einheit markiert. */
.kacheln-bereich .beschriftung {
  border-bottom: 0;
  min-height: 0;
  font-size: 10px;
  padding-bottom: 0;
  margin-top: 4px;
}
.kacheln-bereich .name { font-weight: 600; }
.kacheln-bereich .anzahl { font-weight: 300; }

/* Auf dem Telefon liegt der Auswahlblock aus dem Bild – dort erscheint er
   als Leiste am unteren Rand, sobald etwas gewählt ist. */
.korbleiste {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 16px;
  background: var(--weiss);
  border-top: 1px solid var(--grau-linie);
  box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.08);
  font-size: 13px;
  z-index: 10;
}
.korbleiste .btn { width: auto; }
@media (min-width: 1000px) {
  /* Auf breiten Schirmen steht der Block in der Filterspalte. */
  .korbleiste { display: none; }
}

/* ---------- Familienseite, Suche, Fehlerseite ---------- */

/* Der Titel steht im selben Raster wie "Piktogrammfamilien" auf der
   Startseite – gleiche Linie, gleiche Höhe, damit die beiden Seiten als
   eine Familie lesbar sind. */
.familientitel {
  display: flex;
  align-items: baseline;
  gap: 12px;
  font-size: 13px;
  font-weight: 600;
  margin: 0 0 6px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--grau-linie);
}
/* Die Zahl ganz rechts, der Schalter direkt nach dem Namen – so steht er
   dort, wo der Blick nach dem Familiennamen ohnehin hinwandert, und nicht
   in der Ecke. */
.familienzahl { margin-left: auto; }

.alle-waehlen {
  font: inherit;
  font-size: 11px;
  font-weight: 600;
  color: var(--blau-schrift);
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
}
.alle-waehlen:hover { text-decoration: underline; }
.alle-waehlen.aktiv { color: var(--schwarz); }
.familienzahl {
  font-weight: 300;
  color: var(--grau-text);
  font-variant-numeric: tabular-nums;
}

.fehlerseite {
  padding: 40px 0 80px;
  max-width: 34em;
}
.fehlerseite h1 {
  font-size: 28px;
  font-weight: 600;
  color: var(--blau-schrift);
  margin: 0 0 12px;
}
.fehlerseite p {
  font-size: 17px;
  line-height: 1.5;
  margin: 0 0 10px;
}
.fehlerseite a {
  color: var(--blau-schrift);
  font-weight: 600;
}

/* ---------- Teaser ---------- */

.teaser {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--abstand);
  margin: 34px 0 60px;
}
@media (min-width: 700px) { .teaser { grid-template-columns: repeat(3, 1fr); } }

.teaser article {
  background: var(--grau);
  padding: 22px 24px 26px;
  font-size: 23px;
  line-height: 1.35;
  color: var(--blau-schrift);
  font-weight: 300;
}
.teaser p { margin: 0; }
.teaser a {
  color: var(--blau-schrift);
  font-weight: 600;
  text-decoration: none;
}
.teaser a:hover { text-decoration: underline; }

/* ---------- Infoseiten ---------- */

/* Satzspiegel: KEIN eigenes max-width hier. `main` gibt --breite vor und
   zentriert mit `margin: 0 auto`; ein engeres max-width auf demselben
   Element wird mitzentriert – der Text begann dann an einer anderen linken
   Kante als das Logo und der Fuss. Die Lesebreite gehoert deshalb nach
   INNEN, wo sie links am Satzspiegel stehen bleibt. */
.infoseite {
  padding-top: 30px;
  padding-bottom: 70px;
}
/* Zwei Breiten, beide in REM und nicht in em: `em` rechnet gegen die
   Schriftgroesse DES ELEMENTS – 46em waeren an der 30px-Ueberschrift
   1380px (also wirkungslos) und am 20px-Lead 920px. Drei verschiedene
   rechte Kanten fuer eine Angabe, die ueberall dasselbe meint.
   46rem = 736px fuer den Kopfblock und die Gliederung, 34rem = 544px fuer
   den Fliesstext. */
.infoseite h1 { max-width: 46rem; }
/* Der Lead bricht erst, wenn der Satzspiegel ihn zwingt – eine
   Zeilenbegrenzung, die knapp unter der Satzlaenge liegt, erzeugt einen
   Umbruch, den nichts verlangt (Owner 30.09.2026). */
.infoseite .lead { max-width: none; }
.infoseite h1 {
  font-size: 30px;
  font-weight: 600;
  color: var(--blau-schrift);
  margin: 0 0 14px;
  line-height: 1.2;
}
.infoseite .lead {
  font-size: 20px;
  font-weight: 300;
  line-height: 1.45;
  color: var(--blau-schrift);
  margin: 0 0 32px;
}
.infoabschnitt {
  border-top: 1px solid var(--grau-linie);
  padding-top: 14px;
  margin-bottom: 22px;
  /* Volle Satzspiegelbreite – der Entwurf des Owners (30.09.2026) fuehrt die
     Trennlinien ueber die ganze Breite, und die Bildpaare darunter brauchen
     sie fuer zwei Spalten. Der FLIESSTEXT bleibt trotzdem schmal (s.u.):
     die Linie gliedert, sie setzt keine Lesebreite. */
}
.infoabschnitt h2 {
  font-size: 17px;
  font-weight: 600;
  margin: 0;
}
/* 34em ist die Fliesstextbreite dieses Projekts (Fehlerseite, Formulare) –
   bei 16px rund 68 Zeichen je Zeile. Die frueheren 46em galten einer Seite
   ohne Text; an echten Absaetzen waeren es gegen 95 Zeichen, und die Zeile
   verliert am Umbruch den Anschluss. */
.infoabschnitt p {
  font-size: 16px;
  font-weight: 300;
  line-height: 1.6;
  max-width: 34rem;
  margin: 12px 0 0;
}

/* ---------- Nummerierter Vertragstext ---------- */

/* HAENGENDER EINZUG, kein Tabulator. Stand die Ziffer im Textfluss, lief
   die zweite Zeile unter sie: «1.1 Diese Geschaeftsbedingungen gelten …»
   und darunter, buendig mit der Ziffer, «picto.designstudios.ch bei …».
   Beim Ueberfliegen verschwand damit, wo eine Ziffer anfaengt – und genau
   das Ueberfliegen ist, was man mit einem Vertragstext tut.

   Zwei Spalten statt `text-indent: -2.5em`: Das Grid haelt die Ziffer in
   ihrer Spalte, egal wie lang sie wird, und braucht keinen negativen
   Einzug, den jedes Elternelement mit `overflow` abschneiden kann.

   DIE SPALTE IST GEMESSEN, nicht geraten (04.10.2026, Chrome gegen diese
   Datei): Die laengste Ziffer «13.2» misst 31,72 px in 600er Schnitt
   (dt, h3) und 28,97 px in 300er (Absatz). 2,5rem = 40 px traegt beide
   und laesst gut 8 px Abstand. EINE Breite fuer alle drei, damit die
   Ziffer eines Absatzes mit der einer Stufe fluchtet – stuenden sie
   versetzt, saehe die Gliederung nach zwei Gliederungen aus. */
.ziffer {
  display: grid;
  grid-template-columns: 2.5rem 1fr;
}
.ziffer > .nr { grid-column: 1; }

/* Was unter einer Ziffer haengt, ohne selbst eine zu tragen – die
   Ausfuehrungen «Vektor»/«Pro» unter 5.2, die Verbotsliste unter 6.6, der
   Nachsatz dazu. `padding` und nicht `margin`, weil `box-sizing:
   border-box` den Einzug dann INNERHALB der max-width haelt: Sonst waere
   jeder eingerueckte Block um 2,5rem breiter als der Text darueber und
   ragte rechts aus dem Satzspiegel. */
.unterzug { padding-left: 2.5rem; }
/* Die Aufzaehlungspunkte brauchen ihren eigenen Platz zusaetzlich –
   20px ist der Wert aus `.regelliste`. */
.regelliste.unterzug { padding-left: calc(2.5rem + 20px); }

/* Die Lizenzseite laesst den Vertragstext breiter fliessen als die
   uebrigen Infoseiten (Owner 04.10.2026). Das widerspricht der 34rem-Regel
   darueber nur scheinbar: Sie gilt fuer Fliesstext, den man am Stueck
   liest, und dort verliert eine lange Zeile am Umbruch den Anschluss. Ein
   nummerierter Vertrag wird nicht am Stueck gelesen, sondern
   nachgeschlagen – in Einheiten von zwei bis vier Zeilen, die je eine
   Ziffer zusammenhaelt.

   GEMESSEN: 34rem sind 67 Zeichen je Zeile, 42rem sind 84, 46rem waeren
   93. Bei 42rem bleibt auch nach Abzug der Ziffernspalte genug Zeile,
   ohne dass der Rueckweg zum Zeilenanfang zu weit wird.

   Erst ab 1000px: Darunter ist die Spalte ohnehin schmaler als 42rem,
   und die Regel liefe leer. */
@media (min-width: 1000px) {
  .vertragstext .infoabschnitt p,
  .vertragstext .regelliste,
  .vertragstext .stufen { max-width: 42rem; }
}

/* Bildraster nach dem Entwurf des Owners (30.09.2026): Bild oben, sein
   Text darunter, zwei Zellen nebeneinander. Auf dem Telefon eine Spalte.
   Die Media Query steht HINTER der Grundregel – davor verliert sie bei
   gleicher Spezifitaet. */
.bilder {
  margin: 16px 0 0;
  display: grid;
  gap: var(--abstand);
  grid-template-columns: 1fr;
}
@media (min-width: 1000px) {
  .bilder {
    grid-template-columns: 1fr 1fr;
    align-items: start;
    gap: 24px;
  }
}
/* Entwurfsbanner ueber einem Rechtstext. Auffaellig genug, dass niemand
   die Seite fuer geltend haelt. */
.entwurfsbanner {
  margin: 0 0 24px;
  max-width: 46rem;
  padding: 12px 16px;
  background: #fdf3e3;
  border-left: 4px solid #d69e00;
  font-size: 15px;
  line-height: 1.5;
}

/* Das Fassungsdatum unter dem Vertragstext – leise, aber auffindbar.
   Ziffer 1.2 und 12 machen es zur massgebenden Angabe: Welche Fassung
   galt, entscheidet im Streitfall. */
.fassung {
  margin-top: 4px;
  font-size: 12px;
  font-weight: 300;
  color: var(--grau-text);
}

.regelliste {
  max-width: 34rem;
  margin: 8px 0 0;
  padding-left: 20px;
  font-size: 16px;
  font-weight: 300;
  line-height: 1.6;
}
.regelliste li { margin-top: 6px; }
.infoabschnitt h3 {
  font-size: 16px;
  font-weight: 600;
  margin: 16px 0 0;
}

/* ---------- Pro-Konfigurator ---------- */

/* Drei Zonen nebeneinander, wie in der Vorlage des Owners: Kacheln,
   Regler, grosse Vorschau. Das Raster schrumpft mit, statt an einem
   Haltepunkt umzuklappen – `auto` fuer die Kacheln, `minmax` fuer den
   Regler, der Rest fuer die Vorschau. So traegt EINE Regel von 680 px
   aufwaerts; eine feste Dreispaltenregel ab 1000 px liess alles darunter
   untereinanderfallen und den Konfigurator mannshoch werden (gesehen bei
   871 px, 01.10.2026). */
.konfigurator {
  margin: 16px 0 0;
  display: grid;
  /* Die Vorschau ist GENAU so breit wie eine Spalte des Bildrasters
     darueber – dieselbe Formel wie `.bilder` (1fr 1fr mit 24px Lücke),
     deshalb steht sie in derselben rechten Kante und beginnt an
     derselben Mittelfuge. Vorher stand hier `1.4fr`: das verteilte den
     Rest nach Anteil und machte die Vorschau 574 statt 532 breit
     (gemessen bei 1440px Fenster, 02.10.2026) – 42px, die das Auge als
     Bruch in der Spaltenkante liest.
     Die `minmax`-Untergrenze bleibt: schrumpft das Fenster, gibt die
     Vorschau nach, statt das Raster zu sprengen. */
  grid-template-columns:
    auto
    minmax(190px, 1fr)
    minmax(260px, calc((100% - 24px) / 2));
  grid-template-areas: "duktus regler vorschau";
  gap: 20px;
  align-items: start;
}
.duktuswahl  { grid-area: duktus; }
.staerkewahl { grid-area: regler; }
.konfvorschau { grid-area: vorschau; }

@media (max-width: 679px) {
  /* Darunter reicht die Breite fuer drei Zonen nicht: Kacheln und Regler
     nebeneinander, die Vorschau darunter ueber die ganze Breite. */
  .konfigurator {
    grid-template-columns: auto 1fr;
    grid-template-areas:
      "duktus regler"
      "vorschau vorschau";
    gap: 14px 16px;
  }
}
@media (max-width: 439px) {
  .konfigurator {
    grid-template-columns: 1fr;
    grid-template-areas: "duktus" "regler" "vorschau";
  }
}

.duktuswahl {
  display: grid;
  grid-template-columns: repeat(3, 72px);
  gap: 6px;
}
.duktus {
  appearance: none;
  border: 2px solid transparent;
  background: var(--grau);
  padding: 0;
  cursor: pointer;
  display: block;
  width: 72px;
}
/* Die Kachel zeigt einen AUSSCHNITT, nicht das ganze Piktogramm: bei 72 px
   ist eine komplette Teetasse nicht lesbar, und erkennbar sein soll der
   DUKTUS. In der Vorgabe steht hier ein Pinselstrich; solange der nicht
   als Datei vorliegt, ist der vergroesserte Bogen die naechstbeste
   Auskunft. */
.duktus .kachelbild { display: block; aspect-ratio: 1; overflow: hidden; }
.duktus .kachelbild img {
  display: block;
  width: 100%;
  height: auto;
  transform: scale(2.4);
  transform-origin: 42% 56%;
}
.duktus .fehlt { display: block; width: 100%; aspect-ratio: 1; }
.duktus .duktusname {
  display: block;
  font-size: 9px;
  line-height: 1.2;
  padding: 2px 3px 3px;
  color: var(--grau-text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.duktus[aria-checked="true"] { border-color: var(--blau-flaeche); }
.duktus[aria-checked="true"] .duktusname { color: var(--blau-schrift); }

.endewahl { display: flex; gap: 6px; margin-bottom: 14px; }
.ende {
  appearance: none;
  border: 1px solid var(--grau-linie);
  background: var(--weiss);
  font: inherit;
  font-size: 13px;
  padding: 4px 12px;
  cursor: pointer;
  color: var(--grau-text);
}
.ende[aria-checked="true"] {
  border-color: var(--blau-flaeche);
  color: var(--blau-schrift);
  font-weight: 600;
}
/* Gesperrt, wenn der Duktus dieses Ende nicht fuehrt (Kreide, Pinsel:
   nur eckig). Der Grund steht im title. */
.ende:disabled {
  cursor: not-allowed;
  color: var(--grau-linie);
  border-style: dashed;
}

.staerkelabel {
  display: block;
  font-size: 13px;
  color: var(--grau-text);
  margin-bottom: 6px;
}
/* Der Schieber trug bis 02.10.2026 Chromes Standardblau (#0075ff) – es
   gab schlicht keine Regel dafür, und zwischen den eigenen Blautönen fiel
   es auf. Jetzt das SCHRIFTBLAU (Owner-Vorgabe): Der Schieber ist ein
   Bedienelement, kein Farbfeld. */
.staerkewahl input[type="range"] {
  width: 100%;
  display: block;
  accent-color: var(--blau-schrift);
}
.staerkeskala {
  display: flex;
  justify-content: space-between;
  font-size: 11px;
  color: var(--grau-text);
  font-variant-numeric: tabular-nums;
  margin-top: 2px;
}

.konfvorschau { margin: 0; background: var(--grau); }
.konfvorschau img {
  display: block;
  width: 100%;
  height: auto;
  /* 3:2 statt quadratisch (Owner 02.10.2026): NUR DAS FELD wird
     niedriger, das Piktogramm bleibt gleich gross. Deshalb `cover` und
     nicht `contain` – `contain` haette das Motiv auf zwei Drittel
     geschrumpft, und genau das soll nicht passieren.

     Dass das traegt, ist gemessen und keine Hoffnung: Das Motiv belegt
     im Muster nur 39% der Bildhoehe (y 346..736 von 1001). `cover`
     schneidet oben und unten je ein Sechstel weg, sichtbar bleibt
     y 167..834 – reiner Weissraum. Ein Piktogramm, das hoeher steht als
     zwei Drittel des Felds, wuerde hier allerdings angeschnitten; das
     gilt es beim naechsten Muster nachzumessen. */
  aspect-ratio: 3 / 2;
  object-fit: cover;
  object-position: center;
}
.konfvorschau figcaption {
  font-size: 13px;
  color: var(--grau-text);
  padding: 6px 0 0;
  background: none;
}
.konfvorschau figcaption.fehlt { color: #b1281f; }

/* Ab 680 px: Die grosse Vorschau ist QUADRATISCH und genau so hoch wie das
   Musterraster links (Owner 05.10.2026) – Oberkante buendig mit der
   obersten, Unterkante mit der untersten Musterkachel. Das ersetzt das
   3:2-Feld vom 02.10.
   Die Hoehe kommt aus dem Raster, nicht aus einem Pixelwert: Mit jeder
   neuen Duktus-Variante waechst es um eine Zeile. Deshalb steht das Bild
   ABSOLUT in der gestreckten Rasterzelle – im Fluss wuerde es mit seinen
   1000 px Eigenhoehe die Zeile selbst bestimmen, und `height: 100%` waere
   ein Zirkel. So traegt allein das Musterraster die Zeilenhoehe, das Bild
   nimmt sie mit `height: 100%` ab und leitet die Breite aus
   `aspect-ratio: 1` ab. Es beginnt links an der Mittelfuge, wie zuvor.
   Die Bildunterschrift haengt darunter; den Platz dafuer haelt der
   Abstand unten am Konfigurator frei.
   Zwischen 680 und 899 px reicht die Breite nicht fuer drei Zonen PLUS
   ein Quadrat in Rasterhoehe (gemessen 05.10.2026: bei 800 px ragte es
   59 px ueber den Rand). Dort steht der Regler unter dem Musterraster,
   die Vorschau daneben. `max-width: 100%` ist die Notbremse, falls das
   Raster einmal so hoch wird, dass auch das nicht reicht: dann lieber
   angeschnitten als quer scrollend. */
@media (min-width: 680px) and (max-width: 899px) {
  .konfigurator {
    grid-template-columns: auto 1fr;
    grid-template-areas:
      "duktus vorschau"
      "regler .";
  }
}
@media (min-width: 680px) {
  .konfigurator { margin-bottom: 26px; }
  .konfvorschau {
    align-self: stretch;
    position: relative;
    background: none;
    min-height: 0;
  }
  .konfvorschau img {
    position: absolute;
    top: 0;
    left: 0;
    height: 100%;
    width: auto;
    max-width: 100%;
    aspect-ratio: 1;
    background: var(--grau);
  }
  .konfvorschau figcaption {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
  }
}

.konfigurator-leer {
  margin: 16px 0 0;
  max-width: 34rem;
  background: var(--grau);
  padding: 14px 16px;
  font-size: 14px;
  line-height: 1.5;
}
.konfigurator-leer p { margin: 0; }
.konfigurator-leer code { font-size: 13px; }

/* Lizenzstufen: Begriff und Erklaerung, kein Aufzaehlungspunkt. */
.stufen {
  margin: 12px 0 0;
  max-width: 34rem;
}
.stufen dt {
  font-weight: 600;
  font-size: 16px;
  margin-top: 12px;
}
.stufen dd {
  margin: 2px 0 0;
  font-size: 16px;
  font-weight: 300;
  line-height: 1.6;
}
/* Traegt der Begriff eine Ziffer, rueckt die Erklaerung darunter um
   dieselbe Spalte ein – sonst begaenne sie unter der Ziffer statt unter
   dem Begriff, zu dem sie gehoert. Der Geschwisterselektor greift genau
   dann, wenn `_mit_nr` dem <dt> die Klasse gegeben hat. */
.stufen dt.ziffer + dd { margin-left: 2.5rem; }

/* Abschnitt mit GENAU EINEM Bild: Text links, Bild rechts daneben.
   Erst ab der Rasterbreite – darunter bleibt alles gestapelt. */
@media (min-width: 1000px) {
  .einbild {
    display: grid;
    grid-template-columns: 1fr 1fr;
    column-gap: 24px;
    align-items: start;
  }
  .einbild > h2 { grid-column: 1 / -1; }
  /* In der halben Spalte ist nur Platz fuer EIN Bild – das innere Raster
     muss hier einspaltig werden, sonst belegt das Bild nur die Haelfte
     der Haelfte. */
  .einbild > .bilder {
    margin-top: 0;
    grid-template-columns: 1fr;
  }
}
.textspalte { display: contents; }
@media (min-width: 1000px) {
  .einbild > .textspalte { display: block; }
}

/* Abschnitt mit zwei Bildern: der Text darueber nutzt die ganze Zeile.
   Nur dort – wo kein Bild danebensteht, bleibt die Lesebreite bindend. */
@media (min-width: 1000px) {
  .breittext > .textspalte > p { max-width: none; }
}

.bildzelle { margin: 0; }
.bildzelle img { display: block; width: 100%; height: auto; }
.bildtext {
  display: block;
  font-size: 15px;
  font-weight: 300;
  line-height: 1.5;
  margin: 8px 0 0;
}

/* Platzhalter, solange die Datei fehlt. Eckig wie alles hier (Owner
   28.09.2026: keine Abrundungen) und bewusst sichtbar. */
.bild-fehlt {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 170px;
  padding: 20px;
  background: var(--grau);
  border: 1px dashed var(--grau-linie);
  font-size: 13px;
  color: var(--grau-text);
  text-align: center;
  line-height: 1.45;
}

.weiter {
  margin: 16px 0 0;
  font-size: 16px;
}
.weiter a { color: var(--blau-schrift); }
.offen-hinweis {
  background: var(--grau);
  padding: 14px 16px;
  font-size: 13px;
  color: var(--grau-text);
  line-height: 1.45;
}

/* ---------- Fuss ---------- */

.fuss {
  border-top: 1px solid var(--grau-linie);
  padding-top: 16px;
  padding-bottom: 40px;
  font-size: 12px;
  color: var(--grau-text);
}

/* Der Impressum-Link im Fuss: zurueckhaltend in der Farbe des Fusses,
   unterstrichen nur beim Ueberfahren – wie das Menue. */
.fuss a { color: inherit; text-decoration: none; }
.fuss a:hover { color: var(--blau-schrift); text-decoration: underline; }

/* Auf dem Telefon ist Höhe das knappe Gut, und die Kacheln sind
   unantastbar quadratisch. Der Platz kommt deshalb aus Kopf und Hero –
   dort kostet er nichts: 210 px für sechs Textzeilen waren grosszügig,
   und das Logo braucht keine 28 px Luft nach oben und unten.

   Was damit NICHT erreicht wird: die Teaser in den ersten Bildschirm zu
   holen. Mit drei quadratischen Spalten beginnen sie bei rund 800 px, ein
   iPhone zeigt 724 px. Das ist in Ordnung – auf einer Startseite scrollt
   man, und die Kacheln sind das Produkt. Wer sie kleiner macht, damit ein
   Teaser hineinpasst, tauscht das Wichtige gegen das Zweitwichtige. */
@media (max-width: 699px) {
  .kopf {
    padding-top: 20px;
    padding-bottom: 18px;
  }
  .marke img { height: 30px; }

  .hero {
    /* EINE Höhe überall, wo der Block steht – Start, Katalog, Suche
       (Owner-Vorgabe 28.09.2026); seit 07.10.2026 189 px statt 174 px
       (Owner). Auch dort, wo er leer ist. Ein zweizeiliger Hinweis bräuchte
       194 px (gemessen 07.10.) – der Text bleibt deshalb kurz. */
    min-height: 189px;
    padding: 20px;
    font-size: 16px;
    line-height: 1.4;
  }
  .hero .hero-hinweis { margin-top: 5px; font-size: 13px; line-height: 17.4px; }

  .familien { margin-top: 24px; }
  .teaser { margin-top: 24px; }
  .teaser article { font-size: 20px; padding: 18px 20px 22px; }
}

.visuell-versteckt {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* ---------- Warenkorb ---------- */

/* Dieselbe Breite wie die Piktogrammseite (--breite, über `main` geerbt) –
   Owner-Vorgabe 29.09.2026. Mein erster Entwurf war schmaler, mit dem
   Argument "hier wird geprüft, nicht gestöbert"; das zerschneidet aber den
   Weg: Der Kunde kommt aus dem Katalog, und ein springender Satzspiegel
   lässt den Korb wie eine fremde Seite wirken. Die Formulare weiter unten
   bleiben schmal – das ist Zeilenlänge im Eingabefeld, nicht Satzspiegel. */
.warenkorb {
  padding-top: 30px;
  padding-bottom: 70px;
}
.warenkorb h1 {
  font-size: 30px;
  font-weight: 600;
  color: var(--blau-schrift);
  margin: 0 0 24px;
  line-height: 1.2;
}
.korb-laedt { color: var(--grau-text); font-weight: 300; }

.korb-leer { color: var(--grau-text); font-weight: 300; }
.korb-leer .btn {
  width: auto;
  display: inline-block;
  text-decoration: none;
  margin-top: 6px;
}

/* Die sechs Schritte tragen dieselbe Linie wie die Infoabschnitte – es ist
   dieselbe Gliederungsebene und darf nicht wie eine zweite Sprache wirken. */
.korb-schritt {
  border-top: 1px solid var(--grau-linie);
  padding-top: 14px;
  margin-bottom: 30px;
}
.korb-schritt h2 {
  display: flex;
  align-items: baseline;
  gap: 10px;
  font-size: 17px;
  font-weight: 600;
  color: var(--schwarz);
  margin: 0 0 10px;
}
/* Die Schrittzahl führt durch den Ablauf, ohne ihn zu dominieren: Sie ist
   Orientierung, nicht Inhalt. */
.schrittzahl {
  font-weight: 300;
  color: var(--grau-text);
  font-variant-numeric: tabular-nums;
}
.schrittzahl-rechts {
  margin-left: auto;
  font-weight: 300;
  font-variant-numeric: tabular-nums;
  color: var(--grau-text);
}

.korb-hinweis {
  font-size: 12px;
  font-weight: 300;
  line-height: 1.4;
  color: var(--grau-text);
  margin: 0 0 12px;
}
.korb-hinweis a { color: var(--blau-schrift); text-decoration: none; }
.korb-hinweis a:hover { text-decoration: underline; }

/* Ein weggefallenes Piktogramm ist keine Randnotiz: Ohne sichtbare Warnung
   sucht der Kunde den Fehler bei sich. */
.korb-warnung {
  font-size: 12px;
  line-height: 1.4;
  color: var(--schwarz);
  background: var(--grau);
  border-left: 3px solid var(--blau-flaeche);
  padding: 8px 10px;
  margin: 0 0 12px;
}

/* ---------- Kacheln im Korb ---------- */

/* ≈72 px statt der 120 px des Katalogs: Im Korb wird geprüft, und 22 Stück
   sollen ohne Scrollen in zwei Reihen stehen. Der Deckel bei 88 px
   verhindert, dass wenige Positionen auf breitem Schirm aufgeblasen werden. */
.korbkacheln {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(72px, 88px));
  gap: var(--abstand);
}
.korbkachel {
  position: relative;
  min-width: 0;
}
.korbkachel .bild {
  background: var(--grau);
  aspect-ratio: 1 / 1;      /* quadratisch und eckig, wie überall */
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  font-weight: 300;
  color: var(--blau-schrift);
}
/* 9 px, kleiner als im Katalog: Kontrolliert wird am BILD (Owner
   29.09.2026) – der Name ist die Stütze für den Zweifelsfall und den
   Screenreader, nicht das Führende. Er darf deshalb leiser sein als die
   Kachel selbst. */
.korbkachel .beschriftung {
  display: block;
  margin-top: 4px;
  font-size: 9px;
  line-height: 1.3;
}
/* Der Name MUSS hier stehen – im Korb kontrolliert man eine Liste, und
   dafür braucht es Wörter (Spec). Zwei Zeilen, dann abgeschnitten: Sonst
   stehen die Kacheln je nach Namenslänge auf verschiedener Höhe. */
.korbkachel .name {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  font-weight: 600;
  /* Ohne das schneidet "Gepäckschliessfach" mitten im Wort ab: Ein langes
     Wort ohne Trennstelle passt in keine 72-px-Zeile, bricht nicht um und
     läuft in den overflow. So bricht es hart um und die zweite Zeile wird
     benutzt, für die der Platz ohnehin reserviert ist. */
  overflow-wrap: anywhere;
}
.korbkachel .code {
  display: block;
  font-weight: 300;
  color: var(--grau-text);
  font-variant-numeric: tabular-nums;
}

/* Entfernen sitzt AN der Kachel, nicht in einer Aktionsspalte: Die Spec
   verlangt es dort, und bei 72 px ist der Weg zur Zeile sonst weiter als
   zum Ziel. */
.entfernen {
  position: absolute;
  top: 0;
  right: 0;
  width: 20px;
  height: 20px;
  line-height: 18px;
  text-align: center;
  font-size: 15px;
  font-weight: 300;
  color: var(--weiss);
  background: var(--schwarz);
  border: 0;
  padding: 0;
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.12s;
}
.korbkachel:hover .entfernen,
.entfernen:focus-visible { opacity: 1; }
/* Auf dem Telefon gibt es kein Hover – dort steht das Kreuz immer. */
@media (hover: none) {
  .entfernen { opacity: 1; }
}

/* Der Schalter, der die Einzelauswahl überhaupt erst einblendet. Als
   Textknopf, nicht als Kasten: Er ist eine Nebentür und soll die
   Kachelreihe nicht anführen. */
.einzelzeile { margin: 0 0 10px; }
.einzelschalter {
  font: inherit;
  font-size: 12px;
  font-weight: 300;
  color: var(--blau-schrift);
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  text-align: left;
}
.einzelschalter:hover { text-decoration: underline; }
.einzelschalter[aria-pressed="true"] { font-weight: 600; }

/* Abweichende Variante je Position: normalerweise GAR NICHT da. Sie
   erscheint, wenn der Schalter oben an ist – oder wenn diese eine Position
   abweicht, denn eine getroffene Entscheidung darf nie unsichtbar werden,
   auch nicht nach dem Ausschalten.

   Ein- und ausgeblendet wird über DIESELBE Struktur, nur die Klasse
   schaltet: Zwei verschiedene Markup-Formen für zwei Zustände haben hier
   schon zweimal Farbfehler erzeugt. */
.positionsvariante {
  display: block;
  width: 100%;
  margin-top: 3px;
  font: inherit;
  font-size: 9px;
  font-weight: 300;
  text-align: left;
  color: var(--grau-text);
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  visibility: hidden;   /* nicht `display:none` – die Kachelhöhe bleibt gleich */
}
.korbkacheln.einzeln .positionsvariante,
.positionsvariante.abweichend { visibility: visible; }
.positionsvariante:hover { color: var(--blau-schrift); }
.positionsvariante.abweichend {
  font-weight: 600;
  color: var(--blau-schrift);
}

/* ---------- Variante und Verwendung ---------- */

.wahl {
  display: grid;
  gap: var(--abstand);
  grid-template-columns: 1fr;
}
@media (min-width: 700px) {
  .wahl { grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
}
.wahlfeld {
  display: block;
  position: relative;
  padding: 12px 14px;
  background: var(--grau);
  border: 1px solid transparent;   /* eckig, kein Radius */
  cursor: pointer;
}
.wahlfeld:hover { border-color: var(--grau-linie); }
/* :has trägt hier: Fällt es aus (alte Browser), bleibt das Feld nur ohne
   Rahmen – die Radiobutton selbst zeigt den Zustand weiterhin an. */
.wahlfeld:has(input:checked) {
  border-color: var(--blau-flaeche);
  background: var(--weiss);
}
.wahlfeld:has(input:focus-visible) {
  outline: 2px solid var(--blau-flaeche);
  outline-offset: 2px;
}
/* Dasselbe wie beim Schieber: Bedienelemente tragen das SCHRIFTBLAU.
   Meine automatische Umstellung hatte `accent-color` zu den Flächen
   gezählt – es ist aber weder Fläche noch Schrift, sondern ein drittes,
   und der Owner hat es für den Schieber entschieden. Hier mitgezogen,
   damit Schieber und Auswahlknöpfe nicht in zwei Blautönen stehen. */
.wahlfeld input { margin-right: 6px; accent-color: var(--blau-schrift); }
.wahltitel { font-weight: 600; font-size: 14px; }
.wahltext {
  display: block;
  margin-top: 4px;
  font-size: 12px;
  font-weight: 300;
  line-height: 1.4;
  color: var(--grau-text);
}
.wahlpreis {
  display: block;
  margin-top: 8px;
  font-size: 12px;
  font-weight: 600;
  color: var(--blau-schrift);
  font-variant-numeric: tabular-nums;
}

/* ---------- Preis ---------- */

.preistabelle {
  width: 100%;
  border-collapse: collapse;
  font-size: 14px;
}
.preistabelle th,
.preistabelle td {
  text-align: left;
  padding: 7px 0;
  font-weight: 300;
  border-bottom: 1px solid var(--grau-linie);
}
.preistabelle th { font-weight: 600; }
/* Zahlen rechtsbündig mit tabular-nums: untereinander stehende Beträge,
   die nicht fluchten, liest diese Zielgruppe als Schlamperei. */
.preistabelle .stueck,
.preistabelle .betrag {
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.preistabelle .stueck { color: var(--grau-text); font-size: 12px; }
.preistabelle .summe th,
.preistabelle .summe td {
  font-weight: 600;
  border-bottom: 0;
  border-top: 1px solid var(--schwarz);
  padding-top: 9px;
}
.preis-fuss {
  font-size: 11px;
  font-weight: 300;
  color: var(--grau-text);
  margin: 8px 0 0;
}

/* ---------- Adresse und Anfrage ---------- */

.adressformular,
.anfrageformular {
  display: grid;
  gap: 10px var(--abstand);
  grid-template-columns: 1fr;
  max-width: 34em;
}
@media (min-width: 700px) {
  .adressformular { grid-template-columns: 1fr 1fr; }
  .feld-schmal { max-width: 8em; }
  .feld-breit { grid-column: 1 / -1; }
}
.feld { margin: 0; display: flex; flex-direction: column; }
/* `display: flex` schlägt das `hidden`-Attribut – das USt-IdNr.-Feld
   erscheint nur für EU-Länder und muss sonst wirklich weg sein. */
.feld[hidden] { display: none; }
.feld label {
  font-size: 12px;
  font-weight: 600;
  margin-bottom: 3px;
}
/* Der Punkt markiert Pflichtfelder. Ein Sternchen liest sich als Fussnote
   und braucht eine Legende, die sonst nirgends steht. */
.pflicht { color: var(--blau-schrift); }
/* type fehlt bei keinem Feld – ein <input> ohne type fällt durch diese
   Regel und steht dann in der Browsergrundoptik. */
.feld input,
.feld select,
.feld textarea {
  font: inherit;
  font-size: 14px;
  font-weight: 300;
  padding: 7px 9px;
  border: 1px solid var(--grau-linie);
  background: var(--weiss);
  color: var(--schwarz);
  min-width: 0;
}
.feld input:focus,
.feld select:focus,
.feld textarea:focus {
  outline: 2px solid var(--blau-flaeche);
  outline-offset: -1px;
  border-color: var(--blau-flaeche);
}
.feldhilfe {
  font-size: 11px;
  font-weight: 300;
  color: var(--grau-text);
  margin-top: 3px;
}
.anfrageformular { grid-template-columns: 1fr; }
.anfrageformular textarea { resize: vertical; }

/* Die Abzweigung für Weiterverkauf: deutlich abgesetzt, weil sie den
   Kaufweg ERSETZT und nicht ergänzt. */
.korb-anfrage {
  border-top: 1px solid var(--grau-linie);
  padding-top: 14px;
  margin-bottom: 30px;
}
.korb-anfrage h2 {
  font-size: 17px;
  font-weight: 600;
  margin: 0 0 8px;
  color: var(--blau-schrift);
}
.korb-anfrage > p {
  font-size: 14px;
  font-weight: 300;
  line-height: 1.5;
  max-width: 40em;
  margin: 0 0 16px;
}
.korb-anfrage .btn { width: auto; }

.btn-gross { width: auto; padding: 12px 22px; font-size: 15px; }
.btn:disabled {
  background: var(--grau-linie);
  color: var(--weiss);
  cursor: not-allowed;
}
.btn:disabled:hover { background: var(--grau-linie); }

/* ---------- Abschlussseite ---------- */

.bestellseite h1 {
  font-size: 26px;
  margin-bottom: 8px;
}
.lead-bestellung {
  font-size: 16px;
  font-weight: 300;
  line-height: 1.5;
  color: var(--blau-schrift);
  margin: 0 0 30px;
  max-width: 44em;
}

/* Der Beleg ist eine Liste von Angaben, keine Rechnung mit Beträgen –
   deshalb linksbündig und ohne die Zahlenausrichtung der Preistabelle. */
.belegtabelle {
  border-collapse: collapse;
  font-size: 14px;
  max-width: 44em;
}
.belegtabelle th,
.belegtabelle td {
  text-align: left;
  vertical-align: top;
  padding: 5px 0;
  font-weight: 300;
}
.belegtabelle th {
  font-weight: 600;
  width: 11em;
  padding-right: var(--abstand);
}

/* Die Kacheln der Abschlussseite sind nicht bedienbar: kein Entfernen,
   kein Umschalten. Was gekauft ist, ist gekauft. */
.bestellseite .korbkachel { cursor: default; }

/* ---------- Zustimmungen vor der Kasse ---------- */

/* Die beiden Häkchen stehen zwischen Zahlungsart und Knopf – an der
   letzten Stelle, an der man sie noch liest. Weiter oben gingen sie im
   Durchklicken unter, und gerade diese zwei dürfen das nicht: Das eine
   nimmt die Bedingungen an, das andere lässt das Widerrufsrecht
   erlöschen. */
/* OHNE Streifen an der linken Kante (Owner 04.10.2026: «die schwarze Linie
   vor dem grauen Feld wird nicht benötigt»). Die graue Fläche grenzt den
   Block schon ab; der Streifen hätte zusätzlich den Zustand angezeigt, und
   das tut der Bestellknopf darunter ohnehin – grau, solange ein Häkchen
   fehlt. Zwei Anzeigen für denselben Zustand sind eine zu viel. */
.korb-zustimmung {
  margin: 14px 0 12px;
  padding: 12px 14px;
  background: var(--grau);
}

.zustimmzeile {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  font-size: 12px;
  font-weight: 300;
  line-height: 1.45;
  color: var(--schwarz);
  cursor: pointer;
}
.zustimmzeile + .zustimmzeile { margin-top: 10px; }
/* `margin-top` statt `align-items: center`: Die zweite Zeile ist drei
   Zeilen hoch, und ein mittig gesetztes Kästchen stünde dort irgendwo im
   Text. Der Wert hebt es auf die erste Grundlinie. */
.zustimmzeile input {
  flex: 0 0 auto;
  margin: 2px 0 0;
  accent-color: var(--blau-schrift);
}
.zustimmzeile a { color: var(--blau-schrift); text-decoration: underline; }

/* Das freiwillige Häkchen für Hinweise auf neue Piktogramme, am Ende des
   Adressformulars. Ohne graue Fläche: Es gehört NICHT zu den zwei
   Pflicht-Zustimmungen, und es soll auch nicht so aussehen. */
.einwilligung { margin-top: 4px; }
.einwilligung .feldhilfe { display: block; }

.kassezeile { margin: 14px 0 8px; }

/* Der gesperrte Bestellknopf. Ohne eigenen Zustand sähe er aus wie der
   freie, und der Kunde klickte ins Leere, ohne zu erfahren, woran es
   liegt. `not-allowed` zeigt es am Zeiger, die Fläche am Kontrast. */
.btn:disabled,
.btn:disabled:hover {
  background: var(--grau-linie);
  color: var(--weiss);
  cursor: not-allowed;
}

/* ---------- Umgebungs-Kennzeichnung ---------- */

/* Übernommen aus der Auftragsverwaltung (`--env-lokal-bg`,
   `--env-staging-bg`), Werte unverändert: Dieselbe Farbe muss in beiden
   Werkzeugen dasselbe heissen, sonst ist sie schlechter als keine.

     lokal (dieser Mac) → rot
     Staging            → gelb
     Produktion         → KEINE Hinterlegung – der Normalfall bleibt ruhig

   Kräftiger als eine übliche Warnfläche, weil eine ganze Leiste sonst wie
   ein Rendering-Fehler wirkt statt wie eine Warnung. */
:root {
  --env-lokal-bg: rgba(177, 40, 31, 0.16);
  --env-staging-bg: rgba(214, 158, 0, 0.24);
}

body[data-umgebung="lokal"] .kopf   { background: var(--env-lokal-bg); }
body[data-umgebung="staging"] .kopf { background: var(--env-staging-bg); }

/* Die Kopfzeile ist zentriert und schmaler als das Fenster – ohne das
   endet die Farbe mitten im Bild und sieht nach Fehler aus. Der Streifen
   läuft deshalb über die volle Breite. */
body[data-umgebung="lokal"] .kopf,
body[data-umgebung="staging"] .kopf {
  box-shadow: -50vw 0 0 var(--env-farbe), 50vw 0 0 var(--env-farbe);
}
body[data-umgebung="lokal"]   { --env-farbe: var(--env-lokal-bg); }
body[data-umgebung="staging"] { --env-farbe: var(--env-staging-bg); }

/* Das Wort stand hier bis 29.09.2026 neben dem Logo und ist auf
   Owner-Wunsch weg: Der Farbcode ist eingeführt und eindeutig, das Wort
   war Doppelung. Für Screenreader trägt `title` am <body> (kopf.js) – die
   Farbe allein wäre dort keine Aussage. */

/* ---------- Fehlendes Piktogramm melden ---------- */

/* Der Block unter einer ergebnislosen Suche. Er steht IM Trefferbereich,
   nicht in der Filterspalte: Wer nichts gefunden hat, schaut dorthin, wo
   die Treffer stehen müssten. */
.wunschhinweis {
  margin: 4px 0 0;
  padding: 18px 20px;
  background: var(--grau);
  max-width: 34rem;
}
.wunschhinweis p { margin: 0; font-size: 15px; font-weight: 300; line-height: 1.55; }
.wunschhinweis p + p { margin-top: 14px; }

.wunschseite { padding-bottom: 60px; }
.wunschform {
  margin: 26px 0 0;
  max-width: 34rem;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.wunschform label {
  font-size: 12px;
  font-weight: 600;
  margin-top: 14px;
}
.wunschform label:first-of-type { margin-top: 0; }
/* `input` UND `textarea` ausdrücklich: Ein Feld ohne eigene Regel fällt in
   die Browser-Grundoptik und steht dann sichtbar neben den anderen. */
.wunschform input[type="text"],
.wunschform input[type="email"],
.wunschform textarea {
  font: 300 15px var(--schrift);
  padding: 9px 10px;
  border: 1px solid var(--grau-linie);
  background: var(--weiss);
  color: var(--schwarz);
  width: 100%;
}
.wunschform textarea { resize: vertical; min-height: 72px; line-height: 1.5; }
.wunschform input:focus-visible,
.wunschform textarea:focus-visible {
  outline: 2px solid var(--blau-flaeche);
  outline-offset: 1px;
  border-color: var(--blau-flaeche);
}
.wunschform .btn { margin-top: 22px; align-self: flex-start; }
.freiwillig { font-weight: 300; color: var(--grau-text); }
.wunschform .hinweis {
  margin: 5px 0 0;
  font-size: 12px;
  font-weight: 300;
  color: var(--grau-text);
  line-height: 1.45;
}

/* Honigtopf: für Menschen unsichtbar, für automatische Ausfüller nicht.
   NICHT `display: none` – manche Ausfüller überspringen, was so markiert
   ist, und dann fängt die Falle nichts. Aus dem Lesefluss und aus der
   Tastaturreihenfolge ist das Feld trotzdem heraus (`tabindex="-1"`,
   `aria-hidden` im Markup). */
.honigtopf {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.formfehler {
  margin: 12px 0 0;
  padding: 10px 12px;
  background: #fdecea;
  border-left: 4px solid #b1281f;
  font-size: 14px;
  line-height: 1.45;
}
.kleingedruckt {
  margin: 28px 0 0;
  max-width: 34rem;
  font-size: 13px;
  font-weight: 300;
  line-height: 1.55;
  color: var(--grau-text);
}
.wunschdank {
  margin: 26px 0 0;
  max-width: 34rem;
  padding: 20px 22px;
  background: var(--grau);
}
.wunschdank h2 { margin: 0 0 8px; font-size: 17px; font-weight: 600; }
.wunschdank p { margin: 0 0 8px; font-size: 15px; font-weight: 300; line-height: 1.55; }

/* Der Pfeil im Suchknopf ist GEZEICHNET, nicht gesetzt. Vorher stand dort
   das Unicode-Zeichen ⟶ (U+27F6) – das widersprach der eigenen Regel
   («Jedes Symbol in der Oberfläche kommt aus der eigenen Serie. Kein
   Unicode-Emoji: Es wird auf jeder Plattform anders gezeichnet») und sah
   je nach Schrift anders aus.

   DIE MASSE STAMMEN AUS DER KONSTRUKTIONSDATEI, nicht aus einem
   Bildschirmfoto (04.10.2026). Der Owner führt den Pfeil in
   `d.picto.ai`, oberste Ebene «Logo», als vier gefüllte Flächen: den
   Schaft (36 × 3) und zwei um 45° gedrehte Rechtecke (je 15 × 3), dazu
   den Rahmen 60 × 32.

   Gefüllte Flächen, aber hier ein Strich-Pfad – deshalb muss aus den
   Rechtecken ihre MITTELLINIE zurückgerechnet werden (Mitte der kurzen
   Seiten). Die beiden Schenkelachsen schneiden sich bei (944,310 |
   8340,901), also exakt auf der Schaftachse; von dort sind beide
   Schenkel 13,500 lang und laufen auf 45,000°. Die Gehrung an der Spitze
   ergibt die Hülle 40,132 × 21,213 – die Datei misst 40,133 × 21,213.

   Die frühere Fassung war aus einem Bildschirmfoto nachgebaut und lag im
   Verhältnis nur 0,1 % daneben, in den Einzelmassen aber rund 2 %. Davor
   lag sie deutlicher falsch: Schenkel auf 39° statt 45°, Kopf 22 % statt
   28 % der Länge.

   Inline im Markup und nicht als <img>, damit `currentColor` greift: Ein
   SVG als <img> ist ein eigenes Dokument und erbt keine Farbe. So trägt
   der Pfeil immer die Schriftfarbe des Knopfs, auch beim Überfahren. */
.pfeil {
  display: block;
  /* Ueber die HOEHE bemessen, nicht ueber die Breite: Im Entwurf des
     Owners nimmt der Pfeil 53% der Knopfhoehe ein (156 von 296). Mit
     einer Breitenangabe geriet er auf 9px Hoehe und wirkte duenn,
     obwohl die Strichstaerke proportional stimmte.

     21px statt der frueheren 19: Die neue Form ist hoeher als die alte
     (Verhaeltnis 1,89 statt 2,38), und bei gleicher Hoehe waere der Pfeil
     um neun Pixel KUERZER geworden – ein Pfeil wirkt aber ueber seine
     Laenge. 21px halten die Laenge bei rund 40px und damit den Knopf in
     seiner Breite; die Knopfhoehe waechst um zwei Pixel. */
  height: 21px;
  width: auto;
  fill: none;
  stroke: currentColor;
  stroke-width: 3;
  /* Eckig, wie alles hier – runde Enden wären ein Fremdkörper neben
     Piktogrammen, die auf einem Raster konstruiert sind. */
  stroke-linecap: butt;
  stroke-linejoin: miter;
}

/* ---------- Kasse geschlossen in Produktion ---------- */

/* Owner 07.10.2026: «Wir sperren den Probeknopf, und es gibt keine
   Downloadfunktion, bis Stripe angeschlossen ist.»

   Entschieden wird am Server: `seiten.py` schreibt die Umgebung an den
   <body>, und dieselbe Umgebung sperrt in `zahlung.py` die Routen. Diese
   Regeln sind nur die Anzeige dazu – kein zweites Verfahren im Browser.

   `!important`, weil die Skripte `hidden` an diesen Blöcken umschalten
   (Weiterverkauf, bezahlt/offen); ein `hidden = false` darf den Kassen-
   knopf in Produktion nicht zurückholen. Der Hinweis selbst respektiert
   `hidden` – beim Weiterverkauf steht dort das Anfrageformular. */
[data-kasse-zu] { display: none; }
body[data-umgebung="produktion"] [data-kasse-zu]:not([hidden]) { display: block; }
body[data-umgebung="produktion"] [data-nur-mit-kasse] { display: none !important; }
