/* ============================================================
   ZEICHENRASTER-BILD  (js/fx/ascii-img.js)
   Die Vorlage bleibt sichtbar, bis das Raster steht — fällt das
   Modul aus, sieht man also das Foto und keine leere Fläche.
   ============================================================ */
[data-ascii] {
  position: relative;
  overflow: hidden;
  background: var(--void);
}
[data-ascii] > img {
  display: block;
  width: 100%; height: 100%;
  object-fit: cover;
  transition: opacity 400ms var(--ease);
}
[data-ascii].is-ascii > img { opacity: 0; }
[data-ascii] canvas.ascii-cv {
  position: absolute; inset: 0;
  display: block;
  width: 100%; height: 100%;
}
/* Feiner Rahmen + Eckmarken wie auf einem Planblatt */
[data-ascii]::after {
  content: '';
  position: absolute; inset: 0;
  pointer-events: none;
  border: 1px solid var(--grey-line);
}

/* ============================================================
   HANS BAUR GMBH — RELAUNCH 2026
   leistung.css — die acht Leistungsseiten

   Setzt auf css/base.css auf (Farben, Schriften, Navigation,
   Fuß, [data-flow]-Stapelung) und ergänzt nur das, was diese
   Seiten zusätzlich brauchen. home.css wird hier NICHT geladen —
   die Startseite bleibt davon unberührt.

   Ebenen nach DESIGN.md §6:
   0 Canvas · 1 Verlauf · 2 Glas · 3 Inhalt · 4 Navigation
   ============================================================ */

/* ============================================================
   HERO DER LEISTUNGSSEITE
   Gleicher innerer Aufbau wie der Hero der Startseite, damit
   js/site.js (Kamerafahrt, Scroll-Hinweis) ohne Sonderfall
   arbeitet: .hero-stage / .hero-fx / .hero-content / .hero-plate.
   ============================================================ */
.lhero {
  position: relative;
  min-height: 100svh;
  display: flex;
  align-items: center;
  padding-block: calc(var(--nav-h) + 92px) clamp(52px, 9vh, 104px);
  overflow: hidden;
  --fall: 0;
}

/* ---- Ebene 0: die Bühne ---- */
.lhero .hero-stage {
  position: absolute;
  inset: -6% 0 -6% 0;
  z-index: 0;
  will-change: transform;
}
.lhero .hero-fx { position: absolute; inset: 0; }
.lhero .hero-fx canvas { width: 100%; height: 100%; }

/* Lichtstrahlen wie auf der Startseite, etwas zurückgenommen */
.lhero .hero-rays {
  position: absolute;
  inset: -20% -10%;
  z-index: 2;
  pointer-events: none;
  background:
    /* Der weisse Strahl setzte Dunkelheit voraus; umgedreht wurde daraus
       eine dunkle Schliere auf dem Papier. Es bleibt der blaue Hauch. */
    linear-gradient(97deg, transparent 54%, rgba(8,70,168,0.05) 59%, transparent 66%);
  filter: blur(6px);
  animation: rayDrift 26s ease-in-out infinite alternate;
}
@keyframes rayDrift {
  from { transform: translate3d(-2.5%, 0, 0) rotate(-0.6deg); opacity: 0.75; }
  to   { transform: translate3d(2.5%, 0, 0)  rotate(0.6deg);  opacity: 1; }
}

.lhero .hero-veil {
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  /* Mitte bei 58 %, nicht bei 42 %: Die Trasse des Canvas läuft
     bei 72 % der Breite — läge der helle Kern weiter links, würde
     der Schleier ausgerechnet den Signatur-Effekt abdunkeln. */
  background:
    radial-gradient(140% 110% at 62% 46%, transparent 48%, rgba(250,248,244,0.30) 84%, rgba(250,248,244,0.86) 100%),
    linear-gradient(180deg,
      var(--void) 0%,
      rgba(250,248,244,0.82) 7%,
      rgba(250,248,244,0.45) 15%,
      transparent 30%,
      transparent 62%,
      var(--void) 100%);
}
/* Blende der Kamerafahrt — gleiche Kurve wie auf der Startseite:
   erst das Tempo, dann das Dunkel. */
.lhero .hero-veil::after {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(115% 80% at 42% 44%, transparent 22%, var(--void) 96%);
  opacity: calc(max(0, var(--fall, 0) - 0.42) * 1.75);
}

.lhero .hero-content { position: relative; z-index: 4; width: 100%; }

/* ---- KEINE Glasplatte mehr ----
   Der Text steht frei auf der Szene; die Lesbarkeit trägt der
   weiche Schleier (.lhero-scrim), kein Panel. Gefasst wird er von
   zwei Leuchtstrichen — siehe unten. */
.lhero .hero-plate {
  /* Die Box legt sich um ihren Inhalt, statt auf fester Breite zu
     stehen. Vorher war sie 640 px breit, der Text aber nur 383 px —
     dadurch hing der rote Strich rechts 214 px im Leeren, während
     der blaue links nur 44 px überstand. Mit fit-content stehen
     beide gleich weit über. */
  width: fit-content;
  max-width: min(640px, 100%);
  padding: clamp(30px, 3.4vw, 46px) clamp(30px, 3.4vw, 48px);
  position: relative;
  transform-origin: 50% 40%;
  will-change: transform, filter;
}

/* Zwei Leuchtstriche statt Winkel.
   Vier Quadrate schlossen den Text ein wie einen Kasten; L-Winkel
   wirkten wegen des Leuchtscheins immer noch rechteckig — der
   Schein legt sich als Halo um die Form. Deshalb jetzt reine
   waagerechte Striche, die nach außen auslaufen. Sie können gar
   nicht mehr als Fläche gelesen werden und sprechen dieselbe
   Sprache wie die Lichtbänder zwischen den Abschnitten.
   Sie fahren auf; KEIN Füllmodus, der Ruhezustand ist die volle
   Länge. */
.lhero .hero-plate::before,
.lhero .hero-plate::after {
  content: '';
  position: absolute;
  height: 2px;
  width: clamp(90px, 14vw, 210px);
  pointer-events: none;
  border-radius: 2px;
  animation: hudOut 820ms cubic-bezier(0.16, 1, 0.3, 1);
}
@keyframes hudOut { from { width: 0; opacity: 0; } }

