/* ============================================================
   50 · SECTIONS — Seitenabschnitte
   ------------------------------------------------------------
   Sektionen komponieren Komponenten und setzen deren Rahmen
   (Hintergrund, Rhythmus, Raster). Sie greifen NICHT in die
   Innereien der Komponenten ein (CLAUDE.md) -- wo das noetig
   waere, bekommt die Komponente einen Modifier.

   Breakpoints: 600 / 768 / 1024 / 1280, nur min-width.
   ============================================================ */

/* ============================================================
   HERO
   ============================================================ */
.hero {
  /* Dunkle Flaeche: heller Fokusring (Rueckfall in 10-base.css). */
  --focus-ring: var(--amber-soft);
  position: relative;
  display: flex;
  align-items: flex-end;
  min-height: 100dvh;
  overflow: hidden;
  background: var(--green-deep);
}

.hero__media {
  position: absolute;
  inset: 0;
}

/* Bild und Video liegen uebereinander, nicht untereinander. Ohne Position
   stapelte der Fluss sie: Das Video stand unterhalb des Kopfes und war nie zu
   sehen -- gemessen auf der Startseite Bild -18..918, Video 900..1800 bei
   900px Kopfhoehe. Geladen wurde es trotzdem. */
.hero__media img,
.hero__media video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform-origin: center;
}

.hero__scrim {
  position: absolute;
  inset: 0;
  background: var(--scrim-hero);
}

.hero__content {
  position: relative;
  z-index: var(--z-content);
  width: 100%;
  padding-bottom: clamp(48px, 7vh, 96px);
}

.hero__title {
  /* Das Mass haelt die Ueberschrift zweizeilig und schlagkraeftig. Ein
     einzelnes Wort, das laenger ist als 14 Zeichen, passte damit aber nicht
     mehr in seine Zeile -- und weil .rmask fuer die Maske overflow:hidden
     braucht, wurde es wortlos abgeschnitten statt umzubrechen. min-content
     haelt die Zeile mindestens so breit wie ihr laengstes Wort; min-width
     sticht max-width, aber nur dort, wo ein Wort es verlangt (KI-049). */
  min-width: min-content;
  max-width: 14ch;
  color: var(--white);
  font-size: var(--fs-display-hero-sm);
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1.06;
}

.hero__title em {
  color: var(--amber-soft);
  font-style: normal;
}

.hero__row {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 40px;
  flex-wrap: wrap;
  margin-top: 36px;
}

.hero__sub {
  max-width: 38ch;
  color: var(--on-dark);
  font-size: var(--fs-600);
  font-weight: 500;
}

@media (min-width: 768px) {
  .hero__title {
    font-size: var(--fs-display-hero);
  }
}

@media (prefers-reduced-motion: no-preference) {
  .hero__media img {
    animation: fay-hero-zoom 22s var(--ease) forwards;
  }

  @keyframes fay-hero-zoom {
    from { transform: scale(1.1); }
    to   { transform: none; }
  }

  /* Eyebrow und Aktionszeile folgen der Ueberschrift zeitversetzt.
     Die Ueberschrift selbst nutzt die Utility .rmask. */
  .hero .eyebrow {
    opacity: 0;
    animation: fay-fade-in 0.7s var(--ease) 0.8s forwards;
  }

  .hero__row {
    opacity: 0;
    transform: translateY(16px);
    animation: fay-rise-in 0.8s var(--ease) 0.95s forwards;
  }

  @keyframes fay-fade-in {
    to { opacity: 1; }
  }

  @keyframes fay-rise-in {
    to { opacity: 1; transform: none; }
  }
}

/* ---------- Hero-Variante: Text neben Bewegtbild (Projektseite) ---------- */
/* Hoehe aus der Breite, nicht aus der Fensterhoehe. 88vh und 55vw sind bei
   einem 16:10-Fenster deckungsgleich (1440 x 900 ergibt beidemal 792px), aber
   88vh liess den Bildausschnitt mit der Fensterhoehe wandern -- derselbe
   Rechner zeigte bei anderem Fensterformat ein anderes Bild. Darauf laesst
   sich redaktionell nichts festlegen (KI-030). */
.hero--split {
  display: grid;
  /* minmax(0, …) statt 1fr: Sonst ist die Spalte mindestens so breit wie der
     laengste nicht umbrechbare Inhalt der Textspalte -- gemessen 421 px in
     einem 375 px breiten Fenster, der Ueberhang wurde abgeschnitten. */
  grid-template-columns: minmax(0, 1fr);
  align-items: stretch;
  min-height: clamp(560px, 55vw, 860px);
}

