/* Grundlagen: Zurücksetzen, Schrift, Textkörper, Layout-Gerüst.
 * Farbwerte kommen ausschließlich aus tokens.css. */

/* ---------------------------------------------------------------- Schriften */

@font-face {
  font-family: "Source Sans 3";
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url("/assets/fonts/source-sans-3-variable.woff2") format("woff2");
}

@font-face {
  font-family: "Source Serif 4";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/assets/fonts/source-serif-4-variable.woff2") format("woff2");
}

/* ---------------------------------------------------------- Zurücksetzen */

*,
*::before,
*::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 6rem;   /* damit Sprungziele nicht unter der Kopfzeile landen */
}

@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;
  }
}

/* Der Seitengrund liegt am Wurzelelement, nicht am Textkörper.
 *
 * Nur so kann der bewegte Wasch-Grund darunter (body::before, z-index -1) über
 * der Grundfarbe liegen und trotzdem hinter allem Inhalt. Läge die Farbe am
 * body, würde sie den Wasch-Grund verdecken. */
html { background: var(--papier); }

body {
  margin: 0;
  background: transparent;
  color: var(--tinte);
  font-family: var(--schrift-text);
  font-size: var(--grad-text);
  line-height: var(--zeile-text);
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img,
picture,
video,
svg { max-width: 100%; height: auto; display: block; }

/* ---------------------------------------------------------------- Textkörper */

h1, h2, h3, h4 {
  font-family: var(--schrift-titel);
  color: var(--tinte-kraeftig);
  font-weight: 600;
  line-height: var(--zeile-titel);
  letter-spacing: -0.015em;
  text-wrap: balance;
  margin: 0 0 var(--ab-4);
}

h1 {
  font-size: var(--grad-h1);
  line-height: var(--zeile-eng);
  letter-spacing: -0.025em;
}

/* Deutsche Komposita auf schmalen Schirmen.
 *
 * Gemessen bei 320 px Breite: Das Wort "Bausatzhäuser" ist bei 40 px
 * Schriftgrad rund 270 px breit, "Deckenrandschalung" rund 350 px. Rasterelemente schrumpfen nicht unter ihre
 * Mindestbreite (min-width: auto), also wurde die Spalte 304 px breit, obwohl
 * der Satzspiegel nur 284 px hergibt - und die ganze Seite liess sich um 2 px
 * waagerecht schieben. Auf Deutsch ist das kein Sonderfall, sondern der
 * Normalfall: Deckenrandschalung, Passivhausschalsteine, Dachstuhlelemente.
 *
 * Zwei Massnahmen: Silbentrennung auf schmalen Schirmen, und Rasterelemente
 * duerfen unter ihre Mindestbreite. */
/* Silbentrennung in Überschriften bei JEDER Breite.
 *
 * Vorher galt sie nur bis 40 rem. Auf breiten Schirmen brach dadurch
 * "PassivHaus/NullEnergiehaus/PlusEnergiehaus" mitten im Wort um, ohne
 * Trennstrich: "…PlusEnergiehau" / "s". Mit hyphens: auto trennt der Browser
 * an Silbengrenzen und setzt einen Strich - so, wie es sich für deutschen Satz
 * gehört. overflow-wrap bleibt als letzte Rückfallebene bestehen. */
h1, h2, h3, h4 { hyphens: auto; }

h2 { font-size: var(--grad-h2); margin-top: var(--ab-8); }
h3 { font-size: var(--grad-h3); margin-top: var(--ab-6); }
h4 { font-size: var(--grad-h4); margin-top: var(--ab-5); font-weight: 700; }

/* Die erste Überschrift eines Abschnitts braucht keinen Abstand nach oben,
 * den liefert der Abschnitt selbst. */
:is(h2, h3, h4):first-child { margin-top: 0; }

p { margin: 0 0 var(--ab-4); text-wrap: pretty; }

/* Deutsche Komposita sind lang. Damit kein Wort seinen Kasten sprengt und die
   Seite waagerecht scrollbar macht, darf ueberall umgebrochen werden. */
p, li, dd, dt, figcaption, td, th, summary,
h1, h2, h3, h4 { overflow-wrap: break-word; }
p:last-child { margin-bottom: 0; }

strong, b { font-weight: 700; color: var(--tinte-kraeftig); }

a {
  color: var(--leitton);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
  transition: color var(--dauer-kurz) var(--kurve);
}

a:hover { color: var(--leitton-tief); }

:focus-visible {
  outline: 2px solid var(--fokus);
  outline-offset: 3px;
  border-radius: var(--radius-klein);
}

ul, ol { margin: 0 0 var(--ab-4); padding-left: 1.35em; }
li { margin-bottom: var(--ab-2); }
li:last-child { margin-bottom: 0; }

/* Ziffern in einer Breite. Auf dieser Seite stehen sehr viele Maße, Preise und
 * U-Werte; springende Ziffernbreiten lassen Tabellen unruhig wirken. */
table, .zahl, .preis { font-variant-numeric: tabular-nums; }

hr {
  border: 0;
  border-top: 1px solid var(--linie);
  margin: var(--ab-7) 0;
}

/* ------------------------------------------------------- Bewegter Grund
 *
 * Drei sehr durchlässige Blauflächen, die langsam gegeneinander wandern.
 * Zusammen kommen sie auf rund 7 % Deckung - genug, dass die Seite lebt,
 * zu wenig, um beim Lesen aufzufallen.
 *
 * Bewegt wird ausschließlich über transform. Das läuft im Compositor, ohne
 * Layout und ohne Neuzeichnen; die Hauptleitung bleibt frei. Wanderte statt
 * dessen background-position, müsste der Browser die Fläche in jedem Bild neu
 * malen - genau das, was auf schwächeren Geräten ruckelt.
 *
 * Kein GSAP, keine Bibliothek: Für eine gleichmäßige Endlosbewegung ohne
 * Steuerung durch den Nutzer bringt eine Animationsbibliothek nichts, was
 * @keyframes nicht kann, kostet aber Ladezeit und Rechenzeit im Haupt-Thread.
 *
 * WICHTIG: Der Wasch-Grund darf niemals hinter den Produktabbildungen liegen.
 * Deren Bildgrund ist auf genau eine Farbe montiert (--leitton-hauch); zöge
 * dort etwas durch, zeichnete sich der Bildrand wieder als Kasten ab. Alle
 * betroffenen Flächen (.materialkreis, .rechner, .kundenhinweis) sind deckend
 * und liegen darüber. */

.waschgrund {
  position: fixed;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
}

.waschgrund span {
  position: absolute;
  display: block;
  border-radius: 50%;
  /* Weit über den Rand hinaus, damit beim Wandern nie eine Kante sichtbar
     wird. */
  width: 78vmax;
  height: 78vmax;
  will-change: transform;
}

.waschgrund span:nth-child(1) {
  top: -28vmax;
  left: -18vmax;
  background: radial-gradient(circle closest-side, var(--wasch-1), transparent);
  animation: waschen-1 58s ease-in-out infinite alternate;
}

.waschgrund span:nth-child(2) {
  top: 12vmax;
  right: -26vmax;
  background: radial-gradient(circle closest-side, var(--wasch-3), transparent);
  animation: waschen-2 74s ease-in-out infinite alternate;
}

.waschgrund span:nth-child(3) {
  bottom: -34vmax;
  left: 18vmax;
  background: radial-gradient(circle closest-side, var(--wasch-2), transparent);
  animation: waschen-3 91s ease-in-out infinite alternate;
}

/* Drei verschiedene Dauern, keine davon ein Vielfaches der anderen. Sonst
   träfen sich die drei Flächen regelmäßig in derselben Stellung und die
   Bewegung bekäme einen erkennbaren Takt. */
@keyframes waschen-1 {
  from { transform: translate3d(0, 0, 0) scale(1); }
  to   { transform: translate3d(14vmax, 9vmax, 0) scale(1.18); }
}

@keyframes waschen-2 {
  from { transform: translate3d(0, 0, 0) scale(1.12); }
  to   { transform: translate3d(-12vmax, 15vmax, 0) scale(0.94); }
}

@keyframes waschen-3 {
  from { transform: translate3d(0, 0, 0) scale(1); }
  to   { transform: translate3d(11vmax, -13vmax, 0) scale(1.22); }
}

/* Wer keine Bewegung will, bekommt eine ruhige Fläche - nicht gar keine.
   Der Farbeindruck der Seite bleibt damit derselbe. */
@media (prefers-reduced-motion: reduce) {
  .waschgrund span { animation: none; }
}

/* Beim Drucken hat der Grund nichts zu suchen. */
@media print {
  .waschgrund { display: none; }
}

/* --------------------------------------------------------------- Hilfsmittel */

.nur-fuer-vorleser {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.zum-inhalt {
  position: absolute;
  left: var(--ab-4);
  top: var(--ab-4);
  z-index: var(--ebene-oben);
  transform: translateY(-160%);
  background: var(--flaeche);
  color: var(--leitton);
  border: 1px solid var(--linie-kraeftig);
  border-radius: var(--radius);
  padding: var(--ab-3) var(--ab-5);
  font-weight: 600;
  text-decoration: none;
  transition: transform var(--dauer) var(--kurve-aus);
}

.zum-inhalt:focus { transform: translateY(0); }

/* ------------------------------------------------------------------- Gerüst */

.huelle {
  width: 100%;
  max-width: var(--breite-inhalt);
  margin-inline: auto;
  padding-inline: var(--rand-seite);
}

.huelle--weit { max-width: var(--breite-weit); }

/* Lesespalte. Alles, was Fließtext ist, läuft hierdurch, damit die Zeilen bei
 * rund 68 Zeichen umbrechen statt über die volle Breite zu laufen. */
.satz {
  max-width: var(--breite-satz);
}

/* Lesefluss: EINE gemeinsame linke Kante fuer alles.
 *
 * Die vorige Fassung hatte die Lesespalte in der Mitte des Containers
 * zentriert. Gemessen auf einem 1440-px-Schirm ergab das drei verschiedene
 * linke Kanten auf derselben Seite:
 *
 *     Markenzug, Titelbereich, Fusszeile   x = 171
 *     Bildstrecken                         x = 280
 *     Ueberschriften und Fliesstext        x = 408
 *
 * Das liest sich als Versatz, nicht als Gestaltung. Hier laufen jetzt alle
 * Bausteine an derselben Kante los - derselben, an der auch Kopfzeile,
 * Titelbereich und Fusszeile stehen. Der Fliesstext endet nach der Lesebreite,
 * alles mit der Klasse "breit" (Bildstrecken, Tabellen, Videos) laeuft bis zur
 * rechten Containerkante durch. */
.lesefluss {
  display: grid;
  width: 100%;
  max-width: var(--breite-inhalt);
  margin-inline: auto;
  padding-inline: var(--rand-seite);
  grid-template-columns:
    [satz-start] minmax(0, var(--breite-satz)) [satz-ende]
    minmax(0, 1fr) [breit-ende];
}

.lesefluss > * { grid-column: satz-start / satz-ende; }
.lesefluss > .breit { grid-column: satz-start / breit-ende; }

.abschnitt { padding-block: var(--ab-abschnitt); }
.abschnitt--eng { padding-block: var(--ab-7); }
.abschnitt--abgesetzt { background: var(--papier-tief); }

/* Bauzeichnungs-Raster.
 * Sehr zurückhaltend: ein Millimeterpapier-Raster als Hintergrund für
 * abgesetzte Abschnitte. Das nimmt dem Weiß die Leere, ohne dass es als
 * Verzierung auffällt, und passt zum Thema der Seite. */
.abschnitt--raster {
  background-color: var(--papier-tief);
  background-image:
    linear-gradient(to right, var(--linie) 1px, transparent 1px),
    linear-gradient(to bottom, var(--linie) 1px, transparent 1px);
  background-size: 28px 28px;
  background-position: center;
  position: relative;
}

/* Das Raster am Rand ausblenden, damit es nicht wie ein Kachelfehler wirkt. */
.abschnitt--raster::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(ellipse 80% 70% at 50% 50%,
              transparent 20%, var(--papier-tief) 100%);
}

.abschnitt--raster > * { position: relative; z-index: var(--ebene-grund); }

/* ------------------------------------------------------------------ Bewegung
 * MOTION_INTENSITY 3: Eintritt beim Scrollen, sonst nichts. Ausgeführt über
 * IntersectionObserver in js/sichtbar.js, niemals über ein scroll-Ereignis.
 * Ohne JavaScript bleibt der Inhalt sichtbar, deshalb wird die Startlage erst
 * gesetzt, wenn das Skript die Klasse am <html> gesetzt hat. */

.js-bewegung .eintritt {
  opacity: 0;
  transform: translateY(12px);
  transition: opacity var(--dauer-lang) var(--kurve-aus),
              transform var(--dauer-lang) var(--kurve-aus);
}

.js-bewegung .eintritt.ist-da {
  opacity: 1;
  transform: none;
}

/* Staffelung in CSS statt per JavaScript. Ein per el.style gesetztes
   transition-delay ist ein Inline-Stil und wird von style-src 'self'
   blockiert - die Verzögerung kam nie an. */
.js-bewegung .eintritt:nth-child(6n+2) { transition-delay: 60ms; }
.js-bewegung .eintritt:nth-child(6n+3) { transition-delay: 120ms; }
.js-bewegung .eintritt:nth-child(6n+4) { transition-delay: 180ms; }
.js-bewegung .eintritt:nth-child(6n+5) { transition-delay: 240ms; }
.js-bewegung .eintritt:nth-child(6n+0) { transition-delay: 300ms; }

@media (prefers-reduced-motion: reduce) {
  .js-bewegung .eintritt { opacity: 1; transform: none; transition-delay: 0s; }
}

/* ------------------------------------------------------------------- Drucken */

@media print {
  .kopfzeile, .fusszeile, .sprungmarken, .zum-inhalt { display: none !important; }
  body { background: none; font-size: 11pt; }
  a::after { content: " (" attr(href) ")"; font-size: 9pt; color: var(--tinte-leise); }
}