.lhero .hero-plate::before {
  left: 0; top: 0;
  background:
    linear-gradient(90deg, rgba(214,232,255,0) 0%, rgba(214,232,255,0.95) 50%, rgba(214,232,255,0) 100%),
    linear-gradient(90deg, var(--blue-lift) 0%, rgba(46,111,224,0.55) 55%, transparent 100%);
  background-size: 26% 100%, 100% 100%;
  background-repeat: no-repeat, no-repeat;
  background-position: -30% 0, 0 0;
  box-shadow: 0 0 18px rgba(46,111,224,0.75);
  animation: hudOut 820ms cubic-bezier(0.16, 1, 0.3, 1),
             glintHin 3s cubic-bezier(0.42, 0, 0.35, 1) 0.45s infinite;
}
.lhero .hero-plate::after {
  right: 0; bottom: 0;
  background:
    linear-gradient(90deg, rgba(255,214,208,0) 0%, rgba(255,214,208,0.9) 50%, rgba(255,214,208,0) 100%),
    linear-gradient(270deg, var(--red) 0%, rgba(210,32,28,0.5) 55%, transparent 100%);
  background-size: 26% 100%, 100% 100%;
  background-repeat: no-repeat, no-repeat;
  background-position: 130% 0, 0 0;
  box-shadow: 0 0 18px rgba(210,32,28,0.6);
  /* Zurueck: Das Licht laeuft auf dem blauen Strich hinaus und auf
     dem roten wieder herein — ein Umlauf, keine zwei Effekte. */
  animation: hudOut 820ms cubic-bezier(0.16, 1, 0.3, 1) 140ms,
             glintZurueck 3s cubic-bezier(0.42, 0, 0.35, 1) 1.95s infinite;
}

@keyframes glintHin {
  0%   { background-position: -30% 0, 0 0; }
  38%  { background-position: 130% 0, 0 0; }
  100% { background-position: 130% 0, 0 0; }
}
@keyframes glintZurueck {
  0%   { background-position: 130% 0, 0 0; }
  38%  { background-position: -30% 0, 0 0; }
  100% { background-position: -30% 0, 0 0; }
}



/* ---- Schleier statt Kasten: trägt die Lesbarkeit des Textes ---- */
.lhero-scrim {
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  /* Auf schwarzem Grund musste dieser Schleier die Szene niederdrücken,
     damit helle Schrift trug. Auf Papier ist der Kontrast schon ohne ihn
     gemessene 9,4:1 — er würde nur die Szene ausbleichen. Er bleibt als
     Sicherheitsboden für dunklere Motive, aber halb so stark. */
  background: radial-gradient(58% 62% at 26% 74%, rgba(250,248,244,0.48) 0%, rgba(250,248,244,0.28) 46%, transparent 78%);
}

/* Brotkrumen als Messzeile */
.lcrumb {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-bottom: 20px;
  font-family: var(--f-mono);
  font-size: 0.66rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--text-mute);
}
.lcrumb a { color: var(--blue-text); text-decoration: none; }
.lcrumb a:hover { color: var(--paper); }
.lcrumb i { font-style: normal; opacity: 0.4; }

.lhero h1 {
  font-family: var(--f-display);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: -0.015em;
  line-height: 0.92;
  font-size: clamp(2.8rem, 9vw, 7rem);
  margin-bottom: 18px;
}
.lhero-claim {
  color: var(--text-mute);
  font-size: clamp(1rem, 1.5vw, 1.22rem);
  max-width: 52ch;
}

/* ============================================================
   INHALTSABSCHNITT
   ============================================================ */
.lgrid {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(32px, 5vw, 76px);
  align-items: start;
}
.lgrid p { color: var(--text-mute); margin-bottom: 16px; max-width: 62ch; }
.lgrid p:last-of-type { margin-bottom: 0; }

/* Leistungsliste als Aufmaß: nummeriert, Haarlinien, Mono-Zähler */
.llist { list-style: none; margin-top: 34px; counter-reset: pos; }
.llist li {
  position: relative;
  display: flex;
  align-items: baseline;
  gap: 16px;
  padding: 13px 0 13px 2px;
  border-bottom: 1px solid var(--grey-line);
  color: var(--text);
  transition: color 240ms var(--ease), padding-left 240ms var(--ease);
}
.llist li::before {
  counter-increment: pos;
  content: counter(pos, decimal-leading-zero);
  font-family: var(--f-mono);
  font-size: 0.66rem;
  letter-spacing: 0.16em;
  color: var(--blue-text);
  flex: 0 0 auto;
  min-width: 2.4em;
  transition: color 240ms var(--ease);
}
.llist li:hover { color: var(--paper); padding-left: 10px; }
.llist li:hover::before { color: var(--red-text); }

/* Aufrollen nach Origin „imagefold" — Ruhewert 1 = voll abgerollt,
   das Bild steht also auch ohne Skript normal da. */
.lshot {
  /* Der obere Abstand entsteht schon durch die Liste darüber,
     deshalb hier nur ein kleiner Zuschlag. Die Luft NACH UNTEN
     regelt jetzt die Sektion selbst — siehe „PANEL-ÜBERLAPPUNG"
     am Dateiende. */
  margin-top: clamp(4px, 0.8vh, 10px);
  position: relative;
  border: 1px solid var(--grey-line);
  background: rgba(250,248,244,0.5);
  padding: 12px;
  perspective: 1500px;
  perspective-origin: 50% 0%;
  --unroll: 1;
}
.lshot .roll {
  position: relative;
  transform-origin: 50% 0%;
  transform: rotateX(calc((1 - var(--unroll)) * -82deg))
             translateZ(calc((1 - var(--unroll)) * -60px));
  transition: transform 120ms linear;
  will-change: transform;
}
.lshot .roll::after {
  content: '';
  position: absolute;
  left: 0; right: 0; top: 0;
  height: 42%;
  pointer-events: none;
  background: linear-gradient(180deg, rgba(4,7,14,0.85), rgba(4,7,14,0));
  opacity: calc(1 - var(--unroll));
}
.lshot img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 21 / 9;
  object-fit: cover;
  filter: contrast(1.06) saturate(1.08);
}
.lshot::after {
  content: attr(data-tag);
  position: absolute;
  left: 12px; bottom: 12px;
  padding: 6px 12px;
  font-family: var(--f-mono);
  font-size: 0.6rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--paper);
  background: rgba(250,248,244,0.72);
  -webkit-backdrop-filter: blur(8px);
          backdrop-filter: blur(8px);
  border-left: 2px solid var(--blue-lift);
}

/* ============================================================
   ABLAUF — angeheftete Bühne, Schritte laufen daneben
   ============================================================ */