/* Der obere Abstand misst den Logoblock, nicht die Kopfleiste: Das Logo ragt
   unter sie hinaus und ist damit das unterste Element des Kopfes. Mit --nav-h
   sass die erste Zeile auf schmalen Fenstern 2 px UEBER der Logounterkante.

   Die Spalte richtet mittig aus; der Abstand nach oben verschiebt den Block
   deshalb nur um seine Haelfte. Gemessen bei 1440 px: --space-l ergibt 69 px
   zwischen Logo und Eyebrow, --space-xl 93 px, --space-2xl 107 px. Viel mehr
   traegt die Spalte nicht -- ab rund 114 px waechst der Kopf mit. */
.hero--split .hero__panel {
  /* Diese Spalte ist hell -- hier gilt wieder der dunkle Ring. */
  --focus-ring: var(--amber);
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: calc(var(--logo-mt) + var(--logo-h) + var(--space-2xl)) var(--gutter-wide) clamp(44px, 6vw, 76px);
  background: var(--paper);
}

/* Einspaltig folgt die Bildflaeche dem Medienformat. Ab 1024px wird es
   zurueckgenommen (siehe unten) -- dort steht die Hoehe der Zeile fest, und
   das Verhaeltnis wuerde daraus die BREITE rechnen und die Rasterspalte
   sprengen: gemessen 1188px in einer 840px breiten Spalte, der Ausschnitt
   sass dadurch links statt mittig. */
.hero--split .hero__media {
  position: relative;
  /* Ohne die Breitenangabe rechnet der Browser sie aus min-height und
     Verhaeltnis: 340 x 1,5 = 510 px in einer 375 px breiten Spalte. Der Kopf
     schnitt die ueberstehenden 135 px ab -- ein Viertel des Bildes samt der
     halben KI-Kennzeichnung. */
  width: 100%;
  aspect-ratio: var(--ar-media);
  min-height: 340px;
  overflow: hidden;
  background: var(--green-deep);
}

/* Kleiner als der Seitenkopf des Archivs: Der Titel steht hier in der
   schmalen linken Spalte (5fr von 12), lange Projektnamen brachen dort in
   --fs-display-page unruhig um. */
.hero__title--page {
  max-width: none;
  margin: 4px 0 24px;
  color: var(--green-deep);
  font-size: var(--fs-h2);
  line-height: 0.98;
}

.hero__title--page em {
  display: block;
  /* Deutlicher Abstand zum Namen -- bei zweizeiligen Namen sassen die
     Unterlaengen sonst fast auf der Zeile darunter. */
  margin-top: 0.55em;
  color: var(--amber);
  font-size: 0.46em;
  font-weight: 600;
  letter-spacing: 0;
  line-height: 1.25;
}

/* Ueberschrift und Beitext in der Textspalte: dieselbe Umkehrung wie im
   hellen Seitenkopf, nur ohne Schleier -- die Spalte steht auf Papier.
   .hero__title--page daneben ist der Sonderfall der Projektseite, deren
   Untertitel als kleineres <em> unter dem Namen steht. */
.hero--split .hero__title {
  max-width: none;
  color: var(--green-deep);
  font-size: var(--fs-h2);
}

.hero--split .hero__title em {
  color: var(--amber);
  font-style: normal;
}

.hero--split .hero__sub {
  max-width: 42ch;
  margin-top: var(--space-m);
  color: var(--ink);
}

.hero__cta {
  align-self: flex-start;
  margin-top: 28px;
}

@media (min-width: 1024px) {
  .hero--split {
    grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  }

  /* Zweispaltig bestimmt die Spaltenteilung die Flaeche, nicht das
     Medienformat. Das Verhaeltnis liegt damit zwischen 1,06 und 1,30 -- es
     haengt aber nur noch an der Fensterbreite, nicht mehr an ihrer Hoehe.
     Was hier beschnitten wird, entscheidet der Fokuspunkt. */
  .hero--split .hero__media {
    aspect-ratio: auto;
  }

  .hero--split .hero__panel {
    position: relative;
  }

  .hero__cta {
    position: absolute;
    left: var(--gutter-wide);
    bottom: clamp(28px, 4vw, 52px);
    margin-top: 0;
  }

  /* Die Schaltflaeche steht ausserhalb des Flusses und kann den mittig
     ausgerichteten Textblock deshalb nicht wegdruecken. Der Fussraum haelt
     ihn oberhalb: Schaltflaechenhoehe plus ihr eigener Abstand nach unten.
     Nur mit Schaltflaeche -- ohne sie bliebe der Kopf sonst unten hohl. */
  /* Zweistufig, weil .hero--split .hero__panel darueber steht: Ein einstufiger
     Modifier haette die Polsterung nicht erreicht. */
  .hero--split .hero__panel--cta {
    padding-bottom: calc(clamp(28px, 4vw, 52px) + var(--space-xl));
  }
}

