/* =========================================================================
   NOVA WORKS - Stylesheet
   Alle Stellschrauben stehen im :root-Block. Wer Farben, Abstaende oder
   Schriftgroessen aendern will, aendert sie dort - nicht weiter unten.
   ========================================================================= */

:root {
  /* --- Farben ------------------------------------------------------- */
  --ink:          #0b0b0c;   /* Seitenhintergrund                        */
  --ink-raised:   #121213;   /* abgesetzte Flaechen, Karten              */
  --ink-sunken:   #08080a;   /* Footer, tiefste Ebene                    */
  --line:         #26262a;   /* Trennlinien, Rahmen                      */
  --line-strong:  #3a3a40;   /* Rahmen im Fokus / Hover                  */

  --signal:       #f8f808;   /* Markenfarbe: Signalgelb                  */
  --signal-dim:   #c9c907;   /* gedeckt, fuer Hover auf hellem Grund     */

  --text:         #f4f4f2;   /* Fliesstext                               */
  --text-dim:     rgba(244, 244, 242, .64);
  --text-faint:   rgba(244, 244, 242, .58);

  --danger:       #ff6b5e;

  --kopf-grund:   rgba(11, 11, 12, .82);   /* Kopfzeile, sobald sie klebt */

  /* --- Typografie --------------------------------------------------- */
  --font: 'Zalando Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI',
          Helvetica, Arial, sans-serif;

  /* Die Staffel der bisherigen nova-works.de: 8vw, hoechstens 250 px,
     am Tablet 10vw, am Handy 14vw. Am Handy also bewusst groesser im
     Verhaeltnis zum Schirm - genau dort soll der Claim wuchten. Die drei
     Stufen stehen weiter unten unter "Umbrueche". */
  --fs-hero:   min(8vw, 250px);
  --fs-h2:     clamp(2rem, 4.6vw, 4.25rem);
  --fs-h3:     clamp(1.25rem, 1.9vw, 1.75rem);
  --fs-lead:   clamp(1.05rem, 1.35vw, 1.3rem);
  --fs-body:   1.0625rem;
  --fs-small:  0.875rem;

  /* --- Raster & Rhythmus -------------------------------------------- */
  --shell:      1320px;
  --gutter:     clamp(1.25rem, 5vw, 4rem);
  --section-y:  clamp(5rem, 12vh, 10rem);
  /* Zwei Radien mit zwei Bedeutungen, nicht einer fuer alles: Der kleine
     gehoert allem, was auf der Seite liegt - Bildrahmen, Eingabefelder,
     Hinweise. Der grosse gehoert dem, was ueber der Seite schwebt: dem
     Einwilligungsfenster und seinen Einstellungen. So sagt die Rundung
     etwas ueber die Ebene, statt nur ueberall gleich weich zu sein. */
  --radius:      4px;   /* auf der Seite                                 */
  --radius-lg:  10px;   /* ueber der Seite                               */

  /* --- Bewegung ------------------------------------------------------ */
  --ease:      cubic-bezier(.22, .61, .36, 1);
  --ease-out:  cubic-bezier(.16, 1, .3, 1);
  --dur:       .5s;
}

/* =========================================================================
   Grundlagen
   ========================================================================= */

@font-face {
  font-family: 'Zalando Sans';
  src: url('../fonts/zalando-sans-latin.woff2') format('woff2');
  font-weight: 100 900;          /* variabler Schnitt, eine Datei         */
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6,
                 U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F,
                 U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF,
                 U+FFFD;
}

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 6rem;
}

body {
  margin: 0;
  background: var(--ink);
  color: var(--text);
  font-family: var(--font);
  font-size: var(--fs-body);
  font-weight: 300;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

img, svg { max-width: 100%; height: auto; display: block; }

/* <picture> ist nur eine Klammer um das <img> und seine WebP-Quellen. Es
   soll selbst keinen Kasten aufspannen - sonst stünde zwischen einem
   Rahmen und seinem Bild plötzlich ein weiteres Element, und alles, was
   sich auf "das direkte Kind" verlässt, ginge daneben. */
picture { display: contents; }

h1, h2, h3, h4 {
  margin: 0;
  font-weight: 400;
  line-height: 1.08;
  letter-spacing: -.02em;
}

p { margin: 0 0 1.25em; }
p:last-child { margin-bottom: 0; }

a { color: inherit; }

::selection { background: var(--signal); color: var(--ink); }

:focus-visible {
  outline: 2px solid var(--signal);
  outline-offset: 3px;
  border-radius: 2px;
}

/* Hilfsklassen ------------------------------------------------------- */

.shell {
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  top: 0; left: 50%;
  transform: translate(-50%, -140%);
  z-index: 200;
  padding: .85rem 1.5rem;
  background: var(--signal);
  color: var(--ink);
  font-size: var(--fs-small);
  font-weight: 500;
  text-decoration: none;
  border-radius: 0 0 var(--radius) var(--radius);
  transition: transform .25s var(--ease);
}
.skip-link:focus { transform: translate(-50%, 0); }

/* Feines Korn - nimmt den Flaechen das Digitale ----------------------- */
.grain {
  position: fixed;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  opacity: .028;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* Eyebrow: kleine Auszeichnungszeile --------------------------------- */
/* Die Meta-Zeile ueber einem Titel nennt den Ort - sie ist Inhalt, kein
   Etikett. Deshalb steht sie in Satzschreibung: Eine gesperrte
   Grossbuchstabenzeile ueber jeder Ueberschrift ist die haeufigste
   Vorlagen-Zutat ueberhaupt, und sie macht den Ort schwerer lesbar,
   statt ihn hervorzuheben.

   Zeilen, die nur den Abschnittsnamen wiederholten - "Services",
   "Kontakt" -, sind ganz entfallen. */
.eyebrow {
  margin: 0;
  font-size: var(--fs-small);
  font-weight: 400;
  color: var(--text-faint);
}
.eyebrow--signal { color: var(--signal); }

/* =========================================================================
   Buttons
   ========================================================================= */

.btn {
  --btn-bg: transparent;
  --btn-fg: var(--text);
  --btn-border: var(--line-strong);

  position: relative;
  display: inline-flex;
  align-items: center;
  gap: .75rem;
  padding: 1rem 1.9rem;
  border: 1px solid var(--btn-border);
  border-radius: 100px;
  background: var(--btn-bg);
  color: var(--btn-fg);
  font: inherit;
  font-size: var(--fs-small);
  font-weight: 500;
  letter-spacing: .01em;
  text-decoration: none;
  cursor: pointer;
  overflow: hidden;
  isolation: isolate;
  transition: color .35s var(--ease), border-color .35s var(--ease),
              background-color .55s var(--ease);
}

/* Fuellung waechst von unten - der Text wechselt dabei auf Schwarz */
.btn::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--signal);
  transform: scaleY(0);
  transform-origin: bottom;
  transition: transform .45s var(--ease-out);
}

/* Frueher hing an jedem Knopf ein Strich, der beim Ueberfahren
   wuchs - dieselbe Geste wie der Pfeil, den man an jeder zweiten Seite
   sieht. Ein Knopf sagt mit seinem Wort, was er tut; der Strich sagte
   nichts dazu. Geblieben ist er nur am Ladezeiger. */

.btn:hover, .btn:focus-visible {
  color: var(--ink);
  border-color: var(--signal);
}
.btn:hover::before, .btn:focus-visible::before { transform: scaleY(1); }