.lflow-wrap {
  display: grid;
  grid-template-columns: 0.95fr 1.05fr;
  gap: clamp(28px, 4vw, 64px);
  align-items: start;
}
.lflow-stage {
  position: sticky;
  top: calc(var(--nav-h) + 28px);
  border: 1px solid var(--grey-line);
  background: rgba(250,248,244,0.5);
  padding: 12px;
  overflow: hidden;
}
.lflow-frames {
  position: relative;
  aspect-ratio: 4 / 3;
  overflow: hidden;
}
/* Das Zeichenraster füllt die ganze Bühne */
.lflow-shot {
  position: absolute;
  inset: 0;
  opacity: 0;
  transform: scale(1.04);
  transition: opacity 620ms var(--ease), transform 1100ms var(--ease);
}
.lflow-shot.is-on { opacity: 1; transform: none; }
.lflow-num {
  position: absolute;
  right: 3%; bottom: -3%;
  z-index: 2;
  font-family: var(--f-display);
  font-weight: 700;
  font-size: clamp(5rem, 13vw, 10rem);
  line-height: 0.8;
  color: rgba(10,14,24,0.10);
  pointer-events: none;
  user-select: none;
}
.lflow-bar {
  position: relative;
  height: 2px;
  margin-top: 12px;
  background: var(--grey-line);
  overflow: hidden;
}
.lflow-bar i {
  position: absolute;
  inset: 0;
  transform-origin: 0 50%;
  transform: scaleX(var(--p, 0));
  background: linear-gradient(90deg, var(--blue-lift), var(--paper) 70%, var(--red));
  transition: transform 520ms var(--ease);
}
.lstep {
  padding: clamp(30px, 5vh, 56px) 0;
  border-bottom: 1px solid var(--grey-line);
  opacity: 0.34;
  transition: opacity 520ms var(--ease);
}
.lstep:last-child { border-bottom: 0; }
.lstep.is-on { opacity: 1; }
.lstep .k {
  display: block;
  font-family: var(--f-mono);
  font-size: 0.66rem;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  color: var(--blue-text);
  margin-bottom: 14px;
}
.lstep h3 {
  font-family: var(--f-display);
  font-weight: 700;
  text-transform: uppercase;
  font-size: clamp(1.5rem, 2.6vw, 2.3rem);
  line-height: 1;
  margin-bottom: 14px;
}
.lstep p { color: var(--text-mute); max-width: 56ch; }

/* ============================================================
   PROJEKTRASTER — drei grosse Kacheln je Reihe
   ============================================================ */
/* ============================================================
   DAS PROJEKTBLATT — bündige Reihen

   Vorher ein Raster aus gleich breiten Spalten. Jede Kachel behielt
   ihr eigenes Seitenverhältnis, also bekam jede eine andere Höhe —
   das Blatt franste unten aus und wirkte unruhig.

   Jetzt setzt sich jede Reihe auf eine gemeinsame Höhe und läuft
   links wie rechts auf Kante. Der Kniff steckt in zwei Zeilen:
   Grundbreite UND Wachstum jeder Kachel sind proportional zu ihrem
   Seitenverhältnis (--g). Verteilt der Umbruch den freien Platz
   dann proportional, wächst jede Kachel um denselben Faktor —
   und damit haben alle in der Reihe exakt dieselbe Höhe, ohne dass
   ein einziges Bild beschnitten wird.

   Dasselbe Verfahren wie bei der Bildwand im Referenzen-Hero, dort
   in JavaScript gerechnet, hier vom Umbruch selbst erledigt.

   --g ist das Seitenverhältnis als ZAHL (--ar ist es als Bruch;
   aus einem Bruch kann CSS nicht rechnen, deshalb beide).
   ============================================================ */
.lsheet {
  --luecke: clamp(16px, 2vw, 26px);
  display: flex;
  flex-wrap: wrap;
  gap: var(--luecke);
}
.lframe {
  position: relative;
  /* Der Wachstumsfaktor ist absichtlich das Vierfache des
     Seitenverhältnisses. Flexbox verteilt den freien Platz nur
     anteilig, solange die Faktoren einer Reihe zusammen unter 1
     bleiben: Ein Hochformat mit dem Faktor 0,749 allein in seiner
     Reihe bekam nur 75 % des Rests und blieb auf dem Handy sichtbar
     schmaler als jede andere Kachel. Ein gemeinsamer Multiplikator
     hebt jede Reihensumme über 1, lässt die Verhältnisse
     untereinander aber unverändert — die Reihen sehen also überall
     genauso aus wie zuvor. */
  flex: calc(var(--g, 1.333) * 4) 1 calc(var(--g, 1.333) * 232px);
  /* Die Untergrenze darf nicht in die Verteilung eingreifen: Wird
     eine Kachel auf sie hochgezwungen, folgt sie dem Wachstum der
     Reihe nicht mehr und wird höher als ihre Nachbarn — auf Tiefbau
     standen so 342 px neben 287 px in derselben Reihe. 140 px ist
     die Breite der schmalsten Vorlage; keine Kachel wird also je
     kleiner gezeigt, als ihre Datei ist, und darüber bleibt allein
     das Seitenverhältnis massgebend. */
  min-width: 140px;
}
/* Der Auffüller der letzten Reihe.
   Bleibt in der letzten Reihe nur eine Kachel übrig, verteilt der
   Umbruch den freien Platz auf sie allein — auf Hochbau wuchs eine
   251 px breite Aufnahme so auf 1152 x 863 px, viermal so hoch wie
   ihre Nachbarn und maßlos vergrössert.

   Dieses leere Element steht am Ende und betrifft damit immer nur
   die letzte Reihe. Es wächst tausendfach stärker als jede Kachel,
   nimmt den Rest also vollständig auf und lässt die Kacheln bei
   ihrer Grundbreite stehen.

   Die Grundbreite von 300 px ist der Schalter: Der Auffüller passt
   nur dann noch in die letzte Reihe, wenn dort mindestens eine
   Kachelbreite frei ist — genau der Fall, in dem das Strecken
   entgleist. Fehlt weniger, passt er nicht mehr hinein, rutscht
   ohne Höhe in eine eigene Reihe, und die letzte Reihe füllt die
   Spalte wie bisher bündig aus (auf Spezialtiefbau wächst sie so
   weiterhin um das 1,19-fache auf volle Breite).

   In der eigenen Reihe bleibt ihr Reihenabstand als Leerraum unter
   der Galerie stehen — 26 px, weniger als die Spaltenfassung
   darunter ohnehin frei lässt.

   Der Faktor 40 gegen die 4 bis 11 einer Kachel lässt der letzten
   Reihe noch etwa ein Achtel des freien Platzes. Genug, dass sie
   die Höhe der Reihe darüber erreicht und wie ein Abschluss wirkt,
   zu wenig, um sie zu strecken: auf Tiefbau 267 px neben 277 px,
   auf Hochbau 278 px neben 271 px. */
.lsheet:not(.lsheet--frei)::after {
  content: '';
  flex: 40 1 300px;
  min-width: 0;
}
.lframe .shot {
  aspect-ratio: var(--ar, 4 / 3);
  transition: transform 620ms var(--ease);
}
.lframe:hover .shot { transform: translateY(-6px); }
.lframe figcaption {
  display: flex;
  align-items: baseline;
  gap: 12px;
  padding: 14px 2px 0;
  font-family: var(--f-mono);
  font-size: 0.68rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-mute);
  transition: color 300ms var(--ease);
}
.lframe .n { color: var(--blue-text); flex: 0 0 auto; }
.lframe:hover figcaption { color: var(--paper); }