/* ---------- Hero-Variante: Seitenkopf ueber Bild (Archiv) ---------- */
/* Kuerzer als der Seitenkopf der Startseite: hier folgt unmittelbar
   Inhalt, ein volles Ansichtsfenster waere eine Huerde.

   Bewusst KEIN --ar-media: Ein Band im Medienformat waere bei 1440px 960px
   hoch und damit genau die Huerde, die der Absatz oben vermeidet. Aus der
   Fensterhoehe wird die Breite -- 52vh und 32,5vw sind bei 16:10
   deckungsgleich (je 468px), aber das Verhaeltnis haengt nicht mehr am
   Fensterformat (KI-030). Beschnitten wird hier senkrecht; dafuer ist der
   Fokuspunkt zustaendig, nicht das Format.

   .hero--flat gibt dasselbe Mass dem zweigeteilten Kopf einer Seite: Alle
   Unterseiten sollen gleich hohe Koepfe haben (Kundenwunsch 2026-08-20). Nur
   die Projekteinzelseite bleibt beim hoeheren .hero--split -- dort steht der
   Kopf fuer sich und traegt zusaetzlich Adresse, Kartenlink und Schaltflaeche.
   Die Zeile steht deshalb hier und nicht zweimal. */
.hero--page {
  min-height: clamp(420px, 32.5vw, 620px);
}

/* Der zweigeteilte Kopf einer Seite ist so hoch wie das Band -- gemessen,
   nicht gerechnet: Beim Band schiebt der Fliesstext ueber dem Bild die Hoehe
   ueber das Mindestmass (623 px bei 1440 px statt 468 px), die schmale
   Textspalte daneben tut das nicht. Mit demselben Mindestmass blieb der Kopf
   deshalb bei 544 px. Das hoehere Mindestmass gleicht genau diesen Unterschied
   aus und trifft dieselben rund 630 px (Kundenwunsch 2026-08-20).

   Hoeher bleibt nur die Projekteinzelseite (.hero--split ohne --flat): Ihre
   Textspalte traegt zusaetzlich Adresse, Kartenlink und Schaltflaeche. */
.hero--flat {
  min-height: clamp(460px, 44vw, 640px);
}

/* Auf dem Telefon traegt der Kopf der drei Unterseiten gar kein Medium mehr --
   weder Video noch Standbild. Er ist dort ein Band, an dem man vorbeiscrollt:
   Das laufende Bild stoert, und das Standbild kostet nur Hoehe, ohne etwas zu
   sagen. Was bleibt, ist die Ueberschrift mit ihrem Beitext (Zuruf
   2026-08-27, KI-054).

   Der ganze .hero__media und nicht seine Kinder: So faellt auch die Flaeche
   weg, die er im Raster einnimmt. Ausgeblendet wuerden nur Bild und Video,
   bliebe seine 340px hohe gruene Kachel stehen.

   display: none und nicht opacity: Das Video traegt nur ein data-src, den src
   haengt lazyVideo() erst an, wenn der IntersectionObserver es schneiden
   sieht. Ein ausgeblendetes Element schneidet nie -- das Video wird damit gar
   nicht erst geladen. Der Vermerk zur KI-Herkunft verschwindet mit: Er haengt
   an .is-playing, und was nicht laeuft, spielt auch nicht.

   .hero--flat und nicht .hero--split: Der Kopf der Projekteinzelseite traegt
   das Kachelvideo (KI-029) und behaelt es -- er ist der einzige zweigeteilte
   Kopf ohne diesen Modifier. */
@media not all and (min-width: 768px) {
  .hero--flat .hero__media {
    display: none;
  }
}