.btn[data-loading] { pointer-events: none; opacity: .6; }
.btn[data-loading]::after {
  content: '';
  width: .8rem; height: .8rem;
  border: 1px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  background: none;
  animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* Vollflaechige Variante */
.btn--solid {
  --btn-bg: var(--signal);
  --btn-fg: var(--ink);
  --btn-border: var(--signal);
  font-weight: 600;
}
.btn--solid::before { background: var(--text); }
.btn--solid:hover, .btn--solid:focus-visible { color: var(--ink); border-color: var(--text); }

.btn--ghost { --btn-border: var(--line); }

/* =========================================================================
   Kopfzeile
   ========================================================================= */

.masthead {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 100;
  padding-block: 1.35rem;
  transition: background-color .55s var(--ease), border-color .55s var(--ease),
              color .55s var(--ease), padding .4s var(--ease),
              backdrop-filter .4s var(--ease);
  border-bottom: 1px solid transparent;
}

.masthead.is-stuck {
  padding-block: .9rem;
  background: var(--kopf-grund);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-bottom-color: var(--line);
}

.masthead__inner {
  display: flex;
  align-items: center;
  gap: 2rem;
}

/* --- Die Marke --------------------------------------------------------
   Wortmarke als Grafik, Claim als echter Text darunter.

   Im Original steckte beides in einer SVG-Datei. Der Claim ist darin
   14,5 von 425 Einheiten hoch - 3,4 Prozent der Logobreite. Bei den
   frueheren 170 px waren das 5,8 px; selbst bei 300 px waeren es erst
   10, und das bei einem hellen, weit gesperrten Schnitt. Groesser
   skalieren loest das nicht, es macht nur das ganze Logo zu gross.

   Als Text haengt die Groesse des Claims nicht mehr an der Breite der
   Wortmarke. Beide lassen sich dadurch unabhaengig einstellen - und die
   Wortmarke konnte deutlich waschsen, ohne dass der Kopf auseinander
   faellt. */
/* Mittig, wie im Original.

   Nachgemessen am Original: Wortmarke, Trennstrich und Claim liegen dort
   alle drei auf derselben Mitte (299,5 / 300,5 / 300 bei 600 px Breite).
   In der beschnittenen Grafik steht die Wortmarke ebenfalls mittig im
   Bildrahmen - es genuegt also, den Claim im selben Rahmen zu zentrieren.

   Linksbuendig sass er sichtbar daneben; der Claim beginnt im Original
   deutlich weiter innen als die Wortmarke.                             */
.marke {
  display: inline-grid;
  justify-items: center;
  gap: .34em;
  text-decoration: none;
  width: max-content;
}
.marke__zeichen {
  height: auto;
  transition: opacity .3s var(--ease), filter .55s var(--ease);
}
.marke:hover .marke__zeichen,
.marke:hover .marke__claim { opacity: .72; }

/* Gesperrt wie im Original, aber in einer Groesse, die man liest.

   Gewicht 400 statt 300: Ein Haarstrich-Schnitt deckt bei dieser Groesse
   weniger als einen ganzen Pixel ab, und was uebrigbleibt, zeichnet der
   Browser grau statt weiss - das sieht nach schlechter Aufloesung aus,
   obwohl es Text ist. Ein Schnitt mehr kostet nichts und deckt.

   Der negative Abstand am Ende nimmt die Sperrung hinter dem letzten
   Buchstaben wieder weg. Ohne ihn waere der Kasten um .2em breiter als
   die Schrift darin, und beim Zentrieren saesse der Text um die Haelfte
   davon zu weit links.                                                 */
.marke__claim {
  font-size: var(--claim-groesse, .85rem);
  font-weight: 400;
  /* Im Original ist der Claim 71 Prozent so breit wie die Wortmarke.
     Mit .2em Sperrung und der groesseren Schrift waeren es 97 - er
     saehe aus wie eine zweite Wortmarke statt wie eine Unterzeile.
     .11em bringt ihn auf rund 82 Prozent, ohne ihn zu verkleinern. */
  letter-spacing: .11em;
  margin-right: -.11em;
  line-height: 1;
  color: rgba(244, 244, 242, .82);
  white-space: nowrap;
  transition: opacity .3s var(--ease);
}

/* Die Marke bekommt den Platz, der da ist: Neben ihr stehen Navigation
   (444 px) und Schalter (161 px), bei 1320 px Schale bleiben 651 px
   uebrig. Genutzt waren 200. Bei 300 px ist der Trennstrich 2,65 px hoch
   statt 1,76 und die Buchstaben decken ganze Pixel - erst dadurch sind
   sie weiss statt grau. */
.masthead__logo { flex: none; margin-right: auto; }
.masthead__logo .marke__zeichen { width: clamp(190px, 21vw, 300px); }
.masthead__logo { --claim-groesse: clamp(.75rem, 1vw, .95rem); }

.nav { display: flex; gap: clamp(1.5rem, 2.5vw, 2.75rem); }

.nav__link {
  position: relative;
  padding-block: .35rem;
  font-size: var(--fs-small);
  font-weight: 400;
  letter-spacing: .04em;
  text-decoration: none;
  color: var(--text-dim);
  transition: color .3s var(--ease);
}
.nav__link::after {
  content: '';
  position: absolute;
  left: 0; bottom: 0;
  width: 100%; height: 1px;
  background: var(--signal);
  transform: scaleX(0);
  transform-origin: right;
  transition: transform .4s var(--ease-out);
}
.nav__link:hover, .nav__link:focus-visible { color: var(--text); }
.nav__link:hover::after, .nav__link:focus-visible::after {
  transform: scaleX(1);
  transform-origin: left;
}

.masthead__cta { flex: none; padding: .8rem 1.5rem; }

/* Menuetaste - nur mobil sichtbar */
.nav-toggle {
  display: none;
  flex: none;
  width: 46px; height: 46px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: transparent;
  cursor: pointer;
  color: var(--text);
}
.nav-toggle__bars {
  position: relative;
  display: block;
  width: 17px; height: 1px;
  margin-inline: auto;
  background: currentColor;
  transition: background-color .2s var(--ease);
}
.nav-toggle__bars::before,
.nav-toggle__bars::after {
  content: '';
  position: absolute;
  left: 0;
  width: 100%; height: 1px;
  background: currentColor;
  transition: transform .35s var(--ease-out);
}
.nav-toggle__bars::before { top: -5px; }
.nav-toggle__bars::after  { top:  5px; }

.nav-toggle[aria-expanded="true"] .nav-toggle__bars { background: transparent; }
.nav-toggle[aria-expanded="true"] .nav-toggle__bars::before { transform: translateY(5px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] .nav-toggle__bars::after  { transform: translateY(-5px) rotate(-45deg); }

/* Mobiles Menue ------------------------------------------------------- */
.nav-drawer {
  position: fixed;
  inset: 0;
  z-index: 90;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: .5rem;
  padding: 6rem var(--gutter) 3rem;
  background: var(--ink);
  opacity: 0;
  transition: opacity .35s var(--ease);
}
.nav-drawer.is-open { opacity: 1; }
.nav-drawer[hidden] { display: none; }

.nav-drawer a:not(.btn) {
  padding-block: 1rem;
  border-bottom: 1px solid var(--line);
  font-size: clamp(1.6rem, 7vw, 2.4rem);
  font-weight: 300;
  letter-spacing: -.01em;
  text-decoration: none;
  color: var(--text);
}
.nav-drawer .btn { align-self: flex-start; margin-top: 2rem; }

/* =========================================================================
   Hero
   ========================================================================= */

.hero {
  position: relative;
  display: flex;
  align-items: flex-end;
  min-height: 100svh;
  padding-block: 9rem 3.5rem;
  overflow: hidden;
  isolation: isolate;
}

/* Der Verlauf liegt auf dem Abschnitt selbst. Fehlt spaeter das Foto,
   bleibt die Flaeche trotzdem gestaltet - kein leeres Schwarz. */
.hero {
  background: linear-gradient(178deg, #141416 0%, var(--ink) 62%);
}

/* Foto als Hintergrundbild, nicht als <img>: fehlt die Datei, rendert der
   Browser schlicht nichts - statt eines kaputten Bildsymbols. */
/* Das Kopfbild ist ein <img>, kein Hintergrundbild. Als Hintergrundbild
   lud der Browser auf jedem Gerät dieselbe Datei; über srcset holt er
   jetzt 640 Pixel ans Handy und 2560 an den Retina-Schirm. */
.hero__media {
  position: absolute;
  inset: 0;
  z-index: -2;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: .5;
}

/* Verlauf, damit die Schrift auf jedem Bild sitzt */
.hero::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(180deg,
    rgba(11, 11, 12, .70) 0%,
    rgba(11, 11, 12, .30) 38%,
    rgba(11, 11, 12, .88) 88%,
    var(--ink) 100%);
}

.hero__inner { width: 100%; }

/* Hier stand eine Zeile mit "Based in Germany" und "Established 2026" in
   den beiden oberen Ecken - auf einer deutschsprachigen Seite zwei
   englische Etiketten, die nichts sagen, was nicht ohnehin im Impressum,
   im Kontaktteil und in der Fusszeile steht. Sie sind entfallen; der
   Claim bekommt die Luft. */

/* Der Claim traegt die Seite: mittig, im schwersten brauchbaren Schnitt
   und dicht gesetzt. Die Schrift ist ein variabler Schnitt von 100 bis
   900 - 800 ist also ein echtes Gewicht und kein vom Browser
   nachgezogenes Fett.

   Je schwerer der Schnitt, desto enger darf er stehen: Die Buchstaben
   werden breiter, die Zwischenraeume von selbst kleiner. -.03em haelt
   den Block zusammen, ohne dass die Formen ineinanderlaufen. */
.hero__title {
  font-size: var(--fs-hero);
  font-weight: 800;
  line-height: .85;
  letter-spacing: -.03em;
  text-transform: uppercase;
  text-align: center;
}
/* Auf schmalen Schirmen bricht jede Haelfte fuer sich um. Ohne balance
   bleibt dabei ein Rest stehen ("MOMENTE, DIE / BLEIBEN,"); mit balance
   verteilt der Browser die Woerter gleichmaessig auf die Zeilen. Kann er
   es nicht, bricht er wie bisher - kein Schaden. */
/* Nur die beiden Halbsaetze, nicht jedes span darin. Der Nachkomme-Wahl
   ohne > fielen auch die Woerter zum Opfer, die main.js beim Schneiden
   einzeln setzt - jedes waere ein Block geworden und damit eine eigene
   Zeile. Gemessen kam dann Wort fuer Wort statt Zeile fuer Zeile heraus. */
.hero__title > span { display: block; text-wrap: balance; }
.hero__title em {
  font-style: normal;
  color: var(--signal);
}

/* --- Auftritt: Zeile fuer Zeile ----------------------------------------
   Der Claim baut sich zeilenweise auf - jede Zeile faehrt von unten in
   ihren Kasten, kurz versetzt zur vorigen.

   main.js schneidet die beiden Halbsaetze dafuer in ihre tatsaechlichen
   Zeilen. Von Hand geht das nicht: Wo umbrochen wird, haengt von der
   Breite ab - am Schirm zwei Zeilen, am Handy vier.

   Der Kasten schneidet ab, das Innenleben faehrt. Ohne den Rand am Kasten
   wuerde er die Oberlaengen abschneiden: Bei Zeilenhoehe 0,85 ist der
   Kasten niedriger als die Buchstaben hoch sind. Der Rand schafft Platz,
   der negative Aussenabstand nimmt ihn dem Satzbild wieder weg, und das
   Innenleben startet 130 Prozent tief - weit genug, dass auch mit Rand
   nichts hervorlugt.

   Alles haengt an .hero--auftritt. Diese Klasse setzt dasselbe Skript,
   das auch die Zeilen schneidet - beides kommt also zwangslaeufig
   zusammen oder gar nicht. Eine Klasse von woanders her (etwa ein
   html.js aus einem Schnipsel im Kopf) waere eine zweite, unabhaengige
   Bedingung: Wo die fehlt, stehen die Zeilen sofort auf ihrem Platz und
   es passiert sichtbar nichts. Genau so war es in der Vorschau. */

.hero__zeile {
  display: block;
  overflow: hidden;
  padding-block: .09em;
  margin-block: -.09em;
}

.hero--auftritt .hero__zeile-innen {
  display: block;
  transform: translateY(130%);
}

@media (prefers-reduced-motion: no-preference) {
  .hero--auftritt.is-ready .hero__zeile-innen {
    transform: none;
    /* Kurz und hart heraus: Der Weg ist in den ersten Hundertsteln fast
       vorbei, danach setzt die Zeile nur noch auf. Das ist der Schlag. */
    transition: transform .58s cubic-bezier(.13, .9, .2, 1);
    transition-delay: calc(var(--z, 0) * 90ms);
  }
}

/* Beim Neuschneiden nach einer Drehung darf nichts nachfahren. */
.hero--auftritt.hero--ohne-fahrt .hero__zeile-innen { transition: none; }

/* Ruhe-Modus: kein Fahren, nur da sein. */
@media (prefers-reduced-motion: reduce) {
  .hero--auftritt .hero__zeile-innen { transform: none; }
}

/* Das Hintergrundbild faehrt beim Scrollen langsam heran und tritt zurueck.
   Bevorzugt ueber eine scrollgebundene CSS-Animation, die ohne JavaScript
   und ausserhalb des Hauptstrangs laeuft. Kann der Browser das nicht,
   uebernimmt main.js dieselbe Bewegung. */

@keyframes hero-tiefe {
  from { transform: scale(1.04) translateY(0);      opacity: .5; }
  to   { transform: scale(1.13) translateY(-2.5%);  opacity: .32; }
}

@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: scroll()) {
    .hero__media {
      animation: hero-tiefe linear both;
      animation-timeline: scroll(root block);
      animation-range: 0 100vh;
    }
  }
}