/* --- Freies Raster ------------------------------------------
   Wo die Vorlagen sehr verschiedene Formate haben (Panorama neben
   Hochformat), zwingt ein festes 4:3 jedes zweite Bild in einen
   harten Beschnitt. Hier behält stattdessen jede Kachel ihr eigenes
   Seitenverhältnis; die Spalten gleichen die Höhen selbst aus.
   ------------------------------------------------------------ */
.lsheet--frei {
  display: block;
  columns: 3;
  column-gap: clamp(16px, 2vw, 26px);
}
.lsheet--frei .lframe {
  break-inside: avoid;
  margin: 0 0 clamp(22px, 2.6vw, 34px);
}
/* Panoramaformat trägt die volle Breite — als Aufmacher der Reihe */
.lframe--band { margin-bottom: clamp(22px, 2.6vw, 34px); }
@media (max-width: 900px) { .lsheet--frei { columns: 2; } }
@media (max-width: 560px) { .lsheet--frei { columns: 1; } }

/* ============================================================
   KÖRNUNGSVERGLEICH — die Materialprobe (nur Sand und Kies)

   Auf der ganzen Seite ist jedes Foto ein Zeichenraster. Hier
   nicht: Das Raster ersetzt Helligkeiten durch Zeichen und würde
   ausgerechnet das zerstören, worum es geht — Korngrösse und
   Kornform. Diese vier Aufnahmen sind deshalb die einzigen echten
   Fotos im Seiteninhalt. Der Bruch ist gewollt: Das Material zeigt
   sich als es selbst, alles andere bleibt Planzeichnung.

   Der zweite Gedanke steckt im Fenster. Die vier Proben stehen
   nicht in vier Bildrahmen nebeneinander, sondern in vier
   Ausschnitten aus einem gemeinsamen Abbildungsmassstab: Jede
   Aufnahme wird auf dieselbe feste Breite (--fenster) gerechnet,
   die Kachel schneidet davon nur unterschiedlich viel frei. Zieht
   man eine Probe auf, wächst also der Ausschnitt, nicht das Korn.
   Ein Vergrössern würde den Vergleich falsch machen — genau das
   passiert hier nicht.
   ============================================================ */
.ksieb {
  --hoehe: clamp(190px, 23vw, 290px);
  /* Muss mindestens so breit sein wie die breiteste aufgezogene
     Probe, sonst liefe das Bild an ihrem Rand aus. Die aufgezogene
     Probe misst 1,9 / (1,9 + 3 x 0,78) der Bandbreite, also gut
     45 % — bei 1152 px sind das 447 px. */
  --fenster: clamp(240px, 31vw, 460px);
  margin-bottom: clamp(30px, 4vw, 48px);
}
.ksieb-lead {
  max-width: 54ch;
  margin: 0 0 clamp(18px, 2.4vw, 28px);
  color: var(--text-mute);
}
.ksieb-band {
  display: flex;
  align-items: stretch;
  border: 1px solid var(--grey-line);
  background: var(--void);
}
.ksieb-probe {
  position: relative;
  /* Vier gleiche Viertel im Ruhezustand. Bewusst über die Breite
     gesteuert und nicht über einen Wachstumsfaktor: Die aufgezogene
     Probe wird damit GENAU so breit wie das Bildfenster. Über einen
     Faktor geriet sie auf 515 px gegen ein 446 px breites Fenster —
     die Aufnahme musste sich dehnen und der gemeinsame Massstab war
     hin, also genau der Punkt der ganzen Tafel. */
  flex: 0 1 25%;
  min-width: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  transition: flex-basis 720ms var(--ease);
}
/* Die berührte Probe gibt nicht nach; die anderen teilen sich den
   Rest, weil nur sie schrumpfen dürfen. */
.ksieb-band .ksieb-probe:hover,
.ksieb-band .ksieb-probe:focus-within {
  flex-basis: var(--fenster);
  flex-shrink: 0;
}

.ksieb-fenster {
  position: relative;
  display: block;
  height: var(--hoehe);
  overflow: hidden;
  background: var(--void);
}
/* Der Schnitt zwischen zwei Proben — eine Kante, keine Lücke.
   Die vier Materialien stossen aneinander wie Proben auf einem
   Brett, deshalb trennt sie nur die Papierfarbe. */
.ksieb-probe + .ksieb-probe .ksieb-fenster { border-left: 2px solid var(--grund); }
.ksieb-fenster img {
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  width: var(--fenster);
  /* base.css deckelt jedes Bild auf max-width:100%. Genau das
     würde hier das Fenster aufheben — die Aufnahme wäre wieder so
     breit wie ihre Kachel und der gemeinsame Massstab dahin. */
  max-width: none;
  /* Notbremse: Wird eine Probe doch breiter als das Fenster,
     dehnt sich lieber das Bild, als dass die Kachel ausläuft. */
  min-width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: filter 620ms var(--ease);
}
/* Die nicht berührten Proben treten zurück, ohne zu verschwinden */
.ksieb-band:hover .ksieb-probe:not(:hover) .ksieb-fenster img,
.ksieb-band:focus-within .ksieb-probe:not(:focus-within) .ksieb-fenster img {
  filter: saturate(0.55) brightness(0.94);
}

/* ---- Die Messleiste unter den Proben ----
   Der Strich läuft durch, die Teilstriche sitzen auf jeder
   Probengrenze und wandern mit, wenn eine Probe aufzieht. */
.ksieb-marke {
  position: relative;
  padding: 13px 12px 0 0;
  border-top: 1px solid var(--tinte);
  font-size: 0.86rem;
  line-height: 1.25;
  color: var(--tinte);
}
.ksieb-marke::before {
  content: '';
  position: absolute;
  left: 0; top: 0;
  width: 1px; height: 10px;
  background: var(--tinte);
}
.ksieb-probe:last-child .ksieb-marke::after {
  content: '';
  position: absolute;
  right: 0; top: 0;
  width: 1px; height: 10px;
  background: var(--tinte);
}
.ksieb-marke .n {
  display: block;
  margin-bottom: 5px;
  font-size: 0.64rem;
  letter-spacing: 0.2em;
  color: var(--blue);
}
/* Die berührte Probe bekommt ihren Teilstrich in Markenblau */
.ksieb-probe:hover .ksieb-marke::before,
.ksieb-probe:focus-within .ksieb-marke::before { background: var(--blue); height: 16px; }

.ksieb-achse {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  margin: 14px 0 0;
  font-size: 0.64rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--text-dim);
}
.ksieb-achse span:nth-child(2) { text-align: center; }

