/* =====================================================================
   index.css — Basis-Layer (global)
   Aufbau:
     1. Reset & Box-Sizing
     2. Design-Tokens (CSS-Variablen) inkl. Dark-Theme
     3. Basis-Elemente
     4. Layout-Helfer (12-Spalten-Grid)
     5. Typografie
     6. Medien (Aspect-Ratio-Boxen)
     7. Header
     8. Footer
     9. Animation / Reduced-Motion
    10. Utilities
   Template-spezifisches Layout liegt in assets/css/templates/*.css
   (per @auto automatisch geladen) → klare Trennung Layout ↔ Inhalt.
   ===================================================================== */

/* 1. Reset --------------------------------------------------------------- */
*,
*::before,
*::after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

/* 1b. Webfont: Bricolage Grotesque (lokal, assets/fonts) ----------------- *
   Standardschrift des Projekts. Pfade relativ zu dieser CSS-Datei. Nur die
   benötigten Schnitte; font-display: swap → Text sofort sichtbar (Fallback),
   Webfont tauscht nach. */
@font-face {
  font-family: "Bricolage Grotesque";
  src: url("../fonts/BricolageGrotesque-Light.ttf") format("truetype");
  font-weight: 300;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Bricolage Grotesque";
  src: url("../fonts/BricolageGrotesque-Regular.ttf") format("truetype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Bricolage Grotesque";
  src: url("../fonts/BricolageGrotesque-Medium.ttf") format("truetype");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Bricolage Grotesque";
  src: url("../fonts/BricolageGrotesque-SemiBold.ttf") format("truetype");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Bricolage Grotesque";
  src: url("../fonts/BricolageGrotesque-Bold.ttf") format("truetype");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Bricolage Grotesque";
  src: url("../fonts/BricolageGrotesque-ExtraBold.ttf") format("truetype");
  font-weight: 800;
  font-style: normal;
  font-display: swap;
}
/* Display-Schrift nur für den Site-Titel (Logo). */
@font-face {
  font-family: "CoralPixels";
  src: url("../fonts/CoralPixels-Regular.ttf") format("truetype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Space Mono";
  src: url("../fonts/SpaceMono-BoldItalic.ttf") format("truetype");
  font-weight: 700;
  font-style: italic;
  font-display: swap;
}

/* 2. Design-Tokens ------------------------------------------------------- */
:root {
  /* Farben (Light) */
  --color-bg: #ffffff;
  --color-text: #111111;
  --color-muted: #767676;
  --color-line: #d6d6d6;
  --color-accent: #111111;

  /* Markenfarbe (Indigo) – für Headline, Buttons, Menü */
  --color-brand: #3826e0;
  --color-on-brand: #ffffff;

  /* Akzentuierter Hintergrund (helles Blau) – Medien-/Akzentflächen */
  --color-bg-accent: #eef0ff;

  /* Layout – zentrale Maße (HIER justieren, gelten site-weit) */
  --padding: clamp(1.25rem, 4vw, 3rem);
  --maxwidth: 115rem;
  --shell-max: 115rem;         /* Default-Breite eines Inhalts-Containers (.shell) */
  --feed-gutter: 5rem;         /* Mindestabstand des gesamten Contents zu den Rändern (Desktop) */
  --feed-text-max: 80rem;      /* EINE max-Breite für alle Texte & Boxen (Feed + Hero-Video ausgenommen, die nutzen --feed-max) */
  --width-narrow: var(--feed-text-max);  /* .shell--narrow (Texte, Header-Pille) folgt --feed-text-max */
  --grid-cols: 12;
  --gutter: clamp(1rem, 3vw, 3rem);
  --measure: 38rem;            /* angenehme Lesebreite */
  --radius: 13px;              /* abgerundete Bildecken */
  --radius-lg: 19px;         /* große Boxen – Hero-Video, Feed-Card, .box, Fotobox, Footer */
  --footer-gap: clamp(1.5rem, 4vw, 2.5rem);  /* Abstand des Glas-Footers zu den Viewport-Rändern */
  /* EIN Wert für den Abstand ZWISCHEN den eingefassten "Boxen" (Hero-Video,
     .box, Fotobox, Footer – nur auf home.php außer Footer) – site-weit hier
     definiert, weil der Footer auf jeder Seite erscheint. Hier ändern wirkt
     einheitlich auf alle. */
  --section-gap: clamp(3rem, 9vh, 6rem);
  /* EIN Wert für „mehrere Boxen/Medien nebeneinander, schmaler Abstand" –
     case-row-Bild-/Video-Paare, Gallery, Mockups (s. .case-row unten) UND
     .testimonial (Bild | Zitat) nutzen alle DIESEN Wert. */
  --media-row-gap: clamp(0.75rem, 2.25vw, 1.5rem);
  /* dezente Flächentönung (Feed + Footer): color-mix macht sie automatisch
     leicht dunkler im Light- und leicht heller im Dark-Mode */
  --surface-tint: color-mix(in srgb, var(--color-text) 5%, var(--color-bg));

  /* Glas-Effekt (Header + Footer). In Chromium per .reduce-glass gedrosselt,
     weil Blink backdrop-filter über bewegtem Video teuer rendert (s. JS). */
  --glass-blur: 19px;
  --glass-blur-footer: 45px;   /* Footer separat (vollbreit → teurer) */
  --glass-saturate: 280%;

  /* Motion */
  --motion-duration: 0.7s;
  --motion-ease: cubic-bezier(0.22, 1, 0.36, 1);

  /* Typo */
  --font-sans: "Bricolage Grotesque", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif,
    "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
  --font-mono: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
}

/* Chromium/Blink (Chrome, Edge, Opera, Brave): Glas günstiger rechnen –
   kleinerer Blur-Radius + weniger Sättigung. Klasse setzt JS (navigator.vendor).
   Safari (WebKit) und Firefox bleiben unangetastet. */
html.reduce-glass {
  --glass-blur: 22px;
  --glass-blur-footer: 12px;   /* Footer noch stärker gedrosselt (große Fläche) */
  --glass-saturate: 120%;
}

/* Dark-Theme: aktiv über <html data-theme="dark"> (gesetzt in header.php) */
:root[data-theme="dark"] {
  --color-bg: #0d0d0d;
  --color-text: #f2f2f2;
  --color-muted: #9a9a9a;
  --color-line: #242424;
  --color-accent: #f2f2f2;
  --color-brand: #8a7bff;   /* helleres Indigo für dunklen Grund */
  --color-on-brand: #111111;
  --color-bg-accent: #15171f;
}

/* 3. Basis-Elemente ------------------------------------------------------ */
html {
  font-family: var(--font-sans);
  color: var(--color-text);
  background: var(--color-bg);
  -webkit-font-smoothing: antialiased;
  /* Theme-Wechsel sanft – außer bei Reduced Motion (s. u.) */
  transition: background-color 0.3s ease, color 0.3s ease;
  /* Full-bleed-Elemente (z. B. .feed-slider) dürfen bis zum Viewport-Rand
     reichen, ohne einen horizontalen Scrollbalken auszulösen. `clip` (statt
     hidden) erzeugt keinen Scroll-Container, sticky/fixed bleiben intakt. */
  overflow-x: clip;
}
/* Anker-Links (Nav → #angebot/#box/#projects/#testimonials): sanftes Scrollen
   NUR bei einem Sprung innerhalb derselben Seite – ein Link von /about auf
   /#projects lädt ohnehin neu und springt beim Laden ohnehin sofort, das
   ist Browser-Standardverhalten und bleibt unverändert. Wie überall auf der
   Seite: nur aktiv, wenn Bewegung erlaubt ist (OS-Präferenz + Motion-Toggle,
   data-motion="reduced" – s. initReveal/motionAllowed in index.js). */
@media (prefers-reduced-motion: no-preference) {
  :root:not([data-motion="reduced"]) {
    scroll-behavior: smooth;
  }
}
body {
  /* Voller Viewport-Wrapper: Breite & horizontaler Abstand kommen jetzt aus
     .shell (Container-System), nicht mehr vom body. So lassen sich Bereiche
     unterschiedlich breit setzen und Hintergründe full-bleed darstellen. */
  line-height: 1.5;
}

img {
  display: block;
  width: 100%;
  height: auto;
}
li {
  list-style: none;
}
a {
  color: currentColor;
  text-decoration: none;
}
button {
  font: inherit;
  background: none;
  border: 0;
  color: currentColor;
  cursor: pointer;
}
strong,
b {
  font-weight: 600;
}
:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 3px;
}

/* Skip-Link (Accessibility) */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--color-text);
  color: var(--color-bg);
  padding: 0.75rem 1rem;
  z-index: 100;
}
.skip-link:focus {
  left: 1rem;
  top: 1rem;
}