.hero__foot {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: end;
  gap: clamp(1.75rem, 4vw, 4rem);
  margin-top: clamp(2rem, 5vh, 3.5rem);
}

.hero__lead {
  max-width: 46ch;
  font-size: var(--fs-lead);
  color: var(--text-dim);
}

/* Auftritt: erst Claim, dann Text, dann Zeile ------------------------- */
/* Vorspann und Fuss blenden ein - der Claim nicht, der faehrt zeilenweise
   herein (siehe "Auftritt: Zeile fuer Zeile").

   Der Ausgangszustand haengt an .hero--auftritt, gesetzt von main.js.
   Ohne JavaScript kaeme weder die noch is-ready, und der Kopfbereich
   bliebe dauerhaft unsichtbar. So steht er dann einfach sofort da. */
.hero--auftritt .hero__foot {
  opacity: 0;
  transform: translateY(1.4rem);
  transition: opacity .9s var(--ease-out), transform .9s var(--ease-out);
}
/* Der Fuss kommt nach den Zeilen, nicht mit ihnen. */
.hero--auftritt.is-ready .hero__foot { opacity: 1; transform: none; transition-delay: .62s; }

/* =========================================================================
   Abschnitte
   ========================================================================= */

.section { position: relative; padding-block: var(--section-y); }
.section--raised { background: var(--ink-raised); }

.section__head { margin-bottom: clamp(2.5rem, 6vh, 4.5rem); }
.section__vorspann {
  max-width: 54ch;
  margin: 1.1rem 0 0;
  color: var(--text-dim);
  font-size: var(--fs-lead);
}

/* Kein Abstand nach oben mehr: Darueber stand frueher eine Etikettzeile
   ("Services", "Kontakt"), die den Abschnittsnamen wiederholte. Die ist
   entfallen, der Abstand mit ihr. */
.section__title {
  max-width: 20ch;
  font-size: var(--fs-h2);
  font-weight: 300;
  letter-spacing: -.03em;
}
/* --- Warum hier kein Farbtausch mehr steht ------------------------------
   Jede Abschnitts-Ueberschrift war zweigeteilt: ein weisser und ein
   gelber Halbsatz, die beim Vorbeiscrollen die Farbe tauschten. Zwei
   Dinge stimmten daran nicht.

   Erstens sagte die Teilung nichts. "Ausgewaehlte / Produktionen." ist
   ein Begriff, kein Gegensatz - die Farbe trennte Woerter, die
   zusammengehoeren. Ein einzelnes farbig gesetztes Wort in einer
   Ueberschrift ist die haeufigste Zutat aus dem Baukasten.

   Zweitens war es die dritte Bewegung ohne Zutun auf derselben Seite.
   Geblieben sind zwei, und beide haben einen Grund: der Auftritt des
   Claims beim Ankommen, und die Bilder, die beim Scrollen heranfahren -
   die tragen den Beweis, um den es auf dieser Seite geht.

   Gelb steht jetzt nur noch dort, wo es etwas bedeutet: auf dem
   Schalter, im Fokusrahmen, in der Auswahlmarkierung, am Geltungshinweis
   der AGB und am Zaehler der Grossansicht.                              */

/* Reveal beim Scrollen ------------------------------------------------ */
/* Hier stand das Einblenden: Jeder Abschnitt verblasste herein und fuhr
   dabei ein Stueck nach oben - auf zwanzig Stellen der Seite.

   Das ist die verbreitetste Bewegung ueberhaupt und sagt nichts ueber
   den Inhalt. Sie ist ersatzlos entfallen. Bewegung ohne Zutun bleibt
   an zwei Stellen, und beide haben einen Grund: der Auftritt des Claims
   beim Ankommen auf der Seite, und die Bilder, die beim Scrollen
   langsam heranfahren. */

/* --- Ueber uns ------------------------------------------------------- */

.about__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(2rem, 6vw, 6rem);
  align-items: start;
}

.about__body { color: var(--text-dim); font-size: var(--fs-lead); }
.about__body p + p { margin-top: 1.5rem; }
.about__cta { margin-top: 2.5rem; }


/* --- Leistungen ------------------------------------------------------ */

/* Laufband statt Raster: drei Karten nebeneinander, danebenliegende
   schieben sich langsam durchs Bild. Ohne JavaScript bleibt es eine ganz
   normale, seitwaerts scrollbare Reihe - Wischen funktioniert dann trotzdem. */

.slider {
  overflow-x: auto;
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  cursor: grab;
}
.slider::-webkit-scrollbar { display: none; }
.slider[data-greift] { cursor: grabbing; }
.slider:focus-visible { outline: 2px solid var(--signal); outline-offset: 6px; border-radius: var(--radius); }

.slider__spur {
  display: flex;
  gap: .625rem;                 /* wie frueher: 10px */
  width: max-content;
  align-items: stretch;
}

/* Drei Karten sichtbar, darunter zwei, auf dem Handy eine. */
.slider__spur > .card {
  flex: 0 0 calc((min(100vw, var(--shell)) - 2 * var(--gutter) - 1.25rem) / 3);
  min-width: 240px;
}

/* Die Karte ist kein Kasten mehr.

   Vorher: eine gerahmte Flaeche mit abgerundeten Ecken, einem Verlauf
   darunter, einem zweiten darueber, und beim Zeigen darauf hob sie sich
   an und das Foto zoomte. Auf eine Karte, die man gar nicht anklicken
   kann, antwortet eine Bewegung auf nichts - sie war reine Zierde, und
   drei gleiche Kaesten nebeneinander sind der verbreitetste Baustein
   ueberhaupt.

   Jetzt steht das Foto im eigenen Rahmen und die Zeile darunter - genau
   wie bei den Projekten weiter unten. Dieselbe Ordnung zweimal auf einer
   Seite ist leichter zu lesen als zwei Erfindungen. */

.card {
  display: grid;
  grid-template-rows: auto auto 1fr;
  gap: .9rem;
  align-content: start;
}

/* Der Rahmen schneidet ab, das Foto darin faehrt (siehe "Bildtiefe").
   Grundflaeche und Haarlinie tragen ihn auch, wenn eine Datei fehlt -
   dann steht dort ein leerer Rahmen statt eines Lochs. Genau dieselbe
   Vorsorge wie bei den Projektbildern weiter unten. */
.card__rahmen {
  position: relative;
  aspect-ratio: 4 / 3;
  min-width: 0;
  overflow: clip;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: #17171a;
}