@media (max-width: 860px) {
  /* Vier Proben nebeneinander wären hier je 170 px breit — für
     einen Grössenvergleich zu wenig. Also zwei mal zwei, dann sind
     es 345 px. Das Aufziehen entfällt dabei: Es gäbe keinen Platz
     mehr, den die Nachbarn hergeben könnten. */
  .ksieb-band { flex-wrap: wrap; }
  .ksieb-probe { flex-basis: 50%; }
  .ksieb-band .ksieb-probe:hover,
  .ksieb-band .ksieb-probe:focus-within { flex-basis: 50%; flex-shrink: 1; }
  .ksieb-probe:nth-child(3) .ksieb-fenster { border-left: 0; }
  .ksieb-probe:nth-child(n+3) .ksieb-fenster { border-top: 2px solid var(--grund); }
  .ksieb-achse { font-size: 0.58rem; letter-spacing: 0.12em; }
}
@media (prefers-reduced-motion: reduce) {
  .ksieb-probe, .ksieb-fenster img { transition: none; }
}

/* ============================================================
   PREISLISTE — das einzige Papier auf der Seite

   Auf dieser Seite ist alles dunkel und jedes Foto ein Zeichen-
   raster. Genau deshalb braucht das Wichtigste keinen Rahmen und
   keinen Blinkeffekt: Ein echtes, helles Blatt ist hier der
   grösstmögliche Bruch und zieht den Blick von allein. Die dafür
   nötigen Farben (--doc-*) stehen seit Beginn in base.css und
   werden hier zum ersten Mal eingelöst.
   ============================================================ */
.lpreis {
  position: relative;
  display: grid;
  grid-template-columns: clamp(180px, 24%, 280px) 1fr;
  gap: clamp(28px, 5vw, 68px);
  align-items: center;
  padding: clamp(26px, 4vw, 54px);
  background: var(--doc-bg);
  color: var(--doc-text);
  box-shadow: 0 30px 70px -26px rgba(10,14,24,0.30);
}
/* Eckmarken wie auf einem Planblatt */
.lpreis::before, .lpreis::after {
  content: '';
  position: absolute;
  width: 18px; height: 18px;
  border: 1px solid var(--doc-line);
  pointer-events: none;
}
.lpreis::before { top: 12px; left: 12px; border-right: 0; border-bottom: 0; }
.lpreis::after { bottom: 12px; right: 12px; border-left: 0; border-top: 0; }

/* --- Das Blatt selbst --------------------------------------- */
.lpreis-blatt {
  position: relative;
  display: block;
  overflow: hidden;
  transform: rotate(-2.2deg);
  box-shadow: 0 18px 40px -12px rgba(10, 14, 24, 0.45);
  transition: transform 620ms var(--ease), box-shadow 620ms var(--ease);
}
.lpreis-blatt img { display: block; width: 100%; height: auto; }
.lpreis:hover .lpreis-blatt {
  transform: rotate(0deg) translateY(-8px) scale(1.02);
  box-shadow: 0 30px 60px -14px rgba(10, 14, 24, 0.55);
}
/* Lichtstreifen wandert einmal über das Blatt, wenn man hingeht */
.lpreis-glanz {
  position: absolute; inset: 0;
  pointer-events: none;
  background: linear-gradient(104deg,
    rgba(255,255,255,0) 38%, rgba(255,255,255,0.55) 50%, rgba(255,255,255,0) 62%);
  transform: translateX(-130%);
  transition: transform 900ms var(--ease);
}
.lpreis:hover .lpreis-glanz { transform: translateX(130%); }

/* --- Zwei Dokumente in einem Feld ----------------------------
   Preisliste und technisches Datenblatt liegen als Fächer
   nebeneinander. Beide stehen absolut übereinander, das Feld
   kostet die Karte also keine einzige Zeile Höhe — die Bedingung
   war, dass nichts mehr Platz braucht.

   Damit vom zweiten Blatt wirklich etwas zu sehen ist, bekommt die
   Spalte hier mehr Breite (30 % statt 24 %) und die Preisliste
   steht nur noch auf 76 % davon. Nur so kann das Datenblatt neben
   ihr stehen statt hinter ihr: sichtbar sind damit 44 % seiner
   Fläche statt vorher 18 % — gemessen bei 1440 px.

   Angefasst wird es über den benannten Verweis in der Spalte
   daneben; hier ist es reine Ansicht und für Screenreader und
   Tastatur unsichtbar. */
.lpreis--zwei { grid-template-columns: clamp(200px, 30%, 340px) 1fr; }
.lpreis-stapel { position: relative; }
.lpreis-stapel > .lpreis-blatt { position: relative; z-index: 1; width: 76%; }
/* Muss den Stapel mitnennen, sonst gewinnt die Regel darüber und
   das Beiblatt stünde im Fluss — es hängte sich dann unter die
   Preisliste und machte die Karte 200 px höher. */
.lpreis-stapel > .lpreis-blatt--bei {
  position: absolute;
  z-index: 0;
  top: 3%;
  /* Der Überstand nach rechts muss in den Spaltenabstand passen.
     Der wächst mit der Fensterbreite, die Spalte hat dagegen bei
     200 px einen Boden — eng wird es also um 768 px herum. Mit
     diesen Werten ragt das Blatt dort 28 px in einen 38 px breiten
     Abstand, bei 1440 px 43 px in einen von 68 px. Die Drehung
     verbreitert das umschliessende Rechteck mit, sie ist in den
     Zahlen enthalten. */
  left: 40%;
  width: 68%;
  transform: rotate(7.5deg);
  box-shadow: 0 14px 30px -12px rgba(10, 14, 24, 0.55);
}
/* Muss nach der allgemeinen Hover-Regel stehen: beide greifen
   gleich stark, die spätere gewinnt. Sonst richtete sich das
   Beiblatt beim Überfahren mit auf und verschwände hinter der
   Preisliste. Beim Überfahren fächern die beiden weiter auf. */
.lpreis:hover .lpreis-stapel > .lpreis-blatt--bei {
  transform: rotate(10.5deg) translate(12px, -8px);
}
.lpreis:hover .lpreis-stapel > .lpreis-blatt:not(.lpreis-blatt--bei) {
  transform: rotate(-4deg) translate(-6px, -8px) scale(1.02);
}

/* --- Knopfzeile mit Zweitdokument ---------------------------- */
.lpreis-reihe {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 18px clamp(20px, 3vw, 40px);
}
.lpreis-reihe .lpreis-knopf { flex: 0 0 auto; }
.lpreis-bei {
  /* Darf schrumpfen, damit der Verweis neben dem Knopf stehen
     bleibt statt darunter zu rutschen. Wird der Platz eng, bricht
     die Kleinschrift um; das kostet 14 px statt einer ganzen
     zweiten Zeile von 66 px. */
  flex: 1 1 200px;
  min-width: 0;
  padding-left: clamp(20px, 3vw, 40px);
  border-left: 1px solid var(--doc-line);
  text-decoration: none;
}
.lpreis-bei-t {
  display: block;
  font-size: 0.95rem;
  color: var(--doc-text);
}
/* Pfeil in Leserichtung — das Blatt öffnet sich, es lädt nicht
   herunter wie die Preisliste, deren Knopf nach unten zeigt. */
