
/* ============================================================
   Ferro & Partner Ziviltechniker GesmbH

   Aufbau wie im Bestand: drei Gewerke-Spalten fuellen sofort den
   Bildschirm, rechts steht der Briefkopf als feste Spalte mit
   Kontakt und Navigation. Die Verbesserungen stecken innerhalb
   dieser Struktur, nicht an ihrer Stelle.

   Kein Framework, keine Fremdanfrage zur Laufzeit. Die Symbole
   sind Phosphor Icons (MIT) und liegen als Inline-Sprite in der
   Datei, damit die Datenschutzzusage im Fuss stimmt.
   ============================================================ */

/* ---------- 1. Tokens ---------- */
:root{
  color-scheme: light dark;

  /* --red ist exakt der Rotton aus der Logodatei (gemessen #EC193A)
     und traegt alle nicht-textlichen Markenelemente.
     Weisse Schrift darauf ergibt 4,41:1 und verfehlt WCAG AA knapp,
     deshalb --red-aa (3 % dunkler, 4,65:1) fuer Flaechen mit Text
     und --red-text (5,09:1) fuer rote Schrift. */
  --red:#ec193a;
  --red-aa:#e51838;
  --red-text:#d91735;
  --red-press: color-mix(in oklab, #e51838 84%, #000);

  --paper:#ffffff;
  --surface:#f6f5f3;
  --surface-2:#ebe9e5;
  --ink:#111111;
  --ink-2:#56544f;
  --ink-3:#6f6c66;
  --line:#dcd9d4;

  /* Vier gleich breite Spalten: 3 Gewerke + Briefkopf, wie im Bestand. */
  /* Gemessen: ab etwa 1440 px Fensterbreite begrenzte nicht mehr die
     Fensterhoehe das Logo, sondern die Spalte selbst - 84 % von 277 px
     Innenbreite. Auf grossen Bildschirmen darf die feste Spalte deshalb
     breiter werden, damit die Visitenkarte mitwaechst. Bis 1440 px
     bleibt es bei 360 px, dort aendert sich nichts. */
  --sidebar-w: min(25vw, 420px);

  --space-2xs: .5rem;
  --space-xs:  clamp(.6rem, .5rem + .3vw, .9rem);
  --space-s:   clamp(.9rem, .75rem + .5vw, 1.4rem);
  --space-m:   clamp(1.4rem, 1.1rem + 1.1vw, 2.2rem);
  --space-l:   clamp(2.4rem, 1.9rem + 1.9vw, 3.8rem);
  --space-xl:  clamp(4rem, 3rem + 3.4vw, 6.5rem);

  --fs-micro:   clamp(.69rem, .67rem + .08vw, .78rem);
  --fs-sub:     clamp(.78rem, .75rem + .13vw, .9rem);
  --fs-base:    clamp(.94rem, .91rem + .16vw, 1.06rem);
  --fs-h3:      clamp(1.15rem, 1rem + .6vw, 1.7rem);
  --fs-h2:      clamp(1.5rem, 1.2rem + 1.3vw, 2.5rem);

  /* Shape Consistency Lock: durchgehend scharfkantig. */
  --radius: 0;

  --ease: cubic-bezier(.16,1,.3,1);
}

@media (prefers-color-scheme: dark){
  :root{
    --paper:#121211;
    --surface:#1a1a18;
    --surface-2:#242422;
    --ink:#f2f1ee;
    --ink-2:#b3b0a9;
    --ink-3:#97948d;
    --line:#302f2c;
    --red-text:#ff5670;
  }
  /* Fuer die dunkle Darstellung liegt eine eigene Logofassung bereit, in
     der Schwarz und Weiss getauscht sind. Das Rot der Bildmarke und der
     weisse Adler darin bleiben unveraendert. Die weisse Traegerflaeche
     entfaellt damit, die Marke steht direkt auf dem dunklen Grund. */
}

/* ---------- 2. Reset ---------- */
*,*::before,*::after{ box-sizing:border-box; }
*{ margin:0; padding:0; }
html{ -webkit-text-size-adjust:100%; scroll-behavior:smooth; }
@media (prefers-reduced-motion: reduce){ html{ scroll-behavior:auto; } }
body{
  background:var(--paper); color:var(--ink);
  font-family:'Century Gothic','Futura','Avenir Next',-apple-system,BlinkMacSystemFont,sans-serif;
  font-size:var(--fs-base); line-height:1.55;
  -webkit-font-smoothing:antialiased;
  /* clip statt hidden: hidden macht den Body zum Scroll-Container und
     haengt jedes position:sticky daran auf statt an den Viewport. */
  overflow-x:clip;
}
img,svg{ display:block; max-width:100%; }
img{ height:auto; }
a{ color:inherit; text-decoration:none; }
button,input,select,textarea{ font:inherit; color:inherit; }
:where(a,button,input,select,textarea,[tabindex]):focus-visible{
  outline:3px solid var(--red); outline-offset:2px;
}
.vh{
  position:absolute!important; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip:rect(0,0,0,0); white-space:nowrap; border:0;
}
.icon{ width:1em; height:1em; fill:currentColor; flex:none; }

/* ---------- 3. Gewerke-Raster ----------
   Drei gleich breite Spalten, rechts bleibt exakt die Breite des
   Briefkopfs frei. Anders als im Bestand scrollt die Seite als
   Ganzes: die Spalten sind keine eigenen Scroll-Container mehr,
   das Mausrad bleibt also nicht in einer Spalte haengen. */
.cols{
  display:grid;
  grid-template-columns:repeat(3, minmax(0,1fr));
  gap:var(--space-m);
  height:100vh;                  /* exakt ein Bildschirm, wie im Bestand -
                                    vh statt dvh aus demselben Grund wie
                                    bei der festen Spalte rechts */
  /* Oben derselbe Abstand wie in der festen Spalte rechts (.info), damit
     die drei Balken auf einer Linie mit dem Briefkopf beginnen. Ohne ihn
     klebten sie am oberen Fensterrand - und weil der Balken in seiner
     Spalte klebt (sticky), sprang er beim Scrollen wieder dorthin. */
  padding:clamp(.4rem, 1.6vh, var(--space-m)) 0 0 var(--space-l);
  padding-right:calc(var(--sidebar-w) + var(--space-l));
  position:relative;
}
/* Jede Gewerke-Spalte scrollt fuer sich, Scrollbalken ausgeblendet.
   Das ist die Signatur der Seite und bleibt unveraendert. */
.gewerk{
  /* Container, damit sich der Spaltenkopf nach der Spaltenbreite richtet
     und alle drei denselben Schriftgrad bekommen. */
  container-type:inline-size;
  min-width:0; display:flex; flex-direction:column;
  overflow-y:auto; overflow-x:visible;
  scrollbar-width:none; -ms-overflow-style:none;
  /* KEIN overscroll-behavior:contain: am Ende einer Spalte soll der
     Scroll an die Seite weitergegeben werden, damit man direkt zu
     "Ueber uns" weiterfaehrt. */
}
.gewerk::-webkit-scrollbar{ display:none; }

.g-title{
  position:sticky; top:0; z-index:35;
  /* So gross wie moeglich und bei allen drei gleich: der Schriftgrad
     haengt an der Spaltenbreite (cqi), nicht am Fenster.

     7,2cqi statt der frueheren 8cqi. Der Grund ist die Schrift: ob
     "TRAGWERKSPLANUNG" - das laengste der drei Woerter - in seine
     Spalte passt, haengt nicht an der Fensterbreite, sondern allein
     daran, welche Schrift der Rechner des Besuchers wirklich hat.
     Schriftgrad und Spaltenbreite wachsen beide mit cqi, ihr
     Verhaeltnis bleibt also gleich; nur die Laufweite der Schrift
     aendert sich. Gemessen bei 294 px Spaltenbreite und 23,5 px
     Schriftgrad, verfuegbar sind 281 px:

         Century Gothic   260 px   passt
         Segoe UI         272 px   passt
         Arial            286 px   ragt hinaus
         Futura, Avenir   287 px   ragt hinaus
         Verdana          311 px   ragt hinaus

     Mit 8cqi passte das Wort also nur dort, wo Century Gothic
     installiert ist; sonst stiess es an den Rahmen und wurde vom
     overflow:hidden an den Enden beschnitten. 7,2cqi verkleinert alle
     drei Titel um ein Zehntel - sie bleiben damit untereinander
     gleich gross - und laesst "TRAGWERKSPLANUNG" bis zu einer Schrift
     von 312 px Laufweite vollstaendig stehen. Das deckt jede Schrift
     ab, die als Ersatz in Frage kommt. */
  /* Die zweite Zeile ("Generalplanung", in den anderen beiden Balken
     unsichtbar) macht den Balken um ihre Hoehe hoeher. Damit alle drei
     genau so hoch bleiben wie vor ihrer Einfuehrung, wird das Polster
     oben und unten um je die halbe Zeilenhoehe verringert.
     Rechnung: zweite Zeile = .52em Schriftgrad x 1,55 Zeilenhoehe
     + .15em Abstand = .956em, davon die Haelfte sind .478em. Nachge-
     messen fehlten danach noch zwei Punkt, daher .443em - der Balken
     ist damit wieder exakt so hoch wie zuvor (gemessen 103 px bei
     1440 px Fensterbreite). */
  padding:calc(var(--space-m) - .443em) .4rem;
  /* Der Wert aus clamp() ist der Rueckfall ohne Skript. Steht das
     Skript zur Verfuegung, setzt es --g-fs auf den groessten Grad,
     bei dem das laengste Wort noch ganz in seine Spalte passt. */
  font-size:var(--g-fs, clamp(.7rem, 7.2cqi, 2rem));
  font-weight:700; letter-spacing:.04em; text-transform:uppercase;
  text-align:center; white-space:nowrap;
  transition:opacity .3s var(--ease), filter .3s var(--ease);
}
.g-title.architektur{ background:var(--ink); color:var(--paper); }
.g-title.tragwerk{ background:var(--paper); color:var(--red-text); box-shadow:inset 0 0 0 2px var(--red); }
.g-title.bau{ background:var(--red-aa); color:#fff; }

.proj-scroll{ display:flex; flex-direction:column; gap:var(--space-s); padding-top:var(--space-s); }

/* ---------- 4. Projektkachel ---------- */
.proj{
  position:relative; width:100%; display:block; text-align:left;
  background:none; border:0; padding:0; color:inherit; cursor:pointer;
  transition:opacity .3s var(--ease), filter .3s var(--ease);
}
.proj-media{
  display:block; position:relative; width:100%;
  aspect-ratio: 1 / 1.6180339887;   /* Goldener Schnitt, wie im Bestand */
  max-height:62vh; overflow:hidden; background:var(--surface-2);
}
.proj-media img{
  width:100%; height:100%; object-fit:cover;
  filter:grayscale(35%);
  transition:filter .4s var(--ease), transform .6s var(--ease);
}
.proj:hover .proj-media img,
.proj:focus-visible .proj-media img{ filter:grayscale(0%); transform:scale(1.03); }

.proj-label{
  display:block; background:var(--paper); color:var(--ink);
  padding:var(--space-s) var(--space-m) var(--space-s) 0;
}
/* Lange Projektnamen wie "OELZ-Frischdienst-Zentrum" sind ein einziges
   Wort. In schmalen Spalten (ab 901 px Fensterbreite sind es nur 170 px)
   passte es nicht in die Kachel und wurde von deren overflow:hidden
   seitlich abgeschnitten. Getrennt wird nach deutschen Regeln, und was
   sich nicht trennen laesst, bricht notfalls hart um. */
.p-name{
  display:block; font-size:var(--fs-h3); font-weight:700;
  line-height:1.15; letter-spacing:-.01em;
  hyphens:auto; overflow-wrap:anywhere;
}
.p-sub{ display:block; font-size:var(--fs-micro); letter-spacing:.08em; text-transform:uppercase; color:var(--ink-3); margin-top:.15rem; }

/* Auf Zeigegeraeten faehrt die Beschriftung wie im Bestand von unten
   ins Bild. Auf Touch gibt es kein Hover, dort steht sie deshalb
   dauerhaft unter dem Bild (siehe Media Query unten). */
@media (hover:hover) and (pointer:fine){
  /* Die Kachel klippt, damit die Beschriftung von unten ins Bild
     faehrt statt darunter zu stehen. Genau wie im Bestand. */
  .proj{ overflow:hidden; }
  .proj-label{
    position:absolute; left:0; bottom:0; width:100%; z-index:2;
    padding:var(--space-s) var(--space-m);
    transform:translateY(100%);
    transition:transform .45s var(--ease);
  }
  .proj:hover .proj-label,
  .proj:focus-visible .proj-label{ transform:translateY(0); }
  /* Beim Ueberfahren einer Kachel treten die uebrigen Spalten zurueck. */
  .cols:has(.proj:hover) .gewerk:not(:has(.proj:hover)) .proj{ opacity:.35; filter:grayscale(100%); }
  .cols:has(.proj:hover) .gewerk:not(:has(.proj:hover)) .g-title{ opacity:.45; }
}
/* Ohne Hover gibt es kein Aufdecken. Dort steht die Beschriftung
   dauerhaft unter dem Bild: auf dem Telefon war sie im Bestand
   sonst ueberhaupt nicht zu sehen. */
@media (hover:none), (pointer:coarse){
  .proj-label{ position:static; transform:none; padding:var(--space-2xs) 0 0; }
}

/* Querverweis: dieselbe Kachel steht auch in einer anderen Sparte.
   Ohne diese Markierung liest sich das Raster wie ein Kopierfehler. */
/* Auf Wunsch komplett ausgeblendet. */
.proj-also{ display:none!important; }
.proj-also-unused{
  position:absolute; left:0; top:0; z-index:3; max-width:100%;
  display:inline-flex; align-items:center; gap:.35rem;
  background:var(--paper); color:var(--ink-2);
  padding:.3rem .55rem; font-size:var(--fs-micro);
  letter-spacing:.05em; text-transform:uppercase;
  box-shadow:inset 0 0 0 1px var(--line);
}

/* Zustand, solange ein Projekt geoeffnet ist */
.cols[data-open] .proj:not([data-active]){ opacity:.25; filter:grayscale(80%); }
.cols[data-open] .gewerk:not([data-active]) .g-title{ opacity:.3; filter:grayscale(70%); }
.proj[data-active] .proj-media{ box-shadow:inset 0 0 0 3px var(--red); }
/* Kommt man ueber ein Kompetenzbild, wird dasselbe Projekt in jeder
   Spalte hervorgehoben, in der es vorkommt. Der naechste Klick daneben
   nimmt die Markierung wieder weg. */
.proj.ist-gesucht .proj-media{ box-shadow:inset 0 0 0 3px var(--red); }

/* ---------- 5. Briefkopf, feste Spalte ---------- */
/* Der Briefkopf ist ein eigener Container. Alle Schriftgroessen
   darin rechnen in cqi, also relativ zur Spaltenbreite. Damit
   bleiben Adresse, Mail und Buttons auf jeder Fensterbreite
   einzeilig, ohne die JS-Schrumpfschleife aus dem Bestand. */
.info{
  container-type:inline-size;
  position:fixed; top:0; right:0; z-index:100;
  /* 100vh, nicht 100dvh: dvh ist die DYNAMISCHE Fensterhoehe und wird
     beim Scrollen neu gerechnet. Der Knopfblock haengt mit margin-top:auto
     am verbleibenden Platz - aenderte sich die Hoehe, sprang er um gut
     140 Punkt nach oben. vh bleibt waehrend des Scrollens gleich. */
  width:var(--sidebar-w); height:100vh;
  display:flex; flex-direction:column; gap:clamp(.25rem, .85vh, var(--space-s));
  padding:clamp(.4rem, 1.6vh, var(--space-m)) var(--space-l) clamp(.4rem, 1.6vh, var(--space-m)) var(--space-s);
  /* Die Spalte steht fest und scrollt nicht mit. Damit ihr Inhalt auch
     auf grossen Bildschirmen hineinpasst, ist ihre Breite bei 360 px
     gedeckelt - vorher wuchs sie mit 25vw mit und lief unten hinaus. */
  background:var(--paper); overflow:hidden;
}
/* Gemessen in der Logodatei: "ZIVILTECHNIKER" beginnt bei 20,0 % und endet
   bei 99,6 % der Logobreite, ist also 79,6 % breit. Damit GENERALPLANER
   genau darunter steht und genauso breit ist, haengen Einzug und
   Schriftgrad an der Logobreite statt an der Spaltenbreite. */
/* cqi statt Prozent: eine Prozentangabe bedeutet bei width die Breite
   des Elternelements, bei font-size aber die Schriftgroesse des
   Elternelements. 80cqi sind dagegen ueberall dieselbe Laenge, naemlich
   80 % der Spaltenbreite. */
/* Die Visitenkarte waechst mit dem Fenster. Gemessen stand unter der
   Anschrift bis zur Navigation viel Luft frei: 96 px bei 1101x640,
   174 px bei 1440x900, 284 px bei 1920x1080. Der Hoehenanteil (vh)
   holt diesen Platz, der Breitenanteil (cqi) begrenzt das Logo in
   schmalen, hohen Fenstern auf seine Spalte. */
.info{ --logo-w:min(84cqi, 27vh); }
/* Knoepfe und Fusszeile sitzen fest am unteren Rand und brauchen rund
   280 Punkt. Bei niedrigen Fenstern waere der Briefkopf darueber sonst
   zu hoch und die Anschrift liefe unter die Knoepfe. Gemessen bei
   640 Punkt Fensterhoehe: mit 27vh blieben nur 6 Punkt Luft. */
@media (max-height: 820px){ .info{ --logo-w:min(84cqi, 23vh); } }
@media (max-height: 700px){ .info{ --logo-w:min(84cqi, 18vh); } }
.letterhead{ display:block; width:var(--logo-w); }
/* Gemessen in der Logodatei: das "F" von FERRO beginnt bei exakt 20,0 %
   der Logobreite (x=128 von 640). Das Logo ist 80 % der Spalte breit,
   das F sitzt also bei 0,20 x 0,80 = 16 % der Spaltenbreite. Alle
   Textbloecke der festen Spalte stehen auf dieser Kante. */
:root{ --lh-indent:16%; }
.brand-claim{
  font-size:calc(var(--logo-w) * 0.0886);
  margin-top:calc(var(--logo-w) * 0.06);
  font-weight:700; color:var(--red-text);
  text-transform:uppercase; letter-spacing:.08em;
  margin-left:calc(var(--logo-w) * 0.20);
}
.lh-text{
  margin-left:calc(var(--logo-w) * 0.20); font-size:min(clamp(.76rem, 6cqi, 1rem), 1.9vh);
  text-transform:uppercase; letter-spacing:.02em; line-height:1.55; color:var(--ink);
}
.lh-group + .lh-group{ margin-top:clamp(.25em, .9vh, .8em); }
.lh-text a, .lh-text div{ white-space:nowrap; }
.lh-text a{ display:inline-block; max-width:100%; }
.lh-text a:hover{ color:var(--red-text); text-decoration:underline; }

/* Der Fuss der Spalte - Knoepfe und Zeile darunter - haengt fest am
   unteren Rand, nicht am verbleibenden Platz. Die Werte entsprechen dem
   Innenabstand der Spalte, damit nichts wandert. */
.info-unten{
  position:absolute;
  left:var(--space-s); right:var(--space-l);
  bottom:clamp(.4rem, 1.6vh, var(--space-m));
}
.info-nav{ display:flex; flex-direction:column; margin-left:calc(var(--logo-w) * 0.20); }
.box{
  display:flex; align-items:center; justify-content:space-between; gap:.5em;
  padding:clamp(.3em, .8vh, .72em) .8em; width:100%; text-align:left; white-space:nowrap;
  font-size:min(clamp(.76rem, 4.9cqi, 1.05rem), 1.75vh);
  font-weight:700; letter-spacing:.02em; text-transform:uppercase; line-height:1.25;
  border-radius:var(--radius);
  transition:background .2s var(--ease), color .2s var(--ease), transform .18s var(--ease);
}
.box:hover{ transform:translateX(3px); }
.nav-btn{ background:var(--paper); color:var(--ink); border:1px solid var(--ink); }
.nav-btn:hover{ background:var(--ink); color:var(--paper); }
.nav-btn[aria-current="true"]{ background:var(--red-aa); color:#fff; border-color:var(--red-aa); }
/* Der einzige Knopf mit langer Beschriftung. Bei schmalen Fenstern
   (ab 901 px ist die Leiste nur 225 px breit) brauchte "Kontaktieren Sie
   uns hier" 153 px und wurde vom nowrap der Knopfklasse abgeschnitten.
   Hier darf die Zeile umbrechen; die uebrigen Knoepfe bleiben einzeilig,
   damit die Hoehe der Gewerke-Leiste auf dem Telefon nicht springt. */
.cta-project{
  background:var(--red-aa); color:#fff; border:1px solid var(--red-aa);
  margin-top:clamp(.2rem, .9vh, var(--space-xs)); white-space:normal;
}
.cta-project:hover{ background:var(--red-press); border-color:var(--red-press); color:#fff; }

/* "Ueber uns" als Bildkachel ueber den Buttons, wie im Bestand */
.ueber-uns-tile{ display:block; padding:0; border:0; margin-bottom:clamp(.15rem, .7vh, var(--space-2xs)); }
.ueber-uns-tile img{ width:100%; aspect-ratio:auto; height:clamp(34px, 7vh, 118px); object-fit:cover; object-position:center 25%; filter:grayscale(15%); transition:filter .4s var(--ease); }
.ueber-uns-tile:hover img{ filter:grayscale(0%); }
.ueber-uns-label{
  display:flex; align-items:center; justify-content:space-between; gap:.5em;
  background:var(--paper); color:var(--ink); border:1px solid var(--ink); border-top:0;
  padding:clamp(.3em, .8vh, .72em) .8em; white-space:nowrap;
  font-size:min(clamp(.76rem, 4.9cqi, 1.05rem), 1.75vh);
  font-weight:700; letter-spacing:.02em; text-transform:uppercase;
}
.ueber-uns-tile:hover .ueber-uns-label{ background:var(--ink); color:var(--paper); }
.ueber-uns-tile[aria-current="true"] .ueber-uns-label{ background:var(--red-aa); color:#fff; border-color:var(--red-aa); }

/* Die drei Gewerke-Reiter gibt es nur in der schmalen Ansicht: am
   Desktop stehen die Spalten ohnehin nebeneinander. */
.nav-cat{ display:none; }
.nav-cat.architektur{ background:var(--ink); color:var(--paper); }
.nav-cat.tragwerk{ background:var(--paper); color:var(--red-text); box-shadow:inset 0 0 0 2px var(--red); }
.nav-cat.bau{ background:var(--red-aa); color:#fff; }
.nav-cat + .nav-cat{ margin-top:var(--space-2xs); }

.info-footer{
  margin-left:calc(var(--logo-w) * 0.20); padding-top:clamp(.25rem, 1.2vh, var(--space-s));
  font-size:min(var(--fs-micro), 1.7vh); letter-spacing:.1em; text-transform:uppercase; color:var(--ink-3);
  /* Impressum steht allein in seiner Zeile und war als reiner Textlink
     nur 14 px hoch. Das Innenmass vergroessert nur die Klickflaeche, die
     Grundlinie und damit die Ausrichtung auf das F von FERRO bleibt. */
  line-height:1.9;
}
.info-footer a{ display:inline-block; padding-block:.28rem; }
.info-footer a:hover{ color:var(--red-text); text-decoration:underline; }
/* Der Weg in die Pflege der Seite steht ganz am Ende des Datenschutz-
   abschnitts. Er gilt dem Buero, nicht den Besuchern - deshalb klein und
   ruhig, aber als Knopf klar zu treffen. */
.pflege-zeile{
  display:flex; flex-wrap:wrap; align-items:center; gap:var(--space-s);
  margin-top:var(--space-l); padding-top:var(--space-s);
  border-top:1px solid var(--line);
  font-size:var(--fs-micro); color:var(--ink-3);
}
.pflege-knopf{
  flex:none; display:inline-block;
  padding:.5em 1.1em; border:1.5px solid var(--ink); border-radius:var(--radius);
  color:var(--ink); text-decoration:none;
  font-weight:700; letter-spacing:.1em; text-transform:uppercase;
  transition:background .2s var(--ease), color .2s var(--ease);
}
.pflege-knopf:hover, .pflege-knopf:focus-visible{ background:var(--ink); color:var(--paper); }
.info-toggle{ display:none; }
.mobile-mark{ display:none; }

/* ---------- 6. Projektdialog ---------- */
dialog.proj-dialog{
  /* Eine Breite fuer beides: die Infospalte und die drei Spartenmarken
     darueber. Sie enden damit auf derselben Kante. */
  --ov-spalte:26rem;
  width:100vw; max-width:none; height:100dvh; max-height:none;
  margin:0; padding:0; border:0; border-radius:var(--radius);
  background:var(--paper); color:var(--ink); overflow:hidden;
}
dialog.proj-dialog::backdrop{ background:color-mix(in srgb, #000 58%, transparent); }
dialog.proj-dialog[open]{ display:grid; grid-template-rows:auto minmax(0,1fr); }

/* Der Spaltentitel traegt eine Schaltflaeche, mit der sich das Gewerk auf
   dem Telefon auf- und zuklappen laesst. Am Desktop erbt sie alles vom
   Titel und ist von der bisherigen Ueberschrift nicht zu unterscheiden. */
.g-toggle{
  display:block; width:100%; margin:0; padding:0; border:0;
  background:none; color:inherit; font:inherit; text-decoration:none;
  letter-spacing:inherit; text-transform:inherit; text-align:inherit;
  cursor:pointer;
}
.g-toggle:hover{ text-decoration:underline; text-underline-offset:.3em; }
/* Zweite Zeile im Spaltentitel ("Generalplanung" unter "Architektur").
   Deutlich kleiner und weiter gesperrt, damit das Wort den Balken nicht
   sprengt: die Groesse haengt wie beim Titel an der Spaltenbreite, nicht
   am Fenster. Eigene Zeile, aber ohne zusaetzlichen Abstand nach oben -
   die beiden Woerter gehoeren zusammen. */
/* Das Wort selbst, damit seine Breite messbar ist. */
.g-wort{ display:inline-block; }
.g-unter{
  display:block; margin-top:.15em;
  font-size:.52em; letter-spacing:.18em; font-weight:700; opacity:.85;
  /* Die Sperrung stellt das Skript so ein, dass die Zeile genau so
     breit wird wie das Wort darueber. Der Wert hier ist der Ausgangs-
     wert, falls kein JavaScript laeuft. */
  letter-spacing:var(--g-sperrung, .18em);
  margin-right:calc(-1 * var(--g-sperrung, .18em));
}
/* Platzhalter in den beiden anderen Balken: nimmt denselben Raum ein,
   ist aber nicht zu sehen und wird nicht vorgelesen. */
.g-unter-leer{ visibility:hidden; }
/* Der Teamsatz unter dem Bild der Geschaeftsfuehrung. */
.about-team{ margin-top:var(--space-m); }

/* Platzhalterkachel: sieht aus wie eine Projektkachel, verhaelt sich
   aber nicht wie eine - kein Zeiger, keine Vergroesserung, gedaempft.
   Sie soll nicht zum Klicken einladen. */
.proj-platzhalter{ cursor:default; }
.proj-platzhalter .proj-media img{ filter:none; }
.proj-platzhalter:hover .proj-media img{ transform:none; }
.proj-platzhalter .p-sub{ color:var(--ink-3); letter-spacing:.14em; text-transform:uppercase; }
.g-caret{ display:none; }

/* ---------- Archiv ---------- */
/* Liegt unter den drei Spalten und nimmt deren Raster auf: dieselben
   drei gleich breiten Spalten, dieselbe Einrueckung links, derselbe
   Freiraum rechts fuer den Briefkopf. Die Angaben stehen damit genau
   unter dem Gewerk, zu dem sie gehoeren. */
.archiv{
  padding:var(--space-l) 0 var(--space-xl) var(--space-l);
  padding-right:calc(var(--sidebar-w) + var(--space-l));
  border-top:1px solid var(--line);
  /* Messpunkt fuer die Schriftgroesse der Ueberschriften: sie richtet
     sich nach der Tabellenbreite, nicht nach der Schriftgroesse der
     Seite. Ein fester Wert passte bei 1900 Punkt und sprengte bei 1440
     den schmalsten Kasten. */
  container-type:inline-size;
}
/* Der Kopf liegt auf demselben Dreierraster wie die Tabelle darunter.
   Vorher war er ein Flexkasten: der Titel bestimmte die Breite, und die
   Anzahl dahinter lief quer ueber die erste Spaltengrenze. Jetzt steht
   der Titel in der ersten, die Anzahl buendig in der zweiten Spalte. */
/* Der Kopf ist ein gerahmtes Feld ueber die gesamte Tabellenbreite -
   die Deckzeile des Archivblatts. Text links, die Anzahl daneben. */
.archiv-kopf, .archiv-tab{ --archiv-kopf-fs:clamp(8px, 1.10cqi, 17px); }
.archiv-kopf{
  /* Dasselbe Dreierraster wie die Tabelle: der Titel in der ersten
     Spalte, die Anzahl buendig in der zweiten. Vorher lief sie direkt
     hinter dem Titel und stand auf keiner Spaltenkante. */
  display:grid; grid-template-columns:repeat(3, minmax(0,1fr));
  align-items:center; gap:var(--space-m); cursor:pointer;
  background:var(--paper); color:var(--ink);
  box-shadow:inset 0 0 0 2px var(--ink);
  /* Genau so hoch wie die Ueberschriftenfelder darunter - das Archiv
     soll eine durchgehende Tabelle sein, keine Ueberschrift mit Tabelle
     darunter. Deshalb dieselbe Schriftgroesse und dasselbe Polster. */
  min-height:3.1em; padding:.4em 9px;
  /* Der Rahmen steht auf der Kante der Bilder darueber, der Text rueckt
     um sein Polster nach innen. Vorher griff der Kasten um dieses Polster
     nach aussen - dann stand der Text zwar auf der Spaltenkante, der
     schwarze Strich aber neun Punkt neben den Bildern. */
  margin-inline:0;
  font-weight:700; letter-spacing:.14em; text-transform:uppercase;
  font-size:var(--archiv-kopf-fs); list-style:none;
}
.archiv-kopf::-webkit-details-marker{ display:none; }
/* Derselbe schwarze Balken wie "ARCHITEKTUR" ueber den Projekten: er
   markiert das Archiv als eigenen Abschnitt statt als Ueberschrift
   nebenbei. Der Schriftgrad rechnet in Prozent der Tabellenbreite, damit
   er mitwaechst und das Wort in der ersten Spalte bleibt. */
.archiv-titel{
  display:flex; align-items:center; justify-content:flex-start; gap:var(--space-s);
  min-width:0; color:var(--ink);
  /* Hoehe wie der Balken "ARCHITEKTUR": der traegt eine zweite Zeile
     ("Generalplanung") und ist dadurch hoeher. Das Polster gleicht den
     Unterschied aus - gemessen 114 px bei 1680 px Fensterbreite. */
  padding:0; font-size:inherit; letter-spacing:inherit; white-space:nowrap;
}
/* Das Dreieck zeigt den Zustand an - eigenes Zeichen statt des
   Standardmarkers, damit es zur uebrigen Seite passt. Es steht HINTER
   dem Wort: davor haette es "Archivprojekte" eingerueckt, und der Titel
   soll links buendig mit JAHR und den Projektnamen darunter stehen. */
.archiv-titel::after{
  content:""; flex:none; width:0; height:0; align-self:center;
  border-left:.42em solid var(--red); border-top:.3em solid transparent;
  border-bottom:.3em solid transparent; transition:transform .2s var(--ease);
}
.archiv[open] .archiv-titel::after{ transform:rotate(90deg); }
.archiv-zahl{ font-size:var(--fs-micro); font-weight:400; letter-spacing:.06em; color:var(--ink-3); text-transform:none; }
/* Aufgeklappt umfasst der Rahmen den ganzen Abschnitt: der Kopf gibt
   seinen unteren Rand ab, der Inhaltskasten schliesst nahtlos an. */
.archiv[open] .archiv-kopf{ box-shadow:inset 0 0 0 1px var(--ink); clip-path:inset(0 0 1px 0); }
.archiv-inhalt{
  margin:-1px 0 0; padding:var(--space-s) 9px var(--space-m);
  box-shadow:inset 0 0 0 1px var(--ink);
}
/* Die Gewerkefelder und die Beschriftungen liegen vor den schwarzen
   Linien der Kopfzeile - sie ueberdecken sie um deren eigene Staerke. */
.archiv-kopfreihe .archiv-gewerk,
.archiv-kopfreihe .archiv-sort{
  position:relative; z-index:1; margin-block:-2px;
  padding-block:calc(.4em + 2px);
}
/* Projektname und Jahr stehen links, genau unter ihrer Ueberschrift. */
.archiv-kopfreihe .archiv-sort[data-feld="name"],
.archiv-kopfreihe .archiv-sort[data-feld="jahr"]{ justify-content:flex-start; }
.archiv-suche{
  /* Genau eine Spalte breit, wie der Titelbalken darueber: dieselbe
     Rechnung wie im Raster der Tabelle - Gesamtbreite abzueglich der
     beiden Spaltenabstaende, geteilt durch drei. */
  margin-top:var(--space-m); width:calc((100% - 2 * var(--space-m)) / 3);
  padding:.6rem .8rem; border:1.5px solid var(--line); border-radius:var(--radius);
  background:var(--paper); color:var(--ink); font-size:var(--fs-sub);
}
.archiv-suche:focus-visible{ outline:none; border-color:var(--red); box-shadow:0 0 0 3px var(--red); }
/* Das Raster sitzt auf der Tabelle, nicht auf der Zeile: die Zeilen
   sind Verweise mit display:contents, ihre drei Felder sind damit
   unmittelbar Kinder der Tabelle. Lag das Raster auf der Zeile, hob
   display:contents es wieder auf und alle Felder fielen untereinander
   in die erste Spalte. */
/* Die Tabelle ist nur noch ein Stapel von Zeilen; das Raster sitzt auf
   der Zeile. Nur so gibt es einen Zeilenkasten, der eine durchgehende
   Linie tragen kann - mit display:contents gab es keinen. */
.archiv-tab{ margin-top:var(--space-s); display:block; }
.archiv-reihe{
  display:grid; grid-template-columns:repeat(3, minmax(0,1fr));
  column-gap:var(--space-m); align-items:stretch;
}
/* Kraeftige Linie ueber und unter der Kopfzeile, feine zwischen den
   Projektzeilen - damit die Tabelle waagrecht lesbar wird. */
.archiv-kopfreihe{ border-top:2px solid var(--ink); border-bottom:2px solid var(--ink); }
.archiv-zeile{ border-bottom:1px solid var(--line); }
/*    Nicht "> " verwenden: die Zeile traegt display:contents, im Rasterbau
   sind ihre Felder zwar Kinder der Tabelle, im Dokumentbaum aber nicht -
   der Kindselektor hat deshalb nie gegriffen. */
/* Alle sechs Ueberschriften sind gerahmte Felder gleicher Groesse:
   die drei Gewerke im Farbcode der Spaltenkoepfe, Projekte, Jahr und
   Flaeche weiss mit schwarzem Rahmen. Die durchgehende Linie unter der
   Kopfzeile ist entfallen - sie lief ueber beide Haelften einer Spalte
   und zerschnitt die Felder optisch. */
/* Die drei Angabenspalten tragen schlichte Beschriftungen, die drei
   Gewerke ihre farbigen Balken. Nur dort, wo die Farbe etwas bedeutet,
   steht auch Farbe - alles andere bleibt ruhig. Rahmen um jede einzelne
   Zelle gibt es nicht mehr; sie zerlegten die Tabelle optisch in lauter
   Einzelkaestchen. */
.archiv-sort{
  display:flex; align-items:center; justify-content:center; gap:.4em;
  background:none; color:var(--ink-2);
  border:0; min-height:3.1em; padding:.4em .3em; cursor:pointer;
  font:inherit; font-size:var(--archiv-kopf-fs); font-weight:700;
  letter-spacing:.06em; text-transform:uppercase;
}
.archiv-sort:hover{ color:var(--red-text); }
/* Flaeche steht rechts - Zahlen liest man an der Einerstelle, und die
   Spalte schliesst damit buendig mit dem Tabellenrand ab. */
.archiv-kopfreihe .archiv-sort[data-feld="flaeche"]{ justify-content:flex-end; }

.archiv-sort:hover{ color:var(--red-text); }
.archiv-sort::after{ content:"\2195"; opacity:.4; font-weight:400; }
.archiv-sort[data-richtung="auf"]::after{ content:"\2191"; opacity:1; color:var(--red-text); }
.archiv-sort[data-richtung="ab"]::after{ content:"\2193"; opacity:1; color:var(--red-text); }
/* Die mittlere Kopfzelle traegt die drei Gewerke nebeneinander, zu
   gleichen Teilen ueber die Spaltenbreite. Jedes ist ein Schalter: ein
   Druck zeigt nur dieses Gewerk, ein zweiter wieder alle. */
/* Spalte zwei und drei sind noch einmal halbiert: Architektur und
   Tragwerksplanung links, Baumanagement und Flaeche rechts. Der Abstand
   zwischen den Haelften ist derselbe wie zwischen den Hauptspalten -
   dadurch stehen alle vier Felder im selben Rhythmus, und die aeusseren
   Kanten bleiben auf den Spalten der Projektmatrix darueber.
   Die Klasse steht doppelt im Selektor, damit sie das display:flex von
   .archiv-feld sicher ueberschreibt. */
.archiv-paar,
.archiv-feld.archiv-paar{
  display:grid; grid-template-columns:repeat(2, minmax(0,1fr));
  column-gap:var(--space-m); align-items:stretch;
}
/* Die drei Gewerke sind gleich grosse Kaesten mit dem Farbcode der
   Spaltenkoepfe. Gesetzte Trennstellen (&shy; im Markup) sorgen dafuer,
   dass die langen Woerter sauber brechen statt an beliebiger Stelle. */
.archiv-gewerk{
  display:flex; align-items:center; justify-content:center; text-align:center;
  min-height:3.1em; padding:.4em .3em; border:0; cursor:pointer;
  font:inherit; font-weight:700; text-transform:uppercase;
  font-size:var(--archiv-kopf-fs); letter-spacing:.06em; line-height:1.15;
  overflow-wrap:break-word; hyphens:manual;
  box-shadow:inset 0 0 0 2px transparent;
}
/* In den Zeilen steht das Gewerk ausgeschrieben, in gewoehnlicher
   Schrift und in derselben Groesse wie das Jahr daneben. Die Farbe
   traegt die Ueberschrift darueber; in den Zeilen waere sie Unruhe. */
.archiv-g{
  display:flex; align-items:center; justify-content:center;
  font-weight:400; font-size:1em; line-height:1.2; text-align:center;
  background:none; box-shadow:none; color:var(--ink-2); opacity:1;
}
.archiv-farbe-architektur{ background:var(--ink); color:var(--paper); }
.archiv-farbe-tragwerk{ background:var(--paper); color:var(--red-text); box-shadow:inset 0 0 0 2px var(--red); }
.archiv-farbe-bau{ background:var(--red-aa); color:#fff; }
.archiv-gewerk:hover{ filter:brightness(1.12); }
/* Ist ein Gewerk gewaehlt, treten die anderen beiden zurueck. */
.archiv-kopfzelle:has(.archiv-gewerk[aria-pressed="true"]) .archiv-gewerk[aria-pressed="false"]{ opacity:.3; }
.archiv-gewerk:focus-visible{ outline:2px solid var(--ink); outline-offset:2px; }
/* Kein Rahmen je Zelle: die Zeile wird von der feinen Linie darunter
   zusammengehalten, die Spalten vom Raster. Das ist ruhiger und laesst
   die farbigen Gewerkebalken wirken. */
.archiv-name, .archiv-wert, .archiv-gzelle{
  min-height:2.8em; padding:.3em .7em;
}
.archiv-gzelle{ display:flex; min-width:0; align-items:center; justify-content:center; }
.archiv-g{ flex:1; }

/* Jahr und Flaeche stehen rechts in ihrer Haelfte - Zahlen liest man an
   der Einerstelle. */
.archiv-wert{ display:flex; align-items:center; min-width:0; transition:opacity .2s var(--ease); }
/* Das Jahr steht links in seiner Haelfte, genau unter seiner
   Ueberschrift. Die Flaeche steht rechts, dort liest man an der
   Einerstelle. */
.archiv-jahr{ justify-content:flex-start; }
.archiv-flaeche{ justify-content:flex-end; text-align:right; }
/* Faehrt die Maus ueber eine Zeile, leuchtet sie auf: der Hintergrund
   hebt sich ab und die Kreuze stehen in voller Farbe. Zurueckgenommen
   wird nichts - das sah nach Ausblenden aus, nicht nach Auswaehlen. */

.archiv-zeile{ color:inherit; }
.archiv-zeile:hover .archiv-feld,
.archiv-zeile:focus-visible .archiv-feld{ background:var(--surface-2); }
/* Vorschau beim Ueberfahren einer Archivzeile: das erste Bild des
   Projekts folgt dem Zeiger. Die Tafel nimmt keine Mausereignisse an,
   sonst verliesse der Zeiger die Zeile, sobald sie erscheint. */
.archiv-vorschau{
  position:fixed; z-index:60; width:clamp(180px, 18vw, 280px);
  aspect-ratio:3/2; margin:0; padding:0; overflow:hidden;
  background:var(--paper); box-shadow:0 2px 14px rgba(0,0,0,.22);
  pointer-events:none; opacity:0; transition:opacity .14s var(--ease);
}
.archiv-vorschau.is-da{ opacity:1; }
.archiv-vorschau img{ display:block; width:100%; height:100%; object-fit:cover; }
@media (prefers-reduced-motion: reduce){ .archiv-vorschau{ transition:none; } }
/* Alles in einer Zeile steht auf derselben Hoehe und in derselben
   Groesse - auch die Gewerkefelder. Dadurch liest sich die Liste als
   Tabelle und nicht als Folge unterschiedlich hoher Baender.
   Trennstriche gibt es keine mehr: der Zeilenabstand reicht, und die
   gestueckelten Linien zwischen den Spalten wirkten unruhig. */
.archiv-feld{
  font-size:var(--archiv-kopf-fs); color:var(--ink-2); min-width:0;
  padding:0; height:100%;
  display:flex; align-items:stretch;
}
.archiv-name{ display:flex; align-items:center; font-weight:700; color:var(--ink); min-width:0; }
/* Die Jahreszahl fuehrt die Leistungsspalte an, wie der Projektname
   die erste Spalte. */
.archiv-name::after{ content:" \2192"; color:var(--red-text); opacity:0; transition:opacity .2s var(--ease); }
.archiv-zeile:hover .archiv-name::after{ opacity:1; }
.archiv-leer{ padding:var(--space-m) 0; color:var(--ink-3); font-size:var(--fs-sub); }
@media (max-width: 1100px){
  .archiv{ padding:var(--space-l) var(--space-s) var(--space-l); }
  .archiv-reihe{ grid-template-columns:minmax(0,1.4fr) minmax(0,1fr); gap:var(--space-s); }
  /* Auf dem Telefon faellt die dritte Spalte in die naechste Zeile;
     die Kopfzeile wuerde dadurch verrutschen und wird ausgeblendet.
     Sortiert wird dort ueber die beiden verbliebenen Knoepfe. */
  .archiv-kopfreihe .archiv-sort:nth-child(3){ display:none; }
}
/* ---- Archiv am Telefon ----------------------------------------------
   Sechs Felder nebeneinander gehen sich auf einem Telefon nicht aus:
   allein "Tragwerksplanung" braucht mehr Platz, als ein Sechstel von
   390 Punkten hergibt. Unter 760 Punkten Breite stehen die drei Paare
   deshalb untereinander - Projekt und Jahr, darunter die Gewerke,
   darunter die Flaeche. Jedes Paar bleibt in sich zweispaltig, die
   Tabelle also waagrecht lesbar.
   Diese Regeln stehen bewusst NACH dem Block fuer 1100 Punkt: beide
   treffen auf ein Telefon zu, und bei gleichem Gewicht gilt die
   spaetere. */
@media (max-width: 760px){
  .archiv-suche{ width:100%; }
  /* Zwei Spalten, beide genau halb: links der Projektname, rechts ein
     Wert, den man selbst waehlt - Jahr, Flaeche oder ein Gewerk. Danach
     wird auch sortiert. Die Kante in der Mitte zieht sich durch Kopf,
     Auswahlleiste und alle Zeilen. */
  /* Kein Spaltenabstand: er verschoebe die Kante um seine halbe Breite.
     Den Abstand zum Nachbarn traegt stattdessen die rechte Spalte. */
  .archiv-reihe{ grid-template-columns:1fr 1fr; column-gap:0; }
  /* Auch die Deckzeile des Archivs folgt der Mitte: der Titel links, die
     Anzahl rechts daneben. Vorher lagen beide uebereinander. */
  .archiv-kopf{
    grid-template-columns:1fr 1fr; align-items:start; column-gap:0;
  }
  .archiv-zahl{ text-align:left; padding-left:var(--space-s); }
  .archiv-zeile{ padding-block:7px; }
  /* Von den drei Paaren bleibt nur das erste stehen, und auch dort nur
     der Name. Der gewaehlte Wert kommt aus der zweiten Spalte. */
  .archiv-zeile .archiv-feld{ display:none; }
  .archiv-zeile .archiv-feld:first-child{ display:block; }
  .archiv-zeile .archiv-feld:first-child .archiv-wert{ display:none; }
  .archiv-name{ min-height:0; padding:.2em 0; }
  .archiv-mobil{
    display:flex; align-items:center; justify-content:flex-end;
    padding:.2em 0 .2em var(--space-s); white-space:nowrap; color:var(--ink-2);
  }
  .archiv-mobil:empty::before{ content:"\2013"; color:var(--ink-3); }
  /* Die Kopfzeile der Tabelle weicht der eigenen Leiste darueber. */
  .archiv-kopfreihe{ display:none; }
  .archiv-mobilkopf{
    display:grid; grid-template-columns:1fr 1fr; align-items:center;
    column-gap:0;
    margin-top:var(--space-s); padding-block:.5em;
    border-top:2px solid var(--ink); border-bottom:2px solid var(--ink);
    font-size:var(--archiv-kopf-fs); font-weight:700;
    letter-spacing:.14em; text-transform:uppercase;
  }
  /* Der Abstand zur linken Spalte geht von der eigenen Breite ab, sonst
     stuende die Auswahl rechts ueber die Tabellenkante hinaus. */
  .archiv-mobilkopf select{ margin-left:var(--space-s); width:calc(100% - var(--space-s)); }
  .archiv-mobilkopf select{
    font:inherit; letter-spacing:.08em; text-transform:uppercase;
    padding:.4em 1.8em .4em .6em; border:1.5px solid var(--ink);
    border-radius:var(--radius); background:var(--paper); color:var(--ink);
    -webkit-appearance:none; appearance:none;
    background-image:linear-gradient(45deg, transparent 50%, currentColor 50%),
                     linear-gradient(135deg, currentColor 50%, transparent 50%);
    background-position:calc(100% - 15px) 55%, calc(100% - 10px) 55%;
    background-size:5px 5px, 5px 5px; background-repeat:no-repeat;
  }
  .archiv-mobilkopf select:focus-visible{ outline:2px solid var(--red); outline-offset:1px; }
  /* Der Schriftgrad haengt sonst an der Breite der Tabelle und fiele
     am Telefon auf den Mindestwert; hier zaehlt die Lesbarkeit. */
  .archiv-kopf, .archiv-tab{ --archiv-kopf-fs:clamp(11px, 3.2vw, 15px); }
}
/* Am Schreibtisch gibt es die Leiste nicht - dort steht die volle
   Tabelle mit ihren eigenen Sortierschaltflaechen. */
@media (min-width: 761px){ .archiv-mobilkopf, .archiv-mobil{ display:none; } }

/* Die Kompetenz-Ueberschrift fuehrt zu den Projekten derselben Sparte. */
.komp-link{
  /* Mittig wie die Spaltentitel auf der Startseite: der Pfeil steht
     direkt neben dem Wort, nicht am rechten Rand.
     Knapper Abstand und kleinerer Pfeil, weil der Schriftgrad derselbe
     ist wie im Banner, dort aber kein Zeichen danebensteht: gemessen
     brauchte "TRAGWERKSPLANUNG" 260 px, verfuegbar sind 281 px, und
     Pfeil samt Abstand belegten davon 36 px - es fehlten 7 px. */
  display:flex; align-items:center; justify-content:center; gap:.2em;
  color:inherit; text-decoration:none;
}
.komp-link .icon{ opacity:.7; flex:none; width:.7em; height:.7em; }
.komp-link:hover{ text-decoration:underline; text-underline-offset:.25em; }
/* Die vier ausgewaehlten Projekte stehen nur auf dem Telefon vor den
   Gewerken. Am Desktop wuerde eine vierte Spalte das Raster sprengen. */
.gewerk-vorschau{ display:none; }

.ov-bar{
  display:flex; align-items:center; gap:var(--space-s);
  padding:var(--space-2xs) var(--space-m); border-bottom:1px solid var(--line);
}
.ov-close{
  order:2; display:inline-flex; align-items:center; gap:.5rem;
  background:none; border:0; cursor:pointer; padding:.6rem 0;
  font-size:var(--fs-sub); font-weight:700; letter-spacing:.06em; text-transform:uppercase; color:var(--ink-2);
}
.ov-close:hover{ color:var(--red-text); }
/* Sparten links oben, in denselben Farben wie die Spaltenkoepfe.
   Es stehen immer alle drei nebeneinander, zu gleichen Teilen; das
   Gewerk, an dem das Buero nicht beteiligt war, bleibt ausgegraut
   stehen. So zeigt die Reihe bei jedem Projekt dasselbe Bild.
   Die Breite entspricht der Infospalte darunter, damit die dritte
   Marke und die Spaltenkante gemeinsam abschliessen. */
.ov-sparten{
  display:grid; grid-template-columns:repeat(3, minmax(0,1fr));
  gap:var(--space-2xs); margin-right:auto;
  width:calc(var(--ov-spalte) - var(--space-m));
}
.ov-sparte{
  display:block; text-align:center; min-width:0;
  /* 0,64 rem und 0,02 em Sperrung: gemessen passt damit die laengste
     Beschriftung "Tragwerksplanung" in das Drittel, ohne anzustossen. */
  padding:.5em .3em; font-size:.64rem;
  font-weight:700; letter-spacing:.02em; text-transform:uppercase;
  white-space:nowrap; overflow:hidden;
}
.ov-sparte.architektur{ background:var(--ink); color:var(--paper); }
.ov-sparte.tragwerk{ background:var(--paper); color:var(--red-text); box-shadow:inset 0 0 0 2px var(--red); }
.ov-sparte.bau{ background:var(--red-aa); color:#fff; }

/* Nicht abgedeckte Gewerke bleiben am Telefon ausgegraut stehen, damit
   die Reihe immer dieselben drei Felder zeigt. Am Desktop, wo die Leiste
   schmal ist, bleiben sie weg. */
/* Nicht abgedecktes Gewerk: steht mit, aber zurueckgenommen. */
.ov-sparte.is-off{ background:var(--surface-2); color:var(--ink-3); box-shadow:none; }
.ov-mark{ display:none; }
/* ---- Einzelbild im Vollbild ----------------------------------
   Ein Klick auf eine Aufnahme legt sie formatfuellend ueber die Ansicht.
   Dort laesst sich mit den Pfeilen, den Pfeiltasten oder auf dem Telefon
   mit einer Wischbewegung durch alle Bilder des Projekts blaettern.
   position:fixed wirkt gegen das Sichtfenster und liegt trotzdem ueber
   dem Dialog, weil die Elemente selbst im Dialog stehen. */
.ov-gross-zu, .gross-nav{ display:none; }
.ov-slide{ cursor:zoom-in; }
.ov-slide.gross{
  position:fixed; inset:0; z-index:30; margin:0;
  padding:var(--space-s); background:var(--paper);
  display:grid; place-items:center; cursor:zoom-out;
  touch-action:pan-y;
}
.ov-slide.gross img{
  position:static; inset:auto; margin:0;
  /* In der Vollbildansicht zaehlt die echte Form der Aufnahme, nicht
     das einheitliche 3:2 der Galerie: wer hier hinschaut, will das
     ganze Bild so sehen, wie es aufgenommen wurde. Deshalb hier auch
     object-fit:contain - die Galerie schneidet zu, das Vollbild nicht. */
  width:auto; height:auto; max-width:100%; max-height:100%; aspect-ratio:auto;
  object-fit:contain;
}
.hat-gross .ov-gross-zu,
.hat-gross .gross-nav{
  display:grid; place-items:center; position:fixed; z-index:31;
  width:2.75rem; height:2.75rem; padding:0;
  background:var(--ink); color:var(--paper); border:0;
  border-radius:var(--radius); cursor:pointer; font-size:1.35rem;
  box-shadow:0 2px 10px rgb(0 0 0 / .28);
}
.hat-gross .ov-gross-zu{ top:var(--space-s); right:var(--space-s); }
.hat-gross .gross-nav{ top:50%; translate:0 -50%; }
.hat-gross .gross-prev{ left:var(--space-s); }
.hat-gross .gross-next{ right:var(--space-s); }
.hat-gross .gross-nav:hover, .hat-gross .ov-gross-zu:hover{ background:var(--red-aa); }
.gross-zaehler{
  display:none; position:fixed; left:50%; translate:-50% 0;
  bottom:var(--space-s); z-index:31;
  background:var(--ink); color:var(--paper);
  padding:.35em .8em; font-size:var(--fs-micro);
  letter-spacing:.1em; border-radius:var(--radius);
}
.hat-gross .gross-zaehler{ display:block; }

.ov-body{ display:grid; grid-template-columns:var(--ov-spalte) minmax(0,1fr); min-height:0; }
.ov-info{
  padding:var(--space-m); border-right:1px solid var(--line);
  overflow:auto; min-height:0; display:flex; flex-direction:column; gap:var(--space-s);
}
.ov-info h2{ font-size:var(--fs-h2); font-weight:700; line-height:1.08; letter-spacing:-.01em; hyphens:auto; overflow-wrap:anywhere; }
.ov-facts{ display:grid; gap:var(--space-2xs); }
.ov-fact{ display:grid; grid-template-columns:8rem minmax(0,1fr); gap:var(--space-2xs); font-size:var(--fs-sub); }
.ov-fact dt{ font-size:var(--fs-micro); letter-spacing:.1em; text-transform:uppercase; color:var(--ink-3); padding-top:.15rem; }
.ov-desc{ color:var(--ink-2); max-width:52ch; }
/* Mehrteilige Beschreibungen: jeder Absatz steht fuer sich, sonst
   klebten 1.500 Zeichen in einem Block aneinander. */
.ov-desc + .ov-desc{ margin-top:var(--space-s); }
/* Film zum Projekt. Steht unter dem Text, nicht in der Bildergalerie:
   ein Video zwischen Standbildern unterbricht das Durchblaettern. */
/* Der Film ist das erste Blatt der Galerie und verhaelt sich dort wie
   eine Aufnahme: er fuellt die Flaeche, ohne sie zu sprengen. Vergroessern
   laesst er sich nicht - ein Klick gilt seiner Bedienleiste. */
.ov-slide-film{ cursor:default; }
.ov-slide-film video{
  /* Am 30.10.2026 auf Wunsch: derselbe Rahmen wie ein Querformat -
     gleiche Breite, gleiches 3:2. Vorher stand der Film in 16:9 und
     nur zwei Drittel breit und fiel damit doppelt aus der Reihe.
     16:9 auf 3:2 heisst links und rechts je rund 8 Prozent weniger. */
  display:block; width:min(100cqw, calc(100cqh * 1.5), 1200px);
  height:auto; max-width:none; max-height:none;
  aspect-ratio:3 / 2; object-fit:cover; background:transparent;
}
.ov-slide-film figcaption{
  position:absolute; left:var(--space-s); right:var(--space-s);
  bottom:var(--space-2xs); text-align:center;
  font-size:var(--fs-micro); color:var(--ink-3);
}
/* Am Telefon waeren von zwei Dritteln nur 257 von 390 Punkten uebrig -
   dort laeuft der Film wie die Fotos ueber die volle Breite. Die Regel
   steht NACH der Zwei-Drittel-Regel: beide wiegen gleich schwer, es
   gilt die spaetere. */
@media (max-width: 760px){
  .ov-slide-film video, .ov-film video, .ps-film video{
    width:100%; max-width:100%; margin-inline:0;
  }
}
.ov-film, .ps-film{ margin-top:var(--space-m); max-width:52ch; }
.ps-film{ max-width:42rem; }
.ov-film video, .ps-film video{
  /* Zwei Drittel der Breite, mittig - und ohne schwarzen Grund, der
     ueber und unter dem 16:9-Bild als Balken stehen blieb. */
  display:block; width:66%; margin-inline:auto; aspect-ratio:16/9;
  background:transparent; border:0;
}
.ov-film figcaption, .ps-film figcaption{
  margin-top:var(--space-2xs); font-size:var(--fs-micro); color:var(--ink-3);
}
/* Der Untertitel ist der Claim aus der Projektmappe. Er steht zwischen
   Projektnamen und Angaben und traegt keine eigene Auszeichnung. */
.ov-unter{ color:var(--ink-3); font-size:var(--fs-sub); max-width:52ch; margin-top:var(--space-2xs); }
.ov-contact{
  margin-top:auto; display:inline-flex; align-items:center; gap:.6rem; width:fit-content; white-space:nowrap;
  background:var(--red-aa); color:#fff; padding:.8rem 1.2rem;
  font-weight:700; letter-spacing:.06em; text-transform:uppercase; font-size:var(--fs-sub);
}
.ov-contact:hover{ background:var(--red-press); }

.ov-gallery{ position:relative; min-width:0; min-height:0; }
.ov-track{ display:flex; height:100%; overflow-x:auto; overflow-y:hidden; scroll-snap-type:x mandatory; }
/* Jede Ansicht nutzt die volle Flaeche. Die Deckelung auf --iw/--ih
   (die echten Pixelmasse der Datei) verhindert Hochskalieren: das
   Bild wird so gross wie moeglich, aber nie unscharf gerechnet. */
/* container-type:size macht 100cqw und 100cqh im Bild darunter
   verfuegbar. Ohne das laesst sich der Rahmen nicht aus der Hoehe der
   Flaeche ableiten - eine Prozentangabe fuer die Hoehe bleibt in der
   Kette Dialog > Koerper > Galerie > Spur unbestimmt. */
.ov-slide{ flex:0 0 100%; min-width:0; min-height:0; scroll-snap-align:start; position:relative; padding:var(--space-2xs); container-type:size; display:grid; place-items:center; }
.ov-slide img{
  /* Das Bild waechst bis zur Breite der Flaeche, hoechstens aber auf das
     1,5-fache seiner echten Pixelbreite: darueber wird es sichtbar weich,
     die Quellen liegen bei 640 px Medianbreite.
     Wichtig ist die Trennung der beiden Grenzen. Frueher stand hier
     max-height:min(100%, ...). Die Prozentangabe wurde in min() nicht
     aufgeloest, hochformatige Bilder standen dadurch mit 897 px in einer
     827 px hohen Flaeche und waren unten um 70 px abgeschnitten.
     max-height:100% allein greift zuverlaessig, und weil die Hoehe auto
     ist, zieht sie die Breite massstabsgetreu mit. */
  /* Das Bild wird absolut in die Flaeche gelegt. Nur so ist der Bezug
     fuer die Prozentangaben eindeutig: die Hoehenkette Dialog > Koerper >
     Galerie > Spur ist im Flusslayout unbestimmt, weshalb sowohl
     max-height:min(100%, ...) als auch max-height:100% wirkungslos blieben
     und hochformatige Aufnahmen unten abgeschnitten waren.
     Jetzt ist der Kasten exakt die Flaeche, object-fit:contain zeigt darin
     immer das ganze Bild, und die beiden Hoechstmasse deckeln auf das
     1,5-fache der echten Pixelmasse, damit nichts weichgerechnet wird. */
  /* Der Bezugsrahmen fuer die Prozentangaben ist der Polsterkasten der
     Flaeche, also ihre volle Breite. inset rueckt das Bild um den Rand
     nach innen, width:100% machte es aber wieder so breit wie die ganze
     Flaeche - es stand damit um genau diesen Rand nach rechts ueber.
     Beim letzten Bild einer Reihe verlaengerte das die Spur um 8 px:
     das Weiterklicken sprang in Bildbreiten und kam an diese letzten
     8 px nie heran, der Pfeil wirkte dadurch ohne Funktion (gemessen
     bei ÖLZ-Frischdienst-Zentrum und Eco Center). Der Rand muss
     deshalb doppelt abgezogen werden, links und rechts. */
  /* Ein Format fuer alle Aufnahmen: der Kasten ist der groesste 3:2-
     Ausschnitt, der in die Flaeche passt, und bleibt damit von Bild zu
     Bild gleich. Vorher war er so hoch wie die ganze Flaeche (864x827,
     fast quadratisch); darin stand eine querformatige Aufnahme 616 px
     hoch, eine hochformatige 811 px, ein Streifen 289 px - beim
     Weiterklicken sprang die Bildgroesse um das Dreifache.
     3:2 ist das Format, das 75 der 105 Galeriebilder ohnehin haben.
     object-fit:contain zeigt darin weiterhin das ganze Bild: die 19
     hochformatigen und 6 streifenfoermigen Aufnahmen stehen vollstaendig
     im gleichen Rahmen, nur mit Rand daneben. Ein abgeschnittenes
     Gebaeude waere schlimmer als dieser Rand.
     Die frueheren Hoechstmasse je Bild (1,5-fache der echten Pixelmasse)
     sind entfallen - sie haetten den Rahmen je nach Dateigroesse wieder
     unterschiedlich gross gemacht, also genau das Springen zurueckgeholt.
     Das Hochrechnen deckelt jetzt der Rahmen selbst: bei 1280 px
     Fensterbreite ist er rund 848x565 gross, eine 640 px breite Datei
     wird darin auf das 1,33-fache gerechnet. Die Obergrenze von 1200 px
     haelt das auch auf sehr grossen Schirmen in Grenzen. */
     Die Breite steht ausdruecklich da und wird nicht dem Bild
     ueberlassen: bei width:auto nimmt ein Bild seine echte Pixelbreite
     an, der Rahmen waere dann bei einer 640er Datei 639 px und bei
     einer 1800er 847 px breit - wieder verschieden gross. Deshalb der
     kleinste der drei Werte: Breite der Flaeche, Hoehe der Flaeche mal
     1,5 (sonst steht der Rahmen unten ueber) und 1200 px Obergrenze.
     Die Hoehenangabe braucht Container-Einheiten; 100% loeste sich in
     der Hoehenkette des Dialogs nicht auf. */
     Das Bild steht wieder im Fluss und wird vom Raster der Flaeche
     mittig gesetzt. Die fruehere absolute Lage mit margin:auto konnte
     nicht mittig stehen: dafuer muesste die Hoehe fest angegeben sein,
     sie ergibt sich hier aber aus dem Seitenverhaeltnis. Das Bild hing
     dadurch oben und darunter blieb ein grosses Loch.
     Die Container-Einheiten rechnen ab dem Inhaltskasten, das Polster
     ist darin schon abgezogen - es darf kein zweites Mal abgehen. */
  /* Am 30.10.2026 auf Wunsch von contain auf cover gewechselt: der
     Rahmen war schon einheitlich, das Foto stand aber mit Rand darin.
     Jetzt fuellt es ihn aus - ein einheitlicher Ausschnitt statt
     unterschiedlich grosser Bilder in gleichen Rahmen. Gemessen ueber
     61 Galeriefotos kostet 3:2 im Schnitt 8,4 Prozent des Bildes;
     30 der 54 Querformate haben es ohnehin schon. */
  margin:0;
  width:min(100cqw, calc(100cqh * 1.5), 1200px);
  height:auto;
  aspect-ratio:3 / 2;
  object-fit:cover;
}
/* Ein Rahmen je Lage statt einem fuer alle.
   Der eine 3:2-Rahmen hielt die Groesse beim Weiterklicken ruhig, war
   fuer ein Hochformat aber zu niedrig: in einem 848x565 grossen Rahmen
   stand eine 3:4-Aufnahme 424 px breit - halb so breit wie das
   Querformat daneben. Mit einem eigenen 3:4-Rahmen nutzt sie die ganze
   Hoehe der Flaeche und steht 620 px breit.
   Ruhig bleibt es weiterhin: zwei Querformate hintereinander sind
   gleich gross, zwei Hochformate auch. Nur beim Wechsel zwischen den
   Lagen aendert sich der Rahmen - und das ist der Sinn der Sache.
   3:4 ist die Mitte der 28 Hochformate (0,75); die Spanne reicht von
   0,56 bis 0,85, object-fit:contain zeigt jede davon vollstaendig. */
.ov-slide.ist-hoch img{
  width:min(100cqw, calc(100cqh * 0.75), 900px);
  aspect-ratio:3 / 4;
}
/* Sehr breite Aufnahmen bleiben ganz. Auf 3:2 beschnitten bliebe von
   einem 3,3:1-Panorama die Mitte uebrig - mehr als die Haelfte waere
   weg. Die Grenze liegt bei 1,9:1; darueber zaehlt die echte Form.
   Eine Grenze von 1,6 waere die naheliegende Loesung fuer die
   Laderampenfassade bei Pacovis (1,66:1) gewesen - sie haette aber
   auch die 23 Aufnahmen in 16:9 vom Zuschnitt ausgenommen, und damit
   waeren 46 statt 13 der 318 Fotos aus der Reihe gefallen. Das eine
   Foto ist deshalb namentlich ausgenommen, siehe die Lagebestimmung
   weiter unten. */
.ov-slide.ist-panorama img{
  width:min(100cqw, 1200px);
  max-height:100cqh;
  aspect-ratio:calc(var(--iw, 2px) / var(--ih, 1px));
  object-fit:contain;
}
/* Deckende Flaeche statt weisser Button: der linke Pfeil steht neben
   der weissen Infospalte und war dort praktisch unsichtbar, der rechte
   auf dem Foto. Beide lesen sich jetzt auf jedem Untergrund gleich. */
.gal-btn{
  position:absolute; top:50%; translate:0 -50%; z-index:5;
  display:grid; place-items:center; width:2.75rem; height:2.75rem;
  background:var(--ink); color:var(--paper); cursor:pointer;
  border:0; border-radius:var(--radius); font-size:1.35rem;
  box-shadow:0 2px 10px rgb(0 0 0 / .28);
  transition:background .2s var(--ease), transform .15s var(--ease);
}
.gal-btn:hover{ background:var(--red-aa); color:#fff; }
.gal-btn:active{ transform:translateY(-50%) scale(.94); }
/* Ein Druck auf den Pfeil darf weder Text markieren noch als Ziehen
   oder Doppeltipp gewertet werden - beides verschluckt sonst den
   Tastendruck. */
.gal-btn, .gross-nav, .ov-gross-zu{
  touch-action:manipulation; user-select:none; -webkit-user-select:none;
}
.gal-prev{ left:var(--space-2xs); } .gal-next{ right:var(--space-2xs); }

/* Rechtsangaben im Impressum als Begriffsliste. */
.impressum-daten{ display:grid; gap:.35rem; margin:0; font-size:var(--fs-micro); line-height:1.55; }
.impressum-daten > div{ display:grid; grid-template-columns:11rem minmax(0,1fr); gap:var(--space-s); }
.impressum-daten dt{ color:var(--ink-3); letter-spacing:.06em; text-transform:uppercase; }
.impressum-daten dd{ margin:0; color:var(--ink); }

/* Die Karte laedt erst auf Klick, damit ohne Zutun keine Verbindung
   zu Google aufgebaut wird. */
.map-consent{
  position:absolute; inset:0; display:grid; place-content:center; justify-items:center;
  gap:var(--space-2xs); padding:var(--space-m); text-align:center;
  background:var(--surface-2); color:var(--ink-2); font-size:var(--fs-micro); line-height:1.5;
}
.map-consent button{
  background:var(--ink); color:var(--paper); border:0; cursor:pointer;
  padding:.7rem 1.1rem; font-weight:700; letter-spacing:.06em; text-transform:uppercase; font-size:var(--fs-micro);
}
.map-consent button:hover{ background:var(--red-aa); }
.map-wrap.is-loaded .map-consent{ display:none; }
/* Die einmalige Frage nach der Karte. Sie sitzt unten, nimmt wenig Raum
   und verschwindet mit der Antwort fuer sechs Monate. */
.karte-frage{
  position:fixed; left:0; right:0; bottom:0; z-index:200;
  display:flex; flex-wrap:wrap; gap:var(--space-s); align-items:center;
  padding:var(--space-s) var(--space-m);
  background:var(--paper); border-top:2px solid var(--ink);
  box-shadow:0 -2px 14px rgba(0,0,0,.12);
  font-size:var(--fs-micro); line-height:1.5;
}
.karte-frage p{ margin:0; flex:1 1 20rem; color:var(--ink-2); }
.karte-frage-knoepfe{ display:flex; gap:var(--space-2xs); margin-left:auto; }
.karte-frage button{
  font:inherit; font-weight:700; letter-spacing:.06em; text-transform:uppercase;
  padding:.5em 1em; border:1px solid var(--ink); border-radius:var(--radius);
  background:var(--paper); color:var(--ink); cursor:pointer; white-space:nowrap;
}
.karte-frage button[data-ja]{ background:var(--red-aa); border-color:var(--red-aa); color:#fff; }
.karte-frage button:hover{ opacity:.85; }

/* Anrufen als zweite Handlung neben dem Kontaktknopf. */
.cta-call{
  background:var(--paper); color:var(--red-text); border:1px solid var(--red-aa);
  margin-top:var(--space-2xs); white-space:normal;
}
.cta-call:hover{ background:var(--red-aa); color:#fff; }
.ov-contact.ov-call{ margin-top:0; background:var(--paper); color:var(--red-text); box-shadow:inset 0 0 0 1.5px var(--red-aa); }
.ov-contact.ov-call:hover{ background:var(--red-aa); color:#fff; }
/* ---------- 7. Seiten unterhalb des Rasters ---------- */
/* Wie im Bestand: jede Aussage bekommt einen eigenen Bildschirm.
   Titelseiten sind mittig gesetzt, Rasterseiten fuellen die Breite. */
.section{
  min-height:100dvh;
  display:flex; flex-direction:column; justify-content:center;
  padding:var(--space-xl) var(--space-l);
  padding-right:calc(var(--sidebar-w) + var(--space-l));
  border-top:1px solid var(--line);
}
.section-tight{ min-height:auto; padding-block:var(--space-l); border-top:0; }
.page-kicker{
  font-size:var(--fs-sub); font-weight:700; letter-spacing:.24em; text-transform:uppercase;
  color:var(--red-text); margin-bottom:var(--space-s);
}
.section h2{ font-size:var(--fs-h2); font-weight:700; line-height:1.08; letter-spacing:.06em; text-transform:uppercase; margin-bottom:var(--space-m); text-wrap:balance; }
.section p{ color:var(--ink-2); max-width:62ch; }
.section p + p{ margin-top:var(--space-s); }
.narrow{ max-width:48rem; }
/* Unterpunkt innerhalb eines Abschnitts - kleiner als eine h2, aber in
   derselben Sprache: Versalien, weit gesperrt, roter Strich davor. */
.team-titel{
  font-size:var(--fs-h3); font-weight:700; letter-spacing:.14em; text-transform:uppercase;
  margin-bottom:var(--space-s); display:flex; align-items:center; gap:.7em;
}
.team-titel::before{ content:""; width:2.2em; height:3px; background:var(--red); flex:none; }
/* Die Schaltflaeche steht unter dem Absatz, nicht daneben: sie ist ein
   Weg weiter, kein Teil des Satzes. */
.team-btn{ margin-top:var(--space-m); }
/* Dasselbe Format wie ueberall sonst: 3:2 quer. */
.team-figur{ margin-top:var(--space-m); background:var(--surface-2); }
.team-figur img{ display:block; width:100%; aspect-ratio:3 / 2; object-fit:cover; }
.team-figur figcaption{
  margin-top:var(--space-2xs); font-size:var(--fs-micro);
  letter-spacing:.1em; text-transform:uppercase; color:var(--ink-3);
}

/* Titelseite: Kicker, Titel und Einleitung zentriert auf einem Schirm. */
.section-title{ align-items:center; text-align:center; }
/* Ein Gedanke je Bildschirm: die Titelseite von Kompetenzen und Karriere
   fuellt eine ganze Seite, damit beim Sprung dorthin wirklich nur sie zu
   sehen ist. Der Inhalt darunter beginnt am Kopf der naechsten Seite -
   deshalb dort kein oberer Abstand und keine Trennlinie, sonst stuende
   zwischen Titel und Inhalt noch einmal eine halbe Seite Luft. */
/* Beide Titelseiten sind bewusst kuerzer als eine Bildschirmhoehe:
   unter dem Text stand sonst der leere Rest der Seite - gemessen
   265 px bei Karriere - und der Inhalt darunter rutschte entsprechend
   weit nach unten. */
#pageKompetenzen, #pageKarriere{ min-height:auto; }
#pageKompetenzen + .section,
#pageKarriere + .section{
  min-height:auto; border-top:0; padding-bottom:var(--space-xl);
  /* Soviel Luft, dass "Offene Stellen" nicht an der Aufzaehlung der
     Titelseite klebt, aber keine halbe Leerseite entsteht. */
  padding-top:var(--space-l);
}
.section-title p{ margin-inline:auto; }

/* Das Foto ist 900x600, also genau 3:2. Der Rahmen hat dieses Format,
   damit nichts beschnitten wird - weder die Koepfe oben noch der Tisch
   mit den Plaenen unten. object-position ist damit gegenstandslos. */
.about-figure{ margin-top:var(--space-m); aspect-ratio:3/2; overflow:hidden; background:var(--surface-2); max-width:min(100%, 62vh); margin-inline:auto; }
.about-figure img{ width:100%; height:100%; object-fit:cover; filter:grayscale(20%); }
/* subgrid: Foto, Name, Rolle, Funktion und Mail liegen bei allen vier
   Karten auf derselben Hoehe, auch wenn eine Rollenbezeichnung laenger
   ist. Ersetzt die Hoehenangleichung per JavaScript aus dem Bestand. */
.partners{
  margin-top:var(--space-l); display:grid;
  grid-template-columns:repeat(4,minmax(0,1fr));
  grid-template-rows:auto auto auto auto auto;
  gap:var(--space-m);
}
.partner{ display:grid; grid-row:span 5; grid-template-rows:subgrid; gap:.25rem; }
@supports not (grid-template-rows: subgrid){
  .partner{ grid-row:auto; grid-template-rows:none; align-content:start; }
  .pt-role{ min-height:3.4em; }
}
/* Der Wert object-position je Portrait ist gemessen, nicht geschaetzt:
   die Scheitel liegen in den Aufnahmen zwischen 3,5 % (Steffel) und
   10,5 % (Pelikan) der Bildhoehe. Die Werte im Markup ruecken alle vier
   auf 5 % der Rahmenhoehe; nur Steffel bleibt bei 3,9 %, weil sein Bild
   darueber keine Reserve mehr hat. Der Unterschied betraegt rund 4 px. */
.partner-photo{ aspect-ratio:1/1.3; overflow:hidden; background:var(--surface-2); margin-bottom:var(--space-2xs); position:relative; }
/* Jedes Portrait bekommt einen eigenen Zuschnitt, weil die vier Aufnahmen
   unterschiedlich eng gefasst sind: die Scheitel liegen zwischen 3,5 %
   (Steffel) und 10,5 % (Pelikan) der Bildhoehe, und die Koepfe sind
   verschieden gross. --zoom gleicht die Kopfgroesse an, --oben setzt alle
   Scheitel auf 4 % der Rahmenhoehe. Die Werte stehen am Bild und sind
   gerechnet, nicht geschaetzt. */
.partner-photo img{
  position:absolute; left:50%; top:var(--oben, 0%);
  /* max-width:none hebt den globalen Bild-Reset auf, der sonst den
     Zoom wieder auf die Rahmenbreite zurueckdeckeln wuerde. */
  width:calc(100% * var(--zoom, 1)); max-width:none; height:auto;
  transform:translateX(-50%);
  filter:grayscale(25%); transition:filter .4s var(--ease);
}
.partner:hover .partner-photo img{ filter:grayscale(0%); }
/* Der Name steht in einer Zeile.
   KEIN container-type auf .partner: die Karte ist ein Raster, und der
   Einschluss liess ihre Zeilen zusammenfallen - Foto, Name, Rolle und
   Adresse lagen danach uebereinander, die Karte war 176 statt 560 Punkt
   hoch. Der Schriftgrad haengt deshalb am Fenster.
   Gerechnet: die Spalte misst ein Viertel der Inhaltsbreite, also rund
   0,147 der Fensterbreite. "DI Christian Steffel" braucht das 10,4fache
   seines Schriftgrads; damit passt er bis 1,4 % der Fensterbreite. */
.pt-name{
  font-size:min(var(--fs-h3), 1.4vw); font-weight:700; line-height:1.15;
  white-space:nowrap;
}
.pt-role{ font-size:var(--fs-sub); color:var(--ink-2); }
.pt-sub{ font-size:var(--fs-micro); letter-spacing:.12em; text-transform:uppercase; color:var(--ink-3); }
/* Die vier Adressen sind der einzige Weg zu einer bestimmten Person und
   stehen jeweils allein in ihrer Zeile. Als reiner Textlink waren sie
   21 px hoch und damit unter den 24 px, die WCAG 2.2 fuer eigenstaendige
   Bedienelemente verlangt. Das Innenmass hebt sie darueber, ohne das
   Schriftbild zu aendern. */
.pt-mail{
  display:inline-block; font-size:var(--fs-sub); color:var(--red-text);
  word-break:break-word; margin-top:.2rem; padding-block:.2rem; min-height:24px;
}
.pt-mail:hover{ text-decoration:underline; }

.komp{ margin-top:var(--space-l); display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:var(--space-m); }
/* minmax(0,1fr) statt auto: ein auto-Track waechst auf die Max-Content-
   Breite des nowrap-Titels und zieht damit Bild, Untertitel und Liste
   mit ueber die Spaltenbreite hinaus. */
.komp-col{ display:grid; grid-template-columns:minmax(0,1fr); gap:var(--space-s); align-content:start; container-type:inline-size; }
.jobs-col{ container-type:inline-size; grid-template-columns:minmax(0,1fr); }
/* Die Disziplin-Titel auf den Inhaltsseiten stehen auf nowrap. "TRAGWERKSPLANUNG"
   ist das laengste Wort und ragte dadurch samt rotem Rahmen ueber seine Spalte
   hinaus, was die drei Spalten unterschiedlich breit wirken liess. Schriftgroesse
   und Innenabstand rechnen hier deshalb aus der Spaltenbreite. */
.komp-col > .g-title, .jobs-col > .g-title{
  /* Kein eigener Schriftgrad mehr: die Titel bei Kompetenzen und
     Karriere sollen genau so aussehen wie die Spaltenbanner im
     scrollbaren Teil. Sie erben deshalb alles aus .g-title. Weil auch
     diese Spalten Abfragecontainer sind, bezieht sich das dortige 8cqi
     auf ihre eigene Breite - die Groesse passt sich also genauso an.
     Gemessen waren es vorher 21,6 px gegen 23,5 px im Banner.
     Etwas knapperer seitlicher Innenabstand als im Banner (.4rem):
     der Pfeil neben dem Wort kostet Platz, den das Banner nicht
     braucht, und bei 1101 px fehlten damit noch 2 px. Die Rahmen
     bleiben gleich breit, nur die Luft darin ist knapper. */
  padding-left:.15rem; padding-right:.15rem;
  min-width:0; overflow:hidden;
}
.komp-figure{ aspect-ratio:4/3; overflow:hidden; background:var(--surface-2); }
/* Auch das Bild fuehrt zu den Projekten der Sparte. */
.komp-bild{ display:block; width:100%; height:100%; }
.komp-figure img{ width:100%; height:100%; object-fit:cover; filter:grayscale(30%); transition:filter .4s var(--ease); }
.komp-col:hover .komp-figure img{ filter:grayscale(0%); }
.komp-sub{ font-size:var(--fs-sub); color:var(--ink-2); }
.komp-list{ list-style:none; display:grid; gap:.5rem; font-size:var(--fs-sub); }
.komp-list li{ padding-left:1.1rem; position:relative; color:var(--ink-2); }
.komp-list li::before{ content:""; position:absolute; left:0; top:.62em; width:.5rem; height:1px; background:var(--red); }

.karriere-split{ display:grid; grid-template-columns:minmax(0,1.2fr) minmax(0,1fr); gap:var(--space-l); align-items:start; }
.benefits{ list-style:none; display:grid; gap:0; }
.benefits li{ display:flex; align-items:baseline; gap:.7rem; padding:var(--space-2xs) 0; border-top:1px solid var(--line); font-size:var(--fs-sub); }
.benefits li:last-child{ border-bottom:1px solid var(--line); }
.benefits .check{ color:var(--red-text); font-size:1.05em; flex:none; align-self:center; }
.benefits b{ color:var(--red-text); }
/* Links in der Liste muessen als solche erkennbar sein: die Seite setzt
   a{text-decoration:none}, ohne diese Regel saehe die Adresse aus wie
   gewoehnlicher Text. */
.benefits a{ color:var(--red-text); text-decoration:underline; text-underline-offset:.2em; }
.benefits a:hover{ text-decoration-thickness:2px; }

/* Derselbe Rhythmus wie auf den Titelseiten: dort stehen zwischen dem
   kleinen roten Text und der Ueberschrift 19 px und zwischen der
   Ueberschrift und dem Text darunter 33 px. Hier waren es gemessen 8 px
   und 91 px. */
.open-jobs{ text-align:center; display:grid; gap:var(--space-s); }
/* Halber Abstand zur Stellenliste. Der Selektor braucht das h2: die
   Vorgabe kommt aus ".section h2" und schlaegt ein blosses ".open-jobs". */
.section h2.open-jobs{ margin-bottom:calc(var(--space-m) / 2); }
.open-jobs span{
  display:block; font-size:var(--fs-sub); font-weight:400;
  letter-spacing:.14em; text-transform:uppercase; color:var(--red-text);
}
.section-title .benefits{ margin-top:var(--space-m); text-align:left; width:min(100%, 32rem); }
/* Kein eigener oberer Abstand: die Ueberschrift darueber bringt ihren
   schon mit (--space-m). Zusammen waren es sonst 91 px. */
.jobs-grid{ margin-top:0; display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:var(--space-m); }
.jobs-col{ display:grid; grid-template-columns:minmax(0,1fr); gap:var(--space-s); align-content:start; }
.job{
  display:grid; gap:.45rem; text-align:left; width:100%;
  background:var(--surface); color:inherit; cursor:pointer;
  border:0; border-left:3px solid var(--red); border-radius:var(--radius);
  padding:var(--space-s);
  transition:background .2s var(--ease), transform .15s var(--ease);
}
.job:hover{ background:var(--surface-2); transform:translateX(3px); }
.job-title{ font-size:var(--fs-base); font-weight:700; line-height:1.2; }
.job-type{ font-size:var(--fs-micro); letter-spacing:.12em; text-transform:uppercase; color:var(--ink-3); }
.job-desc{ font-size:var(--fs-sub); color:var(--ink-2); }
.job-pay{ font-size:var(--fs-micro); color:var(--ink-3); line-height:1.45; }
.job-pay b{ color:var(--ink); }
/* Die Pflichtangabe zur Einstufung ist der laengste Text auf der
   Kachel. Sie muss nach dem Gleichbehandlungsgesetz im Inserat
   stehen, aber nicht dauernd offen: zugeklappt bleibt die Kachel
   ueberschaubar, ein Klick zeigt den vollen Wortlaut. */
details.job-pay{ border-top:1px solid var(--line); padding-top:.5rem; }
details.job-pay > summary{
  list-style:none; cursor:pointer; display:flex; align-items:center;
  gap:.4rem; color:var(--ink-2); font-weight:700;
  font-size:var(--fs-micro); letter-spacing:.08em; text-transform:uppercase;
}
details.job-pay > summary::-webkit-details-marker{ display:none; }
details.job-pay > summary::after{
  content:""; width:.45rem; height:.45rem; margin-left:auto;
  border-right:1.5px solid currentColor; border-bottom:1.5px solid currentColor;
  transform:rotate(45deg) translate(-.1em, -.1em);
  transition:transform .25s var(--ease);
}
details.job-pay[open] > summary::after{ transform:rotate(225deg) translate(-.05em, -.05em); }
details.job-pay > summary:hover{ color:var(--red-text); }
details.job-pay .job-pay-text{ display:block; margin-top:.45rem; }
/* Ansprechperson: etwas kraeftiger als der Entgelthinweis, damit der
   Name als Anlaufstelle lesbar ist und nicht im Kleingedruckten liegt. */
.job-kontakt{ font-size:var(--fs-micro); color:var(--ink-2); font-weight:700; letter-spacing:.02em; }

/* Eckdaten der Stelle, wie im eigenen Inserat unter "Über den Job".
   Beschriftung und Wert als zwei Spalten; die Beschriftung ist so breit
   wie das laengste Wort, damit die Werte auf einer Kante stehen. */
.job-fakten{ display:grid; gap:.55rem; margin:.15rem 0 .1rem; }
/* Bezeichnung oben, Angabe darunter - beide ueber die volle Breite.
   Vorher standen sie nebeneinander, wobei die linke Spalte 7,6rem
   fest belegte. In der schmalen Kachel blieb fuer die Angabe so wenig
   Platz, dass fast jede Zeile umbrach ("Projekt-/Bereichsleitung" auf
   zwei, "Fuehrung, Management, Technik, Ingenieurwesen" auf vier
   Zeilen). Untereinander steht jede Angabe in einer Zeile. */
.job-fakt{ display:grid; grid-template-columns:minmax(0,1fr); gap:.1rem; }
.jf-k{ font-size:var(--fs-micro); letter-spacing:.06em; text-transform:uppercase; color:var(--ink-3); }
.jf-v{ font-size:var(--fs-sub); color:var(--ink); }
/* Zwei Knoepfe mittig unter den Eckdaten, untereinander und gleich
   breit: "Details" fuehrt in die volle Ansicht, "Direkt bewerben"
   sofort ins Formular. */
.job-knoepfe{ display:grid; gap:.4rem; justify-items:stretch; margin-top:var(--space-s); }
.job-mehr{
  display:inline-flex; align-items:center; justify-content:center; gap:.5rem;
  background:none; border:1.5px solid var(--line); border-radius:var(--radius);
  padding:.6rem 1rem; cursor:pointer; color:var(--red-text);
  font:inherit; font-size:var(--fs-micro); font-weight:700;
  letter-spacing:.1em; text-transform:uppercase; text-align:center;
  transition:background .2s var(--ease), border-color .2s var(--ease), color .2s var(--ease);
}
.job-mehr:hover{ background:var(--red-aa); border-color:var(--red-aa); color:#fff; }
.job-mehr-rot{ background:var(--red-aa); border-color:var(--red-aa); color:#fff; }
.job-mehr-rot:hover{ background:var(--red-press); border-color:var(--red-press); }

/* Textbereich der Stellenansicht, an der Stelle der Bildergalerie. */
.job-text{ min-width:0; overflow-y:auto; padding:var(--space-l) var(--space-xl) var(--space-xl); }
/* Der Stellentitel darf nicht in der Wortmitte getrennt werden. Fuer
   Projektnamen ist "overflow-wrap:anywhere" richtig - die sind kurz und
   wuerden sonst ueberstehen. Ein Stellentitel besteht dagegen aus langen
   Woertern; dort erzeugte die Regel "Ört-liche" mit Trennstrich und
   einen Schraegstrich allein in einer Zeile. Hier bleibt jedes Wort
   ganz, umbrochen wird nur zwischen den Woertern. */
.job-dialog .ov-info h2{
  hyphens:none; overflow-wrap:normal; word-break:normal;
  letter-spacing:0; text-wrap:balance;
  font-size:clamp(1.25rem, 1rem + 1.2vw, 2rem);
}
/* Mit Bild zwei Spalten: Aufgaben und Voraussetzungen links, das Foto
   rechts daneben. Ohne Bild laufen die Listen ueber die volle Breite,
   damit kein leerer Kasten stehen bleibt. */
/* Das Bild bekommt die groessere Haelfte: die Listen sind schmale
   Aufzaehlungen, das Foto traegt die Flaeche. Gemessen waren beide
   Spalten sonst nur 287 px breit. */
.job-text-bild{
  display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1.35fr);
  gap:var(--space-l); align-items:start;
  padding-left:var(--space-l); padding-right:var(--space-l);
}
.job-bild{ margin:0; background:var(--surface-2); position:sticky; top:var(--space-l); }
.job-bild img{ display:block; width:100%; height:auto; filter:grayscale(15%); }
@media (max-width: 1100px){
  .job-text-bild{ grid-template-columns:minmax(0,1fr); gap:var(--space-l); }
  .job-bild{ position:static; order:-1; }
}
/* Gleichmaessige Abstaende in der Infospalte der Stellenansicht. */
.job-dialog .ov-info{ gap:var(--space-m); }
/* Der Entgelthinweis ist Pflichtangabe, aber kein Fliesstext: er stand
   in voller Textgroesse und nahm dadurch mehr Platz ein als die
   Eckdaten darueber. Kleiner gesetzt, mit engerem Zeilenabstand. */
.job-dialog .ov-desc{
  margin:0; font-size:var(--fs-micro); line-height:1.5; color:var(--ink-3);
}
.job-h{
  margin-top:var(--space-m); margin-bottom:var(--space-2xs);
  font-size:var(--fs-micro); font-weight:700;
  letter-spacing:.12em; text-transform:uppercase; color:var(--red-text);
}
.job-h:first-child{ margin-top:0; }
.job-liste{ list-style:none; display:grid; gap:.45rem; }
.job-liste li{ position:relative; padding-left:1.2rem; font-size:var(--fs-sub); color:var(--ink-2); }
.job-liste li::before{ content:""; position:absolute; left:0; top:.62em; width:.5rem; height:1px; background:var(--red); }
/* Der Bewerbungsknopf sitzt in der Infospalte an derselben Stelle wie
   "Kontaktieren Sie uns hier" in der Projektansicht und erbt deren Form
   ueber .ov-contact; als <button> braucht er nur die Schrift zurueck. */
.job-apply{ border:0; cursor:pointer; font:inherit; font-weight:700; letter-spacing:.06em; text-transform:uppercase; font-size:var(--fs-sub); }
.job-go{ display:inline-flex; align-items:center; gap:.4rem; margin-top:.2rem; font-size:var(--fs-micro); font-weight:700; letter-spacing:.1em; text-transform:uppercase; color:var(--red-text); }

.form{ margin-top:var(--space-l); display:grid; gap:var(--space-s); max-width:44rem; }
.form-row{ display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:var(--space-s); }
.field{ display:grid; gap:.35rem; }
.field label{ font-size:var(--fs-micro); font-weight:700; letter-spacing:.1em; text-transform:uppercase; color:var(--ink-2); }
.field input, .field select, .field textarea{
  width:100%; padding:.8rem .9rem; background:var(--paper); color:var(--ink);
  border:1.5px solid var(--line); border-radius:var(--radius); font-size:var(--fs-base);
  transition:border-color .2s var(--ease), box-shadow .2s var(--ease);
}
.field input::placeholder, .field textarea::placeholder{ color:var(--ink-3); }
/* Kein Fokusverlust: die Standard-outline wird durch einen gleich
   starken, deckenden Ring ersetzt (WCAG 2.2 SC 2.4.13). */
.field input:focus-visible, .field select:focus-visible, .field textarea:focus-visible{
  outline:none; border-color:var(--red); box-shadow:0 0 0 3px var(--red);
}
.field textarea{ min-height:9rem; resize:vertical; }
.field-hint{ font-size:var(--fs-micro); color:var(--ink-3); }
.form-file{ border:1.5px dashed var(--line); padding:var(--space-s); display:grid; gap:.45rem; }
.form-submit{
  display:inline-flex; align-items:center; gap:.6rem; width:fit-content; white-space:nowrap;
  background:var(--red-aa); color:#fff; border:0; cursor:pointer;
  padding:.95rem 1.6rem; border-radius:var(--radius);
  font-weight:700; letter-spacing:.06em; text-transform:uppercase; font-size:var(--fs-sub);
  transition:background .2s var(--ease), transform .12s var(--ease);
}
.form-submit:hover{ background:var(--red-press); }
.form-submit:active{ transform:translateY(1px); }
.form-submit[aria-busy="true"]{ opacity:.7; cursor:progress; }
.form-status{ font-size:var(--fs-sub); padding:var(--space-s); border-left:3px solid var(--red); background:var(--surface); }
.form-status[hidden]{ display:none; }
/* Rueckmeldung nach dem Absenden. Gelungen und misslungen unterscheiden
   sich nicht allein durch die Farbe - der Text sagt es ohnehin, und die
   Randstaerke ist auch ohne Farbsehen zu erkennen (WCAG 1.4.1). */
.form-status.ist-ok{ border-left-color:var(--ink); }
.form-status.ist-fehler{ border-left-width:6px; }

/* Einwilligung. Das Kaestchen sitzt in der ersten Zeile buendig zur
   Schrift, nicht mittig zum ganzen Absatz. */
.check{ display:grid; grid-template-columns:auto minmax(0,1fr); gap:.7rem; align-items:start; font-size:var(--fs-sub); color:var(--ink-2); }
.check input{ width:1.15rem; height:1.15rem; margin-top:.2rem; accent-color:var(--red-aa); }
.check input:focus-visible{ outline:none; box-shadow:0 0 0 3px var(--red); }
.check a{ color:var(--red-text); text-decoration:underline; text-underline-offset:.2em; }

/* Honigtopf: ein Feld, das nur selbsttaetige Eintraege ausfuellen.
   display:none wuerde von manchen Skripten erkannt, deshalb wird es
   aus dem Bild geschoben und aus der Vorlesereihenfolge genommen. */
.hp{ position:absolute; left:-9999px; width:1px; height:1px; overflow:hidden; }

/* Knopf und Anleitung stehen untereinander und mittig unter der
   Ueberschrift - der ganze Abschnitt ist zentriert gesetzt.
   justify-items:center haelt beide auf ihrer eigenen Breite und ruecht
   sie in die Spaltenmitte; ohne die Angabe zoege das Raster sie ueber
   die ganze Spalte, und der schwarze Knopf waere 579 statt 290 Punkt
   breit. */
.sp-wege{ display:grid; justify-items:center; gap:var(--space-s); margin-top:var(--space-m); }
/* Zweitrangig zum roten Knopf darueber: nur Text mit Linie darunter. */
.sp-blatt{
  display:inline-flex; align-items:center; gap:.45rem;
  font-size:var(--fs-sub); font-weight:700; letter-spacing:.02em;
  color:var(--red-text); border-bottom:1px solid currentColor; padding-bottom:.12em;
}
.sp-blatt:hover{ border-bottom-width:2px; }
.sp-btn{
  display:inline-flex; align-items:center; gap:.6rem; white-space:nowrap;
  background:var(--ink); color:var(--paper); padding:.95rem 1.6rem;
  font-weight:700; letter-spacing:.06em; text-transform:uppercase; font-size:var(--fs-sub);
  transition:background .2s var(--ease), color .2s var(--ease);
}
.sp-btn:hover{ background:var(--red-aa); color:#fff; }

.impressum{ display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1fr); gap:var(--space-l); align-items:start; }
.impressum-text{ display:grid; gap:var(--space-s); font-size:var(--fs-sub); color:var(--ink-2); }
.impressum-text strong{ color:var(--ink); }
.impressum-text a{ color:var(--red-text); }
.impressum-text a:hover{ text-decoration:underline; }
/* Der Verweis auf die Vertragsbedingungen ist der einzige Download der
   Seite und soll als solcher erkennbar sein. */
.avb-link{ color:var(--red-text); text-decoration:underline; text-underline-offset:.2em; }
.avb-link .icon{ width:.8em; height:.8em; vertical-align:-.05em; }
/* Telefon, E-Mail und Web stehen im Adressblock als Textlinks und waren
   auf dem Telefon nur 15 px hoch. Der groessere Zeilenabstand schafft
   Platz fuer eine Klickflaeche von 24 px, ohne den Satz zu veraendern.
   Dieselben Wege gibt es darunter zusaetzlich als grosse Knoepfe. */
.impressum-adresse{ line-height:2; }
.impressum-adresse a{ display:inline-block; padding-block:.3rem; }
.impressum-sozial{ margin:var(--space-2xs) 0 var(--space-s); line-height:1.8; }
.impressum-actions{ display:flex; flex-wrap:wrap; gap:var(--space-2xs); }
.impressum-actions a{
  display:inline-flex; align-items:center; gap:.5rem; white-space:nowrap;
  padding:.7rem 1.1rem; box-shadow:inset 0 0 0 1.5px var(--ink);
  font-size:var(--fs-sub); font-weight:700; letter-spacing:.06em; text-transform:uppercase; color:var(--ink);
  transition:background .2s var(--ease), color .2s var(--ease);
}
.impressum-actions a:hover{ background:var(--red-aa); color:#fff; box-shadow:inset 0 0 0 1.5px var(--red-aa); }
.map-wrap{ position:relative; aspect-ratio:4/3; background:var(--surface-2); }
/* Google setzt seine eigene Markierung auf die Adresse; die Karte darf
   deshalb wieder bedient werden. Der Graustufenfilter entfaellt, sonst
   waere auch die Markierung grau. */
.map-wrap iframe{ width:100%; height:100%; border:0; }
@media (prefers-color-scheme: dark){ .map-wrap iframe{ filter:grayscale(1) invert(.92) contrast(.9); } }
.map-link{
  position:absolute; left:0; bottom:0;
  display:inline-flex; align-items:center; gap:.5rem;
  background:var(--paper); color:var(--ink); padding:.6rem .9rem;
  font-size:var(--fs-micro); font-weight:700; letter-spacing:.08em; text-transform:uppercase;
}
.map-link:hover{ background:var(--red-aa); color:#fff; }

.privacy{
  padding:var(--space-l);
  padding-right:calc(var(--sidebar-w) + var(--space-l));
  background:var(--surface); border-top:1px solid var(--line);
}
.privacy-inner{ font-size:var(--fs-micro); color:var(--ink-3); line-height:1.7; }
.privacy-inner strong{ display:block; color:var(--ink); font-size:var(--fs-sub); letter-spacing:.1em; text-transform:uppercase; margin-bottom:var(--space-2xs); }
.privacy-inner a{ color:var(--red-text); }

/* ---------- 8. Scroll-Reveal ---------- */
.reveal{ opacity:0; transform:translateY(16px); }
.reveal.is-in{ opacity:1; transform:none; transition:opacity .55s var(--ease), transform .55s var(--ease); }

/* ---------- 9. Schmale Ansicht ----------
   Der Briefkopf wird zur festen Leiste am oberen Rand, die sich
   aufklappen laesst. Die Gewerke-Titel bleiben sichtbar und die
   Projektbeschriftung steht dauerhaft unter dem Bild: beides war
   im Bestand auf dem Telefon nicht vorhanden. */
/* Umschaltpunkt bei 1100 px statt 900 px: darunter reicht die Breite fuer
   drei nebeneinanderliegende Spalten nicht aus. Bei 901 px waren sie nur
   170 px breit, Spaltentitel und Kompetenz-Ueberschriften fielen auf
   10 px. Untereinander bleibt bis 1100 px alles lesbar. */
@media (max-width: 1100px){
  /* 64 px Logoleiste, Abstand und die 29 px hohe Gewerke-Leiste darunter,
     gemessen: 110 px. Die Spaltentitel kleben genau darunter, sonst
     ueberdecken sie die Leiste oder lassen einen Schlitz offen, durch den
     die Kacheln durchlaufen. Die Knopfhoehe ist deshalb festgesetzt. */
  :root{ --bar-total:110px; }
  .cols{
    grid-template-columns:1fr; gap:0; height:auto;
    padding:calc(var(--bar-total) + var(--space-s)) var(--space-s) var(--space-l);
  }
  .gewerk{ overflow:visible; }
  .gewerk + .gewerk{ margin-top:var(--space-l); }
  /* Die vier ausgewaehlten Projekte stehen nur hier, vor den Gewerken. */
  .gewerk-vorschau{ display:block; }
  .gewerk-vorschau + .gewerk{ margin-top:var(--space-m); }
  /* Jedes Gewerk laesst sich einzeln auf- und zuklappen. Beim Laden steht
     Architektur offen, damit sofort Projekte zu sehen sind, die beiden
     anderen sind eingeklappt. */
  .g-toggle{
    /* Mittig im Rahmen wie am Desktop: der Klapppfeil steht direkt
       neben dem Wort, nicht am rechten Rand. */
    display:flex; align-items:center; justify-content:center;
    gap:.5em; cursor:pointer;
  }
  .g-caret{ display:block; transition:transform .25s var(--ease); }
  .g-toggle[aria-expanded="false"] .g-caret{ transform:rotate(-90deg); }
  .gewerk.zu .proj-scroll{ display:none; }
  .gewerk.zu + .gewerk{ margin-top:var(--space-s); }
  .g-title{ top:var(--bar-total); text-align:center; font-size:1rem; padding:var(--space-s) var(--space-m); }
  /* Die feste Leiste oben ist 110 px hoch. Ohne diesen Sprungabstand
     landet jedes Sprungziel dahinter und man sieht die Ueberschrift
     nicht, zu der man gesprungen ist. */
  .g-title, .komp-col, .section, .gewerk{ scroll-margin-top:calc(var(--bar-total) + var(--space-2xs)); }
  .proj-media{ aspect-ratio:4/3; max-height:none; }
  /* Wie am Desktop: der Titel liegt auf dem Bild und erscheint erst beim
     Beruehren oder beim Antippen. Auf Touch gibt es kein Ueberfahren,
     deshalb zaehlen hier auch :active und der Tastaturfokus. */
  .proj{ overflow:hidden; }
  .proj-label{
    position:absolute; left:0; bottom:0; width:100%; z-index:2;
    padding:var(--space-s) var(--space-m);
    transform:translateY(100%);
    transition:transform .28s var(--ease);
  }
  .proj:hover .proj-label,
  .proj:active .proj-label,
  .proj:focus-visible .proj-label,
  .proj[data-active] .proj-label{ transform:translateY(0); }

  .info{
    top:0; right:0; left:0; width:100%; height:auto; max-height:100dvh;
    flex-direction:row; flex-wrap:wrap; align-items:center; gap:var(--space-2xs);
    padding:0 var(--space-s); border-bottom:1px solid var(--line);
  }
  .mobile-mark{ display:block; height:64px; padding:10px 0; margin-right:auto; }
  .mobile-mark img{ height:100%; width:auto; }
  .letterhead{ display:none; width:auto; order:2; }
  .info-toggle{
    display:inline-flex; align-items:center; justify-content:center;
    width:2.6rem; height:2.6rem; background:none; border:1.5px solid var(--line);
    cursor:pointer; color:var(--ink); font-size:1.3rem;
  }
  .brand-claim, .lh-text, .info-footer{ display:none; margin-left:0; }
  /* Am Telefon ist die Leiste eine Zeile, kein hoher Streifen: der
     Fussblock loest sich auf, damit Navigation und Fusszeile wieder
     unmittelbar in der Leiste liegen und ihre Ordnungszahlen greifen. */
  .info-unten{ display:contents; position:static; }

  /* Zugeklappt bleibt von der Navigation nur die Gewerke-Leiste stehen:
     Architektur, Tragwerksplanung und Baumanagement sind damit sofort
     sichtbar und anklickbar, ohne das Menue zu oeffnen. */
  .info-nav{
    display:flex; flex-direction:row; gap:2px;
    order:3;
    /* Genau so breit wie die Projektbilder darunter: die Leiste sitzt im
       selben Seitenabstand wie der Inhalt, nicht mehr randlos. */
    width:100%; margin:0;
    padding:0 0 var(--space-2xs);
  }
  .info-nav > :not(.nav-cat){ display:none; }
  .nav-cat{
    display:flex; flex:1 1 0; min-width:0;
    justify-content:center; text-align:center;
    font-size:clamp(.44rem, 2.15vw, .66rem);
    letter-spacing:0; padding:0 .2em; height:29px;
  }
  .nav-cat svg{ display:none; }
  .nav-cat + .nav-cat{ margin-top:0; }
  /* Beim Scrollen durch eine Sparte treten die beiden anderen Reiter
     zurueck. Die Leiste sagt damit weiter, wo man ist, auch wenn die
     Ueberschrift des Abschnitts laengst aus dem Bild gelaufen ist.
     Im aufgeklappten Menue ist das nicht gemeint: dort ist die Leiste
     Navigation, keine Ortsangabe. */
  .info:not(.is-open) .nav-cat{ transition:opacity .3s var(--ease); }
  .info:not(.is-open) .nav-cat.nav-fern{ opacity:.32; }
  /* Aufgeklappt bleibt das Logo oben in seiner Leiste stehen, der
     Inhalt faellt darunter auf. Vorher rutschte es nach links, weil
     das grosse Briefkopf-Logo an seine Stelle trat. */
  /* Aufgeklappt steht alles auf einer Seite, ohne zu scrollen. Dafuer
     sind Logo, Zeilenabstaende und die Ueber-uns-Kachel enger gesetzt:
     zusammengerechnet war das Feld sonst 1133 px hoch bei 811 px Platz. */
  .info.is-open{
    display:grid; grid-template-columns:1fr auto; align-items:center;
    /* Das Feld deckt den ganzen Bildschirm ab, nicht nur die Hoehe seines
       Inhalts. Die verbleibende Luft verteilt sich gleichmaessig auf die
       Abstaende, der Fuss steht damit unten. */
    height:100dvh; align-content:space-between;
    row-gap:var(--space-2xs); overflow:hidden;
    padding-bottom:var(--space-s);
  }
  /* Aufgeklappt tritt das grosse Briefkopf-Logo an die Stelle der
     kleinen Leistenmarke. Es steht in Spalte 1, der Schliessen-Knopf
     rechts daneben, der Inhalt faellt darunter auf. */
  /* Die Reihenfolge wird hier ausdruecklich gesetzt. Die Leiste gibt dem
     Briefkopf und der Gewerke-Navigation eigene order-Werte, damit sie im
     zugeklappten Zustand an der richtigen Stelle sitzen; ohne diese Angaben
     rutschte das Logo im aufgeklappten Feld hinter Adresse und Impressum. */
  .info.is-open .mobile-mark{ display:none; }
  /* Logo so gross, dass der frei gewordene Platz aufgebraucht wird und
     die Luecken auf etwa die Haelfte zusammengehen. Die Hoehenbremse
     (vh) haelt das Feld auch auf kurzen Geraeten auf einer Seite. */
  .info.is-open{ --lh-mobil:min(13.5rem, 60vw, 25.5vh); }
  .info.is-open .letterhead{
    display:block; order:1; grid-column:1;
    width:var(--lh-mobil);
    padding-top:var(--space-2xs);
  }
  .info.is-open .info-toggle{ order:2; grid-column:2; align-self:start; margin-top:var(--space-2xs); }
  .info.is-open .brand-claim{
    order:3;
    /* Keine eigene Marge: das Feld verteilt den Restplatz mit
       align-content:space-between gleichmaessig auf alle Luecken. Jede
       zusaetzliche Marge hier machte die Luecke ueber GENERALPLANER
       groesser als die darunter - beide sollen gleich sein. Kleiner
       werden die Luecken dadurch, dass Logo und Text mehr Platz
       einnehmen, siehe --lh-mobil und die Schriftgrade unten. */
    margin-top:0; margin-bottom:0;
  }
  .info.is-open .lh-text{ order:4; }
  .info.is-open .info-nav{ order:5; }
  .info.is-open .info-footer{ order:6; line-height:2.1; }
  .info.is-open .info-footer a{ display:inline-block; padding-block:.35rem; }
  /* Das F von FERRO beginnt bei 20 % der Logobreite. Der Text darunter
     steht auf derselben Kante wie am Desktop. */
  .info.is-open .brand-claim,
  .info.is-open .lh-text,
  .info.is-open .info-footer{
    display:block; grid-column:1 / -1;
    margin-left:calc(var(--lh-mobil) * 0.20);
  }
  .info.is-open .info-nav{
    display:flex; flex-direction:column; gap:0;
    grid-column:1 / -1; width:auto; padding:0;
    /* Die Felder stehen auf derselben Kante wie GENERALPLANER, also am
       F von FERRO, und halten rechts denselben Abstand. */
    margin:0 calc(var(--lh-mobil) * 0.20);
  }
  /* Pauschal display:flex zu setzen war falsch: die Ueber-uns-Kachel ist
     Bild ueber Beschriftung (display:block). Als Flexzeile schob das Bild
     die Beschriftung 118 px aus dem Feld heraus. Jede Art bekommt deshalb
     ihren eigenen Wert zurueck. */
  .info.is-open .info-nav > .box{ display:flex; }
  .info.is-open .info-nav > .ueber-uns-tile{ display:block; }
  .info.is-open .nav-cat{ display:flex; font-size:clamp(.66rem, 3.4vw, .95rem); padding:.72em .8em; justify-content:space-between; text-align:left; }
  .info.is-open .nav-cat svg{ display:block; }
  .info.is-open .nav-cat + .nav-cat{ margin-top:2px; }
  /* Luft zwischen dem letzten Gewerk und der Ueber-uns-Kachel. */
  .info.is-open .ueber-uns-tile{ margin-top:var(--space-s); }
  .info.is-open .ueber-uns-tile img{ aspect-ratio:auto; height:clamp(34px, 7.5vh, 68px); }
  /* Alles, was Hoehe kostet, haengt an der Fensterhoehe. So passt das Feld
     auch auf kuerzeren Geraeten auf eine Seite, ohne zu scrollen. */
  .info.is-open .lh-text{ line-height:1.3; font-size:clamp(.62rem, 1.78vh, .86rem); }
  .info.is-open .brand-claim{ font-size:clamp(.72rem, 2.02vh, .97rem); }
  .info.is-open .info-footer{ padding-top:2px; line-height:1.5; font-size:clamp(.55rem, 1.4vh, .7rem); }
  .info.is-open .box{ padding:clamp(.3em, 1.0vh, .6em) .8em; font-size:clamp(.6rem, 1.6vh, .9rem); }
  .info.is-open .ueber-uns-label{ padding:clamp(.3em, 1.0vh, .6em) .8em; font-size:clamp(.6rem, 1.6vh, .9rem); }
  .info.is-open .cta-project{ margin-top:var(--space-2xs); }

  /* Seitlich derselbe Abstand wie bei den Projektbildern oben
     (--space-s, nicht --space-m): Kompetenzbilder, Titelfelder,
     Stellenfelder, das Gruppenbild und die vier Portraets stehen damit
     auf genau derselben Kante wie die Projektkacheln. */
  .section{ padding:var(--space-xl) var(--space-s); }
  .privacy{ padding:var(--space-l) var(--space-s); }
  .partners, .komp, .jobs-grid{ grid-template-columns:1fr; }
  /* Am Desktop haelt die Hoehenbremse das Gruppenbild im Rahmen. Auf dem
     Telefon soll es die volle Breite der Projektbilder haben. Die feste
     Breite ist noetig, weil der Abschnitt seine Kinder mittig setzt
     (align-items:center) und der Rahmen sonst auf die Breite des noch
     nicht geladenen Bildes zusammenfiele. */
  .about-figure{ max-width:100%; width:100%; }
  /* Die Portraets nehmen auf dem Telefon sonst fast die ganze Seite ein. */
  .partner-photo{ width:min(58%, 13rem); }
  .karriere-split, .impressum{ grid-template-columns:1fr; }
  /* Projektansicht auf dem Telefon: Logo, darunter die drei Gewerke, dann
     das erste Bild, der Text und die restlichen Bilder - alles in einem
     durchgehenden Lauf statt im Nebeneinander des Desktops.
     display:contents loest Galerie und Spur auf, damit die einzelnen Bilder
     zu Geschwistern des Textes werden und per order davor bzw. dahinter
     sortiert werden koennen. */

  .ov-bar{ flex-wrap:wrap; gap:var(--space-2xs); padding:0 var(--space-s) var(--space-2xs); }
  .ov-mark{ display:block; height:56px; width:auto; padding:8px 0; margin-right:auto; order:1; }
  .ov-mark img{ display:block; height:100%; width:auto; }
  .ov-close{ order:2; font-size:0; gap:0; padding:.6rem; }
  .ov-close .icon{ font-size:1.4rem; width:1.4rem; height:1.4rem; }
  .ov-sparten{
    order:3; width:calc(100% + var(--space-s) * 2);
    margin:0 calc(var(--space-s) * -1);
    display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:2px;
  }
  .ov-sparte{
    display:block; text-align:center; white-space:normal;
    font-size:clamp(.44rem, 2.15vw, .66rem); letter-spacing:0;
    padding:.62em .2em;
  }
  .ov-sparte.is-off{ display:block; background:var(--surface-2); color:var(--ink-3); box-shadow:none; }

  .ov-body{ display:flex; flex-direction:column; grid-template-columns:none; overflow:auto; }
  /* In der Spalte duerfen die Teile nicht schrumpfen: die Hoehe des
     Dialogs ist begrenzt, und ohne diese Angabe quetscht der Flexbox
     Text und Bilder ineinander. */
  .ov-body > *, .ov-info, .ov-slide{ flex:0 0 auto; }
  .ov-gallery, .ov-track{ display:contents; }
  /* Das erste Foto steht vor dem Projektnamen und braucht deshalb eine
     eigene Ordnungszahl. Beschnitten wird es nicht mehr: es folgt
     denselben zwei Regeln je Lage wie jedes andere Foto.
     Am 30.10.2026 auf Wunsch so geaendert - vorher war es auf 40 dvh
     gedeckelt und mit object-fit:cover beschnitten, damit der Name
     ohne Scrollen zu sehen war. */
  .ov-slide.ov-slide-first{ order:1; }
  /* Der Film behaelt seine eigene Hoehe: 16:9, ganz zu sehen. */
  /* Der Film bekommt am Telefon dasselbe 3:2 wie jedes Foto und
     laeuft ueber die ganze Breite. */
  .ov-slide.ov-slide-film video{ width:100%; height:auto; aspect-ratio:3 / 2; object-fit:cover; }
  .ov-info{ order:2; flex:0 0 auto; border-right:0; border-bottom:1px solid var(--line); overflow:visible; padding:var(--space-m) var(--space-s); }
  .ov-slide{ order:3; }
  /* Ohne eigene Ordnungszahl stuende der Aufgabentext der Stellenansicht
     vor Titel und Eckdaten - gemessen begann er bei 95 px, die Angaben
     erst bei 992 px. */
  .job-text{ order:3; flex:0 0 auto; overflow:visible; padding:var(--space-m) var(--space-s) var(--space-l); }
  .ov-slide{
    display:block; flex:none; padding:0; margin:0 0 var(--space-2xs);
    scroll-snap-align:none;
    /* container-type:size wieder abschalten. Am Telefon stehen die
       Bilder untereinander und die Hoehe ergibt sich aus dem Inhalt -
       mit Groessenbindung waere sie 0 und die Flaeche verschwaende.
       inline-size bindet nur die Breite, die Hoehe bleibt am Inhalt:
       so steht 100cqw fuer die Hoehe der Hochformate zur Verfuegung,
       ohne die Bildlaufleiste mitzurechnen wie vw. */
    container-type:inline-size;
  }
  .ov-slide img{
    position:static; inset:auto; margin:0;
    /* Dasselbe eine Format wie am Schreibtisch: volle Breite, 3:2.
       Jedes Bild ist damit gleich hoch, bei 390 px Breite 260 px.
       Die fruehere Deckelung auf das 1,5-fache der Dateibreite ist weg -
       sie machte die Bilder je nach Datei verschieden gross. */
    display:block; width:100%; height:auto;
    aspect-ratio:3 / 2; object-fit:cover;
    max-width:none; max-height:none;
  }
  /* Zwei Regeln, eine je Lage - dieselben wie auf der Projektseite.
     Der eine 3:2-Kasten hielt die Hoehen gleich, liess aber jedes
     Hochformat als schmalen Streifen darin stehen: bei 390 px Breite
     war ein Querformat 260 px hoch und ein Hochformat genauso, obwohl
     es bei gleicher Hoehe nur 195 px breit war. */
  /* quer: eigenes Verhaeltnis, volle Breite - bis an die Raender.

     Das Verhaeltnis kommt aus --iw/--ih, den Dateimassen, die an jedem
     Bild stehen. Mit aspect-ratio:auto waere es erst da, wenn das Foto
     geladen ist: gemessen am 30.10.2026 reservierten 19 von 20 ersten
     Fotos vorher 0 Pixel, der Projektname sprang beim Eintreffen des
     Bildes um 211 bis 285 Pixel nach unten. Solange das erste Foto der
     beschnittene Kopf mit fester Hoehe war, fiel das nicht auf.
     Fehlen die Masse, gilt 3:2 - dann steht der Platz zwar nicht genau,
     aber er steht. */
  /* quer: einheitlich 3:2, ueber die ganze Breite des Telefons, bis
     an beide Raender. Bei 390 px Breite also immer 260 px hoch.
     Vorher galt das eigene Verhaeltnis jedes Fotos - die Hoehe sprang
     damit von Bild zu Bild zwischen 211 und 285 px. */
  .ov-slide.ist-quer img{ aspect-ratio:3 / 2; width:100%; height:auto; }
  /* hoch: eine Hoehe fuer alle Hochformate. 0.85 ist das breiteste
     vorkommende Hochformat, 100vw/0.85 also genau die Hoehe, bei der
     auch dieses noch ganz in die Breite passt - mehr waere nicht mehr
     fuer alle dieselbe Hoehe. 72vh deckelt nach oben, damit ein
     Hochformat nie hoeher wird als der Bildschirm. */
  /* hoch: einheitlich 3:4, ebenfalls ueber die ganze Breite. Bei
     390 px sind das 520 px Hoehe. 3:4 ist die Mitte der sieben
     Hochformate (0,75); die Spanne reicht von 0,56 bis 0,78. */
  .ov-slide.ist-hoch img{
    aspect-ratio:3 / 4; width:100%; height:auto;
    max-width:none; margin-inline:0;
  }
  /* Panoramen behalten auch am Telefon ihre Form. */
  .ov-slide.ist-panorama img{
    aspect-ratio:calc(var(--iw, 2px) / var(--ih, 1px));
    width:100%; height:auto; object-fit:contain;
  }
  /* In der Vollbildansicht zaehlt wieder die echte Form der Aufnahme.
     Die Regel dafuer weiter oben (.ov-slide.gross img) ist gleich stark
     gewichtet, steht aber vor diesem Umbruch - ohne die Wiederholung
     hier deckelte die Hochformat-Hoehe auch das Vollbild. */
  .ov-slide.gross.ist-quer img,
  .ov-slide.gross.ist-panorama img,
  .ov-slide.gross.ist-hoch img{
    width:auto; height:auto; max-width:100%; max-height:100%;
    object-fit:contain; margin-inline:auto;
  }
  .gal-btn{ display:none; }


  .proj-also{ font-size:.65rem; }

  /* Die drei Kompetenzen stehen untereinander, man liest immer nur eine.
     Deshalb tritt beim Scrollen die gerade gelesene hervor und die beiden
     anderen treten zurueck. Am Desktop stehen alle drei nebeneinander,
     dort bleibt es unveraendert.
     .reveal.is-in setzt opacity:1 mit derselben Spezifitaet, diese Regel
     steht aber spaeter im Stilblatt und gewinnt dadurch. */
  /* transform bleibt mit drin: diese Regel steht spaeter als
     .reveal.is-in und wuerde dessen Uebergang sonst ersetzen, das
     Einblenden der Spalte spraenge dann. */
  .komp-col, .jobs-col{ transition:opacity .3s var(--ease), transform .55s var(--ease); }
  .komp-col.komp-fern, .jobs-col.komp-fern{ opacity:.3; }
  .komp-col.komp-nah .komp-figure img{ filter:grayscale(0%); }
}
/* Projektname und Jahr bleiben in der ganzen Mobilfassung verdeckt und
   erscheinen erst beim Antippen - auch auf dem Tablet, damit das Bild
   ungestoert bleibt. */
@media (max-width: 1100px){
  .p-sub{ font-size:.8rem; }
}

@media (max-width: 599px){
  .form-row{ grid-template-columns:1fr; }
  .ov-fact{ grid-template-columns:6.5rem minmax(0,1fr); }
}

/* ---------- 9b. Eigene Projektseiten ----------
   Jedes Projekt hat unter /projekte/<kennung>/ eine eigene, einzeln
   auffindbare Seite. Sie teilt sich dieses Stilblatt mit der Startseite
   (dort eingebettet, hier als styles.css ausgeliefert) und braucht nur
   ihr eigenes Geruest: Kopfleiste, Textspalte, Bilder untereinander.
   Bewusst ohne feste Seitenspalte - eine einzelne Projektseite ist ein
   Dokument zum Lesen, keine Navigationsflaeche. */
.projektseite{ background:var(--paper); color:var(--ink); }
.ps-bar{
  position:sticky; top:0; z-index:20;
  display:flex; align-items:center; gap:var(--space-m);
  padding:var(--space-2xs) var(--space-l);
  background:var(--paper); border-bottom:1px solid var(--line);
}
.ps-mark{ display:block; height:56px; flex:none; }
.ps-mark img{ height:100%; width:auto; display:block; }
.ps-bar .ov-sparten{ width:min(26rem, 46vw); margin-left:auto; }
.ps-zurueck{
  display:inline-flex; align-items:center; gap:.5rem; flex:none;
  font-size:var(--fs-micro); font-weight:700; letter-spacing:.1em;
  text-transform:uppercase; color:var(--red-text);
}
.ps-zurueck:hover{ text-decoration:underline; text-underline-offset:.3em; }

.ps-main{ max-width:62rem; margin-inline:auto; padding:var(--space-xl) var(--space-l) var(--space-2xl); }
.ps-weg{ font-size:var(--fs-micro); letter-spacing:.1em; text-transform:uppercase; color:var(--ink-3); }
.ps-weg a:hover{ color:var(--red-text); text-decoration:underline; }
.ps-titel{
  margin:var(--space-s) 0 var(--space-m);
  font-size:var(--fs-h2); font-weight:700; line-height:1.08;
  letter-spacing:.06em; text-transform:uppercase; text-wrap:balance;
}
.ps-facts{ max-width:34rem; }
.ps-text{ margin-top:var(--space-m); max-width:42rem; font-size:var(--fs-body); color:var(--ink-2); }
.ps-text + .ps-text{ margin-top:var(--space-s); }
.ps-unter{ margin-top:var(--space-2xs); max-width:42rem; font-size:var(--fs-sub); color:var(--ink-3); }
.ps-kontakt{ margin-top:var(--space-m); }
/* Wegweiser auf der Seite fuer nicht gefundene Adressen. Keine
   Aufzaehlungszeichen: die Zeilen sind Wege, keine Aufzaehlung. */
.ps-wege{ margin-top:var(--space-m); list-style:none; max-width:42rem; }
.ps-wege li + li{ margin-top:var(--space-2xs); }
.ps-wege a{
  display:inline-block; padding:var(--space-2xs) 0;
  font-size:var(--fs-body); color:var(--red-text);
  text-decoration:underline; text-underline-offset:.2em;
}
.ps-wege a:hover{ text-decoration-thickness:2px; }
/* ---------- Die Galerie einer Projektseite ----------
   Gemessen an allen 242 Galeriebildern der 23 Projekte:
     214 Querformate, Breite/Hoehe von 1,08 bis 3,32, Mitte 1,50
      28 Hochformate,  Breite/Hoehe von 0,56 bis 0,85, Mitte 0,75

   Vorher lag jede Aufnahme in einem festen 3:2-Kasten. Das hielt die
   Hoehen gleich, liess aber jedes Hochformat als schmalen Streifen
   zwischen zwei grauen Balken stehen - auf dem Handy war ein
   Hochformat damit kaum halb so gross wie ein Querformat daneben.

   Jetzt zwei Regeln, eine je Lage, auf jedem Projekt dieselben:
     quer  - laeuft ueber die ganze Bandbreite, in seinem eigenen
             Verhaeltnis. Kein Kasten, keine Balken, nichts
             abgeschnitten; am Handy bis an die Raender.
     hoch  - eine einzige Hoehe fuer alle Hochformate. Die Breite
             ergibt sich aus dem Bild selbst, mittig gestellt.

   Die Hoehe der Hochformate ist nicht frei gewaehlt: 0.85 ist das
   breiteste vorkommende Hochformat. Band / 0.85 ist also genau die
   Hoehe, bei der auch das breiteste noch ganz hineinpasst - mehr
   waere nicht mehr fuer alle gleich. Nach oben begrenzt sie der
   Bildschirm, damit ein Hochformat nie hoeher als die Sicht wird. */
.ps-bilder{
  /* Die Bandbreite begrenzen drei Dinge: das Fenster, seine Hoehe und
     eine Obergrenze. Der Hoehenanteil ist noetig, weil ein Querformat
     seine Hoehe aus der Breite bekommt - bei 1400 px Band stand ein
     3:2-Foto 935 px hoch und damit hoeher als ein 950 px hohes
     Fenster. 1.5 ist das Verhaeltnis, das 110 der 214 Querformate
     haben; mit 82vh passt dieses Format auf den Schirm, und alle
     Querformate bleiben gleich breit. */
  --ps-band: min(calc(100vw - 4rem), calc(82vh * 1.5), 1400px);
  /* Das Band ist Bezugsgroesse fuer die Hoehe der Hochformate. Ein
     Element kann seine eigene Breite nicht in cqw abfragen, deshalb
     steht die Hoehe weiter unten an .ps-bild - dort loest 100cqw sich
     gegen dieses Band auf, und zwar gegen seine echte Breite. vw waere
     hier falsch: es rechnet die senkrechte Bildlaufleiste mit. */
  container-type:inline-size;
  margin-top:var(--space-xl);
  /* Bricht aus der Textspalte aus: das Band darf breiter sein als der
     Text, den man liest. Bewusst nicht width:100vw - vw rechnet die
     senkrechte Bildlaufleiste mit, und am Rechner entstuende dadurch
     ein waagrechtes Schieben von etwa 15 Pixeln. Das Band ist deshalb
     genau so breit wie die Bilder darin. */
  width:var(--ps-band); margin-inline:calc(50% - var(--ps-band) / 2);
  display:grid; gap:var(--space-m); justify-items:center;
}
/* Grundform, falls die Lage eines Bildes einmal nicht bekannt ist:
   dann bleibt es beim alten, ruhigen 3:2-Kasten. */
.ps-bild{
  width:100%;
  /* 0.85 ist das breiteste der 28 Hochformate. Band / 0.85 ist damit
     genau die Hoehe, bei der auch dieses noch ganz in die Breite
     passt - mehr waere nicht mehr fuer alle dieselbe Hoehe. 78vh
     deckelt nach oben, damit kein Hochformat hoeher wird als die
     Sicht. */
  --ps-hoch: min(78vh, calc(100cqw / 0.85));
  background:var(--surface-2); aspect-ratio:3 / 2; overflow:hidden;
}
.ps-bild img{ display:block; width:100%; height:100%; object-fit:contain; }

/* Am 30.10.2026: einheitlicher Ausschnitt wie im Dialog. Vorher galt
   das eigene Verhaeltnis jedes Fotos (aspect-ratio:auto) - auf einer
   Projektseite standen dadurch 1107x830, 1107x706 und 527x702
   untereinander. Jetzt ist jedes Querformat 3:2 und gleich gross. */
.ps-bild.ist-quer{ background:none; }
.ps-bild.ist-quer img{ width:100%; height:100%; object-fit:cover; }

.ps-bild.ist-hoch{
  height:var(--ps-hoch); aspect-ratio:auto; background:none;
  display:flex; justify-content:center;
}
.ps-bild.ist-hoch img{
  /* 3:4 wie im Dialog, der Rahmen wird ausgefuellt. Die Hoehe gibt
     --ps-hoch vor, die Breite folgt dem Verhaeltnis. */
  width:auto; height:100%; aspect-ratio:3 / 4;
  max-width:100%; object-fit:cover;
}

/* Sehr breite Aufnahmen bleiben ganz - dieselbe Grenze wie im Dialog
   (1,9:1). Ohne Verhaeltnisangabe nimmt das Bild seine echte Form aus
   den width- und height-Angaben im Quelltext. */
.ps-bild.ist-panorama{
  aspect-ratio:auto; height:auto; background:none;
}
.ps-bild.ist-panorama img{
  width:100%; height:auto; object-fit:contain;
}

/* Der Film bekommt die Bandbreite wie ein Querformat, nur in 16:9.
   Ohne das stand er mit 444 px neben 1169 px breiten Fotos - die alten
   66 % von 42 rem waren auf die frueher schmalere Textspalte gerechnet.
   Die beiden Regeln je Lage bekommt er nicht: ein Video hat keine
   Lage, und .ps-film bringt seine eigene Form mit. */
.ps-bild.ps-film{
  width:100%; max-width:none;
  /* Dasselbe 3:2 wie die Fotos - am 30.10.2026 auf Wunsch geaendert,
     vorher brachte der Film mit aspect-ratio:auto seine eigene Form
     (16:9) mit und stand damit niedriger als alles daneben. */
  aspect-ratio:3 / 2; background:none; overflow:hidden;
}
.ps-bild.ps-film video{ width:100%; height:100%; object-fit:cover; }
.ps-fuss{
  border-top:1px solid var(--line); padding:var(--space-l);
  font-size:var(--fs-sub); color:var(--ink-2); text-align:center;
}
.ps-fuss a{ color:var(--red-text); }
.ps-fuss a:hover{ text-decoration:underline; }
.ps-fuss p + p{ margin-top:var(--space-2xs); }
@media (max-width: 1100px){
  .ps-bar{ padding:var(--space-2xs) var(--space-s); gap:var(--space-s); flex-wrap:wrap; }
  .ps-mark{ height:46px; }
  .ps-bar .ov-sparten{ order:3; width:100%; margin:0 0 var(--space-2xs); }
  .ps-zurueck{ margin-left:auto; }
  .ps-main{ padding:var(--space-l) var(--space-s) var(--space-xl); }
}
/* Am Handy ohne Rand: ein Querformat soll die ganze Breite haben.
   Die Hoehe der Hochformate richtet sich hier nach derselben Breite,
   damit auch sie so gross stehen, wie der Bildschirm es zulaesst. */
@media (max-width: 760px){
  .ps-bilder{
    /* Bis an die Raender, aber ohne 100vw: das rechnet die senkrechte
       Bildlaufleiste mit, und in einem 375 px schmalen Fenster mit
       klassischer Leiste stand das Band dadurch 8 px ueber - am
       30.10.2026 so gemessen. Breite auto plus das Polster der
       Textspalte als Minusrand trifft genau die nutzbare Breite,
       welche Leiste der Browser auch zeichnet. */
    width:auto;
    margin-inline:calc(-1 * var(--space-s));
    gap:var(--space-s);
  }
  .ps-bild{ --ps-hoch: min(72vh, calc(100cqw / 0.85)); }
  /* Am Telefon nutzen auch Hochformate die ganze Breite - genau wie
     im Dialog. Ueber --ps-hoch standen sie 344 px breit mit 23 px
     Rand links und rechts, waehrend im Dialog dasselbe Foto 390 px
     breit war. Bei 390 px Breite sind es jetzt 520 px Hoehe. */
  .ps-bild.ist-hoch{ height:auto; }
  .ps-bild.ist-hoch img{ width:100%; height:auto; }
}

/* ---------- 10. Reduced motion ---------- */
@media (prefers-reduced-motion: reduce){
  *, *::before, *::after{
    animation-duration:.01ms!important; animation-iteration-count:1!important;
    transition-duration:.01ms!important; scroll-behavior:auto!important;
  }
  .reveal{ opacity:1; transform:none; }
  .proj:hover .proj-media img{ transform:none; }
}

/* ---------- 11. Druck ---------- */
@media print{
  .info, dialog.proj-dialog, .gal-btn{ display:none!important; }
  .cols, .section, .privacy{ padding-right:var(--space-l); }
  .section{ break-inside:avoid; }
}