/* 4. Layout-Helfer: 12-Spalten-Grid ------------------------------------- */
.grid {
  --columns: 12;
  --gutter: 3rem;
  display: grid;
  gap: var(--gutter);
  grid-template-columns: 1fr;
}
.grid > .column {
  margin-bottom: var(--gutter);
}

/* 4b. Container / Shell -------------------------------------------------- *
   Jeder Inhaltsbereich liegt in einer .shell: zentriert, mit horizontalem
   Padding und einer pro Bereich anpassbaren max-width (--shell-max).
   Neue Breite = eine Zeile (Variable überschreiben). Da der body voll breit
   ist, spannt ein Bereich OHNE .shell automatisch die volle Viewport-Breite
   (→ Full-Bleed-Hintergründe). */
.shell {
  /* Flush zum Mindestrand – gleiche Kante wie Header-Pille & Hero-Video, damit
     ALLE Inhalte bündig starten (der Rand ist Margin, kein Innen-Padding). */
  width: min(100% - 2 * var(--feed-gutter), var(--shell-max));
  margin-inline: auto;
}
.shell--wide   { --shell-max: 100rem; }  /* z. B. breite Raster */
.shell--narrow { --shell-max: var(--width-narrow); }  /* Feed, Hero-Text, spätere Textbereiche */
/* Schmale Screens: 5rem Rand würde die Inhaltsbreite auffressen → weniger Rand. */
@media (max-width: 60rem) { :root { --feed-gutter: 1.5rem; } }

/* 5. Typografie ---------------------------------------------------------- */
h1, h2, h3, h4, h5, h6 {
  font-size: inherit;
  font-weight: 200;     /* Überschriften extra bold */
  line-height: inherit;
}
.text {
  line-height: 1.6;
  max-width: var(--measure);
}
.text a {
  text-decoration: underline;
  text-underline-offset: 0.15em;
}
.text :first-child { margin-top: 0; }
.text :last-child { margin-bottom: 0; }
.text p,
.text ul,
.text ol {
  margin-bottom: 1.25rem;
}
.text ul,
.text ol {
  margin-left: 1.1rem;
}
.text ul > li { list-style: disc; }
.text ol > li { list-style: decimal; }
.text h2 {
  font-size: 1.25rem;
  font-weight: 600;
  margin: 2rem 0 0.75rem;
}
.text h3 {
  font-weight: 600;
  margin: 1.5rem 0 0.5rem;
}

.color-muted { color: var(--color-muted); }

/* Pfeil-Link: Links mit vorangestelltem ↳ (als ::before) bekommen die
   Panel-Akzentfarbe. Einfach die Klasse .arrow-link an den <a> hängen –
   der Pfeil wird per CSS gesetzt (kein <span> im Markup nötig). */
.arrow-link {
  color: var(--color-cta);
  font-weight: 600;
}
.arrow-link::before {
  content: "↳";   /* dekorativer Pfeil (Pseudo-Element, nicht im DOM) */
  margin-right: 0.25rem;
}
.arrow-link:hover {
  text-decoration: underline;
  text-underline-offset: 0.15em;
}