.lpreis-bei-t i {
  display: inline-block;
  width: 7px; height: 7px;
  margin-left: 9px;
  border-top: 2px solid currentColor;
  border-right: 2px solid currentColor;
  transform: translateY(-1px) rotate(45deg);
  transition: transform var(--t-hover);
}
.lpreis-bei-m {
  display: block;
  margin-top: 5px;
  font-size: 0.66rem;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--doc-mute);
}
.lpreis-bei:hover .lpreis-bei-t { color: #5A8EE7; }
.lpreis-bei:hover .lpreis-bei-t i { transform: translate(4px, -1px) rotate(45deg); }
.lpreis-bei:focus-visible { outline: 2px solid var(--doc-text); outline-offset: 6px; }

/* --- Angaben ------------------------------------------------- */
.lpreis-marke {
  display: inline-block;
  padding-top: 10px;
  border-top: 2px solid var(--red);
  font-size: 0.68rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--doc-mute);
}
.lpreis-inhalt h3 {
  margin: 14px 0 0;
  font-family: var(--f-display);
  font-weight: 700;
  font-size: clamp(1.9rem, 4.4vw, 3.1rem);
  line-height: 0.94;
  letter-spacing: 0.005em;
  text-transform: uppercase;
  color: var(--doc-text);
}
.lpreis-daten {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(112px, 1fr));
  gap: 0;
  margin: clamp(22px, 3vw, 32px) 0;
  border-top: 1px solid var(--doc-line);
}
.lpreis-daten > div {
  padding: 14px 14px 14px 0;
  border-bottom: 1px solid var(--doc-line);
}
.lpreis-daten dt {
  font-family: var(--f-mono);
  font-size: 0.62rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--doc-mute);
  margin-bottom: 6px;
}
.lpreis-daten dd {
  margin: 0;
  font-family: var(--f-mono);
  font-size: 0.92rem;
  color: var(--doc-text);
}

/* --- Tafel: die Datenzeile, wenn sie mehrzeilig wird ---------
   Die Datenzeile darüber trägt vier kurze Wertepaare. Auf
   Betonblocksteine sind es aber vier Zeilen mit je drei Werten —
   das ist eine Tabelle und soll auch eine sein, damit die Spalten
   untereinander stehen und vorgelesen werden können. */
.lpreis-tafel {
  width: 100%;
  margin: clamp(22px, 3vw, 32px) 0;
  border-collapse: collapse;
  font-family: var(--f-mono);
  text-align: left;
}
.lpreis-tafel th {
  padding: 0 18px 10px 0;
  border-bottom: 1px solid var(--doc-line);
  font-size: 0.62rem;
  font-weight: 400;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--doc-mute);
  white-space: nowrap;
}
.lpreis-tafel td {
  padding: 12px 18px 12px 0;
  border-bottom: 1px solid var(--doc-line);
  font-size: 0.92rem;
  color: var(--doc-text);
  white-space: nowrap;
}
.lpreis-tafel tr > *:last-child { padding-right: 0; }
@media (max-width: 560px) {
  /* Drei Spalten passen hier nicht mehr nebeneinander. Statt zu
     schrumpfen, bis nichts mehr lesbar ist, wird jede Zeile zum
     eigenen Block und die Spaltenköpfe wandern als Marke davor. */
  .lpreis-tafel, .lpreis-tafel tbody, .lpreis-tafel tr { display: block; width: 100%; }
  .lpreis-tafel thead { display: none; }
  .lpreis-tafel tr { padding: 12px 0; border-bottom: 1px solid var(--doc-line); }
  /* Volle Breite gilt nur für die Abmessung. Bekämen die beiden
     Nebenwerte sie auch, stünde jeder in einer eigenen Zeile —
     sie sollen aber zusammen eine bilden. */
  .lpreis-tafel td { display: block; padding: 0; border: 0; white-space: normal; }
  .lpreis-tafel td + td { margin-top: 4px; font-size: 0.78rem; color: var(--doc-mute); display: inline-block; }
  /* Als Rand, nicht als Leerzeichen im Text: Am Anfang eines
     inline-block fällt ein führendes Leerzeichen weg, es stand
     dann „1,50 to· 1,08 m²“ da. */
  .lpreis-tafel td + td + td::before { content: '·'; margin: 0 0.45em 0 0.35em; }
}