/* --scrim-hero verdunkelt unten, weil dort der Text der Startseite steht.
   Hier steht er oben -- auf einem hellen Bild kam die Schrift dort auf
   1,2 : 1. --scrim-page dreht den Verlauf um und haelt die 4,5 : 1 ein. */
.hero--page .hero__scrim {
  background: var(--scrim-page);
}

/* Der Abstand nach oben misst nicht die Kopfleiste, sondern den Logoblock:
   Er ragt bewusst unter die Leiste hinaus und ist damit das unterste Element
   des Seitenkopfs. Mit --space-l stand die Brotkrume ab 1024 px darunter. */
.hero--page .hero__content {
  padding-top: calc(var(--nav-h) + var(--space-2xl));
  padding-bottom: var(--space-xl);
}

.hero--page .hero__title {
  max-width: 16ch;
  font-size: var(--fs-display-page);
}

/* Volle Deckkraft statt --on-dark: Der durchscheinende Weisston kostet rund
   ein Fuenftel des Kontrasts. Auf einem Foto ist das der Unterschied
   zwischen 3,6 : 1 und 5,4 : 1. */
.hero--page .hero__sub {
  margin-top: var(--space-s);
  color: var(--white);
}

/* ============================================================
   STATS — Einleitung und Kennzahlen
   ============================================================ */
.stats {
  position: relative;
  overflow: hidden;
  background: var(--cream);
}

.stats__grid {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: 1fr;
  gap: 48px;
  align-items: center;
  padding: var(--space-3xl) 0;
}

/* Vorspanntexte stehen im leichten Schnitt, nicht im halbfetten des
   Entwurfs (KI-033). Bei 22-30 px wirkte 600 als Textblock zu draengend --
   Manrope ist eine Variable Font mit Bereich 200-800, der leichtere Schnitt
   kostet keine zusaetzliche Datei. */
.stats__lead {
  color: var(--ink);
  font-size: var(--fs-lead);
  font-weight: 400;
  line-height: 1.4;
  letter-spacing: -0.015em;
}

.stats__lead strong {
  color: var(--green);
  font-weight: 800;
}

.stats__cells {
  display: grid;
  grid-template-columns: 1fr;
  gap: 28px;
}

.stats__cell {
  padding: 24px 0 0;
  border-top: 1px solid var(--line-green);
}

.stats__cell:first-child {
  padding-top: 0;
  border-top: 0;
}

/* Kein Umbruch: Eine Kennzahl ist eine Angabe. Eine Spanne wie "25-150"
   brach am Halbgeviertstrich um und stand zweizeilig ueber ihrer Einheit. */
.stats__num {
  display: flex;
  align-items: flex-start;
  color: var(--green);
  font-size: var(--fs-stat);
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1;
  white-space: nowrap;
}

/* Waehrungszeichen: eine Spur Luft zur Zahl, sonst kleben sie aneinander. */
.stats__num .prefix {
  margin-right: 0.06em;
}

.stats__num sup {
  margin-top: 0.1em;
  color: var(--amber);
  font-size: 0.5em;
  font-weight: 800;
}

.stats__num .unit {
  align-self: flex-end;
  margin: 0 0 0.18em 0.12em;
  color: var(--amber);
  font-size: 0.42em;
  font-weight: 800;
  letter-spacing: 0;
}