/* Große Standalone-Headline (genutzt u. a. vom intro-Snippet / About-Seite) */
.h1 {
  font-size: clamp(1.75rem, 4vw, 2.5rem);
  font-weight: 800;
  line-height: 1.15;
  margin-bottom: 2rem;
}

/* 6. Medien: Aspect-Ratio-Boxen (--w / --h) ----------------------------- */
.video,
.img {
  position: relative;
  display: block;
  --w: 1;
  --h: 1;
  padding-bottom: calc(100% / var(--w) * var(--h));
  background: var(--color-bg-accent);
  overflow: hidden;
  border-radius: var(--radius);
}
.img img,
.video iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border: 0;
}
.img[data-contain] img { object-fit: contain; }
.img-caption,
.video-caption {
  padding-top: 0.75rem;
  color: var(--color-muted);
}

/* 6b. Slider (geteilt: Feed + Case-Study) ------------------------------- *
   Ein-Bild-Fenster: genau EIN Slide (100 % Breite) ist sichtbar, mittig im
   Fenster. Die Spur liegt in Inhaltsbreite (.slider__viewport) und bricht NICHT
   mehr full-bleed aus – die Nachbar-Slides werden am Fensterrand abgeschnitten
   und erscheinen nur während des Slidens. */
.slider {
  display: flex;
  gap: var(--gutter);
  width: 100%;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;          /* Firefox */
}
.slider::-webkit-scrollbar { display: none; }   /* WebKit */
.slider__slide { scroll-snap-align: start; flex: none; }
.slider__dots {
  display: flex;
  gap: 0.5rem;
  margin-top: 1rem;
}
.slider__dot {
  width: 0.55rem;
  height: 0.55rem;
  border-radius: 50%;
  background: var(--color-line);
  transition: background-color 0.2s ease, transform 0.2s ease;
}
.slider__dot:hover { transform: scale(1.2); }
.slider__dot.is-active { background: var(--color-brand); }

/* Viewport = das Fenster (Inhaltsbreite) + Positionskontext für die Pfeil-
   Buttons. Genau ein Slide ist sichtbar; die scrollende .slider-Spur darin
   schneidet die Nachbar-Slides am Fensterrand ab. */
.slider__viewport { position: relative; }

/* Runde Pfeil-Buttons im Glas-Design der Header-Pille (s. .site-header::before).
   Standardmäßig versteckt; erst aktiv, wenn der Endlos-Slider per JS bereit ist
   ([data-slider].is-ready, s. initSliders). */
[data-slider]:not(.is-ready) .slider__nav { display: none; }
.slider__nav {
  position: absolute;
  top: 50%;
  z-index: 5;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 3rem;
  height: 3rem;
  border-radius: 999px;
  color: var(--color-text);
  /* Button-Mitte sitzt exakt auf der Fensterkante → 50 % über dem Bild,
     50 % außerhalb. --nav-x verschiebt je Seite um die halbe Buttonbreite. */
  transform: translate(var(--nav-x, 0), -50%);
  transition: transform 0.2s var(--motion-ease), opacity 0.2s ease;
}
.slider__nav svg { width: 1.25rem; height: 1.25rem; }
.slider__nav--prev { inset-inline-start: 0; --nav-x: -50%; }
.slider__nav--next { inset-inline-end: 0;   --nav-x: 50%; }
.slider__nav:hover  { transform: translate(var(--nav-x, 0), -50%) scale(1.06); }
.slider__nav:active { transform: translate(var(--nav-x, 0), -50%) scale(0.96); }
/* Glas (Hintergrund + Blur + Border) auf ::before – identisch zur Header-Pille. */
.slider__nav::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  background: color-mix(in srgb, var(--color-header) 35%, transparent);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  border: 1px solid rgba(255, 255, 255, 0.2);
  box-shadow:
    0 6px 24px rgba(0, 0, 0, 0.08),
    inset 0 1px 1px rgba(255, 255, 255, 0.1);
}
:root[data-theme="dark"] .slider__nav::before {
  background: rgba(12, 16, 28, 0.78);
  border-color: rgba(255, 255, 255, 0.2);
  box-shadow:
    0 10px 30px rgba(0, 0, 0, 0.26),
    inset 0 1px 1px rgba(255, 255, 255, 0.1);
}

/* 6c. Badge / Tag (Pills, geteilt) ------------------------------------- */
.badge {
  display: inline-block;
  padding: 0.35rem 0.95rem;
  border: 1px solid var(--color-muted);
  border-radius: 2rem;
  font-size: 0.8rem;
  color: var(--color-text);
}

/* 6d. Modularer Inhalt (geteilt: project.php „Inhalt der Fallstudie" UND
   about.php) ------------------------------------------------------------ *
   EIN System für beide Seiten: Blueprint-Feld blueprints/fields/
   casestudylayout.yml, gerendert über site/snippets/case-body.php
   (.case__body > .case-row > .column > Block-Snippets aus
   site/snippets/blocks/). Hier geändert wirkt automatisch auf beiden Seiten –
   nichts davon in project.css/about.css duplizieren. */
.case__body {
  display: flex;
  flex-direction: column;
  gap: clamp(3rem, 8vh, 7rem);
}
/* Eine Layout-Reihe = 12er-Grid; Spaltenbreite kommt aus --columns.
   --media-row-gap (site-weit in :root, s. oben) sorgt für denselben schmalen
   Abstand bei case-row-Bild-/Video-Paaren, Gallery, Mockups UND .testimonial. */
.case-row {
  --gutter: var(--gutter);
}
.case-row .column { display: flex; flex-direction: column; gap: 1.5rem; }
.case-block { margin: 0; }
/* abgerundete Bildecken durchgängig (wie Referenz) */
.case-block img,
.mockups__item img,
.slider__slide img { border-radius: var(--radius); }
/* Eigener Video-Upload (natives <video>, s. blocks/video.php): eigene Größe
   wie ein Bild – kein .video-Aspect-Ratio-Wrapper nötig (der ist nur für
   Iframe-Embeds ohne Eigengröße). Volle Breite, Höhe ergibt sich von selbst. */