/* --- Knopf --------------------------------------------------- */
.lpreis-knopf {
  display: inline-flex;
  align-items: center;
  gap: 14px;
  padding: 16px 26px;
  background: var(--blue);
  color: var(--auf-farbe);   /* helle Schrift auf blauer Fläche */
  font-family: var(--f-mono);
  font-size: 0.74rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  text-decoration: none;
  transition: background var(--t-hover), transform var(--t-hover);
}
.lpreis-knopf i {
  width: 9px; height: 9px;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
  transition: transform var(--t-hover);
}
.lpreis-knopf:hover { background: #063a8c; }
.lpreis-knopf:hover i { transform: translateY(2px) rotate(45deg); }
.lpreis-knopf:focus-visible { outline: 2px solid var(--doc-text); outline-offset: 3px; }

.lpreis-ruf {
  margin: 18px 0 0;
  font-size: 0.92rem;
  color: var(--doc-mute);
}
/* Angaben, die nicht auf dem Blatt stehen und deshalb auch nicht
   in die Datenzeile darüber gehören — auf Transporte die beiden
   Sätze zu Sondermaßen und Genehmigungen. Sie standen vorher in
   einem eigenen Textblock, der dieselben Maße noch einmal
   aufzählte; die Maße hat jetzt die Karte, diese zwei Sätze
   bleiben Wort für Wort erhalten. */
.lpreis-notiz {
  margin: 18px 0 0;
  font-size: 0.92rem;
  line-height: 1.5;
  color: var(--doc-mute);
}
.lpreis-notiz + .lpreis-notiz { margin-top: 8px; }
.lpreis-ruf a {
  /* Diese Kachel ist die einzige dunkle Fläche der Seite. Das
     Markenblau #0846A8 kommt darauf nur auf 2,11:1 — gemessen. Auf
     Dunkel gilt das aufgehellte Blau, wie im ganzen alten System. */
  color: #5A8EE7;   /* 5,56:1 auf #101624 */
  text-decoration: none;
  border-bottom: 1px solid currentColor;
  white-space: nowrap;
}

@media (max-width: 720px) {
  .lpreis { grid-template-columns: 1fr; gap: 26px; }
  /* Der Stapel ist hier das Feld; ohne ihn greift die Grenze wie
     bisher direkt am Blatt (Spezialtiefbau, Sand und Kies). */
  .lpreis-blatt { max-width: 230px; }
  /* Der Fächer braucht mehr Feld als ein einzelnes Blatt, sonst
     schrumpft die Preisliste auf 76 % von 230 px. Untereinander
     ist rechts ohnehin Platz frei. */
  .lpreis-stapel { max-width: 310px; }
  .lpreis-stapel > .lpreis-blatt { max-width: none; }
  /* Hier gibt es keine Nachbarspalte mehr, in deren Abstand das
     Blatt hineinragen könnte — rechts steht nur noch der Rand der
     Karte. Bei 375 px hing es 14 px darüber hinaus. Also bleibt es
     jetzt vollständig im Feld; sichtbar sind davon 29 %. */
  .lpreis-stapel > .lpreis-blatt--bei { left: 32%; width: 62%; }
  .lpreis-bei { padding-left: 0; border-left: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .lpreis-blatt, .lpreis-glanz { transition: none; }
  .lpreis:hover .lpreis-blatt { transform: rotate(-2.2deg); }
  .lpreis:hover .lpreis-stapel > .lpreis-blatt--bei { transform: rotate(6.5deg); }
  .lpreis:hover .lpreis-glanz { transform: translateX(-130%); }
}

/* ============================================================
   DATENBLATT
   ============================================================ */
.ldata {
  border: 1px solid var(--grey-line);
  border-left: 2px solid var(--blue-lift);
  background: rgba(250,248,244,0.5);
  padding: clamp(22px, 3vw, 34px);
}
.ldata h4 {
  font-family: var(--f-mono);
  font-size: 0.68rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--blue-text);
  margin-bottom: 16px;
}
.ldata p { color: var(--text-mute); margin-bottom: 12px; }
.ldata strong { color: var(--paper); }

/* ============================================================
   GEWERKE-WECHSLER — die anderen sieben Leistungen
   Kein Schmuck, sondern ein Weg: Wer hier landet, kommt sonst nur
   über das Menü weiter. Gleiche Sprache wie die Leistungsliste
   oben — Mono-Nummer, Haarlinie, beim Überfahren rückt der Name.
   ============================================================ */
.lswitch {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  gap: 0 clamp(24px, 4vw, 64px);
  border-top: 1px solid var(--grey-line);
}
.lswitch a {
  display: flex;
  align-items: baseline;
  gap: 16px;
  padding: 20px 2px;
  border-bottom: 1px solid var(--grey-line);
  color: var(--text);
  text-decoration: none;
  font-family: var(--f-display);
  font-weight: 700;
  text-transform: uppercase;
  font-size: clamp(1.05rem, 1.6vw, 1.45rem);
  line-height: 1.1;
  transition: color 240ms var(--ease), padding-left 240ms var(--ease);
}
.lswitch a .n {
  flex: 0 0 auto;
  min-width: 2.6em;
  font-family: var(--f-mono);
  font-weight: 400;
  font-size: 0.66rem;
  letter-spacing: 0.16em;
  color: var(--blue-text);
  transition: color 240ms var(--ease);
}
.lswitch a .go {
  margin-left: auto;
  font-family: var(--f-mono);
  font-size: 0.7rem;
  color: var(--text-mute);
  opacity: 0;
  transform: translateX(-6px);
  transition: opacity 240ms var(--ease), transform 240ms var(--ease);
}
.lswitch a:hover { color: var(--paper); padding-left: 10px; }
.lswitch a:hover .n { color: var(--red-text); }
.lswitch a:hover .go { opacity: 1; transform: none; }

/* ============================================================
   ABSCHLUSS-AUFFORDERUNG
   ============================================================ */
.lcta { text-align: center; }
.lcta h2 {
  font-family: var(--f-display);
  font-weight: 700;
  text-transform: uppercase;
  font-size: clamp(2rem, 5vw, 3.8rem);
  line-height: 0.98;
  margin-bottom: 18px;
}
.lcta p { color: var(--text-mute); margin-bottom: 34px; }
.lcta-btns { display: flex; flex-wrap: wrap; gap: 14px; justify-content: center; }
.lcta-tel {
  margin-top: 30px;
  font-family: var(--f-mono);
  font-size: 0.72rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--text-mute);
}
.lcta-tel a {
  color: var(--paper);
  text-decoration: none;
  border-bottom: 1px solid var(--blue-lift);
  padding-bottom: 2px;
}
.lcta-tel a:hover { color: var(--blue-text); }

@media (max-width: 900px) {
  .lgrid, .lflow-wrap { grid-template-columns: 1fr; }
  .lflow-stage { position: relative; top: auto; margin-bottom: 26px; }
  .lstep { opacity: 1; }          /* ohne Pinnung kein Abdunkeln */
}
@media (max-width: 700px) {
  .lhero { min-height: 68svh; align-items: center; }
  .lhero .hero-plate { width: auto; max-width: none; }
  .lhero-facts { gap: 10px 20px; }
  .lhero-facts .v { font-size: 1.25rem; }
  .lsheet { grid-template-columns: repeat(auto-fill, minmax(108px, 1fr)); }
  .lframe { padding: 8px 8px 0; }
}
@media (prefers-reduced-motion: reduce) {
  .lhero .hero-rays { animation: none; }
  .lflow-frames img, .lstep, .lflow-bar i,
  .lframe img, .lframe figcaption, .lshot img { transition: none; }
  .lstep { opacity: 1; }
}


/* ============================================================
   ÜBERSCHRIFT: FOCUS-REVEAL  (Origin „focus-reveal")
   Jedes Zeichen kommt aus der Unschärfe, leicht vergrößert und
   angehoben, und rastet scharf ein — wie ein Objektiv, das
   fokussiert. js/site.js setzt die Verzögerung je Zeichen;
   `is-lit` kommt vom Einblend-Beobachter.

   Ruhezustand ist SCHARF und sichtbar: Ohne `is-split` (kein
   Skript) oder bei reduzierter Bewegung steht die Zeile normal
   da. Nur der Startzustand ist unscharf — und der gilt erst,
   wenn das Skript die Zeichen gebaut hat.
   ============================================================ */
.lhero [data-split].is-split .wd { display: inline-block; white-space: nowrap; }
.lhero [data-split].is-split .ch {
  display: inline-block;
  opacity: 0;
  filter: blur(14px);
  transform: translateY(0.24em) scale(1.22);
  transition: opacity 700ms cubic-bezier(0.16, 1, 0.3, 1),
              filter 700ms cubic-bezier(0.16, 1, 0.3, 1),
              transform 700ms cubic-bezier(0.16, 1, 0.3, 1);
  will-change: filter, transform, opacity;
}
.lhero [data-split].is-split.is-lit .ch {
  opacity: 1;
  filter: blur(0);
  transform: none;
}
/* Die Mono-Zeile darüber zieht als Haarlinie auf */
.lcrumb { position: relative; padding-bottom: 14px; }
.lcrumb::after {
  content: '';
  position: absolute;
  left: 0; bottom: 0; height: 1px; width: 100%;
  transform-origin: 0 50%;
  transform: scaleX(1);
  background: linear-gradient(90deg, var(--blue-lift), transparent 78%);
}
.lhero.is-ready .lcrumb::after { animation: crumbLine 900ms var(--ease) 120ms; }
@keyframes crumbLine { from { transform: scaleX(0); } to { transform: scaleX(1); } }