.card__media {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.card__title {
  margin: 0;
  font-size: var(--fs-h3);
  font-weight: 400;
}
.card__text {
  margin: 0;
  max-width: 38ch;
  font-size: var(--fs-small);
  line-height: 1.6;
  color: var(--text-dim);
}

/* --- Referenzen ------------------------------------------------------ */

.refs {
  display: grid;
  gap: clamp(3.5rem, 9vh, 7rem);
}

/* Ein Projekt steht gestapelt: erst der Kopf, dann das Bild ueber die
   ganze Breite, dann der Text. Vorher standen Bild und Text nebeneinander
   und teilten sich die Breite - das Bild kam dabei nie zur Geltung.

   Das ist die Ordnung, in der man ein Projekt liest: Worum geht es, wie
   sah es aus, was haben wir gemacht. */
.ref {
  display: grid;
  grid-template-areas: "bild" "text";
  gap: clamp(1.25rem, 2.5vw, 2rem);
}

.ref__media { grid-area: bild; }
.ref__text  { grid-area: text; }

/* Ort und Titel liegen in derselben Rasterzelle wie das Bild, unten
   links darin. Titel und Bild lesen sich dadurch als ein Stueck, statt
   als zwei gestapelte Bloecke.

   Nicht der ganze Text: Gemessen verdeckt ein Verlauf, der einen
   Absatz traegt, rund 40 Prozent der Bildflaeche - genau die Flaeche,
   die das grosse Bild gewonnen hat. Fuer zwei Zeilen reicht ein
   flacher Verlauf am unteren Rand, und der kostet 1 Prozent. */
.ref__kopf {
  grid-area: bild;
  align-self: end;
  justify-self: start;
  position: relative;
  z-index: 1;
  max-width: min(70%, 42rem);
  padding: clamp(1.5rem, 3vw, 2.75rem);
  /* Der Kasten selbst laesst Klicks durch zum Bildschalter darunter,
     seine Zeilen bleiben markierbar. */
  pointer-events: none;
}
.ref__kopf > * { pointer-events: auto; }

/* Ein oder zwei Bilder. Bei zweien teilen sie sich die Spalte. */
.ref__media {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  gap: .7rem;
}

/* Rahmen und Foto sind getrennt: Der Rahmen steht, das Foto bewegt sich
   darin. Deshalb liegt das Bild im inneren .ref__foto und nicht hier -
   sonst wanderten Rand und Ecken mit. */
.ref__bild {
  position: relative;
  /* Breiter als hoch, seit das Bild ueber die ganze Spalte laeuft: Im
     3:2-Format waere es bei 1320 px Breite 880 px hoch und passte auf
     keinen Laptop-Schirm mehr. max-height deckelt es zusaetzlich, damit
     es auch auf flachen Schirmen ganz zu sehen ist. */
  aspect-ratio: 16 / 9;
  max-height: min(76vh, 820px);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  /* Feste Flaeche, damit ein fehlendes Foto kein Loch hinterlaesst. */
  background-color: #17171a;
  /* overflow: clip, nicht hidden und nicht clip-path.
     hidden macht den Rahmen zu einem Scrollbereich - view() im Kind
     bezoege sich dann auf diesen Rahmen statt auf die Seite, und da im
     Rahmen nichts zu scrollen ist, stuende die Bewegung still.
     clip-path wiederum schneidet nur das Bild ab, nicht den Ueberlauf:
     Das vergroesserte Foto zaehlte weiter zur Breite der Seite und liess
     sie auf dem Handy um 17 px seitlich wackeln.
     clip schneidet beides ab und ist trotzdem kein Scrollbereich. */
  overflow: clip;
  transition: border-color .4s var(--ease);
}
.ref:hover .ref__bild { border-color: var(--line-strong); }

/* Der Verlauf unter dem Titel. Nur am unteren Rand und flach - dort
   steht auf diesen Fotos ohnehin meist der Publikumsblock. */
.ref__bild::after {
  content: '';
  position: absolute;
  inset: auto 0 0 0;
  height: 62%;
  background: linear-gradient(to top,
    rgba(8, 8, 9, .92) 0%,
    rgba(8, 8, 9, .72) 26%,
    rgba(8, 8, 9, .34) 54%,
    rgba(8, 8, 9, 0) 100%);
  pointer-events: none;
}

/* Der Rahmen ist ein Schalter - er muss aussehen wie vorher der Kasten.
   width: 100% ist noetig, weil ein button sonst nur so breit wird wie
   sein Inhalt, und der Inhalt ist absolut gesetzt, also nichts. */
.ref__bild {
  width: 100%;
  padding: 0;
  font: inherit;
  color: inherit;
  cursor: zoom-in;
  -webkit-appearance: none;
  appearance: none;
}
/* Projekt ohne Foto. Kein Schalter, keine Grossansicht - nur der Rahmen
   in der roten Kennzeichnung, die auf dieser Seite ueberall "hier fehlt
   noch etwas" bedeutet. So bleibt die Zeile im Raster stehen, statt dass
   der Text allein auf halber Breite haengt. */
.ref__bild--offen {
  /* min-width: 0 ist hier kein Schoenheitsfehler, sondern noetig: Das
     Feld ist ein Raster und traegt aspect-ratio. Ohne die Angabe leitet
     der Browser seine Mindestbreite aus der Hoehe des umbrochenen Textes
     ab (Hoehe x 3/2) - am Handy wurde der Kasten dadurch 424 statt
     350 px breit und die ganze Seite lief seitlich ueber. */
  min-width: 0;
  display: grid;
  align-content: center;
  justify-items: center;
  gap: .4rem;
  margin: 0;
  padding: 1.5rem;
  border-style: dashed;
  border-color: var(--danger);
  background-color: color-mix(in srgb, var(--danger) 6%, #17171a);
  color: var(--danger);
  text-align: center;
  font-size: var(--fs-small);
  line-height: 1.55;
  cursor: default;
}
.ref__bild--offen strong { font-size: var(--fs-body); font-weight: 600; }

.ref__bild:focus-visible {
  outline: 2px solid var(--signal);
  outline-offset: 3px;
}

/* Heranfahren beim Ueberfahren. Ueber transform, weil scale und translate
   schon der Bildtiefe beim Scrollen gehoeren - die beiden ueberlagern
   sich, statt sich auszuknipsen. */
.ref__bild:hover .ref__foto,
.ref__bild:focus-visible .ref__foto {
  transform: scale(1.06);
}
.ref__foto { transition: transform .5s var(--ease-out); }

/* Das Zeichen sagt, dass hier etwas zu holen ist: eine Lupe, die erst
   beim Ueberfahren auftaucht. Gezeichnet aus zwei Formen - Kreis und
   Griff -, damit keine Bilddatei dafuer noetig ist. */
.ref__zeichen {
  position: absolute;
  z-index: 1;   /* ueber dem Verlauf, der als ::after zuletzt gezeichnet wird */
  right: 1rem;
  bottom: 1rem;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 50%;
  background: rgba(11, 11, 12, .72);
  backdrop-filter: blur(6px);
  opacity: 0;
  transform: translateY(.4rem);
  transition: opacity .35s var(--ease), transform .35s var(--ease-out);
  pointer-events: none;
}
.ref__zeichen::before {
  content: '';
  position: absolute;
  left: .78rem; top: .78rem;
  width: .95rem; height: .95rem;
  border: 2px solid var(--text);
  border-radius: 50%;
}
.ref__zeichen::after {
  content: '';
  position: absolute;
  right: .72rem; bottom: .72rem;
  width: .55rem; height: 2px;
  background: var(--text);
  transform: rotate(45deg);
  transform-origin: right center;
}
.ref__bild:hover .ref__zeichen,
.ref__bild:focus-visible .ref__zeichen {
  opacity: 1;
  transform: none;
}

/* Ohne JavaScript bleibt hier eine schlichte Liste von Verweisen auf die
   Bilddateien stehen. main.js blendet sie aus, sobald es den Rahmen zum
   Schalter gemacht hat. */
.ref__bilder {
  margin: .6rem 0 0;
  padding: 0;
  list-style: none;
  font-size: var(--fs-small);
}
.ref__bilder a { color: var(--text-faint); }
.ref__bilder a:hover { color: var(--signal); }
.ref__nachweis { color: var(--text-faint); }

/* Ein echtes <img>, kein Hintergrundbild - nur so greift loading="lazy".
   object-fit: cover fuellt den Rahmen wie background-size: cover es tat,
   object-position ersetzt background-position (das Festivalbild nutzt das,
   weil es hochformatig ist). */
.ref__foto {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}

.ref__titel {
  margin: .35rem 0 0;
  /* Groesser als vorher: Der Titel steht jetzt allein ueber dem Bild und
     traegt den Abschnitt, statt neben ihm herzulaufen. */
  font-size: clamp(1.75rem, 3.4vw, 3rem);
  font-weight: 400;
  letter-spacing: -.02em;
  text-wrap: balance;
}

/* Der Text steht unter dem Bild in zwei Spalten: links, worum es ging,
   rechts, was wir daran gemacht haben. Nicht ueber die volle Breite -
   eine Zeile von 1320 px laesst sich nicht lesen.

   Die beiden Saeulen sind eigene Kaesten und nicht einfach Absaetze im
   Raster: Zu unserem Teil gehoeren manchmal zwei Absaetze, und die
   sollen untereinander stehen statt in die naechste Rasterzeile zu
   rutschen - dort klaffte sonst eine Luecke ueber die halbe Breite. */
.ref__text {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(1rem, 3vw, 3rem);
  align-items: start;
  margin-top: clamp(.25rem, 1vw, .75rem);
}

.ref__text p {
  margin: 0 0 1em;
  max-width: 54ch;
  color: var(--text-dim);
}
.ref__text p:last-child { margin-bottom: 0; }

/* Die Gewerke laufen unter beiden Spalten durch. */
.ref__text .gewerke { grid-column: 1 / -1; margin-top: clamp(.5rem, 1.5vw, 1.25rem); }

/* --- Bildtiefe beim Scrollen -------------------------------------------
   Die Fotos stehen nicht still, solange sie im Bild sind: Sie fahren
   langsam heran und wandern dabei ein Stueck nach oben. Dieselbe Bewegung
   wie im Kopfbild, nur auf die Flaeche des jeweiligen Rahmens bezogen.

   Gerechnet wird mit den eigenstaendigen Eigenschaften scale und
   translate, nicht mit transform. Das ist Absicht: transform bleibt so
   fuer das Ueberfahren mit der Maus frei, beide ueberlagern sich, statt
   sich gegenseitig auszuknipsen.

   Der Weg ist bemessen. Das Foto deckt den Rahmen nur, solange der
   Ueberstand groesser bleibt als der Versatz - und der Ueberstand ist die
   halbe Vergroesserung: Bei scale 1.22 stehen 11 Prozent auf jeder Seite
   ueber, verschoben wird um hoechstens 7,5. Bleiben 3,5 Prozent Luft -
   auf einem 233 Pixel hohen Rahmen rund 8 Pixel. Wer den Versatz erhoeht,
   muss die Vergroesserung mitziehen, sonst blitzt der Rahmen durch.

   15 Prozent Gesamtweg sind mit Absicht kein Hauch: Am Handy wandert die
   Bildmitte damit rund 34 Pixel durch ihren Rahmen - man sieht es, ohne
   dass die Seite unruhig wird. */

@keyframes bild-tiefe {
  from { scale: 1.22; translate: 0  7.5%; }
  to   { scale: 1.32; translate: 0 -7.5%; }
}

/* Beide Bedingungen zusammen, nicht getrennt: Die Karten brauchen
   timeline-scope. Kann ein Browser nur die Haelfte, blieben sie in der
   Mitte der Bewegung stehen statt sich zu ruehren - dann ist es besser,
   main.js macht die Arbeit fuer alles. Genau dieses Paar fragt main.js
   noch einmal ab. */
@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) and (timeline-scope: --pruefung) {
    .ref__foto {
      animation: bild-tiefe linear both;
      animation-timeline: view(block);
      /* Von dem Moment an, in dem das Bild unten hereinkommt, bis es oben
         verschwindet - also ueber die ganze Zeit, in der man es sieht. */
      animation-range: cover 0% cover 100%;
    }

    /* Die Karten liegen in einem waagerecht scrollenden Kasten. Damit ist
       dieser Kasten fuer view() der naechste Scrollbereich - und weil er
       senkrecht nichts zu scrollen hat, käme dort keine Bewegung zustande.
       Deshalb spannt der Abschnitt selbst die Zeitachse auf und gibt sie
       ueber timeline-scope nach innen weiter. Alle vier Karten atmen so
       gemeinsam, waehrend der Abschnitt vorbeizieht. */
    #services { view-timeline-name: --dienste-sicht; }
    main { timeline-scope: --dienste-sicht; }

    .card__media {
      animation: bild-tiefe linear both;
      animation-timeline: --dienste-sicht;
      animation-range: cover 0% cover 100%;
    }
  }
}