.stats__label {
  margin-top: 14px;
  color: var(--ink-60);
  font-size: var(--fs-200);
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

@media (min-width: 768px) {
  .stats__cells {
    grid-template-columns: repeat(3, 1fr);
    gap: 0;
  }

  .stats__cell {
    padding: 8px clamp(16px, 1.6vw, 24px);
    border-top: 0;
    border-left: 1px solid var(--line-green);
  }

  .stats__cell:first-child {
    padding-top: 8px;
  }
}

/* Erst ab 1280 stehen Text und Kennzahlen nebeneinander. Zwischen 1024 und
   1280 bliebe fuer die drei Zahlen zu wenig Breite -- die laengste Angabe
   muesste kleiner gesetzt werden als auf dem Tablet daneben. */
@media (min-width: 1280px) {
  .stats__grid {
    grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    gap: var(--gap-grid);
  }
}

/* ============================================================
   SERVICES — Leistungen
   ============================================================ */
.services {
  padding: var(--space-4xl) 0 var(--space-2xl);
}

.services__head {
  max-width: 900px;
  margin-bottom: var(--space-xl);
}

.scols {
  display: grid;
  grid-template-columns: 1fr;
}

.scols .scol + .scol {
  margin-top: 28px;
  padding-top: 32px;
  border-top: 1px solid var(--line);
}

.services__more {
  display: flex;
  justify-content: flex-end;
  margin-top: clamp(28px, 3.5vw, 48px);
}

/* Vier Leistungen seit dem 2026-09-17 (KI-064), vorher drei. Deshalb zwei
   Spalten ab Tablet und vier ab Desktop -- vier gehen durch beides auf, drei
   Spalten haetten die vierte Kachel allein in eine zweite Reihe gestellt.

   Die Trennlinien sind die Rasterfuge selbst: ein Pixel Abstand auf der
   Linienfarbe, den die Kacheln mit ihrem eigenen Grund abdecken. Ein
   border-left an .scol + .scol -- so stand es hier bis dahin -- setzt die
   Linie an jede Kachel ausser der ersten und damit auch an den Anfang der
   zweiten Reihe, wo keine hingehoert. Die Fuge weiss von sich aus, wo eine
   Kante ist, und bleibt richtig, wenn eine fuenfte Leistung dazukommt. */
@media (min-width: 768px) {
  /* minmax(0, …) statt 1fr, wie schon bei .hero--split: 1fr ist
     minmax(auto, 1fr), und eine Spalte wird damit nie schmaler als ihr
     laengster unteilbarer Inhalt. „Projektentwicklung" -- 18 Zeichen ohne
     Fuge in der Ueberschriftsgroesse -- zog seine Spalte deshalb auf Kosten
     der drei anderen auf: gemessen 38,67px Unterschied bei 1920px, 24,41px
     bei 1024px. Mit minmax(0, 1fr) sind alle vier gleich breit; dass das
     Wort dann umbricht, regelt die Silbentrennung an .scol__name. */
  .scols {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1px;
    background: var(--line);
  }

  .scols .scol + .scol {
    margin-top: 0;
    padding-top: clamp(28px, 3vw, 44px);
    border-top: 0;
  }
}

/* Vier Spalten erst ab 1280px und nicht schon ab 1024px: Bei 1024px blieben
   je Kachel 169,6px Textbreite, und „Service Development" braucht 10,23px je
   Pixel Schriftgroesse -- die Ueberschrift haette auf 16px gemusst, einen
   Pixel ueber dem Fliesstext daneben. Ab 1280px sind es 213,1px und 20px
   Schrift passen mit Reserve. Der Preis: 1024 bis 1279px stehen die vier
   Kacheln 2x2 (KI-064). */
@media (min-width: 1280px) {
  .scols {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

/* ============================================================
   CLAIM — Aussagenband mit Bewegtbild
   ============================================================ */
.claim {
  /* Dunkle Flaeche: heller Fokusring (Rueckfall in 10-base.css). */
  --focus-ring: var(--amber-soft);
  position: relative;
  overflow: hidden;
  padding: var(--space-5xl) 0;
  background: var(--green);
}

.claim::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  z-index: var(--z-overlay);
  height: 1px;
  background: var(--line-light);
}

.claim__video {
  position: absolute;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: grayscale(1) contrast(1.05);
}

.claim__tint {
  position: absolute;
  inset: 0;
  z-index: var(--z-tint);
  background: var(--green);
  opacity: 0.82;
}

.claim > .container {
  position: relative;
  z-index: var(--z-content);
}

.claim__text {
  max-width: 22ch;
  margin: 0 auto;
  color: var(--white);
  font-size: var(--fs-display-claim);
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.18;
  text-align: center;
}

.claim__text em {
  color: var(--amber-soft);
  font-style: normal;
}

/* Wortweiser Aufstieg. Der Index --wi wird beim Aufsplitten per JS gesetzt;
   ein berechneter Index laesst sich nicht als Klasse abbilden. */
.claim__text .w {
  display: inline-block;
  overflow: hidden;
  vertical-align: top;
  padding-bottom: 0.16em;
  margin-bottom: -0.16em;
}

.claim__text .w > span {
  display: inline-block;
  transform: translateY(115%);
  transition: transform 0.65s var(--ease);
  transition-delay: calc(var(--wi) * 65ms);
}

.claim__text.is-in .w > span {
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  .claim__text .w > span {
    transition: none;
  }
}

/* ============================================================
   PROJECTS — Mosaik
   ============================================================ */
.projects {
  padding: var(--space-4xl) 0 0;
}

.projects__head {
  margin-bottom: clamp(36px, 4.5vw, 64px);
}

.pmosaic {
  display: grid;
  grid-template-columns: 1fr;
  gap: 2px;
  margin-inline: calc(50% - 50vw);
  width: 100vw;
  background: var(--line);
}

/* Das Raster bestimmt die Groesse seiner Kacheln -- einspaltig im Breitformat,
   im Mosaik dann ueber die Rasterzeilen. Das ist Aufgabe des Rasters; die
   Innereien der Komponente bleiben unberuehrt. */
.pmosaic .pcard {
  min-height: 0;
  aspect-ratio: var(--ar-media);
}

.pmosaic .pcard--link {
  min-height: 180px;
  aspect-ratio: auto;
}

@media (min-width: 1024px) {
  .pmosaic {
    grid-template-columns: 2fr 1fr;
  }

  /* min-height: 320px war dasselbe Verhaeltnis, nur als Pixelwert notiert:
     bei 1440px ist die Kachel 479px breit, und 479 / 1,5 = 320. Als
     Verhaeltnis gilt es in jeder Breite statt nur in der einen (KI-033). */
  .pmosaic .pcard {
    min-height: 0;
    aspect-ratio: var(--ar-media);
  }

  /* Kein eigenes Verhaeltnis und keine eigene Mindesthoehe: Die grosse Kachel
     spannt drei Rasterzeilen und wird vom Raster gestreckt, ihre Hoehe ist
     also die Summe der rechten Spalte. Beide Angaben blieben wirkungslos und
     behaupteten eine Steuerung, die es nicht gibt. Mit dem Verhaeltnis auf den
     kleinen Kacheln folgt sie ihnen -- 1,00 bis 1,19 statt vorher 0,79 bis 1,48.

     min-height: 100% stand hier und war nicht nur ueberfluessig, sondern
     schaedlich: Die Prozentangabe bezieht sich auf die Rasterflaeche, deren
     Hoehe erst aus den Zeilen entsteht, die gerade berechnet werden. WebKit
     loest diesen Zirkel einmal auf und rechnet ihn beim Verkleinern des
     Fensters nicht neu. Die Kacheln schrumpfen ueber ihr aspect-ratio mit der
     Breite, die Mosaikhoehe blieb stehen, und die Differenz verteilte sich als
     Balken auf die drei Rasterzeilen -- von 1440px auf 1024px gezogen waren
     das 64px unter jeder rechten Kachel, bis zum Neuladen. Gemessen in
     WebKit; Blink war nie betroffen. */
  .pmosaic .pcard--featured {
    grid-row: span 3;
    aspect-ratio: auto;
  }

  /* Die Textkachel traegt kein Bild -- sie bleibt bei ihrer festen Hoehe und
     bestimmt damit die dritte Rasterzeile. */
  .pmosaic .pcard--link {
    min-height: 220px;
    aspect-ratio: auto;
  }
}

/* ---------- Gleichmaessiges Raster (Archiv) ----------
   Zwei Unterschiede zum Mosaik, beide durch den Filter begruendet:

   1. Gleich grosse Kacheln. Das Mosaik betont jede vierte -- diese Betonung
      wanderte mit jeder Auswahl.
   2. Die Trennlinien zeichnen die Kacheln selbst (Rahmen in .pcard--stacked)
      statt das Raster ueber Fugen und Hintergrund. Sobald eine Auswahl keine
      volle Reihe fuellt, erschiene die leere Rasterzelle sonst als grosser
      grauer Block und saehe aus wie eine fehlende Kachel.

   Die Kachel selbst bleibt dieselbe Komponente. */
.pgrid {
  display: grid;
  grid-template-columns: 1fr;
}

/* Die Kacheln bestimmen ihre Hoehe hier selbst (.pcard--stacked): einspaltig
   als Zeile mit Bild links und Text rechts, ab zwei Spalten das Bild im festen
   Seitenverhaeltnis mit dem Text darunter. Das Raster gibt nur Spalten vor. */

/* Oben genuegt weniger Luft als auf der Startseite: Dort steht das Mosaik
   unter einem randlosen Abschnitt, hier bringt der Abschnitt darueber
   seinen eigenen Fussabstand mit. */
.projects--archive {
  padding-top: var(--space-l);
  padding-bottom: var(--space-4xl);
}

@media (min-width: 600px) {
  .pgrid {
    grid-template-columns: 1fr 1fr;
  }
}

@media (min-width: 1024px) {
  .pgrid {
    grid-template-columns: repeat(3, 1fr);
  }
}

/* ============================================================
   NEWS
   ============================================================ */
.news {
  padding: var(--space-4xl) 0;
  background: var(--paper);
}

.news__head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 32px;
  flex-wrap: wrap;
  margin-bottom: clamp(36px, 4.5vw, 60px);
}

/* Ohne waagerechte Linien: Die Meldungen stehen frei im Abschnitt, getrennt
   nur durch den senkrechten Strich zwischen den Spalten (Kundenentscheidung
   2026-08-12, KI-026 -- der Entwurf hatte oben und unten eine Linie). */
.news__grid {
  display: grid;
  grid-template-columns: 1fr;
}

@media (min-width: 768px) {
  .news__grid {
    grid-template-columns: 1fr 1fr;
  }

  .news__grid .nitem:nth-child(odd) {
    padding-right: var(--space-l);
    border-right: 1px solid var(--line);
  }

  .news__grid .nitem:nth-child(even) {
    padding-left: var(--space-l);
  }
}

/* ---------- Varianten: Uebersicht und Fuss der Einzelansicht ---------- */
/* Beide folgen unmittelbar auf Inhalt, der seinen Fussabstand schon mitbringt
   -- der volle Sektionsabstand der Startseite waere dort das zweite Mal. */
/* Die Meldungen einer Projektseite schliessen an den Inhalt darueber an und
   brauchen deshalb weniger Vorlauf als ein eigener Abschnitt. */
.news--related {
  padding-top: var(--space-2xl);
}

/* Die Meldungsuebersicht traegt seit dem 2026-08-21 keinen Seitenkopf mehr
   (KI-050). Sie ist damit das erste Element der Seite -- und die Kopfleiste
   liegt fest darueber.

   Der Vorlauf misst deshalb die Leiste mit, statt sich auf einen Abstand zu
   verlassen: --space-3xl schrumpft auf schmalen Fenstern auf 72 px und ist
   dort niedriger als die 76 px hohe Leiste, die erste Zeile begaenne also
   dahinter. */
.news--archive {
  padding-top: calc(var(--nav-h) + var(--space-l));
}

/* Die neueste Meldung steht in voller Laenge und im Layout der Einzelansicht.
   Die Linie trennt sie vom Kartenraster darunter -- ohne sie liefe der
   Fliesstext ohne Zaesur in die erste Kachel. */
.news__lead {
  margin-bottom: var(--space-2xl);
  padding-bottom: var(--space-2xl);
  border-bottom: 1px solid var(--line);
}


/* Grundform zweispaltig -- so stehen die beiden Meldungen unter der
   Leitmeldung und die vier am Fuss einer Einzelansicht. Der Modifier geht
   eine Stufe weiter, statt die Grundregel zurueckzunehmen. */
.news__cards {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0 var(--space-l);
}

@media (min-width: 768px) {
  .news__cards {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 1024px) {
  .news__cards--three {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

/* ============================================================
   CONTACT
   ============================================================ */
.contact {
  padding: var(--space-5xl) 0;
  border-top: 1px solid var(--line);
}

.contact__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 40px;
  align-items: center;
}

.contact__aside {
  display: grid;
  justify-items: stretch;
}

.contact__line {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 20px;
  margin: 0;
  padding: 20px 2px;
  border-bottom: 1px solid var(--line);
  color: var(--ink-60);
  font-size: var(--fs-500);
  font-weight: 600;
}

.contact__line:first-of-type {
  border-top: 1px solid var(--line);
}

.contact__line a {
  position: relative;
  color: var(--green);
  font-weight: 800;
  letter-spacing: -0.01em;
  transition: color var(--dur-fast);
}

.contact__line a::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: -3px;
  width: 100%;
  height: 1px;
  background: var(--amber);
  transform: scaleX(0);
  transform-origin: right;
  transition: transform 0.35s var(--ease);
}

.contact__line a:hover {
  color: var(--amber-deep);
}

.contact__line a:hover::after {
  transform: scaleX(1);
  transform-origin: left;
}

.contact__btn {
  justify-self: start;
  margin-top: 34px;
  padding: 18px 34px;
}

@media (min-width: 1024px) {
  .contact__grid {
    grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
    gap: var(--gap-grid);
  }
}