.case-block--video video {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--radius);
}

/* Bild-/Video-Blöcke, die NEBENEINANDER in einer Reihe liegen (Spalte hat
   Geschwister UND ist selbst nur mit einem Bild/Video belegt): schmaler
   Abstand statt des großen Standard-Gutters, alle Medien der Reihe auf
   gleiche Höhe. Die Grid-Spalte streckt sich per Default (align-items:
   stretch) auf die Höhe der höchsten Reihen-Nachbarin; height:100% gibt das
   an das Medium weiter, object-fit:cover schneidet ohne Verzerrung zu –
   überschreibt damit bewusst ein individuell gesetztes Seitenverhältnis
   (--ratio am Block), DAS ist genau der Zweck: gleiche Zeilenhöhe. Bei
   Video-Embeds per URL (iframe) greift object-fit nicht in jedem Browser
   zuverlässig; das Video füllt die Zeile dann trotzdem (kein Crop, kein Bug). */
.case-row:has(> .column:not(:only-child) > .case-block--image:only-child),
.case-row:has(> .column:not(:only-child) > .case-block--video:only-child) {
  --gutter: var(--media-row-gap);
}
.case-row .column:not(:only-child) > .case-block--image:only-child,
.case-row .column:not(:only-child) > .case-block--video:only-child {
  height: 100%;
}
/* Bild-Block: Bild steckt in einem <a> (Lightbox-Link, s. snippets/image.php).
   <a> ist standardmäßig inline und würde die Höhe nicht sauber weiterreichen –
   explizit auf Block + volle Höhe setzen statt uns auf Inline-Prozent-Edge-
   cases zu verlassen. */
.case-row .column:not(:only-child) > .case-block--image:only-child a {
  display: block;
  height: 100%;
}
.case-row .column:not(:only-child) > .case-block--image:only-child img,
.case-row .column:not(:only-child) > .case-block--video:only-child video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Textabschnitt: zentriert + schmale Lesebreite NUR bei voller Breite;
   in mehrspaltigen Reihen füllt der Text seine Spalte. */
.case-block--text {
  max-width: var(--measure);
  margin-inline: auto;
}
.case-row .column:not(:only-child) .case-block--text {
  max-width: none;
  margin-inline: 0;
}
/* Sektions-Intro: Überschrift links, Text rechts (Vorlage) */
.sectionintro .column { margin-bottom: 0; }
.sectionintro__headline {
  font-size: clamp(1.5rem, 3vw, 2.5rem);
  font-weight: 800;
  line-height: 1.1;
  letter-spacing: -0.01em;
}
.sectionintro__body {
  font-size: 1.0625rem;
  line-height: 1.6;
  color: var(--color-muted);
}

.case-block__headline {
  font-size: clamp(1.5rem, 3vw, 2.25rem);
  font-weight: 800;
  line-height: 1.15;
  margin-bottom: 1rem;
}
.case-block__body { line-height: 1.6; }
.case-block__caption {
  padding-top: 0.75rem;
  color: var(--color-muted);
}

/* Galerie: responsives Raster, schmaler Abstand, alle Bilder einer Zeile auf
   fester, gleicher Höhe (object-fit: cover) – unabhängig vom individuell am
   Block gesetzten Seitenverhältnis (s. Kommentar bei .case-row oben). */
.case-block--gallery ul {
  display: grid;
  gap: var(--media-row-gap);
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  grid-auto-rows: clamp(12rem, 30vw, 22rem);
}
.case-block--gallery li { line-height: 0; height: 100%; }
.case-block--gallery li a { display: block; height: 100%; }
.case-block--gallery li img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Mockups nebeneinander (Subgrid): dieselbe Zeilen-Logik wie Gallery – schmaler
   Abstand (--media-row-gap statt --gutter) + gleiche Höhe per object-fit:cover.
   .mockups__item ist als Grid-Item automatisch auf die Zeilenhöhe gestreckt
   (Grid-Default align-items:stretch); nur das <img> braucht height:100%, um
   das an sich weiterzugeben (kein <a>-Wrapper wie beim Bild-Block). */
.mockups {
  display: grid;
  gap: var(--media-row-gap);
  grid-template-columns: 1fr;
}
.mockups__item { line-height: 0; }
.mockups__item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
@media screen and (min-width: 48rem) {
  .mockups { grid-template-columns: repeat(var(--count, 2), 1fr); }
}

/* Slider: Basis-Komponente in 6b. oben; hier nur Slide-Größe.
   Ein-Bild-Fenster: jeder Slide füllt das Fenster (= Inhaltsbreite) komplett,
   sodass immer genau ein Bild mittig sichtbar ist. */
.case-block--slider .slider__slide {
  flex-basis: 100%;
  line-height: 0;
}

/* Pull-Quote */
.case-block--quote {
  max-width: 40rem;
  margin-inline: auto;
  text-align: center;
}
.pullquote {
  font-size: clamp(1.5rem, 3.5vw, 2.25rem);
  line-height: 1.25;
  font-weight: 500;
}
.pullquote__cite {
  margin-top: 1rem;
  color: var(--color-muted);
  font-size: 1rem;
}

/* 7. Header: zentrierte „Liquid Glass"-Pille (schwebt über dem Inhalt) -- *
   Logo links, rechts Inline-Nav + Dark-Mode-Icon + Kontakt-Button. Auf dem
   Smartphone wandert der Kontakt-Button als FAB nach unten rechts (s. u.). */