/* =========================================================================
   Grossansicht der Projektbilder
   ========================================================================= */

/* Das <dialog> deckt die ganze Flaeche ab, damit ein Klick daneben es
   schliessen kann - die Pruefung dafuer steht in main.js und fragt, ob
   der Treffer ausserhalb von .lupe__rahmen lag. Deshalb keine Groesse
   nach Inhalt, sondern Vollbild mit durchsichtigem Grund. */
.lupe {
  width: 100%;
  max-width: none;
  height: 100%;
  max-height: none;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--text);
  overflow: hidden;
}
.lupe::backdrop {
  background: rgba(6, 6, 7, .88);
  backdrop-filter: blur(10px);
}

/* Der Rahmen fuellt die ganze Flaeche, damit das Bild in der Mitte sitzt -
   und laesst Klicks trotzdem durch. Sonst gaebe es kein "daneben": Jeder
   Treffer auf den Rand laege im Rahmen, und die Ansicht liesse sich nur
   ueber Escape und das Kreuz schliessen. Bild und Knoepfe nehmen ihre
   Klicks einzeln wieder an. */
.lupe__rahmen {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  /* stretch, nicht center: Nur so bekommt die Figur eine feste Hoehe, und
     nur dann hat "max-height: 100%" am Bild etwas, worauf es sich
     beziehen kann. Mit center war die Figur so hoch wie ihr Inhalt, die
     Angabe lief ins Leere - ein hochformatiges Foto stand dann mit 1600
     px in einem 900 px hohen Fenster und ragte oben und unten heraus.
     Die Knoepfe setzen sich einzeln wieder in die Mitte. */
  align-items: stretch;
  gap: clamp(.5rem, 2vw, 1.5rem);
  height: 100%;
  padding: clamp(3.5rem, 8vh, 5rem) clamp(.75rem, 3vw, 2.5rem) clamp(1.5rem, 5vh, 3rem);
  pointer-events: none;
}
.lupe__bild,
.lupe__knopf { pointer-events: auto; }

/* grid-column: 2 ist Pflicht, nicht Zierde. Hat ein Projekt nur ein Bild,
   sind beide Pfeile ausgeblendet - die Figur rutscht dann von selbst in
   die erste Spalte, und die ist "auto", also so breit wie ihr Inhalt.
   Das Bild stand damit klein am linken Rand statt gross in der Mitte. */
.lupe__figur {
  grid-column: 2;
  display: grid;
  grid-template-rows: minmax(0, 1fr) auto;
  gap: 1rem;
  margin: 0;
  height: 100%;
  min-height: 0;
  justify-items: center;
}

/* Das Bild fuellt, was der Kasten hergibt, ohne sein Verhaeltnis zu
   verlieren und ohne ueber den Rand zu wachsen. min-height: 0 an den
   Eltern ist dafuer Pflicht - ein Rasterfeld gibt sonst nie unter seine
   Inhaltsgroesse nach, und ein hohes Bild schoebe die Zeile darunter aus
   dem Bild. */
.lupe__bild {
  display: block;
  align-self: center;
  max-width: 100%;
  max-height: 100%;
  min-height: 0;
  object-fit: contain;
  border-radius: var(--radius);
  background: var(--ink-raised);
}

.lupe__zeile {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: center;
  gap: .35rem 1rem;
  font-size: var(--fs-small);
  color: var(--text-dim);
}
.lupe__zaehler {
  font-variant-numeric: tabular-nums;
  letter-spacing: .08em;
  color: var(--text-faint);
}

/* Der Bildnachweis steht zwischen Projektname und Zaehler und tritt
   zurueck - er gehoert zum Bild, ist aber nicht die Aussage. */
.lupe__nachweis { color: var(--text-faint); }
.lupe__nachweis[hidden] { display: none; }

.lupe__knopf {
  display: grid;
  place-items: center;
  align-self: center;
  width: 3rem;
  height: 3rem;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: rgba(18, 18, 19, .8);
  color: var(--text);
  cursor: pointer;
  transition: border-color .3s var(--ease), background .3s var(--ease);
}
.lupe__knopf:hover { border-color: var(--line-strong); background: var(--ink-raised); }
.lupe__knopf:focus-visible { outline: 2px solid var(--signal); outline-offset: 3px; }
.lupe__knopf[hidden] { display: none; }

/* Die Zeichen sind gezeichnet, nicht gesetzt: zwei Striche als Kreuz,
   zwei als Pfeilspitze. Das spart eine Schriftart oder Bilddatei nur fuer
   drei Symbole. */
.lupe__knopf::before,
.lupe__knopf::after {
  content: '';
  position: absolute;
  width: .85rem;
  height: 2px;
  background: currentColor;
  border-radius: 2px;
}
.lupe__knopf { position: relative; }
.lupe__zu::before { transform: rotate(45deg); }
.lupe__zu::after  { transform: rotate(-45deg); }

.lupe__blaettern::before,
.lupe__blaettern::after {
  width: .7rem;
  transform-origin: right center;
}
.lupe__vor::before      { transform: translateX(-.1rem) rotate(45deg); }
.lupe__vor::after       { transform: translateX(-.1rem) rotate(-45deg); }
.lupe__zurueck::before  { transform: translateX(.25rem) rotate(-135deg); }
.lupe__zurueck::after   { transform: translateX(.25rem) rotate(135deg); }

.lupe__zu {
  position: absolute;
  top: clamp(.75rem, 3vh, 1.5rem);
  right: clamp(.75rem, 3vw, 2.5rem);
  z-index: 1;
}

/* Am Handy ist neben dem Bild keine Spalte fuer Pfeile uebrig. Dort
   liegen sie deshalb auf halber Hoehe am linken und rechten Rand, ueber
   dem Bild statt daneben - so bleibt die ganze Breite fuer das Foto.

   Sie aus dem Raster zu nehmen ist Absicht: Im Raster liessen sie sich
   nur nebeneinander unter die Zeile setzen, und dann sassen beide in
   derselben Zelle. */
@media (max-width: 620px) {
  .lupe__rahmen {
    grid-template-columns: minmax(0, 1fr);
    padding-inline: 1rem;
  }
  .lupe__figur { grid-column: 1; grid-row: 1; width: 100%; }
  .lupe__blaettern {
    position: absolute;
    top: 50%;
    margin-top: -1.5rem;
    background: rgba(11, 11, 12, .78);
    backdrop-filter: blur(6px);
  }
  .lupe__zurueck { left: .75rem; }
  .lupe__vor { right: .75rem; }
}

