/* PrintSupport — Grundlagen: Reset, Grundtypografie, Fokus, Screenreader-Helfer
   und globale Bewegungsreduzierung. Seitengerüst (Kopfzeile/Navigation/Layout)
   liegt in layout.css. */

/* ---------- Schriften (02.09.2026) -----------------------------------

   ⛔ SELBST AUSGELIEFERT, KEINE FREMDQUELLE. Die CSP der Seite steht auf
   `default-src 'self'` (deploy/Caddyfile), und die Datenschutzerklärung
   sagt zu, dass beim Anzeigen keine Verbindung zu fremden Servern
   aufgebaut wird. Ein Google-Fonts-Verweis bräche beides zugleich — den
   einen sichtbar (die Schrift käme nicht), den anderen unsichtbar.

   Es sind VARIABLE FONTS mit voller Gewichtsachse: eine Datei je Familie
   statt vier Schnitten, zusammen 89 KB. Deshalb steht in font-weight eine
   Spanne und nicht eine Zahl — ohne sie synthetisiert der Browser den
   Fettdruck, statt die Achse zu benutzen (verzerrte Buchstaben).

   ⚠️ `font-display: swap`: Bis die Datei da ist, steht der Text in der
   Ersatzschrift (ui-serif/Georgia bzw. Consolas). Sichtbar ist dann ein
   Umsprung — unsichtbar wäre der Text selbst, und das ist schlechter.

   ⚠️ Der Zeichenvorrat ist auf Latin beschränkt und enthält Umlaute,
   Eszett und die typografischen Anführungszeichen des Projekts. Wer eine
   andere Sprache aufnimmt, braucht eine zweite Datei — die Ersatzschrift
   fängt fehlende Zeichen sonst zeichenweise ab (Mischsatz in einer Zeile).

   Beide Familien stehen unter der SIL Open Font License 1.1; die
   Lizenztexte liegen daneben unter /assets/fonts. */
@font-face {
  font-family: "Source Serif 4";
  src: url("/assets/fonts/source-serif-4-latin.woff2") format("woff2");
  font-weight: 200 900;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "JetBrains Mono";
  src: url("/assets/fonts/jetbrains-mono-latin.woff2") format("woff2");
  font-weight: 100 800;
  font-style: normal;
  font-display: swap;
}

*, *::before, *::after { box-sizing: border-box; }

html {
  height: 100%;
  /* Für Abschnitte, die über die Inhaltsspalte hinaus bis an die Fensterkante
     laufen (Kopfbereich der Startseite): Sie rechnen mit 100vw, und darin
     steckt die Breite des senkrechten Rollbalkens. Ohne diese Zeile ergäbe
     das einen waagerechten Rollbalken von rund 15px.

     Bewusst `clip` und nicht `hidden`: clip erzeugt keinen Scrollbereich.
     Mit `hidden` würde das <html> zum Scrollcontainer, und die klebende
     Kopfzeile verlöre ihren Halt. */
  overflow-x: clip;
}

body {
  margin: 0;
  min-height: 100%;
  font-family: var(--schrift);
  font-size: var(--body-large);
  line-height: var(--zeile-text);
  color: var(--on-background);
  background: var(--background);
  -webkit-font-smoothing: antialiased;
  /* ---------- Auffangnetz gegen unteilbare Zeichenfolgen ----------

     Ein Ordnername darf alles enthalten, auch 300 Zeichen ohne ein einziges
     Leerzeichen. Wo so etwas ausgegeben wird, lief es bis zum 08.08.2026 aus
     seinem Kasten heraus und gab dem Dokument einen waagerechten Rollbalken —
     zuerst aufgefallen an der Ordnerkachel des Merkzettels, möglich aber an
     jeder Stelle, die Freitext zeigt: Löschdialog, Ordnerwahl, Snackbar,
     Seitentitel eines Ordners.

     ⚠️ `break-word` und ausdrücklich NICHT `anywhere`: Diese Regel gilt der
     ganzen Seite, und `anywhere` ginge in die Mindestbreite JEDES Elements
     ein — das änderte Rasterspuren und Flex-Verteilungen an Stellen, die mit
     Freitext nichts zu tun haben. `break-word` greift ausschließlich dann,
     wenn ein Wort ohnehin nicht passt, und ist damit für alles andere
     wirkungslos. Wo die Mindestbreite mitsprechen MUSS, steht `anywhere`
     einzeln daneben (siehe `.ok-name` in css/seiten.css). */
  overflow-wrap: break-word;
}

h1, h2, h3, h4, p { margin: 0; }
button, input { font: inherit; color: inherit; }
img { max-width: 100%; display: block; }
a { color: var(--primary); }