.site-header {
  position: fixed;
  top: clamp(0.75rem, 2vw, 1.25rem);
  left: 0;
  right: 0;
  margin-inline: auto;
  width: min(70% - 2 * var(--padding), var(--maxwidth) - 2 * var(--padding));
  z-index: 70;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--gutter);
  padding: .8rem 1.9rem .8rem 3.9rem;

  /* Auto-Hide beim Scrollen: bewusst `top` statt `transform` animiert. Ein
     transform (auch nur als `transition: transform` angekündigt) hebt das
     Element in Firefox auf eine eigene Ebene und nimmt dann das Hero-<video>
     aus dem Backdrop → kein Blur über dem Video. `top` ist davon nicht
     betroffen. Richtung schaltet JS über .is-hidden (s. initHeaderHide). */
  transition: top 0.35s var(--motion-ease);
}
/* Hover: leichte Vergrößerung (Apple-„Liquid Glass"-Anmutung). Nutzt bewusst
   transform/scale trotz des Firefox-Risikos oben (Hero-Video-Blur kann
   während des Hovers kurz aussetzen – akzeptiert, weil der Effekt nur den
   kurzen Hover-Moment betrifft). Beim Verlassen läuft dieselbe Kurve
   rückwärts (site-header-unbounce = gespiegelte Keyframes von site-header-
   bounce), gesteuert über die Klasse .is-leaving (initHeaderBounce in
   index.js setzt/entfernt sie bei mouseenter/mouseleave/animationend) – ein
   reines :not(:hover) + animation-direction:reverse hätte beim ersten
   Seitenaufruf (ohne je gehovert zu haben) sofort auf den Endzustand
   gesprungen, daher der JS-Trigger. */
@keyframes site-header-bounce {
  0%   { transform: scale(1); }
  100% { transform: scale(1.0051); }
}
@keyframes site-header-unbounce {
  0%   { transform: scale(1.0051); }
  100% { transform: scale(1); }
}
@media (prefers-reduced-motion: no-preference) {
  :root:not([data-motion="reduced"]) .site-header {
    transition: top 0.35s var(--motion-ease);
  }
  /* will-change nur hier (nicht permanent auf .site-header): promotet die
     Ebene nur für die kurze Dauer der scale-Animation, statt die Firefox-
     Video-Blur-Ausnahme oben dauerhaft auszulösen. */
  :root:not([data-motion="reduced"]) .site-header:hover {
    will-change: transform;
    animation: site-header-bounce 0.26s ease-in-out forwards;
  }
  :root:not([data-motion="reduced"]) .site-header.is-leaving {
    will-change: transform;
    animation: site-header-unbounce 0.3s ease-in-out forwards;
  }
}
/* Glas (Hintergrund + Blur + Border) auf ::before – sauber vom Layout getrennt
   und konsistent mit dem Footer. */
.site-header::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: 999px;
  background: color-mix(in srgb, var(--color-header) 90%, transparent);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  border: 1px solid rgba(255, 255, 255, 0.2);
  box-shadow:
    0 6px 24px rgba(0, 0, 0, 0.08),
    inset 0 1px 1px rgba(255, 255, 255, 0.1);
}
/* nach unten gescrollt → Pille nach oben aus dem Bild schieben (top statt transform) */
.site-header.is-hidden { top: -8rem; }
:root[data-theme="dark"] .site-header::before {
  background: rgba(12, 16, 28, 0.78);
  border-color: rgba(255, 255, 255, 0.2);
  box-shadow:
    0 10px 30px rgba(0, 0, 0, 0.26),
    inset 0 1px 1px rgba(255, 255, 255, 0.1);
}
.site-header {
  font-size: 1.1rem;
  font-weight: 300;
}

.site-header__logo {
  font-family: "Space Mono", monospace;   /* Site-Titel */
  font-weight: 700;
  font-style: italic;
  font-size: clamp(0.9rem, 4vw, 1.7rem);
  letter-spacing: 0;
  color: var(--color-brand);
   text-transform: uppercase;
}
.site-header__actions {
  display: flex;
  align-items: center;
  gap: 1.25rem;
}

/* Desktop-Inline-Nav (Projekte, Über mich) */
.site-header__nav {
  display: flex;
  align-items: center;
  gap: 1.75rem;
}
.site-header__nav a {
  color: var(--color-brand);
  font-weight: 600;
}
.site-header__nav a:hover,
.site-header__nav a[aria-current] {
  text-decoration: underline;
  text-underline-offset: 0.2em;
}

/* Inhalt unter der schwebenden Header-Pille beginnen lassen */
.main {
  padding-top: clamp(5.5rem, 9vw, 7rem);
  /* Footer liegt jetzt im normalen Fluss (kein fixiertes Glas-Panel mehr) →
     keine Höhen-Reservierung mehr nötig. */
  padding-bottom: 0;
}

/* === Button-Komponente (Pillen) ===================================== *
   „Blueprint" für alle abgerundeten Buttons – Größe / Form / Typografie sind
   vom Header-Kontaktbutton abgeleitet und liegen NUR hier. Farben kommen
   bewusst NICHT von hier, sondern lokal aus der jeweiligen Button-Klasse
   (.cta, .hero__btn, .box__cta …).
   Neuen Button anlegen: <a class="btn deine-klasse"> + lokale Farb-Regel. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: .65rem 1.4rem;
  border-radius: 999px;
  font-weight: 600;
  line-height: 1.2;
  transition: transform 0.45s cubic-bezier(0.34, 2.8, 0.64, 1),
    opacity 0.2s ease, background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease;
}

/* Kontakt-Button (Akzentfarbe) – nur Farben, Geometrie aus .btn.
   Hover: ein kreisförmiger, aufhellender Layer (weiß, 20 % Deckkraft =
   80 % Transparenz) wächst vom linken Rand aus und füllt beim Hovern die
   ganze Pille – überall dort, wo .cta verwendet wird (Header-, FAB-, Footer-
   und Box-Kontakt-Button, s. site-header__contact/fab-contact/
   site-footer__cta-link/box__cta), automatisch dieselbe Animation, weil sie
   an der geteilten Klasse .cta hängt statt an jedem Button einzeln. */