/* --- Gewerke ---------------------------------------------------------
   Eine Definitionsliste, kein Baukasten: links, worum es geht, rechts
   die Leistungen. Vorher standen sie als gleichfoermige Pillen mit
   farbigen Punkten davor. Die Punkte verschluesselten eine Einteilung,
   die nirgends erklaert war, und zehn Reihen davon sahen aus wie ein
   Bausatz - nicht wie das Leistungsverzeichnis, das sie sind.

   Der Begriff links steht in Satzschreibung, nicht in Versalien: Eine
   gesperrte Grossbuchstabenzeile ueber dem Inhalt ist die haeufigste
   Beschriftung, die man sieht, und sagt nichts, was der Inhalt nicht
   schon sagt. */

.gewerke {
  display: grid;
  grid-template-columns: minmax(6.5rem, 9ch) minmax(0, 1fr);
  gap: 0 clamp(1rem, 2vw, 2rem);
  margin: 0;
  padding-top: 1.1rem;
  border-top: 1px solid var(--line);
  font-size: var(--fs-small);
  line-height: 1.6;
}
.gewerke dt {
  color: var(--text-faint);
  font-weight: 500;
}
.gewerke dd {
  margin: 0;
  max-width: 62ch;
  color: var(--text);
  /* Die Aufzaehlung soll als eine Zeile Satz lesbar bleiben, auch wenn
     sie umbricht - deshalb kein hartes Trennen einzelner Begriffe. */
  hyphens: none;
}

.gewerke--gross {
  margin-top: clamp(2.5rem, 6vh, 4rem);
  font-size: var(--fs-body);
}

/* Noch auszufuellen. Bewusst auffaellig, damit es niemand uebersieht. */
.offen {
  border-style: dashed;
  border-color: var(--danger);
  color: var(--danger);
}


/* Gleiche Kennzeichnung als Block, etwa fuer eine Seite ohne Inhalt. */
.offen--block {
  display: block;
  padding: 1.15rem 1.35rem;
  border: 1px dashed var(--danger);
  border-radius: var(--radius);
  background: color-mix(in srgb, var(--danger) 8%, transparent);
  line-height: 1.6;
}
.offen--block strong { color: var(--danger); }
.offen--block code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .9em;
}

/* =========================================================================
   Kontakt
   ========================================================================= */

/* Hier lag der einzige Schmuck des Abschnitts: ein gelber Schein hinter
   der Ueberschrift und eine schmale gelbe Marke daneben. Beides ist
   entfallen.

   Der Schein war eine Farbwaesche ohne Aussage - der verbreitetste
   Zierrat auf einer dunklen Seite. Und die Marke stand an genau einer
   von fuenf Ueberschriften; wo ein Zeichen nur einmal vorkommt, liest
   man es als Hinweis und sucht danach vergeblich einen Grund.

   Gelb bleibt dort, wo es etwas heisst: auf dem Schalter, im
   Fokusrahmen, an den Pflichtfeld-Sternchen, in der Auswahlmarkierung,
   am Geltungshinweis der AGB und am Zaehler der Grossansicht. */
#kontakt { position: relative; }

.contact__grid {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, .85fr);
  gap: clamp(2.5rem, 6vw, 5.5rem);
  align-items: start;
}

/* --- Formular -------------------------------------------------------- */

.form__row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.25rem;
}

.field { margin-bottom: 1.5rem; }

.field__label {
  display: block;
  margin-bottom: .55rem;
  font-size: var(--fs-small);
  font-weight: 400;
  color: var(--text-dim);
}
.field__label .req { color: var(--signal); }

.field__input {
  width: 100%;
  padding: .95rem 1.1rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--ink-raised);
  color: var(--text);
  font: inherit;
  font-size: var(--fs-body);
  transition: border-color .3s var(--ease), background-color .55s var(--ease),
              color .55s var(--ease);
}
.section--raised .field__input { background: var(--ink); }

.field__input::placeholder { color: var(--text-faint); }
.field__input:hover { border-color: var(--line-strong); }
.field__input:focus {
  outline: none;
  border-color: var(--signal);
}
.field__input[aria-invalid="true"] { border-color: var(--danger); }

textarea.field__input { min-height: 150px; resize: vertical; }

.field__error {
  display: block;
  min-height: 1.2em;
  margin-top: .4rem;
  font-size: var(--fs-small);
  color: var(--danger);
}

/* Kategorien als Schalter -------------------------------------------- */
.chips { display: flex; flex-wrap: wrap; gap: .6rem; }

.chip { position: relative; }
.chip input {
  position: absolute;
  opacity: 0;
  width: 0; height: 0;
}
.chip span {
  display: inline-block;
  padding: .6rem 1.25rem;
  border: 1px solid var(--line);
  border-radius: 100px;
  font-size: var(--fs-small);
  color: var(--text-dim);
  cursor: pointer;
  transition: all .3s var(--ease);
}
.chip input:hover + span { border-color: var(--line-strong); color: var(--text); }
.chip input:checked + span {
  background: var(--signal);
  border-color: var(--signal);
  color: var(--ink);
  font-weight: 500;
}
.chip input:focus-visible + span {
  outline: 2px solid var(--signal);
  outline-offset: 3px;
}

/* Einwilligung -------------------------------------------------------- */
.consent {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: .85rem;
  align-items: start;
  margin-block: 1.75rem 1.25rem;
  font-size: var(--fs-small);
  line-height: 1.55;
  color: var(--text-dim);
}
.consent input {
  width: 20px; height: 20px;
  margin: .18rem 0 0;
  accent-color: var(--signal);
  cursor: pointer;
  flex: none;
}
.consent a { color: var(--text); text-decoration-color: var(--text-faint); }
.consent a:hover { color: var(--signal); }

/* Honigtopf: fuer Menschen unsichtbar, fuer Bots verlockend */
.honeypot {
  position: absolute;
  left: -9999px;
  width: 1px; height: 1px;
  overflow: hidden;
}

.form__status {
  margin-top: 1.5rem;
  padding: 1.1rem 1.35rem;
  border: 1px solid var(--danger);
  border-radius: var(--radius);
  background: rgba(255, 107, 94, .08);
  background: color-mix(in srgb, var(--danger) 12%, transparent);
  font-size: var(--fs-small);
  line-height: 1.55;
}
.form__status--ok {
  border-color: var(--signal);
  background: rgba(248, 248, 8, .08);
  background: color-mix(in srgb, var(--signal) 10%, transparent);
}
.form__status a { color: var(--signal); }

.form__note {
  margin-top: 1.25rem;
  font-size: var(--fs-small);
  color: var(--text-faint);
}

/* --- Kontaktdaten ---------------------------------------------------- */

.contact__details { display: grid; gap: 1px; background: var(--line); border-block: 1px solid var(--line); }

.detail { padding: 1.5rem 0 1.5rem 1.5rem; background: var(--ink); }
.section--raised .detail { background: var(--ink-raised); }

.detail__label {
  margin: 0 0 .35rem;
  font-size: var(--fs-small);
  font-weight: 400;
  color: var(--text-faint);
}
.detail__value {
  margin: 0;
  font-size: clamp(1.05rem, 1.5vw, 1.3rem);
  font-weight: 300;
  letter-spacing: -.01em;
}
.detail__value a {
  text-decoration: none;
  background-image: linear-gradient(var(--signal), var(--signal));
  background-size: 0% 1px;
  background-repeat: no-repeat;
  background-position: 0 100%;
  transition: background-size .4s var(--ease-out), color .3s var(--ease);
}
.detail__value a:hover { background-size: 100% 1px; color: var(--signal); }

/* =========================================================================
   Fusszeile
   ========================================================================= */

.footer {
  padding-block: 3rem;
  background: var(--ink-sunken);
  border-top: 1px solid var(--line);
}

.footer__grid {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem 2rem;
}

.footer__logo { --claim-groesse: .72rem; opacity: .7; }
.footer__logo .marke__zeichen { width: 238px; }
.footer__logo:hover { opacity: 1; }

.footer__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem;
  margin: 0;
  font-size: var(--fs-small);
  color: var(--text-faint);
}
.footer__meta a { text-decoration: none; transition: color .3s var(--ease); }
.footer__meta a:hover { color: var(--signal); }

/* Der Weg zurueck in die Einwilligung. main.js haengt ihn ein - ohne
   JavaScript gibt es keine Einstellung, die er oeffnen koennte. */
.footer__knopf {
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  cursor: pointer;
  transition: color .3s var(--ease);
}
.footer__knopf:hover, .footer__knopf:focus-visible { color: var(--signal); }

/* =========================================================================
   Rechtstexte & 404
   ========================================================================= */

.legal { padding-block: clamp(8rem, 18vh, 12rem) var(--section-y); }

.legal__inner { max-width: 74ch; }

/* Kopf einer Rechtsseite: Titel, darunter eine Zeile, die sagt, was die
   Seite ist. Danach eine Linie - dieselbe Trennung wie zwischen den
   Abschnitten der Startseite. */
.legal__kopf {
  padding-bottom: clamp(1.5rem, 3vh, 2.25rem);
  margin-bottom: clamp(2rem, 4vh, 3rem);
  border-bottom: 1px solid var(--line);
}
.legal__unter {
  margin: .9rem 0 0;
  color: var(--text-faint);
  font-size: var(--fs-small);
}

.legal__vorspann {
  font-size: var(--fs-lead);
  color: var(--text) !important;
}
/* Der Anbieter steht heraus - es ist die Angabe, wegen der die Seite
   existiert. */
.legal__anbieter {
  margin: 0 0 clamp(2rem, 4vh, 2.75rem);
  font-size: var(--fs-lead);
  line-height: 1.5;
  color: var(--text) !important;
}
.legal__anbieter strong { font-weight: 600; }