/* ⛔ ÜBERSCHRIFTEN STEHEN SEIT DEM 02.09.2026 IN DER SERIFENSCHRIFT.
   Die frühere Regel lautete „Fettdruck ist allein dem preisProKg vorbehalten,
   Überschriften unterscheiden sich über GRÖSSE, nicht über Gewicht". Sie war
   die richtige Antwort auf eine Seite mit EINER Schriftfamilie: Dort war das
   Gewicht das einzige verfügbare Signal und musste deshalb knapp gehalten
   werden. Jetzt trägt der Familienwechsel die Auszeichnung — eine Serif in
   600 neben serifenlosem Fließtext ist als Überschrift erkennbar, ohne dem
   Preis etwas wegzunehmen. Der behält seine Sonderstellung über GRÖSSE und
   FARBE (bis 44px in --primary); beides hat sonst nichts auf der Seite.

   ⚠️ Die Größe von h1 WÄCHST MIT DEM FENSTER (34 → 44px). Die Vorlagen
   setzen den Seitentitel deutlich größer als die bisherigen 34px, aber auf
   320px Breite ist das nicht zu haben: „Datenschutzerklärung" misst dort
   schon bei 34px volle 328px und schob das Dokument über den Rand (deshalb
   das overflow-wrap darunter). clamp() löst beides — Handy unverändert 34px,
   ab rund 1200px die 44px der Vorlage.

   Enge Zeilen, weil große Schrift sonst auseinanderfällt. */
h1, h2, h3, h4 { font-family: var(--schrift-serif); }
/* ⚠️ overflow-wrap gehört an die Überschriften, nicht an einzelne Seiten.
   Deutsche Komposita sind lang, und eine Überschrift steht in der größten
   Schrift der Seite: „Datenschutzerklärung" ist bei 320px Bildschirmbreite
   allein 328px breit und schob das ganze Dokument 24px über den Rand. Ein
   Wort, das in keine Zeile passt, muss brechen dürfen — sonst bestimmt es
   die Breite der Seite. */
h1, h2, h3, h4 { overflow-wrap: break-word; }
h1 {
  font-size: clamp(var(--headline-large), 1.6rem + 1.6vw, var(--display-medium));
  font-weight: 600;
  line-height: 1.08;
  letter-spacing: -0.015em;
}
h2 { font-size: var(--headline-medium); font-weight: 600; line-height: var(--zeile-eng); letter-spacing: -0.01em; }
h3 { font-size: var(--title-large); font-weight: 600; line-height: var(--zeile-normal); }
h4 { font-weight: 600; }

/* Sichtbarer Tastaturfokus auf allen Bedienelementen. Bewusst OHNE
   border-radius: Der Ring folgt in heutigen Browsern von selbst der Form des
   Elements. Die frühere Angabe verformte stattdessen das Element beim
   Fokussieren — ein Pillenknopf wurde beim Antippen eckig. */
:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

/* ---------- Zustände für ALLE Bedienelemente ----------
   Eine Stelle statt je Komponente. Vorher gab es drei verschiedene
   Hover-Lösungen (Flächenwechsel, filter: brightness, Schatten + Versatz)
   und gar kein Aktiv-Bild.

   Hover  = eine Flächenstufe höher
   Aktiv  = eine weitere Stufe (gedrückt wirkt tiefer, nicht heller)
   Sperre = 0.38 Deckkraft, wie in Material 3

   Komponenten setzen darauf nur noch ihre eigene Grundfläche. */
button:disabled {
  opacity: 0.38;
  cursor: default;
}

/* Nur für Screenreader sichtbar. */
.sr-only {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip: rect(0 0 0 0); overflow: hidden; white-space: nowrap;
}

/* Sprungmarke „Zum Inhalt springen".

   ⛔ SIE DARF NICHT .sr-only SEIN. Genau so stand sie bis zum 10.08.2026: als
   erster Tabstopp der Seite, dauerhaft unsichtbar — auch im Fokus. Wer die
   Seite mit der Tastatur bedient, drückte Tab, bekam einen unsichtbaren
   Fokus irgendwo im Nichts und danach die volle Kopfleiste. Eine Sprungmarke,
   die man nicht sehen kann, ist keine: Ihr ganzer Zweck ist, im Fokus
   sichtbar zu werden.

   Ausgeblendet wird sie deshalb mit denselben Mitteln wie .sr-only, aber nur
   solange sie NICHT fokussiert ist. :focus statt :focus-visible mit Absicht —
   sie wird ausschließlich per Tastatur erreicht, und ein Fokus, der hier
   ankommt, soll immer sichtbar sein.

   z-index über der Kopfleiste (50) und der Hauptleiste (45), damit sie nicht
   dahinter auftaucht; unter den Overlays (60), die ohnehin nie gleichzeitig
   offen sind. */