.cta {
  position: relative;
  isolation: isolate;   /* hält den ::before-Layer sicher innerhalb der Pille */
  overflow: hidden;     /* clippt den wachsenden Kreis an die Pillenform */
  background: var(--color-cta);      /* Panel-Akzentfarbe */
  color: var(--color-on-cta);        /* Panel-Schriftfarbe auf dem Button (Default weiß) */
}
.cta::before {
  content: "";
  position: absolute;
  /* Startpunkt unten mittig → wächst gerade Richtung oben */
  top: 100%;
  left: 50%;
  z-index: -1;
  width: 2rem;
  height: 2rem;
  margin: -1rem 0 0 -1rem;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.109);
  /* Ruhezustand: halb so groß wie im Hover UND ein Stück weiter unten
     (außerhalb der Pille) – schiebt sich beim Hovern zugleich nach oben
     in den Button UND wächst auf die volle Größe. */
  transform: scale(12.5) translateY(1rem);
  pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
  /* Raus-Animation (Hover-Ende): schneller … */
  :root:not([data-motion="reduced"]) .cta::before {
    transition: transform 0.5s var(--motion-ease);
  }
  /* … Rein-Animation (Hover-Start): langsamer. Eigene Transition auf :hover,
     weil der Browser beim Wechsel jeweils die Transition der ZIEL-Regel nimmt. */
  :root:not([data-motion="reduced"]) .cta:hover::before {
    transition: transform 2.4s var(--motion-ease);
  }
}
.cta:hover::before { transform: scale(25) translateY(0); }
/* gestrichelte Variante (Bestand) */
.cta--dashed {
  background: transparent;
  color: var(--color-text);
  border: 1.5px dashed var(--color-text);
}
.cta--dashed:hover {
  background: var(--color-brand);
  color: var(--color-on-brand);
  border-color: var(--color-brand);
  opacity: 1;
}

/* Dark-Mode-Icon: Sonne ↔ Mond, animiert über :root[data-theme="dark"] */
.theme-toggle {
  flex: none;
  width: 2.5rem;
  height: 2.5rem;
  display: grid;
  place-items: center;
  color: var(--color-brand);
  border-radius: 50%;
  transition: transform 0.45s cubic-bezier(0.34, 2.8, 0.64, 1), background-color 0.2s ease;
}
.theme-toggle:hover { background: color-mix(in srgb, var(--color-text) 10%, transparent); }
.theme-toggle__svg { width: 1.7rem; height: 1.7rem; overflow: visible; }
.theme-toggle__core,
.theme-toggle__rays,
.theme-toggle__moon,
.theme-toggle__moon-outline {
  transform-box: fill-box;
  transform-origin: center;
  transition: transform 0.4s var(--motion-ease), opacity 0.3s ease;
}
.theme-toggle__moon { transform: translateX(-7px); }
.theme-toggle__rays { opacity: 0; transform: scale(0.5); }
:root[data-theme="dark"] .theme-toggle__moon { transform: translateX(0); }
:root[data-theme="dark"] .theme-toggle__rays { opacity: 1; transform: scale(1); }
:root[data-theme="dark"] .theme-toggle__core { transform: scale(1.08); }
:root[data-theme="dark"] .theme-toggle__moon-outline { opacity: 0; }

/* Kein eigenes Hover mehr auf .site-header__contact – der Button trägt
   bereits .btn.cta und teilt sich damit automatisch dieselbe Hover-Animation
   (Opacity-Fade, s. .cta:hover oben) mit dem Footer-Button
   (.site-footer__cta-link, ebenfalls .btn.cta). Kein Vergrößern mehr. */

/* Responsive ----------------------------------------------------------- *
   Smartphone (mobile-first): die Pille zeigt dieselben Punkte wie ab Tablet
   (Inline-Nav + Theme-Toggle) und nutzt dafür nahezu die volle Viewport-
   Breite. Der Kontakt-Button löst sich aus der Leiste und schwebt als FAB
   unten rechts (daumenfreundlich). Ab 40rem (kein Handy mehr) gilt das
   Desktop-Design: Kontakt-Button wieder in der Pille (s. Media-Queries). */
.site-header__nav     { display: flex; }
.theme-toggle         { display: grid; }
.site-header__contact { display: none; }    /* in der Pille erst ab Tablet */

/* Mobile: breite Pille + engere Abstände, damit Logo + Nav + Toggle passen.
   Vertikales Padding bewusst großzügiger (höhere, besser greifbare Leiste). */
.site-header {
  /* seitlicher Abstand zum Viewport halbiert (padding/2 je Seite) */
  width: calc(100% - var(--padding));
  gap: 0.6rem;
  padding: 0.5rem 1rem;
  /* Ohne Kontaktbutton (FAB statt Pille) wäre die Leiste dünner als ab 40rem.
     min-height = Pillenhöhe der Desktop-Bar (halbe = 2.25rem, s. --hero-top) →
     gleich dick wie die Desktop-Variante mit Kontaktbutton. */
  min-height: 4.5rem;
}
.site-header__nav     { gap: 1.1rem; }
.site-header__actions { gap: 0.85rem; }

/* Kontakt-Button als schwebender FAB unten rechts (Markup außerhalb des
   Headers, damit position:fixed am Viewport hängt – s. header.php). */
.fab-contact {
  position: fixed;
  /* rechter Abstand = seitlicher Abstand der Header-Bar (padding/2) → bündig */
  right: calc(var(--padding) / 2);
  bottom: clamp(1rem, 5vw, 1.5rem);
  z-index: 75;
  padding: 1.25rem 1.6rem;
  box-shadow: 0 10px 28px rgba(0, 0, 0, 0.22);
}
.fab-contact:hover { transform: scale(1.06); }

/* Ab 40rem (640px) ist es kein Handy-Format mehr → Desktop-Design: Kontakt-
   Button zurück in die Pille, kein FAB. Die Pille nutzt hier zunächst nahezu
   die volle Breite, damit Logo + Nav + Toggle + Button sicher passen – das
   deckt zugleich das Tablet im Hochkantformat ab. */