/* Pflichtangaben als Definitionsliste - dieselbe Form wie die Gewerke
   auf der Startseite und die Kontaktdaten darunter. Wer eine Angabe
   sucht, findet sie an der Bezeichnung links, statt sie aus einem
   Absatz herauszulesen. */
.angaben {
  display: grid;
  gap: 0;
  margin: 0 0 clamp(2.5rem, 5vh, 3.5rem);
  border-top: 1px solid var(--line);
}
.angaben__zeile {
  display: grid;
  grid-template-columns: minmax(9rem, 13ch) minmax(0, 1fr);
  gap: 0 clamp(1rem, 2.5vw, 2.5rem);
  padding: 1.05rem 0;
  border-bottom: 1px solid var(--line);
}
.angaben dt {
  color: var(--text-faint);
  font-size: var(--fs-small);
  font-weight: 500;
}
.angaben dd {
  margin: 0;
  color: var(--text);
  line-height: 1.65;
}

.legal__inner h1 {
  margin: 0;
  font-size: var(--fs-h2);
  font-weight: 300;
  letter-spacing: -.03em;
}
/* Die Gliederungsebene wird ueber Groesse und Linie unterschieden, nicht
   ueber Farbe. Vorher stand h3 in Signalgelb - ein Rest aus der Zeit vor
   der Ueberarbeitung des Entwurfs. Auf einer Seite mit zwanzig
   Zwischenueberschriften war die Seite dadurch ueberwiegend gelb, und
   Gelb sollte auf dieser Website etwas heissen. */
.legal__inner h2 {
  margin: clamp(3rem, 6vh, 4rem) 0 1rem;
  padding-top: clamp(1.5rem, 3vh, 2rem);
  border-top: 1px solid var(--line);
  font-size: clamp(1.4rem, 2.4vw, 1.9rem);
  font-weight: 400;
  letter-spacing: -.02em;
}
.legal__inner h3 {
  margin: 2.5rem 0 .75rem;
  font-size: var(--fs-h3);
  font-weight: 500;
}
.legal__inner h4 {
  margin: 1.75rem 0 .5rem;
  font-size: 1.05rem;
  font-weight: 500;
}
.legal__inner p,
.legal__inner li { color: var(--text-dim); }

/* Die Rechtstexte fuehren lange Fremdadressen als Linktext. Ohne diese
   beiden Zeilen schiebt eine einzige davon die Seite am Handy auf 561
   statt 390 px auf, und sie laesst sich seitlich verschieben. anywhere
   statt break-word, weil eine Adresse fuer den Umbruch ein einziges Wort
   ist und break-word sie erst am Ende der Zeile bricht. */
.legal__inner { overflow-wrap: break-word; }
.legal__inner a { overflow-wrap: anywhere; }
.legal__inner ul { padding-left: 1.15rem; margin: 0 0 1.25em; }
/* Der Name eines Speichereintrags im Fliesstext - lesbar als das, was er
   ist, ohne wie Programmcode zu wuchten. */
.legal__inner code {
  padding: .1em .4em;
  border-radius: 4px;
  background: var(--ink-raised);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: .9em;
  word-break: break-word;
}
.legal__inner li { margin-bottom: .5rem; }
.legal__inner a { color: var(--text); text-decoration-color: var(--text-faint); }
.legal__inner a:hover { color: var(--signal); }
.legal__inner strong { color: var(--text); font-weight: 500; }

/* --- AGB ----------------------------------------------------------------
   Sechsunddreissig Paragraphen auf einer Seite brauchen mehr Fuehrung als
   Impressum und Datenschutz. Drei Dinge leisten das:

   Die Teil-Ueberschriften tragen eine Linie und stehen in Grossschrift -
   das ist die Gliederung eines Vertragswerks, nicht die einer Website.
   Farbe traegt dabei nichts bei: Gelb bleibt dem Geltungshinweis und den
   Verweisen vorbehalten.

   Das Anspringen der Paragraphen deckt bereits scroll-padding-top: 6rem
   am html-Element ab - so weit steht die feste Kopfzeile in die Seite
   hinein. scroll-margin legt nur noch etwas Luft darueber; die beiden
   Werte addieren sich. */

.legal--agb { max-width: 78ch; }

/* Der Abstand war frueher negativ, weil h1 selbst 2,5 rem nach unten
   mitbrachte. Seit h1 keinen eigenen Abstand mehr hat, zog der negative
   Wert die Zeile in die Ueberschrift hinein - im Bild lag "Fuer
   Vermietung, Vermittlung ..." quer ueber "Geschaeftsbedingungen". */
.legal--agb .agb__kopf {
  margin: .9rem 0 2rem;
  font-size: var(--fs-small);
  color: var(--text-faint);
}
.legal--agb .agb__kopf span {
  display: inline-block;
  margin-top: .35rem;
}

/* Der einzige gelbe Akzent auf dieser Seite. */
.legal--agb .agb__geltung {
  position: relative;
  margin: 0 0 2.5rem;
  padding: .9rem 0 .9rem 1.25rem;
  color: var(--text);
  font-size: 1.02rem;
}
.legal--agb .agb__geltung::before {
  content: '';
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 2px;
  border-radius: 2px;
  background: linear-gradient(to bottom, var(--signal), rgba(248, 248, 8, .15));
}

.legal--agb .agb__inhalt {
  margin: 0 0 3.5rem;
  padding: 1.5rem 0;
  border-block: 1px solid var(--line);
}
.legal--agb .agb__inhalt ol {
  margin: 0; padding: 0;
  list-style: none;
  display: grid;
  gap: .55rem;
}
.legal--agb .agb__inhalt li {
  display: flex;
  align-items: baseline;
  gap: .75rem;
  margin: 0;
  color: var(--text-faint);
}
/* min-width: 0 an beiden Stellen ist Pflicht: Ein Flex-Kind schrumpft von
   sich aus nicht unter seine Inhaltsbreite. Ohne das sprengt
   "Dienstleistungen und Personaleinsatz" die Zeile, und die Seite wird
   auf schmalen Schirmen breiter als das Fenster. */
.legal--agb .agb__inhalt a {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  gap: .6rem;
  text-decoration: none;
  color: var(--text-faint);
}
.legal--agb .agb__inhalt a span { min-width: 0; }
.legal--agb .agb__inhalt a span { color: var(--text); }
.legal--agb .agb__inhalt a:hover span,
.legal--agb .agb__inhalt a:focus-visible span { color: var(--signal); }
.legal--agb .agb__inhalt b {
  flex: 0 0 auto;
  font-weight: 400;
  font-variant-numeric: tabular-nums;
}

.legal--agb h2 {
  margin: 4.5rem 0 1.75rem;
  padding-top: 2rem;
  border-top: 1px solid var(--line);
  font-size: clamp(1.05rem, 1.6vw, 1.25rem);
  font-weight: 500;
  letter-spacing: .1em;
  scroll-margin-top: 1.5rem;
}
.legal--agb h2:first-of-type { border-top: 0; }

.legal--agb h3 {
  margin: 2.5rem 0 .85rem;
  font-size: 1.06rem;
  font-weight: 500;
  color: var(--text);
  scroll-margin-top: 1.5rem;
}

.legal--agb p { margin-bottom: 1.15em; }

/* Die Buchstabenpunkte der PDF. Kein Aufzaehlungszeichen - der Buchstabe
   ist das Zeichen und muss genau so stehen bleiben, wie er im Vertrag
   steht, weil andere Paragraphen darauf verweisen. */
.legal--agb .agb__punkte {
  list-style: none;
  margin: 0 0 1.25em;
  padding-left: .25rem;
}
.legal--agb .agb__punkte li {
  display: grid;
  grid-template-columns: 1.75rem 1fr;
  margin-bottom: .55rem;
}
.legal--agb .agb__bst { color: var(--text-faint); }

/* Laeuft der Satz nach der Aufzaehlung weiter, haengt er an ihr statt auf
   vollem Absatzabstand zu stehen (§ 17 Abs. 2). */
.legal--agb .agb__punkte + .agb__fort { margin-top: -.7em; }

/* =========================================================================
   Einwilligung
   =========================================================================
   Der Balken unten und die Einstellungen dahinter. Beides baut main.js
   zur Laufzeit - es soll auf jeder Seite gleich sein, und ohne
   JavaScript gibt es nichts einzuwilligen, weil dann auch nichts
   gespeichert wird.

   Kein Sperrschirm ueber der Seite: Impressum und Datenschutzerklaerung
   muessen erreichbar bleiben, auch solange die Frage offen ist. Der
   Balken liegt deshalb ueber dem Inhalt, nicht davor.                  */

.zustimmung {
  position: fixed;
  z-index: 200;
  left: var(--gutter);
  bottom: var(--gutter);
  width: min(30rem, calc(100vw - 2 * var(--gutter)));
  padding: 1.5rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--ink-raised);
  color: var(--text);
  box-shadow: 0 24px 60px rgba(0, 0, 0, .55);
}
@media (prefers-reduced-motion: no-preference) {
  .zustimmung { animation: zustimmung-auf .5s var(--ease-out) both; }
}
@keyframes zustimmung-auf {
  from { opacity: 0; transform: translateY(1.5rem); }
  to   { opacity: 1; transform: none; }
}

/* Solange die Frage offen ist, bekommt die Fusszeile unten so viel Platz
   dazu, wie der Balken hoch ist. Sonst deckt er am Handy genau die Zeile
   ab, in der Impressum und Datenschutzerklaerung stehen - und die
   muessen erreichbar bleiben, gerade solange nicht entschieden ist. */