@media (prefers-reduced-motion: reduce) {
  .lhero [data-split].is-split .ch {
    opacity: 1; filter: none; transform: none; transition: none;
  }
  .lhero.is-ready .lcrumb::after { animation: none; }
}


@media (prefers-reduced-motion: reduce) {
  .lhero .hero-plate::before, .lhero .hero-plate::after { animation: none; }
  .lhero .hero-plate::before, .lhero .hero-plate::after { animation: none; }
}


/* ============================================================
   PANEL-ÜBERLAPPUNG AUSGLEICHEN — grundsätzlich, nicht pro Fall

   base.css gibt jedem [data-flow] `margin-top: -54px` (so schiebt
   sich ein Abschnitt sichtbar über den vorigen) und als Ausgleich
   `padding-bottom: 54px`. Beide Werte heben sich EXAKT auf —
   netto bleibt null Luft, und das nächste Panel schneidet in den
   letzten Inhalt. Gemessen auf dieser Seite: alle vier Abschnitte
   bei 0 bis −22 px.

   Hier bekommen sie 54 px Ausgleich PLUS 60 px echte Luft.
   Bewusst in leistung.css und nicht in base.css — dadurch gilt es
   nur für die Leistungsseiten, die abgenommene Startseite bleibt
   unberührt.

   Bei reduzierter Bewegung schaltet base.css die Überlappung ganz
   ab; dort zählt der Ausgleich nicht, es bleiben die 60 px Luft.
   ============================================================ */
[data-flow] { padding-bottom: 114px; }

/* AUSNAHME letzter Abschnitt: Auf ihn schiebt sich nichts mehr —
   der Fuß hat `margin-top: 0` und überlappt nicht. Die 54 px
   Ausgleich wären dort tote Fläche, und der Fuß bringt mit seinem
   eigenen padding-top schon 64 px mit. Deshalb hier nur ein
   knapper Abschluss. */
[data-flow]:last-of-type { padding-bottom: 44px; }

@media (prefers-reduced-motion: reduce) {
  [data-flow] { padding-bottom: 60px; }
  [data-flow]:last-of-type { padding-bottom: 44px; }
}


/* ============================================================
   FUSS — identisch zur Startseite

   Diese vier Regeln stehen in home.css, das auf den
   Leistungsseiten NICHT geladen wird. Ohne sie liegt das
   Sternenstaub-Canvas (.foot-fx) im normalen Fluss und schiebt
   den gesamten Fußinhalt nach unten — das war der große
   Leerraum oben im Fuß. Hier wortgleich übernommen, damit
   Startseite und Unterseiten denselben Fuß zeigen.
   ============================================================ */
.foot { position: relative; overflow: hidden; }
.foot-fx {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}
.foot-fx canvas { width: 100%; height: 100%; }
.foot .wrap { position: relative; z-index: 1; }


/* ============================================================
   SCROLL-HINWEIS

   Wie beim Fuß: Diese Regeln stehen in home.css, die auf den
   Leistungsseiten NICHT geladen wird. Ohne sie stand der Hinweis
   als `position: static` irgendwo am rechten Rand mitten im Bild
   (gemessen x = 1225 auf allen Unterseiten) statt unten mittig.

   js/site.js setzt beim Scrollen `is-gone` — nur das Ausblenden
   selbst fehlte hier. Der Ruhezustand ist sichtbar, das Verstecken
   passiert erst nach 60 px Scrollweg.
   ============================================================ */
.lhero .hero-scroll {
  position: absolute;
  left: 50%; bottom: 22px;
  transform: translateX(-50%);
  z-index: 5;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  transition: opacity 500ms var(--ease);
}
.lhero .hero-scroll .mono { font-size: 0.6rem; }
.lhero .hero-scroll i {
  display: block;
  width: 1px; height: 42px;
  background: linear-gradient(180deg, var(--blue-lift), transparent);
}
.lhero .hero-scroll.is-gone { opacity: 0; pointer-events: none; }

@media (max-width: 700px) {
  /* Auf schmalen Geräten füllt der Inhalt den Hero — der Hinweis
     läge sonst über dem Text. */
  .lhero .hero-scroll { display: none; }
}


/* ============================================================
   MENGENRECHNER (transportbeton, sand-und-kies)
   Die Rechenlogik steht in js/site.js — hier nur die Gestaltung
   im neuen System. Dunkle Eingabefelder mit hellem Text, weil
   der alte Rechner auf hellem Grund gestaltet war und auf dem
   dunklen Untergrund sonst unlesbar ist.
   ============================================================ */
.calc-card {
  border: 1px solid var(--grey-line);
  border-left: 2px solid var(--blue-lift);
  background: rgba(250,248,244,0.55);
  padding: clamp(24px, 3.4vw, 40px);
}
.calc-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: clamp(14px, 2vw, 24px);
}
.calc-field { display: flex; flex-direction: column; gap: 8px; }
.calc-field > span {
  font-family: var(--f-mono);
  font-size: 0.62rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--text-mute);
}
.calc-field select,
.calc-field input {
  font-family: var(--f-body);
  font-size: 1rem;
  padding: 13px 14px;
  color: var(--paper);
  background: rgba(250,248,244,0.72);
  border: 1px solid var(--grey-line);
  border-radius: 0;
  transition: border-color 220ms var(--ease), box-shadow 220ms var(--ease);
}
.calc-field input::placeholder { color: rgba(10,14,24,0.34); }
/* Aufklappliste: ohne das steht schwarz auf schwarz */
.calc-field select option { background: #FFFFFF; color: var(--tinte); }
.calc-field select:focus,
.calc-field input:focus {
  outline: none;
  border-color: var(--blue-lift);
  box-shadow: 0 0 0 3px rgba(46,111,224,0.18);
}

.calc-result {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(16px, 3vw, 40px);
  margin-top: clamp(22px, 3vh, 32px);
  padding-top: clamp(20px, 3vh, 28px);
  border-top: 1px solid var(--grey-line);
}
.calc-out { display: flex; flex-direction: column; gap: 6px; }
.calc-out-label {
  font-family: var(--f-mono);
  font-size: 0.62rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--text-mute);
}
.calc-out-value {
  font-family: var(--f-display);
  font-weight: 700;
  font-size: clamp(1.7rem, 3.4vw, 2.6rem);
  line-height: 1;
  color: var(--paper);
}
.calc-out-value .calc-vol,
.calc-out-value .calc-weight { color: var(--blue-text); }

.calc-hint {
  margin-top: 20px;
  color: var(--text-mute);
  font-size: 0.92rem;
  max-width: 62ch;
}
.calc-card .btn { margin-top: 22px; }

@media (prefers-reduced-motion: reduce) {
  .calc-field select, .calc-field input { transition: none; }
}

}