.sprungmarke {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip: rect(0 0 0 0); overflow: hidden; white-space: nowrap;
}

.sprungmarke:focus {
  position: fixed;
  top: var(--abstand-s); left: var(--abstand-s);
  width: auto; height: auto;
  margin: 0; padding: var(--abstand-s) var(--abstand-l);
  clip: auto; overflow: visible;
  z-index: 100;
  background: var(--surface-container-high);
  color: var(--on-surface);
  border-radius: var(--radius-m);
  box-shadow: var(--schatten-schwebend);
  outline: 2px solid var(--primary);
  outline-offset: 2px;
  text-decoration: none;
}

/* Bewegungsreduzierung: sämtliche Animationen und Übergänge abschalten
   (gleiche Regel wie in der App: keine Bewegung, Endzustand sofort). */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ---------------------------------------------------------------------------
   DRUCK

   Bis zum 10.08.2026 hatte die Seite keine einzige Druckregel: Gedruckt wurde
   das Bildschirmlayout samt fixierter Menüspalte, klebender Werkzeugzeile und
   Filterspalte. Auf Papier ergibt das eine erste Seite voller Bedienelemente
   und einen Inhalt, der daneben in einer schmalen Spalte klebt — die
   haftenden Leisten wiederholen sich zudem auf jeder Seite oder verdecken
   Text, je nach Browser.

   Ein Preisvergleich wird durchaus ausgedruckt: Wer eine Auswahl in die
   Werkstatt mitnimmt oder einem anderen zeigt, druckt Liste, Vergleich oder
   Detailseite. Deshalb bleibt der INHALT, und alles verschwindet, was nur zur
   Bedienung da ist.

   ⚠️ Die Regeln stehen bewusst hier und nicht in einer sechsten Datei: Sie
   gelten dokumentweit wie der Bewegungsblock darüber, und ein eigenes
   Stylesheet müsste in index.html, in der Prüfseite und in dieser Datei
   nachgezogen werden.
   --------------------------------------------------------------------------- */