@media (min-width: 40rem) {
  .site-header {
    /* seitlicher Abstand zum Viewport halbiert (padding/2 je Seite) */
    width: calc(100% - var(--padding));
    gap: var(--gutter);
    padding: .9rem 1.3rem .9rem 2.3rem;
  }
  .site-header__nav     { gap: 1.75rem; }
  .site-header__actions { gap: 1.25rem; }
  .site-header__contact { display: inline-flex; }
  .fab-contact { display: none; }           /* FAB nur im Handy-Format (< 40rem) */
}

/* Ab 64rem (Desktop, Tablet quer): zentrierte Pille mit derselben max-width wie
   die Text-Container (.shell--narrow → --width-narrow). Auf schmaleren Viewports
   bündig zum Seitenabstand (100 % minus --padding je Seite, kein Überlauf). */
@media (min-width: 64rem) {
  .site-header {
    width: min(100% - 2 * var(--feed-gutter), var(--width-narrow));
  }
}

/* 8. Footer -------------------------------------------------------------- *
   Footer = eigenständiger Block im normalen Fluss (wie ein Article): 90vw breit
   und zentriert wie das Hero-Video, abgerundet, mit SOLIDER (nicht mehr
   transluzenter) Fläche. Reveal beim Scrollen wie die Projekte (s. Abschnitt 9
   + initReveal in index.js). */
.site-footer {
  /* Standardfarben: automatisch invertierte Fläche (Light-Theme aktiv →
     Dark-Farben, s. :root[data-theme="dark"] unten für die Umkehr). Panel-Tab
     „Footer-Farben" (designColorStyle() in footer.php) überschreibt
     --footer-bg/--footer-fg per Inline-Style, wenn „Standardfarben verwenden"
     ausgeschaltet ist – feste Farbe in beiden Themes. */
  --footer-bg: var(--color-text);
  --footer-fg: var(--color-bg);

  /* Text/Links/Border auf der Fläche aus currentColor ableiten. */
  --color-brand: currentColor;                                  /* Links in Textfarbe */
  --color-cta: currentColor;                                    /* Pfeil-Links hier lesbar statt Akzent */
  --color-muted: color-mix(in srgb, currentColor 60%, transparent);
  --color-line: color-mix(in srgb, currentColor 22%, transparent);

  /* gleiche Maße wie das Hero-Video: 90vw, zentriert, gleiche Rundung.
     Insgesamt höher als zuvor (großzügigeres padding-block + mehr interner
     Rhythmus unten) – bewusst mehr Präsenz am Seitenende. Abstand nach oben
     etwas kleiner als --section-gap (Footer darf näher an den Feed rücken
     als die anderen Boxen), Abstand nach unten bleibt --footer-gap (eigener
     Wert für die Nähe zum Viewport-Rand, nicht Teil der Box-zu-Box-Reihe). */
  position: relative;
  width: 90vw;
  margin: calc(var(--section-gap) * 0.5) auto var(--footer-gap);
  padding-block: clamp(5.25rem, 9.5vh, 8rem);
  border-radius: var(--radius-lg);

  /* solide Fläche (nicht mehr transparent/Glas) */
  background: var(--footer-bg);
  color: var(--footer-fg);
  box-shadow: 0 8px 30px rgba(0, 0, 0, 0.18);
}

/* Optionales Hintergrundbild (Panel-Tab „Footer-Farben" → footerImage), s.
   footer.php für --footer-image/-focus/-overlay-color/-opacity. Fokuspunkt
   wie bei der Fotobox. Die Farb-Überlagerung (::before, wie .offer--bg/
   .testimonials--bg) sorgt für Lesbarkeit; .shell bekommt einen eigenen
   Stapelkontext, damit der Inhalt über der Überlagerung bleibt. */
.site-footer--image {
  background-image: var(--footer-image);
  background-size: cover;
  background-position: var(--footer-focus, center);
}
.site-footer--image::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  border-radius: inherit;
  background: color-mix(in srgb, var(--footer-overlay-color, transparent) var(--footer-overlay-opacity, 0%), transparent);
  pointer-events: none;
}
.site-footer--image > .shell {
  position: relative;
  z-index: 1;
}

/* FAB (Mobile) weicht am Seitenende, wenn der Footer erreicht ist (JS:
   body.footer-open via initFooterReveal) → kein Überlappen. */
body.footer-open .fab-contact {
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease;
}

/* Oben: Marke + Notiz links, Link-Spalten rechts (wie footer16_top-wrapper
   der Referenz thekids.eu – ohne Logo-Bild/Newsletter, die gibt's im Panel
   nicht). Auf Mobile untereinander. */
.site-footer__top {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(2.5rem, 6vh, 3.5rem);
}
.site-footer__brand {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  max-width: 26rem;
}
.site-footer__logo {
  font-family: "Space Mono", monospace;
  font-weight: 700;
  font-style: italic;
  font-size: clamp(1.1rem, 3vw, 1.5rem);
  text-transform: uppercase;
}
.site-footer__note { font-size: 0.95rem; line-height: 1.6; }

.site-footer__menu {
  display: flex;
  flex-wrap: wrap;
  gap: 2.5rem 4rem;
}
.site-footer__col {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  min-width: 8rem;
}
.site-footer__col-title {
  font-weight: 600;
  font-size: 0.85rem;
}
.site-footer__link-list {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  color: var(--color-muted);
}
.site-footer__link-list a:hover { text-decoration: underline; }

@media (min-width: 48rem) {
  .site-footer__top {
    grid-template-columns: 1.2fr 1fr;
    align-items: start;
  }
  /* Der Block "Seiten"/"Folge uns" als Ganzes bündig zum rechten Rand –
     gleicher Abstand wie die Marke links (beide innerhalb derselben .shell).
     Die Listen selbst bleiben linksbündig (nur der Container rückt nach
     rechts, nicht der Text darin). */
  .site-footer__menu { justify-content: flex-end; }
}

/* E-Mail-Headline (wie „Let's create together?" der Referenz) – nutzt die
   vorhandenen Felder Kontakt-E-Mail + Angebot-Anfrage-Label statt neuer,
   nicht vorhandener Panel-Inhalte. Sitzt jetzt IN der .site-footer__brand-
   Spalte (Logo/Notiz/CTA gestapelt); Abstand nach oben statt der früheren
   Section-Innenabstände. */