.hat-zustimmung .footer::after {
  content: '';
  display: block;
  height: var(--zustimmung-hoehe, 0px);
}

.zustimmung__titel {
  margin: 0 0 .5rem;
  font-size: var(--fs-h3);
  font-weight: 600;
  letter-spacing: -.01em;
}
.zustimmung__text {
  margin: 0 0 1.25rem;
  font-size: var(--fs-small);
  line-height: 1.6;
  color: var(--text-dim);
}
.zustimmung__text a { color: var(--text); text-decoration: underline; text-underline-offset: .2em; }
.zustimmung__text a:hover, .zustimmung__text a:focus-visible { color: var(--signal); }

/* Zustimmen und Ablehnen stehen gleich gross nebeneinander - eine
   Ablehnung darf nicht muehsamer sein als eine Zustimmung. */
.zustimmung__wahl {
  display: flex;
  flex-wrap: wrap;
  gap: .6rem;
}
.zustimmung__wahl .btn {
  flex: 1 1 8rem;
  justify-content: center;
  padding: .8rem 1.2rem;
}
.zustimmung__wahl .btn::after { display: none; }

.zustimmung__mehr {
  margin-top: .9rem;
  padding: 0;
  border: 0;
  background: none;
  color: var(--text-dim);
  font: inherit;
  font-size: var(--fs-small);
  text-decoration: underline;
  text-underline-offset: .2em;
  cursor: pointer;
  transition: color .3s var(--ease);
}
.zustimmung__mehr:hover, .zustimmung__mehr:focus-visible { color: var(--signal); }

/* --- Die Einstellungen ---------------------------------------------- */

.einstellungen {
  width: min(41rem, calc(100vw - 2rem));
  max-width: none;
  margin: auto;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--ink-raised);
  color: var(--text);
}
.einstellungen::backdrop {
  background: rgba(6, 6, 7, .82);
  backdrop-filter: blur(8px);
}
.einstellungen__inhalt { padding: clamp(1.5rem, 4vw, 2.25rem); }
.einstellungen__titel {
  margin: 0 0 .6rem;
  font-size: var(--fs-h3);
  font-weight: 600;
  letter-spacing: -.01em;
}
.einstellungen__text {
  margin: 0 0 1.5rem;
  font-size: var(--fs-small);
  line-height: 1.6;
  color: var(--text-dim);
}

.einstellungen__liste {
  list-style: none;
  margin: 0 0 1.75rem;
  padding: 0;
  display: grid;
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
}
.gruppe {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: start;
  gap: 1rem;
  padding: 1.1rem 1.2rem;
  background: var(--ink);
}
.gruppe__name {
  margin: 0 0 .3rem;
  font-size: var(--fs-body);
  font-weight: 500;
}
.gruppe__was {
  margin: 0;
  font-size: var(--fs-small);
  line-height: 1.55;
  color: var(--text-dim);
}
.gruppe__leer {
  display: block;
  margin-top: .45rem;
  font-size: var(--fs-small);
  color: var(--text-faint);
}

/* Der Schalter. Die Checkbox bleibt bedienbar und wird nur unsichtbar
   darueber gelegt - so bringt sie Tastatur, Fokus und Vorlesen mit. */
.schalter { position: relative; flex: none; }
.schalter__feld {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}
.schalter__feld:disabled { cursor: default; }
.schalter__spur {
  display: block;
  width: 2.75rem; height: 1.5rem;
  border: 1px solid var(--line-strong);
  border-radius: 100px;
  background: var(--ink-sunken);
  transition: background-color .3s var(--ease), border-color .3s var(--ease);
}
.schalter__spur::before {
  content: '';
  display: block;
  width: 1rem; height: 1rem;
  margin: .19rem;
  border-radius: 50%;
  background: var(--text-faint);
  transition: transform .3s var(--ease-out), background-color .3s var(--ease);
}
.schalter__feld:checked + .schalter__spur {
  background: var(--signal);
  border-color: var(--signal);
}
.schalter__feld:checked + .schalter__spur::before {
  transform: translateX(1.25rem);
  background: var(--ink);
}
.schalter__feld:focus-visible + .schalter__spur {
  outline: 2px solid var(--signal);
  outline-offset: 3px;
}
.schalter__feld:disabled + .schalter__spur { opacity: .55; }

.einstellungen__wahl {
  display: flex;
  flex-wrap: wrap;
  gap: .6rem;
}
.einstellungen__wahl .btn {
  flex: 1 1 auto;
  justify-content: center;
  padding: .8rem 1rem;
  white-space: nowrap;
}
.einstellungen__wahl .btn::after { display: none; }

@media (max-width: 560px) {
  .zustimmung { left: .75rem; right: .75rem; bottom: .75rem; width: auto; padding: 1.25rem; }
  .gruppe { grid-template-columns: minmax(0, 1fr); }
}

/* =========================================================================
   Umbrueche
   ========================================================================= */

/* Die Groessenstaffel des Claims - dieselben Stufen wie auf der
   bisherigen nova-works.de. Am Handy steht er mit 14vw am groessten im
   Verhaeltnis zum Schirm: Dort hat er am wenigsten Platz und muss am
   meisten wirken. */
@media (max-width: 999px) {
  :root { --fs-hero: 10vw; }
}
@media (max-width: 690px) {
  :root { --fs-hero: 14vw; }
}

@media (max-width: 960px) {
  .nav, .masthead__cta { display: none; }

  .slider__spur > .card {
    flex-basis: calc((100vw - 2 * var(--gutter) - .625rem) / 2);
  }

  /* Unter 960 px steht der Kopf wieder ueber dem Bild statt darin: Auf
     einem 390 px breiten Bild braeuchte ein Titel so viel Verlauf, dass
     vom Foto nichts uebrig bliebe. */
  .ref { grid-template-areas: none; gap: 1.25rem; }
  .ref__media, .ref__text, .ref__kopf { grid-area: auto; }
  .ref__kopf {
    position: static;
    max-width: none;
    padding: 0;
    pointer-events: auto;
  }
  .ref__bild::after { display: none; }
  .ref__text { grid-template-columns: 1fr; gap: 0; }
  .ref__text p { max-width: none; }
  /* Untereinander braucht der zweite Kasten Luft nach oben. */
  .ref__unser { margin-top: 1em; }
  /* Am Handy hat das Bild die Breite des Schirms - 16:9 waere dort ein
     schmaler Streifen. Zurueck auf 3:2, das traegt das Motiv besser. */
  .ref__bild { aspect-ratio: 3 / 2; max-height: none; }
  .nav-toggle { display: block; }

  .about__grid,
  .contact__grid { grid-template-columns: 1fr; }


  .hero__foot { grid-template-columns: 1fr; }
}

@media (max-width: 620px) {
  .slider__spur > .card { flex-basis: calc(100vw - 2 * var(--gutter) - 2.5rem); }


  /* Am Handy begrenzt die Schirmbreite, nicht der Geschmack: Wortmarke
     und Claim duerfen zusammen nicht breiter werden als der Platz neben
     der Menuetaste. */
  .masthead__logo { --claim-groesse: .68rem; }
  .masthead__logo .marke__zeichen { width: min(196px, 52vw); }
  .footer__logo { --claim-groesse: .72rem; }
  .footer__logo .marke__zeichen { width: min(200px, 56vw); }

  .form__row { grid-template-columns: 1fr; gap: 0; }
  .detail { padding-left: 1.15rem; }
}

/* =========================================================================
   Ruhiger Modus
   ========================================================================= */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }

  .hero__title span,
  .hero__foot { opacity: 1; transform: none; }
}

/* =========================================================================
   Druck
   ========================================================================= */

@media print {
  .masthead, .nav-drawer, .grain, .hero__media, .footer, .skip-link,
  .zustimmung, .einstellungen { display: none !important; }
  body { background: #fff; color: #000; }
  .legal__inner h3, .legal__inner a { color: #000; }
  .legal__kopf, .angaben, .angaben__zeile { border-color: #999; }

  /* Die AGB werden ausgedruckt und abgeheftet. Auf Weiss muss deshalb der
     ganze Satz schwarz stehen, nicht nur die Ueberschriften - der
     Fliesstext ist auf dem Schirm bewusst gedaempft und waere sonst grau
     bis unlesbar. Dazu die Umbrueche: jeder Teil beginnt auf einer neuen
     Seite, keine Ueberschrift bleibt allein am Fuss stehen. */
  /* Ein Strich fuer alles: Auf Papier ist jede Farbe im Satz schwarz.
     Einzeln aufgezaehlt bliebe zwangslaeufig etwas uebrig - die
     Hervorhebungen etwa tragen ihre eigene Regel mit hoeherem Gewicht.

     Das gilt fuer alle Rechtstexte, nicht nur die AGB: Impressum und
     Datenschutzerklaerung werden genauso ausgedruckt und abgeheftet,
     und ihr Fliesstext ist auf dem Schirm ebenso gedaempft. Vorher
     stand hier nur die AGB-Regel - die beiden anderen Seiten kamen
     grau aus dem Drucker. Gefunden hat das die neue Druckpruefung. */
  .legal,
  .legal * { color: #000 !important; }
  .legal--agb .agb__geltung::before { background: #000; }
  .legal--agb h2,
  .legal--agb .agb__inhalt { border-color: #999; }

  .legal--agb h2 { break-before: page; break-after: avoid; }
  .legal--agb h2:first-of-type { break-before: auto; }
  .legal--agb h3 { break-after: avoid; }
  .legal--agb p,
  .legal--agb li { break-inside: avoid; }
  .legal { padding-block: 0 2rem; }
}