@media print {
  /* ⛔ DIE PAPIER-PALETTE (03.09.2026)
     ========================================================================

     Der Bildschirm ist seit dem 03.09.2026 dauerhaft dunkel; css/theme.css
     führt nur noch EINEN Satz Farbrollen, und der ist hell auf dunkel.
     Papier ist das Gegenteil, und das ist kein zweites Schema, sondern ein
     anderes Medium: kein data-theme, kein Umschalter, keine Systemabfrage —
     eine Medienabfrage.

     ⛔ WARUM DAS SEIN MUSS, UND ZWAR GEMESSEN. Bis hierher setzte dieser
     Block `color-scheme`, Papierfarbe und Textfarbe, aber KEINE Farbtokens.
     Jedes Element mit eigener `color:`-Angabe druckte damit seine
     Bildschirmfarbe auf weißes Papier. Gemessen auf /, /filamente und
     /wissen mit dunklem Schema:

       --on-surface          #E3E6EA auf Weiß   1,25:1   (Überschriften)
       --on-surface-variant  #C2C7CF auf Weiß   1,70:1   (Kicker, Fließtext)
       schwarze Schrift auf --surface-container #181B21  1,22:1

     Das war schon vorher kaputt, sobald jemand im Dunkelmodus druckte — nur
     fiel es nicht auf, weil die meisten hell unterwegs waren. Seit es kein
     anderes Schema mehr gibt, wäre es der Normalfall gewesen.

     ⚠️ ES IST DER VOLLE SATZ (61 Rollen), nicht die gemessen nötige Auswahl.
     Der Grund ist der stille Fehler: Eine künftige Ansicht kann eine Rolle
     drucken, die heute nicht im gedruckten Inhalt vorkommt — dann stünde
     wieder heller Text auf Papier, und niemand bemerkt es, weil am Bildschirm
     alles richtig aussieht.

     ⚠️ Die VIER --schema-*-Rollen fehlen hier ABSICHTLICH. Sie waren nie
     schemaabhängig (das Bildfeld der Drucker-Zeichnung ist auch am Bildschirm
     hell) und stehen in theme.css bereits richtig; ein zweiter Satz hier wäre
     eine zweite Stelle, die jemand nachziehen müsste.

     ⛔ WER IN theme.css EINE FARBROLLE ÄNDERT, SIEHT HIER NACH. Die beiden
     Sätze sind bewusst getrennt, aber sie beschreiben dieselben Rollen.
     Die Werte sind die des hellen Schemas, wie es bis zum 03.09.2026 galt. */
  :root {
    color-scheme: light;

    --primary: #2B50E0;
    --on-primary: #FFFFFF;
    --primary-container: #E4EAFD;
    --on-primary-container: #1E3AAE;
    /* ⛔ DUNKLER ALS AUF DEM SCHIRM, und das ist gerechnet: Das Cyan der
       Marke (#01D3F8) mißt auf Weiß 1,80:1 — auf Papier wäre die halbe
       Marke weg. #0E7490 trägt 5,36:1. Die dunkle Hälfte braucht hier
       nichts: Sie nimmt currentColor und folgt der Textfarbe, die dieser
       Block ohnehin auf Schwarz setzt. */
    --marke-akzent: #0E7490;
    --secondary: #0E7490;
    --on-secondary: #FFFFFF;
    --secondary-container: #CFFAFE;
    --on-secondary-container: #164E63;
    --tertiary: #BE123C;
    --on-tertiary: #FFFFFF;
    --tertiary-container: #FFE4E6;
    --on-tertiary-container: #881337;
    --error: #B3261E;
    --on-error: #FFFFFF;
    --error-container: #F9DEDC;
    --on-error-container: #410E0B;
    --background: #F4F5F7;
    --on-background: #14161A;
    --surface: #F4F5F7;
    --on-surface: #14161A;
    --surface-variant: #E7E9EE;
    --on-surface-variant: #5A5F6A;
    --outline: #6A6D77;
    --outline-variant: #DCDFE6;
    --surface-container-lowest: #FFFFFF;
    --surface-container-low: #FAFAFC;
    --surface-container: #FFFFFF;
    --surface-container-high: #FFFFFF;
    --surface-container-highest: #ECEEF2;
    --inverse-surface: #2F3136;
    --inverse-on-surface: #F0F1F5;
    --gruen-container: #C6ECCB;
    --gruen-inhalt: #10461F;
    --gruen-feld: #EAF6EC;
    --gruen-kante: #A8CDB2;
    --balken-gruen: #286E2D;
    --balken-gelb: #B58900;
    --balken-rot: #C62828;
    --stern-gelb: #9A7300;
    --kauf: #2E7D32;
    --on-kauf: #FFFFFF;
    --warnung-erhoeht: #AD4F08;
    --kennzeichen-flaeche: #2B50E0;
    --kennzeichen-tinte: #FFFFFF;
    --versand-frei-flaeche: #EAF6EC;
    --versand-frei-tinte: #286E2D;
    --versand-auf-flaeche: #FFF4D6;
    --versand-auf-tinte: #7A5A00;
    --knopf-kante: #6A6D77;
    --hotend-1: #DBE2EE;
    --hotend-2: #E2E7F0;
    --hotend-3: #F3E0CD;
    --hotend-4: #EFD4B7;
    --hotend-5: #EAC59E;
    --hotend-tinte-kuehl: #1B2430;
    --hotend-tinte-warm: #4A2A0C;
    --resin-schicht-1: #DFE3EB;
    --resin-schicht-2: #D3DEF2;
    --resin-schicht-3: #F2DAEC;
    --resin-schicht-4: #E7EAEF;
    --resin-schicht-5: #D8E0F5;
    --resin-schicht-6: #E4DCF5;
    --resin-schicht-tinte: #1B2430;
    /* ⚠️ Die drei folgenden sind auf Papier gegenstandslos — `* { box-shadow:
       none }` weiter unten löscht sie. Sie stehen trotzdem hier, weil der
       Satz vollständig sein soll: Wer ihn liest, soll nicht raten müssen,
       ob eine Rolle vergessen wurde oder absichtlich fehlt. */
    --schatten-schwebend: 0 4px 16px rgba(0, 0, 0, 0.18);
    --karten-kante: 0 0 0 1px var(--outline-variant), 0 1px 2px rgba(20, 22, 26, 0.04);
    --feld-kante: 0 0 0 1px #A7ACBA;
    --zustand-hover: rgba(20, 22, 26, 0.08);
    --zustand-aktiv: rgba(20, 22, 26, 0.12);
  }

  html, body {
    background: #FFFFFF;
    color: #000000;
  }

  /* Der Platz der Icon-Spalte wird am Bildschirm beidseitig freigehalten
     (siehe CLAUDE.md). Auf Papier gibt es die Spalte nicht. */
  body {
    padding-inline: 0;
  }

  /* Reine Bedienelemente — nichts davon ist auf Papier zu gebrauchen. */
  .kopfzeile,
  .hauptleiste,
  .listen-kopf,
  .filter-sidebar,
  .vergleichsleiste,
  .snackbar,
  .schleier-flaeche,
  .rollspule,
  .sprungmarke,
  .fusszeile-links,
  [data-rolle="zurueck"],
  .vergleich-aktionen {
    display: none !important;
  }

  /* ⚠️ Die Rollsperre eines offenen Overlays wird auf Papier zurückgenommen.
     Der Schleier ist eine Zeile weiter oben ausgeblendet, das `data-modal`
     an der Wurzel bleibt aber stehen — und `overflow: hidden` an der Wurzel
     kann den Ausdruck je nach Browser auf eine einzige Seite beschneiden.
     Ein Zustand der BEDIENUNG darf nicht über den Umfang des Papiers
     entscheiden. */
  :root[data-modal="offen"] {
    overflow: visible;
    padding-right: 0;
  }

  /* Nichts klebt: Auf Papier führt das je nach Browser zu Wiederholungen auf
     jeder Seite oder zu verdecktem Text.

     ⚠️ GEZIELT, nicht `* { position: static }`. Ein pauschaler Rücksetzer
     träfe auch die absolut positionierten Elemente, die INHALT tragen — die
     Spulenbühne der Wortmarke, die Wertblasen der Regler, die Sieger-Bänder
     der Vergleichskarten. Aufgeführt sind deshalb nur die Elemente, die
     wirklich kleben und trotzdem sichtbar bleiben sollen; die klebenden
     Bedienleisten sind oben schon ausgeblendet. */
  .vt-label,
  .vt-blocktitel span,
  .dv-tabelle tbody th,
  .dv-ecke {
    position: static !important;
  }

  /* Schatten kosten nur Toner und tragen auf Papier nichts bei. */
  * {
    box-shadow: none !important;
  }

  /* ⛔ DER KOPFBEREICH DER STARTSEITE IST AUF DEM SCHIRM EIN DUNKLER GRUND MIT
     HELLEM TEXT (css/seiten.css, .start-kopf). Auf Papier gibt es diesen Grund
     nicht — der Druckblock erzwingt oben ausdrücklich das helle Schema und
     weißes Papier. Ohne diese Regel druckte die Startseite ihre Überschrift,
     ihre Einleitung und ihre Kennzahlen WEISS AUF WEISS: vollständig
     unsichtbar, und zwar ohne dass irgendetwas meldet.

     Foto und Schleier fallen weg statt mitgedruckt zu werden — ein
     randabfallendes Foto kostet Toner und trägt keine Auskunft; die Bühne
     bricht zugleich aus der Textflucht aus, was auf Papier nichts erklärt. */
  .kopf-foto,
  .kopf-schleier {
    display: none !important;
  }

  .start-kopf {
    --kopf-tinte: #000000;
    --kopf-tinte-leise: #333333;
    --kopf-kante: #999999;
    --kopf-linie: #999999;
    margin-inline: 0 !important;
    padding-inline: 0 !important;
    padding-bottom: 0 !important;
  }

  /* ⛔ AUF PAPIER STEHT JEDER ABSCHNITT OFFEN.

     Preisverlauf und beschreibende Karten der Detailseite lassen sich einklappen
     (siehe css/seiten.css). Auf dem Schirm ist das der Sinn der Sache; auf
     Papier wäre es Datenverlust, denn ein gedruckter Abschnitt lässt sich
     nicht mehr aufklappen. Wer eine Produktseite ausdruckt, will die
     Produktdaten — nicht die Überschrift darüber.

     Alle drei Zeilen werden gebraucht: die Rasterzeile trägt die Höhe, die
     Sichtbarkeit hält den Inhalt für Vorlesehilfen UND für den Druck, und der
     Chevron ist ein Bedienelement, also auf Papier gegenstandslos. */
  .klapp-huelle {
    grid-template-rows: 1fr !important;
  }
  .klapp-inhalt {
    visibility: visible !important;
  }
  .klapp-pfeil {
    display: none !important;
  }

  /* Eine Kachel, eine Gerätezeile oder eine Karte soll nicht mitten
     auseinandergerissen werden. */
  .filament-kachel,
  .produkt-karte,
  .material-kachel,
  .dr-zeile,
  .detail-karte,
  .angebot-karte,
  .ordner-karte {
    break-inside: avoid;
    page-break-inside: avoid;
  }

  /* Der Merkzettel und die Vergleichstabelle sind die Ansichten, die man am
     ehesten mitnimmt — ihre Spalten dürfen nicht in die Breite laufen. */
  .liste-layout,
  .detail-layout {
    display: block !important;
  }
}