.site-footer__cta {
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
  margin-top: 0.25rem;
}
/* Gleiches Design wie der Kontakt-Button im Header (.btn.cta). Standard:
   Button-Fläche = Schriftfarbe des Footers (--footer-fg), Button-Schrift =
   Hintergrundfarbe des Footers (--footer-bg) – ein "Negativ" der Fläche, folgt
   automatisch der Standard-Invertierung UND einer im Panel eingestellten
   Footer-Farbe. --footer-btn-bg/-text (Panel „Footer-Farben" → Button-Farbe,
   footer.php) überschreiben das optional individuell; leer = obiges Negativ
   bleibt aktiv (var(...,Fallback)). */
.site-footer__cta-link {
  align-self: flex-start;
  margin-top: 1rem;
  --color-cta: var(--footer-btn-bg, var(--footer-fg));
  --color-on-cta: var(--footer-btn-text, var(--footer-bg));
}
.site-footer__email {
  font-size: clamp(1.125rem, 3.5vw, 2.5rem);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.05;
}
.site-footer__email:hover { color: var(--color-brand); }

.site-footer__bottom {
  padding-top: clamp(1.5rem, 4vh, 2rem);
}
.site-footer__copy {
  color: var(--color-muted);
  font-size: 0.85rem;
}

/* 9. Animation / Reduced-Motion ----------------------------------------
   Wichtig: Der versteckte Startzustand wird NUR aktiv, wenn JS Bewegung
   freischaltet und die Klasse `reveal-enabled` auf <html> setzt (siehe
   index.js). Ohne JS oder bei Reduced Motion bleibt alles sofort sichtbar
   → Progressive Enhancement, niemals „leerer Bildschirm".
   ---------------------------------------------------------------------- */
html.reveal-enabled [data-animate] {
  opacity: 0;
  transform: translateY(2rem);
  transition:
    opacity var(--motion-duration) var(--motion-ease),
    transform var(--motion-duration) var(--motion-ease);
  will-change: opacity, transform;
}
html.reveal-enabled [data-animate].is-visible {
  opacity: 1;
  transform: none;
}
/* Projekte: von unten einschieben und von 80 % auf 100 % skalieren (Fallback
   ohne Scroll-Driven-Animations; die scrubbende Variante folgt weiter unten).
   Deutlich langsamer als der Standard-Reveal (--motion-duration · 2.5). */
html.reveal-enabled .feed-title[data-animate],
html.reveal-enabled .offer__item[data-animate],
html.reveal-enabled .site-footer[data-animate] {
  transform: translateY(4rem) scale(0.8);
  transition:
    opacity calc(var(--motion-duration) * 2.5) var(--motion-ease),
    transform calc(var(--motion-duration) * 2.5) var(--motion-ease);
}
html.reveal-enabled .feed-title[data-animate].is-visible,
html.reveal-enabled .offer__item[data-animate].is-visible,
html.reveal-enabled .site-footer[data-animate].is-visible {
  transform: none;
}
/* gestaffelte Kinder (Index via --i im JS gesetzt) */
html.reveal-enabled [data-animate-stagger] > [data-animate] {
  transition-delay: calc(var(--i, 0) * 70ms);
}

/* Scroll-getriebene „scrubbende" Reveal-Animation der einzelnen Projekte
   (Feeling wie cuberto.com): Statt eines einmaligen Übergangs ist die Bewegung
   direkt an die Scroll-Position gekoppelt → butterweich, läuft beim Hoch-/
   Runterscrollen mit. Nur wenn der Browser CSS Scroll-Driven Animations kennt
   und der Nutzer keine reduzierte Bewegung wünscht; sonst bleibt der
   IntersectionObserver-Reveal oben als Fallback aktiv. */
@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {
    html.reveal-enabled .feed-title,
    html.reveal-enabled .offer__item,
    html.reveal-enabled .site-footer {
      /* Start-/Endzustand liefern die Keyframes (fill: both); IO-Baseline aus */
      opacity: 1;
      transform: none;
      transition: none;
      animation: project-reveal linear both;
      animation-timeline: view();
      /* Sehr früh starten, sobald der Article den unteren Viewport-Rand berührt
         (entry 0%), und nicht zu spät fertig sein (cover 40%) → er erscheint
         zeitig und der Reveal läuft trotzdem über genug Scrollweg (langsam). */
      animation-range: entry 0% cover 40%;
    }
    /* Footer sitzt ganz unten → kann nicht bis „cover 40%" hochscrollen. Daher
       früher fertig (spätestens wenn er vollständig eingetreten ist). */
    html.reveal-enabled .site-footer {
      animation-range: entry 0% entry 100%;
    }
    @keyframes project-reveal {
      from { opacity: 0; transform: translateY(4rem) scale(0.8); }
      to   { opacity: 1; transform: translateY(0)    scale(1); }
    }
  }
}

/* Harte Sicherheitsnetz-Regel: System-Wunsch „weniger Bewegung" gewinnt. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

/* 10. Utilities ---------------------------------------------------------- */
/* Full-Bleed-Bereich: spannt die volle Viewport-Breite (Hintergrund), während
   der Inhalt über eine innere .shell auf seine Breite begrenzt bleibt.
   Beispiel:
     <section class="bleed-bg"><div class="shell shell--narrow">…</div></section>
   Da der body voll breit ist, genügt hier ein Top-Level-Element ohne .shell. */
.bleed-bg { width: 100%; }

.margin-m { margin-bottom: 1.5rem; }
.margin-l { margin-bottom: 3rem; }
.margin-xl { margin-bottom: 4.5rem; }

/* Responsives 12-Spalten-Grid ab Tablet */
@media screen and (min-width: 60rem) {
  .grid { grid-template-columns: repeat(12, 1fr); }
  .grid > .column { grid-column: span var(--columns); margin-bottom: 0; }
}
